[comp.sources.unix] v14i049: Network News Transfer Protocol, version 1.5, Part03/09

rsalz@bbn.com (Rich Salz) (04/20/88)

Submitted-by: Phil Lapsley <phil@ucbvax.berkeley.edu>
Posting-number: Volume 14, Issue 49
Archive-name: nntp1.5/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 9)."
# Wrapped by rsalz@fig.bbn.com on Tue Apr 19 18:16:39 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f './rrnpatches/Makefile.SH.pat' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./rrnpatches/Makefile.SH.pat'\"
else
echo shar: Extracting \"'./rrnpatches/Makefile.SH.pat'\" \(4585 characters\)
sed "s/^X//" >'./rrnpatches/Makefile.SH.pat' <<'END_OF_FILE'
X*** rn/Makefile.SH	Sun Mar 15 19:54:40 1987
X--- rrn/Makefile.SH	Thu Feb 25 20:38:38 1988
X***************
X*** 1,5
X  case $CONFIG in
X!     '') . config.sh ;;
X  esac
X  echo "Extracting Makefile (with variable substitutions)"
X  cat >Makefile <<!GROK!THIS!
X
X--- 1,5 -----
X  case $CONFIG in
X!     '') . ./config.sh ;;
X  esac
X  echo "Extracting Makefile (with variable substitutions)"
X  cat >Makefile <<!GROK!THIS!
X***************
X*** 21,26
X  rnlib = $rnlib
X  mansrc = $mansrc
X  manext = $manext
X  CFLAGS = $iandd -O
X  LDFLAGS = $iandd
X  NDIRC = $ndirc
X
X--- 21,27 -----
X  rnlib = $rnlib
X  mansrc = $mansrc
X  manext = $manext
X+ NNTPSRC = $NNTPSRC
X  CFLAGS = $iandd -O
X  LDFLAGS = $iandd
X  NDIRC = $ndirc
X***************
X*** 31,37
X  cat >>Makefile <<'!NO!SUBS!'
X  
X  public = rn newsetup newsgroups Pnews Rnmail
X! private = norm.saver mbox.saver ng.help art.help pager.help subs.help makedir filexp Pnews.header
X  manpages = rn.1 Pnews.1 Rnmail.1 newsetup.1 newsgroups.1
X  util = Makefile makedepend newsnews
X  
X
X--- 32,38 -----
X  cat >>Makefile <<'!NO!SUBS!'
X  
X  public = rn newsetup newsgroups Pnews Rnmail
X! private = norm.saver mbox.saver ng.help art.help pager.help subs.help makedir filexp Pnews.header getactive
X  manpages = rn.1 Pnews.1 Rnmail.1 newsetup.1 newsgroups.1
X  util = Makefile makedepend newsnews
X  
X***************
X*** 45,51
X  c1 = addng.c art.c artio.c artsrch.c backpage.c bits.c cheat.c
X  c2 = final.c head.c help.c init.c intrp.c kfile.c last.c $(NDIRC) ng.c
X  c3 = ngdata.c ngsrch.c ngstuff.c only.c rcln.c rcstuff.c
X! c4 = respond.c rn.c search.c sw.c term.c util.c
X  
X  c = $(c1) $(c2) $(c3) $(c4)
X  
X
X--- 46,52 -----
X  c1 = addng.c art.c artio.c artsrch.c backpage.c bits.c cheat.c
X  c2 = final.c head.c help.c init.c intrp.c kfile.c last.c $(NDIRC) ng.c
X  c3 = ngdata.c ngsrch.c ngstuff.c only.c rcln.c rcstuff.c
X! c4 = respond.c rn.c search.c sw.c term.c util.c $(NNTPSRC)/common/clientlib.c
X  
X  c = $(c1) $(c2) $(c3) $(c4)
X  
X***************
X*** 52,58
X  obj1 = addng.o art.o artio.o artsrch.o backpage.o bits.o cheat.o
X  obj2 = final.o head.o help.o init.o intrp.o kfile.o last.o $(NDIRO) ng.o
X  obj3 = ngdata.o ngsrch.o ngstuff.o only.o rcln.o rcstuff.o
X! obj4 = respond.o rn.o search.o sw.o term.o util.o
X  
X  obj = $(obj1) $(obj2) $(obj3) $(obj4)
X  
X
X--- 53,59 -----
X  obj1 = addng.o art.o artio.o artsrch.o backpage.o bits.o cheat.o
X  obj2 = final.o head.o help.o init.o intrp.o kfile.o last.o $(NDIRO) ng.o
X  obj3 = ngdata.o ngsrch.o ngstuff.o only.o rcln.o rcstuff.o
X! obj4 = respond.o rn.o search.o sw.o term.o util.o $(NNTPSRC)/common/clientlib.o
X  
X  obj = $(obj1) $(obj2) $(obj3) $(obj4)
X  
X***************
X*** 78,83
X  rn: $(obj)
X  	$(CC) $(LDFLAGS) $(obj) $(libs) -o rn
X  
X  # if a .h file depends on another .h file...
X  $(h):
X  	touch $@
X
X--- 79,92 -----
X  rn: $(obj)
X  	$(CC) $(LDFLAGS) $(obj) $(libs) -o rn
X  
X+ getactive: getactive.o $(NNTPSRC)/common/clientlib.o
X+ 	$(CC) $(LDFLAGS) getactive.o $(NNTPSRC)/common/clientlib.o -o getactive
X+ 
X+ # Eek! This is gross.
X+ $(NNTPSRC)/common/clientlib.o:
X+ 	$(CC) -c $(CFLAGS) $(NNTPSRC)/common/clientlib.c
X+ 	mv clientlib.o $(NNTPSRC)/common/clientlib.o
X+ 
X  # if a .h file depends on another .h file...
X  $(h):
X  	touch $@
X***************
X*** 86,91
X  # won't work with csh
X  	export PATH || exit 1
X  	- mv $(rnbin)/rn $(rnbin)/rn.old
X  	- if test `pwd` != $(rnbin); then cp $(public) $(rnbin); fi
X  	cd $(rnbin); chmod 755 $(public)
X  	chmod 755 makedir
X
X--- 95,101 -----
X  # won't work with csh
X  	export PATH || exit 1
X  	- mv $(rnbin)/rn $(rnbin)/rn.old
X+ 	- ln -s $(rnbin)/rn $(rnbin)/rrn
X  	- if test `pwd` != $(rnbin); then cp $(public) $(rnbin); fi
X  	cd $(rnbin); chmod 755 $(public)
X  	chmod 755 makedir
X***************
X*** 103,109
X  	rm -f *.o
X  
X  realclean:
X! 	rm -f rn *.o core $(addedbyconf)
X  
X  # The following lint has practically everything turned on.  Unfortunately,
X  # you have to wade through a lot of mumbo jumbo that can't be suppressed.
X
X--- 113,119 -----
X  	rm -f *.o
X  
X  realclean:
X! 	rm -f rn *.o core $(addedbyconf) $(NNTPSRC)/common/clientlib.o
X  
X  # The following lint has practically everything turned on.  Unfortunately,
X  # you have to wade through a lot of mumbo jumbo that can't be suppressed.
X***************
X*** 114,120
X  	lint $(lintflags) $(defs) $(c) > rn.fuzz
X  
X  depend:
X! 	makedepend
X  
X  # AUTOMATICALLY GENERATED MAKE DEPENDENCIES--PUT NOTHING BELOW THIS LINE
X  $(obj):
X
X--- 124,130 -----
X  	lint $(lintflags) $(defs) $(c) > rn.fuzz
X  
X  depend:
X! 	./makedepend
X  
X  # AUTOMATICALLY GENERATED MAKE DEPENDENCIES--PUT NOTHING BELOW THIS LINE
X  $(obj):
END_OF_FILE
if test 4585 -ne `wc -c <'./rrnpatches/Makefile.SH.pat'`; then
    echo shar: \"'./rrnpatches/Makefile.SH.pat'\" unpacked with wrong size!
