From karl_kleinpaste@cis.ohio-state.edu Tue Feb 13 18:02:19 1990
Received: from cheops.cis.ohio-state.edu by uunet.uu.net (5.61/1.14) with SMTP 
	id AA05893; Tue, 13 Feb 90 18:01:26 -0500
Received: from triceratops.cis.ohio-state.edu by cheops.cis.ohio-state.edu (5.61-kk/4.900213)
	id AA04685; Tue, 13 Feb 90 16:22:41 -0500
Received: by triceratops.cis.ohio-state.edu (5.61/5.900208)
	id AA09171; Tue, 13 Feb 90 16:21:58 -0500
Date: Tue, 13 Feb 90 16:21:58 -0500
From: karl_kleinpaste@cis.ohio-state.edu
Message-Id: <9002132121.AA09171@triceratops.cis.ohio-state.edu>
To: rick@uunet.uu.net
Subject: full name hacks for 2.11.19?
Status: R

I wrote a posting to alt.hackers last Friday, detailing a scheme I've
devised for advertising fullnames rather than loginnames in all
headers; it depends on the existence of a DNS domain in which
loginname => fullname conversions can be made with use of $[$].  I
just finished doing a similar thing for 2.11.19 inews using
gethostbyname() calls.  Are you interested in the diffs?  It's a half
dozen lines in inews.c, 2 functions at the end of funcs.c, and a new
#define in defs.dist.

From karl_kleinpaste@cis.ohio-state.edu Tue Feb 13 19:29:33 1990
Received: from cheops.cis.ohio-state.edu by uunet.uu.net (5.61/1.14) with SMTP 
	id AA29068; Tue, 13 Feb 90 19:28:02 -0500
Received: from triceratops.cis.ohio-state.edu by cheops.cis.ohio-state.edu (5.61-kk/4.900213)
	id AA06862; Tue, 13 Feb 90 19:14:25 -0500
Received: by triceratops.cis.ohio-state.edu (5.61/5.900208)
	id AA09629; Tue, 13 Feb 90 19:13:36 -0500
Date: Tue, 13 Feb 90 19:13:36 -0500
From: karl_kleinpaste@cis.ohio-state.edu
Message-Id: <9002140013.AA09629@triceratops.cis.ohio-state.edu>
To: rick@uunet.uu.net (Rick Adams)
In-Reply-To: rick@uunet.uu.net's message of Tue, 13 Feb 90 18:31:53 -0500
Subject: Re:  full name hacks for 2.11.19?
Status: R

*** defs.dist~	Wed Jan 25 10:29:35 1989
--- defs.dist	Tue Feb 13 15:24:44 1990
***************
*** 102,107 ****
--- 102,117 ----
  /* #define MINFREE 5000	/* minimum number of free blocks needed in spool*/
  			/* partition before unbatching will take place  */
  			/* USG only */
+ /* #define FULL_NAME_HACK_DOMAIN "name.frobozz.org"
+ 				/* This enables the dastardly transla-  */
+ 				/* tion of loginnames to fullnames,	*/
+ 				/* which requires that you support some */
+ 				/* sort of DNS domain in which to do	*/
+ 				/* such a thing.  You must specify the	*/
+ 				/* string name of the domain in which to*/
+ 				/* do resolutions.  Affects From:,	*/
+ 				/* Sender:, and Path:.  By convention,	*/
+ 				/* this is named "NAME.your.usual.dom."	*/
  
  /* Things you might want to change */
  #define NEWSRC  ".newsrc"	/* name of .newsrc file (in home dir)	*/
*** funcs.c~	Wed Jan 25 10:29:40 1989
--- funcs.c	Tue Feb 13 15:27:11 1990
***************
*** 786,788 ****
--- 786,846 ----
  #endif /* DEBUG */
  	return grplist;
  }
+ 
+ #ifdef FULL_NAME_HACK_DOMAIN
+ 
+ #include <netdb.h>
+ 
+ full_name_hack(field)
+ register char *field;
+ {
+   char *atsign = index(field, '@'),
+        *space  = index(field, ' '),
+        *fn, hold[MBUFLEN];
+   extern char *get_full_name();
+   
+   if (atsign != (char *) NULL)
+     {
+       /*
+        * We found user@some.thing.or.other;
+        * rewrite to fullname format.
+        */
+       *atsign = '\0';
+       if (space != (char *) NULL)
+ 	*space  = '\0';
+       fn = get_full_name(field);
+       sprintf(hold, "%s@%s", fn, atsign+1);
+       strcpy(field, hold);
+     }
+   else
+     strcpy(field, get_full_name(field));
+ }
+ 
+ char *
+ get_full_name(loginname)
+ char *loginname;
+ {
+   struct hostent *host;
+   static char realname[SBUFLEN];
+   char *dot;
+ 
+   sprintf(realname, "%s.%s", loginname, FULL_NAME_HACK_DOMAIN);
+   if ((host = gethostbyname(realname)) != (struct hostent *) NULL)
+     {
+       /*
+        * Got a resolved name.  Get rid of excess domain info.
+        */
+       if ((dot = index(host->h_name, '.')) != (char *) NULL)
+ 	*dot = '\0';
+       return(host->h_name);
+     }
+   else
+     {
+       /*
+        * No fullname.  Send back the original name.
+        */
+       strcpy(realname, loginname);
+       return(realname);
+     }
+ }
+ #endif /* FULL_NAME_HACK_DOMAIN */
*** inews.c~	Wed Nov  1 09:27:09 1989
--- inews.c	Tue Feb 13 15:26:20 1990
***************
*** 481,486 ****
--- 481,496 ----
  		} else {
  			gensender(&header, username);
  		}
+ 
+ #ifdef FULL_NAME_HACK_DOMAIN
+ 		if (header.from[0])
+ 		  full_name_hack(header.from);
+ 		if (header.sender[0])
+ 		  full_name_hack(header.sender);
+ 		if (header.path[0])
+ 		  full_name_hack(header.path);
+ #endif /* FULL_NAME_HACK_DOMAIN */
+ 
  #ifdef MYORG
  		if (header.organization[0] == '\0' && !Mflag &&
  			header.sender[0] == '\0') {

From karl_kleinpaste@cis.ohio-state.edu Wed Feb 14 10:56:43 1990
Received: from cheops.cis.ohio-state.edu by uunet.uu.net (5.61/1.14) with SMTP 
	id AA18211; Wed, 14 Feb 90 10:55:29 -0500
Received: from triceratops.cis.ohio-state.edu by cheops.cis.ohio-state.edu (5.61-kk/4.900213)
	id AA14832; Wed, 14 Feb 90 10:53:03 -0500
Received: by triceratops.cis.ohio-state.edu (5.61/5.900208)
	id AA11599; Wed, 14 Feb 90 10:52:20 -0500
Date: Wed, 14 Feb 90 10:52:20 -0500
From: karl_kleinpaste@cis.ohio-state.edu
Message-Id: <9002141552.AA11599@triceratops.cis.ohio-state.edu>
To: rick@uunet.uu.net
Subject: fixed full_name_hack()
Status: R

I made an error in the full_name_hack() routine I sent you yesterday;
it didn't deal properly with NNTP-posted articles' Path: headers at
all.  Please replace that full_name_hack() with this one.  Sorry about
this...

--karl

full_name_hack(field)
register char *field;
{
  char *atsign =  index(field, '@'),
       *bang   = rindex(field, '!'),
       *space  =  index(field, ' '),
       *fn, hold[MBUFLEN];
  extern char *get_full_name();
  
  if (atsign != (char *) NULL)
    {
      /*
       * Found user@some.thing.or.other; can be rewritten.
       */
      *atsign = '\0';
      if (space != (char *) NULL)
	*space  = '\0';
      fn = get_full_name(field);
      sprintf(hold, "%s@%s", fn, atsign+1);
      strcpy(field, hold);
    }
  else if (bang != (char *) NULL)
    {
      /*
       * Found some!thing!user; can be rewritten.
       */
      *bang = '\0';
      if (space != (char *) NULL)
	*space = '\0';
      fn = get_full_name(bang+1);
      sprintf(hold, "%s!%s", field, fn);
      strcpy(field, hold);
    }
  else
    strcpy(field, get_full_name(field));
}

From ecompin!stewart Sat Feb 17 23:26:33 1990
Received: from ecompin.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA02165; Sat, 17 Feb 90 23:25:17 -0500
Received: by ecompin.uucp (/\=-/\ Smail3.1.18.1 #18.69)
	id <m0gyG0H-0001epC@ecompin.uucp>; Tue, 13 Feb 90 22:48 EST
Message-Id: <m0gyG0H-0001epC@ecompin.uucp>
From: ecompin!stewart (John Stewart)
Subject: proposed patches for news src
To: rick@uunet.uu.net
Date: Tue, 13 Feb 90 22:48:31 EST
X-Mailer: ELM [version 2.2 PL16]
Status: RO

Rick,
I've implemented these patches locally and want to share them with the
world, in the hopes that I and my successors will not find ourselves
reapplying them!
-- 
John Stewart 202-232-5470  Effective Computing, Inc.   Watch out!  You might
uunet!ecompin!stewart      1812 Monroe St., N.W.       what you're after!
stewart@ecompin.UUCP       Washington, D.C. 20010      --Byrning Down the House

Description:
	This is a PROPOSED patch for news 2.11, to follow patch 19.
	It addresses the following problems:

	sendbatch no longer breaks due to the variable du not being set
	optional workaround for the disappearing inode bug
	code to queue incoming news when SPOOLDIR is filling up now works
	directory in which to queue incoming news can now be specified
	expire -e 999999 no longer causes a core dump
	inews makes a temp file in the .rnews directory
	inews can optionally check for space before proceeding (same for
		rnews -U)
Fix:
	if you want to use the new options, read the new install.mn document
	cd src and patch <thisfile
	then make install

diff -rc1 osrc/Makefile.dst src/Makefile.dst
*** osrc/Makefile.dst  Tue Sep 12 17:56:03 1989
--- src/Makefile.dst	Thu Feb  8 15:19:46 1990
***************
*** 1,2
! # '@(#)Makefile.dst	1.35	9/7/89'
  # Generic Makefile.

--- 1,2 -----
! # '@(#)Makefile.dst	1.35x	5 Feb 90'
  # Generic Makefile.
***************
*** 25,26
  SPOOLDIR = /usr/spool/news
  BATCHDIR = /usr/spool/batch

--- 25,27 -----
  SPOOLDIR = /usr/spool/news
+ INCOMINGDIR = /usr/spool/news/.rnews
  BATCHDIR = /usr/spool/batch
***************
*** 54,55
  	-DSPOOLDIR=\"$(DESTDIR)$(SPOOLDIR)\" \
  	-DBATCHDIR=\"$(DESTDIR)$(BATCHDIR)\" -DLIBDIR=\"$(DESTDIR)$(LIBDIR)\" \

--- 55,57 -----
  	-DSPOOLDIR=\"$(DESTDIR)$(SPOOLDIR)\" \
+ 	-DINCOMINGDIR=\"$(DESTDIR)$(INCOMINGDIR)\" \
  	-DBATCHDIR=\"$(DESTDIR)$(BATCHDIR)\" -DLIBDIR=\"$(DESTDIR)$(LIBDIR)\" \
***************
*** 88,89
  
  #VMS TERMLIB = -ltrmlib

--- 90,93 -----
  
+ #INODE FIXNEWS = fixnews
+ 
  #VMS TERMLIB = -ltrmlib
***************
*** 138,140
  
! fullall: $(P) $(OTHERS) $(COMMANDS)
  

--- 142,144 -----
  
! fullall: $(P) $(OTHERS) $(COMMANDS) $(FIXNEWS)
  
***************
*** 146,148
  
! fullinstall: all help vnews.help installit
  	chmod 755 ./installit

--- 150,152 -----
  
! fullinstall: all help vnews.help installit $(FIXNEWS)
  	chmod 755 ./installit
***************
*** 173,174
  #VMS 	vms -v @euninstal
  

--- 177,179 -----
  #VMS 	vms -v @euninstal
+ #INODE 	./installit -c -m 6755 -o root -g $(NEWSGRP) -s fixnews $(DESTDIR)/etc
  
***************
*** 212,214
  fullupdate: install.sh makeactive.sh
! 	sh install.sh $(DESTDIR)$(SPOOLDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(BINDIR) $(NEWSUSR) $(NEWSGRP) $(OSTYPE)
  	chmod 6755 $(DESTDIR)$(LIBDIR)/inews

--- 217,219 -----
  fullupdate: install.sh makeactive.sh
! 	sh install.sh $(DESTDIR)$(SPOOLDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(BINDIR) $(DESTDIR)$(INCOMINGDIR) $(NEWSUSR) $(NEWSGRP) $(OSTYPE)
  	chmod 6755 $(DESTDIR)$(LIBDIR)/inews
***************
*** 216,218
  nfsupdate: install.sh
! 	sh install.sh $(DESTDIR)$(SPOOLDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(BINDIR) $(NEWSUSR) $(NEWSGRP) $(OSTYPE) $(DESTDIR)$(NFSSPOOLDIR) $(DESTDIR)$(NFSLIBDIR)
  	chown root $(DESTDIR)$(LIBDIR)/inews

--- 221,223 -----
  nfsupdate: install.sh
! 	sh install.sh $(DESTDIR)$(SPOOLDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(BINDIR) $(DESTDIR)$(INCOMINGDIR) $(NEWSUSR) $(NEWSGRP) $(OSTYPE) $(DESTDIR)$(NFSSPOOLDIR) $(DESTDIR)$(NFSLIBDIR)
  	chown root $(DESTDIR)$(LIBDIR)/inews
***************
*** 225,226
  	rm -f $(COMMANDS) $(OTHERS) *.o a.out
  	rm -f core index errs getdate.c

--- 230,232 -----
  	rm -f $(COMMANDS) $(OTHERS) *.o a.out
+ 	rm -f fixnews
  	rm -f core index errs getdate.c
***************
*** 306,308
  vnews:	$(P) $(VOBJECTS)
! 	$(CC) $(LFLAGS) $(VOBJECTS)  -o $@  $(TERMLIB) $(NETLIB) $(LIBS)
  #VMS 	mv vnews.exe vnews

--- 312,314 -----
  vnews:	$(P) $(VOBJECTS)
! 	$(CC) $(LFLAGS) $(VOBJECTS)  -o vnews $(TERMLIB) $(NETLIB) $(LIBS)
  #VMS 	mv vnews.exe vnews
***************
*** 351,352
  #VMS 	mv caesar.exe caesar
  

--- 357,361 -----
  #VMS 	mv caesar.exe caesar
+ 
+ fixnews:	fixnews.c
+ 	$(CC) $(CFLAGS) $(LFLAGS) fixnews.c -o fixnews $(LIBS)
  
diff -rc1 osrc/defs.dist src/defs.dist
*** osrc/defs.dist  Tue Jan 24 15:23:59 1989
--- src/defs.dist	Tue Feb  6 14:45:36 1990
***************
*** 16,18
  
! /*	@(#)defs.dist	2.65	1/24/89	*/
  

--- 16,18 -----
  
! /*	@(#)defs.dist	2.65x	2/6/90	*/
  
***************
*** 104,105
  			/* USG only */
  

--- 104,110 -----
  			/* USG only */
+ /* #define INODE_FIX	/* define this, SPOOLNEWS, and SPOOLINEWS if you */
+ 			/* have a System V which can't keep track of inodes. */
+ 			/* Note:  SPOOLDIR must be the mount point of */
+ 			/* a separate file system, SPOOLDEV.  */
+ /* #define SPOOLDEV	"/dev/dsk/1s3"	/* see INODE_FIX */
  
diff -rc1 osrc/expire.c src/expire.c
*** osrc/expire.c  Mon Oct 30 18:50:55 1989
--- src/expire.c	Mon Feb 12 16:37:52 1990
***************
*** 19,21
  #ifdef SCCSID
! static char	*SccsId = "@(#)expire.c	2.64	10/29/89";
  #endif /* SCCSID */

--- 19,21 -----
  #ifdef SCCSID
! static char	*SccsId = "@(#)expire.c	2.64x	02/12/90";
  #endif /* SCCSID */
***************
*** 67,68
  double atof();
  

--- 67,69 -----
  double atof();
+ static long get_time();
  
***************
*** 152,154
  				argc--;
! 				expincr = atof(argv[1]) * DAYS;
  			} else if (isdigit(argv[1][2]))

--- 153,155 -----
  				argc--;
! 				expincr = get_time(argv[1]);
  			} else if (isdigit(argv[1][2]))
***************
*** 154,156
  			} else if (isdigit(argv[1][2]))
! 				expincr = atof(&argv[1][2]) * DAYS;
  			break;

--- 155,157 -----
  			} else if (isdigit(argv[1][2]))
! 				expincr = get_time(&argv[1][2]);
  			break;
***************
*** 160,162
  				argc--;
! 				dropincr = atof(argv[1]) * DAYS;
  			} else if (isdigit(argv[1][2]))

--- 161,163 -----
  				argc--;
! 				dropincr = get_time(argv[1]);
  			} else if (isdigit(argv[1][2]))
***************
*** 162,164
  			} else if (isdigit(argv[1][2]))
! 				dropincr = atof(&argv[1][2]) * DAYS;
  			break;

--- 163,165 -----
  			} else if (isdigit(argv[1][2]))
! 				dropincr = get_time(&argv[1][2]);
  			break;
***************
*** 896,898
  		}
! 		minart = 99999L;
  		/* Change a group name from a.b.c to a/b/c */

--- 897,899 -----
  		}
! 		minart = 9999999L;
  		/* Change a group name from a.b.c to a/b/c */
***************
*** 1275,1276
  	exit(i);
  }

--- 1276,1293 -----
  	exit(i);
+ }
+ 
+ /*
+  * This fixes the floating point exception when the user follows the
+  * documentation and executes:
+  * expire -r -I -e 999999 -E 999999
+  * This assumes the maximum value of a long is 0x7fffffff.
+  */
+ #define	MAX_DAYS	(0x7fffffff / (DAYS))
+ static long get_time(str)
+ char *str;
+ {
+ 	double daycount = atof(str);
+ 	if (daycount > MAX_DAYS)
+ 		daycount = MAX_DAYS;
+ 	return (long)(daycount * DAYS);
  }
diff -rc1 osrc/fixnews.c src/fixnews.c
*** osrc/fixnews.c  Tue Feb 13 14:35:27 1990
--- src/fixnews.c	Tue Feb 13 15:39:36 1990
***************
*** 0

--- 1,27 -----
+ /*
+  * FIXNEWS - An attempt to work around ATT's disappearing inode problem
+  */
+ #include "defs.h"
+ main()
+ {
+ 	extern int errno;
+ 	char cmd[100];
+ 	int tries = 0;
+ 
+ 	printf ( "Fixnews: Here I come, to save the day!\n");
+       
+ 	while (umount(SPOOLDEV) != 0) {
+ 		if (tries++ > 60) {
+ 			printf("Fixnews: umount failed after 60 tries, errno =%d\n", errno);
+ 			exit(1);
+ 		}
+ 		sleep(60);
+ 	}
+ 	printf ( "Fixnews: did the umount\n");
+ 	sprintf(cmd, "/etc/fsck -y %s | /bin/mail root", SPOOLDEV);
+ 	system(cmd);
+ 	printf ( "Fixnews: did the fsck\n");
+ 	mount( SPOOLDEV, SPOOLDIR, 0 );
+ 	printf( "Fixnews: did the mount\n");
+ 	exit(0);
+ }
diff -rc1 osrc/inews.c src/inews.c
*** osrc/inews.c  Mon Oct 30 18:50:58 1989
--- src/inews.c	Thu Feb  8 20:44:07 1990
***************
*** 19,21
  #ifdef SCCSID
! static char	*SccsId = "@(#)inews.c	2.93	10/29/89";
  #endif /* SCCSID */

--- 19,21 -----
  #ifdef SCCSID
! static char	*SccsId = "@(#)inews.c	2.93x	02/08/90";
  #endif /* SCCSID */
***************
*** 40,41
  #endif /* !BSD4_2 */
  /* local defines for inews */

--- 40,45 -----
  #endif /* !BSD4_2 */
+ 
+ #ifdef MINFREE
+ #include <ustat.h>
+ #endif
  /* local defines for inews */
***************
*** 101,102
  FILE *mailhdr();
  extern FILE *controlmail;

--- 105,107 -----
  FILE *mailhdr();
+ char *space();
  extern FILE *controlmail;
***************
*** 133,134
  #endif	/* !LOCKF && ! BSD4_2 */
  

--- 138,142 -----
  #endif	/* !LOCKF && ! BSD4_2 */
+ #ifdef MINFREE
+ 	char errstr[100];
+ #endif
  
***************
*** 170,172
  			if (errno != EEXIST)
- #endif /* V7 */
  #endif	/* !BSD4_2 */

--- 178,179 -----
  			if (errno != EEXIST)
  #endif	/* !BSD4_2 */
***************
*** 172,173
  #endif	/* !BSD4_2 */
  			xerror("Can't lock %s: %s", ACTIVE, errmsg(errno));

--- 179,181 -----
  #endif	/* !BSD4_2 */
+ #endif /* !LOCKF */
  			xerror("Can't lock %s: %s", ACTIVE, errmsg(errno));
***************
*** 194,196
  		(void) UNLINK(bfr);
- #endif 	/* V7 */
  #endif	/* !BSD4_2 */

--- 202,203 -----
  		(void) UNLINK(bfr);
  #endif	/* !BSD4_2 */
***************
*** 196,197
  #endif	/* !BSD4_2 */
  	} else {	/* expire is running */

--- 203,205 -----
  #endif	/* !BSD4_2 */
+ #endif 	/* !LOCKF */
  	} else {	/* expire is running */
***************
*** 209,210
  #endif /* !NFSCLIENT */
  

--- 217,224 -----
  #endif /* !NFSCLIENT */
+ #ifdef MINFREE
+ 	if (space(errstr)) {		/* check disk space */
+ 		spool_news = DO_SPOOL;
+ 		logerr("%s", errstr);
+ 	}
+ #endif	/* MINFREE */
  
***************
*** 238,245
  	}
- #ifdef MINFREE
- 	if (space()) {		/* check disk space */
- 		spool_news = DO_SPOOL;
- 		logerr("Out of space in %s.", SPOOLDIR);
- 	}
- #endif	/* MINFREE */
  	state = OPTION;

--- 252,253 -----
  	}
  	state = OPTION;
***************
*** 714,716
  
! 	(void) sprintf(sfile, "%s/.tmp/spXXXXXX", SPOOL);
  	MKTEMP(sfile);

--- 722,724 -----
  
! 	(void) sprintf(sfile, "%s/.spXXXXXX", INCOMING);
  	MKTEMP(sfile);
***************
*** 735,737
  #ifdef USG
! 	(void) sprintf(buf, "%s/.rnews/%2.2d%2.2d%2.2d%2.2d%2.2d%x",
  #else

--- 743,745 -----
  #ifdef USG
! 	(void) sprintf(buf, "%s/%2.2d%2.2d%2.2d%2.2d%2.2d%x",
  #else
***************
*** 737,744
  #else
! #ifdef VMS
! 	/* Eunice doesn't like dots in directory names */
! 	(void) sprintf(buf, "%s/+rnews/%02d%02d%02d%02d%02d%x",
! #else /* V7 */
! 	(void) sprintf(buf, "%s/.rnews/%02d%02d%02d%02d%02d%x",
! #endif /* V7 */
  #endif /* VMS */

--- 745,747 -----
  #else
! 	(void) sprintf(buf, "%s/%02d%02d%02d%02d%02d%x",
  #endif /* VMS */
***************
*** 744,746
  #endif /* VMS */
! 		SPOOL,
  		tp->tm_year, tp->tm_mon+1, tp->tm_mday,

--- 747,749 -----
  #endif /* VMS */
! 		INCOMING,
  		tp->tm_year, tp->tm_mon+1, tp->tm_mday,
***************
*** 753,765
  	if (LINK(sfile, buf) < 0) {
! 		char dbuf[BUFLEN];
! #ifdef VMS
! 		sprintf(dbuf, "%s/+rnews", SPOOL);
! #else /* !VMS */
! 		sprintf(dbuf, "%s/.rnews", SPOOL);
! #endif /* !VMS */
! 		if (mkdir(dbuf, 0777&~N_UMASK) < 0)
! 			xerror("Cannot mkdir %s: %s", dbuf, errmsg(errno));
! 		if (LINK(sfile, buf) < 0) 
! 			xerror("Cannot link(%s,%s): %s", sfile, buf,
! 				errmsg(errno));
  	}

--- 756,758 -----
  	if (LINK(sfile, buf) < 0) {
! 		xerror("Cannot link(%s,%s): %s", sfile, buf, errmsg(errno));
  	}
***************
*** 1523,1524
  #endif /* LOCKF */
  

--- 1516,1520 -----
  #endif /* LOCKF */
+ #ifdef MINFREE
+ 	char errstr[100];
+ #endif
  
***************
*** 1527,1533
  #endif	/* !LOCKF && ! BSD4_2 */
! #ifdef VMS
! 	sprintf(spbuf, "%s/+rnews", SPOOL);
! #else /* !VMS */
! 	sprintf(spbuf, "%s/.rnews", SPOOL);
! #endif /* !VMS */
  

--- 1523,1525 -----
  #endif	/* !LOCKF && ! BSD4_2 */
! 	strcpy(spbuf, INCOMING);
  
***************
*** 1549,1552
  		if (errno != EWOULDBLOCK)
! #else	/* V7 */
! 	strcat(spbuf, ".lock");
  	sprintf(bfr, "%s.tmp", spbuf);

--- 1541,1544 -----
  		if (errno != EWOULDBLOCK)
! #else	/* !BSD4_2 */
! 	strcat(spbuf, "/.lock");
  	sprintf(bfr, "%s.tmp", spbuf);
***************
*** 1563,1565
  			if (errno != EEXIST)
! #endif /* V7 */
  #endif	/* !LOCKF */

--- 1555,1557 -----
  			if (errno != EEXIST)
! #endif /* !BSD4_2 */
  #endif	/* !LOCKF */
***************
*** 1576,1577
  
  #ifdef IHCC

--- 1568,1578 -----
  
+ #ifdef MINFREE
+ 			if (space(errstr)) {		/* check disk space */
+ 				logerr("%s; rnews -U exiting", errstr);
+ #if	!defined(LOCKF) && !defined(BSD4_2)
+ 				(void) UNLINK(spbuf);
+ #endif
+ 				xxit(0); /*!!! perhaps we should return nonzero status */
+ 			}
+ #endif	/* MINFREE */
  #ifdef IHCC
***************
*** 1604,1609
  			if (status != 0) {
! 				sprintf(bfr, "../.bad/%s", dir->d_name);
! 				(void) LINK(dir->d_name, bfr);
! 				logerr("rnews failed, status %ld. Batch saved in %s/.bad/%s",
! 					(long)status, SPOOL, dir->d_name);
  			}

--- 1605,1629 -----
  			if (status != 0) {
! #ifdef	INODE_FIX
! 				struct stat file;
! 				struct ustat device;
! 				/* see how the space situation looks */
! 				stat(SPOOLDIR, &file);
! 				ustat(file.st_dev, &device);
! 				if ( device.f_tinode < 100 ) {
! 					logerr("inodes lost! status %ld.  Save the batch!",
! 						(long)status);
! 					fixnews();
! 					sleep(60);
! 				} else {
! #endif	/*INODE_FIX*/
! 					sprintf(bfr, "../.bad/%s", dir->d_name);
! 					(void) LINK(dir->d_name, bfr);
! 					logerr("rnews failed, status %ld. Batch saved in %s/.bad/%s",
! 						(long)status, SPOOL, dir->d_name);
! 					(void) unlink(dir->d_name);
! #ifdef	INODE_FIX
! 				}
! #endif	/*INODE_FIX*/
! 			} else {
! 				(void) unlink(dir->d_name);
  			}
***************
*** 1609,1611
  			}
- 			(void) unlink(dir->d_name);
  			foundsome++;

--- 1629,1630 -----
  			}
  			foundsome++;
***************
*** 1614,1617
  	} while (foundsome); /* keep rereading the directory until it's empty */
! #ifndef LOCKF
! #ifndef BSD4_2
  	(void) UNLINK(spbuf);

--- 1633,1635 -----
  	} while (foundsome); /* keep rereading the directory until it's empty */
! #if	!defined(LOCKF) && !defined(BSD4_2)
  	(void) UNLINK(spbuf);
***************
*** 1617,1620
  	(void) UNLINK(spbuf);
! #endif
! #endif
  

--- 1635,1637 -----
  	(void) UNLINK(spbuf);
! #endif /* !LOCKF && !BSD4_2 */
  
***************
*** 1625,1627
  #ifdef MINFREE
- #include <ustat.h>
  /* 

--- 1642,1643 -----
  #ifdef MINFREE
  /* 
***************
*** 1629,1631
   * return 0 if there is and
!  * anything appropriate if there is not 
   * written by Stan Barber (sob@bcm.tmc.edu)

--- 1645,1647 -----
   * return 0 if there is and
!  * pointer to error message if not
   * written by Stan Barber (sob@bcm.tmc.edu)
***************
*** 1631,1632
   * written by Stan Barber (sob@bcm.tmc.edu)
   */

--- 1647,1649 -----
   * written by Stan Barber (sob@bcm.tmc.edu)
+  * heavily modified by John Stewart (stewart@ecompin.uucp)
   */
***************
*** 1632,1634
   */
! space()
  {

--- 1649,1652 -----
   */
! char *space(errstr)
! char *errstr;
  {
***************
*** 1636,1644
  	struct ustat device;
! 	if (stat(SPOOLDIR,&file))
! 		return 1;	/* can't stat spool */
! 	if (ustat(file.st_dev, &device))
! 		return 1;	/* can't stat the device */
! 	if(device.f_tfree < MINFREE)
! 		return 1;
! 	return 0;
  }

--- 1654,1669 -----
  	struct ustat device;
! 
! 	*errstr = '\0';
! 
! 	if (stat(SPOOLDIR,&file)) {
! 		sprintf(errstr, "can't stat %s", SPOOLDIR);
! 	} else if (ustat(file.st_dev, &device)) {
! 		sprintf(errstr, "can't ustat %s", SPOOLDIR);
! 	} else if(device.f_tfree >= MINFREE) {
! 		return (char *) 0;	/* OK */
! 	} else {
! 		sprintf(errstr, "Low on space in %s, %d.%3.3d meg left",
! 			SPOOLDIR, device.f_tfree/1000, device.f_tfree%1000);
! 	}
! 	return errstr;
  }
***************
*** 1645,1647
  #else
! int space()
  {

--- 1670,1672 -----
  #else
! char *space()
  {
***************
*** 1648,1650
  	/* I'll figure this out for BSD some other time */
! 	return(0);
  }

--- 1673,1675 -----
  	/* I'll figure this out for BSD some other time */
! 	return (char *) 0;	/* OK */
  }
***************
*** 1651
  #endif	/* MINFREE */

--- 1676,1685 -----
  #endif	/* MINFREE */
+ 
+ #ifdef	INODE_FIX
+ 
+ fixnews()
+ {
+     logerr("running fixnews!");
+     system("/etc/fixnews | /bin/mail root");
+ }
+ #endif	/*INODE_FIX*/
diff -rc1 osrc/install.sh src/install.sh
*** osrc/install.sh  Sun Jan 15 19:49:00 1989
--- src/install.sh	Mon Feb 12 17:21:04 1990
***************
*** 1,2
! : '@(#)install.sh	1.20	1/15/89'
  

--- 1,2 -----
! : '@(#)install.sh	1.20x	2/5/90'
  
***************
*** 10,16
  BINDIR=$3
! NEWSUSR=$4
! NEWSGRP=$5
! OSTYPE=$6
! NFSSPOOLDIR=$7
! NFSLIBDIR=$8
  

--- 10,17 -----
  BINDIR=$3
! INCOMINGDIR=$4
! NEWSUSR=$5
! NEWSGRP=$6
! OSTYPE=$7
! NFSSPOOLDIR=$8
! NFSLIBDIR=$9
  
***************
*** 54,56
  then
! 	for i in $SPOOLDIR $SPOOLDIR/.rnews $SPOOLDIR/.bad $SPOOLDIR/.tmp
  	do

--- 55,57 -----
  then
! 	for i in $SPOOLDIR $INCOMINGDIR $INCOMINGDIR/.bad $SPOOLDIR/.tmp
  	do
diff -rc1 osrc/localize.vms src/localize.vms
*** osrc/localize.vms  Thu Oct 30 16:12:16 1986
--- src/localize.vms	Mon Feb  5 22:25:54 1990
***************
*** 9,10
  g/^#BSD4_[123] /d
  g/chgrp /d

--- 9,11 -----
  g/^#BSD4_[123] /d
+ /^INCOMINGDIR/s;=.*;= /usr/spool/news/+rnews;p
  g/chgrp /d
diff -rc1 osrc/localize.xenix src/localize.xenix
*** osrc/localize.xenix  Mon Oct 30 18:50:59 1989
--- src/localize.xenix	Tue Feb 13 15:07:58 1990
***************
*** 6,7
  #
  rm -f Makefile

--- 6,9 -----
  #
+ # putting a g in front of the substitutions obscures editing failures
+ #
  rm -f Makefile
***************
*** 35,38
  g/-o readnews/s/-o/-m readnews.map -F 3000 -o/
! /^vnews:/+1;s/-o $@ /-F 5000 -m vnews.map -o vnews/
! /^checknews:/+1;s/$(LFLAGS)/$(LFLAGS) -F E000/
  g/-o expire/s/-o/-F A000 -o/

--- 37,40 -----
  g/-o readnews/s/-o/-m readnews.map -F 3000 -o/
! g/-o vnews/s/-o/-m vnews.map -F 5000 -o/
! g/-o checknews/s/$(LFLAGS)/$(LFLAGS) -F E000/
  g/-o expire/s/-o/-F A000 -o/
***************
*** 61,62
  /MYORG/s/Frobozz Inc., St. Louis/My Organization, Inc., Hometown, ST/
  w

--- 63,65 -----
  /MYORG/s/Frobozz Inc., St. Louis/My Organization, Inc., Hometown, ST/
+ /\/\* #define MINFREE.*0/s//#define MINFREE 2000/p
  w
diff -rc1 osrc/params.h src/params.h
*** osrc/params.h  Tue Sep 12 17:56:26 1989
--- src/params.h	Mon Feb 12 16:39:58 1990
***************
*** 4,6
  
! /*	@(#)params.h	2.32	9/1/89	*/
  

--- 4,6 -----
  
! /*	@(#)params.h	2.32x	02/12/90	*/
  
***************
*** 66,68
  
! extern	char	*SPOOL, *LIB, *BIN, *SUBFILE, *ACTIVE;
  extern	char	*LOCKFILE, *SEQFILE, *ARTFILE, *BUGFILE;

--- 66,68 -----
  
! extern	char	*SPOOL, *INCOMING, *LIB, *BIN, *SUBFILE, *ACTIVE;
  extern	char	*LOCKFILE, *SEQFILE, *ARTFILE, *BUGFILE;
diff -rc1 osrc/pathinit.c src/pathinit.c
*** osrc/pathinit.c  Sun Jan 15 19:49:02 1989
--- src/pathinit.c	Mon Feb 12 16:40:52 1990
***************
*** 36,38
  #ifdef SCCSID
! static char	*SccsId = "@(#)pathinit.c	1.26	1/15/89";
  #endif /* SCCSID */

--- 36,38 -----
  #ifdef SCCSID
! static char	*SccsId = "@(#)pathinit.c	1.26x	2/12/90";
  #endif /* SCCSID */
***************
*** 53,55
  char *FROMSYSNAME, *PATHSYSNAME, *LOCALSYSNAME, *LOCALPATHSYSNAME;
! char *SPOOL, *LIB, *BIN, *ACTIVE, *SUBFILE, *ARTFILE,
  	*username = "Unknown", *userhome;

--- 53,55 -----
  char *FROMSYSNAME, *PATHSYSNAME, *LOCALSYSNAME, *LOCALPATHSYSNAME;
! char *SPOOL, *INCOMING, *LIB, *BIN, *ACTIVE, *SUBFILE, *ARTFILE,
  	*username = "Unknown", *userhome;
***************
*** 136,137
  	SPOOL = AllocCpy(bfr);
  	(void) sprintf(bfr, "%s/%s", logdir(HOME), LIBDIR);

--- 136,139 -----
  	SPOOL = AllocCpy(bfr);
+ 	(void) sprintf(bfr, "%s/%s", logdir(HOME), INCOMINGDIR);
+ 	INCOMING = AllocCpy(bfr);
  	(void) sprintf(bfr, "%s/%s", logdir(HOME), LIBDIR);
***************
*** 141,142
  	SPOOL = AllocCpy(SPOOLDIR);
  	LIB = AllocCpy(LIBDIR);

--- 143,145 -----
  	SPOOL = AllocCpy(SPOOLDIR);
+ 	INCOMING = AllocCpy(INCOMINGDIR);
  	LIB = AllocCpy(LIBDIR);
diff -rc1 osrc/sendbatch.sh src/sendbatch.sh
*** osrc/sendbatch.sh  Mon Oct 30 18:51:05 1989
--- src/sendbatch.sh	Mon Feb 12 16:41:31 1990
***************
*** 1,2
! : '@(#)sendbatch.sh	1.22	10/29/89'
  

--- 1,2 -----
! : '@(#)sendbatch.sh	1.22x	02/12/90'
  
***************
*** 88,89
  
  	if test -n "$MAXBATCH" -a -d /usr/spool/uucp/$rmt

--- 88,90 -----
  
+ 	du=0
  	if test -n "$MAXBATCH" -a -d /usr/spool/uucp/$rmt
***************
*** 116,119
  	sentbytes=0
! 	bytes_this_batch=`expr $MAXBATCH - $du`
! 	if test $bytes_this_batch -gt $MAXPERRUN
  	then

--- 117,120 -----
  	sentbytes=0
! 	bytes_this_batch="`expr $MAXBATCH - $du`"
! 	if test "$bytes_this_batch" -gt $MAXPERRUN
  	then

From ecompin!stewart Sat Feb 17 23:28:00 1990
Received: from ecompin.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA02930; Sat, 17 Feb 90 23:26:56 -0500
Received: by ecompin.uucp (/\=-/\ Smail3.1.18.1 #18.69)
	id <m0gyG1C-0001NEC@ecompin.uucp>; Tue, 13 Feb 90 22:49 EST
Message-Id: <m0gyG1C-0001NEC@ecompin.uucp>
From: ecompin!stewart (John Stewart)
Subject: documentation for proposed patches
To: rick@uunet.uu.net
Date: Tue, 13 Feb 90 22:49:27 EST
X-Mailer: ELM [version 2.2 PL16]
Status: RO

Rick,
These patches bring install.mn more or less up to date and add descriptions
of my new features.  Please see my proposed patches in the accompanying
message.
-- 
John Stewart 202-232-5470  Effective Computing, Inc.   Watch out!  You might
uunet!ecompin!stewart      1812 Monroe St., N.W.       what you're after!
stewart@ecompin.UUCP       Washington, D.C. 20010      --Byrning Down the House



*** install.mn+  Fri Sep  1 15:21:44 1989
--- install.mn	Thu Feb  8 18:58:35 1990
***************
*** 5,7
  .ds f1
! .ds f2 "October 27, 1986
  .de Qp					\" quoted command as hanging char

--- 5,7 -----
  .ds f1
! .ds f2 "February 8, 1990
  .de Qp					\" quoted command as hanging char
***************
*** 21,22
  Revised by Rick Adams for version 2.11
  .hn

--- 21,23 -----
  Revised by Rick Adams for version 2.11
+ Revised by John Stewart for version 2.11
  .hn
***************
*** 66,68
  to ensure that all your local customizations
! got into your final versions. If you saw a \*(lq?\*(rq when you ran
  .i localize.sh ,

--- 67,69 -----
  to ensure that all your local customizations
! got into your final versions.  If you saw a \*(lq?\*(rq when you ran
  .i localize.sh ,
***************
*** 68,70
  .i localize.sh ,
! one or both of the files is certainly wrong. It's a good idea to
  anchor the patterns in

--- 69,71 -----
  .i localize.sh ,
! one or both of the files is certainly wrong.  It's a good idea to
  anchor the patterns in
***************
*** 74,76
  .i Makefile -editing
! lines. For instance, use
  .b /^UUXFLAGS/

--- 75,77 -----
  .i Makefile -editing
! lines.  For instance, use
  .b /^UUXFLAGS/
***************
*** 456,458
  .hn 3
! MANUALLY
  .pg

--- 457,459 -----
  .hn 3
! NORMGROUPS
  .pg
***************
*** 466,468
  If you define
! .b MANUALLY ,
  you should have

--- 467,469 -----
  If you define
! .b NORMGROUPS ,
  you should have
***************
*** 470,472
  defined.
! .b MANUALLY
  is defined by default to protect you against

--- 471,473 -----
  defined.
! .b NORMGROUPS
  is defined by default to protect you against
***************
*** 491,509
  .hn 3
- BATCH
- .pg
- If set,
- this is the name of a program that will be used to unpack
- batched articles (those beginning with the character \*(lq#\*(rq).
- Batched articles normally are files reading
- .sd c
- #! rnews 1234
- article containing 1234 characters
- #! rnews 4321
- article containing 4321 characters
- \\&. . .
- .ed
- Batching is
- .i strongly
- recommended for increased efficiency on both sides.
- .hn 3
  SPOOLNEWS

--- 492,493 -----
  .hn 3
  SPOOLNEWS
***************
*** 515,517
  will be placed in the directory
! .b SPOOLDIR \f2/.rnews\fP
  for later processing by

--- 499,501 -----
  will be placed in the directory
! .b INCOMINGDIR
  for later processing by
***************
*** 522,524
  queue for example), but want to defer the actual processing until
! later. If you define this option, make sure you invoke
  .i "rnews \-U"

--- 506,510 -----
  queue for example), but want to defer the actual processing until
! later.  This can also be used in a hack to get around System V's
! ``disappearing inode problem''.
! If you define this option, make sure you invoke
  .i "rnews \-U"
***************
*** 528,529
  .hn 3
  LOCALNAME

--- 514,523 -----
  .hn 3
+ SPOOLINEWS
+ .pg
+ If this is defined and
+ .b SPOOLNEWS
+ is also defined, then all
+ .i locally
+ generated news will be spooled as well.
+ .hn 3
  LOCALNAME
***************
*** 530,531
  .pg
  Most systems have a full name database on line somewhere,

--- 524,532 -----
  .pg
+ The user's full name is retrieved first from the
+ .i NAME
+ environment variable or from the file
+ .bi $HOME \f2/.name\fP,
+ if
+ .i NAME
+ is not defined.  Normally these methods are used as an override.
  Most systems have a full name database on line somewhere,
***************
*** 540,545
  .b LOCALNAME ,
! and articles posted will only receive full names from local user information
! specified in
! .i NAME
! or
  .bi $HOME \f2/.name\fP

--- 541,543 -----
  .b LOCALNAME ,
! and the user will be prompted for the full name, which will be stored in the
  .bi $HOME \f2/.name\fP
***************
*** 545,547
  .bi $HOME \f2/.name\fP
! by the user.
  If you have a nonstandard gcos format

--- 543,545 -----
  .bi $HOME \f2/.name\fP
! file.
  If you have a nonstandard gcos format
***************
*** 567,569
  You can define this option even if your site does not understand
! internet style headers. The file
  .b LIBDIR \f2/mailpaths\fP

--- 565,567 -----
  You can define this option even if your site does not understand
! internet style headers.  The file
  .b LIBDIR \f2/mailpaths\fP
***************
*** 571,573
  The rest of this line is a string for printf to use to route your
! mail to a site that does understand internet style headers. If your site
  understands internet style headers, this string would just be \*(lq%s\*(rq.

--- 569,571 -----
  The rest of this line is a string for printf to use to route your
! mail to a site that does understand internet style headers.  If your site
  understands internet style headers, this string would just be \*(lq%s\*(rq.
***************
*** 601,603
  use your primary domain.
! The domain always begins with a period. If your site name contains the
  domain, everything after the first \*(lq.\*(rq will be stipped off to

--- 599,601 -----
  use your primary domain.
! The domain always begins with a period.  If your site name contains the
  domain, everything after the first \*(lq.\*(rq will be stipped off to
***************
*** 716,718
  .hn 3
! BSD4_1C
  .pg

--- 714,716 -----
  .hn 3
! BSD2_10
  .pg
***************
*** 718,721
  .pg
! Define this if you are running 4.1C BSD
! .ux .
  .hn 3

--- 716,720 -----
  .pg
! Define this if you are running 2.10 BSD
! .ux ,
! under which only the first 7 characters of identifiers are significant.
  .hn 3
***************
*** 731,732
  .i SVID .
  .pg

--- 730,733 -----
  .i SVID .
+ .hn 3
+ LOCKING
  .pg
***************
*** 732,733
  .pg
  .hn 3

--- 733,737 -----
  .pg
+ Define this if your system supports the 
+ .i locking ()
+ system call.
  .hn 3
***************
*** 733,734
  .hn 3
  ALWAYSALIAS

--- 737,799 -----
  .hn 3
+ DOGETUSER
+ .pg
+ Always call
+ .i getuser ()
+ so user can't fake the login name.
+ .hn 3
+ LOGDIR
+ .pg
+ Somewhat obscure.  If defined, use the home (login) directory of the user whose
+ login id is defined as
+ .b HOME
+ in the
+ .i Makefile
+ as the base for the
+ .b BATCHDIR ,
+ .b BINDIR ,
+ and
+ .b LIBDIR
+ directories.
+ It will also be used to find the
+ .i rnews
+ and the
+ .b PAGE
+ commands.
+ This uses
+ .i logdir ()
+ function on these path lookups.
+ .hn 3
+ MKDIRSUB
+ .pg
+ Should be defined if your system has
+ .i mkdir ()
+ as a system call.
+ .hn 3
+ READDIR
+ .pg
+ Should be defined if your system has
+ .i readdir ()
+ in libc.
+ .hn 3
+ DIRENT
+ .pg
+ Define this if your system uses struct dirent instead of struct direct.
+ .hn 3
+ RENAMESUB
+ .pg
+ Should be defined if your system has
+ .i rename ()
+ in libc.
+ .hn 3
+ VOID_SIGNALS
+ .pg
+ Define this if
+ .i signal ()
+ returns a pointer to a void instead of a pointer to an int.
+ .hn 3
+ SYSLOG
+ .pg
+ Define this to log errors via 4.3bsd
+ .i syslog .
+ .hn 3
  ALWAYSALIAS
***************
*** 739,741
  .b LIBDIR \f2/active\fP
! file. If this is defined, the 
  .b LIBDIR \f2/aliases\fP

--- 804,806 -----
  .b LIBDIR \f2/active\fP
! file.  If this is defined, the 
  .b LIBDIR \f2/aliases\fP
***************
*** 743,745
  .b ALL
! newsgroups. This is useful for a transition period when massive
  newsgroup renaming is occurring, but should normally be undefined as

--- 808,810 -----
  .b ALL
! newsgroups.  This is useful for a transition period when massive
  newsgroup renaming is occurring, but should normally be undefined as
***************
*** 747,748
  .hn 3
  SENDMAIL

--- 812,821 -----
  .hn 3
+ ALLOW_LIB_EXECS
+ .pg
+ Define this to allow news batches to execute commands other
+ than
+ .i inews
+ in
+ .b LIBDIR .
+ .hn 3
  SENDMAIL
***************
*** 785,786
  .pg
  If you want all your news to look like it came from a single machine

--- 858,864 -----
  .pg
+ Do not use, since it is obsolete and has been replaced by the use
+ of
+ .b GENERICPATH
+ and
+ .b GENERICFROM .
  If you want all your news to look like it came from a single machine
***************
*** 795,796
  .hn 3
  NICENESS

--- 873,888 -----
  .hn 3
+ GENERICPATH
+ .pg
+ If you are using a shared USENET/UUCP node,
+ and you want all your news to look like it came from a single machine
+ instead of from every machine on your local network,
+ define
+ .b GENERICPATH
+ to be the name of the machine you wish to pretend to be.
+ .hn 3
+ GENERICFROM
+ .pg
+ You can define to override the fully-qualified node name which appears
+ in the From: line.
+ .hn 3
  NICENESS
***************
*** 868,870
  This can be defined to be the name of the distribution that is \*(lqlocal\*(rq
! to your organization. If a control message arrives with 
  .b ORGDISTRIB

--- 960,962 -----
  This can be defined to be the name of the distribution that is \*(lqlocal\*(rq
! to your organization.  If a control message arrives with 
  .b ORGDISTRIB
***************
*** 870,872
  .b ORGDISTRIB
! as the distribution, it is believed and acted upon. This is useful
  for organizations with one \*(lqmain\*(rq news machine and several

--- 962,964 -----
  .b ORGDISTRIB
! as the distribution, it is believed and acted upon.  This is useful
  for organizations with one \*(lqmain\*(rq news machine and several
***************
*** 872,874
  for organizations with one \*(lqmain\*(rq news machine and several
! subordinate ones. All machines in that organization could define
  .b NONEWGROUPS ,

--- 964,966 -----
  for organizations with one \*(lqmain\*(rq news machine and several
! subordinate ones.  All machines in that organization could define
  .b NONEWGROUPS ,
***************
*** 874,876
  .b NONEWGROUPS ,
! .b MANUALLY
  and also

--- 966,968 -----
  .b NONEWGROUPS ,
! .b NORMGROUPS
  and also
***************
*** 884,886
  They would not have to submit this message to the other machines, as they
! would believe it because of the distribution. They would reject
  the control message if it had any other distribution.

--- 976,978 -----
  They would not have to submit this message to the other machines, as they
! would believe it because of the distribution.  They would reject
  the control message if it had any other distribution.
***************
*** 886,887
  the control message if it had any other distribution.
  .hn 2

--- 978,1024 -----
  the control message if it had any other distribution.
+ .hn 3
+ MODFILEONLY
+ .pg
+ Define when local postings to moderated groups must be approved by the
+ contents of the
+ .b LIBDIR \f2/moderators\fP
+ file.
+ .hn 3
+ MINFREE
+ .pg
+ You can define this to be the minimum number of free blocks
+ needed in spool partition before unbatching will take place.
+ If there is not sufficient room, incoming files are queued in the
+ .b INCOMINGDIR
+ directory for later processing.
+ This is done by
+ .i "rnews -U" ,
+ which is run automatically when
+ .i expire (8)
+ completes.
+ This currently works for
+ .b USG
+ systems only.
+ .hn 3
+ INODE_FIX
+ .pg
+ Define this if you have a brain-damaged System V which sometimes erroneously
+ indicates that there are no inodes left.  You must also define the
+ .b SPOOLNEWS ,
+ .b SPOOLINEWS ,
+ .b INCOMINGDIR ,
+ and
+ .b SPOOLDEV
+ flags and enable the
+ .B INODE
+ stuff in the
+ .i Makefile .
+ .hn 3
+ SPOOLDEV
+ .pg
+ Is only used if
+ .b INODE_FIX
+ is turned on.  Define it to be the name of the filesystem which is
+ mounted on
+ .b SPOOLDIR .
  .hn 2
***************
*** 900,902
  It should be either
! .b V7
  or

--- 1037,1039 -----
  It should be either
! .b v7
  or
***************
*** 902,905
  or
! .b USG .
! Any BSD system is V7. Any System 3 or System 5 system is USG.
  This is normally set by

--- 1039,1045 -----
  or
! .b usg .
! Any BSD system is
! .b v7 .
! Any System 3 or System 5 system is
! .b usg .
  This is normally set by
***************
*** 907,908
  .hn 3
  NEWSUSR

--- 1047,1058 -----
  .hn 3
+ HOME
+ .pg
+ Is used only if the
+ .b LOGDIR
+ flag is defined.
+ It is the login name of the user in whose home directory all the news stuff is.
+ Don't confuse this with the
+ .b HOME
+ environment variable.
+ .hn 3
  NEWSUSR
***************
*** 1024,1026
  .pg
! If this is defined, sccs ids will be included in each file. If you
  are short on address space, don't define this.

--- 1174,1176 -----
  .pg
! If this is defined, sccs ids will be included in each file.  If you
  are short on address space, don't define this.
***************
*** 1062,1064
  \&\*(lqm\*(rq
! the newsgroup is moderated and may not be posted to directly. Instead,
  articles posted to that newsgroup are automatically mailed to the moderator

--- 1212,1214 -----
  \&\*(lqm\*(rq
! the newsgroup is moderated and may not be posted to directly.  Instead,
  articles posted to that newsgroup are automatically mailed to the moderator
***************
*** 1139,1141
  .pg
! This program does a modified Lempel-Ziv data compression. It is used by the
  compressed batching scheme.

--- 1289,1291 -----
  .pg
! This program does a modified Lempel-Ziv data compression.  It is used by the
  compressed batching scheme.
***************
*** 1160,1162
  This program transforms an 8-bit binary file into a file suitable for
! sending over a link that only allows 7-bit characters. It is used
  by

--- 1310,1312 -----
  This program transforms an 8-bit binary file into a file suitable for
! sending over a link that only allows 7-bit characters.  It is used
  by
***************
*** 1240,1242
  style mail addresses.
! Each line consists of two fields. The first field is either the
  keyword

--- 1390,1392 -----
  style mail addresses.
! Each line consists of two fields.  The first field is either the
  keyword
***************
*** 1269,1271
  .i backbone
! path is used when posting articles to moderated groups. A mail
  alias exists on almost all backbone sites to forward mail to the proper

--- 1419,1421 -----
  .i backbone
! path is used when posting articles to moderated groups.  A mail
  alias exists on almost all backbone sites to forward mail to the proper
***************
*** 1271,1273
  alias exists on almost all backbone sites to forward mail to the proper
! moderator for the group. The mail aliases should always be up to
  date on these sites, so when a group changes moderators, only

--- 1421,1423 -----
  alias exists on almost all backbone sites to forward mail to the proper
! moderator for the group.  The mail aliases should always be up to
  date on these sites, so when a group changes moderators, only
***************
*** 1273,1275
  date on these sites, so when a group changes moderators, only
! the backbone sites need to update any files. The mail alias is
  the newsgroups name with \*(lq.\*(rq changed to \*(lq\-\*(rq.

--- 1423,1425 -----
  date on these sites, so when a group changes moderators, only
! the backbone sites need to update any files.  The mail alias is
  the newsgroups name with \*(lq.\*(rq changed to \*(lq\-\*(rq.
***************
*** 1285,1287
  .b INTERNET
! option is defined for replying to news articles. A site whose mailer
  does not understand

--- 1435,1437 -----
  .b INTERNET
! option is defined for replying to news articles.  A site whose mailer
  does not understand
***************
*** 1707,1709
  .b SPOOL
! will be appended to this file. If the fourth field is blank, the filename
  .b BATCHDIR \f2/sysname\fP,

--- 1857,1859 -----
  .b SPOOL
! will be appended to this file.  If the fourth field is blank, the filename
  .b BATCHDIR \f2/sysname\fP,
***************
*** 1738,1740
  .Qp M
! says to use multi-casting. Multi-casting is described in an appendix.
  .Qp I

--- 1888,1890 -----
  .Qp M
! says to use multi-casting.  Multi-casting is described in an appendix.
  .Qp I
***************
*** 1740,1742
  .Qp I
! automatically defines the
  .b F

--- 1890,1892 -----
  .Qp I
! implies the
  .b F
***************
*** 1742,1744
  .b F
! flag. However, it puts the article's 
  .i Message-Id

--- 1892,1894 -----
  .b F
! flag (but don't specify it too).  However, it puts the article's 
  .i Message-Id
***************
*** 1744,1746
  .i Message-Id
! into the file instead of the filename containing the article. This is
  used with the 

--- 1894,1896 -----
  .i Message-Id
! into the file instead of the filename containing the article.  This is
  used with the 
***************
*** 1885,1887
  When you write out the file and exit from the editor,
! you will be prompted for what to do next. Your choices are:
  .b w rite

--- 2035,2037 -----
  When you write out the file and exit from the editor,
! you will be prompted for what to do next.  Your choices are:
  .b w rite
***************
*** 1962,1964
  \f2lockf()\fP) you must make sure that the various lock files are
! removed when the system is rebooted after a crash. You can put a line
  in 

--- 2112,2114 -----
  \f2lockf()\fP) you must make sure that the various lock files are
! removed when the system is rebooted after a crash.  You can put a line
  in 
***************
*** 1965,1967
  .i /etc/rc
! to remove these lock files. The most important one is 
  .b LIBDIR \f2/active.lock\fP.

--- 2115,2117 -----
  .i /etc/rc
! to remove these lock files.  The most important one is 
  .b LIBDIR \f2/active.lock\fP.
***************
*** 2189,2191
  News 2.11 is much more particular about handling distributions than
! previous versions. In particular, make sure that you have the distribution
  .i world

--- 2339,2341 -----
  News 2.11 is much more particular about handling distributions than
! previous versions.  In particular, make sure that you have the distribution
  .i world
***************
*** 2281,2283
  .b I
! flag defined in the sys file for the remote site. For example:
  .sd c

--- 2431,2435 -----
  .b I
! flag defined in the sys file for the remote site.  (Do not specify the
! .b F
! flag at the same time.)  For example:
  .sd c
***************
*** 2283,2285
  .sd c
! elsie:world,na,usa,comp,sci,news,rec,soc,misc,talk,to.elsie:IF
  .ed

--- 2435,2437 -----
  .sd c
! elsie:world,na,usa,comp,sci,news,rec,soc,misc,talk,to.elsie:I
  .ed
***************
*** 2290,2292
  already been received), and is considered for retransmission to other
! sites. If the system you are sending to has the
  .B I

--- 2442,2444 -----
  already been received), and is considered for retransmission to other
! sites.  If the system you are sending to has the
  .B I
***************
*** 2293,2295
  flag defined, the Message-ID
! is saved in the file specified in the sys entry. 
  .pg

--- 2445,2449 -----
  flag defined, the Message-ID
! is saved in the file
! .b /usr/spool/batch/\f2elsie.ihave\fP
! (in this example).
  .pg
***************
*** 2308,2310
  .b sendme
! control message. When the
  .b ihave

--- 2462,2464 -----
  .b sendme
! control message.  When the
  .b ihave
***************
*** 2325,2327
  file 
! .b /usr/spool/batch/ \f2elsie\fP
  for later processing by

--- 2479,2481 -----
  file 
! .b /usr/spool/batch/\f2elsie\fP
  for later processing by
***************
*** 2365,2367
  If
! .b MANUALLY
  is not defined,

--- 2519,2521 -----
  If
! .b NORMGROUPS
  is not defined,
***************
*** 2375,2377
  We recommend that you leave
! .b MANUALLY
  defined,

--- 2529,2531 -----
  We recommend that you leave
! .b NORMGROUPS
  defined,
***************
*** 2565,2567
  .ed
! This will create the active entry locally. The directory will be
  created automatically when the first article for that newsgroup is

--- 2719,2721 -----
  .ed
! This will create the active entry locally.  The directory will be
  created automatically when the first article for that newsgroup is
***************
*** 2847,2849
  Converting from version 2.10 or later to 2.11 requires no special
! intervention. All files are updated automatically when you do 
  \*(lqmake update\*(rq.

--- 3001,3003 -----
  Converting from version 2.10 or later to 2.11 requires no special
! intervention.  All files are updated automatically when you do 
  \*(lqmake update\*(rq.
***************
*** 3347,3349
  .hu
! Appendix C: Installing news on a Eunice system
  .pg

--- 3501,3591 -----
  .hu
! Appendix C: Disappearing Inodes on System V
! .pg
! A very large number of System V machines have a bug in the kernel
! which causes them to suddenly and unexpectedly run out of inodes.
! Some vendors simply refuse to fix their buggy software, so a
! work-around has been developed.
! .pg
! Note that the inodes are not really lost; the count of free inodes is
! just corrupted.  This count can be restored by running
! .i fsck (8).
! That is what this work-around does.
! .i inews (8)
! is configured to queue incoming files to the
! .b INCOMINGDIR
! directory (usually
! .i "/usr/spool/incoming" )
! instead of processing them immediately.
! The queue is processed by running
! .i "rnews -U"
! to unspool the articles.
! Before processing each file, a check is made to ensure that there are
! enough blocks and inodes in the
! .b SPOOLDEV
! file system.
! After each batch, it stats the file system to see if processing failed
! because of problems like being out of space or inodes.
! If not, it removes the processed batch file as it normally does.
! Otherwise, it runs
! .i "etc/fixnews"
! to repair things and reprocesses the batch if the problem is cleared up.
! .pg
! .i fixnews
! tries to unmount the
! .b SPOOLDEV
! filesystem, which is mounted on the
! .b SPOOLDIR
! directory (usually
! .i "/usr/spool/news" ),
! and repair the inode problem.
! .i fixnews
! must be setuid root to work and will not work if someone is reading
! news at the time, since it can't unmount the file system.
! .pg
! This works best if
! .b SPOOLDIR
! and
! .b INCOMINGDIR
! are in separate file systems.  It probably works only if
! .b SPOOLDIR
! is the mount point for its own file system.
! This means that uucp can continue operating even if the file system breaks,
! and the repair happens automatically.
! DON'T leave newsreaders (i.e.
! .i vnews
! or
! .i rn )
! running when no one is around because they will block the
! fixnews from working.
! .pg
! To activate this fix, you need to
! .lp (1)
! Edit localize.sh to specify the following in the
! .i Makefile :
! Enable the lines beginning with
! .b #INODE
! and set
! .b INCOMINGDIR
! to
! .i /usr/spool/incoming .
! .lp (2)
! Edit localize.sh to specify the following in the
! .i defs.h
! file:
! Define
! .b SPOOLNEWS ,
! .b SPOOLINEWS ,
! and
! .b INODE_FIX .
! You must also define
! .b SPOOLDEV to be the device which is mounted on
! .b SPOOLDIR .
! .lp (3)
! Make sure that
! .i "rnews -U"
! is run regularly by
! .i cron (8).
! .bp
! .hu
! Appendix D: Installing news on a Eunice system
  .pg

From rsa@well.UUCP Fri Mar  9 12:58:04 1990
Path: uunet!ns-mx!iowasp!deimos!ux1.cso.uiuc.edu!brutus.cs.uiuc.edu!zaphod.mps.ohio-state.edu!usc!apple!well!rsa
From: rsa@well.sf.ca.us (RSA Data Security)
Newsgroups: sci.crypt
Subject: Re: On the value of a reward
Message-ID: <16587@well.sf.ca.us>
Date: 9 Mar 90 17:58:04 GMT
References: <EZwxxKn0Bww61CnlUS@transarc.com> <1990Mar7.200720.22440@xanadu.com>
Reply-To: rsa@well.UUCP (RSA Data Security)
Organization: Whole Earth 'Lectronic Link, Sausalito, CA
Lines: 453

___________________________________________________________________
License to copy and use this document and the software described
herein is granted provided it is identified as the "RSA Data
Security, Inc. MD4 Message Digest Algorithm" in all materials
mentioning or referencing this software, function, or document.

License is also granted to make derivative works provided that such
works are identified as "derived from the RSA Data Security, Inc. MD4
Message Digest Algorithm" in all material mentioning or referencing
the derived work.

RSA Data Security, Inc. makes no representations concerning the
merchantability of this algorithm or software or their suitability
for any specific purpose.  It is provided "as is" without express or
implied warranty of any kind.

These notices must be retained in any copies of any part of this
documentation and/or software.


		 The MD4 Message Digest Algorithm
		 --------------------------------
			by Ronald L. Rivest
	MIT Laboratory for Computer Science, Cambridge, Mass. 02139
				and
	RSA Data Security, Inc., Redwood City, California 94065
		Copyright 1989,90 Ronald L. Rivest
			(Version 2/14/90)
			    (Revised)


Abstract:
---------
			    
This note describes the MD4 message digest algorithm.  The algorithm
takes as input an input message of arbitrary length and produces as
output a 128-bit ``fingerprint'' or ``message digest'' of the input.
It is conjectured that it is computationally infeasible to produce two
messages having the same message digest, or to produce any message
having a given prespecified target message digest.  The MD4 algorithm
is thus ideal for digital signature applications, where a large file
must be ``compressed'' in a secure manner before being signed with the
RSA public-key cryptosystem.

The MD4 algorithm is designed to be quite fast on 32-bit machines.
On a SUN Sparc station, it runs at 1,066,000 bytes/second.  On a DEC
MicroVax II, it runs at 70,000 bytes/second.  In addition, the MD4
algorithm does not require any large substitution tables; the
algorithm can be coded quite compactly.


I. Terminology and Notation
---------------------------

In this note a ``word'' is a 32-bit quantity and a byte is an 8-byte
quantity.  A sequence of bits can be interpreted in a natural manner
as a sequence of bytes, where each consecutive group of 8 bits is
interpreted as a byte with the high-order (most significant) bit of
each byte listed first.  Similarly, a sequence of bytes can be
interpreted as a sequence of 32-bit words, where each consecutive
group of 4 bytes is interpreted as a word with the low-order (least
significant) byte given first.

Let x_i denote ``x sub i''.  If the subscript is an expression, we
surround it in braces, as in x_{i+1}.  Similarly, we use ^ for
superscripts (exponentiation), so that x^i denotes x to the i-th
power.

Let the symbol ``+'' denote addition of words (i.e., modulo-2^32
addition). Let X <<< s denote the 32-bit value obtained by circularly
shifting (rotating) X left by s bit positions.  Let not(X) denote the
bit-wise complement of X, and let X v Y denote the bit-wise OR of X
and Y.  Let X xor Y denote the bit-wise XOR of X and Y, and let XY
denote the bit-wise AND of X and Y.


II. MD4 Algorithm Description
-----------------------------

We begin by supposing that we have a b-bit message as input, and
that we wish to find its message digest.  Here b is an arbitrary
nonnegative integer; b may be zero, it need not be a multiple of 8,
and it may be arbitrarily large. We imagine the bits of the message
written down as follows:

	m_0 m_1 ... m_{b-1} .

The following five steps are performed to compute the message digest of the
message.


Step 1. Append padding bits
---------------------------

The message is ``padded'' (extended) so that its length (in bits) is
congruent to 448, modulo 512.  That is, the message is extended so
that it is just 64 bits shy of being a multiple of 512 bits long.
Padding is always performed, even if the length of the message is
already congruent to 448, modulo 512 (in which case 512 bits of
padding are added).

Padding is performed as follows: a single ``1'' bit is appended to the
message, and then enough zero bits are appended so that the length in bits
of the padded message becomes congruent to 448, modulo 512.


Step 2. Append length
---------------------

A 64-bit representation of b (the length of the message before the
padding bits were added) is appended to the result of the previous
step.  In the unlikely event that b is greater than 2^64, then only
the low-order 64 bits of b are used.  (These bits are appended as two
32-bit words and appended low-order word first in accordance with the
previous conventions.)

At this point the resulting message (after padding with bits and with
b) has a length that is an exact multiple of 512 bits.  Equivalently,
this message has a length that is an exact multiple of 16 (32-bit)
words.  Let M[0 ... N-1] denote the words of the resulting message,
where N is a multiple of 16.


Step 3. Initialize MD buffer
----------------------------

A 4-word buffer (A,B,C,D) is used to compute the message digest.  Here
each of A,B,C,D are 32-bit registers.  These registers are initialized
to the following values (in hexadecimal, low-order bytes first):

	word A:    01 23 45 67
	word B:    89 ab cd ef
	word C:    fe dc ba 98
	word D:    76 54 32 10


Step 4. Process message in 16-word blocks
-----------------------------------------

We first define three auxiliary functions that each take as input
three 32-bit words and produce as output one 32-bit word.

	f(X,Y,Z)  =  XY v not(X)Z 
	g(X,Y,Z)  =  XY v XZ v YZ 
	h(X,Y,Z)  =  X xor Y xor Z 

In each bit position f acts as a conditional: if x then y else z.
(The function f could have been defined using + instead of v since XY
and not(X)Z will never have 1's in the same bit position.)  In each
bit position g acts as a majority function: if at least two of x, y, z
are on, then g has a one in that bit position, else g has a zero. It
is interesting to note that if the bits of X, Y, and Z are indepedent
and unbiased, the each bit of f(X,Y,Z) will be independent and
unbiased, and similarly each bit of g(X,Y,Z) will be indepedent and
unbiased.  The function h is the bit-wise ``xor'' or ``parity'' function;
it has properties similar to those of f and g.

Do the following:

For i = 0 to N/16-1 do	/* process each 16-word block */
	For j = 0 to 15 do: /* copy block i into X */
	  Set X[j] to M[i*16+j].
	end /* of loop on j */
	Save A as AA, B as BB, C as CC, and D as DD.

	[Round 1]
	  Let [A B C D i s] denote the operation
		A = (A + f(B,C,D) + X[i]) <<< s  .
	  Do the following 16 operations:
		[A B C D 0 3] 
		[D A B C 1 7] 
		[C D A B 2 11] 
		[B C D A 3 19] 
		[A B C D 4 3] 
		[D A B C 5 7] 
		[C D A B 6 11] 
		[B C D A 7 19] 
		[A B C D 8 3] 
		[D A B C 9 7] 
		[C D A B 10 11] 
		[B C D A 11 19] 
		[A B C D 12 3] 
		[D A B C 13 7] 
		[C D A B 14 11] 
		[B C D A 15 19] 

	[Round 2]
	  Let [A B C D i s] denote the operation
	    	A = (A + g(B,C,D) + X[i] + 5A827999) <<< s .
	  (The value 5A..99 is a hexadecimal 32-bit constant, written with
	  the high-order digit first. This constant represents the square
	  root of 2.  The octal value of this constant is 013240474631.
          See Knuth, The Art of Programming, Volume 2
	  (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
	  Table 2, page 660.)
	  Do the following 16 operations:
		[A B C D 0  3] 
		[D A B C 4  5] 
		[C D A B 8  9] 
		[B C D A 12 13] 
		[A B C D 1  3] 
		[D A B C 5  5] 
		[C D A B 9  9] 
		[B C D A 13 13] 
		[A B C D 2  3] 
		[D A B C 6  5] 
		[C D A B 10 9] 
		[B C D A 14 13] 
		[A B C D 3  3] 
		[D A B C 7  5] 
		[C D A B 11 9] 
		[B C D A 15 13] 

	[Round 3]
	  Let [A B C D i s] denote the operation
		A = (A + h(B,C,D) + X[i] + 6ED9EBA1) <<< s
	  (The value 6E..A1 is a hexadecimal 32-bit constant, written with
	  the high-order digit first. This constant represents the square
	  root of 3.  The octal value of this constant is 015666365641.
          See Knuth, The Art of Programming, Volume 2
	  (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
	  Table 2, page 660.)
	  Do the following 16 operations:
		[A B C D 0  3] 
		[D A B C 8  9] 
		[C D A B 4  11] 
		[B C D A 12 15] 
		[A B C D 2  3] 
		[D A B C 10 9] 
		[C D A B 6  11] 
		[B C D A 14 15] 
		[A B C D 1  3] 
		[D A B C 9  9] 
		[C D A B 5  11] 
		[B C D A 13 15] 
		[A B C D 3  3] 
		[D A B C 11 9] 
		[C D A B 7  11] 
		[B C D A 15 15] 

Then perform the following additions:
		A = A + AA
		B = B + BB
		C = C + CC
		D = D + DD
(That is, each of the four registers is incremented by the value it had
before this block was started.)

end /* of loop on i */


Step 5. Output
--------------

The message digest produced as output is A,B,C,D.
(That is, we begin with the low-order byte of A, and end with the
high-order byte of D.)

This completes the description of MD4.  A reference implementation is
given in the Appendix.


III. Extensions
---------------

If more than 128 bits of output are required, then the following procedure
is recommended to obtain a 256-bit output.  (There is no provision made
for obtaining more than 256 bits.)

Two copies of MD4 are run in parallel over the input.  The first copy
is standard as described above.  The second copy is modified as follows.

The initial state of the second copy is:
	word A:    03 69 cf 25
	word B:    8b e1 47 ad
	word C:    05 af 49 e3
	word D:    8d 27 c1 6b

The magic constants in rounds 2 and 3 for the second copy of MD4 are
changed from sqrt(2) and sqrt(3) to cuberoot(2) and cuberoot(3):
				Octal		Hex
	Round 2 constant	012050505746	50a28be6 
	Round 3 constant	013423350444    5c4dd124

Finally, after every 16-word block is processed (including the last
block), the values of the A registers in the two copies are exchanged.

The final message digest is obtaining by appending the result of the
second copy of MD4 to the end of the result of the first copy of MD4.


IV. Summary
------------

The MD4 message digest algorithm is simple to implement, and provides
a ``fingerprint'' or message digest of a message of arbitrary length.

It is conjectured that the difficulty of coming up with two messages
having the same message digest is on the order of 2^64 operations, and
that the difficulty of coming up with any message having a given
message digest is on the order of 2^128 operations.  (The MD4 algorithm
has been carefully scrutinized for weaknesses.  It is, however, a
relatively new algorithm and further security analysis is of course
justified, as is the case with any new proposal of this sort.)  The
level of security provided by MD4 should be sufficient for
implementing very high security hybrid digital signature schemes based
on MD4 and the RSA public-key cryptosystem.

V. Acknowledgements
-------------------

I'd like to thank Don Coppersmith, Burt Kaliski, Ralph Merkle, and
Noam Nisan for helpful comment and suggestions.


APPENDIX. Reference Implementation
----------------------------------

This appendix contains the following files:
	md4.h		-- a header file for using the MD4 implementation
	md4.c		-- the source code for the MD4 routines
	md4test.c	-- a sample ``user'' routine
	results		-- the results of md4test.c

/* 
** **************************************************************************
** md4.h -- Header file for implementation of MD4 Message Digest Algorithm **
** Updated: 2/13/90 by Ronald L. Rivest                                    **
** (C) 1990 RSA Data Security, Inc.                                        **
** **************************************************************************
*/

/* MDstruct is the data structure for a message digest computation.
*/
typedef struct {
  unsigned int buffer[4];    /* Holds 4-word result of MD computation */
  unsigned char count[8];    /* Number of bits processed so far */
  unsigned int state;        /* 1--initialized and in progress, 2--finished */
} MDstruct, *MDptr;

/* MDbegin(MD)
** Input: MD -- an MDptr
** Initialize the MDstruct prepatory to doing a message digest computation.
*/
extern void MDbegin();

/* MDupdate(MD,X,count)
** Input: MD -- an MDptr
**        X -- a pointer to an array of unsigned characters.
**        count -- the number of bits of X to use (an unsigned int).
** Updates MD using the first ``count'' bits of X.
** The array pointed to by X is not modified.
** If count is not a multiple of 8, MDupdate uses high bits of last byte.
** This is the basic input routine for a user.
** The routine terminates the MD computation when count < 512, so
** every MD computation should end with one call to MDupdate with a
** count less than 512.  Zero is OK for a count.
*/
extern void MDupdate();

/* MDprint(MD)
** Input: MD -- an MDptr
** Prints message digest buffer MD as 32 hexadecimal digits.
** Order is from low-order byte of buffer[0] to high-order byte of buffer[3].
** Each byte is printed with high-order hexadecimal digit first.
*/
extern void MDprint();      

/* 
** End of md4.h
****************************(cut)*****************************************/

/* 
** **************************************************************************
** Implementation of MD4 Message Digest Algorithm                          **
** Updated: 2/12/90 by Ronald L. Rivest                                    **
** (C) 1990 RSA Data Security, Inc.                                        **
** **************************************************************************
*/

/* 
** To use MD4:
**   -- Include md4.h in your program
**   -- Declare an MDstruct MD to hold the state of the digest computation.
**   -- Initialize MD using MDbegin(&MD)
**   -- For each full block (64 bytes) X you wish to process, call
**          MDupdate(&MD,X,512)
**      (512 is the number of bits in a full block.)
**   -- For the last block (less than 64 bytes) you wish to process,
**          MDupdate(&MD,X,n)
**      where n is the number of bits in the partial block. A partial
**      block terminates the computation, so every MD computation should
**      terminate by processing a partial block, even if it has n = 0.
**   -- The message digest is available in MD->buffer[0]...MD->buffer[3].
**   -- You can print out the digest using MDprint(&MD)
*/

/* Implementation notes:
** This implementation assumes that int's are 32-bit quantities, and
** that ints are stored so that a pointer to an int actually points
** to the low-order byte of that int.  Some work is needed (at the
** places where byte-ordering sensitivity is indicated) to make this 
** code portable to other kinds of machines.
*/

/* Compile-time includes 
*/
#include <stdio.h>
#include "md4.h"

/* Compile-time declarations of MD4 ``magic constants''.
*/
#define I0  0x67452301       /* Initial values for MD buffer */
#define I1  0xefcdab89
#define I2  0x98badcfe
#define I3  0x10325476
#define C2  013240474631     /* round 1 constant = sqrt(2) in octal */
#define C3  015666365641     /* round 2 constant = sqrt(3) in octal */
/* C2 and C3 are from Knuth, The Art of Programming, Volume 2
** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
** Table 2, page 660.
*/
#define fs1  3               /* round 1 shift amounts */
#define fs2  7   
#define fs3 11  
#define fs4 19  
#define gs1  3               /* round 2 shift amounts */
#define gs2  5   
#define gs3  9   
#define gs4 13  
#define hs1  3               /* round 3 shift amounts */
#define hs2  9 
#define hs3 11 
#define hs4 15


/* Compile-time macro declarations for MD4.
** Note: The ``rot'' operator uses the variable ``tmp''.
** It assumes tmp is declared as unsigned int, so that the >>
** operator will shift in zeros rather than extending the sign bit.
*/
#define	f(X,Y,Z) 	     ((X&Y) | ((~X)&Z))
#define	g(X,Y,Z) 	     ((X&Y) | (X&Z) | (Y&Z))
#define h(X,Y,Z)             (X^Y^Z)
#define rot(X,S) 	     (tmp=X,(tmp<<S) | (tmp>>(32-S)))
#define ff(A,B,C,D,i,s)	     A = rot((A + f(B,C,D) + X[i]),s)
#define gg(A,B,C,D,i,s)	     A = rot((A + g(B,C,D) + X[i] + C2),s)
#define hh(A,B,C,D,i,s)      A = rot((A + h(B,C,D) + X[i] + C3),s)

/* MDprint(MD)
** Print message digest buffer MD as 32 hexadecimal digits.
** Order is from low-order byte of buffer[0] to high-order byte of buffer[3].
** Each byte is printed with high-order he


From hoptoad!gnu Mon Mar 12 06:24:04 1990
Received: from hoptoad.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA16437; Mon, 12 Mar 90 06:24:01 -0500
From: hoptoad!gnu
Received: from localhost by hop.toad.com id AA18297; Mon, 12 Mar 90 03:03:04 PST
Message-Id: <9003121103.AA18297@hop.toad.com>
To: uunet!rick
Cc: gnu
Subject: Minor patch to vnews
Date: Mon, 12 Mar 90 03:03:02 -0800
Status: RO

This patch, applied to 2.11.19 visual.c, avoids a zero-pointer
coredump when doing a 'p' command where the previous article has been
expired by C expire.  C expire leaves history lines with a single tab
and no trailing tabs or spaces.  The code ignored the possibility of a
zero return from index() when looking for the tabs.  The new code
just reports that the article is expired if it can't find the tabs.

It's tested and working.

	John

*** visual.c.mainline	Mon Mar 12 02:23:31 1990
--- visual.c	Mon Mar 12 02:28:30 1990
***************
*** 855,861 ****
--- 855,863 ----
  			break;
  		}
  		ptr2 = index(ptr1, '\t');
+ 		if (!ptr2) goto gonezo;
  		ptr3 = index(++ptr2, '\t');
+ 		if (!ptr3) goto gonezo;
  		ptr2 = index(++ptr3, ' ');
  		if (ptr2)
  			*ptr2 = '\0';
***************
*** 864,869 ****
--- 866,872 ----
  			if (STRCMP(ptr3, "cancelled") == 0)
  				msg("%s has been cancelled", linebuf);
  			else
+ 	gonezo:
  				msg("%s has expired", linebuf);
  			break;
  		}

From trinkle@cs.purdue.edu Fri Mar 16 01:11:53 1990
Received: from arthur.cs.purdue.edu by uunet.uu.net (5.61/1.14) with SMTP 
	id AA11290; Fri, 16 Mar 90 01:11:48 -0500
Received: from bors.cs.purdue.edu by arthur.cs.purdue.edu (5.61/PURDUE_CS-1.2)
	id <AA25287@arthur.cs.purdue.edu>; Fri, 16 Mar 90 01:10:47 -0500
Received: from localhost by bors.cs.purdue.edu (5.61/PURDUE_CS-1.2)
	id <AA03467@bors.cs.purdue.edu>; Fri, 16 Mar 90 01:10:46 -0500
Message-Id: <9003160610.AA03467@bors.cs.purdue.edu>
To: rick@uunet.uu.net
Subject: Bnews 2.11 patches 18 and 19
Date: Fri, 16 Mar 90 01:10:43 EST
From: trinkle@cs.purdue.edu
Status: R

     I just applied patches 18 and 19 for Bnews and I noticed someone
added bogus @exit 1 lines to the targets that are supposed to fail.
Unfortunately all versions of make that I know of fail with this in a
bogus way because it cannot load "exit".  They should really be
@false commands instead, because false does exist on every UNIX system
I have ever seen.  The result is the same, but it just seems a bit
cleaner.

Daniel Trinkle			trinkle@cs.purdue.edu
Dept. of Computer Sciences	{backbone}!purdue!trinkle
Purdue University		317-494-7844
West Lafayette, IN 47907

From dunike!fesk!sverre%boulder@uunet.uu.net Sun Nov 12 17:46:35 1989
Received: from seismo.CSS.GOV by uunet.uu.net (5.61/1.14) with SMTP 
	id AA22035; Sun, 12 Nov 89 17:46:24 -0500
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.61/1.14)
	id AA16252; Sun, 12 Nov 89 17:45:42 -0500
Received: from seismo.CSS.GOV by beno.CSS.GOV (4.0/SMI-4.0)
	id AA00358; Sun, 12 Nov 89 17:46:19 EST
Received: from uunet.UU.NET by seismo.CSS.GOV (5.61/1.14)
	id AA16247; Sun, 12 Nov 89 17:45:36 -0500
Received: from nike.cair.du.edu by uunet.uu.net (5.61/1.14) with SMTP 
	id AA21953; Sun, 12 Nov 89 17:46:04 -0500
Received: by boulder.Colorado.EDU (cu-hub.890824)
Received: by fesk.UUCP (smail2.5)
	id AA02326; 12 Nov 89 15:08:55 MST (Sun)
Subject: B news patchlevel 19
To: rick@uunet.uu.net
Date: Sun, 12 Nov 89 15:08:47 MST
X-Mailer: ELM [version 2.2 PL9]
Message-Id: <8911121508.AA02326@fesk.UUCP>
From: dunike!fesk!sverre@uunet.uu.net (Sverre Froyen)
Status: RO

Rick,
Here are some changes I made to the B 2.11 news software patchlevel 19.
You may want to consider them for a future release.  The changes in
sendbatch.sh were necessary to make it run.  The changes in batch.c
terminates the error listing of missing articles after ~30 lines.
The Makefile.dst changes were needed because inews and rnews reside
on different partitions.  Finally, if you could I would like your
comments on the changes I made to inews.c.  I made these changes
to get patchlevel 17 to run (I got multiple copies of rnews -U),
however, no one else seems to have had problems and patches 18 and
19 contain no changes for this section of code.

Thanks -- Sverre

-- 
Sverre Froyen
UUCP:   boulder!fesk!sverre, sunpeaks!seri!fesk!sverre
ARPA:   sverre@fesk.seri.gov
BITNET: froyen@csugold.bitnet


*** save/Makefile.dst	Sat Nov 11 13:22:31 1989
--- Makefile.dst	Sat Nov 11 13:50:20 1989
***************
*** 168,173
  		$(DESTDIR)$(LIBDIR)
  	-rm -f $(DESTDIR)$(BINDIR)/rnews 
  	${LNRNEWS} $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews
  	chmod 6755 $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews
  	$(INSCOMPRESS)
  #VMS 	vms -v @euninstal

--- 168,175 -----
  		$(DESTDIR)$(LIBDIR)
  	-rm -f $(DESTDIR)$(BINDIR)/rnews 
  	${LNRNEWS} $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews
+ 	chgrp $(NEWSGRP) $(DESTDIR)$(BINDIR)/rnews
+ 	chown $(NEWSUSR) $(DESTDIR)$(BINDIR)/rnews
  	chmod 6755 $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews
  	$(INSCOMPRESS)
  #VMS 	vms -v @euninstal
*** save/batch.c	Sun Nov 12 10:46:13 1989
--- batch.c	Sun Nov 12 10:57:04 1989
***************
*** 64,69
  	char workfile[512];
  	char cbuf[BUFSIZ];
  	char *index(), *fgets();
  
  	if (argc < 2) {
  		fprintf(stderr, "Usage: batch listfile [bytecount]\n");

--- 64,70 -----
  	char workfile[512];
  	char cbuf[BUFSIZ];
  	char *index(), *fgets();
+ 	int maxerror = 30;
  
  	if (argc < 2) {
  		fprintf(stderr, "Usage: batch listfile [bytecount]\n");
***************
*** 115,121
  			nfd = fopen(fname, "r");
  			
  		if (nfd == NULL) {
! 			perror(fname);
  			continue;
  		}
  		(void) fstat(fileno(nfd), &sbuf);

--- 116,125 -----
  			nfd = fopen(fname, "r");
  			
  		if (nfd == NULL) {
! 			if (--maxerror > 0)
! 				perror(fname);
! 			else if (maxerror == 0)
! 				fprintf(stderr, "batch: additional articles missing\n");
  			continue;
  		}
  		(void) fstat(fileno(nfd), &sbuf);
*** save/inews.c	Sat Nov 11 13:26:08 1989
--- inews.c	Sat Nov 11 14:37:08 1989
***************
*** 1558,1564
  	/* assume a dead lock if the active file is over 12 hours old */
  	if (ret < 0 &&
  		(errno != EEXIST ||
! 		(stat(bfr, &stbuf) == 0 &&
  		(time((char *)0) - stbuf.st_mtime) < DAYS/2))) {
  			if (errno != EEXIST)
  #endif /* V7 */

--- 1558,1564 -----
  	/* assume a dead lock if the active file is over 12 hours old */
  	if (ret < 0 &&
  		(errno != EEXIST ||
! 		(stat(spbuf, &stbuf) != 0 ||
  		(time((char *)0) - stbuf.st_mtime) < DAYS/2))) {
  			if (errno != EEXIST)
  #endif /* V7 */
*** save/sendbatch.sh	Sun Nov 12 09:42:56 1989
--- sendbatch.sh	Sun Nov 12 10:33:34 1989
***************
*** 73,79
  
  	if test -n "$SPOOLDISK"
  	then
! 		df=`df $SPOOLDISK | awk '
  			$6 == "'$SPOOLDISK'" {print $4;exit}
  			$1 == "'$SPOOLDISK'" && NF == 7 {print $4;exit}
  			$2 == "'$SPOOLDISK'" {print $5;exit}

--- 73,79 -----
  
  	if test -n "$SPOOLDISK"
  	then
! 		df=`df $SPOOLDISK | sed 's/(/ (/' | awk '
  			$6 == "'$SPOOLDISK'" {print $4;exit}
  			$1 == "'$SPOOLDISK'" && NF == 7 {print $4;exit}
  			$2 == "'$SPOOLDISK'" {print $5;exit}
***************
*** 86,92
  		fi
  	fi
  
! 	if test -n "$MAXBATCH" -a -d /usr/spool/uucp/$rmt
  	then
  		du=`du "/usr/spool/uucp/$rmt" | sed 's/	.*/000/'`
  		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)

--- 86,92 -----
  		fi
  	fi
  
! 	if test -n "$MAXBATCH"
  	then
  		if test -d /usr/spool/uucp/$rmt
  		then
***************
*** 88,94
  
  	if test -n "$MAXBATCH" -a -d /usr/spool/uucp/$rmt
  	then
! 		du=`du "/usr/spool/uucp/$rmt" | sed 's/	.*/000/'`
  		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)
  		then 
  			echo $rmt already has $du Kbytes queued

--- 88,102 -----
  
  	if test -n "$MAXBATCH"
  	then
! 		if test -d /usr/spool/uucp/$rmt
! 		then
! 			du=`du "/usr/spool/uucp/$rmt" | sed 's/	.*/000/'`
! 		elif test -f /tmp/uuq.output
! 		then
! 			du=`grep $rmt /tmp/uuq.output | cut -f4`
! 		else
! 			du=
! 		fi
  		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)
  		then 
  			echo $rmt already has $du bytes queued
***************
*** 91,97
  		du=`du "/usr/spool/uucp/$rmt" | sed 's/	.*/000/'`
  		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)
  		then 
! 			echo $rmt already has $du Kbytes queued
  			continue
  		fi
  	fi

--- 99,105 -----
  		fi
  		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)
  		then 
! 			echo $rmt already has $du bytes queued
  			continue
  		fi
  	fi
***************
*** 114,120
  
  	# make sure $? is zero
  	sentbytes=0
! 	bytes_this_batch=`expr $MAXBATCH - $du`
  	if test $bytes_this_batch -gt $MAXPERRUN
  	then
  		bytes_this_batch=$MAXPERRUN

--- 122,132 -----
  
  	# make sure $? is zero
  	sentbytes=0
! 	bytes_this_batch=$MAXBATCH
! 	if test ! -z "$du"
! 	then
! 		bytes_this_batch=`expr $bytes_this_batch - $du`
! 	fi
  	if test $bytes_this_batch -gt $MAXPERRUN
  	then
  		bytes_this_batch=$MAXPERRUN

From dunike!fesk!sverre%boulder@uunet.uu.net Sun Nov 12 17:46:35 1989
Received: from seismo.CSS.GOV by uunet.uu.net (5.61/1.14) with SMTP 
	id AA22035; Sun, 12 Nov 89 17:46:24 -0500
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.61/1.14)
	id AA16252; Sun, 12 Nov 89 17:45:42 -0500
Received: from seismo.CSS.GOV by beno.CSS.GOV (4.0/SMI-4.0)
	id AA00358; Sun, 12 Nov 89 17:46:19 EST
Received: from uunet.UU.NET by seismo.CSS.GOV (5.61/1.14)
	id AA16247; Sun, 12 Nov 89 17:45:36 -0500
Received: from nike.cair.du.edu by uunet.uu.net (5.61/1.14) with SMTP 
	id AA21953; Sun, 12 Nov 89 17:46:04 -0500
Received: by boulder.Colorado.EDU (cu-hub.890824)
Received: by fesk.UUCP (smail2.5)
	id AA02326; 12 Nov 89 15:08:55 MST (Sun)
Subject: B news patchlevel 19
To: rick@uunet.uu.net
Date: Sun, 12 Nov 89 15:08:47 MST
X-Mailer: ELM [version 2.2 PL9]
Message-Id: <8911121508.AA02326@fesk.UUCP>
From: dunike!fesk!sverre@uunet.uu.net (Sverre Froyen)
Status: RO

Rick,
Here are some changes I made to the B 2.11 news software patchlevel 19.
You may want to consider them for a future release.  The changes in
sendbatch.sh were necessary to make it run.  The changes in batch.c
terminates the error listing of missing articles after ~30 lines.
The Makefile.dst changes were needed because inews and rnews reside
on different partitions.  Finally, if you could I would like your
comments on the changes I made to inews.c.  I made these changes
to get patchlevel 17 to run (I got multiple copies of rnews -U),
however, no one else seems to have had problems and patches 18 and
19 contain no changes for this section of code.

Thanks -- Sverre

-- 
Sverre Froyen
UUCP:   boulder!fesk!sverre, sunpeaks!seri!fesk!sverre
ARPA:   sverre@fesk.seri.gov
BITNET: froyen@csugold.bitnet


*** save/Makefile.dst	Sat Nov 11 13:22:31 1989
--- Makefile.dst	Sat Nov 11 13:50:20 1989
***************
*** 168,173
  		$(DESTDIR)$(LIBDIR)
  	-rm -f $(DESTDIR)$(BINDIR)/rnews 
  	${LNRNEWS} $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews
  	chmod 6755 $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews
  	$(INSCOMPRESS)
  #VMS 	vms -v @euninstal

--- 168,175 -----
  		$(DESTDIR)$(LIBDIR)
  	-rm -f $(DESTDIR)$(BINDIR)/rnews 
  	${LNRNEWS} $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews
+ 	chgrp $(NEWSGRP) $(DESTDIR)$(BINDIR)/rnews
+ 	chown $(NEWSUSR) $(DESTDIR)$(BINDIR)/rnews
  	chmod 6755 $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews
  	$(INSCOMPRESS)
  #VMS 	vms -v @euninstal
*** save/batch.c	Sun Nov 12 10:46:13 1989
--- batch.c	Sun Nov 12 10:57:04 1989
***************
*** 64,69
  	char workfile[512];
  	char cbuf[BUFSIZ];
  	char *index(), *fgets();
  
  	if (argc < 2) {
  		fprintf(stderr, "Usage: batch listfile [bytecount]\n");

--- 64,70 -----
  	char workfile[512];
  	char cbuf[BUFSIZ];
  	char *index(), *fgets();
+ 	int maxerror = 30;
  
  	if (argc < 2) {
  		fprintf(stderr, "Usage: batch listfile [bytecount]\n");
***************
*** 115,121
  			nfd = fopen(fname, "r");
  			
  		if (nfd == NULL) {
! 			perror(fname);
  			continue;
  		}
  		(void) fstat(fileno(nfd), &sbuf);

--- 116,125 -----
  			nfd = fopen(fname, "r");
  			
  		if (nfd == NULL) {
! 			if (--maxerror > 0)
! 				perror(fname);
! 			else if (maxerror == 0)
! 				fprintf(stderr, "batch: additional articles missing\n");
  			continue;
  		}
  		(void) fstat(fileno(nfd), &sbuf);
*** save/inews.c	Sat Nov 11 13:26:08 1989
--- inews.c	Sat Nov 11 14:37:08 1989
***************
*** 1558,1564
  	/* assume a dead lock if the active file is over 12 hours old */
  	if (ret < 0 &&
  		(errno != EEXIST ||
! 		(stat(bfr, &stbuf) == 0 &&
  		(time((char *)0) - stbuf.st_mtime) < DAYS/2))) {
  			if (errno != EEXIST)
  #endif /* V7 */

--- 1558,1564 -----
  	/* assume a dead lock if the active file is over 12 hours old */
  	if (ret < 0 &&
  		(errno != EEXIST ||
! 		(stat(spbuf, &stbuf) != 0 ||
  		(time((char *)0) - stbuf.st_mtime) < DAYS/2))) {
  			if (errno != EEXIST)
  #endif /* V7 */
*** save/sendbatch.sh	Sun Nov 12 09:42:56 1989
--- sendbatch.sh	Sun Nov 12 10:33:34 1989
***************
*** 73,79
  
  	if test -n "$SPOOLDISK"
  	then
! 		df=`df $SPOOLDISK | awk '
  			$6 == "'$SPOOLDISK'" {print $4;exit}
  			$1 == "'$SPOOLDISK'" && NF == 7 {print $4;exit}
  			$2 == "'$SPOOLDISK'" {print $5;exit}

--- 73,79 -----
  
  	if test -n "$SPOOLDISK"
  	then
! 		df=`df $SPOOLDISK | sed 's/(/ (/' | awk '
  			$6 == "'$SPOOLDISK'" {print $4;exit}
  			$1 == "'$SPOOLDISK'" && NF == 7 {print $4;exit}
  			$2 == "'$SPOOLDISK'" {print $5;exit}
***************
*** 86,92
  		fi
  	fi
  
! 	if test -n "$MAXBATCH" -a -d /usr/spool/uucp/$rmt
  	then
  		du=`du "/usr/spool/uucp/$rmt" | sed 's/	.*/000/'`
  		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)

--- 86,92 -----
  		fi
  	fi
  
! 	if test -n "$MAXBATCH"
  	then
  		if test -d /usr/spool/uucp/$rmt
  		then
***************
*** 88,94
  
  	if test -n "$MAXBATCH" -a -d /usr/spool/uucp/$rmt
  	then
! 		du=`du "/usr/spool/uucp/$rmt" | sed 's/	.*/000/'`
  		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)
  		then 
  			echo $rmt already has $du Kbytes queued

--- 88,102 -----
  
  	if test -n "$MAXBATCH"
  	then
! 		if test -d /usr/spool/uucp/$rmt
! 		then
! 			du=`du "/usr/spool/uucp/$rmt" | sed 's/	.*/000/'`
! 		elif test -f /tmp/uuq.output
! 		then
! 			du=`grep $rmt /tmp/uuq.output | cut -f4`
! 		else
! 			du=
! 		fi
  		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)
  		then 
  			echo $rmt already has $du bytes queued
***************
*** 91,97
  		du=`du "/usr/spool/uucp/$rmt" | sed 's/	.*/000/'`
  		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)
  		then 
! 			echo $rmt already has $du Kbytes queued
  			continue
  		fi
  	fi

--- 99,105 -----
  		fi
  		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)
  		then 
! 			echo $rmt already has $du bytes queued
  			continue
  		fi
  	fi
***************
*** 114,120
  
  	# make sure $? is zero
  	sentbytes=0
! 	bytes_this_batch=`expr $MAXBATCH - $du`
  	if test $bytes_this_batch -gt $MAXPERRUN
  	then
  		bytes_this_batch=$MAXPERRUN

--- 122,132 -----
  
  	# make sure $? is zero
  	sentbytes=0
! 	bytes_this_batch=$MAXBATCH
! 	if test ! -z "$du"
! 	then
! 		bytes_this_batch=`expr $bytes_this_batch - $du`
! 	fi
  	if test $bytes_this_batch -gt $MAXPERRUN
  	then
  		bytes_this_batch=$MAXPERRUN

From graham@tsmith.UUCP Thu Nov 16 18:22:05 1989
Path: uunet!allbery
From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Newsgroups: comp.sources.misc
Subject: v09i005: 16 bit compress for MSDOS
Message-ID: <72090@uunet.UU.NET>
Date: 16 Nov 89 23:22:05 GMT
Sender: allbery@uunet.UU.NET
Reply-To: graham@tsmith.UUCP
Lines: 1347
Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)

Posting-number: Volume 9, Issue 5
Submitted-by: graham@tsmith.UUCP
Archive-name: compress.ms

    Recently, there have been people looking for source for compress.c to run
under MSDOS. Here is one that may fit the bill.

Doug.

------------------------------ Cut Here ------------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of shell archive."
# Contents:  README makefile compress.c
# Wrapped by graham@tsmith on Wed Nov 15 20:52:00 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(609 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XHere is a version of compress 4.0 hacked for MSDOS. A makefile is provided
Xwhich will compile it using Microsoft C, Turbo C, or Zortech C. The makefile
Xwill need editing if other than the Microsoft compiler is used.
XThe program requires about 400K to run. It takes the same command line
Xargs as does the UNIX program of the same name, and should be compatible
Xin all ways with that program. It will decode a 16 bit compressed file,
Xand can generate the same. On my machine, it decodes about twice as quickly
Xas the "u16" decompress program posted earlier to c.s.m.
X
XDoug Graham.
Xuunet!mitel!sce!tsmith!graham
END_OF_FILE
if test 609 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile'\"
else
echo shar: Extracting \"'makefile'\" \(1083 characters\)
sed "s/^X//" >'makefile' <<'END_OF_FILE'
X#
X# Makefile for compress.
X#
X# If memory usage is a problem under DOS, you may want to do a
X#
X#	"exemod compress.exe /MAX 0"
X#
X# in order to reduce the size of the near heap. If this is done on the
X# Microsoft executable, memory requirements drop to about 380K from 410K
X# Depending on how the other compilers manage their near/far heaps, this
X# should have similar results there as well.
X#
X
XDOSDEFS =  -Di8088 -DMSDOS -DPROTO
X
X#
X# Microsoft C 5.0 under MSDOS
X#
X# The resulting executable is faster by about 20% than either Turbo C,
X# or Zortech C.
X#
Xcompress.exe: compress.c
X	cl -o compress.exe -W3 -Ox -DMSC $(DOSDEFS) compress.c
X
X#
X# Turbo C 2.0 under MSDOS
X#
X# compress.exe: compress.c
X# 	tcc -ecompress.exe -Z -O -G -w $(DOSDEFS) compress.c
X
X#
X# Zortech C under MSDOS
X#
X# compress.exe: compress.c
X# 	ztc -ocompress.exe -o $(DOSDEFS) compress.c
X
X#
X# Sun OS 3.5.
X# Compression is slightly slower than /usr/ucb/compress probably
X# because the compiler is doing lots of "extl"'s. Decompression
X# is slightly faster.
X#
X# compress:	compress.c
X# 	cc -O -DBSD4_2 -o compress compress.c
END_OF_FILE
if test 1083 -ne `wc -c <'makefile'`; then
    echo shar: \"'makefile'\" unpacked with wrong size!
fi
# end of 'makefile'
fi
if test -f 'compress.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'compress.c'\"
else
echo shar: Extracting \"'compress.c'\" \(32700 characters\)
sed "s/^X//" >'compress.c' <<'END_OF_FILE'
X/* 
X * Compress - data compression program 
X */
Xstatic char rcs_ident[] = "@(#) compress,v 4.1 (DOS) 89/11/10 02:43:00 doug Release $";
X
X/*
X * compress.c - File compression ala IEEE Computer, June 1984.
X *
X * Authors:	Spencer W. Thomas	(decvax!harpo!utah-cs!utah-gr!thomas)
X *		Jim McKie		(decvax!mcvax!jim)
X *		Steve Davies		(decvax!vax135!petsd!peora!srd)
X *		Ken Turkowski		(decvax!decwrl!turtlevax!ken)
X *		James A. Woods		(decvax!ihnp4!ames!jaw)
X *		Joe Orost		(decvax!vax135!petsd!joe)
X *		Doug Graham		(uunet!mitel!sce!tsmith!graham)
X *
X * Revision 4.1 (DOS) 89/11/10 02:43:00 doug
X * Ported to MSDOS. Still works elsewhere, but maybe not as quickly.
X * Removed as much long arithmetic as possible for speed on 16 bit machines.
X * Use unsigned short's instead. Changed secondary hashing function to limit
X * hash table size to 64K. This means table indexes can be 16 bit shorts.
X * This compress will not generate codes from MAXMAXCODE (0xf000) thru
X * 0xffff. Doesn't appear to hurt compression much. Removed speed hacks for
X * other machines so I could understand the code. Added some for the i8088.
X * Send CLEAR immediately when hash table fills instead of waiting for the
X * compression ratio to drop. This is faster, and in some cases improves
X * compression (but more often reduces it slightly). Junked the variable
X * size hash table stuff because I am depending on 16 bit unsigned integer
X * wrap around for indexing into hash table, so the table must have 2^16
X * entries. Took out the XENIX_16 stuff. The DOS way ought to work on Xenix
X * as well, and should be faster, but I don't have access to Xenix in order
X * to find out. Added some extra error checking on decompression to try to
X * avoid blowing the machine out of the water when decompressing a corrupt
X * file. Add "okunlink" to avoid the problem of losing the output file as
X * well as the input file if ^C is hit at the wrong time. Lot's of other
X * cosmetic changes.
X *
X * Revision 4.0  85/07/30  12:50:00  joe
X * Removed ferror() calls in output routine on every output except first.
X * Prepared for release to the world.
X * 
X * Revision 3.6  85/07/04  01:22:21  joe
X * Remove much wasted storage by overlaying hash table with the tables
X * used by decompress: tab_suffix[1<<BITS], stack[8000].  Updated USERMEM
X * computations.  Fixed dump_tab() DEBUG routine.
X *
X * Revision 3.5  85/06/30  20:47:21  jaw
X * Change hash function to use exclusive-or.  Rip out hash cache.  These
X * speedups render the megamemory version defunct, for now.  Make decoder
X * stack global.  Parts of the RCS trunks 2.7, 2.6, and 2.1 no longer apply.
X *
X * Revision 3.4  85/06/27  12:00:00  ken
X * Get rid of all floating-point calculations by doing all compression ratio
X * calculations in fixed point.
X *
X * Revision 3.3  85/06/24  21:53:24  joe
X * Incorporate portability suggestion for M_XENIX.  Got rid of text on #else
X * and #endif lines.  Cleaned up #ifdefs for vax and interdata.
X *
X * Revision 3.2  85/06/06  21:53:24  jaw
X * Incorporate portability suggestions for Z8000, IBM PC/XT from mailing list.
X * Default to "quiet" output (no compression statistics).
X *
X * Revision 3.1  85/05/12  18:56:13  jaw
X * Integrate decompress() stack speedups (from early pointer mods by McKie).
X * Repair multi-file USERMEM gaffe.  Unify 'force' flags to mimic semantics
X * of SVR2 'pack'.  Streamline block-compress table clear logic.  Increase 
X * output byte count by magic number size.
X * 
X * Revision 3.0   84/11/27  11:50:00  petsd!joe
X * Set HSIZE depending on BITS.  Set BITS depending on USERMEM.  Unrolled
X * loops in clear routines.  Added "-C" flag for 2.0 compatibility.  Used
X * unsigned compares on Perkin-Elmer.  Fixed foreground check.
X *
X * Revision 2.7   84/11/16  19:35:39  ames!jaw
X * Cache common hash codes based on input statistics; this improves
X * performance for low-density raster images.  Pass on #ifdef bundle
X * from Turkowski.
X *
X * Revision 2.6   84/11/05  19:18:21  ames!jaw
X * Vary size of hash tables to reduce time for small files.
X * Tune PDP-11 hash function.
X *
X * Revision 2.5   84/10/30  20:15:14  ames!jaw
X * Junk chaining; replace with the simpler (and, on the VAX, faster)
X * double hashing, discussed within.  Make block compression standard.
X *
X * Revision 2.4   84/10/16  11:11:11  ames!jaw
X * Introduce adaptive reset for block compression, to boost the rate
X * another several percent.  (See mailing list notes.)
X *
X * Revision 2.3   84/09/22  22:00:00  petsd!joe
X * Implemented "-B" block compress.  Implemented REVERSE sorting of tab_next.
X * Bug fix for last bits.  Changed fwrite to putchar loop everywhere.
X *
X * Revision 2.2   84/09/18  14:12:21  ames!jaw
X * Fold in news changes, small machine typedef from thomas,
X * #ifdef interdata from joe.
X *
X * Revision 2.1   84/09/10  12:34:56  ames!jaw
X * Configured fast table lookup for 32-bit machines.
X * This cuts user time in half for b <= FBITS, and is useful for news batching
X * from VAX to PDP sites.  Also sped up decompress() [fwrite->putc] and
X * added signal catcher [plus beef in writeerr()] to delete effluvia.
X *
X * Revision 2.0   84/08/28  22:00:00  petsd!joe
X * Add check for foreground before prompting user.  Insert maxbits into
X * compressed file.  Force file being uncompressed to end with ".Z".
X * Added "-c" flag and "zcat".  Prepared for release.
X *
X * Revision 1.10  84/08/24  18:28:00  turtlevax!ken
X * Will only compress regular files (no directories), added a magic number
X * header (plus an undocumented -n flag to handle old files without headers),
X * added -f flag to force overwriting of possibly existing destination file,
X * otherwise the user is prompted for a response.  Will tack on a .Z to a
X * filename if it doesn't have one when decompressing.  Will only replace
X * file if it was compressed.
X *
X * Revision 1.9  84/08/16  17:28:00  turtlevax!ken
X * Removed scanargs(), getopt(), added .Z extension and unlimited number of
X * filenames to compress.  Flags may be clustered (-Ddvb12) or separated
X * (-D -d -v -b 12), or combination thereof.  Modes and other status is
X * copied with copystat().  -O bug for 4.2 seems to have disappeared with
X * 1.8.
X *
X * Revision 1.8  84/08/09  23:15:00  joe
X * Made it compatible with vax version, installed jim's fixes/enhancements
X *
X * Revision 1.6  84/08/01  22:08:00  joe
X * Sped up algorithm significantly by sorting the compress chain.
X *
X * Revision 1.5  84/07/13  13:11:00  srd
X * Added C version of vax asm routines.  Changed structure to arrays to
X * save much memory.  Do unsigned compares where possible (faster on
X * Perkin-Elmer)
X *
X * Revision 1.4  84/07/05  03:11:11  thomas
X * Clean up the code a little and lint it.  (Lint complains about all
X * the regs used in the asm, but I'm not going to "fix" this.)
X *
X * Revision 1.3  84/07/05  02:06:54  thomas
X * Minor fixes.
X *
X * Revision 1.2  84/07/05  00:27:27  thomas
X * Add variable bit length output.
X *
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#ifndef __ZTC__
X#include <malloc.h>
X#endif
X#ifndef BSD4_2
X#include <stdlib.h>
X#include <io.h>
X#endif
X#include <string.h>
X#include <fcntl.h>
X#ifdef MSDOS
X#include <dos.h>
X#endif
X
X#ifdef PROTO
X/*
X * Zortech appears to be missing this prototype, and MSC uses some
X * silly structure as the second arg. Turbo C doesn't support this
X * call at all.
X */
Xextern int utime(char *path, time_t times[]);
X#endif
X
X#define BITS		16		/* max number of bits/code */
X#define INIT_BITS	9		/* initial number of bits/code */
X
X#define MAXCODE(n_bits)		((code_t)((1L << (n_bits)) - 1))
X
X/*
X * Magic numbers which should appear at the beginning of a compressed file.
X */
X#define MAGIC0	0x1f
X#define MAGIC1	0x9d
X
X/*
X * Defines for third byte of header
X */
X#define BIT_MASK	0x1f
X#define BLOCK_MASK	0x80
X
X#if 0
X#define CHECK_GAP	10000		/* ratio check interval */
X#endif
X
X/*
X * the next two codes should not be changed lightly, as they must not
X * lie within the contiguous general code space.
X */ 
X#define FIRST	257		/* first free entry */
X#define	CLEAR	256		/* table clear output code */
X
X#define DE_STACKLEN	8192	/* Size of decoder stack */
X
X#define HSIZE	(1L << 16)	/* Size of the hash table. Don't change this */
X
Xtypedef unsigned char	uchar;
Xtypedef unsigned long	ulong;
Xtypedef unsigned short	code_t;
Xtypedef	unsigned short	hash_t;
X
X#ifdef PROTO
X#define ARGS(x)	x
X#else
X#define ARGS(x)	()
X#endif
X
Xvoid		main ARGS((int argc, char **argv));
Xvoid		Usage ARGS((void));
Xvoid		version ARGS((void));
Xvoid		compress ARGS((void));
Xvoid		decompress ARGS((void));
Xvoid		copystat ARGS((void));
Xvoid		writeerr ARGS((void));
Xvoid		cl_hash ARGS((void));
Xvoid		putcode ARGS((code_t code));
Xvoid		prratio ARGS((long num, long den));
Xint		ofopen ARGS((char *filename));
Xint		ifopen ARGS((char *filename));
Xint		check_magic ARGS((void));
Xint		need_clear ARGS((void));
Xvoid		onintr ARGS(());
Xvoid		oops ARGS(());
Xint		taballoc ARGS((void));
Xvoid		clearhash ARGS((void));
X
X/*
X * block compression parameters -- after all codes are used up,
X * and compression rate changes, start over.
X */
Xint		block_compress = BLOCK_MASK;
X
Xint		maxbits = BITS;		/* user settable max # bits/code */
Xint		magic = 1;		/* 3-byte magic number header */
Xint		zcat_flg = 0;		/* Output on stdout */
Xint		verbose = 0;		/* don't tell me about compression */
Xint		force = 0;		/* Force overwrite of output file */
Xint		do_decomp = 0;		/* Decompress rather than compress. */
Xchar		ofname[100];		/* Output file name */
Xint		foreground;		/* Running in foreground? */
Xint		exit_stat = 0;		/* Exit status */
Xuchar		bitbuf[BITS+2];		/* For (dis)assembling code bytes */
Xint		okunlink;		/* OK for sig handler to unlink output file */
Xchar		*ifname;
X
X#ifdef i8088
X
Xuchar		*de_stack;
Xuchar far	*charptr1;
Xuchar far	*codeptrs1[2];
Xuchar far	*codeptrs2[2];
X
X#define de_suffixof(i)	charptr1[i]
X#define de_prefixof(i)	(*(code_t far *)&codeptrs1[i&1][i&~1])
X
X#define en_hashchar(i)	charptr1[i]
X#define en_hashent(i)	(*(code_t far *)&codeptrs1[i&1][i&~1])
X#define en_hashcode(i)	(*(code_t far *)&codeptrs2[i&1][i&~1])
X
X#ifndef MK_FP
X#define MK_FP(seg, ofs) \
X	((void far *)(((ulong)(seg) << 16) | (unsigned)(ofs)))
X#endif
X
X#define	PARA	16		/* Size of a paragraph */
X
X/*
X * Return a segment address which is the segment part of the normalized
X * version of "fp" rounded upwards.
X * I use this on the far pointers returned by "farmalloc". While
X * they are probably already normalized, I have never seen this
X * stated anywhere in the doc's.
X *
X * There is a lot of junk below which would be unecessary if only
X * there were a reasonably compiler independent way of allocating
X * a given number of PARAGRAPHS (like TC's allocmem). I can't find
X * one though.
X */
X#define FP_SEGCEIL(fp) \
X	(FP_SEG(fp) + (FP_OFF(fp) + PARA - 1)/PARA)
X
X/*
X * Allocate space for the tables used in {en,de}coding. These tables
X * reside in the far heap. It may seem inefficient to be using far pointers
X * for the base of these tables, because the offset portion will always be zero.
X * We could just keep the segment address of the base, and then do something
X * like:
X *		 *MK_FP(baseseg, offset) = blahblah;
X *
X * whenever we need to access the table. This SHOULD be more efficient,
X * but the compilers do not appear to generate very efficient code in this
X * case. Huge pointers are not used, because they are slow, and because
X * Zortech does not support them.
X */
X
X#ifdef MSC
X#define farmalloc(n)	halloc(n, 1)
X#endif
X
Xint taballoc()
X{
X	char far *X;
X
X	if (do_decomp) {
X		if ((de_stack = malloc(DE_STACKLEN)) == 0)
X			return (0);
X	}
X	else {
X		if ((X = farmalloc((HSIZE + PARA) * sizeof(code_t))) == 0)
X			return (0);
X		codeptrs2[0] = MK_FP(FP_SEGCEIL(X), 0);
X		codeptrs2[1] = MK_FP(FP_SEGCEIL(X) + HSIZE/PARA, 0);
X	}
X
X	if ((X = farmalloc((HSIZE + PARA) * sizeof(char))) == 0)
X		return (0);
X	charptr1 = MK_FP(FP_SEGCEIL(X), 0);
X
X	if ((X = farmalloc((HSIZE + PARA) * sizeof(code_t))) == 0)
X		return (0);
X	codeptrs1[0] = MK_FP(FP_SEGCEIL(X), 0);
X	codeptrs1[1] = MK_FP(FP_SEGCEIL(X) + HSIZE/PARA, 0);
X
X	return (1);
X}
X
X#else
X
Xuchar	chartab1[HSIZE];
Xcode_t	codetab1[HSIZE];
Xcode_t	codetab2[HSIZE];
X
X#define de_suffixof(i)	chartab1[i]
X#define de_prefixof(i)	codetab1[i]
X#define de_stack	(uchar *)codetab2
X
X#define en_hashchar(i)	chartab1[i]
X#define en_hashent(i)	codetab1[i]
X#define en_hashcode(i)	codetab2[i]
X
X#endif
X
Xvoid Usage()
X{
X	fprintf(stderr, "Usage: compress [-dfvcVnC] [-b maxbits] [file ...]\n");
X	fprintf(stderr, "	-V => print Version\n");
X	fprintf(stderr, "	-d => decompress\n");
X	fprintf(stderr, "	-v => verbose\n");
X	fprintf(stderr, "	-f => force overwrite of output file\n");
X	fprintf(stderr, "	-n => no header: useful to uncompress old files\n");
X	fprintf(stderr, "	-b maxbits => maxbits. Default %d\n", BITS);
X	fprintf(stderr, "	-c => cat all output to stdout\n");
X	fprintf(stderr, "	-C => generate output compatible with compress 2.0.\n");
X}
X
X/*****************************************************************
X * TAG( main )
X *
X * Algorithm from "A Technique for High Performance Data Compression",
X * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
X *
X * Usage: compress [-dfvc] [-b bits] [file ...]
X * Inputs:
X *	-d:	    If given, decompression is done instead.
X *
X *      -c:         Write output on stdout, don't remove original.
X *
X *      -b:         Parameter limits the max number of bits/code.
X *
X *	-f:	    Forces output file to be generated, even if one already
X *		    exists, and even if no space is saved by compressing.
X *		    If -f is not used, the user will be prompted if stdin is
X *		    a tty, otherwise, the output file will not be overwritten.
X *
X *      -v:	    Write compression statistics
X *
X * 	file ...:   Files to be compressed.  If none specified, stdin
X *		    is used.
X * Outputs:
X *	file.Z:	    Compressed form of file with same mode, owner, and utimes
X * 	or stdout   (if stdin used as input)
X *
X * Assumptions:
X *	When filenames are given, replaces with the compressed version
X *	(.Z suffix) only if the file decreases in size.
X * Algorithm:
X * 	Modified Lempel-Ziv method (LZW).  Basically finds common
X * substrings and replaces them with a variable size code.  This is
X * deterministic, and can be done on the fly.  Thus, the decompression
X * procedure needs no input table, but tracks the way the table was built.
X */
X
X#ifdef __ZTC__
X#include <int.h>
Xint silly_nonsense(struct INT_DATA *foo) {raise(SIGINT); return 1;}
X#endif
X
X#define ARGVAL() (*++(*argv) || (--argc && *++argv))
X
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X{
X	char tempname[100], *cp;
X
X	if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
X		signal(SIGINT, onintr);
X#ifdef __ZTC__
X		/*
X		 * The "signal" call above isn't good enough for Zortech
X		 */
X		int_intercept(0x23, silly_nonsense, 256);
X#endif
X#ifdef SIGSEGV
X		signal(SIGSEGV, oops);
X#endif
X		if (isatty(2))
X			foreground = 1;
X	}
X
X#ifndef MSDOS
X	if ((cp = strrchr(argv[0], '/')) != 0)
X		cp++;
X	else
X		cp = argv[0];
X#else
X	for (cp = argv[0]; *cp; cp++)
X		if (*cp == '/' || *cp == '\\')
X			argv[0] = cp + 1;
X	cp = strlwr(argv[0]);
X#endif
X	/* Limited to 8 char filenames under DOS */
X	if (strncmp(cp, "uncompress", 8) == 0)
X		do_decomp = 1;
X	else if (strncmp(cp, "zcat", 4) == 0) {
X		do_decomp = 1;
X		zcat_flg = 1;
X	}
X
X#ifdef BSD4_2
X	/* 4.2BSD dependent - take it out if not */
X	setlinebuf(stderr);
X#endif /* BSD4_2 */
X
X	for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
X		while (*++(*argv)) {	/* Process all flags in this arg */
X			switch (**argv) {
X			case 'V':
X				version();
X				break;
X			case 'v':
X				verbose = 1;
X				break;
X			case 'd':
X				do_decomp = 1;
X				break;
X			case 'f':
X			case 'F':
X				force = 1;
X				break;
X			case 'n':
X				magic = 0;
X				break;
X			case 'C':
X				block_compress = 0;
X				break;
X			case 'b':
X				if (!ARGVAL()) {
X					fprintf(stderr, "Missing maxbits\n");
X					Usage();
X					exit(1);
X				}
X				maxbits = atoi(*argv);
X				goto nextarg;
X			case 'c':
X				zcat_flg = 1;
X				break;
X			case 'q':
X				verbose = 0;
X				break;
X			default:
X				fprintf(stderr, "Unknown flag: '%c'; ", **argv);
X				Usage();
X				exit(1);
X			}
X		}
Xnextarg:;
X	}
X
X#ifdef i8088
X	if (! taballoc()) {
X		fprintf(stderr, "compress: out of memory\n");
X		exit(1);
X	}
X#endif
X	/*
X	 * If no filename args, do standard input.
X	 */
X	if (argc <= 0) {
X		if (! ifopen((char *)0) || ! ofopen((char *)0))
X			exit(1);
X
X		ifname = "stdin";
X
X		if (do_decomp) {
X			if (!check_magic())
X				exit(1);
X			decompress();
X		}
X		else {
X			compress();
X			if (verbose)
X				putc('\n', stderr);
X		}
X		exit(exit_stat);
X	}
X
X	while (--argc >= 0) {
X		char *suf;
X
X		ifname = *argv++;
X		suf = strrchr(ifname, '.');
X
X		exit_stat = 0;
X		okunlink = 0;
X
X		if (do_decomp) {		/* DECOMPRESSION */
X			if (!suf || (strcmp(suf, ".Z") && strcmp(suf, ".z"))) {
X				strcpy(tempname, ifname);
X				strcat(tempname, ".Z");
X				ifname = tempname;
X			}
X			if (! ifopen(ifname) || !check_magic())
X				continue;
X			if (zcat_flg)
X				ofname[0] = '\0';
X			else {
X				strcpy(ofname, ifname);
X				ofname[strlen(ifname) - 2] = '\0';
X			}
X			if (!ofopen(ofname))
X				continue;
X			if (!zcat_flg && verbose)
X				fprintf(stderr, "%s: ", ifname);
X			decompress();
X		}
X		else {				/* COMPRESSION */
X			if (suf && (!strcmp(suf, ".Z") || !strcmp(suf, ".z"))) {
X				fprintf(stderr, "%s: already has .Z suffix -- no change\n",
X				    ifname);
X				continue;
X			}
X			if (! ifopen(ifname))
X				continue;
X			if (zcat_flg)
X				ofname[0] = 0;
X			else {
X				strcpy(ofname, ifname);
X#ifndef MSDOS	/* We'll let ofopen do the complaining */
X#ifndef BSD4_2
X				if ((cp = strrchr(ofname, '/')) != NULL)
X					cp++;
X				else
X					cp = ofname;
X				if (strlen(cp) > 12) {
X					fprintf(stderr,"%s: filename too long to tack on .Z\n",cp);
X					continue;
X				}
X#endif
X#endif
X				strcat(ofname, ".Z");
X			}
X			if (! ofopen(ofname))
X				continue;
X			if (! zcat_flg && verbose)
X				fprintf(stderr, "%s: ", ifname);
X			compress();
X		}
X
X		if (! zcat_flg) {
X			copystat();
X			if ((exit_stat == 1) || verbose)
X				putc('\n', stderr);
X		}
X	}
X	exit(exit_stat);
X}
X
X/*
X * compress stdin to stdout
X *
X * Algorithm:  use open addressing double hashing (no chaining) on the 
X * prefix code / next character combination.  We do a variant of Knuth's
X * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
X * secondary probe.  Here, the modular division first probe is gives way
X * to a faster exclusive-or manipulation.  Also do block compression with
X * an adaptive reset, whereby the code table is cleared when the compression
X * ratio decreases, but after the table fills.  The variable-length output
X * codes are re-sized at this point, and a special CLEAR code is generated
X * for the decompressor.  Late addition:  construct the table according to
X * file size for noticeable speed improvement on small files.  Please direct
X * questions about this implementation to ames!jaw.
X *
X * Secondary hash function changed slightly for DOS. Hash table used to be
X * > 64K. This is slow on a 16 bit machine because it means long arithmetic,
X * and more complicated addressing of tables in the far address space.
X * We now restrict the table size to 64K, and, so that the table does
X * not overfill, restrict the codes that we will generate to MAXMAXCODE.
X * This causes slightly poorer compression in some cases, but, interestingly
X * enough, also causes better compression ratios in certain other cases.
X * Yes, this is all compatible with other compresses.
X */
Xstatic long	in_count;		/* length of input */
Xstatic long	out_count;		/* length of compressed output */
Xstatic long	ratio;			/* in_count/out_count * 256 */
Xstatic int	n_bits;			/* number of bits/code */
Xstatic int	n_bits8;		/* bits/code times 8 */
Xstatic int	bitoffset;		/* Offset into bitbuf */
X
X#define NOENT		((code_t)0xffff)
X#define MAXMAXCODE	((code_t)0xf000)
X
X/*
X * Clear out the hash table. We try to do this as quickly as possible, because
X * it's running time dominates for small files. For big files, it doesn't matter
X * much because it doesn't get called often. Now I understand why the original
X * had a variable size hash table.
X */
Xvoid clearhash()
X{
X#ifdef i8088
X	register unsigned i;
X	code_t far *hp;
X
X	hp = (code_t far *)codeptrs1[0];
X	i = (unsigned)(HSIZE/2);
X	do
X		*hp++ = NOENT;
X	while (--i > 0);
X
X	hp = (code_t far *)codeptrs1[1];
X	i = (unsigned)(HSIZE/2);
X	do
X		*hp++ = NOENT;
X	while (--i > 0);
X#else
X	/*
X	 * WARNING: assumes that NOENT == 0xffff
X	 */
X	memset((char *)codetab1, 0xff, HSIZE*sizeof(code_t));
X#endif
X}
X
X/*
X * Compress stdin to stdout.
X */
Xvoid compress()
X{
X	register hash_t	i;
X	register code_t	ent;
X	hash_t		disp;
X	int		c;
X	code_t		freecode;	/* first unused entry */
X	code_t		maxcode;	/* maximum code, given n_bits */
X	code_t		maxmaxcode;
X	code_t		k;
X#ifdef CHECK_GAP
X	long		checkpoint = 0;
X#endif
X
X	if (maxbits < INIT_BITS)
X		maxbits = INIT_BITS;
X	if (maxbits > BITS)
X		maxbits = BITS;
X
X	if (magic) {
X		putchar(MAGIC0); putchar(MAGIC1);
X		putchar(maxbits | block_compress);
X		if (ferror(stdout))
X			writeerr();
X	}
X
X	bitbuf[bitoffset = 0] = 0;
X	out_count = 3;			/* includes 3-byte header mojo */
X	ratio = 0;
X	in_count = 1;
X
X	n_bits = INIT_BITS;
X	n_bits8 = INIT_BITS << 3;
X	maxcode = MAXCODE(INIT_BITS);
X	maxmaxcode = MAXCODE(maxbits);
X	if (maxmaxcode > MAXMAXCODE)
X		maxmaxcode = MAXMAXCODE;
X
X	freecode = ((block_compress) ? FIRST : 256);
X
X	clearhash();
X
X	ent = getchar();
X
X	while ((c = getchar()) != EOF) {
X		in_count++;
X
X		i = (hash_t)(c << 8) ^ ent;		/* xor hashing */
X
X		if ((k = en_hashent(i)) == ent && en_hashchar(i) == (uchar)c) {
X			ent = en_hashcode(i);
X			goto Continue;
X		}
X
X		if (k != NOENT) {
X			/*
X			 * New secondary hash for 64K table.
X			 * Experiment shows that the shift by 6 works well.
X			 * Beats me why. "disp" must be relatively
X			 * prime to the table size. Since the table size is a
X			 * power of 2, this means "disp" must be odd.
X			 *
X			 * Note that we do not do a range check before doing
X			 * "i -= disp". It is assumed that the hash table size
X			 * (HSIZE) is 64K, and that the type "hash_t" (which
X			 * is unsigned short) is 16 bits. Thus it is impossible
X			 * for "i" to be out of range. On a machine with something
X			 * other than 16 bit shorts, this would have to change.
X			 */
X			disp = ((hash_t)(c << 6) ^ ent) | 1;
X			do {
X				i -= disp;
X				if ((k = en_hashent(i)) == ent &&
X				    en_hashchar(i) == (uchar)c) {
X					ent = en_hashcode(i);
X					goto Continue;
X				}
X			} while (k != NOENT);
X		}
X
X		putcode(ent);
X
X		if (freecode <= maxmaxcode) {
X			/*
X			 * Add the new entry.
X			 */
X			en_hashchar(i) = (uchar)c;
X			en_hashent(i) = ent;
X			en_hashcode(i) = freecode;
X
X			/*
X			 * If the next entry is going to be too big for the
X			 * code size, then increase it, if possible.
X			 */
X			if (freecode++ > maxcode) {
X				while (bitoffset)
X					putcode(0);
X				++n_bits;
X				n_bits8 += 8;
X				maxcode = MAXCODE(n_bits);
X			}
X		}
X#ifdef CHECK_GAP
X		else if (in_count >= checkpoint && block_compress) {
X			checkpoint = in_count + CHECK_GAP;
X			if (need_clear()) {
X#else
X		else if (block_compress) {
X			if (1) {
X#endif
X				putcode(CLEAR);
X				while (bitoffset > 0)
X					putcode(0);
X				clearhash();
X				freecode = FIRST;
X				maxcode = MAXCODE(INIT_BITS);
X				n_bits = INIT_BITS;
X				n_bits8 = n_bits << 3;
X			}
X		}
X		ent = c;
XContinue:;
X	}
X	/*
X	 * Put out the final code.
X	 */
X	putcode(ent);
X
X	/*
X	 * At EOF, write the rest of the buffer.
X	 */
X	if (bitoffset > 0)
X		fwrite(bitbuf, 1, (bitoffset + 7) / 8, stdout);
X	out_count += (bitoffset + 7) / 8;
X	fflush(stdout);
X	if (ferror(stdout))
X		writeerr();
X
X	/*
X	 * Print out stats on stderr
X	 */
X	if (! zcat_flg && verbose) {
X		fprintf(stderr, "Compression: ");
X		prratio(in_count - out_count, in_count);
X	}
X	if (out_count > in_count)	/* exit(2) if no savings */
X		exit_stat = 2;
X}
X
X/*
X * Output the given code. Assumes that chars are 8 bits.
X * "n_bits" output bytes (containing 8 codes) are assembled
X * in in "bitbuf", and then written out.
X */
Xvoid putcode(code)
Xcode_t code;
X{
X	register int i;
X	register uchar *bp;
X
X	bp = &bitbuf[(bitoffset >> 3)];
X	i = bitoffset & 7;
X	bp[0] |= (uchar)(code << i);
X	bp[1] = (uchar)(code >>= (8 - i));
X	bp[2] = (uchar)(code >> 8);
X
X	if ((bitoffset += n_bits) == n_bits8) {
X		bp = bitbuf;
X		i = n_bits;
X		out_count += i;
X		do
X			putchar(*bp++);
X		while (--i);
X		bitbuf[bitoffset = 0] = 0;
X	}
X}
X
X#ifdef CHECK_GAP
X/*
X * Compute the current compression ratio, and return non-zero if
X * it is has decreased since the last we checked.
X *
X * Don't use this anymore. Whenever the hash table fills,
X * we send a CLEAR immediately (if block_compress). This is faster,
X * and doesn't appear to affect the compression ratio much.
X */
Xint need_clear()
X{
X	long rat;
X
X	if (in_count > 0x007fffffL) {		/* shift will overflow */
X		rat = out_count >> 8;
X		if (rat == 0)	     		/* Don't divide by zero */
X			rat = 0x7fffffffL;
X		else
X			rat = in_count / rat;
X	} else
X		rat = (in_count << 8) / out_count;
X
X	if (rat > ratio) {
X		ratio = rat;
X		return (0);
X	}
X	else {
X		ratio = 0;
X		return (1);
X	}
X}
X#endif
X
X/*
X * Decompress stdin to stdout. This code assumes that chars are 8 bits.
X */
Xvoid decompress()
X{
X	register uchar	*stackp;
X	register code_t	code;
X	code_t		oldcode, incode;
X	code_t		codemask;
X	code_t		freecode;		/* first unused entry */
X	code_t		maxcode;		/* maximum code, given n_bits */
X	code_t		maxmaxcode;
X	int		finchar;
X	int		size;			/* #bits in bitbuf */
X	int		bitoff;			/* Offset into bitbuf */
X	int		n_bits;			/* number of bits/code */
X#ifndef i8088
X	register uchar	*bp;
X#endif
X
X	n_bits = INIT_BITS;
X	maxcode = MAXCODE(INIT_BITS) - 1;
X	codemask = MAXCODE(INIT_BITS);
X	freecode = ((block_compress) ? FIRST : 256) - 1;
X	maxmaxcode = MAXCODE(maxbits);
X
X	/*
X	 * Read the first code into "oldcode"
X	 */
X	if ((size = fread(bitbuf, 1, n_bits, stdin)) <= 0)
X		return;
X	size = (size << 3) - (n_bits - 1);
X	oldcode = (bitbuf[0] | (bitbuf[1] << 8)) & codemask;
X	bitoff = n_bits;
X
X	/*
X	 * First code must be 8 bits == char. Write it, and die
X	 * if it can't be written.
X	 */
X	putchar(finchar = oldcode);
X	if (ferror(stdout))
X		writeerr();
X
X	stackp = de_stack;
X
X	for ( ; ; ) {
X		if (bitoff >= size) {
X			if ((size = fread(bitbuf, 1, n_bits, stdin)) <= 0)
X				break;
X			/* Round size down to integral number of codes */
X			size = (size << 3) - (n_bits - 1);
X			bitoff = 0;
X		}
X		/*
X		 * Read the next code into "code". On the 8088,
X		 * a slight speedup is possible because it has the right byte
X		 * order, and no alignment restrictions.
X		 */
X#ifdef i8088
X		code = ((code_t)(*(long *)&bitbuf[(bitoff >> 3)] >>
X			 (bitoff&7))) & codemask;
X#else
X		bp = &bitbuf[(bitoff >> 3)];
X		code = (code_t)(((bp[0] | (code_t)bp[1] << 8) |
X		     (ulong)bp[2] << 16) >> (bitoff & 7)) & codemask;
X#endif
X		bitoff += n_bits;
X
X		if ((code == CLEAR) && block_compress) {
X			n_bits = INIT_BITS;
X    			maxcode = MAXCODE(INIT_BITS) - 1;
X			codemask = MAXCODE(INIT_BITS);
X			freecode = (FIRST - 1) - 1;
X			size = 0;
X			continue;
X		}
X		incode = code;
X
X		/*
X		 * Special case for KwKwK string.
X		 */
X		if (code > freecode) {
X			if (code != freecode + 1)
X				oops();
X        		*stackp++ = (uchar)finchar;
X			code = oldcode;
X		}
X
X		/*
X		 * Generate output characters in reverse order
X		 */
X		while (code >= 256) {
X			*stackp++ = de_suffixof(code);
X			code = de_prefixof(code);
X		}
X
X		/*
X		 * And write them out in the forward order.
X		 */
X		putchar(finchar = code);
X		for (code = (stackp - de_stack) + 1; --code != 0; )
X			putchar(*--stackp);
X
X		/*
X		 * Generate the new entry.
X		 */
X		if (freecode < maxmaxcode) {
X			if (++freecode > maxcode) {
X				if (++n_bits == maxbits)
X					maxcode = maxmaxcode;
X				else
X					maxcode = MAXCODE(n_bits) - 1;
X				size = 0;
X				codemask = MAXCODE(n_bits);
X			}
X			de_prefixof(freecode) = oldcode;
X			de_suffixof(freecode) = (uchar)finchar;
X		} 
X		/*
X		 * Remember previous code.
X		 */
X		oldcode = incode;
X	}
X	fflush(stdout);
X	if (ferror(stdout))
X		writeerr();
X}
X
X/*
X * Check a compressed file to make sure it has the proper magic number
X * at the beginning. Also read the third byte to determine "maxbits",
X * and "block_compress".
X */
Xint check_magic()
X{
X	if (! magic)
X		return (1);
X	if ((getchar() != MAGIC0) || (getchar() != MAGIC1)) {
X		fprintf(stderr, "%s: not in compressed format\n", ifname);
X		return (0);
X	}
X	maxbits = getchar();	/* set -b from file */
X	block_compress = maxbits & BLOCK_MASK;
X	maxbits &= BIT_MASK;
X	if (maxbits > BITS) {
X		fprintf(stderr,
X		   "%s: compressed with %d bits, can only handle %d bits\n",
X		    ifname, maxbits, BITS);
X		return (0);
X	}
X	return (1);
X}
X
Xvoid writeerr()
X{
X	perror(ofname);
X	fclose(stdout);
X	unlink(ofname);
X	exit(1);
X}
X
X/*
X * Copy the permissions and file times from the input file to the
X * output.
X */
Xvoid copystat()
X{
X	struct stat statbuf;
X	int mode;
X	void (* ss)();
X#ifndef __TURBOC__
X	time_t timep[2];
X#else
X	struct ftime filetime;
X	int fd;
X#endif
X
X	fclose(stdout);
X	if (stat(ifname, &statbuf)) {		/* Get stat on input file */
X		perror(ifname);
X		return;
X	}
X	if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
X		if (! verbose)
X		    	fprintf(stderr, "%s: ", ifname);
X		fprintf(stderr, " -- not a regular file: unchanged");
X		exit_stat = 1;
X	}
X	else if (statbuf.st_nlink > 1) {
X		if (! verbose)
X			fprintf(stderr, "%s: ", ifname);
X		fprintf(stderr, " -- has %d other links: unchanged",
X			statbuf.st_nlink - 1);
X		exit_stat = 1;
X	}
X	else if (exit_stat == 2 && !force) { /* No compression: remove file.Z */
X		if (verbose)
X			fprintf(stderr, " -- file unchanged");
X	}
X	else {			/* ***** Successful Compression ***** */
X		exit_stat = 0;
X		mode = statbuf.st_mode & 07777;
X#ifndef __ZTC__
X		if (chmod(ofname, mode))		/* Copy modes */
X			perror(ofname);
X#endif
X#ifndef MSDOS
X		chown(ofname, statbuf.st_uid, statbuf.st_gid);	/* Copy ownership */
X#endif
X#ifndef __TURBOC__
X		timep[0] = statbuf.st_atime;
X		timep[1] = statbuf.st_mtime;
X		utime(ofname, timep);
X#else
X		if ((fd = open(ofname, O_RDONLY)) >= 0) {
X			if (getftime(fileno(stdin), &filetime) == 0)
X				setftime(fd, &filetime);
X			close(fd);
X		}
X#endif
X		fclose(stdin);
X		ss = signal(SIGINT, SIG_IGN);
X		okunlink = 0;
X		/* ^C here would leave both input, and output files around */
X		if (unlink(ifname))	/* Remove input file */
X			perror(ifname);
X		signal(SIGINT, ss);
X		if (verbose)
X			fprintf(stderr, " -- replaced with %s", ofname);
X		return;		/* Successful return */
X	}
X
X	/* Unsuccessful return -- one of the tests failed */
X
X	if (unlink(ofname))
X		perror(ofname);
X}
X
Xvoid onintr()
X{
X	fclose(stdout);
X	if (okunlink)
X		unlink(ofname);
X	exit(1);
X}
X
Xvoid oops()	/* wild pointer -- assume bad input */
X{
X	if (do_decomp) 
X		fprintf (stderr, "uncompress: %s is corrupt.\n", ifname);
X	fclose(stdout);
X	if (okunlink)
X		unlink(ofname);
X	exit(1);
X}
X
Xvoid prratio(num, den)
Xlong int num, den;
X{
X	register int q;				/* Doesn't need to be long */
X
X	if (num > 214748L)			/* 2147483647/10000 */
X		q = (int)(num / (den / 10000L));
X	else
X		q = (int)(10000L * num / den);	/* Long calculations, though */
X	if (q < 0) {
X		putc('-', stderr);
X		q = -q;
X	}
X	fprintf(stderr, "%d.%02d%%", q / 100, q % 100);
X}
X
Xvoid version()
X{
X	fprintf(stderr, "%s\n", rcs_ident);
X	fprintf(stderr, "BITS = %d\n", BITS);
X}
X
X/*
X * Open the file "ofname" for binary output with possible check
X * for overwrite. If all goes well, return non-zero, else zero.
X */
Xint ofopen(filename)
Xchar *filename;
X{
X	static char IOoutbuf[8192];
X	struct stat statbuf;
X
X	if (filename && !*filename)
X		filename = 0;
X
X	/*
X	 * Check for overwrite of existing file
X	 */
X	if (filename && !force && stat(filename, &statbuf) == 0) {
X		char response[2];
X		response[0] = 'n';
X		fprintf(stderr, "%s already exists;", filename);
X		if (foreground) {
X			fprintf(stderr, " do you wish to overwrite %s (y or n)? ", filename);
X			fflush(stderr);
X			read(2, response, 2);
X			while (response[1] != '\n') {
X				if (read(2, response+1, 1) < 0)	{ /* Ack! */
X					perror("stderr");
X					break;
X				}
X			}
X		}
X		if (response[0] != 'y') {
X			fprintf(stderr, "\tnot overwritten\n");
X			return (0);
X		}
X	}
X
X	okunlink = 1;
X	/*
X	 * Open the output file.
X	 */
X	if (filename && !freopen(filename, "wb", stdout)) {
X		perror(filename);
X		return (0);
X	}
X#ifdef O_BINARY
X	setmode(fileno(stdout), O_BINARY);
X#else
X#ifdef __ZTC__
X	/*
X	 * I'm sure there must be a better way in Zortech C to change the
X	 * mode of an already opened file, but I can't find it. It doesn't
X	 * have a "setmode" call it seems.
X	 */
X	stdout->_flag &= ~_IOTRAN;
X#endif
X#endif
X	setvbuf(stdout, IOoutbuf, _IOFBF, sizeof(IOoutbuf));
X	return (1);
X}
X
Xifopen(filename)
Xchar *filename;
X{
X	static char IOinbuf[8192];
X
X	if (filename && !freopen(filename, "rb", stdin)) {
X		perror(filename);
X		return (0);
X	}
X#ifdef O_BINARY
X	setmode(fileno(stdin), O_BINARY);
X#else
X#ifdef __ZTC__
X	stdin->_flag &= ~_IOTRAN;
X#endif
X#endif
X	setvbuf(stdin, IOinbuf, _IOFBF, sizeof(IOinbuf));
X	return (1);
X}
END_OF_FILE
if test 32700 -ne `wc -c <'compress.c'`; then
    echo shar: \"'compress.c'\" unpacked with wrong size!
fi
# end of 'compress.c'
fi
echo shar: End of shell archive.
exit 0



From auspex!auspex.com!guy Tue Dec 12 20:49:51 1989
Received: from auspex.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA02377; Tue, 12 Dec 89 20:49:41 -0500
Date: Tue, 12 Dec 89 17:37:40 PST
From: guy@auspex.com (Guy Harris)
Message-Id: <8912130137.AA21293@auspex.com>
To: rick@uunet.uu.net
Subject: Is this bug report valid?
Status: RO

Article 203 of news.software.b:
Path: auspex!uunet!lll-winken!ames!ncar!boulder!fesk!news
From: news@fesk.UUCP (news)
Newsgroups: news.software.b
Subject: rnews -U locking via .rnews.lock is broken in 2.11.17
Keywords: inews.c file-locking
Message-ID: <216@fesk.UUCP>
Date: 29 Jan 89 23:43:05 GMT
Organization: SERI, Golden, CO
Lines: 26

When spooling news and executing rnews -U from cron once an hour
I get multiple copies of rnews -U running at the same time.  I have
tracked this down to one line of severely broken code in inews.c
for the case of locking via the lock file SPOOL/.rnews.lock
The patch below (hopefully) corrects the problem.

*** save/inews.c	Wed Jan 25 14:28:10 1989
--- inews.c	Sun Jan 29 16:04:51 1989
***************
*** 1540,1546
  	/* assume a dead lock if the active file is over 12 hours old */
  	if (ret < 0 &&
  		(errno != EEXIST ||
! 		(stat(bfr, &stbuf) == 0 &&
  		(time((char *)0) - stbuf.st_mtime) < DAYS/2))) {
  			if (errno != EEXIST)
  #endif /* V7 */

--- 1540,1546 -----
  	/* assume a dead lock if the active file is over 12 hours old */
  	if (ret < 0 &&
  		(errno != EEXIST ||
! 		(stat(spbuf, &stbuf) != 0 ||
  		(time((char *)0) - stbuf.st_mtime) < DAYS/2))) {
  			if (errno != EEXIST)
  #endif /* V7 */


The code in patchlevel 19 is:

	strcat(spbuf, ".lock");
	sprintf(bfr, "%s.tmp", spbuf);
	(void) close(creat(bfr, 0666));
	ret = LINK(bfr, spbuf);
	status = errno;
	(void) UNLINK(bfr);
	errno = status;
	/* assume a dead lock if the active file is over 12 hours old */
	if (ret < 0 &&
		(errno != EEXIST ||
		(stat(bfr, &stbuf) == 0 &&
		(time((char *)0) - stbuf.st_mtime) < DAYS/2))) {
			if (errno != EEXIST)

and it looks, offhand, as if the claim in the patch is correct.  If the
"unlink" succeeded, the pathname "bfr" no longer refers to a file.  If
the "errno" is EEXIST, something's broken; otherwise, the link failed
because the ".lock" file already exists, so I'd assume the test should
check whether that file is more than 12 hours old, so the "stat" should
be statting "spbuf", i.e., the pathname of the ".lock" file.

From auspex!auspex.com!guy Wed Dec 13 17:50:45 1989
Received: from auspex.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA01310; Wed, 13 Dec 89 17:50:39 -0500
Date: Wed, 13 Dec 89 13:47:31 PST
From: guy@auspex.com (Guy Harris)
Message-Id: <8912132147.AA05928@auspex.com>
To: rick@uunet.uu.net
Subject: A patch to patchlevel 19 "sendbatch.sh"
Status: R

for the benefit of those of us with crufty old UUCPs that don't give
each site its own separate directory for D. files.  If MAXBATCH isn't
set, or if "/usr/spool/uucp/<hostname>" doesn't exist, it gives up and
sets "du" to 0, so that the

	bytes_this_batch=`expr $MAXBATCH - $du`
	if test $bytes_this_batch -gt $MAXPERRUN
	then
		bytes_this_batch=$MAXPERRUN
	fi

stuff doesn't blow up (as it will if "du" isn't set!).

*** sendbatch.sh.dist	Mon Oct 30 15:51:05 1989
--- sendbatch.sh	Wed Dec 13 13:25:46 1989
***************
*** 94,99 ****
--- 94,101 ----
  			echo $rmt already has $du Kbytes queued
  			continue
  		fi
+ 	else
+ 		du=0
  	fi
  
  	if test -n "$COMP"

From jsq@longway.tic.com Mon Dec 18 16:28:55 1989
Received: from cs.utexas.edu by uunet.uu.net (5.61/1.14) with SMTP 
	id AA24246; Mon, 18 Dec 89 16:28:37 -0500
Posted-Date: Mon, 18 Dec 89 14:58:19 -0600
Received: by cs.utexas.edu (5.59/1.45)
	id AA02188; Mon, 18 Dec 89 15:28:34 CST
Received: by longway.tic.com (4.22/4.16)
	id AA03123; Mon, 18 Dec 89 14:58:26 cst
From: jsq@longway.tic.com (John S. Quarterman)
Message-Id: <8912182058.AA03123@longway.tic.com>
To: rick@uunet.uu.net
Cc: fletcher@cs.utexas.edu, jsq@longway.tic.com
Subject: bug in makeactive.sh
Date: Mon, 18 Dec 89 14:58:19 -0600
Status: R

*** makeactive.sh.dist	Tue Sep 12 16:56:25 1989
- --- makeactive.sh	Mon Dec 18 13:45:59 1989
***************
*** 421,427 ****
  : if active file is empty, create it
  if test ! -s $LIBDIR/active
  then
! 	sed 's/[ 	].*/ 00000 00001/' /tmp/$$groups > $LIBDIR/active
  	cat <<'E_O_F' >>$LIBDIR/active
  control 0000000 0000000
  junk 0000000 0000000
- --- 421,427 ----
  : if active file is empty, create it
  if test ! -s $LIBDIR/active
  then
! 	sed 's/[ 	].*/ 0000000 0000001/' /tmp/$$groups > $LIBDIR/active
  	cat <<'E_O_F' >>$LIBDIR/active
  control 0000000 0000000
  junk 0000000 0000000


From avolio@decuac.DEC.COM Sat Dec 16 03:43:43 1989
Received: from DECUAC.DEC.COM by uunet.uu.net (5.61/1.14) with SMTP 
	id AA24584; Sat, 16 Dec 89 03:43:37 -0500
Received: by decuac.DEC.COM (5.57/Ultrix-fma)
	id AA28716; Sat, 16 Dec 89 01:48:47 EST
Date: Sat, 16 Dec 89 01:48:47 EST
From: avolio@decuac.DEC.COM (Frederick M. Avolio)
Message-Id: <8912160648.AA28716@decuac.DEC.COM>
To: rick@uunet.uu.net
Subject: news bug (2.11.19) sendbatch
Status: RO

I *just* noticed since I applied patch #19 on Mon or Tues that we havent
shipped news via sendbatch.  (Mostly, we do nntp now.)  I tracked it
down to the disk usage additions in sendbatch.

1. UUCP spool on ULTRIX is SPOOL/uucp/sys/$rmt for each rmt system.
So, it fails the test -d on/near line 89 so the du inside of the if
never got done (~ line 91) and so the expr that uses du (~ line 118)
failed with a syntax error because "du" was never assigned.  (Du should
be assigned a 0 at the beginning as it is very possible for the
directory test to fail as stated and du never get an assignment.

2. du under ULTRIX and I would think BSD is verbose without the -s flag.
for example,  "du /etc" yields --

9	/etc/namedb/.OLD
38	/etc/namedb
1	/etc/popd
1306	/etc

We want a "du -s ......"
(~ line 91)

fg

3. It is possible for the test on line 118 to fail, i.e., if
bytes_this_batch is lessthan MAXPERRUN.  This is a good thing. 
Unfortunately, that if statement then returns an error status of 1
as a value and the follow while loop is then never done.  (I stuck
an echo in there just to reset the value of $? for the time being.)

Some of these problems might be due to bugs/errors in ULTRIX.  

Thanks

I'm going to sleep......

Fred

From texbell!attctc!sysop Sat Dec 16 15:02:51 1989
Received: from texbell.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA16253; Sat, 16 Dec 89 15:02:49 -0500
Received: by wuarchive.wustl.edu
	(5.61++/IDA-1.2.8) id AA29865; Sat, 16 Dec 89 12:30:03 -0600
Received: from wugate.wustl.edu by wupost.wustl.edu with SMTP
	(5.61++/IDA-1.2.8) id AA23225; Sat, 16 Dec 89 12:18:17 -0600
Received: from texbell.sbc.com by wugate.wustl.edu with SMTP
	(5.61++/IDA-1.2.8) id AA28718; Sat, 16 Dec 89 12:16:16 -0600
Received: by texbell.swbt.com (Smail3.1)
	id <m0gcilI-0000VLC@texbell>; Sat, 16 Dec 89 12:04 CST
Received: by attctc.Dallas.TX.US (killer) (/\=-/\ Smail3.1.18.1 #18.1)
	id <m0gchqX-0002rWC@attctc.Dallas.TX.US>; Sat, 16 Dec 89 11:05 CST
Message-Id: <m0gchqX-0002rWC@attctc.Dallas.TX.US>
Date: Sat, 16 Dec 89 11:05 CST
From: sysop@attctc.Dallas.TX.US (Charles Boykin-BBS Admin)
To: uunet!rick
Subject: Re patch18-19 Bnews
Status: RO


Rick,

   I have noticed a rather strange problem with moderated group handling
since these two patches.
   First, the machine is a 3B2/500 with 22Mhz upgrade, 32MB memory, and
running AT&T SVR3.2.1 Unix. The compiler is C Programming 4.2. I do run
dbm (AT&Ts version).
   I noticed that moderated groups can be posted to directly by any user. I
then defined MODFILEONLY, recompiled and reinstalled. The results did not
change as any moderated group can be posted to by any user. Are you able to
shed any light on this. The problem did show up only after going to patch
level 19. It manifests itself when the posted article is sent to other
systems where they promptly mail it to the moderator because it has no
Approved line. I am checking with some other SYSV sites for the same action.
   Any clarification you might have would be appreciated.

                                                       Thanks,
                                                       Charlie

From rivm!a3@relay.EU.net Fri Dec 22 22:52:17 1989
Received: from mcsun.eu.net by uunet.uu.net (5.61/1.14) with SMTP 
	id AA28418; Fri, 22 Dec 89 22:52:12 -0500
Received: by mcsun.EU.net with SMTP; Sat, 23 Dec 89 04:52:05 +0100 (MET)
Received: from rivm by hp4nl.nluug.nl with UUCP via EUnet
          id AA14424 (5.58.1.14/2.14); Sat, 23 Dec 89 04:52:54 +0100
Message-Id: <8912230352.AA14424@hp4nl.nluug.nl>
Date: Sat, 23 Dec 89 04:15:00 +0100
From: rivm!a3@relay.EU.net
To: uunet!rick
Subject: make install - bogus message displayed
Status: R

Dear Rick,
  When I installed B2.11.19 lately, I couldn't help seeing
this bogus message:

	Can't open /usr/lib/news/ngfile

  We all know that 'ngfile' is not in use anymore, but I can't
seem to figure out for the moment what the offending code
is used for; here is the fragment from "makeactive.sh":
(Code following converting active file to new format)


if test $# -eq 3 -o $# -eq 2
then
	(sed '/^!net/!d
s/^!//
s!^!/!
s!$! /s/$/ n/!
' $LIBDIR/ngfile
	echo '/ n$/!s/$/ y/') >/tmp/$$sed
	mv $LIBDIR/active $LIBDIR/oactive
	sed -f /tmp/$$sed $LIBDIR/oactive >$LIBDIR/active
	chown $NEWSUSR $LIBDIR/active
	chgrp $NEWSGRP $LIBDIR/active
	chmod 644 $LIBDIR/active
fi
--
Adri Verhoef,(uunet!rivm!a3 || a3@rivm.uucp) News Administrator RIVM since 1987.



From rivm!a3@relay.EU.net Sun Dec 24 12:21:40 1989
Received: from mcsun.eu.net by uunet.uu.net (5.61/1.14) with SMTP 
	id AA04780; Sun, 24 Dec 89 12:21:33 -0500
Received: by mcsun.EU.net with SMTP; Sun, 24 Dec 89 18:21:28 +0100 (MET)
Received: from rivm by hp4nl.nluug.nl with UUCP via EUnet
          id AA21179 (5.58.1.14/2.14); Sun, 24 Dec 89 18:22:17 +0100
Message-Id: <8912241722.AA21179@hp4nl.nluug.nl>
Date: Sat, 23 Dec 89 05:05:00 +0100
From: rivm!a3@relay.EU.net
To: uunet!rick
Subject: rnews -U in combination with MINFREE
Status: R

Dear Rick,

  I defined MINFREE (Uniq System V.3 on VAX-630) in defs.h to be 5000.

I will now consider a situation where the number of free blocks is below 5000.
- When an article comes in from another machine, it gets stored in the proper
  newsgroup.  Good.
  In the logfile appears:
	... Out of space in /usr/spool/news.
	... queued <542@soandso...
  "queued" ?  Hmmm.
- Someone posts an article on this - low on free space - machine.
  The article is not stored yet in the proper newsgroup, instead it is queued.
  In the logfile appears:
	... Out of space in /usr/spool/news.
	... Out of space in /usr/spool/news.
	... queued <170@rivm33...
  So far, so good.  (Although low on free space.)
- Some time later on, after doing an expire, rnews -U starts up.  Good.
  However, 'expire' didn't succeed in freeing up MINFREE blocks.  Too bad.
  There is an article waiting in the queue (remember?).
  Let's follow the logfile "log":

Dec 18 18:04	local	Out of space in /usr/spool/news.
Dec 18 18:04	local	Out of space in /usr/spool/news.
Dec 18 18:04	local	queued <170@rivm33.UUCP> ng rivm.test subj 'U2' from cwmvrie@rivm.UUCP (Wilco de Vries)
Dec 18 18:04	local	Out of space in /usr/spool/news.
Dec 18 18:04	local	Out of space in /usr/spool/news.
Dec 18 18:04	local	queued <170@rivm33.UUCP> ng rivm.test subj 'U2' from cwmvrie@rivm.UUCP (Wilco de Vries)
Dec 18 18:04	local	Out of space in /usr/spool/news.
Dec 18 18:04	local	Out of space in /usr/spool/news.
Dec 18 18:04	local	queued <170@rivm33.UUCP> ng rivm.test subj 'U2' from cwmvrie@rivm.UUCP (Wilco de Vries)
Dec 18 18:04	local	Out of space in /usr/spool/news.

	... and so on and so on ... until ...

Dec 18 21:58	local	queued <170@rivm33.UUCP> ng rivm.test subj 'U2' from cwmvrie@rivm.UUCP (Wilco de Vries)
Dec 18 21:58	local	Out of space in /usr/spool/news.
Dec 18 21:58	local	Out of space in /usr/spool/news.
Dec 18 21:58	local	queued <170@rivm33.UUCP> ng rivm.test subj 'U2' from cwmvrie@rivm.UUCP (Wilco de Vries)
Dec 18 21:58	local	Out of space in /usr/spool/news.
Dec 18 21:58	local	Out of space in /usr/spool/news.
Dec 18 21:58	local	queued <170@rivm33.UUCP> ng rivm.test subj 'U2' from cwmvrie@rivm.UUCP (Wilco de Vries)
Dec 18 21:58	local	Out of space in /usr/spool/news.
Dec 18 21:58	local	8912181958645c: Inbound news is garbled
Dec 18 21:58	local	rnews failed, status 256. Batch saved in /usr/spool/news/.bad/8912181958645c

At this time the disk space was used up by the continuous logging of errors
from the rnews -U that was still running.
I've watched it for some time and concluded that rnews -U continuously
starts up an inews, logging the errors, and inews exits.  The inews is
for unbatching the queued article, of course.
In the end, rnews -U succeeds in filling the entire partition.

  I strongly suspect that this is an unwanted procedure for rnews -U
to keep on starting up inews's, that seem to fail on low free space.

  I think it's best for rnews -U to stop unbatching immediately after
detecting free space < MINFREE, and not to wait until the entire partition
is filled up with news error logging.

  To feel safe, I would like to keep MINFREE = 5000, but at this time
I think keeping MINFREE = 0 might be better, but then MINFREE is of no
use.

  Of course I know many ways to prevent low free space, such as:
- keeping the articles around for a shorter period of time (expire)
- expiring voluminous newsgroups faster
- less receiving
- enlarging the news spool partition
- cleaning up (if there are living other things on the partition)


My best wishes for 11111000110(base2), Rick!
--
Adri Verhoef (uunet!rivm!a3 || a3@rivm.uucp), site administrator of the
National Institute for Public Health and Environmental Protection (RIVM).



From rivm!a3@relay.EU.net Sun Dec 24 12:21:42 1989
Received: from mcsun.eu.net by uunet.uu.net (5.61/1.14) with SMTP 
	id AA04830; Sun, 24 Dec 89 12:21:37 -0500
Received: by mcsun.EU.net with SMTP; Sun, 24 Dec 89 18:21:33 +0100 (MET)
Received: from rivm by hp4nl.nluug.nl with UUCP via EUnet
          id AA21183 (5.58.1.14/2.14); Sun, 24 Dec 89 18:22:24 +0100
Message-Id: <8912241722.AA21183@hp4nl.nluug.nl>
Date: Sat, 23 Dec 89 05:21:00 +0100
From: rivm!a3@relay.EU.net
To: uunet!rick
Subject: BATCHDIR not created after 'make install'
Status: R

Dear Rick,
	After running 'make install', BATCHDIR hasn't been
created if it wasn't there already.  This should be corrected
in install.sh, I suppose.

The best of luck to you for 1990!
--
Adri Verhoef, News/Site/Mail/UUCP Administrator RIVM. (a3@rivm)



From heiby@chg.mcd.mot.com Thu Dec 28 20:17:43 1989
Received: from chg.mcd.mot.com by uunet.uu.net (5.61/1.14) with UUCP 
	id AA13341; Thu, 28 Dec 89 20:17:41 -0500
Received: from mcdchg.UUCP by rutgers.edu (5.59/SMI4.0/RU1.3/3.05) with UUCP 
	id AA05948; Thu, 28 Dec 89 19:41:27 EST
Received: by chg.mcd.mot.com (smail2.5)
	id AA21800; 28 Dec 89 17:48:22 CST (Thu)
To: rick@uunet.uu.net
Subject: p19 fix suggestions
Message-Id: <8912281748.AA21800@chg.mcd.mot.com>
Date: 28 Dec 89 17:48:22 CST (Thu)
From: heiby@chg.mcd.mot.com (Ron Heiby)
Status: R

Hi, Rick!  Here are a couple of diffs of changes that I needed to make
to get patch level 19 up and running under SVR3 on a Motorol VME Delta
System.  Ron.

=====================================

These changes allow "batch" to work when we are trying to have everything
be relative to the HOME directory of the news user.

Dec 28 17:20 1989  diff of ./batch.c in vanilla/src and netnews/src Page 1


62c62
< 	int spooldirlen = strlen(SPOOLDIR);
---
> 	int spooldirlen;		/* RWH */
66a67
> 	char rhname[BUFLEN];		/* RWH */
67a69,75
> #if defined(LOGDIR) || defined(HOME)				/* RWH */
> 	(void) sprintf(rhname, "%s/%s", logdir(HOME), SPOOLDIR);/* RWH */
> #else								/* RWH */
> 	(void) sprintf(rhname, "%s", SPOOLDIR);			/* RWH */
> #endif								/* RWH */
> 	spooldirlen = strlen(rhname);	/* RWH */
>
95,96c103,109
< 	if (chdir(SPOOLDIR) < 0) {
< 		logerror("chdir(%s): %s", SPOOLDIR, sys_errlist[errno]);
---
> #if defined(LOGDIR) || defined(HOME)				/* RWH */
> 	(void) sprintf(rhname, "%s/%s", logdir(HOME), SPOOLDIR);/* RWH */
> #else								/* RWH */
> 	(void) sprintf(rhname, "%s", SPOOLDIR);			/* RWH */
> #endif								/* RWH */
> 	if (chdir(rhname) < 0) {				/* RWH */
> 		logerror("chdir(%s): %s", rhname, sys_errlist[errno]);/* RWH */
153,154c166,172
< 	if (chdir(BATCHDIR) < 0) {
< 		logerror("chdir(%s): %s", BATCHDIR, sys_errlist[errno]);
---
> #if defined(LOGDIR) || defined(HOME)				/* RWH */
> 	(void) sprintf(rhname, "%s/%s", logdir(HOME), BATCHDIR);/* RWH */
> #else								/* RWH */
> 	(void) sprintf(rhname, "%s", BATCHDIR);			/* RWH */
> #endif								/* RWH */
> 	if (chdir(rhname) < 0) {				/* RWH */
> 		logerror("chdir(%s): %s", rhname, sys_errlist[errno]);/* RWH */

=====================================

This change should be conditional, the "-s" argument is required for
System V Release 3 (and beyond?) to suppress the automatic generation
of a blank line in front of the message, which would cause all our header
information to be treated as "body".


Dec 28 17:20 1989  diff of ./control.c in vanilla/src and netnews/src Page 1


925c925
< 		execl("/bin/mail", "mail", sendto, (char *)NULL);
---
> 		execl("/bin/mail", "mail", "-s", sendto, (char *)NULL);

=====================================

At this point, LIBDIR is the relative pathname (to HOME) and LIB is the
absolute pathname, which is what is desired.

Dec 28 17:21 1989  diff of ./pathinit.c in vanilla/src and netnews/src Page 1


429c429
< 	(void) sprintf(fbuf,"%s/localdomain", LIBDIR);
---
> 	(void) sprintf(fbuf,"%s/localdomain", LIB); /* RWH */

=====================================

See above comment on "-s" argument to SVR3 /bin/mail.

Dec 28 17:21 1989  diff of ./recmail.c in vanilla/src and netnews/src Page 1


225c225
< 		execlp(mailer, mailer, recip, (char *)0);
---
> 		execlp(mailer, mailer, "-s", recip, (char *)0);

=====================================

See above comment on "-s" argument to SVR3 /bin/mail.

Dec 28 17:21 1989  diff of ./sendnews.c in vanilla/src and netnews/src Page 1


51c51
< 	(void) sprintf(buffer, "/bin/mail %s", *argv);
---
> 	(void) sprintf(buffer, "/bin/mail -s %s", *argv);

From pan!jw@relay.EU.net Mon Jan  1 12:42:30 1990
Received: from seismo.CSS.GOV by uunet.uu.net (5.61/1.14) with SMTP 
	id AA16161; Mon, 1 Jan 90 12:42:28 -0500
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.61/1.14)
	id AA24208; Mon, 1 Jan 90 12:42:24 -0500
Received: from seismo.CSS.GOV by beno.CSS.GOV (4.0/SMI-4.0)
	id AA05536; Mon, 1 Jan 90 12:42:22 EST
Received: from uunet.UU.NET by seismo.CSS.GOV (5.61/1.14)
	id AA24202; Mon, 1 Jan 90 12:42:12 -0500
Received: from mcsun.eu.net by uunet.uu.net (5.61/1.14) with SMTP 
	id AA16152; Mon, 1 Jan 90 12:42:05 -0500
Received: by mcsun.EU.net via EUnet; Mon, 1 Jan 90 18:42:01 +0100 (MET)
Received: by chx400.switch.ch (5.57/Ultrix2.4-C)
	id AA13841; Mon, 1 Jan 90 18:36:44 +0100
Message-Id: <9001011736.AA13838@chx400.switch.ch>
Received: by pan (AIX  2.1 2/4.03)
          id AA15759; Mon, 1 Jan 90 18:17:52 +0100
From: pan!jw@relay.EU.net (Jamie Watson)
Date: Mon, 1 Jan 90 18:17:48 MET
X-Mailer: Mail User's Shell (6.5.6 6/30/89)
To: rick@uunet.uu.net
Subject: B news sendbatch on AIX/RT
Status: R

Rick,

I have just run into two problems with sendbatch from B news, patchlevel 19,
running on AIX/RT version 2.2.1.  One I have seen mentioned on the net some
time ago, but I never saw an official patch for it; the other I have not
seen any mention of before.

First, the one I have seen before.  Although AIX/RT has HDB uucp, there can
be situations where sendbatch is run when there is no uucp/sysname directory
for a known system.  The most common cause of this is the nightly cleanup
script deleting the directory because it is empty.  When this happens, the
value of 'du' never gets set, and the subsequent attempt to use it in an
expression with "expr" results in a syntax error.  To avoid this problem,
I simply added an explicit assignment of "du=0" at the beginning of the
script.

Second, believe it or not, the 'df' on AIX/RT has yet another output format.
This format does not match any of the possibilities in the awk command, so
the value of "df" is set incorrectly (to some completely bogus value).  The
actual output on AIX/RT looks like this:

Device             Mounted on            total     free  used     ifree  used
/dev/hd0           /                     28996     6996   75%      6940    7%
/dev/hd6           /vrm                   3476      548   84%        35   72%
/dev/hd3           /tmp                   9808     8776   10%      1008    1%
/dev/hd2           /usr                  58060     6188   89%     13509    9%
/dev/hd13          /usr/lib/font         14700     7560   48%      1425   24%
/dev/hd1           /usr/home             23184    11628   49%      5299   11%
/dev/hd10          /usr/work             78684    44544   43%      6965   30%
/dev/hd8           /usr/local            63920    27108   57%      7657    5%
/dev/hd9           /usr/spool            12572    12068    4%      1545    5%
/dev/hd7           /usr/spool/news       38152    22276   41%      2582   46%
/dev/hd12          /usr/spool/oldnews    44232    17968   59%      3976   29%
/dev/hd14          /mnt                 457308   213072   53%     26514   17%

I added the following statement to the awk command:

			$2 == "'$SPOOLDISK'" && NF == 7 {print $4;exit}


If I have missed a patch which fixes either of both of these problems,
please let me know so I can look around for it over here.  If you think
that AIX/RT is such a low-volume system as not to be worth worrying about,
please just tell me - I certainly couldn't argue with that...

Thanks,

jw

From heiby@chg.mcd.mot.com Tue Jan  2 20:11:29 1990
Received: from chg.mcd.mot.com by uunet.uu.net (5.61/1.14) with UUCP 
	id AA06787; Tue, 2 Jan 90 20:11:24 -0500
Received: from mcdchg.UUCP by rutgers.edu (5.59/SMI4.0/RU1.3/3.05) with UUCP 
	id AA07313; Tue, 2 Jan 90 19:48:29 EST
Received: by chg.mcd.mot.com (smail2.5)
	id AA29437; 2 Jan 90 09:16:23 CST (Tue)
To: rick@uunet.uu.net
Subject: more p19 fix suggestions
Message-Id: <9001020916.AA29437@chg.mcd.mot.com>
Date: 2 Jan 90 09:16:23 CST (Tue)
From: heiby@chg.mcd.mot.com (Ron Heiby)
Status: R

Hi Rick!  Hope you had a nice holiday.  Just wanted to point out a couple
of things further.  The "checkgroups", "rmgroup", and "sendbatch" shell
scripts in the LIBDIR use absolute pathnames, rather than being relative
to the NEWSUSR HOME as I tried to build everything else.  I used the line

HOME=`awk -F':' '/^usenet/ {print $6}' /etc/passwd`	# News home directory

at the top of each script and based the references to the directories
from HOME.  Ron.

From rivm!a3@relay.EU.net Wed Jan 10 12:27:18 1990
Received: from mcsun.eu.net by uunet.uu.net (5.61/1.14) with SMTP 
	id AA22144; Wed, 10 Jan 90 12:27:11 -0500
Received: by mcsun.EU.net with SMTP; Wed, 10 Jan 90 18:27:01 +0100 (MET)
Received: from rivm by hp4nl.nluug.nl with UUCP via EUnet
          id AA17182 (5.58.1.14/2.14); Wed, 10 Jan 90 18:27:54 +0100
Message-Id: <9001101727.AA17182@hp4nl.nluug.nl>
Date: 9 Jan 1990 22:44:53 MET
From: Adri Verhoef <rivm!a3@relay.EU.net>
Reply-To: <rivm!a3@relay.EU.net>
To: uunet!rick
Subject: Minor change to control.c: "newgroup" --> "newsgroup"
Status: R

*** /tmp/control.c	Tue Jan  9 22:36:46 1990
--- control.c	Tue Jan  9 22:37:31 1990
***************
*** 514,520
  			header.path, argc > 2 ? "moderated " : "", argv[1]);
  			fprintf(fd,"It was approved by %s\n\n",header.approved);
  			fprintf(fd, 
! 		"You can accomplish this by creating the newgroup yourself\n");
  #  ifdef ORGDISTRIB
  			fprintf(fd,"with a distribution of '%s'.\n",
  				ORGDISTRIB);

--- 514,520 -----
  			header.path, argc > 2 ? "moderated " : "", argv[1]);
  			fprintf(fd,"It was approved by %s\n\n",header.approved);
  			fprintf(fd, 
! 		"You can accomplish this by creating the newsgroup yourself\n");
  #  ifdef ORGDISTRIB
  			fprintf(fd,"with a distribution of '%s'.\n",
  				ORGDISTRIB);

--
Adri Verhoef (uunet!rivm!a3 || a3@rivm.uucp), News/site administrator of the
National Institute for Public Health and Environmental Protection (RIVM).

From uucp@hp4nl.nluug.nl Sat Jan 13 07:59:13 1990
Received: from seismo.CSS.GOV by uunet.uu.net (5.61/1.14) with SMTP 
	id AA18816; Sat, 13 Jan 90 07:58:56 -0500
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.61/1.14)
	id AA22612; Sat, 13 Jan 90 07:58:39 -0500
Received: from seismo.CSS.GOV by beno.CSS.GOV (4.0/SMI-4.0)
	id AA00470; Sat, 13 Jan 90 07:58:36 EST
Received: from mcsun.eu.net by seismo.CSS.GOV (5.61/1.14)
	id AA22600; Sat, 13 Jan 90 07:58:12 -0500
Received: by mcsun.EU.net with SMTP; Sat, 13 Jan 90 13:57:54 +0100 (MET)
Received: from westc by hp4nl.nluug.nl with UUCP via EUnet
          id AA07456 (5.58.1.14/2.14); Sat, 13 Jan 90 13:58:53 +0100
Received: by  (4.0/SMI-4.0)
	id AA22876; Fri, 12 Jan 90 11:43:21 +0100
From: @!gertjan@relay.EU.net (Gertjan van Oosten)
Organisation: West Consulting bv
	      Postbox 3318
	      2601 DH Delft, The Netherlands
Phone:        +31 15 123190
Fax:          +31 15 147889
Message-Id: <9001121043.AA22876@>
Subject: Bugs in news 2.11
To: rick@seismo.CSS.GOV
Date: Fri, 12 Jan 90 11:43:20 MET DST
X-Mailer: ELM [version 2.2 PL14]
Status: RO

Below are two context diff's needed to make news work on our system (Sun3/60
running SunOS 4).

The first change is to 'funcs.c' and is a workaround for a (known) bug in the
SunOS 4.x 'fscanf' routine (Sun said that it will be fixed in the next
release of SunOS). The bug is: fscanf() does not return EOF upon end of input
when the first conversion specification in the control string is a character
class. Instead, it just returns '0' (zero).
This patch should only be applied if news is to run on a SunOS 4.x system.

The second change is a patch to a bug in 'inews.c'. This bug manifested
itself only when stderr was not a tty. It then quit with a segmentation
fault. This was caused by a NULL pointer being passed to strncmp. The reason
for this was, that instead of 'username', 'user' (initialized to NULL) was
passed to 'fascist'.
This patch should always be applied (in fact, I can't imagine nobody has
noted this bug before, so this is probably a known bug).

Here follow the context diff's:
---------------
*** funcs.c.orig	Tue Sep 27 14:23:53 1988
--- funcs.c	Tue Jan  9 11:51:30 1990
***************
*** 588,599 ****
  	facfd = fopen(factemp, "r");
  
  	if (facfd != NULL) { /* If no such file, we go with the global default */
! 		while (fscanf(facfd, "%[^:]:%s\n", facuser, factemp) != EOF)
  			if (strncmp(facuser, user, BUFLEN) == 0) {
  				(void) strcat(facgroups, ",");
  				(void) strcat(facgroups, factemp);
  				break;
  			}
  		fclose (facfd);
  	}
  #ifdef DEBUG
--- 588,603 ----
  	facfd = fopen(factemp, "r");
  
  	if (facfd != NULL) { /* If no such file, we go with the global default */
! 		while (fscanf(facfd, "%[^:]:%s\n", facuser, factemp) != EOF) {
  			if (strncmp(facuser, user, BUFLEN) == 0) {
  				(void) strcat(facgroups, ",");
  				(void) strcat(facgroups, factemp);
  				break;
  			}
+ 			/* I hate this */
+ 			if (feof(facfd))
+ 				break;
+ 		}
  		fclose (facfd);
  	}
  #ifdef DEBUG
---------------
*** inews.c.orig	Wed Oct 25 14:46:19 1989
--- inews.c	Thu Jan 11 12:12:18 1990
***************
*** 484,492 ****
  
  	if (mode <= UNPROC) {
  #ifdef FASCIST
! 		if (uid && uid != ROOTID && fascist(user, header.nbuf))
  			xerror("User %s is not authorized to post to newsgroup %s",
! 				user, header.nbuf);
  #endif /* FASCIST */
  		ctlcheck();
  	}
--- 484,492 ----
  
  	if (mode <= UNPROC) {
  #ifdef FASCIST
! 		if (uid && uid != ROOTID && fascist(username, header.nbuf))
  			xerror("User %s is not authorized to post to newsgroup %s",
! 				username, header.nbuf);
  #endif /* FASCIST */
  		ctlcheck();
  	}
---------------
Kind regards,
--
-- Gertjan van Oosten, mcvax!westc!gertjan
-- West Consulting bv, Phoenixstraat 49, 2611 AL  Delft, The Netherlands
--                     P.O. Box 3318,    2601 DH  Delft
-- Tel: +31-15-123190, Fax: +31-15-147889

From jerry@olivey.olivetti.com Fri Jan 12 21:02:22 1990
Path: uunet!mailrus!ames!oliveb!olivey!jerry
From: jerry@olivey.olivetti.com (Jerry Aguirre)
Newsgroups: news.software.b
Subject: Bug in news.2.11.18-19 updating minart.
Keywords: news expire minart
Message-ID: <53602@oliveb.olivetti.com>
Date: 13 Jan 90 02:02:22 GMT
Sender: news@oliveb.olivetti.com
Lines: 17

In news 2.11 patch 18 the min and max article number fields in the active
file were expanded from 5 digits to 7 digits.  The initialization of the
minart value in expire didn't get updated to match.

In expire.c line 897 the line:

	minart = 99999L;

should read:

	minart = 9999999L;

Presumably this means that as articles numbers roll past 99999 the minart
field in the active file will limit at 99999 and never catch up with the
real minimum article number.  I have one group at 60000 so that day
isn't so far away.
				Jerry Aguirre


From epimass!jbuck@apple.com Fri Apr  7 14:47:33 1989
Received: from apple.com by uunet.UU.NET (5.61/1.14) with SMTP 
	id AA17283; Fri, 7 Apr 89 14:47:12 -0400
Received: by apple.com (5.59/25-eef)
	for rick@uunet.uu.net@uunet.uu.net
	id AA06459; Fri, 7 Apr 89 11:47:03 PDT
Received: by epimass.EPI.COM (MC 2.0/smail2.2/05-17-87)
	id AA06061; Fri, 7 Apr 89 10:42:52 PST
From: jbuck@epimass.EPI.COM (Joe Buck)
Message-Id: <8904071842.AA06061@epimass.EPI.COM>
Subject: Question about sys file processing for distributions
To: rick@uunet.UU.NET
Date: Fri, 7 Apr 89 11:42:50 PDT
Cc: oliveb!ames!iuvax!bsu-cs!dhesi@apple.com (Rahul Dhesi)
X-Mailer: Elm [version 2.1 PL1]
Status: RO

Rick,

I've been looking at making a change in news to allow patterns such as

	!!alt.flame

appearing in the /usr/lib/news/sys file to cause a posting to be
rejected, or not transmitted, if ANY of its groups are alt.flame
(!alt.flame won't stop crossposted articles).  The patch for this is
easy:

------------------------------------------------------------------------
*** funcs.c.old	Thu Apr  6 11:33:46 1989
--- funcs.c	Thu Apr  6 11:37:06 1989
***************
*** 53,60
  		for (s = sublist; *s != '\0';) {
  			if (*s != NEGCHAR)
  				rc = rc || ptrncmp(s, n);
! 			else
! 				rc = rc && !ptrncmp(s+1, n);
  			while (*s++ != NGDELIM && *s != '\0')
  				;
  		}

--- 53,63 -----
  		for (s = sublist; *s != '\0';) {
  			if (*s != NEGCHAR)
  				rc = rc || ptrncmp(s, n);
! /* If we match a "!!group" pattern, reject article unconditionally */
! 			else if (*++s == NEGCHAR && ptrncmp (s+1, n))
! 				return FALSE;
! /* !pattern: clear the flag but keep looking for a match */
! 			else rc = rc && !ptrncmp(s, n);
  			while (*s++ != NGDELIM && *s != '\0')
  				;
  		}
------------------------------------------------------------------------

I've been having some discussions with Rahul Dhesi, moderator of
comp.binaries.ibm.pc, about technical solutions to resolve the shareware
controversy -- how to provide an easy way to avoid any legal problems
with tranmitting it over the Internet, etc, if that's illegal or if people
don't want to subsidize shareware authors but still allow it for people
who want it.  Rahul proposed that a new distribution, "payware" be added,
so he could say

Distribution: world,payware

in headers of "commercial" articles.

He initially proposed "!!" in the context of putting "!!payware" in
your sys file, after I explained to him that just "!payware" wouldn't
work.  The patch above would allow this feature too (!! working on
both distributions and newsgroups), except for one problem: the code
in ifuncs.c that checks newsgroups and distributions does

 		if (*dist == '\0')
 			dist = "world";
 		if (!ngmatch(dist, srec.s_nbuf) && !ngmatch(srec.s_nbuf, dist))
 			    continue;

That is, it calls ngmatch "backwards" as well as forwards.  The only
reason I can think of to do this is to support "!distribution" in a
Distribution header, something like

Distribution: !ny

The problem is that this won't work; if that is the intent of this
code, it doesn't do what's intended.  (I suspect that it did work
before the default distribution of "world" was added).

It seems to me that this code is erroneous and is contributing
significantly to the extra CPU cost of having complex sys lines (3
scans instead of 2 of the sys line).  This suggests that the code
should be

 		if (*dist == '\0')
 			dist = "world";
 		if (!ngmatch(dist, srec.s_nbuf))
 			    continue;

Right?  Or am I missing something significant?

Thanks for whatever you can tell me.

- Joe

From leres@helios.ee.lbl.gov Sat Apr  7 00:57:48 1990
Path: uunet!samsung!usc!ucsd!helios.ee.lbl.gov!ace.ee.lbl.gov!leres
From: leres@ace.ee.lbl.gov (Craig Leres)
Newsgroups: news.software.b,news.admin
Subject: Re: What's this strange thing?
Message-ID: <5349@helios.ee.lbl.gov>
Date: 7 Apr 90 04:57:48 GMT
References: <397@sickkids.UUCP>
Sender: usenet@helios.ee.lbl.gov
Reply-To: leres@helios.ee.lbl.gov (ucbvax!leres for uucp weenies)
Organization: Lawrence Berkeley Laboratory, Berkeley
Lines: 77
X-Local-Date: 6 Apr 90 21:57:48 PDT

Ah ha! Looks like Mark Bartelt is well onto a bug that has been
annoying me for the last few months.

The first thing I noticed was that getfield() uses strncpy(), one of my
favorite sources of bugs. Note the unusual (but documented) feature:

    Strncpy copies exactly "count" characters, appending nulls if
    "from" is less than "count" characters in length; the target may
    not be null-terminated if the length of "from" is "count" or more.

So even though the code is careful to leave room for the null
terminator, it doesn't actually install one. If that last byte happens
to be non-zero, string manipulations on the from field will munge on
the path field.

The next problem is that fixfrom() can (theoretically) increase the
length of the from header (say if the closing paren is missing as Mark
suggests). So if the address and comment are too large, just toss the
comment.

Context diffs to src/header.c are appended.

		Craig
------
RCS file: RCS/header.c,v
retrieving revision 1.5
diff -c -r1.5 header.c
*** /tmp/,RCSt1a22288	Fri Apr  6 21:16:27 1990
--- header.c	Fri Apr  6 21:15:40 1990
***************
*** 345,360 ****
  fixfrom(hp)
  register struct hbuf *hp;
  {
! 	char frombuf[PATHLEN];
! 	char fullname[BUFLEN];
  
  	skin(frombuf, fullname, hp->from);	/* remove RFC822-style comments */
! 	if (fullname[0] != '\0') {
  		strcat(frombuf, " (");
  		strcat(frombuf, fullname);
  		strcat(frombuf, ")");
  	}
  	strcpy(hp->from, frombuf);	/* stick the canonicalized "from" back in */
  }
  
  skin(name, fullname, hfield)
--- 345,363 ----
  fixfrom(hp)
  register struct hbuf *hp;
  {
! 	char frombuf[sizeof(hp->from)];
! 	char fullname[sizeof(hp->from)];
  
  	skin(frombuf, fullname, hp->from);	/* remove RFC822-style comments */
! 	/* Only append comment if it fits */
! 	if (fullname[0] != '\0' && strlen(frombuf) + 2 +
! 	    strlen(fullname) + 1 <= sizeof(hp->from) - 1) {
  		strcat(frombuf, " (");
  		strcat(frombuf, fullname);
  		strcat(frombuf, ")");
  	}
  	strcpy(hp->from, frombuf);	/* stick the canonicalized "from" back in */
+ 
  }
  
  skin(name, fullname, hfield)
***************
*** 533,538 ****
--- 536,542 ----
  		;
  	if (*ptr != '\0') {
  		(void) strncpy(hpfield, ptr, size - 1);
+ 		ptr[size - 1] = '\0';
  		(void) nstrip(hpfield);
  	}
  }


From weening@Gang-of-Four.Stanford.EDU Mon Apr  9 23:05:33 1990
Received: from Gang-of-Four.Stanford.EDU by uunet.uu.net (5.61/1.14) with SMTP 
	id AA05936; Mon, 9 Apr 90 23:05:28 -0400
Received: by Gang-of-Four.Stanford.EDU (5.61/inc-1.0)
	id AA17143; Mon, 9 Apr 90 20:05:50 -0700
Date: Mon, 9 Apr 90 20:05:50 -0700
From: weening@Gang-of-Four.Stanford.EDU (Joe Weening)
Message-Id: <9004100305.AA17143@Gang-of-Four.Stanford.EDU>
To: rick@uunet.uu.net
Subject: Bug/misfeature in news 2.11 patch 18
Status: R

I just got around to installing news 2.11 patches 18 and 19 on a
system that does batching, and ran into a problem with the fix
described in the patch message as:

	fixed batch to return to BATCHDIR before renaming work file.

This only works if you are in BATCHDIR when running batch!!  I don't
see why you shouldn't be able to run batch in any directory.  The fix
below, which I had applied to patchlevel 17, worked much better.

						Joe


>From: lmb@vicom.COM (Larry Blair)
Newsgroups: news.software.b
Subject: Re: News 2.11.17 breaks "batch"
Date: 28 Jan 89 00:52:36 GMT
Reply-To: lmb@vicom.COM (Larry Blair)
Organization: VICOM Systems Inc., San Jose, CA

Here is a patch that fixes the problem with batch.  I only wrote it for
systems that have BSD4_2 or USG defined, since I don't know that a get
current directory function is available on other types.  This patch won't
hurt those systems, but they should be sure that the batch file name
given to batch is a full pathname (starts with a /).

*** batch.c.2.17	Fri Jan 27 16:22:19 1989
--- batch.c	Fri Jan 27 16:44:04 1989
***************
*** 42,47 ****
--- 42,48 ----
  
  #if defined(USG) || defined(BSD4_2)
  #include <fcntl.h>
+ char saved_dir[PATHLEN];
  #endif
  
  struct stat sbuf;
***************
*** 92,99 ****
  		exit(1);
  	}
  
  	if (chdir(SPOOLDIR) < 0) {
! 		logerror("chdir(%s): %s", workfile, sys_errlist[errno]);
  		exit(1);
  	}
  
--- 93,107 ----
  		exit(1);
  	}
  
+ #if defined(USG)
+ 	getcwd(saved_dir, PATHLEN);
+ #endif
+ #if defined(BSD4_2)
+ 	getwd(saved_dir);
+ #endif
+ 
  	if (chdir(SPOOLDIR) < 0) {
! 		logerror("chdir(%s): %s", SPOOLDIR, sys_errlist[errno]);
  		exit(1);
  	}
  
***************
*** 150,155 ****
--- 158,171 ----
  			break;
  		}
  	}
+ 
+ #if defined(USG) || defined(BSD4_2)
+ 	if (chdir(saved_dir) < 0) {
+ 		logerror("chdir(%s): %s", saved_dir, sys_errlist[errno]);
+ 		exit(1);
+ 	}
+ #endif
+ 
  	if (fdstatus != NULL) {		/* exceeded maxbytes */
  		char tmpfile[512];
  
-- 
Larry Blair   ames!vsi1!lmb   lmb@vicom.com

From rac@sherpa.UUCP Mon Apr  9 15:42:39 1990
Path: uunet!pdn!palan!sherpa!rac
From: rac@sherpa.UUCP (Roger Cornelius)
Newsgroups: news.software.b
Subject: Bug in fascist()
Keywords: funcs.c
Message-ID: <244@sherpa.UUCP>
Date: 9 Apr 90 19:42:39 GMT
Organization: Personal System Computing,  St. Petersburg, FL
Lines: 38

This is B news patchlevel 19.

fascist() in funcs.c calls feof() before processing each line of the
authorized file, so the last line of authorized is always ignored.  Moving
the feof() call to the last statement in the while loop fixes it, but
I'm not sure why feof() is needed to begin with.  There is already a
check for EOF in the statement which fscanf()s the authorized file.
Am I missing something.

Simple patch follows.

*** ofuncs.c	Mon Apr  9 15:22:21 1990
--- funcs.c	Mon Apr  9 15:26:40 1990
***************
*** 684,691 ****
  	facfd = fopen(factemp, "r");
  	if (facfd != NULL) { /* If no such file, use global default only */
  		while (fscanf(facfd, "%[^:]:%s\n", facuser, factemp) != EOF) {
- 			if (feof(facfd))
- 				break;
  			if (facuser[0] == '#') continue;
  			if (facuser[0] == '\\') {
  				if (!grplist) grplist = getgrplist(user);
--- 684,689 ----
***************
*** 701,706 ****
--- 699,706 ----
  				(void) strcat(facgroups, factemp);
  				break;
  			}
+ 			if (feof(facfd))
+ 				break;
  		}
  		fclose (facfd);
  	}

--
Roger A. Cornelius          rac@sherpa.UUCP         uunet!sherpa!rac


From yenta!dt@uunet.uu.net Thu Apr 19 12:28:16 1990
Received: from seismo.CSS.GOV by uunet.uu.net (5.61/1.14) with SMTP 
	id AA05476; Thu, 19 Apr 90 12:28:14 -0400
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.61/1.14)
	id AA28375; Thu, 19 Apr 90 12:28:12 -0400
Received: from seismo.CSS.GOV by beno.CSS.GOV (4.0/SMI-4.0)
	id AA08763; Thu, 19 Apr 90 12:28:10 EDT
Received: from uunet.UU.NET by seismo.CSS.GOV (5.61/1.14)
	id AA28371; Thu, 19 Apr 90 12:28:07 -0400
Received: from yenta.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA05443; Thu, 19 Apr 90 12:28:02 -0400
Received: by yenta.UUCP (smail2.5)
	id AA01322; 19 Apr 90 02:36:31 MDT (Thu)
Subject: Minor bug in sendbatch script
Message-Id: <9004190236.AA01318@yenta.UUCP>
Date: 19 Apr 90 02:36:29 MDT (Thu)
From: yenta!dt@uunet.uu.net (David B. Thomas)
To: rick@seismo.CSS.GOV
Status: R

Dear Mr. Adams,

	I accidentally encountered a minor bug in the 'sendbatch' script
for bnews 2.11.

Note that the following code only assigns a value to $du if MAXBATCH is
nonempty (true, in my script), and the directory /usr/spool/uucp/$rmt
exists (never true for my primitive uucp system).

>	if test -n "$MAXBATCH" -a -d /usr/spool/uucp/$rmt
>	then
>		du=`du "/usr/spool/uucp/$rmt" | sed 's/	.*/000/'`
>		if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)
>		then 
>			echo $rmt already has $du Kbytes queued
>			continue
>		fi
>	fi

Later, $du is called upon, and was never set.

>	# make sure $? is zero
>	sentbytes=0
>	bytes_this_batch=`expr $MAXBATCH - $du`

I implemented a quickie fix by adding the line "du=0" before the first
"if" clause quoted above.  Anyway, I thought I should report the bug.

			Thanks for your great software and fantastic docs..

					David B. Thomas
					(uunet!yenta!dt)

From slm@wsc-sun.boeing.com Fri Apr 27 17:09:27 1990
Received: from atc.boeing.com by uunet.uu.net (5.61/1.14) with SMTP 
	id AA07103; Fri, 27 Apr 90 17:09:22 -0400
Received: by atc.boeing.com on Fri, 27 Apr 90 14:08:11 PDT
Received: from shuksan. by wsc-sun (4.1/SMI-4.0)
	id AA26893; Fri, 27 Apr 90 14:09:29 PDT
Received: by shuksan. (4.0/SMI-4.0)
	id AA02649; Fri, 27 Apr 90 14:11:27 PDT
Date: Fri, 27 Apr 90 14:11:27 PDT
From: slm@wsc-sun.boeing.com (Shamus McBride)
Message-Id: <9004272111.AA02649@shuksan.>
To: rick@uunet.uu.net
Subject: bnews-2.11 & moderators file
Status: R

I ran into the following problem with bnews-2.11 and the "moderators" file:

   I wanted to comment out a moderator line so I put a '#' in column 1 and
   inews went into an infinite cpu loop. Analysis showed that mod_file_okay
   was stuck on a fscanf which couldn't get past the comment (i.e., fscanf
   was returning 0 and not advancing the stream).

Anyway, I cut some code to read in complete lines, ignore lines starting
with '#' and that aren't formatted correctly. Not completely satisfied 
with the rewrite since I'd prefer to support white-space separated names
(as well as commas), but at least now inews doesn't hang.

With old code 'group:user1,user2 user3' would hang. With new code it won't
hang, but user3 won't be recognized (one of those errors where you can 
look at a file for hours and not see the missing ','). 

I would have coded it with strtok, but I didn't know if there were
portability problems in using that routine. If you don't have the time
and 'strtok' is acceptable let me know and I'll recode the routine.

Finally, I never did find any documentation on the "moderators" file 
or the fact that the "mailpaths" file can have newsgroups moderators 
listed in it. I have the INSTALL document dated 27 October 1986, perhaps
there is a newer version.

--
Name:       Shamus Mc Bride		
Employer:   Boeing Computer Services
Email:      slm%wsc-sun@atc.boeing.com  (static routers)
 or  :      slm@wsc-sun.boeing.com      (domain routers)
 UUCP:      uw-beaver!uw-june!bcsaic!wsc-sun!slm
Voice:      (206) 865-5047
US mail:    MS 7A-35/Boeing Computer Services
	    P.O.Box 24346/Seattle, WA 98124-0346
MOTTO:      A reasonable limit is one I never reach.
DISCLAIMER: The opinions expressed are my personal views and do not
	    necessarily reflect those of The Boeing Company.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
patchlevel.h:
#define	PATCHLEVEL	19
#define NEWS_VERSION   "B 2.11.19 10/30/89"

       O /
--------X----CUT HERE------------------------------------------------------
       O \

*** ifuncs.c.orig	Mon Oct 30 15:50:56 1989
--- ifuncs.c	Thu Apr 26 11:36:34 1990
***************
*** 1229,1244 ****
  	char *grplist = NULL;
  	char *p, *getgrplist();
  	int ret = FALSE;
! 	char mfn[BUFLEN], mgrp[BUFLEN], mlist[LBUFLEN];
  
! 	sprintf(mfn, "%s/%s", LIB, "moderators");
! 	mfd = fopen(mfn, "r");
  	if (mfd == NULL)
  		return FALSE;
! 	while ((!ret) && fscanf(mfd, "%[^:]:%s\n", mgrp, mlist) != EOF) {
! 		if (mgrp[0] == '#')
  			continue;
! 		if (!STRCMP(ngname, mgrp)) {
  			while (*(p = ((p = rindex(mlist, ',')) ? p : mlist ))
  			      && (ret == FALSE)) {
  					if (*p == ',')
--- 1229,1252 ----
  	char *grplist = NULL;
  	char *p, *getgrplist();
  	int ret = FALSE;
! 	char mbuf[LBUFLEN];
! 	char *mlist;
  
! 	sprintf(mbuf, "%s/%s", LIB, "moderators");
! 	mfd = fopen(mbuf, "r");
  	if (mfd == NULL)
  		return FALSE;
! 	while ((!ret) && fgets(mbuf, LBUFLEN, mfd) != NULL) {
! 		if (mbuf[0] == '#')
  			continue;
! 		if ((p = index(mbuf, ':')) == NULL)
! 			continue;
! 		*p = '\0';
! 		for (mlist = ++p; *p; p++)
! 			if (isspace(*p) || *p == '#')
! 				break;
! 		*p = '\0';
! 		if (!STRCMP(ngname, mbuf)) {
  			while (*(p = ((p = rindex(mlist, ',')) ? p : mlist ))
  			      && (ret == FALSE)) {
  					if (*p == ',')

--
end of message

From news@rulcvx.LeidenUniv.nl Thu May 10 06:33:09 1990
Received: from seismo.CSS.GOV by uunet.uu.net (5.61/1.14) with SMTP 
	id AA00524; Thu, 10 May 90 06:33:07 -0400
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.61/1.14)
	id AA10243; Thu, 10 May 90 06:33:04 -0400
Received: from seismo.CSS.GOV by beno.CSS.GOV (4.0/SMI-4.0)
	id AA16981; Thu, 10 May 90 06:33:03 EDT
Received: from mcsun.eu.net by seismo.CSS.GOV (5.61/1.14)
	id AA10233; Thu, 10 May 90 06:32:49 -0400
Received: by mcsun.EU.net with SMTP; Thu, 10 May 90 12:32:44 +0200 (MET)
Received: from rulcvx.LeidenUniv.nl by hp4nl.nluug.nl with UUCP via EUnet
          id AA19022 (5.58.1.14/2.14); Thu, 10 May 90 12:34:25 MET
Received: by rulcvx.LeidenUniv.nl (5.51/7.1)
	id AA03124; Thu, 10 May 90 12:26:20 +0200
From: NEWS system <rulcvx!news@relay.EU.net>
Message-Id: <9005101026.AA03124@rulcvx.LeidenUniv.nl>
Subject: Bugs in Bnews 2.11 PL19, at least at our site.
To: rick@seismo.CSS.GOV (Rick Adams)
Date: Thu, 10 May 90 12:26:19 MET DST
X-Mailer: ELM [version 2.2 PL16]
Status: RO


Hello Stranger,

we have currently updated our Bnews 2.11 system to patchlevel 19.
However, when we did this, sendbatch stopped working.  So I started
hacking.  After some deliberation I came to the following conclusion;
you use separate directories in /usr/spool/uucp for each machine, that
feeds from you.  We, however, are still a small site and feed "all"
our news via /usr/spool/uucp.  Therefore, the following clause from
sendbatch.sh will not be executed, leaving variable $du empty (line
91):

    89		if test -n "$MAXBATCH" -a -d /usr/spool/uucp/$rmt
    90		then
    91			du=`du "/usr/spool/uucp/$rmt" | sed 's/	.*/000/'`
    92			if test ! -z "$du" -a \( "$du" -gt $MAXBATCH \)
    93			then 
    94				echo $rmt already has $du Kbytes queued
    95				continue
    96			fi
    97		fi

When you start using $du further on, no test of this kind is made and
sh(1) starts complaining in line 117, followed by test(1) in line 118;
the output is just the following two text lines.

syntax error
test: argument expected

Line 117 leaves $bytes_this_batch empty, which bugs test(1).

   115		# make sure $? is zero
   116		sentbytes=0
   117		bytes_this_batch=`expr $MAXBATCH - $du`
   118		if test $bytes_this_batch -gt $MAXPERRUN
   119		then
   120			bytes_this_batch=$MAXPERRUN
   121		fi
   122		while test $? -eq 0 -a $sentbytes -le $bytes_this_batch -a \
   123			\( \( $sentbytes -eq 0 -a -s $BATCH/$rmt \) -o \
   124			 -s $BATCH/$rmt.work \)
   125		[etc]

The second bug is, that you have inserted lines between (current)
lines 116 and 122: one can't be sure $? will be zero during the first
test(1) in line 122.

I have made a patch of the modifications I made.  Hope this helps.

Greetings, and thanks for a major league software package!

Stefan Linnemann.

*** sendbatch.sh.PL19	Thu Dec 21 12:18:09 1989
--- sendbatch.sh	Wed May  9 16:26:50 1990
***************
*** 112,120
  		rm $BATCH/$rmt.$$
  	fi
  
! 	# make sure $? is zero
! 	sentbytes=0
! 	bytes_this_batch=`expr $MAXBATCH - $du`
  	if test $bytes_this_batch -gt $MAXPERRUN
  	then
  		bytes_this_batch=$MAXPERRUN

--- 112,123 -----
  		rm $BATCH/$rmt.$$
  	fi
  
! 	if test -n "$du"
! 	then
! 		bytes_this_batch=`expr $MAXBATCH - $du`
! 	else
! 		bytes_this_batch=$MAXBATCH
! 	fi
  	if test $bytes_this_batch -gt $MAXPERRUN
  	then
  		bytes_this_batch=$MAXPERRUN
***************
*** 119,124
  	then
  		bytes_this_batch=$MAXPERRUN
  	fi
  	while test $? -eq 0 -a $sentbytes -le $bytes_this_batch -a \
  		\( \( $sentbytes -eq 0 -a -s $BATCH/$rmt \) -o \
  		 -s $BATCH/$rmt.work \)

--- 122,129 -----
  	then
  		bytes_this_batch=$MAXPERRUN
  	fi
+ 	# make sure $? is zero
+ 	sentbytes=0
  	while test $? -eq 0 -a $sentbytes -le $bytes_this_batch -a \
  		\( \( $sentbytes -eq 0 -a -s $BATCH/$rmt \) -o \
  		 -s $BATCH/$rmt.work \)

From brian%cyberpunk@ucsd.edu Tue May 29 11:23:43 1990
Received: from ucsd.edu by uunet.uu.net (5.61/1.14) with SMTP 
	id AA00819; Tue, 29 May 90 11:23:35 -0400
Received: from cyberpunk.ucsd.edu by ucsd.edu; id AA17373
	sendmail 5.61/UCSD-2.1-sun via SMTP
	Tue, 29 May 90 08:23:30 -0700 for rick@uunet.uu.net
Received: by cyberpunk.ucsd.edu (4.1/UCSDGENERIC.3)
	id AA12278 to rick@uunet.uu.net; Tue, 29 May 90 08:23:27 PDT
Date: Tue, 29 May 90 08:23:27 PDT
From: brian%cyberpunk@ucsd.edu (Brian Kantor)
Message-Id: <9005291523.AA12278@cyberpunk.ucsd.edu>
To: muller@ucsd.edu, rick@uunet.uu.net
Subject: Forwarded - a patch to fix a minor bug in news header handling
Status: R

------- Forwarded Message

Date: 7 Apr 90 04:57:48 GMT
From: leres@ace.ee.lbl.gov (Craig Leres)
Subject: Re: What's this strange thing?
Newsgroups: news.software.b,news.admin

Ah ha! Looks like Mark Bartelt is well onto a bug that has been
annoying me for the last few months.

The first thing I noticed was that getfield() uses strncpy(), one of my
favorite sources of bugs. Note the unusual (but documented) feature:

    Strncpy copies exactly "count" characters, appending nulls if
    "from" is less than "count" characters in length; the target may
    not be null-terminated if the length of "from" is "count" or more.

So even though the code is careful to leave room for the null
terminator, it doesn't actually install one. If that last byte happens
to be non-zero, string manipulations on the from field will munge on
the path field.

The next problem is that fixfrom() can (theoretically) increase the
length of the from header (say if the closing paren is missing as Mark
suggests). So if the address and comment are too large, just toss the
comment.

Context diffs to src/header.c are appended.

		Craig
------
RCS file: RCS/header.c,v
retrieving revision 1.5
diff -c -r1.5 header.c
*** /tmp/,RCSt1a22288	Fri Apr  6 21:16:27 1990
--- header.c	Fri Apr  6 21:15:40 1990
***************
*** 345,360 ****
  fixfrom(hp)
  register struct hbuf *hp;
  {
! 	char frombuf[PATHLEN];
! 	char fullname[BUFLEN];
  
  	skin(frombuf, fullname, hp->from);	/* remove RFC822-style comments */
! 	if (fullname[0] != '\0') {
  		strcat(frombuf, " (");
  		strcat(frombuf, fullname);
  		strcat(frombuf, ")");
  	}
  	strcpy(hp->from, frombuf);	/* stick the canonicalized "from" back in */
  }
  
  skin(name, fullname, hfield)
--- 345,363 ----
  fixfrom(hp)
  register struct hbuf *hp;
  {
! 	char frombuf[sizeof(hp->from)];
! 	char fullname[sizeof(hp->from)];
  
  	skin(frombuf, fullname, hp->from);	/* remove RFC822-style comments */
! 	/* Only append comment if it fits */
! 	if (fullname[0] != '\0' && strlen(frombuf) + 2 +
! 	    strlen(fullname) + 1 <= sizeof(hp->from) - 1) {
  		strcat(frombuf, " (");
  		strcat(frombuf, fullname);
  		strcat(frombuf, ")");
  	}
  	strcpy(hp->from, frombuf);	/* stick the canonicalized "from" back in */
+ 
  }
  
  skin(name, fullname, hfield)
***************
*** 533,538 ****
--- 536,542 ----
  		;
  	if (*ptr != '\0') {
  		(void) strncpy(hpfield, ptr, size - 1);
+ 		ptr[size - 1] = '\0';
  		(void) nstrip(hpfield);
  	}
  }

------- End of Forwarded Message

From rayssd!anomaly.sbs.com!mike@uunet.uu.net Wed Jun  6 04:27:37 1990
Received: from seismo.CSS.GOV by uunet.uu.net (5.61/1.14) with SMTP 
	id AA27136; Wed, 6 Jun 90 04:27:33 -0400
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.61/1.14)
	id AA09378; Wed, 6 Jun 90 03:21:04 -0400
Received: from seismo.CSS.GOV by beno.CSS.GOV (4.0/SMI-4.0)
	id AA16329; Wed, 6 Jun 90 03:20:59 EDT
Received: from uunet.UU.NET by seismo.CSS.GOV (5.61/1.14)
	id AA09370; Wed, 6 Jun 90 03:20:55 -0400
Received: from rayssd.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA07936; Wed, 6 Jun 90 03:20:49 -0400
Received: from anomaly with UUCP by rayssd.ssd.ray.com ; Wed, 6 Jun 90 02:23:49 -0400
Received: by anomaly.sbs.com (smail2.5)
	id AA01132; 6 Jun 90 00:07:12 EDT (Wed)
Subject: Localize.Xnx386
To: rick@seismo.CSS.GOV
Date: Wed, 6 Jun 90 0:07:11 EDT
From: Michael P. Deignan <mike@anomaly.sbs.com>
X-Mailer: ELM [version 2.2 PL9]
Message-Id: <9006060007.AA01128@anomaly.sbs.com>
Status: R

Mr. Adams,

We have just finished compiling Bnews v2.11 patchlevel 19 on our XENIX
386 system. Attached below is the Localize.xenix file which allowed us
to compile cleanly with no modifications. I thought this may be helpful
to any other XENIX-386 users who might need it.

Mike Deignan
mike@anomaly.sbs.com
...!uunet!rayssd!anomaly!mike

-=-

#
#	This is correct for the
#		XENIX 386 v2.3.2 Development System
#	version. There are so many versions of xenix out there
#	that it is probabably wrong for yours. At least this should give
#	you a starting point.
#
rm -f Makefile
cp Makefile.dst Makefile
chmod u+w Makefile
ed - Makefile  <<'EOF'
g/^#USG /s///
g/^#V7 /d
g/^#VMS /d
g/^#BSD4_[123] /d
g/#NOTVMS/s/#NOTVMS.*//
g/^MISC *=/s/$/ uname.o/
g/^UUXFLAGS/s//UUXFLAGS =/
g/^IBMFLAGS/s/$/ -DM_XENIX/
g/^LIBS/s/$/ -lx -ldbm/
g/termlib/s//curses -ltermcap/
g/^LFLAGS =/s/$/ -m ${@}.map/
g/rm -f $(COMMANDS) $(OTHERS) \*.o a.out/s/a.out/\*.map a.out/
g/-o inews/s/-o/-m inews.map -o/
g/-o readnews/s/-o/-m readnews.map -o/
g/-o vnews /s/-o/-m vnews.map -o /
g/-o checknews/s/-o/-o/
g/-o expire/s/-o/-o/
g/-Dvfork=fork/s///
g/-Dindex=strchr/s///
g/-Drindex=strrchr/s///
g/^SCCSID/s/^/#/
w
q
EOF

rm -f defs.h
cp defs.dist defs.h
chmod u+w defs.h
ed - defs.h <<'EOF'
g/#define TMAIL/s//\/\* #define TMAIL/
g/\/usr\/ucb\/more/s//\/usr\/bin\/more/
g/uux - -r -z/s//uux - /
g/uucpname/s//systemid/
g/\/\* #define LOCKF/s//#define LOCKF/
g/\/\* #define UUNAME/s/...//
w
q
EOF

From matthew@sunpix.East.Sun.COM Wed Jun  6 10:12:15 1990
Path: uunet!snorkelwacker!usc!cs.utexas.edu!rutgers!mcnc!rti!sunpix!matthew
From: matthew@sunpix.East.Sun.COM ( Sun Visualization Products)
Newsgroups: news.software.b
Subject: Minor bugs in recnews.c (Bnews 2.11.19)
Keywords: Double quotes, backslashes, recnews.c (v2.20)
Message-ID: <2138@sunpix.East.Sun.COM>
Date: 6 Jun 90 14:12:15 GMT
Organization: Sun Microsystems, Research Triangle Park, NC
Lines: 90


     After having two mail messages, which were for an internal newgroup, 
end up in newgroup "general", I set out to find the problem.

     What I found I would classify as 'Once in a blue moon problem'.  

     What was happening, was that any message ending in a double quote ended
up in the "general" newgroup.  Why? Because a bug in the pipeopen() function
would  cause  the uncontested  coping  of  the  next two characters  after a 
backslash, not just the next one. The cure? The simple removal of one of the
copy statements (line 395).

     During my analysis of the problem, I also noticed that backslashes were
being properly protected.  That fixed required slight changes to lines  161,
176, and 313.

     Below is a short patch to recnews.

#ifdef SCCSID
static char	*SccsId = "@(#)recnews.c	2.20	1/17/89";
#endif /* SCCSID */

*** recnews.c.orig	Wed Jun  6 09:00:20 1990
--- recnews.c	Wed Jun  6 09:06:17 1990
***************
*** 158,164 ****
  				p = buf + 8;
  			q = subject;
  			while (*++p) {
! 				if (*p == '"')
  					*q++ = '\\';
  				*q++ = *p;
  			}
--- 158,164 ----
  				p = buf + 8;
  			q = subject;
  			while (*++p) {
! 				if (*p == '"' || *p == '\\')
  					*q++ = '\\';
  				*q++ = *p;
  			}
***************
*** 173,179 ****
  				p = buf + 3;
  			q = to;
  			while (*++p) {
! 				if (*p == '"')
  					*q++ = '\\';
  				*q++ = *p;
  			}
--- 173,179 ----
  				p = buf + 3;
  			q = to;
  			while (*++p) {
! 				if (*p == '"' || *p == '\\')
  					*q++ = '\\';
  				*q++ = *p;
  			}
***************
*** 310,316 ****
  		p = buf + 4;
  	q = fbuf;
  	while (*++p) {
! 		if (*p == '"')
  			*q++ = '\\';
  		*q++ = *p;
  	}
--- 310,316 ----
  		p = buf + 4;
  	q = fbuf;
  	while (*++p) {
! 		if (*p == '"' || *p == '\\')
  			*q++ = '\\';
  		*q++ = *p;
  	}
***************
*** 392,398 ****
  					while (*cmd) {
  						if(*cmd == '\\') {
  							cmd++;
- 							*bcp++ = *cmd++;
  						} else if (*cmd == '"')
  							break;
  						*bcp++ = *cmd++;
--- 392,397 ----
-- 
Matthew Lee Stier                            |
Sun Microsystems ---  RTP, NC  27709-3447    |     "Wisconsin   Escapee"
uucp:  sun!mstier or mcnc!rti!sunpix!matthew |
phone: (919) 469-8300 fax: (919) 460-8355    |


From analytics!rcsmith Fri Jun  8 15:14:06 1990
Received: from analytics.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA18725; Fri, 8 Jun 90 15:14:02 -0400
Received: by anagld.analytics.com (5.52/smail2.5/10-10-89)
	id AA04390; Fri, 8 Jun 90 15:12:34 EDT
From: rcsmith@anagld.analytics.com (Ray Smith)
Message-Id: <9006081912.AA04390@anagld.analytics.com>
Subject: Problem in makeactive.sh (Bnews 2.11)
To: rick@uunet.uu.net
Date: Fri, 8 Jun 90 15:12:27 EDT
Reply-To: rcsmith@anagld
Return-Receipt-To: rcsmith@anagld
X-Mailer: ELM [version 2.3 PL1]
Status: R

There is a problem in the "makeactive.sh" on line 424.  The initial size
of the highest & lowest article numbers is set to 5 as opposed to 7 which
is what is HARD coded in the inews (line 913) program.  The following
section from the shell should give you an idea of the problem.

NOTE: This appears to be what caused the problem on my Solbourne.

/********* Begin included section *************/
: if active file is empty, create it
if test ! -s $LIBDIR/active
then
	sed 's/[ 	].*/ 00000 00001/' /tmp/$$groups > $LIBDIR/active
			     ^^^^^^^^^^^
			     Here it is!
	cat <<'E_O_F' >>$LIBDIR/active
control 0000000 0000000
junk 0000000 0000000
E_O_F
	set - group 0 1
else
/********* End included section *************/

From netagw!bill Sun Jun 17 16:21:03 1990
Received: from netagw.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA22033; Sun, 17 Jun 90 16:21:02 -0400
Received: by netagw.com (Smail 3.1.18.1)
	id <m0hh65N-0002KPC@netagw.com>; Sun, 17 Jun 90 16:19:09 EDT
Message-Id: <m0hh65N-0002KPC@netagw.com>
From: bill@netagw.com (Bill Aten)
Subject: Getting inews to clean up after itself (fwd)
To: adams@uunet.uu.net (Rick Adams)
Date: Sun, 17 Jun 90 16:19:09 EDT
X-Mailer: ELM [version 2.3 PL2]
Status: R

Rick,

Glancing through Bnews 2.11 and the inews.c module, I see you have claimed
the copyright on inews.c (I'm making a leap here in assuming you're the
same Rick Adams).

So if you are one and the same, I thought I'd forward along the following
to you on the outside chance you're still collecting items for a possible
PL20 to Bnews.

I have no idea of the validity of the problem, or the fix, but felt you
should at least know that the message exists.  With all the news that flows
these days, it's easy to overlook some things unintentionally.

If it turns out that this is misdirected, sorry for the inconvenience, and
hit "d" for delete :-).

Regards,

Bill Aten
_____________________________________________________________________________

UUCP:  ...!uunet!netagw!bill                       Internet:  bill@netagw.com
_____________________________________________________________________________
From: matthew@sunpix.East.Sun.COM ( Sun Visualization Products)
Newsgroups: news.software.b
Subject: Getting inews to clean up after itself
Keywords: Bnews 2.11.19, NFSCLIENT
Message-ID: <2535@sunpix.East.Sun.COM>
Date: 16 Jun 90 21:36:25 GMT
Organization: Sun Microsystems, Research Triangle Park, NC
Lines: 27


    With bnews (2.11.19) run in a 'NFS server/client mode', the client version
of inews leaves hidden temporary files in the '/tmp' directory of every machine
it is run on.  This is due to the fact that the 'NFS client' version of inews
does not unlink all the temporary files it uses.  To correct this problem, a
single statement needs to be added to inews.c.

    At line 1224, add a "(void) unlink(INFILE);" to change:

	(void) sprintf(command, NFSCMDFORMAT, NFSCMDARGS);
	status = system(command);
	(void) unlink(ARTICLE);
	exit(status);

    into:

	(void) sprintf(command, NFSCMDFORMAT, NFSCMDARGS);
	status = system(command);
	(void) unlink(INFILE);		/* unlink hidden temporary file */
	(void) unlink(ARTICLE);
	exit(status);

-- 
Matthew Lee Stier                            |
Sun Microsystems ---  RTP, NC  27709-3447    |     "Wisconsin   Escapee"
uucp:  sun!mstier or mcnc!rti!sunpix!matthew |
phone: (919) 469-8300 fax: (919) 460-8355    |

From vixie@wrl.dec.com Sun Jul 29 22:02:35 1990
Received: from decpa.pa.dec.com by uunet.uu.net (5.61/1.14) with SMTP 
	id AA18313; Sun, 29 Jul 90 22:02:33 -0400
Received: by decpa.pa.dec.com; id AA27353; Sun, 29 Jul 90 19:02:31 -0700
Received: by volition.pa.dec.com; id AA22352; Sun, 29 Jul 90 19:02:29 PDT
Date: Sun, 29 Jul 90 19:02:29 PDT
From: vixie@wrl.dec.com (Paul Vixie)
Message-Id: <9007300202.AA22352@volition.pa.dec.com>
To: rick@uunet.uu.net
Subject: cntrl.c bug? (maybe not in your version)
Status: R

*** /tmp/,RCSt1a22346	Sun Jul 29 19:02:27 1990
--- cntrl.c	Sun Jul 29 19:01:34 1990
***************
*** 127,133 ****
  char *wkpre;
  {
  	char msg[BUFSIZ], rqstr[BUFSIZ];
! 	register FILE *fp;
  	int filemode;
  	char filename[MAXFULLNAME], wrktype, *wrkvec[20];
  	extern (*Rdmsg)(), (*Wrmsg)();
--- 127,133 ----
  char *wkpre;
  {
  	char msg[BUFSIZ], rqstr[BUFSIZ];
! 	register FILE *fp = NULL;
  	int filemode;
  	char filename[MAXFULLNAME], wrktype, *wrkvec[20];
  	extern (*Rdmsg)(), (*Wrmsg)();
***************
*** 234,240 ****
  			&&  (stbuf.st_mode & ANYREAD) == 0) {
  		e_access:;
  				/*  access denied  */
! 				fclose(fp);
  				fp = NULL;
  				TransferSucceeded = 1; /* else will keep sending */
  				logent("DENIED", "ACCESS");
--- 234,242 ----
  			&&  (stbuf.st_mode & ANYREAD) == 0) {
  		e_access:;
  				/*  access denied  */
! 				if (fp) {
! 					fclose(fp);
! 				}
  				fp = NULL;
  				TransferSucceeded = 1; /* else will keep sending */
  				logent("DENIED", "ACCESS");

From rsalz@bbn.com Thu Aug  2 18:50:45 1990
Received: from PINEAPPLE.BBN.COM by uunet.uu.net (5.61/1.14) with SMTP 
	id AA10545; Thu, 2 Aug 90 18:49:22 -0400
Received: from LITCHI.BBN.COM by pineapple.bbn.com id <AA17142@pineapple.bbn.com>; Thu, 2 Aug 90 14:27:09 -0400
From: Rich Salz <rsalz@bbn.com>
Received: by litchi.bbn.com id <AA29098@litchi.bbn.com>; Thu, 2 Aug 90 14:27:02 EDT
Date: Thu, 2 Aug 90 14:27:02 EDT
Message-Id: <9008021827.AA29098@litchi.bbn.com>
To: rick@uunet.uu.net, smb@research.att.com, utzoo!henry
Subject: A cleaned up getdate.y ...
Status: R


We use getdate.y in Cronus here at work, and over time have done lots
of cleanups on the code.  I finally got around to pulling out the
Cronus stuff and making it fit the 2.11 header files.

It's a bit more typesafe, and a lot cleaner (the original, after all,
comes from v6...).  I hope you find it useful.

I thinking of enhancing the grammer.  Ideally, it should be recursive
so you can say "two weeks from 1/1/90".  That mean getting rid of just
about all the global variables, for example.

I hope you find this useful.  Unless anyone complains, I'm gonna post
this in a week or so to alt.sources, and then comp.sources.misc.
	/r$
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  getdate.y
# Wrapped by rsalz@litchi.bbn.com on Thu Aug  2 14:21:00 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive."'
if test -f 'getdate.y' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'getdate.y'\"
else
  echo shar: Extracting \"'getdate.y'\" \(19903 characters\)
  sed "s/^X//" >'getdate.y' <<'END_OF_FILE'
X%{
X/* $Revision: 1.1 $
X**
X**  This code is in the public domain.
X**  Originally written by Steven M. Bellovin <smb@research.att.com> while
X**  at the University of North Carolina at Chapel Hill.  Later tweaked by
X**  a couple of people on Usenet.  Completely overhauled by Rich $alz
X**  <rsalz@bbn.com> in August, 1990.
X*/
X/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
X/* SUPPRESS 288 on yyerrlab *//* Label unused */
X#include <stdio.h>
X#include <ctype.h>
X#include "defs.h"
X#include <sys/types.h>
X#if	defined(USG)
Xstruct timeb {
X    time_t		time;
X    unsigned short	millitm;
X    short		timezone;
X    short		dstflag;
X};
X#else
X#include <sys/timeb.h>
X#endif	/* defined(USG) */
X#if	defined(BSD4_2)
X#include <sys/time.h>
X#else
X#include <time.h>
X#endif	/* defined(BSD4_2) */
X
X#if	!defined(lint) && !defined(SABER)
Xstatic char RCS[] =
X	"$Header: str2date.y,v 1.1 90/06/27 12:08:10 cronan Exp $";
X#endif	/* !defined(lint) && !defined(SABER) */
X
X
X#define EPOCH		1970
X#define HOUR(x)		(x * 60)
X#define SECSPERDAY	(24L * 60L * 60L)
X
X
Xtypedef struct _TABLE {
X    char	*name;
X    int		type;
X    long	value;
X} TABLE;
X
Xtypedef enum _DSTMODE {
X    DSTon, DSToff, DSTmaybe
X} DSTMODE;
X
Xtypedef enum _MERIDIAN {
X    MERam, MERpm, MER24
X} MERIDIAN;
X
X
Xstatic char	*Input;
Xstatic DSTMODE	yyDSTmode;
Xstatic int	yyDayOrdinal;
Xstatic int	yyDayNumber;
Xstatic int	yyHaveDate;
Xstatic int	yyHaveDay;
Xstatic int	yyHaveRel;
Xstatic int	yyHaveTime;
Xstatic int	yyHaveZone;
Xstatic int	yyTimezone;
Xstatic int	yyDay;
Xstatic int	yyHour;
Xstatic int	yyMinutes;
Xstatic int	yyMonth;
Xstatic int	yySeconds;
Xstatic int	yyYear;
Xstatic MERIDIAN	yyMeridian;
Xstatic time_t	yyRelMonth;
Xstatic time_t	yyRelSeconds;
X
X
Xextern struct tm	*localtime();
X%}
X
X%union {
X    int			Number;
X    enum _MERIDIAN	Meridian;
X}
X
X%token	tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
X%token	tSEC_UNIT tSNUMBER tUNUMBER tZONE
X
X%type	<Number>	tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
X%type	<Number>	tSEC_UNIT tSNUMBER tUNUMBER tZONE
X%type	<Meridian>	tMERIDIAN o_merid
X
X%%
X
X
Xspec	: /* NULL */
X	| spec item
X	;
X
Xitem	: time {
X	    yyHaveTime++;
X	}
X	| zone {
X	    yyHaveZone++;
X	}
X	| date {
X	    yyHaveDate++;
X	}
X	| day {
X	    yyHaveDay++;
X	}
X	| rel {
X	    yyHaveRel++;
X	}
X	| number
X	;
X
Xtime	: tUNUMBER tMERIDIAN {
X	    yyHour = $1;
X	    yyMinutes = 0;
X	    yySeconds = 0;
X	    yyMeridian = $2;
X	}
X	| tUNUMBER ':' tUNUMBER o_merid {
X	    yyHour = $1;
X	    yyMinutes = $3;
X	    yySeconds = 0;
X	    yyMeridian = $4;
X	}
X	| tUNUMBER ':' tUNUMBER tSNUMBER {
X	    yyHour = $1;
X	    yyMinutes = $3;
X	    yyMeridian = MER24;
X	    yyDSTmode = DSToff;
X	    yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
X	}
X	| tUNUMBER ':' tUNUMBER ':' tUNUMBER  '.' tUNUMBER {
X	    yyHour = $1;
X	    yyMinutes = $3;
X	    yySeconds = $5;
X	    yyMeridian = MER24;
X	}
X	| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
X	    yyHour = $1;
X	    yyMinutes = $3;
X	    yySeconds = $5;
X	    yyMeridian = $6;
X	}
X	| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
X	    yyHour = $1;
X	    yyMinutes = $3;
X	    yySeconds = $5;
X	    yyMeridian = MER24;
X	    yyDSTmode = DSToff;
X	    yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
X	}
X	;
X
Xzone	: tZONE {
X	    yyTimezone = $1;
X	    yyDSTmode = DSToff;
X	}
X	| tDAYZONE {
X	    yyTimezone = $1;
X	    yyDSTmode = DSTon;
X	}
X	;
X
Xday	: tDAY {
X	    yyDayOrdinal = 1;
X	    yyDayNumber = $1;
X	}
X	| tDAY ',' {
X	    yyDayOrdinal = 1;
X	    yyDayNumber = $1;
X	}
X	| tUNUMBER tDAY {
X	    yyDayOrdinal = $1;
X	    yyDayNumber = $2;
X	}
X	;
X
Xdate	: tUNUMBER '/' tUNUMBER {
X	    yyMonth = $1;
X	    yyDay = $3;
X	}
X	| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
X	    yyMonth = $1;
X	    yyDay = $3;
X	    yyYear = $5;
X	}
X	| tMONTH tUNUMBER {
X	    yyMonth = $1;
X	    yyDay = $2;
X	}
X	| tMONTH tUNUMBER ',' tUNUMBER {
X	    yyMonth = $1;
X	    yyDay = $2;
X	    yyYear = $4;
X	}
X	| tUNUMBER tMONTH {
X	    yyMonth = $2;
X	    yyDay = $1;
X	}
X	| tUNUMBER tMONTH tUNUMBER {
X	    yyMonth = $2;
X	    yyDay = $1;
X	    yyYear = $3;
X	}
X	;
X
Xrel	: relunit tAGO {
X	    yyRelSeconds = -yyRelSeconds;
X	    yyRelMonth = -yyRelMonth;
X	}
X	| relunit
X	;
X
Xrelunit	: tUNUMBER tMINUTE_UNIT {
X	    yyRelSeconds += $1 * $2 * 60L;
X	}
X	| tSNUMBER tMINUTE_UNIT {
X	    yyRelSeconds += $1 * $2 * 60L;
X	}
X	| tMINUTE_UNIT {
X	    yyRelSeconds += $1 * 60L;
X	}
X	| tSNUMBER tSEC_UNIT {
X	    yyRelSeconds += $1;
X	}
X	| tUNUMBER tSEC_UNIT {
X	    yyRelSeconds += $1;
X	}
X	| tSEC_UNIT {
X	    yyRelSeconds++;
X	}
X	| tSNUMBER tMONTH_UNIT {
X	    yyRelMonth += $1 * $2;
X	}
X	| tUNUMBER tMONTH_UNIT {
X	    yyRelMonth += $1 * $2;
X	}
X	| tMONTH_UNIT {
X	    yyRelMonth += $1;
X	}
X	;
X
Xnumber	: tUNUMBER {
X	    if (yyHaveTime && yyHaveDate && !yyHaveRel)
X		yyYear = $1;
X	    else {
X		yyHaveTime++;
X		if ($1 < 100) {
X		    yyHour = $1;
X		    yyMinutes = 0;
X		}
X		else {
X		    yyHour = $1 / 100;
X		    yyMinutes = $1 % 100;
X		}
X		yySeconds = 0;
X		yyMeridian = MER24;
X	    }
X	}
X	;
X
Xo_merid	: /* NULL */ {
X	    $$ = MER24;
X	}
X	| tMERIDIAN {
X	    $$ = $1;
X	}
X	;
X
X%%
X
X/* Month and day table. */
Xstatic TABLE	MonthDayTable[] = {
X    { "january",	tMONTH,  1 },
X    { "february",	tMONTH,  2 },
X    { "march",		tMONTH,  3 },
X    { "april",		tMONTH,  4 },
X    { "may",		tMONTH,  5 },
X    { "june",		tMONTH,  6 },
X    { "july",		tMONTH,  7 },
X    { "august",		tMONTH,  8 },
X    { "september",	tMONTH,  9 },
X    { "sept",		tMONTH,  9 },
X    { "october",	tMONTH, 10 },
X    { "november",	tMONTH, 11 },
X    { "december",	tMONTH, 12 },
X    { "sunday",		tDAY, 0 },
X    { "monday",		tDAY, 1 },
X    { "tuesday",	tDAY, 2 },
X    { "tues",		tDAY, 2 },
X    { "wednesday",	tDAY, 3 },
X    { "wednes",		tDAY, 3 },
X    { "thursday",	tDAY, 4 },
X    { "thur",		tDAY, 4 },
X    { "thurs",		tDAY, 4 },
X    { "friday",		tDAY, 5 },
X    { "saturday",	tDAY, 6 },
X    { NULL }
X};
X
X/* Time units table. */
Xstatic TABLE	UnitsTable[] = {
X    { "year",		tMONTH_UNIT,	12 },
X    { "month",		tMONTH_UNIT,	1 },
X    { "fortnight",	tMINUTE_UNIT,	14 * 24 * 60 },
X    { "week",		tMINUTE_UNIT,	7 * 24 * 60 },
X    { "day",		tMINUTE_UNIT,	1 * 24 * 60 },
X    { "hour",		tMINUTE_UNIT,	60 },
X    { "minute",		tMINUTE_UNIT,	1 },
X    { "min",		tMINUTE_UNIT,	1 },
X    { "second",		tSEC_UNIT,	1 },
X    { "sec",		tSEC_UNIT,	1 },
X    { NULL }
X};
X
X/* Assorted relative-time words. */
Xstatic TABLE	OtherTable[] = {
X    { "tomorrow",	tMINUTE_UNIT,	1 * 24 * 60 },
X    { "yesterday",	tMINUTE_UNIT,	-1 * 24 * 60 },
X    { "today",		tMINUTE_UNIT,	0 },
X    { "now",		tMINUTE_UNIT,	0 },
X    { "last",		tUNUMBER,	-1 },
X    { "this",		tMINUTE_UNIT,	0 },
X    { "next",		tUNUMBER,	2 },
X    { "first",		tUNUMBER,	1 },
X/*  { "second",		tUNUMBER,	2 }, */
X    { "third",		tUNUMBER,	3 },
X    { "fourth",		tUNUMBER,	4 },
X    { "fifth",		tUNUMBER,	5 },
X    { "sixth",		tUNUMBER,	6 },
X    { "seventh",	tUNUMBER,	7 },
X    { "eighth",		tUNUMBER,	8 },
X    { "ninth",		tUNUMBER,	9 },
X    { "tenth",		tUNUMBER,	10 },
X    { "eleventh",	tUNUMBER,	11 },
X    { "twelfth",	tUNUMBER,	12 },
X    { "ago",		tAGO,	1 },
X    { NULL }
X};
X
X/* The timezone table. */
Xstatic TABLE	TimezoneTable[] = {
X    { "gmt",	tZONE,     HOUR( 0) },	/* Greenwich Mean */
X    { "ut",	tZONE,     HOUR( 0) },	/* Universal (Coordinated) */
X    { "utc",	tZONE,     HOUR( 0) },
X    { "wet",	tZONE,     HOUR( 0) },	/* Western European */
X    { "bst",	tDAYZONE,  HOUR( 0) },	/* British Summer */
X    { "wat",	tZONE,     HOUR( 1) },	/* West Africa */
X    { "at",	tZONE,     HOUR( 2) },	/* Azores */
X#if	0
X    /* For completeness.  BST is also British Summer, and GST is
X     * also Guam Standard. */
X    { "bst",	tZONE,     HOUR( 3) },	/* Brazil Standard */
X    { "gst",	tZONE,     HOUR( 3) },	/* Greenland Standard */
X#endif
X    { "nft",	tZONE,     HOUR(3.5) },	/* Newfoundland */
X    { "nst",	tZONE,     HOUR(3.5) },	/* Newfoundland Standard */
X    { "ndt",	tDAYZONE,  HOUR(3.5) },	/* Newfoundland Daylight */
X    { "ast",	tZONE,     HOUR( 4) },	/* Atlantic Standard */
X    { "adt",	tDAYZONE,  HOUR( 4) },	/* Atlantic Daylight */
X    { "est",	tZONE,     HOUR( 5) },	/* Eastern Standard */
X    { "edt",	tDAYZONE,  HOUR( 5) },	/* Eastern Daylight */
X    { "cst",	tZONE,     HOUR( 6) },	/* Central Standard */
X    { "cdt",	tDAYZONE,  HOUR( 6) },	/* Central Daylight */
X    { "mst",	tZONE,     HOUR( 7) },	/* Mountain Standard */
X    { "mdt",	tDAYZONE,  HOUR( 7) },	/* Mountain Daylight */
X    { "pst",	tZONE,     HOUR( 8) },	/* Pacific Standard */
X    { "pdt",	tDAYZONE,  HOUR( 8) },	/* Pacific Daylight */
X    { "yst",	tZONE,     HOUR( 9) },	/* Yukon Standard */
X    { "ydt",	tDAYZONE,  HOUR( 9) },	/* Yukon Daylight */
X    { "hst",	tZONE,     HOUR(10) },	/* Hawaii Standard */
X    { "hdt",	tDAYZONE,  HOUR(10) },	/* Hawaii Daylight */
X    { "cat",	tZONE,     HOUR(10) },	/* Central Alaska */
X    { "ahst",	tZONE,     HOUR(10) },	/* Alaska-Hawaii Standard */
X    { "nt",	tZONE,     HOUR(11) },	/* Nome */
X    { "idlw",	tZONE,     HOUR(12) },	/* International Date Line West */
X    { "cet",	tZONE,     -HOUR(1) },	/* Central European */
X    { "met",	tZONE,     -HOUR(1) },	/* Middle European */
X    { "mewt",	tZONE,     -HOUR(1) },	/* Middle European Winter */
X    { "mest",	tDAYZONE,  -HOUR(1) },	/* Middle European Summer */
X    { "swt",	tZONE,     -HOUR(1) },	/* Swedish Winter */
X    { "sst",	tDAYZONE,  -HOUR(1) },	/* Swedish Summer */
X    { "fwt",	tZONE,     -HOUR(1) },	/* French Winter */
X    { "fst",	tDAYZONE,  -HOUR(1) },	/* French Summer */
X    { "eet",	tZONE,     -HOUR(2) },	/* Eastern Europe, USSR Zone 1 */
X    { "bt",	tZONE,     -HOUR(3) },	/* Baghdad, USSR Zone 2 */
X    { "it",	tZONE,     -HOUR(3.5) },/* Iran */
X    { "zp4",	tZONE,     -HOUR(4) },	/* USSR Zone 3 */
X    { "zp5",	tZONE,     -HOUR(5) },	/* USSR Zone 4 */
X    { "ist",	tZONE,     -HOUR(5.5) },/* Indian Standard */
X    { "zp6",	tZONE,     -HOUR(6) },	/* USSR Zone 5 */
X#if	0
X    /* For completeness.  NST is also Newfoundland Stanard, nad SST is
X     * also Swedish Summer. */
X    { "nst",	tZONE,     -HOUR(6.5) },/* North Sumatra */
X    { "sst",	tZONE,     -HOUR(7) },	/* South Sumatra, USSR Zone 6 */
X#endif	/* 0 */
X    { "wast",	tZONE,     -HOUR(7) },	/* West Australian Standard */
X    { "wadt",	tDAYZONE,  -HOUR(7) },	/* West Australian Daylight */
X    { "jt",	tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
X    { "cct",	tZONE,     -HOUR(8) },	/* China Coast, USSR Zone 7 */
X    { "jst",	tZONE,     -HOUR(9) },	/* Japan Standard, USSR Zone 8 */
X    { "cast",	tZONE,     -HOUR(9.5) },/* Central Australian Standard */
X    { "cadt",	tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
X    { "east",	tZONE,     -HOUR(10) },	/* Eastern Australian Standard */
X    { "eadt",	tDAYZONE,  -HOUR(10) },	/* Eastern Australian Daylight */
X    { "gst",	tZONE,     -HOUR(10) },	/* Guam Standard, USSR Zone 9 */
X    { "nzt",	tZONE,     -HOUR(12) },	/* New Zealand */
X    { "nzst",	tZONE,     -HOUR(12) },	/* New Zealand Standard */
X    { "nzdt",	tDAYZONE,  -HOUR(12) },	/* New Zealand Daylight */
X    { "idle",	tZONE,     -HOUR(12) },	/* International Date Line East */
X    {  NULL  }
X};
X
X/* Military timezone table. */
Xstatic TABLE	MilitaryTable[] = {
X    { "a",	tZONE,	HOUR(  1) },
X    { "b",	tZONE,	HOUR(  2) },
X    { "c",	tZONE,	HOUR(  3) },
X    { "d",	tZONE,	HOUR(  4) },
X    { "e",	tZONE,	HOUR(  5) },
X    { "f",	tZONE,	HOUR(  6) },
X    { "g",	tZONE,	HOUR(  7) },
X    { "h",	tZONE,	HOUR(  8) },
X    { "i",	tZONE,	HOUR(  9) },
X    { "k",	tZONE,	HOUR( 10) },
X    { "l",	tZONE,	HOUR( 11) },
X    { "m",	tZONE,	HOUR( 12) },
X    { "n",	tZONE,	HOUR(- 1) },
X    { "o",	tZONE,	HOUR(- 2) },
X    { "p",	tZONE,	HOUR(- 3) },
X    { "q",	tZONE,	HOUR(- 4) },
X    { "r",	tZONE,	HOUR(- 5) },
X    { "s",	tZONE,	HOUR(- 6) },
X    { "t",	tZONE,	HOUR(- 7) },
X    { "u",	tZONE,	HOUR(- 8) },
X    { "v",	tZONE,	HOUR(- 9) },
X    { "w",	tZONE,	HOUR(-10) },
X    { "x",	tZONE,	HOUR(-11) },
X    { "y",	tZONE,	HOUR(-12) },
X    { "z",	tZONE,	HOUR(  0) },
X    { NULL }
X};
X
X
X
X
X/* ARGSUSED */
Xstatic
Xyyerror(s)
X    char	*s;
X{
X}
X
X
Xstatic time_t
XToSeconds(Hours, Minutes, Seconds, Meridian)
X    register int	Hours;
X    register int	Minutes;
X    register int	Seconds;
X    MERIDIAN		Meridian;
X{
X    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
X	return -1;
X    switch (Meridian) {
X    case MER24:
X	if (Hours < 0 || Hours > 23)
X	    return -1;
X	return (Hours * 60L + Minutes) * 60L + Seconds;
X    case MERam:
X	if (Hours < 1 || Hours > 12)
X	    return -1;
X	return (Hours * 60L + Minutes) * 60L + Seconds;
X    case MERpm:
X	if (Hours < 1 || Hours > 12)
X	    return -1;
X	return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
X    }
X    /* NOTREACHED */
X}
X
X
Xstatic time_t
XConvert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, Timezone, DSTmode)
X    int		Month;
X    int		Day;
X    int		Year;
X    int		Hours;
X    int		Minutes;
X    int		Seconds;
X    MERIDIAN	Meridian;
X    int		Timezone;
X    DSTMODE	DSTmode;
X{
X    static int	DaysInMonth[12] = {
X	31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
X    };
X    time_t	tod;
X    time_t	Julian;
X    int		i;
X
X    if (Year < 0)
X	Year = -Year;
X    if (Year < 100)
X	Year += 1900;
X    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
X		    ? 29 : 28;
X    if (Year < EPOCH || Year > 1999
X     || Month < 1 || Month > 12
X     || Day < 1 || Day > DaysInMonth[--Month])
X	return -1;
X
X    for (Julian = Day - 1, i = 0; i < Month; i++)
X	Julian += DaysInMonth[i];
X    for (i = EPOCH; i < Year; i++)
X	Julian += 365 + (i % 4 == 0);
X    Julian *= SECSPERDAY;
X    Julian += Timezone * 60L;
X    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
X	return -1;
X    Julian += tod;
X    if (DSTmode == DSTon
X     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
X	Julian -= 60 * 60;
X    return Julian;
X}
X
X
Xstatic time_t
XDSTcorrect(Start, Future)
X    time_t	Start;
X    time_t	Future;
X{
X    int		StartDay;
X    int		FutureDay;
X
X    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
X    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
X    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
X}
X
X
Xstatic time_t
XRelativeDate(Start, DayOrdinal, DayNumber)
X    time_t	Start;
X    int		DayOrdinal;
X    int		DayNumber;
X{
X    struct tm	*tm;
X    time_t	now;
X
X    now = Start;
X    tm = localtime(&now);
X    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
X    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
X    return DSTcorrect(Start, now);
X}
X
X
Xstatic time_t
XRelativeMonth(Start, RelMonth)
X    time_t	Start;
X    time_t	RelMonth;
X{
X    struct tm	*tm;
X    int		Month;
X    int		Year;
X
X    tm = localtime(&Start);
X    Month = tm->tm_year * 12 + tm->tm_mon + RelMonth;
X    Year = Month / 12;
X    Month = Month % 12 + 1;
X    return DSTcorrect(Start,
X		Convert(Month, tm->tm_mday, Year,
X		    tm->tm_hour, tm->tm_min, tm->tm_sec,
X		    MER24, yyTimezone, DSTmaybe));
X}
X
X
Xstatic int
XLookupWord(buff)
X    char		*buff;
X{
X    register char	*p;
X    register char	*q;
X    register TABLE	*tp;
X    int			i;
X    int			abbrev;
X
X    /* Make it lowercase. */
X    for (p = buff; *p; p++)
X	if (isupper(*p))
X	    *p = tolower(*p);
X
X    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
X	yylval.Meridian = MERam;
X	return tMERIDIAN;
X    }
X    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
X	yylval.Meridian = MERpm;
X	return tMERIDIAN;
X    }
X
X    /* See if we have an abbreviation for a month. */
X    if (strlen(buff) == 3)
X	abbrev = 1;
X    else if (strlen(buff) == 4 && buff[3] == '.') {
X	abbrev = 1;
X	buff[3] = '\0';
X    }
X    else
X	abbrev = 0;
X
X    for (tp = MonthDayTable; tp->name; tp++) {
X	if (abbrev) {
X	    if (strncmp(buff, tp->name, 3) == 0) {
X		yylval.Number = tp->value;
X		return tp->type;
X	    }
X	}
X	else if (strcmp(buff, tp->name) == 0) {
X	    yylval.Number = tp->value;
X	    return tp->type;
X	}
X    }
X
X    for (tp = TimezoneTable; tp->name; tp++)
X	if (strcmp(buff, tp->name) == 0) {
X	    yylval.Number = tp->value;
X	    return tp->type;
X	}
X
X    for (tp = UnitsTable; tp->name; tp++)
X	if (strcmp(buff, tp->name) == 0) {
X	    yylval.Number = tp->value;
X	    return tp->type;
X	}
X
X    /* Strip off any plural and try the units table again. */
X    i = strlen(buff) - 1;
X    if (buff[i] == 's') {
X	buff[i] = '\0';
X	for (tp = UnitsTable; tp->name; tp++)
X	    if (strcmp(buff, tp->name) == 0) {
X		yylval.Number = tp->value;
X		return tp->type;
X	    }
X    }
X
X    for (tp = OtherTable; tp->name; tp++)
X	if (strcmp(buff, tp->name) == 0) {
X	    yylval.Number = tp->value;
X	    return tp->type;
X	}
X
X    /* Military timezones. */
X    if (buff[1] == '\0' && isalpha(*buff)) {
X	for (tp = MilitaryTable; tp->name; tp++)
X	    if (strcmp(buff, tp->name) == 0) {
X		yylval.Number = tp->value;
X		return tp->type;
X	    }
X    }
X
X    /* Drop out any periods and try the timezone table again. */
X    for (i = 0, p = q = buff; *q; q++)
X	if (*q != '.')
X	    *p++ = *q;
X	else
X	    i++;
X    *p = '\0';
X    if (i)
X	for (tp = TimezoneTable; tp->name; tp++)
X	    if (strcmp(buff, tp->name) == 0) {
X		yylval.Number = tp->value;
X		return tp->type;
X	    }
X
X    return tID;
X}
X
X
Xstatic int
Xyylex()
X{
X    register char	c;
X    register char	*p;
X    char		buff[40];
X    int			Count;
X    int			sign;
X
X    for ( ; ; ) {
X	while (isspace(*Input))
X	    Input++;
X
X	if (isdigit(c = *Input) || c == '-' || c == '+') {
X	    if (c == '-' || c == '+') {
X		sign = c == '-' ? -1 : 1;
X		if (!isdigit(*++Input))
X		    /* skip the '-' sign */
X		    continue;
X	    }
X	    else
X		sign = 0;
X	    for (yylval.Number = 0; isdigit(c = *Input++); )
X		yylval.Number = yylval.Number * 10 + c - '0';
X	    Input--;
X	    if (sign < 0)
X		yylval.Number = -yylval.Number;
X	    return sign ? tSNUMBER : tUNUMBER;
X	}
X	if (isalpha(c)) {
X	    for (p = buff; isalpha(c = *Input++) || c == '.'; )
X		if (p < &buff[sizeof buff - 1])
X		    *p++ = c;
X	    *p = '\0';
X	    Input--;
X	    return LookupWord(buff);
X	}
X	if (c != '(')
X	    return *Input++;
X	Count = 0;
X	do {
X	    c = *Input++;
X	    if (c == '\0')
X		return c;
X	    if (c == '(')
X		Count++;
X	    else if (c == ')')
X		Count--;
X	} while (Count > 0);
X    }
X}
X
X
Xtime_t
Xgetdate(p, now)
X    char		*p;
X    struct timeb	*now;
X{
X    struct tm		*tm;
X    struct timeb	ftz;
X    time_t		Start;
X    time_t		tod;
X
X    if (now == NULL) {
X	now = &ftz;
X#ifdef USG
X	/* Set the timezone global. */
X	tzset();
X	(void)time(&Start);
X	ftz.time = Start;
X	ftz.timezone = (int) timezone / 60;
X#else
X	(void)ftime(&ftz);
X#endif	/* USG */
X    }
X
X    tm = localtime(&now->time);
X    yyYear = tm->tm_year;
X    yyMonth = tm->tm_mon + 1;
X    yyDay = tm->tm_mday;
X    yyTimezone = now->timezone;
X    yyDSTmode = DSTmaybe;
X    yyHour = 0;
X    yyMinutes = 0;
X    yySeconds = 0;
X    yyMeridian = MER24;
X    yyRelSeconds = 0;
X    yyRelMonth = 0;
X    yyHaveDate = 0;
X    yyHaveDay = 0;
X    yyHaveRel = 0;
X    yyHaveTime = 0;
X    yyHaveZone = 0;
X
X    Input = p;
X    if (yyparse()
X     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
X	return -1;
X
X    if (yyHaveDate || yyHaveTime || yyHaveDay) {
X	Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
X		    yyMeridian, yyTimezone, yyDSTmode);
X	if (Start < 0)
X	    return -1;
X    }
X    else {
X	Start = now->time;
X	if (!yyHaveRel)
X	    Start -= ((tm->tm_hour * 60L) + tm->tm_min * 60L) + tm->tm_sec;
X    }
X
X    Start += yyRelSeconds;
X    if (yyRelMonth)
X	Start += RelativeMonth(Start, yyRelMonth);
X
X    if (yyHaveDay && !yyHaveDate) {
X	tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
X	Start += tod;
X    }
X
X    /* Have to do *something* with a legitimate -1 so it's distinguishable
X     * from the error return value.  (Alternately could set errno on error.) */
X    return Start == -1 ? 0 : Start;
X}
X
X
X
X#ifdef	TEST
X
X/* ARGSUSED */
Xmain(ac, av)
X    int		ac;
X    char	*av[];
X{
X    char	buff[128];
X    time_t	t;
X    char	*ctime();
X
X    printf("Enter date, or blank line to exit.\n\t> ");
X    (void)fflush(stdout);
X    while (gets(buff) && buff[0]) {
X	if ((t = getdate(buff, (struct timeb *)NULL)) == -1)
X	    printf("Bad format - couldn't convert.\n");
X	else
X	    printf("%s", ctime(&t));
X	printf("\t> ");
X	(void)fflush(stdout);
X    }
X    exit(0);
X}
X#endif	/* TEST */
END_OF_FILE
  if test 19903 -ne `wc -c <'getdate.y'`; then
    echo shar: \"'getdate.y'\" unpacked with wrong size!
  fi
  # end of 'getdate.y'
fi
echo shar: End of archive.
exit 0

From john@frog.UUCP Tue Aug  7 16:34:00 1990
Path: uunet!crdgw1!uakari.primate.wisc.edu!samsung!crackers!cpoint!frog!john
From: john@frog.UUCP (John Woods)
Newsgroups: news.software.b
Subject: a minor bug in cgtdate() (funcs2.c)
Keywords: news B 2.19 and older
Message-ID: <17515@frog.UUCP>
Date: 7 Aug 90 20:34:00 GMT
Organization: Misanthropes-R-Us
Lines: 29

There is a minor bug in the cgtdate() routine in funcs2.c (I believe I
have B news patched to 2.19).  If a particularly long and ill-formed Expires:
line is found in an article, a buffer on the stack can be overflowed, with
varying consequences depending on the layout of the variables on the stack.
The fix is something like:
*** funcs2.c.old  Tue Aug  7 12:30:44 1990
--- funcs2.c  Tue Aug  7 12:29:38 1990
***************
*** 221,227 ****
  	lasttime = getdate(lastdatestr, &Now);
  	if (lasttime < 0) {
  		logerr("%s: Unparsable date \"%s\"", filename, lastdatestr);
! 		if (sscanf(lastdatestr, "%s %s %s %s %s",
  			junk, month, day, tod,
  			year) == 5) {
  			(void) sprintf(bfr, "%s %s, %s %s", month, day, year,

--- 221,227 ----
  	lasttime = getdate(lastdatestr, &Now);
  	if (lasttime < 0) {
  		logerr("%s: Unparsable date \"%s\"", filename, lastdatestr);
! 		if (sscanf(lastdatestr, "%39s %39s %29s %59s %49s",
  			junk, month, day, tod,
  			year) == 5) {
  			(void) sprintf(bfr, "%s %s, %s %s", month, day, year,

-- 
John Woods, Charles River Data Systems, Framingham MA, (508) 626-1101
...!decvax!frog!john, john@frog.UUCP, ...!mit-eddie!jfw, jfw@eddie.mit.edu


From wswietse@tue.nl Thu Sep  6 07:36:46 1990
Received: from tuegate.tue.nl by uunet.uu.net (5.61/1.14) with SMTP 
	id AA28570; Thu, 6 Sep 90 07:36:24 -0400
Received: by tuegate.tue.nl id AA04147
  (5.64+/TUE-1.1 for rick@uunet.uu.net); Thu, 6 Sep 90 13:36:38 +0200
Date: Thu, 6 Sep 90 13:36:38 +0200
From: Wietse Venema <wswietse@tue.nl>
Message-Id: <9009061136.AA04147@tuegate.tue.nl>
To: rick@uunet.uu.net
Subject: 2.11.19 expire -r problem with nntpd
Cc: wswietse@tue.nl
Status: R

Question:
	Is the following problem known? Would it help if I posted a
	brief note on this matter to news.software.{b,nntp}?

Description:

	When setting up a number of news feeds through nntp, I stumbled
	across a minor problem with the way that B news 2.11.19
	expire(8) creates a new-style history data base from scratch.

	For news downloading via nntp, it is essential that the news
	history be sorted with respect to arrival time of articles.

	It seems that the sort(1) command used by expire(8) when
	rebuilding the history data base from scratch (-r option) still
	assumes old history file format.

Suggested fix:

*** expire.c-	Thu Dec 21 12:18:05 1989
--- expire.c	Thu Aug 30 16:28:09 1990
***************
*** 360,366
  					sizeof (struct multhist));
  			mh_size = SPACE_INCREMENT;
  
! 			(void) sprintf(afline, "exec sort -t\t +1.6 -2 +1 >%s",
  #ifdef DBM
  			NARTFILE);
  #else /* !DBM */

--- 360,366 -----
  					sizeof (struct multhist));
  			mh_size = SPACE_INCREMENT;
  
! 			(void) sprintf(afline, "exec sort -t'\t' +1 >%s",
  #ifdef DBM
  			NARTFILE);
  #else /* !DBM */

From rsalz@bbn.com Wed Sep 19 12:45:33 1990
Path: uunet!lll-winken!sol.ctr.columbia.edu!samsung!usc!apple!bbn.com!papaya.bbn.com!rsalz
From: rsalz@bbn.com (Rich Salz)
Newsgroups: news.software.b,news.admin,alt.sources
Subject: A new version of getdate.y
Message-ID: <2851@litchi.bbn.com>
Date: 19 Sep 90 16:45:33 GMT
Followup-To: news.software.b
Organization: BBN Systems and Technology, Inc.
Lines: 948

This is a new version of getdate.y.  It has several timezone fixes,
documentation on what else needs to be done, int/long problems fixed, and
so on.  Slightly earlier versions of this have been sent to Steve
Bellovin, the original author, and the maintainers of C and B news.

I don't know if/when I'll have a chance to do make the other changes
Steve recommends, but I look forward to comments at any rate.

	/rich $alz

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  README.getdate getdate.y
# Wrapped by rsalz@litchi.bbn.com on Wed Sep 19 12:42:42 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive."'
if test -f 'README.getdate' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README.getdate'\"
else
  echo shar: Extracting \"'README.getdate'\" \(2104 characters\)
  sed "s/^X//" >'README.getdate' <<'END_OF_FILE'
X
XWe've been using Steve Bellovin's getdate() routine in the Cronus project
Xfor over a year.  This past summer Jim Berets and I cleaned up all the
Xtimezones, cleaned up some int/long problems that others have found,
Xreformatted the code and cleaned it up, and contacted Steve about what
Xshould else needs to be done with it.
X
XUnfortunately, we didn't have the time to do anything much with Steve's
Xcomments, other then document them in the code, and here (thanks to Steve
Xfor letting me quote some email):
X    Two things need to be done.  First, the purpose of getdate should be
X    defined; many of its features were for a rather different purpose that
X    it's used for today.  Specifically, I was implementing 'at' before
X    there was such a thing, and I wanted the ability to specify relative
X    intervals.  Thus, getdate accepts things like 'two weeks'.  I don't
X    think that code is tremendously useful.  If it is, it could be
X    strengthened by writing a better grammar, i.e., ``two weeks after
X    monday'' -- currently, the word ``after'' isn't accept, and the
X    relationship between the day of the week and the interval is
X    peculiar.  And that in turn goes back to the central implementation
X    failure:  it is restricted to a simple 'int' stack, because that's all
X    that v6 yacc allowed.  There's also a lot of reliance on global
X    variables, for the same reason.  Using a union as the stack type, one
X    could store much better information, clean up the code, and make the
X    semantics much clearer.  (As a trivial change, I suspect that the
X    military time zones are wrong, as I took them from RFC822 (or maybe
X    even 733), and I've since learned that those are incorrect.  I'd drop
X    that entirely.) It might also be worth some effort to make the time
X    zone stuff more compatible with the 4.3tahoe and the SysVR3.2 stuff,
X    especially as regards the names of the zones.
X
X    It was also intended to let utter novices set the date on a UNIX
X    machine after rebooting it and thus it accepted almost any rational
X    form.
X
XHope you find this useful.
X	/rich $alz
END_OF_FILE
  if test 2104 -ne `wc -c <'README.getdate'`; then
    echo shar: \"'README.getdate'\" unpacked with wrong size!
  fi
  # end of 'README.getdate'
fi
if test -f 'getdate.y' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'getdate.y'\"
else
  echo shar: Extracting \"'getdate.y'\" \(20830 characters\)
  sed "s/^X//" >'getdate.y' <<'END_OF_FILE'
X%{
X/* $Revision: 2.1 $
X**
X**  Originally written by Steven M. Bellovin <smb@research.att.com> while
X**  at the University of North Carolina at Chapel Hill.  Later tweaked by
X**  a couple of people on Usenet.  Completely overhauled by Rich $alz
X**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
X**  send any email to Rich.
X**
X**  This grammar has eight shift/reduce conflicts.
X**
X**  This code is in the public domain and has no copyright.
X*/
X/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
X/* SUPPRESS 288 on yyerrlab *//* Label unused */
X#include "defs.h"
X#include <stdio.h>
X#include <ctype.h>
X
X#if	defined(vms)
X#include <types.h>
X#include <time.h>
X#else
X#include <sys/types.h>
X#if	defined(USG)
X/*
X**  Uncomment the next line if you need to do a tzset() call to set the
X**  timezone, and don't have ftime().  Some SystemV releases, I think.
X*/
X/*#define NEED_TZSET */
Xstruct timeb {
X    time_t		time;		/* Seconds since the epoch	*/
X    unsigned short	millitm;	/* Field not used		*/
X    short		timezone;
X    short		dstflag;	/* Field not used		*/
X};
X#else
X#include <sys/timeb.h>
X#endif	/* defined(USG) */
X#if	defined(BSD4_2)
X#include <sys/time.h>
X#else
X#include <time.h>
X#endif	/* defined(BSD4_2) */
X#endif	/* defined(vms) */
X
X#if	!defined(lint) && !defined(SABER)
Xstatic char RCS[] =
X	"$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $";
X#endif	/* !defined(lint) && !defined(SABER) */
X
X
X#define EPOCH		1970
X#define HOUR(x)		(x * 60)
X#define SECSPERDAY	(24L * 60L * 60L)
X
X
X/*
X**  An entry in the lexical lookup table.
X*/
Xtypedef struct _TABLE {
X    char	*name;
X    int		type;
X    time_t	value;
X} TABLE;
X
X
X/*
X**  Daylight-savings mode:  on, off, or not yet known.
X*/
Xtypedef enum _DSTMODE {
X    DSTon, DSToff, DSTmaybe
X} DSTMODE;
X
X/*
X**  Meridian:  am, pm, or 24-hour style.
X*/
Xtypedef enum _MERIDIAN {
X    MERam, MERpm, MER24
X} MERIDIAN;
X
X
X/*
X**  Global variables.  We could get rid of most of these by using a good
X**  union as the yacc stack.  (This routine was originally written before
X**  yacc had the %union construct.)  Maybe someday; right now we only use
X**  the %union very rarely.
X*/
Xstatic char	*yyInput;
Xstatic DSTMODE	yyDSTmode;
Xstatic time_t	yyDayOrdinal;
Xstatic time_t	yyDayNumber;
Xstatic int	yyHaveDate;
Xstatic int	yyHaveDay;
Xstatic int	yyHaveRel;
Xstatic int	yyHaveTime;
Xstatic int	yyHaveZone;
Xstatic time_t	yyTimezone;
Xstatic time_t	yyDay;
Xstatic time_t	yyHour;
Xstatic time_t	yyMinutes;
Xstatic time_t	yyMonth;
Xstatic time_t	yySeconds;
Xstatic time_t	yyYear;
Xstatic MERIDIAN	yyMeridian;
Xstatic time_t	yyRelMonth;
Xstatic time_t	yyRelSeconds;
X
X
Xextern struct tm	*localtime();
X%}
X
X%union {
X    time_t		Number;
X    enum _MERIDIAN	Meridian;
X}
X
X%token	tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
X%token	tSEC_UNIT tSNUMBER tUNUMBER tZONE
X
X%type	<Number>	tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
X%type	<Number>	tSEC_UNIT tSNUMBER tUNUMBER tZONE
X%type	<Meridian>	tMERIDIAN o_merid
X
X%%
X
Xspec	: /* NULL */
X	| spec item
X	;
X
Xitem	: time {
X	    yyHaveTime++;
X	}
X	| zone {
X	    yyHaveZone++;
X	}
X	| date {
X	    yyHaveDate++;
X	}
X	| day {
X	    yyHaveDay++;
X	}
X	| rel {
X	    yyHaveRel++;
X	}
X	| number
X	;
X
Xtime	: tUNUMBER tMERIDIAN {
X	    yyHour = $1;
X	    yyMinutes = 0;
X	    yySeconds = 0;
X	    yyMeridian = $2;
X	}
X	| tUNUMBER ':' tUNUMBER o_merid {
X	    yyHour = $1;
X	    yyMinutes = $3;
X	    yySeconds = 0;
X	    yyMeridian = $4;
X	}
X	| tUNUMBER ':' tUNUMBER tSNUMBER {
X	    yyHour = $1;
X	    yyMinutes = $3;
X	    yyMeridian = MER24;
X	    yyDSTmode = DSToff;
X	    yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
X	}
X	| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
X	    yyHour = $1;
X	    yyMinutes = $3;
X	    yySeconds = $5;
X	    yyMeridian = $6;
X	}
X	| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
X	    yyHour = $1;
X	    yyMinutes = $3;
X	    yySeconds = $5;
X	    yyMeridian = MER24;
X	    yyDSTmode = DSToff;
X	    yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
X	}
X	;
X
Xzone	: tZONE {
X	    yyTimezone = $1;
X	    yyDSTmode = DSToff;
X	}
X	| tDAYZONE {
X	    yyTimezone = $1;
X	    yyDSTmode = DSTon;
X	}
X	;
X
Xday	: tDAY {
X	    yyDayOrdinal = 1;
X	    yyDayNumber = $1;
X	}
X	| tDAY ',' {
X	    yyDayOrdinal = 1;
X	    yyDayNumber = $1;
X	}
X	| tUNUMBER tDAY {
X	    yyDayOrdinal = $1;
X	    yyDayNumber = $2;
X	}
X	;
X
Xdate	: tUNUMBER '/' tUNUMBER {
X	    yyMonth = $1;
X	    yyDay = $3;
X	}
X	| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
X	    yyMonth = $1;
X	    yyDay = $3;
X	    yyYear = $5;
X	}
X	| tMONTH tUNUMBER {
X	    yyMonth = $1;
X	    yyDay = $2;
X	}
X	| tMONTH tUNUMBER ',' tUNUMBER {
X	    yyMonth = $1;
X	    yyDay = $2;
X	    yyYear = $4;
X	}
X	| tUNUMBER tMONTH {
X	    yyMonth = $2;
X	    yyDay = $1;
X	}
X	| tUNUMBER tMONTH tUNUMBER {
X	    yyMonth = $2;
X	    yyDay = $1;
X	    yyYear = $3;
X	}
X	;
X
Xrel	: relunit tAGO {
X	    yyRelSeconds = -yyRelSeconds;
X	    yyRelMonth = -yyRelMonth;
X	}
X	| relunit
X	;
X
Xrelunit	: tUNUMBER tMINUTE_UNIT {
X	    yyRelSeconds += $1 * $2 * 60L;
X	}
X	| tSNUMBER tMINUTE_UNIT {
X	    yyRelSeconds += $1 * $2 * 60L;
X	}
X	| tMINUTE_UNIT {
X	    yyRelSeconds += $1 * 60L;
X	}
X	| tSNUMBER tSEC_UNIT {
X	    yyRelSeconds += $1;
X	}
X	| tUNUMBER tSEC_UNIT {
X	    yyRelSeconds += $1;
X	}
X	| tSEC_UNIT {
X	    yyRelSeconds++;
X	}
X	| tSNUMBER tMONTH_UNIT {
X	    yyRelMonth += $1 * $2;
X	}
X	| tUNUMBER tMONTH_UNIT {
X	    yyRelMonth += $1 * $2;
X	}
X	| tMONTH_UNIT {
X	    yyRelMonth += $1;
X	}
X	;
X
Xnumber	: tUNUMBER {
X	    if (yyHaveTime && yyHaveDate && !yyHaveRel)
X		yyYear = $1;
X	    else {
X		yyHaveTime++;
X		if ($1 < 100) {
X		    yyHour = $1;
X		    yyMinutes = 0;
X		}
X		else {
X		    yyHour = $1 / 100;
X		    yyMinutes = $1 % 100;
X		}
X		yySeconds = 0;
X		yyMeridian = MER24;
X	    }
X	}
X	;
X
Xo_merid	: /* NULL */ {
X	    $$ = MER24;
X	}
X	| tMERIDIAN {
X	    $$ = $1;
X	}
X	;
X
X%%
X
X/* Month and day table. */
Xstatic TABLE	MonthDayTable[] = {
X    { "january",	tMONTH,  1 },
X    { "february",	tMONTH,  2 },
X    { "march",		tMONTH,  3 },
X    { "april",		tMONTH,  4 },
X    { "may",		tMONTH,  5 },
X    { "june",		tMONTH,  6 },
X    { "july",		tMONTH,  7 },
X    { "august",		tMONTH,  8 },
X    { "september",	tMONTH,  9 },
X    { "sept",		tMONTH,  9 },
X    { "october",	tMONTH, 10 },
X    { "november",	tMONTH, 11 },
X    { "december",	tMONTH, 12 },
X    { "sunday",		tDAY, 0 },
X    { "monday",		tDAY, 1 },
X    { "tuesday",	tDAY, 2 },
X    { "tues",		tDAY, 2 },
X    { "wednesday",	tDAY, 3 },
X    { "wednes",		tDAY, 3 },
X    { "thursday",	tDAY, 4 },
X    { "thur",		tDAY, 4 },
X    { "thurs",		tDAY, 4 },
X    { "friday",		tDAY, 5 },
X    { "saturday",	tDAY, 6 },
X    { NULL }
X};
X
X/* Time units table. */
Xstatic TABLE	UnitsTable[] = {
X    { "year",		tMONTH_UNIT,	12 },
X    { "month",		tMONTH_UNIT,	1 },
X    { "fortnight",	tMINUTE_UNIT,	14 * 24 * 60 },
X    { "week",		tMINUTE_UNIT,	7 * 24 * 60 },
X    { "day",		tMINUTE_UNIT,	1 * 24 * 60 },
X    { "hour",		tMINUTE_UNIT,	60 },
X    { "minute",		tMINUTE_UNIT,	1 },
X    { "min",		tMINUTE_UNIT,	1 },
X    { "second",		tSEC_UNIT,	1 },
X    { "sec",		tSEC_UNIT,	1 },
X    { NULL }
X};
X
X/* Assorted relative-time words. */
Xstatic TABLE	OtherTable[] = {
X    { "tomorrow",	tMINUTE_UNIT,	1 * 24 * 60 },
X    { "yesterday",	tMINUTE_UNIT,	-1 * 24 * 60 },
X    { "today",		tMINUTE_UNIT,	0 },
X    { "now",		tMINUTE_UNIT,	0 },
X    { "last",		tUNUMBER,	-1 },
X    { "this",		tMINUTE_UNIT,	0 },
X    { "next",		tUNUMBER,	2 },
X    { "first",		tUNUMBER,	1 },
X/*  { "second",		tUNUMBER,	2 }, */
X    { "third",		tUNUMBER,	3 },
X    { "fourth",		tUNUMBER,	4 },
X    { "fifth",		tUNUMBER,	5 },
X    { "sixth",		tUNUMBER,	6 },
X    { "seventh",	tUNUMBER,	7 },
X    { "eighth",		tUNUMBER,	8 },
X    { "ninth",		tUNUMBER,	9 },
X    { "tenth",		tUNUMBER,	10 },
X    { "eleventh",	tUNUMBER,	11 },
X    { "twelfth",	tUNUMBER,	12 },
X    { "ago",		tAGO,	1 },
X    { NULL }
X};
X
X/* The timezone table. */
Xstatic TABLE	TimezoneTable[] = {
X    { "gmt",	tZONE,     HOUR( 0) },	/* Greenwich Mean */
X    { "ut",	tZONE,     HOUR( 0) },	/* Universal (Coordinated) */
X    { "utc",	tZONE,     HOUR( 0) },
X    { "wet",	tZONE,     HOUR( 0) },	/* Western European */
X    { "bst",	tDAYZONE,  HOUR( 0) },	/* British Summer */
X    { "wat",	tZONE,     HOUR( 1) },	/* West Africa */
X    { "at",	tZONE,     HOUR( 2) },	/* Azores */
X#if	0
X    /* For completeness.  BST is also British Summer, and GST is
X     * also Guam Standard. */
X    { "bst",	tZONE,     HOUR( 3) },	/* Brazil Standard */
X    { "gst",	tZONE,     HOUR( 3) },	/* Greenland Standard */
X#endif
X    { "nft",	tZONE,     HOUR(3.5) },	/* Newfoundland */
X    { "nst",	tZONE,     HOUR(3.5) },	/* Newfoundland Standard */
X    { "ndt",	tDAYZONE,  HOUR(3.5) },	/* Newfoundland Daylight */
X    { "ast",	tZONE,     HOUR( 4) },	/* Atlantic Standard */
X    { "adt",	tDAYZONE,  HOUR( 4) },	/* Atlantic Daylight */
X    { "est",	tZONE,     HOUR( 5) },	/* Eastern Standard */
X    { "edt",	tDAYZONE,  HOUR( 5) },	/* Eastern Daylight */
X    { "cst",	tZONE,     HOUR( 6) },	/* Central Standard */
X    { "cdt",	tDAYZONE,  HOUR( 6) },	/* Central Daylight */
X    { "mst",	tZONE,     HOUR( 7) },	/* Mountain Standard */
X    { "mdt",	tDAYZONE,  HOUR( 7) },	/* Mountain Daylight */
X    { "pst",	tZONE,     HOUR( 8) },	/* Pacific Standard */
X    { "pdt",	tDAYZONE,  HOUR( 8) },	/* Pacific Daylight */
X    { "yst",	tZONE,     HOUR( 9) },	/* Yukon Standard */
X    { "ydt",	tDAYZONE,  HOUR( 9) },	/* Yukon Daylight */
X    { "hst",	tZONE,     HOUR(10) },	/* Hawaii Standard */
X    { "hdt",	tDAYZONE,  HOUR(10) },	/* Hawaii Daylight */
X    { "cat",	tZONE,     HOUR(10) },	/* Central Alaska */
X    { "ahst",	tZONE,     HOUR(10) },	/* Alaska-Hawaii Standard */
X    { "nt",	tZONE,     HOUR(11) },	/* Nome */
X    { "idlw",	tZONE,     HOUR(12) },	/* International Date Line West */
X    { "cet",	tZONE,     -HOUR(1) },	/* Central European */
X    { "met",	tZONE,     -HOUR(1) },	/* Middle European */
X    { "mewt",	tZONE,     -HOUR(1) },	/* Middle European Winter */
X    { "mest",	tDAYZONE,  -HOUR(1) },	/* Middle European Summer */
X    { "swt",	tZONE,     -HOUR(1) },	/* Swedish Winter */
X    { "sst",	tDAYZONE,  -HOUR(1) },	/* Swedish Summer */
X    { "fwt",	tZONE,     -HOUR(1) },	/* French Winter */
X    { "fst",	tDAYZONE,  -HOUR(1) },	/* French Summer */
X    { "eet",	tZONE,     -HOUR(2) },	/* Eastern Europe, USSR Zone 1 */
X    { "bt",	tZONE,     -HOUR(3) },	/* Baghdad, USSR Zone 2 */
X    { "it",	tZONE,     -HOUR(3.5) },/* Iran */
X    { "zp4",	tZONE,     -HOUR(4) },	/* USSR Zone 3 */
X    { "zp5",	tZONE,     -HOUR(5) },	/* USSR Zone 4 */
X    { "ist",	tZONE,     -HOUR(5.5) },/* Indian Standard */
X    { "zp6",	tZONE,     -HOUR(6) },	/* USSR Zone 5 */
X#if	0
X    /* For completeness.  NST is also Newfoundland Stanard, nad SST is
X     * also Swedish Summer. */
X    { "nst",	tZONE,     -HOUR(6.5) },/* North Sumatra */
X    { "sst",	tZONE,     -HOUR(7) },	/* South Sumatra, USSR Zone 6 */
X#endif	/* 0 */
X    { "wast",	tZONE,     -HOUR(7) },	/* West Australian Standard */
X    { "wadt",	tDAYZONE,  -HOUR(7) },	/* West Australian Daylight */
X    { "jt",	tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
X    { "cct",	tZONE,     -HOUR(8) },	/* China Coast, USSR Zone 7 */
X    { "jst",	tZONE,     -HOUR(9) },	/* Japan Standard, USSR Zone 8 */
X    { "cast",	tZONE,     -HOUR(9.5) },/* Central Australian Standard */
X    { "cadt",	tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
X    { "east",	tZONE,     -HOUR(10) },	/* Eastern Australian Standard */
X    { "eadt",	tDAYZONE,  -HOUR(10) },	/* Eastern Australian Daylight */
X    { "gst",	tZONE,     -HOUR(10) },	/* Guam Standard, USSR Zone 9 */
X    { "nzt",	tZONE,     -HOUR(12) },	/* New Zealand */
X    { "nzst",	tZONE,     -HOUR(12) },	/* New Zealand Standard */
X    { "nzdt",	tDAYZONE,  -HOUR(12) },	/* New Zealand Daylight */
X    { "idle",	tZONE,     -HOUR(12) },	/* International Date Line East */
X    {  NULL  }
X};
X
X/* Military timezone table. */
Xstatic TABLE	MilitaryTable[] = {
X    { "a",	tZONE,	HOUR(  1) },
X    { "b",	tZONE,	HOUR(  2) },
X    { "c",	tZONE,	HOUR(  3) },
X    { "d",	tZONE,	HOUR(  4) },
X    { "e",	tZONE,	HOUR(  5) },
X    { "f",	tZONE,	HOUR(  6) },
X    { "g",	tZONE,	HOUR(  7) },
X    { "h",	tZONE,	HOUR(  8) },
X    { "i",	tZONE,	HOUR(  9) },
X    { "k",	tZONE,	HOUR( 10) },
X    { "l",	tZONE,	HOUR( 11) },
X    { "m",	tZONE,	HOUR( 12) },
X    { "n",	tZONE,	HOUR(- 1) },
X    { "o",	tZONE,	HOUR(- 2) },
X    { "p",	tZONE,	HOUR(- 3) },
X    { "q",	tZONE,	HOUR(- 4) },
X    { "r",	tZONE,	HOUR(- 5) },
X    { "s",	tZONE,	HOUR(- 6) },
X    { "t",	tZONE,	HOUR(- 7) },
X    { "u",	tZONE,	HOUR(- 8) },
X    { "v",	tZONE,	HOUR(- 9) },
X    { "w",	tZONE,	HOUR(-10) },
X    { "x",	tZONE,	HOUR(-11) },
X    { "y",	tZONE,	HOUR(-12) },
X    { "z",	tZONE,	HOUR(  0) },
X    { NULL }
X};
X
X
X
X
X/* ARGSUSED */
Xstatic
Xyyerror(s)
X    char	*s;
X{
X}
X
X
Xstatic time_t
XToSeconds(Hours, Minutes, Seconds, Meridian)
X    time_t	Hours;
X    time_t	Minutes;
X    time_t	Seconds;
X    MERIDIAN	Meridian;
X{
X    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
X	return -1;
X    switch (Meridian) {
X    case MER24:
X	if (Hours < 0 || Hours > 23)
X	    return -1;
X	return (Hours * 60L + Minutes) * 60L + Seconds;
X    case MERam:
X	if (Hours < 1 || Hours > 12)
X	    return -1;
X	return (Hours * 60L + Minutes) * 60L + Seconds;
X    case MERpm:
X	if (Hours < 1 || Hours > 12)
X	    return -1;
X	return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
X    }
X    /* NOTREACHED */
X}
X
X
Xstatic time_t
XConvert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
X    time_t	Month;
X    time_t	Day;
X    time_t	Year;
X    time_t	Hours;
X    time_t	Minutes;
X    time_t	Seconds;
X    MERIDIAN	Meridian;
X    DSTMODE	DSTmode;
X{
X    static int	DaysInMonth[12] = {
X	31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
X    };
X    time_t	tod;
X    time_t	Julian;
X    int		i;
X
X    if (Year < 0)
X	Year = -Year;
X    if (Year < 100)
X	Year += 1900;
X    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
X		    ? 29 : 28;
X    if (Year < EPOCH || Year > 1999
X     || Month < 1 || Month > 12
X     /* Lint fluff:  "conversion from long may lose accuracy" */
X     || Day < 1 || Day > DaysInMonth[(int)--Month])
X	return -1;
X
X    for (Julian = Day - 1, i = 0; i < Month; i++)
X	Julian += DaysInMonth[i];
X    for (i = EPOCH; i < Year; i++)
X	Julian += 365 + (i % 4 == 0);
X    Julian *= SECSPERDAY;
X    Julian += yyTimezone * 60L;
X    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
X	return -1;
X    Julian += tod;
X    if (DSTmode == DSTon
X     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
X	Julian -= 60 * 60;
X    return Julian;
X}
X
X
Xstatic time_t
XDSTcorrect(Start, Future)
X    time_t	Start;
X    time_t	Future;
X{
X    time_t	StartDay;
X    time_t	FutureDay;
X
X    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
X    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
X    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
X}
X
X
Xstatic time_t
XRelativeDate(Start, DayOrdinal, DayNumber)
X    time_t	Start;
X    time_t	DayOrdinal;
X    time_t	DayNumber;
X{
X    struct tm	*tm;
X    time_t	now;
X
X    now = Start;
X    tm = localtime(&now);
X    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
X    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
X    return DSTcorrect(Start, now);
X}
X
X
Xstatic time_t
XRelativeMonth(Start, RelMonth)
X    time_t	Start;
X    time_t	RelMonth;
X{
X    struct tm	*tm;
X    time_t	Month;
X    time_t	Year;
X
X    if (RelMonth == 0)
X	return 0;
X    tm = localtime(&Start);
X    Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
X    Year = Month / 12;
X    Month = Month % 12 + 1;
X    return DSTcorrect(Start,
X	    Convert(Month, (time_t)tm->tm_mday, Year,
X		(time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
X		MER24, DSTmaybe));
X}
X
X
Xstatic int
XLookupWord(buff)
X    char		*buff;
X{
X    register char	*p;
X    register char	*q;
X    register TABLE	*tp;
X    int			i;
X    int			abbrev;
X
X    /* Make it lowercase. */
X    for (p = buff; *p; p++)
X	if (isupper(*p))
X	    *p = tolower(*p);
X
X    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
X	yylval.Meridian = MERam;
X	return tMERIDIAN;
X    }
X    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
X	yylval.Meridian = MERpm;
X	return tMERIDIAN;
X    }
X
X    /* See if we have an abbreviation for a month. */
X    if (strlen(buff) == 3)
X	abbrev = 1;
X    else if (strlen(buff) == 4 && buff[3] == '.') {
X	abbrev = 1;
X	buff[3] = '\0';
X    }
X    else
X	abbrev = 0;
X
X    for (tp = MonthDayTable; tp->name; tp++) {
X	if (abbrev) {
X	    if (strncmp(buff, tp->name, 3) == 0) {
X		yylval.Number = tp->value;
X		return tp->type;
X	    }
X	}
X	else if (strcmp(buff, tp->name) == 0) {
X	    yylval.Number = tp->value;
X	    return tp->type;
X	}
X    }
X
X    for (tp = TimezoneTable; tp->name; tp++)
X	if (strcmp(buff, tp->name) == 0) {
X	    yylval.Number = tp->value;
X	    return tp->type;
X	}
X
X    for (tp = UnitsTable; tp->name; tp++)
X	if (strcmp(buff, tp->name) == 0) {
X	    yylval.Number = tp->value;
X	    return tp->type;
X	}
X
X    /* Strip off any plural and try the units table again. */
X    i = strlen(buff) - 1;
X    if (buff[i] == 's') {
X	buff[i] = '\0';
X	for (tp = UnitsTable; tp->name; tp++)
X	    if (strcmp(buff, tp->name) == 0) {
X		yylval.Number = tp->value;
X		return tp->type;
X	    }
X    }
X
X    for (tp = OtherTable; tp->name; tp++)
X	if (strcmp(buff, tp->name) == 0) {
X	    yylval.Number = tp->value;
X	    return tp->type;
X	}
X
X    /* Military timezones. */
X    if (buff[1] == '\0' && isalpha(*buff)) {
X	for (tp = MilitaryTable; tp->name; tp++)
X	    if (strcmp(buff, tp->name) == 0) {
X		yylval.Number = tp->value;
X		return tp->type;
X	    }
X    }
X
X    /* Drop out any periods and try the timezone table again. */
X    for (i = 0, p = q = buff; *q; q++)
X	if (*q != '.')
X	    *p++ = *q;
X	else
X	    i++;
X    *p = '\0';
X    if (i)
X	for (tp = TimezoneTable; tp->name; tp++)
X	    if (strcmp(buff, tp->name) == 0) {
X		yylval.Number = tp->value;
X		return tp->type;
X	    }
X
X    return tID;
X}
X
X
Xstatic int
Xyylex()
X{
X    register char	c;
X    register char	*p;
X    char		buff[20];
X    int			Count;
X    int			sign;
X
X    for ( ; ; ) {
X	while (isspace(*yyInput))
X	    yyInput++;
X
X	if (isdigit(c = *yyInput) || c == '-' || c == '+') {
X	    if (c == '-' || c == '+') {
X		sign = c == '-' ? -1 : 1;
X		if (!isdigit(*++yyInput))
X		    /* skip the '-' sign */
X		    continue;
X	    }
X	    else
X		sign = 0;
X	    for (yylval.Number = 0; isdigit(c = *yyInput++); )
X		yylval.Number = 10 * yylval.Number + c - '0';
X	    yyInput--;
X	    if (sign < 0)
X		yylval.Number = -yylval.Number;
X	    return sign ? tSNUMBER : tUNUMBER;
X	}
X	if (isalpha(c)) {
X	    for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
X		if (p < &buff[sizeof buff - 1])
X		    *p++ = c;
X	    *p = '\0';
X	    yyInput--;
X	    return LookupWord(buff);
X	}
X	if (c != '(')
X	    return *yyInput++;
X	Count = 0;
X	do {
X	    c = *yyInput++;
X	    if (c == '\0')
X		return c;
X	    if (c == '(')
X		Count++;
X	    else if (c == ')')
X		Count--;
X	} while (Count > 0);
X    }
X}
X
X
Xstatic time_t
Xgetdate(p, now)
X    char		*p;
X    struct timeb	*now;
X{
X    struct tm		*tm;
X    struct timeb	ftz;
X    time_t		Start;
X    time_t		tod;
X
X    yyInput = p;
X    if (now == NULL) {
X	now = &ftz;
X#if	defined(NEED_TZSET)
X	(void)time(&ftz.time);
X	/* Set the timezone global. */
X	tzset();
X	ftz.timezone = (int) timezone / 60;
X#else
X	(void)ftime(&ftz);
X#endif	/* defined(NEED_TZSET) */
X    }
X
X    tm = localtime(&now->time);
X    yyYear = tm->tm_year;
X    yyMonth = tm->tm_mon + 1;
X    yyDay = tm->tm_mday;
X    yyTimezone = now->timezone;
X    yyDSTmode = DSTmaybe;
X    yyHour = 0;
X    yyMinutes = 0;
X    yySeconds = 0;
X    yyMeridian = MER24;
X    yyRelSeconds = 0;
X    yyRelMonth = 0;
X    yyHaveDate = 0;
X    yyHaveDay = 0;
X    yyHaveRel = 0;
X    yyHaveTime = 0;
X    yyHaveZone = 0;
X
X    if (yyparse()
X     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
X	return -1;
X
X    if (yyHaveDate || yyHaveTime || yyHaveDay) {
X	Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
X		    yyMeridian, yyDSTmode);
X	if (Start < 0)
X	    return -1;
X    }
X    else {
X	Start = now->time;
X	if (!yyHaveRel)
X	    Start -= ((tm->tm_hour * 60L) + tm->tm_min * 60L) + tm->tm_sec;
X    }
X
X    Start += yyRelSeconds;
X    Start += RelativeMonth(Start, yyRelMonth);
X
X    if (yyHaveDay && !yyHaveDate) {
X	tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
X	Start += tod;
X    }
X
X    /* Have to do *something* with a legitimate -1 so it's distinguishable
X     * from the error return value.  (Alternately could set errno on error.) */
X    return Start == -1 ? 0 : Start;
X}
X
X
X#if	defined(TEST)
X
X/* ARGSUSED */
Xmain(ac, av)
X    int		ac;
X    char	*av[];
X{
X    char	buff[128];
X    time_t	d;
X
X    (void)printf("Enter date, or blank line to exit.\n\t> ");
X    (void)fflush(stdout);
X    while (gets(buff) && buff[0]) {
X	d = getdate(buff, (struct timeb *)NULL);
X	if (d == -1)
X	    (void)printf("Bad format - couldn't convert.\n");
X	else
X	    (void)printf("%s", ctime(&d));
X	(void)printf("\t> ");
X	(void)fflush(stdout);
X    }
X    exit(0);
X    /* NOTREACHED */
X}
X#endif	/* defined(TEST) */
END_OF_FILE
  if test 20830 -ne `wc -c <'getdate.y'`; then
    echo shar: \"'getdate.y'\" unpacked with wrong size!
  fi
  # end of 'getdate.y'
fi
echo shar: End of archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.


From ADO@elsie.nci.nih.gov Mon Sep 24 17:13:59 1990
Received: from seismo.CSS.GOV by uunet.uu.net (5.61/1.14) with SMTP 
	id AA04756; Mon, 24 Sep 90 17:13:56 -0400
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.61/1.14)
	id AA05804; Mon, 24 Sep 90 17:13:54 -0400
Received: from seismo.CSS.GOV by beno.CSS.GOV (4.0/SMI-4.0)
	id AA27860; Mon, 24 Sep 90 17:13:52 EDT
Received: from alw.nih.gov by seismo.CSS.GOV (5.61/1.14)
	id AA05800; Mon, 24 Sep 90 17:13:44 -0400
Received: from cu.nih.gov by alw.nih.gov (5.61/alw-2.1)
	id AA07043; Mon, 24 Sep 90 17:10:49 -0400
Received: from CU.NIH.GOV by NIHCU (Mailer) id 4888;
              Mon, 24 Sep 90  17:13:11 EDT
Received: from NCI.NIH.GOV by CU.NIH.GOV
    with TCP; Mon, 24 Sep 90 17:13:01 EDT
Received: by nci.nih.gov (4.1/SMI-4.1)
       id AA28972; Mon, 24 Sep 90 17:13:11 EDT
Date: Mon, 24 Sep 90 17:13:11 EDT
From: ado@elsie.nci.nih.gov (Arthur David Olson)
Message-Id: <9009242113.AA28972@nci.nih.gov>
To: rick@seismo.CSS.GOV
Subject: Article cancellation
Status: R

It seems as if both vnews and readnews will not allow folks other than the
news root to cancel their own aritcles, at least here on elsie.  This comes
about because the software sets the "username" variable to "jqsmith"
(or whatever) while the "tailpath" function returns "elsie!jqsmith"; the
mismatch causes grief.

Possible changes attached.

                               --ado

SCCS/s.readr.c: 1.1 vs. 1.2
*** 1.1/readr.c        Mon Sep 24 17:09:23 1990
--- 1.2/readr.c        Mon Sep 24 17:09:24 1990
***************
*** 665,670 ****
--- 665,671 ----
  cancel_command()
  {
       register char *poster;
+      int fromsyslen;
       int notauthor;
       char *tailpath();

***************
*** 680,686 ****
       EOL();
       readmode = SPEC;
       poster = tailpath(hptr);
!      notauthor = STRCMP(username, poster);
       if (uid != ROOTID && uid && notauthor) {
               fprintf(ofp,
                       "You (%s) can't cancel someone else's (%s) article.\n",
--- 681,690 ----
       EOL();
       readmode = SPEC;
       poster = tailpath(hptr);
!      fromsyslen = strlen(FROMSYSNAME);
!      notauthor = strncmp(poster, FROMSYSNAME, fromsyslen) != 0 ||
!              poster[fromsyslen] != '!' ||
!              strcmp(username, &poster[fromsyslen + 1]) != 0;
       if (uid != ROOTID && uid && notauthor) {
               fprintf(ofp,
                       "You (%s) can't cancel someone else's (%s) article.\n",
SCCS/s.visual.c: 1.3 vs. 1.4
*** 1.3/visual.c       Mon Sep 24 17:09:30 1990
--- 1.4/visual.c       Mon Sep 24 17:09:31 1990
***************
*** 977,987 ****
  cancel_command()
  {
       register char *poster;
       int notauthor;
       char *tailpath();

       poster = tailpath(h);
!      notauthor = STRCMP(username, poster);
       if (uid != ROOTID && uid && notauthor) {
               msg("You (%s) can't cancel someone else's (%s) article.",
                       username,poster);
--- 977,991 ----
  cancel_command()
  {
       register char *poster;
+      int fromsyslen;
       int notauthor;
       char *tailpath();

       poster = tailpath(h);
!      fromsyslen = strlen(FROMSYSNAME);
!      notauthor = strncmp(poster, FROMSYSNAME, fromsyslen) != 0 ||
!              poster[fromsyslen] != '!' ||
!              strcmp(username, &poster[fromsyslen + 1]) != 0;
       if (uid != ROOTID && uid && notauthor) {
               msg("You (%s) can't cancel someone else's (%s) article.",
                       username,poster);





From tredysvr!mike@gvlv2.GVL.Unisys.COM Fri Oct 26 16:52:24 1990
Received: from gvlv2.GVL.Unisys.COM by uunet.uu.net (5.61/1.14) with SMTP 
	id AA17987; Fri, 26 Oct 90 16:52:05 -0400
Received: by gvlv2.GVL.Unisys.COM (5.61/mls/3.1.v2) 
	id AA28695; Fri, 26 Oct 90 16:50:58 -0400
Received: by tredysvr.Tredydev.Unisys.COM (5.51/smail2.5/03-27-90)
	id AA14342; Fri, 26 Oct 90 16:22:24 EDT
From: mike@tredysvr.Tredydev.Unisys.COM (Mike Marciniszyn)
Message-Id: <9010262022.AA14342@tredysvr.Tredydev.Unisys.COM>
Subject: B2.11 news patches
To: rick@uunet.uu.net
Date: Fri, 26 Oct 90 16:22:16 EDT
X-Mailer: ELM [version 2.2 PL0]
Status: R


Rick:

I've finally been able to locate a set of patches for 2.11 news at the
OSU achives.  I've transfered them and merged them with some patches
that we have had from some time.

Here are some local patches we have for 2.11 news relative to level 19 that
may or may not be useful to others.  These context diffs patch the following
files:

	compress.c
	defs.dist
	funcs2.c
	getdate.y
	inews.c
	rfuncs.c

They add the following functions and/or fixes:

1).  Furthur enhance the disk full test is inews.c to check for inodes
     as well as free blocks.  Some systems have ample disk space but
     run out of inodes first.

2).  Fix a problem we saw a while back with cgtdate in funcs2.c corrupting the
     stack when it was passed a string longer than 40 characters.
     The sprintf in the routine would corrupt the stack when that occurred.

3).  The USG specific code in inews.c to open permissions and then close
     them around the recursive make directory should not be needed when
     the USG system has a system call to make a directory as does V.3.x. 

4).  Fix a warning of extern daylight made static in getdate.y

5).  Fix a signal int/void warning in compress.c.

5).  Fix a memory corruption in rfuncs.c when it runs out of LINES in the
     while loop.   It still loops back and corrupts the stack after the
     last valid line.

There are some other things that I've noticed that I had not yet had
time to address.

1).  makeactive.sh creates the old style active file when none exists.
     It also probably never adds the moderated stuff correctly.

2).  Some System V users have ported dbm to their systems either from
     BSD source, comp.sources.unix, or from gdbm.  The make for USG should
     allow for it.

Mike Marciniszyn
A Series Console Software
Unisys Tredyffin
DOMAIN: mike@tredysvr.tredydev.unisys.com  UUCP: tredysvr!mike

*** /osrc/bnews/src/compress.c	Tue Oct 23 12:28:44 1990
--- compress.c	Fri Oct 26 15:50:49 1990
***************
*** 261,267
  #ifdef DEBUG
  int verbose = 0;
  #endif /* DEBUG */
! int (*bgnd_flag)();
  
  int do_decomp = 0;
  

--- 261,267 -----
  #ifdef DEBUG
  int verbose = 0;
  #endif /* DEBUG */
! void (*bgnd_flag)();
  
  int do_decomp = 0;
  
*** /osrc/bnews/src/defs.dist	Tue Oct 23 12:28:46 1990
--- defs.dist	Fri Oct 26 15:50:53 1990
***************
*** 14,20
   *
   */
  
! /*	@(#)defs.dist	2.65	1/24/89	*/
  
  /*
   * defs.h - defines for news-related programs.

--- 14,20 -----
   *
   */
  
! /*	@(#)defs.dist	2.66	1/24/89	*/
  
  /*
   * defs.h - defines for news-related programs.
***************
*** 100,105
  				/* groups must be approved by the contents */
  				/* of the $(LIB)/moderators file	   */
  /* #define MINFREE 5000	/* minimum number of free blocks needed in spool*/
  			/* partition before unbatching will take place  */
  			/* USG only */
  

--- 100,108 -----
  				/* groups must be approved by the contents */
  				/* of the $(LIB)/moderators file	   */
  /* #define MINFREE 5000	/* minimum number of free blocks needed in spool*/
+ 			/* partition before unbatching will take place  */
+ 			/* USG only */
+ /* #define MINIFREE 500	/* minimum number of free inodes needed in spool */
  			/* partition before unbatching will take place  */
  			/* USG only */
  
*** /osrc/bnews/src/funcs2.c	Tue Oct 23 12:29:33 1990
--- funcs2.c	Tue Oct 23 13:07:02 1990
***************
*** 17,23
   */
  
  #ifdef SCCSID
! static char	*SccsId = "@(#)funcs2.c	1.26	9/1/89";
  #endif /* SCCSID */
  
  #include "params.h"

--- 17,23 -----
   */
  
  #ifdef SCCSID
! static char	*SccsId = "@(#)funcs2.c	1.27	9/1/89";
  #endif /* SCCSID */
  
  #include "params.h"
***************
*** 203,209
  cgtdate(datestr)
  char *datestr;
  {
! 	char	junk[40],month[40],day[30],tod[60],year[50];
  	register char *cp;
  	static time_t lasttime;
  	static char lastdatestr[BUFLEN] = "";

--- 203,212 -----
  cgtdate(datestr)
  char *datestr;
  {
! 	char	*junk,*month,*day,*tod,*year;
! 	int len;
! 	char *malloc();
! 	void free();
  	register char *cp;
  	static time_t lasttime;
  	static char lastdatestr[BUFLEN] = "";
***************
*** 221,226
  	lasttime = getdate(lastdatestr, &Now);
  	if (lasttime < 0) {
  		logerr("%s: Unparsable date \"%s\"", filename, lastdatestr);
  		if (sscanf(lastdatestr, "%s %s %s %s %s", junk, month, day, tod,
  			year) == 5) {
  			(void) sprintf(bfr, "%s %s, %s %s", month, day, year,

--- 224,240 -----
  	lasttime = getdate(lastdatestr, &Now);
  	if (lasttime < 0) {
  		logerr("%s: Unparsable date \"%s\"", filename, lastdatestr);
+ 		/*
+ 		Worst case or strlen + 1 for each field to avoid memory
+ 		corruption if datestr contains a string without white space.
+ 		It can blow away the stack.
+ 		*/
+ 		len = strlen(datestr) + 1;
+ 		junk = malloc(len);
+ 		month = malloc(len);
+ 		day = malloc(len);
+ 		tod = malloc(len);
+ 		year = malloc(len);
  		if (sscanf(lastdatestr, "%s %s %s %s %s", junk, month, day, tod,
  			year) == 5) {
  			(void) sprintf(bfr, "%s %s, %s %s", month, day, year,
***************
*** 227,232
  				tod);
  			lasttime = getdate(bfr, &Now);
  		}
  		if (lasttime < 0) {
  			strcpy(lastdatestr, "now"); /* better than nothing */
  			lasttime = Now.time;

--- 241,251 -----
  				tod);
  			lasttime = getdate(bfr, &Now);
  		}
+ 		free(year);
+ 		free(tod);
+ 		free(day);
+ 		free(month);
+ 		free(junk);
  		if (lasttime < 0) {
  			strcpy(lastdatestr, "now"); /* better than nothing */
  			lasttime = Now.time;
*** /osrc/bnews/src/getdate.y	Tue Oct 23 12:29:34 1990
--- getdate.y	Fri Oct 26 15:31:01 1990
***************
*** 3,9
  	/* 	Originally from: Steven M. Bellovin (unc!smb)	*/ 
  	/*	Dept. of Computer Science			*/
  	/*	University of North Carolina at Chapel Hill	*/
! 	/*	@(#)getdate.y	2.20	9/1/89	*/
  
  #include "defs.h"
  #include <sys/types.h>

--- 3,9 -----
  	/* 	Originally from: Steven M. Bellovin (unc!smb)	*/ 
  	/*	Dept. of Computer Science			*/
  	/*	University of North Carolina at Chapel Hill	*/
! 	/*	@(#)getdate.y	2.21	9/1/89	*/
  
  #include "defs.h"
  #include <sys/types.h>
***************
*** 30,36
  #define daysec (24L*60L*60L)
  	static int timeflag, zoneflag, dateflag, dayflag, relflag;
  	static time_t relsec, relmonth;
! 	static int hh, mm, ss, merid, daylight;
  	static int dayord, dayreq;
  	static int month, day, year;
  	static int ourzone;

--- 30,36 -----
  #define daysec (24L*60L*60L)
  	static int timeflag, zoneflag, dateflag, dayflag, relflag;
  	static time_t relsec, relmonth;
! 	static int hh, mm, ss, merid, day_light;
  	static int dayord, dayreq;
  	static int month, day, year;
  	static int ourzone;
***************
*** 69,75
  		{hh = $1; mm = $3; merid = $4;}
  	| UNUMBER ':' UNUMBER SNUMBER =
  		{hh = $1; mm = $3; merid = 24;
! 		daylight = STANDARD; ourzone = -($4%100 + 60*($4/100));}
  	| UNUMBER ':' UNUMBER ':' UNUMBER =
  		{hh = $1; mm = $3; ss = $5; merid = 24;}
  	| UNUMBER ':' UNUMBER ':' UNUMBER MERIDIAN =

--- 69,75 -----
  		{hh = $1; mm = $3; merid = $4;}
  	| UNUMBER ':' UNUMBER SNUMBER =
  		{hh = $1; mm = $3; merid = 24;
! 		day_light = STANDARD; ourzone = -($4%100 + 60*($4/100));}
  	| UNUMBER ':' UNUMBER ':' UNUMBER =
  		{hh = $1; mm = $3; ss = $5; merid = 24;}
  	| UNUMBER ':' UNUMBER ':' UNUMBER MERIDIAN =
***************
*** 76,82
  		{hh = $1; mm = $3; ss = $5; merid = $6;}
  	| UNUMBER ':' UNUMBER ':' UNUMBER SNUMBER =
  		{hh = $1; mm = $3; ss = $5; merid = 24;
! 		daylight = STANDARD; ourzone = -($6%100 + 60*($6/100));};
  
  zone:	ZONE =
  		{ourzone = $1; daylight = STANDARD;}

--- 76,82 -----
  		{hh = $1; mm = $3; ss = $5; merid = $6;}
  	| UNUMBER ':' UNUMBER ':' UNUMBER SNUMBER =
  		{hh = $1; mm = $3; ss = $5; merid = 24;
! 		day_light = STANDARD; ourzone = -($6%100 + 60*($6/100));};
  
  zone:	ZONE =
  		{ourzone = $1; day_light = STANDARD;}
***************
*** 79,85
  		daylight = STANDARD; ourzone = -($6%100 + 60*($6/100));};
  
  zone:	ZONE =
! 		{ourzone = $1; daylight = STANDARD;}
  	| DAYZONE =
  		{ourzone = $1; daylight = DAYLIGHT;};
  

--- 79,85 -----
  		day_light = STANDARD; ourzone = -($6%100 + 60*($6/100));};
  
  zone:	ZONE =
! 		{ourzone = $1; day_light = STANDARD;}
  	| DAYZONE =
  		{ourzone = $1; day_light = DAYLIGHT;};
  
***************
*** 81,87
  zone:	ZONE =
  		{ourzone = $1; daylight = STANDARD;}
  	| DAYZONE =
! 		{ourzone = $1; daylight = DAYLIGHT;};
  
  dyspec:	DAY =
  		{dayord = 1; dayreq = $1;}

--- 81,87 -----
  zone:	ZONE =
  		{ourzone = $1; day_light = STANDARD;}
  	| DAYZONE =
! 		{ourzone = $1; day_light = DAYLIGHT;};
  
  dyspec:	DAY =
  		{dayord = 1; dayreq = $1;}
***************
*** 536,542
  	relsec = 0; relmonth = 0;
  	timeflag=zoneflag=dateflag=dayflag=relflag=0;
  	ourzone = now->timezone;
! 	daylight = MAYBE;
  	hh = mm = ss = 0;
  	merid = 24;
  

--- 536,542 -----
  	relsec = 0; relmonth = 0;
  	timeflag=zoneflag=dateflag=dayflag=relflag=0;
  	ourzone = now->timezone;
! 	day_light = MAYBE;
  	hh = mm = ss = 0;
  	merid = 24;
  
***************
*** 549,555
  
  	if (err) return (-1);
  	if (dateflag || timeflag || dayflag) {
! 		sdate = dateconv(month,day,year,hh,mm,ss,merid,ourzone,daylight);
  		if (sdate < 0) return -1;
  	}
  	else {

--- 549,555 -----
  
  	if (err) return (-1);
  	if (dateflag || timeflag || dayflag) {
! 		sdate = dateconv(month,day,year,hh,mm,ss,merid,ourzone,day_light);
  		if (sdate < 0) return -1;
  	}
  	else {
*** /osrc/bnews/src/inews.c	Tue Oct 23 12:29:59 1990
--- inews.c	Fri Oct 26 15:51:15 1990
***************
*** 17,23
   */
  
  #ifdef SCCSID
! static char	*SccsId = "@(#)inews.c	2.93	10/29/89";
  #endif /* SCCSID */
  
  #include "iparams.h"

--- 17,23 -----
   */
  
  #ifdef SCCSID
! static char	*SccsId = "@(#)inews.c	2.94	10/29/89";
  #endif /* SCCSID */
  
  #include "iparams.h"
***************
*** 236,242
  			spool_news = DONT_SPOOL;
  #endif /* SPOOLINEWS */
  	}
! #ifdef MINFREE
  	if (space()) {		/* check disk space */
  		spool_news = DO_SPOOL;
  		logerr("Out of space in %s.", SPOOLDIR);

--- 236,242 -----
  			spool_news = DONT_SPOOL;
  #endif /* SPOOLINEWS */
  	}
! #if defined(MINFREE) || defined(MINIFREE)
  	if (space()) {		/* check disk space */
  		spool_news = DO_SPOOL;
  		logerr("Out of space in %s.", SPOOLDIR);
***************
*** 241,247
  		spool_news = DO_SPOOL;
  		logerr("Out of space in %s.", SPOOLDIR);
  	}
! #endif	/* MINFREE */
  	state = OPTION;
  	header.title[0] = header.nbuf[0] = filename[0] = '\0';
  

--- 241,247 -----
  		spool_news = DO_SPOOL;
  		logerr("Out of space in %s.", SPOOLDIR);
  	}
! #endif	/* MINFREE || MINIFREE */
  	state = OPTION;
  	header.title[0] = header.nbuf[0] = filename[0] = '\0';
  
***************
*** 1437,1443
  char	*fulldir;
  char	*ngname;
  {
! #ifdef USG
  	register char *p;
  	char parent[200];
  	char sysbuf[200];

--- 1437,1443 -----
  char	*fulldir;
  char	*ngname;
  {
! #if defined(USG) && !defined(MKDIRSUB)
  	register char *p;
  	char parent[200];
  	char sysbuf[200];
***************
*** 1442,1448
  	char parent[200];
  	char sysbuf[200];
  	struct stat sbuf;
! #endif /* USG */
  
  	if (ngname == NULL || !isalpha(ngname[0]))
  		xerror("Tried to make illegal newsgroup %s", ngname);

--- 1442,1448 -----
  	char parent[200];
  	char sysbuf[200];
  	struct stat sbuf;
! #endif /* USG && !MKDIRSUB */
  
  	if (ngname == NULL || !isalpha(ngname[0]))
  		xerror("Tried to make illegal newsgroup %s", ngname);
***************
*** 1447,1453
  	if (ngname == NULL || !isalpha(ngname[0]))
  		xerror("Tried to make illegal newsgroup %s", ngname);
  
! #ifdef USG
  	/*
  	 * If the parent is 755 the setuid(getuid)
  	 * will fail, and since mkdir is suid, and our real uid is random,

--- 1447,1453 -----
  	if (ngname == NULL || !isalpha(ngname[0]))
  		xerror("Tried to make illegal newsgroup %s", ngname);
  
! #if defined(USG) && !defined(MKDIRSUB)
  	/*
  	 * If the parent is 755 the setuid(getuid)
  	 * will fail, and since mkdir is suid, and our real uid is random,
***************
*** 1461,1467
  			break;
  		}
  	}
! #endif /* USG */
  
  	/* Create the directory */
  	mkparents(fulldir);

--- 1461,1467 -----
  			break;
  		}
  	}
! #endif /* USG && !MKDIRSUB */
  
  	/* Create the directory */
  	mkparents(fulldir);
***************
*** 1468,1474
  	if (mkdir(fulldir, 0777) < 0)
  		xerror("Cannot mkdir %s: %s", fulldir, errmsg(errno));
  
! #ifdef USG
  	/*
  	 * Give away the directories we just created which were assigned
  	 * our real uid.

--- 1468,1474 -----
  	if (mkdir(fulldir, 0777) < 0)
  		xerror("Cannot mkdir %s: %s", fulldir, errmsg(errno));
  
! #if defined(USG) && !defined(MKDIRSUB)
  	/*
  	 * Give away the directories we just created which were assigned
  	 * our real uid.
***************
*** 1486,1492
  	}
  	(void) setuid(duid);
  	(void) chmod(parent, (int)sbuf.st_mode);	/* put it back */
! #endif /* USG */
  
  	log("make newsgroup %s in dir %s", ngname, fulldir);
  }

--- 1486,1492 -----
  	}
  	(void) setuid(duid);
  	(void) chmod(parent, (int)sbuf.st_mode);	/* put it back */
! #endif /* USG && !MKDIRSUB */
  
  	log("make newsgroup %s in dir %s", ngname, fulldir);
  }
***************
*** 1622,1628
  }
  #endif /* !NFSCLIENT */
  
! #ifdef MINFREE
  #include <ustat.h>
  /* 
   * determine if there is enough free space on the device

--- 1622,1628 -----
  }
  #endif /* !NFSCLIENT */
  
! #if defined(MINFREE) || defined(MINIFREE)
  #include <ustat.h>
  /* 
   * determine if there is enough free space on the device
***************
*** 1638,1643
  		return 1;	/* can't stat spool */
  	if (ustat(file.st_dev, &device))
  		return 1;	/* can't stat the device */
  	if(device.f_tfree < MINFREE)
  		return 1;
  	return 0;

--- 1638,1644 -----
  		return 1;	/* can't stat spool */
  	if (ustat(file.st_dev, &device))
  		return 1;	/* can't stat the device */
+ #ifdef MINFREE
  	if(device.f_tfree < MINFREE)
  		return 1;
  #endif /* MINFREE */
***************
*** 1640,1645
  		return 1;	/* can't stat the device */
  	if(device.f_tfree < MINFREE)
  		return 1;
  	return 0;
  }
  #else

--- 1641,1651 -----
  #ifdef MINFREE
  	if(device.f_tfree < MINFREE)
  		return 1;
+ #endif /* MINFREE */
+ #ifdef MINIFREE
+ 	if(device.f_tinode < MINIFREE)
+ 		return 1;
+ #endif /* MINIFREE */
  	return 0;
  }
  #else
***************
*** 1648,1651
  	/* I'll figure this out for BSD some other time */
  	return(0);
  }
! #endif	/* MINFREE */

--- 1654,1657 -----
  	/* I'll figure this out for BSD some other time */
  	return(0);
  }
! #endif	/* MINFREE || MINIFREE */
*** /osrc/bnews/src/rfuncs.c	Tue Oct 23 12:29:47 1990
--- rfuncs.c	Fri Oct 26 15:51:48 1990
***************
*** 16,22
   */
  
  #ifdef SCCSID
! static char	*SccsId = "@(#)rfuncs.c	2.49	9/7/89";
  #endif /* SCCSID */
  
  /*LINTLIBRARY*/

--- 16,22 -----
   */
  
  #ifdef SCCSID
! static char	*SccsId = "@(#)rfuncs.c	2.51	9/7/89";
  #endif /* SCCSID */
  
  /*LINTLIBRARY*/
***************
*** 690,696
  			strcpy(rcline[line], ngname);
  			tp->rcindex = line;
  		}
! 		tp++;
  #endif /* SORTACTIVE */
  	}
  	(void) fclose(afp);

--- 690,697 -----
  			strcpy(rcline[line], ngname);
  			tp->rcindex = line;
  		}
! 		if (++tp == &table[LINES])
! 			xerror("Too many newsgroups");
  #endif /* SORTACTIVE */
  	}
  	(void) fclose(afp);

From fletcher@cs.utexas.edu Sun Nov 25 22:59:28 1990
Received: from CS.UTEXAS.EDU by uunet.uu.net (5.61/1.14) with SMTP 
	id AA26600; Sun, 25 Nov 90 22:59:25 -0500
Posted-Date: Sun, 25 Nov 1990 21:59:20 CST
Message-Id: <9011260359.AA19525@cs.utexas.edu>
Received: by cs.utexas.edu (5.64/1.86) 
From: Fletcher Mattox <fletcher@cs.utexas.edu>
Date: Sun, 25 Nov 1990 21:59:20 CST
X-Mailer: Mail User's Shell (7.1.2 7/11/90)
To: rick@uunet.uu.net
Subject: newsbug
Status: R

I realise you aren't much interested in supporting this,
but I thought I'd mention it anyway.  I found this when
I increased MBUFLEN to 1024.

In header.c:

*** /tmp/a19104	Sun Nov 25 21:52:13 1990
--- /tmp/b19104	Sun Nov 25 21:52:16 1990
***************
*** 565,571
  		;
  	if (*ptr != '\0') {
  		(void) strncpy(hpfield, ptr, size - 1);
! 		ptr[size - 1] = '\0';
  		(void) nstrip(hpfield);
  	}
  }

--- 565,571 -----
  		;
  	if (*ptr != '\0') {
  		(void) strncpy(hpfield, ptr, size - 1);
! 		hpfield[size - 1] = '\0';
  		(void) nstrip(hpfield);
  	}
  }

From fletcher@cs.utexas.edu Mon Nov 26 12:32:39 1990
Received: from cs.utexas.edu by uunet.uu.net (5.61/1.14) with SMTP 
	id AA01451; Mon, 26 Nov 90 12:32:34 -0500
Posted-Date: Mon, 26 Nov 1990 11:32:18 CST
Message-Id: <9011261732.AA08684@cs.utexas.edu>
Received: by cs.utexas.edu (5.64/1.86) 
From: Fletcher Mattox <fletcher@cs.utexas.edu>
Date: Mon, 26 Nov 1990 11:32:18 CST
X-Mailer: Mail User's Shell (7.1.2 7/11/90)
To: rick@uunet.uu.net (Rick Adams)
Subject: Re:  newsbug
Status: R

Would it be better to put the dbmclose() in savehist rather than xxit?
Or does that close the file prematurely in some cases?

From fletcher@cs.utexas.edu Mon Nov 26 17:58:16 1990
Received: from cs.utexas.edu by uunet.uu.net (5.61/1.14) with SMTP 
	id AA13225; Mon, 26 Nov 90 17:58:12 -0500
Posted-Date: Mon, 26 Nov 1990 16:58:00 CST
Message-Id: <9011262258.AA11106@cs.utexas.edu>
Received: by cs.utexas.edu (5.64/1.86) 
From: Fletcher Mattox <fletcher@cs.utexas.edu>
Date: Mon, 26 Nov 1990 16:58:00 CST
X-Mailer: Mail User's Shell (7.1.2 7/11/90)
To: rick@uunet.uu.net (Rick Adams)
Subject: Re: c expire
Status: R

Very few changes are needed.

You've got to do Bnews-style locking in expire.c and updatemin.c.
Also, updatemin.c needs a small tweak to get the active file format correct.
Here's what I did (this includes a gratuitous change to expire.c which make
it more forgiving of damaged entries in the history file).

I've been using it over a year without problems.  With dbz for
about a week now ...

Oh yeah, if you want to rebuild the history file from scratch,
you've got to rewrite mkhistory so that it does Bnews locking
(not included).


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by cs.utexas.edu!fletcher on Mon Nov 26 16:35:03 CST 1990
# Contents:  Patch bnewslock.c
 
echo x - Patch
sed 's/^@//' > "Patch" <<'@//E*O*F Patch//'
*** ,expire.c	Fri Nov 16 16:36:08 1990
--- expire.c	Mon Nov 26 16:22:02 1990
***************
*** 26,31
  #define	EPOCH	((time_t)0)
  #endif
  
  #define	DAY	((double)24*60*60)
  
  /* structure for expiry-control records */

--- 26,40 -----
  #define	EPOCH	((time_t)0)
  #endif
  
+ #ifdef BNEWS
+ /*
+  * lock the active file, B news style.
+  */
+ #define newslock	b_newslock
+ #define newsunlock	b_newsunlock
+ #define errunlock	b_errunlock
+ #endif
+ 
  #define	DAY	((double)24*60*60)
  
  /* structure for expiry-control records */
***************
*** 459,465
  			nameend = strchr(line, '\t');
  			if (nameend == NULL) {
  				errno = 0;
! 				fail("bad return from doline(): `%.75s'", line);
  			}
  
  			/* make the DBM entry */

--- 468,475 -----
  			nameend = strchr(line, '\t');
  			if (nameend == NULL) {
  				errno = 0;
! 				warning("bad return from doline(): `%.75s'", line);
! 				continue;
  			}
  
  			/* make the DBM entry */
*** ,updatemin.c	Fri Nov 16 16:36:09 1990
--- updatemin.c	Mon Nov 26 16:19:22 1990
***************
*** 7,12
  #include <string.h>
  #include <signal.h>
  
  #ifndef BERKDIR
  #include <dirent.h>
  #else

--- 7,21 -----
  #include <string.h>
  #include <signal.h>
  
+ #ifdef BNEWS
+ /*
+  * lock the active file, B news style.
+  */
+ #define newslock	b_newslock
+ #define newsunlock	b_newsunlock
+ #define errunlock	b_errunlock
+ #endif
+ 
  #ifndef BERKDIR
  #include <dirent.h>
  #else
***************
*** 84,89
  		} else				/* no directory */
  			min = atol(field[2]);
  		fprintf(new, "%s %s ", field[0], field[1]);
  		if (min < 10000) {	/* insist on at least five digits */
  			sprintf(minstr, "%ld", min);
  			fprintf(new, "%s", "00000"+strlen(minstr));

--- 93,104 -----
  		} else				/* no directory */
  			min = atol(field[2]);
  		fprintf(new, "%s %s ", field[0], field[1]);
+ #ifdef BNEWS
+ 		if (min < 1000000) {	/* insist on at least seven digits */
+ 			sprintf(minstr, "%ld", min);
+ 			fprintf(new, "%s", "0000000"+strlen(minstr));
+ 		}
+ #else
  		if (min < 10000) {	/* insist on at least five digits */
  			sprintf(minstr, "%ld", min);
  			fprintf(new, "%s", "00000"+strlen(minstr));
***************
*** 88,93
  			sprintf(minstr, "%ld", min);
  			fprintf(new, "%s", "00000"+strlen(minstr));
  		}
  		fprintf(new, "%ld %s\n", min, field[3]);
  		free(name);
  		free(line);

--- 103,109 -----
  			sprintf(minstr, "%ld", min);
  			fprintf(new, "%s", "00000"+strlen(minstr));
  		}
+ #endif
  		fprintf(new, "%ld %s\n", min, field[3]);
  		free(name);
  		free(line);
*** ,Makefile	Sat Nov 17 07:36:31 1990
--- Makefile	Sat Nov 17 23:42:37 1990
***************
*** 1,6
  PROF = 
  COPTS = -O
! CFLAGS = $(COPTS) -I../include $(PROF)
  LINTFLAGS = -I../include
  JUNKLINT = 'possible pointer align'
  DBM =

--- 1,6 -----
  PROF = 
  COPTS = -O
! CFLAGS = $(COPTS) -DBNEWS -DBERKDIR -I../include $(PROF)
  LINTFLAGS = -I../include
  JUNKLINT = 'possible pointer align'
  DBM =
***************
*** 38,45
  newsinstall:	explist
  	-if test ! -r $(NEWSCTL)/explist ; then cp explist $(NEWSCTL)/explist ; fi
  
! expire: expire.o $(LIBS)
! 	$(CC) $(CFLAGS) $(LDFLAGS) expire.o $(PRE) $(DBM) $(LIBS) $(POST) -o $@
  
  histinfo: histinfo.o $(LIBS)
  	$(CC) $(CFLAGS) $(LDFLAGS) histinfo.o $(PRE) $(LIBS) $(POST) -o $@

--- 38,45 -----
  newsinstall:	explist
  	-if test ! -r $(NEWSCTL)/explist ; then cp explist $(NEWSCTL)/explist ; fi
  
! expire: expire.o bnewslock.o $(LIBS)
! 	$(CC) $(CFLAGS) $(LDFLAGS) expire.o bnewslock.o $(PRE) $(DBM) $(LIBS) $(POST) -o $@
  
  histinfo: histinfo.o $(LIBS)
  	$(CC) $(CFLAGS) $(LDFLAGS) histinfo.o $(PRE) $(LIBS) $(POST) -o $@
***************
*** 44,51
  histinfo: histinfo.o $(LIBS)
  	$(CC) $(CFLAGS) $(LDFLAGS) histinfo.o $(PRE) $(LIBS) $(POST) -o $@
  
! updatemin:	updatemin.o $(LIBS)
! 	$(CC) $(CFLAGS) $(LDFLAGS) updatemin.o $(PRE) $(LIBS) $(POST) -o $@
  
  histslash:	histslash.o $(LIBS)
  	$(CC) $(CFLAGS) $(LDFLAGS) histslash.o $(PRE) $(LIBS) $(POST) -o $@

--- 44,51 -----
  histinfo: histinfo.o $(LIBS)
  	$(CC) $(CFLAGS) $(LDFLAGS) histinfo.o $(PRE) $(LIBS) $(POST) -o $@
  
! updatemin:	updatemin.o bnewslock.o $(LIBS)
! 	$(CC) $(CFLAGS) $(LDFLAGS) updatemin.o bnewslock.o $(PRE) $(LIBS) $(POST) -o $@
  
  histslash:	histslash.o $(LIBS)
  	$(CC) $(CFLAGS) $(LDFLAGS) histslash.o $(PRE) $(LIBS) $(POST) -o $@
@//E*O*F Patch//
chmod u=rw,g=rw,o=r Patch
 
echo x - bnewslock.c
sed 's/^@//' > "bnewslock.c" <<'@//E*O*F bnewslock.c//'
/*
 * Lock the system, B news style.
 */

#include <sys/syslog.h>
#include <sys/file.h>
static int fd;

void
b_newslock()
{
	extern char *progname, *ctlfile();
	char *active = ctlfile("active");

	openlog(progname, 0, LOG_NEWS);
	if ((fd = open(active, 2)) < 0) {
		perror(active);
		exit(1);
	}
	if (flock(fd, LOCK_EX) < 0) {
		perror("expire can't flock the active file");
		exit(1);
	}
	syslog(LOG_INFO, "%s: locked", active);
}

void
b_newsunlock()
{
	(void) close(fd);
	syslog(LOG_INFO, "active file unlocked");
}

void
b_errunlock(fmt, s)		/* like error(3), but unlock before exit */
char *fmt, *s;
{
	warning(fmt, s);
	b_newsunlock();
	exit(1);
	/* NOTREACHED */
}
@//E*O*F bnewslock.c//
chmod u=rw,g=rw,o=r bnewslock.c
 
exit 0


From ado@alw.nih.gov Wed Jan 30 16:43:06 1991
Received: from alw.nih.gov by uunet.uu.net (5.61/1.14) with SMTP 
	id AA16822; Wed, 30 Jan 91 16:43:03 -0500
Received: from sunrise.nci.nih.gov by alw.nih.gov (5.61/alw-2.1)
	id AA06115; Wed, 30 Jan 91 16:43:01 -0500
Received: by sunrise.nci.nih.gov (4.0/afs-1.0)
	id AA05334; Wed, 30 Jan 91 16:42:59 EST
Date: Wed, 30 Jan 91 16:42:59 EST
From: ado@alw.nih.gov
Message-Id: <9101302142.AA05334@sunrise.nci.nih.gov>
To: rick@uunet.uu.net
Subject: checknews.c
Status: R

Just in case anybody wants to maintain B news, the attached changes ensure
that "checknews" doesn't leave files in /tmp when it's used in an nntp
environment.

				--ado

*** 1.1/checknews.c	Wed Jan 30 16:40:49 1991
--- 1.2/checknews.c	Wed Jan 30 16:40:50 1991
***************
*** 225,231 ****
  	fprintf(stderr, "header.nbuf = %s\n", header.nbuf);
  #endif
  	nchk(argv);
! 	exit(0);
  }
  
  nchk(argv)
--- 225,231 ----
  	fprintf(stderr, "header.nbuf = %s\n", header.nbuf);
  #endif
  	nchk(argv);
! 	xxit(0);
  }
  
  nchk(argv)
***************
*** 317,322 ****
--- 317,327 ----
  			printf(".\n");
  	}
  	if (e) {
+ #ifdef SERVER
+ 		if (active_name() != NULL) 
+ 			(void) unlink(active_name());
+ 		close_server();
+ #endif /* SERVER */
  #ifdef V6
  		execv("/usr/bin/readnews", argv);
  #else
***************
*** 325,333 ****
  		perror("Cannot exec readnews.");
  	}
  	if (q)
! 		exit(1);
  	else
! 		exit(0);
  }
  
  xerror(message, arg1, arg2)
--- 330,338 ----
  		perror("Cannot exec readnews.");
  	}
  	if (q)
! 		xxit(1);
  	else
! 		xxit(0);
  }
  
  xerror(message, arg1, arg2)
***************
*** 338,344 ****
  
  	sprintf(buffer, message, arg1, arg2);
  	fprintf(stderr, "checknews: %s.\n", buffer);
! 	exit(1);
  }
  
  /*
--- 343,349 ----
  
  	sprintf(buffer, message, arg1, arg2);
  	fprintf(stderr, "checknews: %s.\n", buffer);
! 	xxit(1);
  }
  
  /*
***************
*** 549,554 ****
--- 554,561 ----
  xxit(i)
  {
  #ifdef SERVER
+ 	if (active_name() != NULL) 
+ 		(void) unlink(active_name());
  	close_server();
  #endif /* SERVER */
  	exit(i);

From jagware!jjb@uunet.UU.NET Sun Dec 29 14:02:40 1991
Received: from relay2.UU.NET by rodan.UU.NET with SMTP 
	(5.61/UUNET-mail-drop) id AA00713; Sun, 29 Dec 91 14:02:38 -0500
Received: from seismo.CSS.GOV by relay2.UU.NET with SMTP 
	(5.61/UUNET-internet-primary) id AA02070; Sun, 29 Dec 91 14:02:25 -0500
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.65/1.14)
	id AA29171; Sun, 29 Dec 91 14:02:17 -0500
Received: from seismo.CSS.GOV by beno.CSS.GOV (4.1/SMI-4.1)
	id AA11220; Sun, 29 Dec 91 14:02:15 EST
Received: from relay2.UU.NET by seismo.CSS.GOV (5.65/1.14)
	id AA29167; Sun, 29 Dec 91 14:02:14 -0500
Received: from uunet.uu.net (via LOCALHOST.UU.NET) by relay2.UU.NET with SMTP 
	(5.61/UUNET-internet-primary) id AA02018; Sun, 29 Dec 91 14:02:05 -0500
Received: from jagware.UUCP by uunet.uu.net with UUCP/RMAIL
	(queueing-rmail) id 140144.2177; Sun, 29 Dec 1991 14:01:44 EST
Received: by jagware.acco.com (/\==/\ Smail3.1.25.1 #25.1)
	id <m0ky539-0001ANC@jagware.acco.com>; Sun, 29 Dec 91 10:15 PST
Message-Id: <m0ky539-0001ANC@jagware.acco.com>
From: jjb@jagware.acco.com (J.J.Bailey)
Subject: bnews-2.11 patch
To: rick@seismo.CSS.GOV
Date: Sun, 29 Dec 91 10:15:49 PST
X-Mailer: ELM [version 2.3 PL11]
Status: OR

I had to make the following change to virtterm.c to compile it
on Interactive UNIX 3.0 (SVR3.2.2):


*** virtterm.c-	Tue Sep 12 14:56:36 1989
--- virtterm.c	Sun Dec 29 10:05:20 1991
***************
*** 17,22
  #include <signal.h>
  #ifdef USG
  #include <termio.h>
  #else /* !USG */
  #include <sgtty.h>
  #endif /* !USG */

--- 17,26 -----
  #include <signal.h>
  #ifdef USG
  #include <termio.h>
+ #ifdef	i386
+ #include <sys/stream.h>
+ #include <sys/ptem.h>
+ #endif
  #else /* !USG */
  #include <sgtty.h>
  #endif /* !USG */


-Jack

-- 
J.J.Bailey           jjb@jagware.acco.com || {uunet,pacbell}!jagware!jjb

From brook@trillium.botany.utexas.edu Mon Jan  6 16:35:32 1992
Received: from relay2.UU.NET by rodan.UU.NET with SMTP 
	(5.61/UUNET-mail-drop) id AA00728; Mon, 6 Jan 92 16:35:32 -0500
Received: from seismo.CSS.GOV by relay2.UU.NET with SMTP 
	(5.61/UUNET-internet-primary) id AA06371; Mon, 6 Jan 92 16:35:29 -0500
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.65/1.14)
	id AA05585; Mon, 6 Jan 92 16:35:22 -0500
Received: from masakayan.CSS.GOV by beno.CSS.GOV (4.1/SMI-4.1)
	id AA02869; Mon, 6 Jan 92 16:35:19 EST
Received: from emx.utexas.edu by masakayan.CSS.GOV (5.61/1.14)
	id AA16705; Mon, 6 Jan 92 16:35:13 -0500
Posted-Date:  Mon, 6 Jan 92 15:23:39 -0600
Received: from trillium.botany.utexas.edu by emx.utexas.edu (5.61/1.9)
	id AA24544; Mon, 6 Jan 92 15:24:59 -0600
Received: by trillium.botany.utexas.edu (5.57/Ultrix3.0-C)
	id AA16350; Mon, 6 Jan 92 15:23:39 -0600
Date: Mon, 6 Jan 92 15:23:39 -0600
From: brook@trillium.botany.utexas.edu (Brook Milligan)
Message-Id: <9201062123.AA16350@trillium.botany.utexas.edu>
To: rick@seismo.CSS.GOV
Cc: brook@trillium.botany.utexas.edu
Subject: bnews v2.11 errors
Status: OR

I am trying to install bnews v2.11 on a decstation 3100 running ultrix
4.2.  When compiling the source I get errors with both ifuncs.c and
rfuncs2.c.  As you can see from below, I know what is causing the
ifuncs.c error and provide a suggestion for one means of fixing the
source to eliminate it.

ifuncs.c:

cc  -DDBM -DRNEWS=\"/usr/local/bin/rnews\"
	-DSPOOLDIR=\"/usr/spool/news\" -DBATCHDIR=\"/usr/spool/batch\"
	-DLIBDIR=\"/usr/local/lib/news\"  -DBINDIR=\"/usr/local/bin\"
	-DNEWSUSR=\"news\"  -DNEWSGRP=\"news\"   -DSCCSID    -c
	ifuncs.c 

ccom: Error: /usr/include/unistd.h, line 184: redeclaration of sleep
      	sleep();
      ---------^
*** Error code 1

Apparently this error results from including the header file (which
declares sleep() as "unsigned int sleep()") after implicitly declaring
sleep() as returning int by using it as "sleep((unsigned)60);".
Including the header earlier in the source eliminates the
redeclaration complaint.  Is there a problem with this solution?

The portion of my localize.sh script that fixes ifuncs.c follows:

     ed - ifuncs.c <<'EOF'
     /#include "iparams.h"/a

     #if defined(BSD4_2) || defined(LOCKF)
     #ifdef LOCKF
     #include <unistd.h>
     #else /* !LOCKF */
     #include <sys/file.h>
     #endif /* !LOCKF */
     #endif /* BSD4_2 */

     .
     w
     q
     EOF


The rfuncs2.c error is less clear.

rfuncs2.c:

cc  -DDBM -DRNEWS=\"/usr/local/bin/rnews\"
	-DSPOOLDIR=\"/usr/spool/news\" -DBATCHDIR=\"/usr/spool/batch\"
	-DLIBDIR=\"/usr/local/lib/news\" -DBINDIR=\"/usr/local/bin\"
	-DNEWSUSR=\"news\"  -DNEWSGRP=\"news\"   -DSCCSID   -c
	rfuncs2.c 

ccom: Error: rfuncs2.c, line 314: illegal lhs of assignment operator
      		((int)((fp)->_file)) = -1;
      -----------------------------------^
ccom: Error: rfuncs2.c, line 316: illegal lhs of assignment operator
      		((int)((fp)->_file)) = fno;
      ------------------------------------^
*** Error code 1

The function being compiled is:

     /*
      * Quiet 'flush'.
      * Empty (without fflush()) the buffer for stream fp.
      */
     #ifndef fileno
     /* ARGSUSED */
     #endif /* !defined fileno */
     qfflush(fp)
     FILE *fp;
     {
     #ifdef fileno
	     int	fno, err;

	     fno = fileno(fp);
	     err = ferror(fp);
	     fileno(fp) = -1;                  <----- error
	     (void) fflush(fp);
	     fileno(fp) = fno;                 <----- error
	     if (!err)
		     (void) clearerr(fp);
     #endif /* fileno */
     }

It would seem to me that these statements are syntactically incorrect.
Are they not treating a function (or macro) as an lvalue?  On other
systems, how is `fileno(fp)' defined, and why do these statements
work?  How can these statements be fixed in the context of the ultrix
#include files?  Have other people succeeded in compiling this under
ultrix?

Thanks for any help you can offer.  If you cannot help, please suggest
someone who might be able to.

===========================================================================
Brook G. Milligan               Internet:  brook@trillium.botany.utexas.edu
Department of Botany            Bitnet:    bohk313@utaivc
University of Texas at Austin   UUCP:      ...!ut-emx!brook
Austin, Texas  78713   U.S.A.   (512) 471-3530
===========================================================================


From prg@mgweed.att.com Sat Jan 25 00:01:11 1992
Received: from relay2.UU.NET by rodan.UU.NET with SMTP 
	(5.61/UUNET-mail-drop) id AA23248; Sat, 25 Jan 92 00:01:10 -0500
Received: from seismo.CSS.GOV by relay2.UU.NET with SMTP 
	(5.61/UUNET-internet-primary) id AA19023; Sat, 25 Jan 92 00:01:09 -0500
Received: from beno.CSS.GOV by seismo.CSS.GOV (5.65/1.14)
	id AA18059; Sat, 25 Jan 92 00:00:57 -0500
Received: from seismo.CSS.GOV by beno.CSS.GOV (4.1/SMI-4.1)
	id AA20436; Sat, 25 Jan 92 00:00:55 EST
Received: from att.att.com by seismo.CSS.GOV (5.65/1.14)
	id AA18053; Sat, 25 Jan 92 00:00:54 -0500
From: prg@mgweed.att.com
Received: by mgweed.uucp (/\==/\ Smail3.1.21.1 #21.8)
	id <m0l7fTH-0001MhC@mgweed.uucp>; Fri, 24 Jan 92 22:58 CST
Message-Id: <m0l7fTH-0001MhC@mgweed.uucp>
Date: Fri, 24 Jan 92 22:58 CST
Original-From: prg@mgweed.uucp (Phil Gunsul - WB9AAX)
To: rick@seismo.CSS.GOV
Subject: Problems with 2.11 (patch 19) compiling on 3.2.2 UNIX (3B2/1000 - 80)
Status: OR

Hi Rick,

I thought I would drop a note to you about a problem I was having with
compiling 2.11 on our 3B2/1000 model 80's (4.2 "C" compiler, BTW)...
The operating system, UNIX 3.2.2 R3

Without the expert guidance and help from Kevin Darcy, I'd still be
scratching my head!

The problem arose while nearing the end of the 'make', compiling the
virtterm.c.  There were some missing definitions where the TIOCGWINSZ
variables were "ifdef"'d, but were fixable by adding "stream.h" and
"ptem.h" to the includes for USG..

#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <signal.h>
#ifdef USG
#include <sys/stream.h>
#include <sys/ptem.h>
#include <termio.h>
#else /* !USG */
#include <sgtty.h>
#endif /* !USG */


Next, "vnews" would not allow a shell escape, which included not being
able to "post" from vnews..  This was fixed by modifying "visual.c",
declaring the "char arg[4]" array in the "shcmd()" function, as "static",
preventing the 'sudden dumbness' that occurred when the arguments passed from
"shcmd()" to "prun()" were lost on the stack somewhere..

(Somewhere around line 1725 of visual.c)


/*
 * Execute a shell command.
 */

shcmd(cmd, flags)
char *cmd;
{
	static char *arg[4];

	arg[0] = SHELL, arg[1] = "-c", arg[2] = cmd, arg[3] = NULL;
	return prun(arg, flags);
}


prun(args, flags)
char **args;
{
	int pid;
	int i;
	SIGNAL_TYPE savequit;
	char *env[100], **envp, **oenvp;
	char a[BUFLEN + 2];
	extern char **environ;
	int pstatus, retval;



Thanks for your time and effort on vnews Rick, hope the above info is of some
use.


   ____   _______   _____   _______     -------      Phil Gunsul
  / __ \ |__   __| /   _ \ |__   __|  -====------    AT&T Information Systems
 | (__) |   | |    \  \ \_\   | |    -======------   ...!att!mgweed!prg
 |  __  |   | |    /   \ __   | |    --====-------   prg@mgweed.ATT.COM
 | |  | |   | |   |  (\ / /   | |     -----------    Montgomery, IL 60538
 |_|  |_|   |_|    \_____/    |_|       -------      (708)-859-4485