fi
# end of './rrnpatches/Makefile.SH.pat'
fi
if test -f './rrnpatches/artio.c.pat' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./rrnpatches/artio.c.pat'\"
else
echo shar: Extracting \"'./rrnpatches/artio.c.pat'\" \(3894 characters\)
sed "s/^X//" >'./rrnpatches/artio.c.pat' <<'END_OF_FILE'
X*** rn/artio.c	Sun Mar 15 19:54:46 1987
X--- rrn/artio.c	Wed Aug 19 21:29:20 1987
X***************
X*** 8,13
X  
X  #include "EXTERN.h"
X  #include "common.h"
X  #include "INTERN.h"
X  #include "artio.h"
X  
X
X--- 8,14 -----
X  
X  #include "EXTERN.h"
X  #include "common.h"
X+ #include "server.h"
X  #include "INTERN.h"
X  #include "artio.h"
X  
X***************
X*** 23,29
X  artopen(artnum)
X  ART_NUM artnum;
X  {
X!     char artname[8];			/* filename of current article */
X  
X      if (artnum < 1)
X  	return Nullfp;
X
X--- 24,34 -----
X  artopen(artnum)
X  ART_NUM artnum;
X  {
X! #ifdef SERVER
X!     static long our_pid;
X!     char ser_line[256];
X! #endif SERVER
X!     char artname[32];			/* filename of current article */
X  
X  #ifdef SERVER
X      if (our_pid == 0)
X***************
X*** 25,30
X  {
X      char artname[8];			/* filename of current article */
X  
X      if (artnum < 1)
X  	return Nullfp;
X      if (openart == artnum) {		/* this article is already open? */
X
X--- 30,40 -----
X  #endif SERVER
X      char artname[32];			/* filename of current article */
X  
X+ #ifdef SERVER
X+     if (our_pid == 0)
X+ 	our_pid = getpid();
X+ #endif SERVER
X+ 
X      if (artnum < 1)
X  	return Nullfp;
X      if (openart == artnum) {		/* this article is already open? */
X***************
X*** 33,38
X      }
X      if (artfp != Nullfp) {		/* it was somebody else? */
X  	fclose(artfp);			/* put them out of their misery */
X  	openart = 0;			/* and remember them no more */
X      }
X      sprintf(artname,"%ld",(long)artnum);
X
X--- 43,52 -----
X      }
X      if (artfp != Nullfp) {		/* it was somebody else? */
X  	fclose(artfp);			/* put them out of their misery */
X+ #ifdef SERVER
X+ 	sprintf(artname, "/tmp/rrn%ld.%ld", (long) openart, our_pid);
X+ 	UNLINK(artname);
X+ #endif SERVER
X  	openart = 0;			/* and remember them no more */
X      }
X  
X***************
X*** 35,40
X  	fclose(artfp);			/* put them out of their misery */
X  	openart = 0;			/* and remember them no more */
X      }
X      sprintf(artname,"%ld",(long)artnum);
X  					/* produce the name of the article */
X      if (artfp = fopen(artname,"r"))	/* if we can open it */
X
X--- 49,92 -----
X  #endif SERVER
X  	openart = 0;			/* and remember them no more */
X      }
X+ 
X+ #ifdef SERVER
X+ 
X+     sprintf(artname,"/tmp/rrn%ld.%ld", (long) artnum, our_pid);
X+     artfp = fopen(artname, "w+");	/* create the temporary article */
X+     if (artfp == Nullfp) {
X+ 	UNLINK(artname);
X+ 	return Nullfp;
X+     }
X+     sprintf(ser_line, "ARTICLE %ld", (long)artnum);
X+     put_server(ser_line);		/* ask the server for the article */
X+     if (get_server(ser_line, sizeof(ser_line)) < 0) {
X+ 	fprintf(stderr, "rrn: Unexpected close of server socket.\n");
X+ 	finalize(1);
X+     }
X+     if (*ser_line != CHAR_OK) {		/* and get it's reaction */
X+ 	fclose(artfp);
X+ 	artfp = Nullfp;
X+ 	UNLINK(artname);
X+         return Nullfp;
X+     }
X+ 
X+     for (;;) {
X+         if (get_server(ser_line, sizeof(ser_line)) < 0) {
X+ 	    fprintf(stderr, "rrn: Unexpected close of server socket.\n");
X+ 	    finalize(1);
X+ 	}
X+ 	if (ser_line[0] == '.' && ser_line[1] == '\0')
X+ 		break;
X+ 	fputs((ser_line[0] == '.' ? ser_line + 1 : ser_line), artfp);
X+ 	putc('\n', artfp);
X+     }
X+ 
X+     fseek(artfp, 0L, 0);		/* Then get back to the start */
X+     openart = artnum;
X+ 
X+ #else not SERVER
X+ 
X      sprintf(artname,"%ld",(long)artnum);
X  					/* produce the name of the article */
X      if (artfp = fopen(artname,"r"))	/* if we can open it */
X***************
X*** 39,44
X  					/* produce the name of the article */
X      if (artfp = fopen(artname,"r"))	/* if we can open it */
X  	openart = artnum;		/* remember what we did here */
X  #ifdef LINKART
X      {
X  	char tmpbuf[256];
X
X--- 91,98 -----
X  					/* produce the name of the article */
X      if (artfp = fopen(artname,"r"))	/* if we can open it */
X  	openart = artnum;		/* remember what we did here */
X+ 
X+ #endif SERVER
X  #ifdef LINKART
X      {
X  	char tmpbuf[256];
END_OF_FILE
if test 3894 -ne `wc -c <'./rrnpatches/artio.c.pat'`; then
    echo shar: \"'./rrnpatches/artio.c.pat'\" unpacked with wrong size!
fi
# end of './rrnpatches/artio.c.pat'
fi
if test -f './rrnpatches/common.h.pat' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./rrnpatches/common.h.pat'\"
else
echo shar: Extracting \"'./rrnpatches/common.h.pat'\" \(4168 characters\)
sed "s/^X//" >'./rrnpatches/common.h.pat' <<'END_OF_FILE'
X*** rn/common.h	Sun Mar 15 19:54:22 1987
X--- rrn/common.h	Sun Mar 15 22:20:24 1987
X***************
X*** 567,573
X  
X  #ifndef PIPESAVER		/* % */
X  #   ifdef CONDSUB
X! #	define PIPESAVER "%(%B=^0$?<%A:tail +%Bc %A |) %b"
X  #   else
X  #	define PIPESAVER "tail +%Bc %A | %b"
X  #   endif
X
X--- 567,577 -----
X  
X  #ifndef PIPESAVER		/* % */
X  #   ifdef CONDSUB
X! #       ifdef SERVER
X! #               define PIPESAVER "%(%B=^0$?<%P/rrn%a.%$:tail +%Bc %P/rrn%a.%$ |) %b"
X! #       else
X! #		define PIPESAVER "%(%B=^0$?<%A:tail +%Bc %A |) %b"
X! #	endif
X  #   else
X  #       ifdef SERVER
X  #               define PIPESAVER "tail +%Bc %P/rrn%a.%$ | %b"
X***************
X*** 569,575
X  #   ifdef CONDSUB
X  #	define PIPESAVER "%(%B=^0$?<%A:tail +%Bc %A |) %b"
X  #   else
X! #	define PIPESAVER "tail +%Bc %A | %b"
X  #   endif
X  #endif
X  
X
X--- 573,583 -----
X  #		define PIPESAVER "%(%B=^0$?<%A:tail +%Bc %A |) %b"
X  #	endif
X  #   else
X! #       ifdef SERVER
X! #               define PIPESAVER "tail +%Bc %P/rrn%a.%$ | %b"
X! #       else
X! #		define PIPESAVER "tail +%Bc %A | %b"
X! #	endif
X  #   endif
X  #endif
X  
X***************
X*** 574,580
X  #endif
X  
X  #ifndef NORMSAVER		/* % and ~ */
X! #   define NORMSAVER "%X/norm.saver %A %P %c %a %B %C \"%b\""
X  #endif
X  
X  #ifndef MBOXSAVER		/* % and ~ */
X
X--- 582,592 -----
X  #endif
X  
X  #ifndef NORMSAVER		/* % and ~ */
X! #    ifdef SERVER
X! #	define NORMSAVER "%X/norm.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\""
X! #    else
X! #   	define NORMSAVER "%X/norm.saver %A %P %c %a %B %C \"%b\""
X! #    endif
X  #endif
X  
X  #ifndef MBOXSAVER		/* % and ~ */
X***************
X*** 579,585
X  
X  #ifndef MBOXSAVER		/* % and ~ */
X  #   ifdef MININACT		/* 2.10.2 site? */
X! #	define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %`date`\""
X  #   else
X  #	ifdef CONDSUB
X  #	    define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4)\""
X
X--- 591,601 -----
X  
X  #ifndef MBOXSAVER		/* % and ~ */
X  #   ifdef MININACT		/* 2.10.2 site? */
X! #       ifdef SERVER
X! #           define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\" \"From %T %`date`\""
X! #       else
X! #	    define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %`date`\""
X! #	endif SERVER
X  #   else
X  #	ifdef CONDSUB
X  #           ifdef SERVER
X***************
X*** 582,588
X  #	define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %`date`\""
X  #   else
X  #	ifdef CONDSUB
X! #	    define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4)\""
X  					/* header munging with a vengeance */
X  #	else
X  #	    define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %[posted]\""
X
X--- 598,610 -----
X  #	endif SERVER
X  #   else
X  #	ifdef CONDSUB
X! #           ifdef SERVER
X! #               define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\
X! " \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?
X! %1 %3 %(%2=..?%2: %2) %5 19%4)\""
X! #           else
X! #	        define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4)\""
X! #	    endif
X  					/* header munging with a vengeance */
X  #	else
X  #           ifdef SERVER
X***************
X*** 585,591
X  #	    define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4)\""
X  					/* header munging with a vengeance */
X  #	else
X! #	    define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %[posted]\""
X  #	endif
X  #   endif
X  #endif
X
X--- 607,617 -----
X  #	    endif
X  					/* header munging with a vengeance */
X  #	else
X! #           ifdef SERVER
X! #               define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\" \"From %T %[posted]\""
X! #           else
X! #	        define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %[posted]\""
X! #	    endif
X  #	endif
X  #   endif
X  #endif
END_OF_FILE
if test 4168 -ne `wc -c <'./rrnpatches/common.h.pat'`; then
    echo shar: \"'./rrnpatches/common.h.pat'\" unpacked with wrong size!
fi
# end of './rrnpatches/common.h.pat'
fi
if test -f './rrnpatches/head.c.pat' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./rrnpatches/head.c.pat'\"
else
echo shar: Extracting \"'./rrnpatches/head.c.pat'\" \(3320 characters\)
sed "s/^X//" >'./rrnpatches/head.c.pat' <<'END_OF_FILE'
X*** rn/head.c	Sun Mar 15 19:54:37 1987
X--- rrn/head.c	Mon Jun  1 10:18:35 1987
X***************
X*** 16,21
X  #include "common.h"
X  #include "artio.h"
X  #include "bits.h"
X  #include "util.h"
X  #include "INTERN.h"
X  #include "head.h"
X
X--- 16,22 -----
X  #include "common.h"
X  #include "artio.h"
X  #include "bits.h"
X+ #include "server.h"
X  #include "util.h"
X  #include "INTERN.h"
X  #include "head.h"
X***************
X*** 180,185
X  bool copy;				/* do you want it savestr()ed? */
X  {
X      char *s = Nullch, *t;
X  
X  #ifdef CACHESUBJ
X      if (!subj_list) {
X
X--- 181,191 -----
X  bool copy;				/* do you want it savestr()ed? */
X  {
X      char *s = Nullch, *t;
X+ #ifdef SERVER
X+     static int xhdr = 1;		/* Can we use xhdr command? */
X+     int eoo;				/* End of server output */
X+     char ser_line[256];
X+ #endif SERVER
X  
X  #ifdef CACHESUBJ
X      if (!subj_list) {
X***************
X*** 208,213
X  	else {
X  	    s = safemalloc((MEM_SIZE)256);
X  	    *s = '\0';
X  	    if (artopen(artnum) != Nullfp) {
X  		do {
X  		    if (fgets(s,256,artfp) == Nullch)
X
X--- 214,268 -----
X  	else {
X  	    s = safemalloc((MEM_SIZE)256);
X  	    *s = '\0';
X+ #ifdef SERVER
X+ 	    if (xhdr) {
X+ 	    	sprintf(ser_line, "XHDR subject %ld", artnum);
X+ 	    	put_server(ser_line);
X+ 		if (get_server(ser_line, sizeof (ser_line)) >= 0) {
X+ 			if (ser_line[0] == CHAR_FATAL) {
X+ 			    xhdr = 0;
X+ 			} else {
X+ 			    while (get_server(ser_line, sizeof (ser_line)) >= 0) {
X+ 				if (ser_line[0] == '.')
X+ 				    break;
X+ 				else {
X+ 				    t = index(ser_line, ' ');
X+ 				    if (t++) {
X+ 					strcpy(s, t);
X+ 					if (t = index(s, '\r'))
X+ 						*t = '\0';
X+ 				    }
X+ 				}
X+ 			    }
X+ 			}
X+ 		} else {
X+ 		    fprintf(stderr,
X+ 			"rrn: Unexpected close of server socket.\n");
X+ 		    finalize(1);
X+ 		}
X+ 	    }
X+ 
X+ 	    if (!xhdr) {
X+ 		sprintf(ser_line, "HEAD %ld", artnum);
X+ 		put_server(ser_line);
X+ 		eoo = 0;
X+ 		if (get_server(ser_line, 256) >= 0 && ser_line[0] == CHAR_OK) {
X+ 		    do {
X+ 			if (get_server(s, 256) < 0 || (*s == '.')) {
X+ 			strcpy(s, "Title: \n");
X+ 			eoo = 1;
X+ 		        }
X+ 		    } while (strnNE(s,"Title:",6) && strnNE(s,"Subject:",8));
X+ 
X+ 		    if (!eoo)
X+ 			while (get_server(ser_line, sizeof (ser_line)) >= 0 &&
X+ 				ser_line[0] != '.');
X+ 		    t = index(s,':')+1;
X+ 		    while (*t == ' ') t++;
X+ 		    strcpy(s, t);
X+ 	        }
X+ 	    }
X+ #else not SERVER
X  	    if (artopen(artnum) != Nullfp) {
X  		do {
X  		    if (fgets(s,256,artfp) == Nullch)
X***************
X*** 213,218
X  		    if (fgets(s,256,artfp) == Nullch)
X  			strcpy(s, "Title: \n");
X  		} while (strnNE(s,"Title:",6) && strnNE(s,"Subject:",8));
X  		s[strlen(s)-1] = '\0';
X  		t = index(s,':')+1;
X  		while (*t == ' ') t++;
X
X--- 268,274 -----
X  		    if (fgets(s,256,artfp) == Nullch)
X  			strcpy(s, "Title: \n");
X  		} while (strnNE(s,"Title:",6) && strnNE(s,"Subject:",8));
X+ 
X  		s[strlen(s)-1] = '\0';
X  		t = index(s,':')+1;
X  		while (*t == ' ') t++;
X***************
X*** 218,223
X  		while (*t == ' ') t++;
X  		strcpy(s, t);
X  	    }
X  	    s = saferealloc(s, (MEM_SIZE)strlen(s)+1);
X  #ifdef CACHESUBJ
X  	    subj_list[OFFSET(artnum)] = s;
X
X--- 274,280 -----
X  		while (*t == ' ') t++;
X  		strcpy(s, t);
X  	    }
X+ #endif
X  	    s = saferealloc(s, (MEM_SIZE)strlen(s)+1);
X  #ifdef CACHESUBJ
X  	    subj_list[OFFSET(artnum)] = s;
END_OF_FILE
if test 3320 -ne `wc -c <'./rrnpatches/head.c.pat'`; then
    echo shar: \"'./rrnpatches/head.c.pat'\" unpacked with wrong size!
fi
# end of './rrnpatches/head.c.pat'
fi
if test -f './server/README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./server/README'\"
else
echo shar: Extracting \"'./server/README'\" \(2963 characters\)
sed "s/^X//" >'./server/README' <<'END_OF_FILE'
X     Caveat: Before compiling anything here, go look at README and conf.h
in the "common" directory.  Fix conf.h up, and then come back here.
X
X     Back already?  Ok.  Now following the bouncing numbers:
X
X	1. Create the access file with the proper entries.
X	   This file goes wherever you said ACCESS_FILE
X	   was supposed to be in common/conf.h.  It's format is
X	   explained in the manual entry for nntpd.8c.
X	   A sample access file is in ../support/access_file.
X	   If you don't care who (ab)uses your news server,
X	   you can have the line "default read post" in your access
X	   file, which will allow anyone on the network to
X	   read and post news via your server.  See the manual
X	   page for a better explanation.
X
Parts two and three are necessary if you're running with TCP:
X
X	2. Make an entry for "nntp" in /etc/services.  Should
X	   be port number 119, tcp.  I.e., should look something like:
X
nntp		119/tcp		readnews	# Network News Transfer Protocol
X
X	   Sun users running yp should yppush this file to make sure all
X	   the clients get it.
X
X	3. Check ../common/conf.h to make sure you're set to do what
X	   you want to do with inetd (i.e., #define ALONE or #undef ALONE).
X	   If you are using inetd,
X
X	   a. Add a line to /etc/inetd.conf, or whatever your
X	      configuration file is, to reflect the presence
X	      of the news server.  On 4.3 BSD machines this should
X	      look like:
X
nntp	stream	tcp	nowait	root	/etc/nntpd	nntpd
X
X	      while under Ultrix or 4.2 BSD machines:
X
nntp	stream	tcp	nowait	/etc/nntpd	nntpd
X
X	      On a Sun, the file is /etc/servers; the line looks like:
X
nntp	tcp	/usr/etc/in.nntpd
X
X	      Be sure to yppush your /etc/servers file if you run
X	      yellow pages.
X
X	      Don't forget to kill -HUP your inetd.
X
X	   If you're NOT using inetd,
X
X	   a. Edit ../common/conf.h to have the line
X
X			#define ALONE
X
X	      to compile in code for the stand alone server.
X
X	   b. You may as well also define "FASTFORK" in
X	      ../common/conf.h.  This causes the server not to
X	      read in the active file every time it forks, but
X	      rather to stat it every READINTVL seconds, and if
X	      the file has changed since the last read, to
X	      read it in again.  This makes the children run
X	      faster, since they don't have to read the active
X	      file every time the parent forks off a child, but
X	      the parent server will eat more cpu, doing
X	      stat()s every 10 minutes or so.  If your server machine
X	      is heavily loaded, you might leave this out.
X
X	   c. Change /etc/rc.local to start the server at
X	      boot time.
X
Else, if you're using decnet:
X
X	2. && 3. Define the NNTP object with ncp:
X
ncp define object NNTP number 0 file /etc/nntpd
ncp define object NNTP default user guest type stream
X
ncp set object NNTP all			# just once for the running system
X
X	4. Compile the server by doing "make".
X
X	5. Cd .. and continue with the rest of the stuff; you'll
X	   wind up doing a make install later.
END_OF_FILE
if test 2963 -ne `wc -c <'./server/README'`; then
    echo shar: \"'./server/README'\" unpacked with wrong size!
fi
# end of './server/README'
fi
if test -f './server/access.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./server/access.c'\"
else
echo shar: Extracting \"'./server/access.c'\" \(4680 characters\)
sed "s/^X//" >'./server/access.c' <<'END_OF_FILE'
X#ifndef lint
static char	*sccsid = "@(#)access.c	1.19	(Berkeley) 2/6/88";
X#endif
X
X#include "common.h"
X#ifdef EXCELAN
X#include <netinet/in.h>
X#endif
X#include <sys/socket.h>
X
X#define	SNETMATCH	1
X#define	NETMATCH	2
X
X/*
X * host_access -- determine if the client has permission to
X * read, transfer, and/or post news.  read->transfer.
X * We switch on socket family so as to isolate network dependent code.
X *
X *	Parameters:	"canread" is a pointer to storage for
X *			an integer, which we set to 1 if the
X *			client can read news, 0 otherwise.
X *
X *			"canpost" is a pointer to storage for
X *			an integer,which we set to 1 if the
X *			client can post news, 0 otherwise.
X *
X *			"canxfer" is a pointer to storage for
X *			an integer,which we set to 1 if the
X *			client can transfer news, 0 otherwise.
X *
X *			"gdlist" is a comma separated list of
X *			newsgroups/distributions which the client
X *			can access.
X *
X *	Returns:	Nothing.
X *
X *	Side effects:	None.
X */
X
X#ifdef EXCELAN
extern struct sockaddr_in current_peer;
X#endif
X
X#ifdef LOG
char	hostname[256];
X#endif
X
host_access(canread, canpost, canxfer, gdlist)
X	int		*canread, *canpost, *canxfer;
X	char		*gdlist;
X{
X	int		sockt;
X	int		length;
X	struct sockaddr	sa;
X	int		match;
X	int		count;
X	char		hostornet[MAXHOSTNAMELEN];
X	char		host_name[MAXHOSTNAMELEN];
X	char		net_name[MAXHOSTNAMELEN];
X	char		snet_name[MAXHOSTNAMELEN];
X	char		readperm[MAXBUFLEN];
X	char		postperm[MAXBUFLEN];
X	char		groups[MAXBUFLEN];
X	char		line[MAXBUFLEN];
X	register char	*cp;
X	register FILE	*acs_fp;
X
X	gdlist[0] = '\0';
X
X#ifdef DEBUG
X	*canread = *canpost = *canxfer = 1;
X	return;
X#endif
X
X	*canread = *canpost = *canxfer = 0;
X
X	sockt = fileno(stdin);
X	length = sizeof (sa);
X
X#ifdef EXCELAN
X	if (raddr(current_peer.sin_addr) == NULL) {
X#else
X	if (getpeername(sockt, &sa, &length) < 0) {
X#endif
X		if (isatty(sockt)) {
X#ifdef LOG
X			(void) strcpy(hostname, "stdin");
X#endif
X			*canread = 1;
X		} else {
X#ifdef SYSLOG
X			syslog(LOG_ERR, "host_access: getpeername: %m");
X#endif
X#ifdef LOG
X			(void) strcpy(hostname, "unknown");
X#endif
X		}
X		return;
X	}
X#ifdef EXCELAN
X	else bcopy(&current_peer,&sa,length);
X#endif
X
X	switch (sa.sa_family) {
X	case AF_INET:
X		inet_netnames(sockt, &sa, net_name, snet_name, host_name);
X		break;
X
X#ifdef DECNET
X	case AF_DECnet:
X		dnet_netnames(sockt, &sa, net_name, snet_name, host_name);
X		break;
X#endif
X
X	default:
X#ifdef SYSLOG
X		syslog(LOG_ERR, "unknown address family %ld", sa.sa_family);
X#endif
X		return;
X	};
X
X	/* Normalize host name to lower case */
X
X	for (cp = host_name; *cp; cp++)
X		if (isupper(*cp))
X			*cp = tolower(*cp);
X
X#ifdef LOG
X	syslog(LOG_INFO, "%s connect\n", host_name);
X	(void) strcpy(hostname, host_name);
X#endif
X
X	/*
X	 * We now we have host_name, snet_name, and net_name.
X	 * Our strategy at this point is:
X	 *
X	 * for each line, get the first word
X	 *
X	 *	If it matches "host_name", we have a direct
X	 *		match; parse and return.
X	 *
X	 *	If it matches "snet_name", we have a subnet match;
X	 *		parse and set flags.
X	 *
X	 *	If it matches "net_name", we have a net match;
X	 *		parse and set flags.
X	 *
X	 *	If it matches the literal "default", note we have
X	 *		a net match; parse.
X	 */
X
X	acs_fp = fopen(accessfile, "r");
X	if (acs_fp == NULL) {
X#ifdef SYSLOG
X		syslog(LOG_ERR, "access: fopen %s: %m", accessfile);
X#endif
X		return;
X	}
X
X	while (fgets(line, sizeof(line), acs_fp) != NULL) {
X		if ((cp = index(line, '\n')) != NULL)
X			*cp = '\0';
X		if ((cp = index(line, '#')) != NULL)
X			*cp = '\0';
X		if (*line == '\0')
X			continue;
X
X		count = sscanf(line, "%s %s %s %s",
X				hostornet, readperm, postperm, groups);
X
X		if (count < 4) {
X			if (count < 3)
X				continue;
X			groups[0] = '\0';	/* No groups specified */
X		}
X
X		if (!strcasecmp(hostornet, host_name)) {
X			*canread = (readperm[0] == 'r' || readperm[0] == 'R');
X			*canxfer = (*canread || readperm[0] == 'X'
X					     || readperm[0] == 'x');
X			*canpost = (postperm[0] == 'p' || postperm[0] == 'P');
X			(void) strcpy(gdlist, groups);
X			break;
X		}
X
X		if (*snet_name && !strcasecmp(hostornet, snet_name)) {
X			match = SNETMATCH;
X			*canread = (readperm[0] == 'r' || readperm[0] == 'R');
X			*canxfer = (*canread || readperm[0] == 'X'
X					     || readperm[0] == 'x');
X			*canpost = (postperm[0] == 'p' || postperm[0] == 'P');
X			(void) strcpy(gdlist, groups);
X		}
X
X		if (match != SNETMATCH && (!strcasecmp(hostornet, net_name) ||
X		    !strcasecmp(hostornet, "default"))) {
X			match = NETMATCH;
X			*canread = (readperm[0] == 'r' || readperm[0] == 'R');
X			*canxfer = (*canread || readperm[0] == 'X'
X					     || readperm[0] == 'x');
X			*canpost = (postperm[0] == 'p' || postperm[0] == 'P');
X			(void) strcpy(gdlist, groups);
X		}
X	}
X
X	(void) fclose(acs_fp);
X}
END_OF_FILE
if test 4680 -ne `wc -c <'./server/access.c'`; then
    echo shar: \"'./server/access.c'\" unpacked with wrong size!
fi
# end of './server/access.c'
fi
if test -f './server/access_inet.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./server/access_inet.c'\"
else
echo shar: Extracting \"'./server/access_inet.c'\" \(3098 characters\)
sed "s/^X//" >'./server/access_inet.c' <<'END_OF_FILE'
X#ifndef lint
static char	*sccsid = "@(#)access_inet.c	1.4	(Berkeley) 1/9/88";
X#endif
X
X#include "common.h"
X
X#include <stdio.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#ifndef EXCELAN
X#include <netdb.h>
X#include <arpa/inet.h>
X#endif
X
X/*
X * inet_netnames -- return the network, subnet, and host names of
X * our peer process for the Internet domain.
X *
X *	Parameters:	"sock" is our socket, which we don't need.
X *			"sin" is a pointer to the result of
X *			a getpeername() call.
X *			"net_name", "subnet_name", and "host_name"
X *			are filled in by this routine with the
X *			corresponding ASCII names of our peer.
X *	Returns:	Nothing.
X *	Side effects:	None.
X */
X
inet_netnames(sock, sin, net_name, subnet_name, host_name)
X	int			sock;
X	struct sockaddr_in	*sin;
X	char			*net_name;
X	char			*subnet_name;
X	char			*host_name;
X{
X#ifdef EXCELAN
X	excelan_netnames(sock, sin, net_name, subnet_name, host_name);
X#else
X	static int		gotsubnetconf;
X	u_long			net_addr;
X	u_long			subnet_addr;
X	struct hostent		*hp;
X	struct netent		*np;
X
X#ifdef SUBNET
X	if (!gotsubnetconf) {
X		if (getifconf() < 0) {
X#ifdef SYSLOG
X			syslog(LOG_ERR, "host_access: getifconf: %m");
X#endif
X			return;
X		}
X		gotsubnetconf = 1;
X	}
X#endif
X
X	net_addr = inet_netof(sin->sin_addr);	/* net_addr in host order */
X	np = getnetbyaddr(net_addr, AF_INET);
X	if (np != NULL)
X		(void) strcpy(net_name, np->n_name);
X	else
X		(void) strcpy(net_name,inet_ntoa(*(struct in_addr *)&net_addr));
X
X#ifdef SUBNET
X	subnet_addr = inet_snetof(sin->sin_addr.s_addr);
X	if (subnet_addr == 0)
X		subnet_name[0] = '\0';
X	else {
X		np = getnetbyaddr(subnet_addr, AF_INET);
X		if (np != NULL)
X			(void) strcpy(subnet_name, np->n_name);
X		else
X			(void) strcpy(subnet_name,
X			    inet_ntoa(*(struct in_addr *)&subnet_addr));
X	}
X#else
X	subnet_name[0] = '\0';
X#endif SUBNET
X
X	hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
X		sizeof (sin->sin_addr.s_addr), AF_INET);
X	if (hp != NULL)
X		(void) strcpy(host_name, hp->h_name);
X	else
X		(void) strcpy(host_name, inet_ntoa(sin->sin_addr));
X#endif
X}
X
X
X#ifdef EXCELAN
excelan_netnames(sock, sin, net_name, subnet_name, host_name)
X	int			sock;
X	struct sockaddr_in	*sin;
X	char			*net_name;
X	char			*subnet_name;
X	char			*host_name;
X{
X	char *hp, *raddr();
X	int octet[4];
X
X	/* assumes sizeof addr is long */
X	octet[0] = (sin->sin_addr.s_addr>>24)&0xff;
X	octet[1] = (sin->sin_addr.s_addr>>16)&0xff;
X	octet[2] = (sin->sin_addr.s_addr>>8 )&0xff;
X	octet[3] = (sin->sin_addr.s_addr    )&0xff;
X
X	hp = raddr(sin->sin_addr.s_addr);
X	if (hp != NULL)
X		(void) strcpy(host_name,hp);
X	else
X
X		(void) sprintf(host_name,"%d.%d.%d.%d",
X			octet[0],octet[1],octet[2],octet[3]);	
X	/* No inet* routines here, so we fake it. */
X	if (octet[0] < 128)		/* CLASS A address */
X		(void) sprintf(net_name,"%d",octet[0]);
X	else if(octet[0] < 192)		/* CLASS B address */
X			(void) sprintf(net_name,"%d.%d",
X						octet[0],octet[1]);
X		else 			/* CLASS C address */
X			(void) sprintf(net_name,"%d.%d.%d",
X					octet[0],octet[1],octet[2]);
X
X/* hack to cover the subnet stuff */
X	(void) sprintf(subnet_name,"%d.%d.%d",octet[0],octet[1],octet[2]);
X}
X#endif
END_OF_FILE
if test 3098 -ne `wc -c <'./server/access_inet.c'`; then
    echo shar: \"'./server/access_inet.c'\" unpacked with wrong size!
fi
# end of './server/access_inet.c'
fi
if test -f './server/active.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./server/active.c'\"
else
echo shar: Extracting \"'./server/active.c'\" \(3476 characters\)
sed "s/^X//" >'./server/active.c' <<'END_OF_FILE'
X#ifndef lint
static char	*sccsid = "@(#)active.c	1.12	(Berkeley) 1/11/88";
X#endif
X
X#include "common.h"
X
X/*
X * Routines to deal with the active file
X */
X
int	act_cmp();
X
X/*
X * read_groups -- read the active file into memory, sort it,
X *	and return the number of newsgroups read in.
X *	If FASTFORK is true, this can be called by interrupt,
X *	and may have to free up the old storage.  We decide
X *	this by the fact that "num_groups" will be non-zero if
X *	we're here on an interrupt.
X *
X *	Parameters:	None.
X *
X *	Returns:	Number of newsgroups read into
X *			memory.
X *			Zero on error.
X *
X *	Side effects:	Reads newsgroups into "group_array"
X *			and sorts them.
X */
X
read_groups()
X{
X	register int	i;
X	register int	act_fd;
X	register char	*actbuf, *cp, *end;
X	char		*malloc();
X	struct stat	statbuf;
X
X	/*
X	 * If we're here on an interrupt, free up all the
X	 * previous groups.
X	 */
X
X	if (num_groups != 0) {
X		(void) free(group_array[0]);	/* Assume [0] -> actbuf */
X		(void) free(group_array);
X	}
X
X	act_fd = open(activefile, O_RDONLY);
X	if (act_fd < 0) {
X#ifdef SYSLOG
X		syslog(LOG_ERR, "read_groups: open %s: %m", activefile);
X#endif
X		return (0);
X	}
X
X	if (fstat(act_fd, &statbuf) < 0) {
X#ifdef SYSLOG
X		syslog(LOG_ERR, "read_groups: fstat: %m");
X#endif
X		(void) close(act_fd);
X		return (0);
X	}
X
X	actbuf = malloc(statbuf.st_size);
X	if (actbuf == NULL) {
X#ifdef SYSLOG
X		syslog(LOG_ERR, "read_groups: malloc %d bytes: %m",
X			statbuf.st_size);
X#endif
X		(void) close(act_fd);
X		return (0);
X	}
X
X	if (read(act_fd, actbuf, (int)statbuf.st_size) != statbuf.st_size) {
X#ifdef SYSLOG
X		syslog(LOG_ERR, "read_groups: read %d bytes: %m",
X			statbuf.st_size);
X#endif
X		(void) close(act_fd);
X		return (0);
X	}
X
X	(void) close(act_fd);
X
X	for (i = 0, cp = actbuf, end = actbuf + statbuf.st_size; cp < end; cp++)
X		if (*cp == '\n')
X			i++;
X
X	group_array = (char **) malloc(i * (sizeof (char *)));
X	if (group_array == NULL) {
X#ifdef SYSLOG
X		syslog(LOG_ERR, "read_groups: malloc %d bytes: %m",
X			i * sizeof (char **));
X#endif
X		(void) close(act_fd);
X		return (0);
X	}
X
X	cp = actbuf;
X	i = 0;
X	while (cp < end) {
X		group_array[i++] = cp;
X		cp = index(cp, '\n');
X		if (cp == NULL)
X			break;
X		*cp = '\0';
X		cp++;
X	}
X
X	qsort((char *) group_array, i, sizeof (char *), act_cmp);
X
X	return (i);
X}
X
X
act_cmp(ptr1, ptr2)
X	char	 **ptr1, **ptr2;
X{
X	return(strcmp(*ptr1, *ptr2));
X}
X
X
X/*
X * find_group -- find a given newsgroup and return
X *	the low and high message numbers in the group
X *	(space provided by user).
X *
X *	Parameters:	"group" is the name of the group
X *			we're searching for.
X *			"num_groups" is the total number
X *			of groups in the group array.
X *			"low_msg" and "high_msg" are
X *			pointers to where we're supposed
X *			to put the low and high message numbers.
X *
X *	Returns:	0 if all goes well,
X *			-1 if we can't find the group.
X *
X *	Side effects:	None.
X */
X
find_group(group, num_groups, low_msg, high_msg)
X	char		*group;
X	int		num_groups;
X	int		*low_msg, *high_msg;
X{
X	char		kludgebuf[MAXBUFLEN];
X	int		cond;
X	register int	low, high, mid;
X	int		length;
X
X	low = 0;
X	high = num_groups-1;
X	(void) strcpy(kludgebuf, group);
X	(void) strcat(kludgebuf, " ");
X	length = strlen(kludgebuf);
X
X	while (low <= high) {
X		mid = (low + high) / 2;
X		if ((cond = strncmp(kludgebuf, group_array[mid], length)) < 0)
X			high = mid - 1;
X		else if (cond > 0)
X			low = mid + 1;
X		else {
X			(void) sscanf(group_array[mid], "%s %d %d",
X				kludgebuf, high_msg, low_msg);
X			return(0);
X		}
X	}
X	return(-1);
X}
END_OF_FILE
if test 3476 -ne `wc -c <'./server/active.c'`; then
    echo shar: \"'./server/active.c'\" unpacked with wrong size!
fi
# end of './server/active.c'
fi
if test -f './server/strcasecmp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./server/strcasecmp.c'\"
else
echo shar: Extracting \"'./server/strcasecmp.c'\" \(3456 characters\)
sed "s/^X//" >'./server/strcasecmp.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific written prior permission. This software
X * is provided ``as is'' without express or implied warranty.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strcasecmp.c	5.5 (Berkeley) 11/24/87";
X#endif /* LIBC_SCCS and not lint */
X
X#include <sys/types.h>
X
X/*
X * This array is designed for mapping upper and lower case letter
X * together for a case independent comparison.  The mappings are
X * based upon ascii character sequences.
X */
static u_char charmap[] = {
X	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
X	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
X	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
X	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
X	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
X	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
X	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
X	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
X	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
X	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
X	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
X	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
X	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
X	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
X	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
X	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
X	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
X	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
X	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
X	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
X	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
X	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
X	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
X	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
X	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
X	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
X	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
X	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
X	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
X	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
X	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
X	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
X};
X
strcasecmp(s1, s2)
X	char *s1, *s2;
X{
X	register u_char	*cm = charmap,
X			*us1 = (u_char *)s1,
X			*us2 = (u_char *)s2;
X
X	while (cm[*us1] == cm[*us2++])
X		if (*us1++ == '\0')
X			return(0);
X	return(cm[*us1] - cm[*--us2]);
X}
X
strncasecmp(s1, s2, n)
X	char *s1, *s2;
X	register int n;
X{
X	register u_char	*cm = charmap,
X			*us1 = (u_char *)s1,
X			*us2 = (u_char *)s2;
X
X	while (--n >= 0 && cm[*us1] == cm[*us2++])
X		if (*us1++ == '\0')
X			return(0);
X	return(n < 0 ? 0 : cm[*us1] - cm[*--us2]);
X}
END_OF_FILE
if test 3456 -ne `wc -c <'./server/strcasecmp.c'`; then
    echo shar: \"'./server/strcasecmp.c'\" unpacked with wrong size!
fi
# end of './server/strcasecmp.c'
fi
if test -f './server/time.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./server/time.c'\"
else
echo shar: Extracting \"'./server/time.c'\" \(4156 characters\)
sed "s/^X//" >'./server/time.c' <<'END_OF_FILE'
X#ifndef lint
static char	*sccsid = "@(#)time.c	1.9	(Berkeley) 2/6/88";
X#endif
X
X/*
X * Collection of routines for dealing with ASCII time strings.
X * These may actually be useful in their own right.
X */
X
X#include "../common/conf.h"
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <ctype.h>
X#ifdef USG
X#include <time.h>
X#else not USG
X#include <strings.h>
X#include <sys/time.h>
X#endif not USG
X
X/*
X * dtol -- convert date to long integer.  This is not implicitly
X * local time, or any other kind of time, for that matter.  If you
X * pass it a date you think is GMT, you wind up with that number of
X * seconds...
X *
X *	Parameters:		"date_ascii" is in the form "yymmddhhmmss".
X *
X *	Returns:		Long integer containing number
X *				of seconds since 000000 Jan 1, 1970,
X *				and "date".  -1 on error.
X *
X *	Side effects:		None.
X */
X
X#define twodigtoi(x)	(((x[0]) - '0') + (x[1] - '0')*10)
X#define	dysize(y)	((y % 4 ? 365 : 366))
X
static	int	dmsize[12] =
X    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
X
long
dtol(date_ascii)
X	char	*date_ascii;
X{
X	char	date[32], *date_str;
X	char	*lhs, *rhs;
X	char	temp;
X	long	seconds;
X	int	year, month, day, hour, mins, secs;
X	int	len, i;
X
X	len = strlen(date_ascii);
X	if (len != sizeof("yymmddhhmmss")-1)
X		return (-1);
X
X	(void) strcpy(date, date_ascii);
X	date_str = date;
X
X#ifdef debug
X	printf("date_str = %s\n", date_str);
X#endif
X	rhs = date_str + len - 1;
X	lhs = date_str;
X
X	for (; lhs < rhs; ++lhs, --rhs) {
X		temp = *lhs;
X		*lhs = *rhs;
X		*rhs = temp;
X		if (!isdigit(temp) || !isdigit(*lhs))
X			return (-1);
X	}
X
X	lhs = date_str;
X#ifdef debug
X	printf("date_str = %s\n", date_str);
X#endif
X
X	secs = twodigtoi(lhs);
X	lhs += 2;
X	mins = twodigtoi(lhs);
X	lhs += 2;
X	hour = twodigtoi(lhs);
X	lhs += 2;
X	day = twodigtoi(lhs);
X	lhs += 2;
X	month = twodigtoi(lhs);
X	lhs += 2;
X	year = twodigtoi(lhs);
X
X	if (month < 1 || month > 12 ||
X	    day < 1 || day > 31 ||
X	    mins < 0 || mins > 59 ||
X	    secs < 0 || secs > 59)
X		return (-1);
X	if (hour == 24) {
X		hour = 0;
X		day++;
X	}
X	if (hour < 0 || hour > 23)
X		return (-1);
X	seconds = 0;
X	year += 1900;
X	for (i = 1970; i < year; i++)
X		seconds += dysize(i);
X	/* Leap year */
X	if (dysize(year) == 366 && month >= 3)
X		seconds++;
X	while (--month)
X		seconds += dmsize[month-1];
X	seconds += day-1;
X	seconds = 24 * seconds + hour;
X	seconds = 60 * seconds + mins;
X	seconds = 60 * seconds + secs;
X
X	return (seconds);
X}
X
X
X/*
X * ltod -- convert long integer to date string.
X *
X *	Parameters:		"date" is in the number of seconds
X *				since the epoch.
X *
X *	Returns:		Pointer to static data in the form
X *				yymmddhhmmss\0.
X *
X *	Side effects:		None.
X */
X
char *
ltod(date)
X	long		date;
X{
X	static char	timebuf[32];
X	struct tm	*tp;
X
X	tp = gmtime(&date);
X
X	(void) sprintf(timebuf, "%02d%02d%02d%02d%02d%02d",
X		tp->tm_year,
X		tp->tm_mon + 1,		/* 0 to 11??? How silly. */
X		tp->tm_mday,
X		tp->tm_hour,
X		tp->tm_min,
X		tp->tm_sec);
X
X	return (timebuf);
X}
X
X
X/*
X * local_to_gmt -- convert a local time (in form of number of
X * seconds since you-know-when) to GMT.
X *
X *	Parameters:	"date" is date we want converted, in
X *			seconds since 000000 1 Jan 1970.
X *
X *	Returns:	Number of seconds corrected for local
X *			and dst.
X */
X
long
local_to_gmt(date)
X	long	date;
X{
X#ifdef USG
X	extern	int	timezone;
X	tzset();
X	date += timezone;
X#else not USG
X	struct	timeval	tv;
X	struct	timezone tz;
X
X	(void) gettimeofday(&tv, &tz);
X	date += (long) tz.tz_minuteswest * 60;
X#endif not USG
X
X	/* now fix up local daylight time */
X	if (localtime((time_t *)&date)->tm_isdst)
X		date -= 60*60;
X
X	return (date);
X}
X
X/*
X * gmt_to_local -- take a GMT time expressed in seconds since
X * the epoch, and convert it to local time.
X *
X *	Parameters:	"date" is the number of seconds...
X *
X *	Returns:	Number of seconds corrected to reflect
X *			local time and dst.
X */
X
long
gmt_to_local(date)
X	long	date;
X{
X#ifdef USG
X	extern	int	timezone;
X	tzset();
X	date -= timezone;
X#else not USG
X	struct	timeval	tv;
X	struct	timezone tz;
X
X	(void) gettimeofday(&tv, &tz);
X	date -= (long) tz.tz_minuteswest * 60;
X#endif not USG
X
X	/* now fix up local daylight time */
X	if (localtime((time_t *)&date)->tm_isdst)
X		date += 60*60;
X
X	return (date);
X}
END_OF_FILE
if test 4156 -ne `wc -c <'./server/time.c'`; then
    echo shar: \"'./server/time.c'\" unpacked with wrong size!
fi
# end of './server/time.c'
fi
if test -f './server/xhdr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./server/xhdr.c'\"
else
echo shar: Extracting \"'./server/xhdr.c'\" \(3457 characters\)
sed "s/^X//" >'./server/xhdr.c' <<'END_OF_FILE'
X#ifndef lint
static char	*sccsid = "@(#)xhdr.c	1.6	(Berkeley) 2/25/88";
X#endif
X
X#include "common.h"
X
X#ifdef XHDR
X
X/*
X * XHDR header [<messageid>|articlerange]
X *
X * header is a case-insensitive header field, minus any colons.
X *
X * articlerange is one of:
X *	an article number
X *	an article number followed by a dash to indicate all following
X *	an article number followed by a dash followed by another
X *		article number.
X * e.g.,
X * XHDR subject			retrieve subject of current article
X * XHDR subject 5589-6325	retrieve subject of arts 5589 to 6325
X * XHDR subject 5589-		retrieve subject of arts 5589 and up
X * XHDR subject 5589		retrieve subject of art 5589 only
X * XHDR subject <123@ucbvax>	retrieve subject of art <123@ucbvax>
X *
X * This command is an extention, and not included in RFC 977.
X */
X
xhdr(argc, argv)
X	int		argc;
X	char		*argv[];
X{
X	char		buf[MAXPATHLEN];
X	register int	artptr;
X	register int	artnum;
X	register int	low, high;
X	register FILE	*fp;
X	register char	*cp;
X
X	if (argc < 2 || argc > 3) {
X		printf("%d Usage: XHDR headerfield [artrange|<message-id>]\r\n",
X			ERR_CMDSYN);
X		(void) fflush(stdout);
X		return;
X	}
X
X	if (!canread) {
X		printf("%d You only have permission to transfer, sorry.\r\n",
X			ERR_ACCESS);
X		(void) fflush(stdout);
X		return;
X	}
X
X	/* Handle message-id requests */
X
X	if (argc == 3 && *argv[2] == '<') {	/* Message ID */
X		fp = openartbyid(argv[2]);
X		if (fp == NULL) {
X			printf("%d No article by message-id %s, sorry.\r\n",
X				ERR_NOART, argv[2]);
X			(void) fflush(stdout);
X			return;
X		}
X		printf("%d 0 %s header of article %s.\r\n",
X			OK_HEAD, argv[1], argv[2]);
X		print_header(fp, argv[1], argv[2]);
X		(void) fclose(fp);
X
X		putchar('.');
X		putchar('\r');
X		putchar('\n');
X		(void) fflush(stdout);
X		return;
X	}
X
X	/*
X	 * It must be a range of articles, which means that we need
X	 * to be in a newsgroup already.
X	 */
X
X	if (!ingroup) {
X		printf("%d You are not currently in a newsgroup.\r\n",
X			ERR_NCING);
X		(void) fflush(stdout);
X		return;
X	}
X
X	artptr = 0;
X
X	if (argc == 2) {
X		if (art_ptr < 0 || art_ptr >= num_arts) {
X			printf("%d No article is currently selected.\r\n",
X				ERR_NOCRNT);
X			(void) fflush(stdout);
X			return;
X		}
X		high = low = art_array[art_ptr];
X		artptr = art_ptr;
X	} else {
X		cp = index(argv[2], '-');
X		if (cp == NULL)
X			low = high = atoi(argv[2]);
X		else {
X			*cp = '\0';
X			low = atoi(argv[2]);
X			cp++;
X			high = atoi(cp);
X			if (high < low)
X				high = art_array[num_arts-1];
X		}
X	}
X
X	printf("%d %s fields follow\r\n", OK_HEAD, argv[1]);
X
X	for (;; artptr++) {
X		if ((artnum = art_array[artptr]) < low)
X			continue;
X		if (artnum > high)
X			break;
X
X		(void) sprintf(buf, "%d", artnum);
X		fp = fopen(buf, "r");
X		if (fp == NULL)
X			continue;
X		print_header(fp, argv[1], buf);
X		(void) fclose(fp);
X	}
X
X	putchar('.');
X	putchar('\r');
X	putchar('\n');
X	(void) fflush(stdout);
X}
X
X
print_header(fp, header, artname)
X	register FILE	*fp;
X	register char	*header;
X	register char	*artname;
X{
X	char		line[NNTP_STRLEN];
X	register char	*cp, *cp1;
X
X	while (fgets(line, sizeof (line), fp) != NULL) {
X		if (*line == '\n' || *line == '\0') {
X			printf("%s (none)\r\n", artname);
X			return;
X		}
X		if (cp = index(line, ':')) {
X			*cp = '\0';
X			if (!strcasecmp(header, line)) {
X				if (cp1 = index(cp + 2, '\n'))
X					*cp1 = '\0';
X				printf("%s %s\r\n", artname, cp + 2);
X				return;
X			}
X		}
X	}
X}
X
X#else not XHDR
X
X/* Kludge to get around Greenhills C compiler */
X
xhdr_greenkluydge()
X{
X}
X
X#endif not XHDR
END_OF_FILE
if test 3457 -ne `wc -c <'./server/xhdr.c'`; then
    echo shar: \"'./server/xhdr.c'\" unpacked with wrong size!
fi
# end of './server/xhdr.c'
fi
if test -f './support/mkgrdates.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./support/mkgrdates.c'\"
else
echo shar: Extracting \"'./support/mkgrdates.c'\" \(3755 characters\)
sed "s/^X//" >'./support/mkgrdates.c' <<'END_OF_FILE'
X#ifndef lint
static char	*sccsid = "@(#)mkgrdates.c	1.4	(Berkeley) 2/6/88";
X#endif
X
X/*
X * Make a list of newsgroups which are "new" in the file NGDATE_FILE.
X * "New" means having an entry in the active file, and having
X * a message numbered "1" in the appropriate news directory.
X * Since this involves a stat of all the newsgroups, we try
X * to be intelligent about things -- if the active file's size
X * since we last ran -- stored in STAT_FILE -- hasn't changed
X * since last time, we assume things are ok, and exit without
X * doing anything.  This could fail in extreme circumstances,
X * but is "too painful to do right".
X *
X * Output in NGDATE_FILE is of the form
X *
X *	date newsgroup
X *
X * where "date" is the date the newsgroup was created, expressed as
X * the number of seconds since 000000 Jan 1, 1970, GMT.  This file
X * winds up sorted in cronological order.
X *
X *	Phil Lapsley
X *	College of Engineering
X *	University of California, Berkeley
X *	(ARPA: phil@Berkeley.ARPA; UUCP: ...!ucbvax!phil)
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "../common/conf.h"
X#ifdef USG
X#include <time.h>
X#else not USG
X#include <sys/time.h>
X#endif not USG
X
X#define MODE		0644	/* Better be readable by nntpd! */
X
X#ifndef MAXPATHLEN
X#define	MAXPATHLEN	1024
X#endif
X
X#ifndef MAXGROUPLEN
X#define	MAXGROUPLEN	256
X#endif
X
extern	int	linecmp();
extern	char	*index(), *malloc(), *strcpy(), *strcat();
X
main(argc, argv)
int	argc;
char	*argv[];
X{
X	char	*groups[1024];		/* XXX 1024 groups max */
X	char	line[MAXPATHLEN], gr_name[MAXGROUPLEN];
X	char	*cp;
X	int	i, j;
X	long	lastsize, crntsize;
X	long	birthtime;
X	struct tm *tmptr;
X	FILE	*stat_fp, *active_fp, *date_fp;
X	long	birthof();
X
X	stat_fp = fopen(STAT_FILE, "r");
X
X	if (stat_fp != NULL) {
X		(void) fscanf(stat_fp, "%d", &lastsize);
X		(void) fclose(stat_fp);
X	}
X
X	active_fp = fopen(ACTIVE_FILE, "r");
X	if (active_fp == NULL) {
X		fprintf(stderr, "Can't read active file?\n");
X		perror(ACTIVE_FILE);
X		exit(1);
X	}
X
X	/* Check length; if it's the same as last time, quit */
X
X	(void) fseek(active_fp, (long) 0, 2);
X	crntsize = ftell(active_fp);
X	if (crntsize == lastsize) {
X		(void) fclose(active_fp);
X		exit(0);
X	}
X
X	/* Ok, time to rebuild the date file */
X
X	date_fp = fopen(NGDATE_FILE, "w");
X
X	if (date_fp == NULL) {
X		perror(NGDATE_FILE);
X		(void) fclose(active_fp);
X		exit(1);
X	}
X
X	rewind(active_fp);
X
X	i = 0;
X	while (fgets(line, sizeof(line), active_fp) != NULL) {
X		if ((cp = index(line, ' ')) != NULL)
X			*cp = '\0';
X		(void) strcpy(gr_name, line);
X		birthtime = birthof(line, atoi(cp + 1));
X		
X		if (birthtime == 0)	/* Skip ancient newsgroups */
X			continue;
X
X		(void) sprintf(line, "%ld %s", birthtime, gr_name);
X		groups[i] = malloc(strlen(line)+1);
X		if (groups[i] != NULL)
X			(void) strcpy(groups[i++], line);
X		else {
X			perror("malloc");
X			exit(1);
X		}
X	}
X
X	(void) fclose(active_fp);
X
X	qsort((char *) groups, i, sizeof(char *), linecmp);
X
X	for (j = 0; j < i; ++j)
X		fprintf(date_fp, "%s\n", groups[j]);
X
X	(void) fclose(date_fp);
X
X	(void) chmod(NGDATE_FILE, MODE);
X
X	stat_fp = fopen(STAT_FILE, "w");
X	if (stat_fp == NULL) {
X		perror(STAT_FILE);
X		exit(1);
X	}
X
X	fprintf(stat_fp, "%d\n", crntsize);
X
X	(void) fclose(stat_fp);
X
X	(void) chmod(STAT_FILE, MODE);
X
X	exit(0);
X}
X
linecmp(line1, line2)
char	 **line1, **line2;
X{
X	return(0 - strcmp(*line1, *line2));
X}
X
X
X/* return creation time of newsgroup */
X
long
birthof(group, highart)
char	*group;
int	highart;
X{
X	char	*cp, *index();
X	char	tst[128];
X	struct stat statbuf;
X 
X	while ((cp = index(group, '.')))
X		*cp = '/';
X
X	(void) strcpy(tst, SPOOLDIR);
X	(void) strcat(tst, group);
X	if (highart)
X		(void) strcat(tst, "/1");
X	if (stat(tst, &statbuf) < 0)
X		return 0L;		/* not there, assume ancient */
X	else
X		return(statbuf.st_mtime);
X}
END_OF_FILE
if test 3755 -ne `wc -c <'./support/mkgrdates.c'`; then
    echo shar: \"'./support/mkgrdates.c'\" unpacked with wrong size!
fi
# end of './support/mkgrdates.c'
fi
if test -f './xmit/sysexits.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./xmit/sysexits.h'\"
else
echo shar: Extracting \"'./xmit/sysexits.h'\" \(4212 characters\)
sed "s/^X//" >'./xmit/sysexits.h' <<'END_OF_FILE'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)sysexits.h	4.3 (Berkeley) 12/15/87
X */
X
X/*
X**  SYSEXITS.H -- Exit status codes for system programs.
X**
X**	This include file attempts to categorize possible error
X**	exit statuses for system programs, notably delivermail
X**	and the Berkeley network.
X**
X**	Error numbers begin at EX__BASE to reduce the possibility of
X**	clashing with other exit statuses that random programs may
X**	already return.  The meaning of the codes is approximately
X**	as follows:
X**
X**	EX_USAGE -- The command was used incorrectly, e.g., with
X**		the wrong number of arguments, a bad flag, a bad
X**		syntax in a parameter, or whatever.
X**	EX_DATAERR -- The input data was incorrect in some way.
X**		This should only be used for user's data & not
X**		system files.
X**	EX_NOINPUT -- An input file (not a system file) did not
X**		exist or was not readable.  This could also include
X**		errors like "No message" to a mailer (if it cared
X**		to catch it).
X**	EX_NOUSER -- The user specified did not exist.  This might
X**		be used for mail addresses or remote logins.
X**	EX_NOHOST -- The host specified did not exist.  This is used
X**		in mail addresses or network requests.
X**	EX_UNAVAILABLE -- A service is unavailable.  This can occur
X**		if a support program or file does not exist.  This
X**		can also be used as a catchall message when something
X**		you wanted to do doesn't work, but you don't know
X**		why.
X**	EX_SOFTWARE -- An internal software error has been detected.
X**		This should be limited to non-operating system related
X**		errors as possible.
X**	EX_OSERR -- An operating system error has been detected.
X**		This is intended to be used for such things as "cannot
X**		fork", "cannot create pipe", or the like.  It includes
X**		things like getuid returning a user that does not
X**		exist in the passwd file.
X**	EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
X**		etc.) does not exist, cannot be opened, or has some
X**		sort of error (e.g., syntax error).
X**	EX_CANTCREAT -- A (user specified) output file cannot be
X**		created.
X**	EX_IOERR -- An error occurred while doing I/O on some file.
X**	EX_TEMPFAIL -- temporary failure, indicating something that
X**		is not really an error.  In sendmail, this means
X**		that a mailer (e.g.) could not create a connection,
X**		and the request should be reattempted later.
X**	EX_PROTOCOL -- the remote system returned something that
X**		was "not possible" during a protocol exchange.
X**	EX_NOPERM -- You did not have sufficient permission to
X**		perform the operation.  This is not intended for
X**		file system problems, which should use NOINPUT or
X**		CANTCREAT, but rather for higher level permissions.
X**		For example, kre uses this to restrict who students
X**		can send mail to.
X**
X**	Maintained by Eric Allman (eric@berkeley, ucbvax!eric) --
X**		please mail changes to me.
X**
X**			@(#)sysexits.h	4.3		12/15/87
X*/
X
X# define EX_OK		0	/* successful termination */
X
X# define EX__BASE	64	/* base value for error messages */
X
X# define EX_USAGE	64	/* command line usage error */
X# define EX_DATAERR	65	/* data format error */
X# define EX_NOINPUT	66	/* cannot open input */
X# define EX_NOUSER	67	/* addressee unknown */
X# define EX_NOHOST	68	/* host name unknown */
X# define EX_UNAVAILABLE	69	/* service unavailable */
X# define EX_SOFTWARE	70	/* internal software error */
X# define EX_OSERR	71	/* system error (e.g., can't fork) */
X# define EX_OSFILE	72	/* critical OS file missing */
X# define EX_CANTCREAT	73	/* can't create (user) output file */
X# define EX_IOERR	74	/* input/output error */
X# define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
X# define EX_PROTOCOL	76	/* remote error in protocol */
X# define EX_NOPERM	77	/* permission denied */
END_OF_FILE
if test 4212 -ne `wc -c <'./xmit/sysexits.h'`; then
    echo shar: \"'./xmit/sysexits.h'\" unpacked with wrong size!
fi
# end of './xmit/sysexits.h'
fi
echo shar: End of archive 3 \(of 9\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 9 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.