Article 2699 of comp.sources.unix:
Path: nntpd.lkg.dec.com!crl.dec.com!crl.dec.com!bloom-beacon.mit.edu!news.kei.com!news.mathworks.com!newsfeed.internetmci.com!in1.uu.net!news1.digital.com!vixie!vixie!not-for-mail
From: davison@borland.com (Wayne Davison)
Newsgroups: comp.sources.unix
Subject: v29i041: trn-3.6 - threaded newsreader based on RN, V3.6, Part04/14
Date: 29 Oct 1995 01:32:48 -0800
Organization: Vixie Enterprises
Lines: 3071
Sender: vixie@vix.com
Approved: vixie@gw.home.vix.com
Message-ID: <46vho0$t4g@gw.home.vix.com>
References: <1.814959141.29825@gw.home.vix.com>
NNTP-Posting-Host: gw.home.vix.com

Submitted-By: davison@borland.com (Wayne Davison)
Posting-Number: Volume 29, Issue 41
Archive-Name: trn-3.6/part04

#!/bin/sh
# This is `part04' (part 4 of a multipart archive).
# Do not concatenate these parts, unpack them in order with `/bin/sh'.
# File `trn-3.6/Configure' is being continued...
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  echo 'WARNING: not restoring timestamps.  Consider getting and'
  echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if test ! -r _sharseq.tmp; then
  echo 'Please unpack part 1 first!'
  exit 1
fi
shar_sequence=`cat _sharseq.tmp`
if test "$shar_sequence" != 4; then
  echo "Please unpack part $shar_sequence next!"
  exit 1
fi
if test ! -f _sharnew.tmp; then
  echo 'x - still skipping trn-3.6/Configure'
else
  echo 'x - continuing file trn-3.6/Configure'
  sed 's/^X//' << 'SHAR_EOF' >> 'trn-3.6/Configure' &&
Xcase "$alldone" in
Xexit)
X	$rm -rf UU
X	echo "Done."
X	exit 0
X	;;
Xcont)
X	;;
X'')
X	echo " "
X	dflt=''
X	nostick=true
Xecho "If you didn't make any mistakes, then just type a carriage return here."
X	rp="If you need to edit config.sh, do it as a shell escape here:"
X	. UU/myread
X	nostick=''
X	case "$ans" in
X	'') ;;
X	*) : in case they cannot read
X		sh 1>&4 -c "$ans";;
X	esac
X	;;
Xesac
X
X: if this fails, just run all the .SH files by hand
X. ./config.sh
X
Xecho " "
Xexec 1>&4
X. UU/extract
X
Xecho " "
Xecho 'Now type "make".'
X
X$rm -f kit*isdone ark*isdone
X$rm -rf UU
X: End of Configure
SHAR_EOF
  echo 'File trn-3.6/Configure is complete' &&
  $shar_touch -am 1107173594 'trn-3.6/Configure' &&
  chmod 0755 'trn-3.6/Configure' ||
  echo 'restore of trn-3.6/Configure failed'
  shar_count="`wc -c < 'trn-3.6/Configure'`"
  test 100790 -eq "$shar_count" ||
    echo "trn-3.6/Configure: original size 100790, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/decode.c ==============
if test -f 'trn-3.6/decode.c' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/decode.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/decode.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/decode.c' &&
X/* $Id: decode.c,v 3.0 1991/11/22 04:12:25 davison Trn $
X */
X/* The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "INTERN.h"
X#include "decode.h"
X
Xvoid
Xdecode_init()
X{
X    unship_init();
X}
X
Xvoid
Xdecode_end()
X{
X    if (decode_fp != Nullfp) {
X	fclose(decode_fp);
X	decode_fp = Nullfp;
X	printf("\n%s INCOMPLETE -- removed.\n", decode_dest) FLUSH;
X	unlink(decode_dest);
X    }
X}
SHAR_EOF
  $shar_touch -am 0711223593 'trn-3.6/decode.c' &&
  chmod 0644 'trn-3.6/decode.c' ||
  echo 'restore of trn-3.6/decode.c failed'
  shar_count="`wc -c < 'trn-3.6/decode.c'`"
  test 562 -eq "$shar_count" ||
    echo "trn-3.6/decode.c: original size 562, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/decode.h ==============
if test -f 'trn-3.6/decode.h' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/decode.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/decode.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/decode.h' &&
X/* $Id: decode.h,v 3.0 1991/11/22 04:12:25 davison Trn $
X */
X/* The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
XEXT FILE *decode_fp INIT(NULL);
XEXT char decode_fname[MAXFILENAME];
XEXT char decode_dest[MAXFILENAME];
XEXT int decode_type;
X
Xvoid decode_init _((void));
Xvoid decode_end _((void));
X
Xvoid uud_start _((void));
Xint uudecode _((FILE*));
X
Xvoid unship_init _((void));
Xint unship _((FILE*));
X
X#define UUDECODE 0
X#define UNSHIP   1
SHAR_EOF
  $shar_touch -am 0711223593 'trn-3.6/decode.h' &&
  chmod 0644 'trn-3.6/decode.h' ||
  echo 'restore of trn-3.6/decode.h failed'
  shar_count="`wc -c < 'trn-3.6/decode.h'`"
  test 578 -eq "$shar_count" ||
    echo "trn-3.6/decode.h: original size 578, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/final.c ==============
if test -f 'trn-3.6/final.c' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/final.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/final.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/final.c' &&
X/* $Id: final.c,v 3.0 1992/02/01 03:09:32 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "cache.h"
X#include "bits.h"
X#include "term.h"
X#include "ng.h"
X#include "init.h"
X#include "last.h"
X#include "rcstuff.h"
X#include "ngdata.h"
X#include "artio.h"
X#include "intrp.h"
X#include "nntp.h"
X#include "INTERN.h"
X#include "final.h"
X
X#ifndef sigmask
X#define sigmask(m)	(1 << ((m)-1))
X#endif
X
Xvoid
Xfinal_init()
X{
X#ifdef SIGTSTP
X    sigset(SIGTSTP, stop_catcher);	/* job control signals */
X    sigset(SIGTTOU, stop_catcher);	/* job control signals */
X    sigset(SIGTTIN, stop_catcher);	/* job control signals */
X#endif
X
X    sigset(SIGINT, int_catcher);	/* always catch interrupts */
X#ifdef SIGHUP
X    sigset(SIGHUP, sig_catcher);	/* and hangups */
X#endif
X#ifdef SIGWINCH
X    sigset(SIGWINCH, winch_catcher);
X#endif
X
X#ifndef lint
X#ifdef SIGEMT
X    sigignore(SIGEMT);		/* Ignore EMT signals from old [t]rn's */
X#endif
X#endif
X
X#ifdef DEBUG
X    /* sometimes we WANT a core dump */
X    if (debug & DEB_COREDUMPSOK)
X	return;
X#endif
X    sigset(SIGILL, sig_catcher);
X#ifdef SIGTRAP
X    sigset(SIGTRAP, sig_catcher);
X#endif
X    sigset(SIGFPE, sig_catcher);
X#ifdef SIGBUS
X    sigset(SIGBUS, sig_catcher);
X#endif
X    sigset(SIGSEGV, sig_catcher);
X#ifdef SIGSYS
X    sigset(SIGSYS, sig_catcher);
X#endif
X    sigset(SIGTERM, sig_catcher);
X#ifdef SIGXCPU
X    sigset(SIGXCPU, sig_catcher);
X#endif
X#ifdef SIGXFSZ
X    sigset(SIGXFSZ, sig_catcher);
X#endif
X}
X
Xvoid					/* very much void */
Xfinalize(status)
Xint status;
X{
X    termlib_reset();
X    if (bizarre)
X	resetty();
X    xmouse_off();	/* turn off mouse tracking (if on) */
X    if (lockname && *lockname)
X 	UNLINK(lockname);
X#ifdef USE_NNTP
X    nntp_cleanup();
X#endif
X    if (status < 0) {
X	chdir(tmpdir);
X	sigset(SIGILL,SIG_DFL);
X#ifdef HAS_SIGBLOCK
X	sigsetmask(sigblock(0) & ~(sigmask(SIGILL) | sigmask(SIGIOT)));
X#endif
X	abort();
X    }
X    exit(status);
X}
X
X/* come here on interrupt */
X
XSignal_t
Xint_catcher(dummy)
Xint dummy;
X{
X    sigset(SIGINT,int_catcher);
X#ifdef DEBUG
X    if (debug)
X	write(2,"int_catcher\n",12);
X#endif
X    if (!waiting) {
X	if (int_count) {		/* was there already an interrupt? */
X	    write(2,"\nBye-bye.\n",10);
X	    sig_catcher(0);		/* emulate the other signals */
X	}
X	int_count++;
X    }
X}
X
X/* come here on signal other than interrupt, stop, or cont */
X
XSignal_t
Xsig_catcher(signo)
Xint signo;
X{
X#ifdef VERBOSE
X    static char *signame[] = {
X	"",
X	"HUP",
X	"INT",
X	"QUIT",
X	"ILL",
X	"TRAP",
X	"IOT",
X	"EMT",
X	"FPE",
X	"KILL",
X	"BUS",
X	"SEGV",
X	"SYS",
X	"PIPE",
X	"ALRM",
X	"TERM",
X	"???"
X#ifdef SIGTSTP
X	,"STOP",
X	"TSTP",
X	"CONT",
X	"CHLD",
X	"TTIN",
X	"TTOU",
X	"TINT",
X	"XCPU",
X	"XFSZ"
X#ifdef SIGPROF
X	,"VTALARM",
X	"PROF"
X#endif
X#endif
X	};
X#endif
X
X#ifdef DEBUG
X    if (debug) {
X	printf("\nSIG%s--.newsrc not restored in debug\n",signame[signo]);
X	finalize(-1);
X    }
X#endif
X    if (panic) {
X#ifdef HAS_SIGBLOCK
X      sigsetmask(sigblock(0) & ~(sigmask(SIGILL) | sigmask(SIGIOT)));
X#endif
X	abort();
X      }
X    (void) sigset(SIGILL,SIG_DFL);
X    panic = TRUE;			/* disable terminal I/O */
X    if (doing_ng) {			/* need we reconstitute rc line? */
X	yankback();
X	bits_to_rc();			/* then do so (hope this works) */
X    }
X    doing_ng = FALSE;
X    if (rc_changed)			/* need we write .newsrc out? */
X	write_rc();			/* then do so */
X    rc_changed = FALSE;
X#ifdef SIGHUP
X    if (signo != SIGHUP)
X#endif
X#ifdef VERBOSE
X	IF(verbose)
X	    printf("\nCaught %s%s--.newsrc restored\n",
X		signo ? "a SIG" : "an internal error", signame[signo]);
X	ELSE
X#endif
X#ifdef TERSE
X	    printf("\nSignal %d--bye bye\n",signo);
X#endif
X    switch (signo) {
X#ifdef SIGBUS
X    case SIGBUS:
X#endif
X    case SIGILL:
X    case SIGSEGV:
X	finalize(-signo);
X    }
X    finalize(1);				/* and blow up */
X}
X
X#ifdef SIGTSTP
X/* come here on stop signal */
X
XSignal_t
Xstop_catcher(signo)
Xint signo;
X{
X    if (!waiting) {
X	bool mouse_flag;	/* if TRUE, mouse tracking was on */
X	mouse_flag = xmouse_status;
X	xmouse_off();
X	checkpoint_rc();	/* good chance of crash while stopped */
X	if (clear_on_stop) {
X	    clear();
X	    putchar('\n') FLUSH;
X	}
X	termlib_reset();
X	resetty();		/* this is the point of all this */
X#ifdef DEBUG
X	if (debug)
X	    write(2,"stop_catcher\n",13);
X#endif
X	sigset(signo,SIG_DFL);	/* enable stop */
X#ifdef HAS_SIGBLOCK
X	sigsetmask(sigblock(0) & ~(1 << (signo-1)));
X#endif
X	kill(0,signo);		/* and do the stop */
X    	savetty();
X#ifdef MAILCALL
X    	mailcount = 0;			/* force recheck */
X#endif
X    	if (!panic) {
X	    if (!waiting) {
X		termlib_init();
X		noecho();			/* set no echo */
X		crmode();			/* set cbreak mode */
X		forceme("\f");			/* cause a refresh */
X						/* (defined only if TIOCSTI defined) */
X		errno = 0;			/* needed for getcmd */
X	    }
X    	}
X	if (mouse_flag)
X	    xmouse_on();
X    }
X    sigset(signo,stop_catcher);	/* unenable the stop */
X}
X#endif
SHAR_EOF
  $shar_touch -am 1017161694 'trn-3.6/final.c' &&
  chmod 0644 'trn-3.6/final.c' ||
  echo 'restore of trn-3.6/final.c failed'
  shar_count="`wc -c < 'trn-3.6/final.c'`"
  test 5407 -eq "$shar_count" ||
    echo "trn-3.6/final.c: original size 5407, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/final.h ==============
if test -f 'trn-3.6/final.h' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/final.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/final.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/final.h' &&
X/* $Id: final.h,v 3.0 1992/02/01 03:09:32 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X/* cleanup status for fast exits */
X
XEXT bool panic INIT(FALSE);		/* we got hung up or something-- */
X					/*  so leave tty alone */
XEXT bool rc_changed INIT(FALSE);	/* need we rewrite .newsrc? */
XEXT bool doing_ng INIT(FALSE);		/* do we need to reconstitute */
X					/* current rc line? */
X
XEXT char int_count INIT(0);		/* how many interrupts we've had */
X
XEXT bool clear_on_stop INIT(FALSE);	/* set when handling the stop signal */
X					/* would leave the screen a mess */
X
X/* signal catching routines */
X
XSignal_t int_catcher _((int));
XSignal_t sig_catcher _((int));
X#ifdef SIGTSTP
XSignal_t stop_catcher _((int));
X#endif
X
Xvoid	final_init _((void));
Xvoid	finalize _((int))
X#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR >= 5)
X  __attribute__((noreturn))
X#endif
X  ;
SHAR_EOF
  $shar_touch -am 1129200893 'trn-3.6/final.h' &&
  chmod 0644 'trn-3.6/final.h' ||
  echo 'restore of trn-3.6/final.h failed'
  shar_count="`wc -c < 'trn-3.6/final.h'`"
  test 1420 -eq "$shar_count" ||
    echo "trn-3.6/final.h: original size 1420, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/filexp.SH ==============
if test -f 'trn-3.6/filexp.SH' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/filexp.SH (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/filexp.SH (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/filexp.SH' &&
Xcase $CONFIG in
X    '') . ./config.sh ;;
Xesac
Xecho "Extracting filexp (with variable substitutions)"
X$spitshell >filexp <<!GROK!THIS!
X$startsh
Xsed=${sed-sed}
Xexpr=${expr-expr}
Xbasename=${basename-basename}
Xtest=${test-test}
X!GROK!THIS!
X$spitshell >>filexp <<'!NO!SUBS!'
X: expand filename
Xcase "$1" in
X ~/*|~)
X	echo $1 | $sed "s|~|${HOME-$LOGDIR}|"
X	;;
X ~*)
X	if $test -f /bin/csh; then
X		/bin/csh -f -c "glob $1"
X		failed=$?
X		echo ""
X		exit $failed
X	else
X		name=`$expr x$1 : '..\([^/]*\)'`
X		dir=`$sed -n -e "/^${name}:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/" -e p -e q -e '}' </etc/passwd`
X		if $test ! -d "$dir"; then
X			me=`$basename $0`
X			echo "$me: can't locate home directory for: $name" >&2
X			exit 1
X		fi
X		case "$1" in
X		*/*)
X			echo $dir/`$expr x$1 : '..[^/]*/\(.*\)'`
X			;;
X		*)
X			echo $dir
X			;;
X		esac
X	fi
X	;;
X*)
X	echo $1
X	;;
Xesac
X!NO!SUBS!
Xchmod +x filexp
X$eunicefix filexp
SHAR_EOF
  $shar_touch -am 0419193994 'trn-3.6/filexp.SH' &&
  chmod 0644 'trn-3.6/filexp.SH' ||
  echo 'restore of trn-3.6/filexp.SH failed'
  shar_count="`wc -c < 'trn-3.6/filexp.SH'`"
  test 906 -eq "$shar_count" ||
    echo "trn-3.6/filexp.SH: original size 906, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/hash.c ==============
if test -f 'trn-3.6/hash.c' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/hash.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/hash.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/hash.c' &&
X/* $Id: hash.c,v 3.0 1992/12/14 00:14:13 davison Trn $
X*/
X/* This file is an altered version of a set of hash routines by
X** Geoffrey Collyer.  See the end of the file for his copyright.
X*/
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "final.h"
X#include "INTERN.h"
X#include "hash.h"
X
X/* tunable parameters */
X#define RETAIN 600		/* retain & recycle this many HASHENTs */
X
Xstatic HASHENT *hereuse = NULL;
Xstatic int reusables = 0;
X
Xstatic HASHENT **hashfind _((HASHTABLE*,char*,int));
Xstatic unsigned hash _((char*,int));
Xstatic int default_cmp _((char*,int,HASHDATUM));
Xstatic HASHENT *healloc _((void));
Xstatic void hefree _((HASHENT*));
X
XHASHTABLE *
Xhashcreate(size, cmpfunc)
Xunsigned size;			/* a crude guide to size */
Xint (*cmpfunc)();
X{
X    register HASHTABLE *tbl;
X    /* allocate HASHTABLE and (HASHENT*) array together to reduce the
X    ** number of malloc calls. */
X    register struct alignalloc {
X	HASHTABLE ht;
X	HASHENT *hepa[1];	/* longer than it looks */
X    } *aap;
X
X    if (size < 1)		/* size < 1 is nonsense */
X	size = 1;
X    aap = (struct alignalloc*)
X	safemalloc(sizeof *aap + (size-1)*sizeof (HASHENT*));
X    bzero((char*)aap, sizeof *aap + (size-1)*sizeof (HASHENT*));
X    tbl = &aap->ht;
X    tbl->ht_size = size;
X    tbl->ht_magic = HASHMAG;
X    tbl->ht_cmp = (cmpfunc == NULL? default_cmp: cmpfunc);
X    tbl->ht_addr = aap->hepa;
X    return tbl;
X}
X
X/* Free all the memory associated with tbl, erase the pointers to it, and
X** invalidate tbl to prevent further use via other pointers to it.
X*/
Xvoid
Xhashdestroy(tbl)
Xregister HASHTABLE *tbl;
X{
X    register unsigned idx;
X    register HASHENT *hp, *next;
X    register HASHENT **hepp;
X    register int tblsize;
X
X    if (tbl == NULL || BADTBL(tbl))
X	return;
X    tblsize = tbl->ht_size;
X    hepp = tbl->ht_addr;
X    for (idx = 0; idx < tblsize; idx++) {
X	for (hp = hepp[idx]; hp != NULL; hp = next) {
X	    next = hp->he_next;
X	    hp->he_next = NULL;
X	    hefree(hp);
X	}
X	hepp[idx] = NULL;
X    }
X    tbl->ht_magic = 0;			/* de-certify this table */
X    tbl->ht_addr = NULL;
X    free((char*)tbl);
X}
X
Xvoid
Xhashstore(tbl, key, keylen, data)
Xregister HASHTABLE *tbl;
Xchar *key;
Xint keylen;
XHASHDATUM data;
X{
X    register HASHENT *hp;
X    register HASHENT **nextp;
X
X    nextp = hashfind(tbl, key, keylen);
X    hp = *nextp;
X    if (hp == NULL) {			/* absent; allocate an entry */
X	hp = healloc();
X	hp->he_next = NULL;
X	hp->he_keylen = keylen;
X	*nextp = hp;			/* append to hash chain */
X    }
X    hp->he_data = data;		/* supersede any old data for this key */
X}
X
Xvoid
Xhashdelete(tbl, key, keylen)
Xregister HASHTABLE *tbl;
Xchar *key;
Xint keylen;
X{
X    register HASHENT *hp;
X    register HASHENT **nextp;
X
X    nextp = hashfind(tbl, key, keylen);
X    hp = *nextp;
X    if (hp == NULL)			/* absent */
X	return;
X    *nextp = hp->he_next;		/* skip this entry */
X    hp->he_next = NULL;
X    hp->he_data.dat_ptr = NULL;
X    hefree(hp);
X}
X
XHASHENT **slast_nextp;
Xint slast_keylen;
X
XHASHDATUM				/* data corresponding to key */
Xhashfetch(tbl, key, keylen)
Xregister HASHTABLE *tbl;
Xchar *key;
Xint keylen;
X{
X    register HASHENT *hp;
X    register HASHENT **nextp;
X    static HASHDATUM errdatum = { NULL, 0 };
X
X    nextp = hashfind(tbl, key, keylen);
X    slast_nextp = nextp;
X    slast_keylen = keylen;
X    hp = *nextp;
X    if (hp == NULL)			/* absent */
X	return errdatum;
X    else
X	return hp->he_data;
X}
X
Xvoid
Xhashstorelast(data)
XHASHDATUM data;
X{
X    register HASHENT *hp;
X
X    hp = *slast_nextp;
X    if (hp == NULL) {			/* absent; allocate an entry */
X	hp = healloc();
X	hp->he_next = NULL;
X	hp->he_keylen = slast_keylen;
X	*slast_nextp = hp;		/* append to hash chain */
X    }
X    hp->he_data = data;		/* supersede any old data for this key */
X}
X
X/* Visit each entry by calling nodefunc at each, with key, data and extra as
X** arguments.
X*/
Xvoid
Xhashwalk(tbl, nodefunc, extra)
XHASHTABLE *tbl;
Xregister void (*nodefunc)();
Xregister int extra;
X{
X    register unsigned idx;
X    register HASHENT *hp;
X    register HASHENT **hepp;
X    register int tblsize;
X
X    if (BADTBL(tbl))
X	return;
X    hepp = tbl->ht_addr;
X    tblsize = tbl->ht_size;
X    for (idx = 0; idx < tblsize; idx++)
X	for (hp = hepp[idx]; hp != NULL; hp = hp->he_next)
X	    (*nodefunc)(&hp->he_data, extra);
X}
X
X/* The returned value is the address of the pointer that refers to the
X** found object.  Said pointer may be NULL if the object was not found;
X** if so, this pointer should be updated with the address of the object
X** to be inserted, if insertion is desired.
X*/
Xstatic HASHENT **
Xhashfind(tbl, key, keylen)
Xregister HASHTABLE *tbl;
Xchar *key;
Xregister int keylen;
X{
X    register HASHENT *hp, *prevhp = NULL;
X    register HASHENT **hepp;
X    register unsigned size; 
X
X    if (BADTBL(tbl)) {
X	fputs("Hash table is invalid.",stderr);
X	finalize(1);
X    }
X    size = tbl->ht_size;
X    hepp = &tbl->ht_addr[hash(key,keylen) % size];
X    for (hp = *hepp; hp != NULL; prevhp = hp, hp = hp->he_next) {
X	if (hp->he_keylen == keylen && !(*tbl->ht_cmp)(key, keylen, hp->he_data))
X	    break;
X    }
X    /* assert: *(returned value) == hp */
X    return (prevhp == NULL? hepp: &prevhp->he_next);
X}
X
Xstatic unsigned				/* not yet taken modulus table size */
Xhash(key, keylen)
Xregister char *key;
Xregister int keylen;
X{
X    register unsigned hash = 0;
X
X    while (keylen--)
X	hash += *key++;
X    return hash;
X}
X
Xstatic int
Xdefault_cmp(key, keylen, data)
Xchar *key;
Xint keylen;
XHASHDATUM data;
X{
X    /* We already know that the lengths are equal, just compare the strings */
X    return bcmp(key, data.dat_ptr, keylen);
X}
X
Xstatic HASHENT *
Xhealloc()				/* allocate a hash entry */
X{
X    register HASHENT *hp;
X
X    if (hereuse == NULL)
X	return (HASHENT*)safemalloc(sizeof (HASHENT));
X    /* pull the first reusable one off the pile */
X    hp = hereuse;
X    hereuse = hereuse->he_next;
X    hp->he_next = NULL;			/* prevent accidents */
X    reusables--;
X    return hp;
X}
X
Xstatic void
Xhefree(hp)				/* free a hash entry */
Xregister HASHENT *hp;
X{
X    if (reusables >= RETAIN)		/* compost heap is full? */
X	free((char*)hp);		/* yup, just pitch this one */
X    else {				/* no, just stash for reuse */
X	++reusables;
X	hp->he_next = hereuse;
X	hereuse = hp;
X    }
X}
X
X/*
X * Copyright (c) 1992 Geoffrey Collyer
X * All rights reserved.
X * Written by Geoffrey Collyer.
X *
X * This software is not subject to any license of the American Telephone
X * and Telegraph Company, the Regents of the University of California, or
X * the Free Software Foundation.
X *
X * Permission is granted to anyone to use this software for any purpose on
X * any computer system, and to alter it and redistribute it freely, subject
X * to the following restrictions:
X *
X * 1. The author is not responsible for the consequences of use of this
X *    software, no matter how awful, even if they arise from flaws in it.
X *
X * 2. The origin of this software must not be misrepresented, either by
X *    explicit claim or by omission.  Since few users ever read sources,
X *    credits must appear in the documentation.
X *
X * 3. Altered versions must be plainly marked as such, and must not be
X *    misrepresented as being the original software.  Since few users
X *    ever read sources, credits must appear in the documentation.
X *
X * 4. This notice may not be removed or altered.
X */
SHAR_EOF
  $shar_touch -am 0409160994 'trn-3.6/hash.c' &&
  chmod 0644 'trn-3.6/hash.c' ||
  echo 'restore of trn-3.6/hash.c failed'
  shar_count="`wc -c < 'trn-3.6/hash.c'`"
  test 7259 -eq "$shar_count" ||
    echo "trn-3.6/hash.c: original size 7259, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/hash.h ==============
if test -f 'trn-3.6/hash.h' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/hash.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/hash.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/hash.h' &&
X/*
X * general-purpose in-core hashing
X */
X/* The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#define HASHDATUM struct hashdatum
XHASHDATUM {
X    char *dat_ptr;
X    unsigned dat_len;
X};
X
X#ifndef HASHTABLE
X#define HASHTABLE struct hashtable
X#endif
X
XEXT HASHTABLE *hashcreate _((unsigned, int(*)()));
XEXT void hashdestroy _((HASHTABLE*));
XEXT void hashstore _((HASHTABLE*,char*,int,HASHDATUM));
XEXT void hashdelete _((HASHTABLE*,char*,int));
XEXT HASHDATUM hashfetch _((HASHTABLE*,char*,int));
XEXT void hashstorelast _((HASHDATUM));
XEXT void hashwalk _((HASHTABLE*,void(*)(),int));
X
X/* Internal stuff */
X
X#ifdef DOINIT
X
X#define BADTBL(tbl)	((tbl)->ht_magic != HASHMAG)
X
X#define HASHMAG  ((char)0257)
X
X#define HASHENT struct hashent
X
XHASHENT {
X    HASHENT *he_next;		/* in hash chain */
X    HASHDATUM he_data;
X    int he_keylen;		/* to help verify a match */
X};
X
XHASHTABLE {
X    HASHENT **ht_addr;		/* array of HASHENT pointers */
X    unsigned ht_size;
X    char ht_magic;
X    int (*ht_cmp)();
X};
X#endif
SHAR_EOF
  $shar_touch -am 1116205993 'trn-3.6/hash.h' &&
  chmod 0644 'trn-3.6/hash.h' ||
  echo 'restore of trn-3.6/hash.h failed'
  shar_count="`wc -c < 'trn-3.6/hash.h'`"
  test 1140 -eq "$shar_count" ||
    echo "trn-3.6/hash.h: original size 1140, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/MANIFEST ==============
if test -f 'trn-3.6/MANIFEST' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/MANIFEST (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/MANIFEST (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/MANIFEST' &&
XConfigure          A shell script that installs everything system dependent.
XEXTERN.h           When included, makes other includes not belong to me.
XHACKERSGUIDE       A brief guide to the contorted innards of [t]rn.
XHINTS.TRN          Some helpful hints to get the most out of using trn.
XINIT               Sample system-wide switch file.
XINSTALL            Installation instructions.
XINTERN.h           When included, makes other includes belong to me.
XMANIFEST           This list of files.
XMakefile.SH        Shell script to generate the makefile.
XNEW                List of new features with trn 3.0.
XPnews.1            Manual page for Pnews.
XPnews.SH           A news posting shell script that knows about -h.
XPolicy.sh.SH       Script to save the local policy answers.
XREADME             Start by reading this file.
XRnmail.1           Manual page for Rnmail.
XRnmail.SH          A mailer that knows about -h.
XSpeller.SH         An ispell wrapper that understands news articles.
Xaddng.c            Routines for scanning the active file for new newsgroups.
Xaddng.h            Public info regarding addng.c.
Xart.c              Routines to display an article.
Xart.h              Public info regarding art.c.
Xartio.c            Reserved for the article abstract type, someday.
Xartio.h            Public info regarding artio.c.
Xartsrch.c          Routines for searching among articles.
Xartsrch.h          Public info regarding artsrch.c.
Xartstate.h         Info on the current state of the article.
Xautosub.c          Routines to allow automatic subscription management
Xautosub.h          Public info regarding autosub.c
Xbackpage.c         Routines for paging backwards in articles.
Xbackpage.h         Public info regarding backpage.c.
Xbits.c             Bitmap management functions.
Xbits.h             Public info regarding bits.c.
Xcache.c            Routines to handle caching of articles.
Xcache.h            Public info regarding cache.c.
Xcharsubst.c        Routines for converting between various character sets.
Xcharsubst.h        Public info regarding charsubst.c.
Xcommon.h           Global info.
Xconfig.h.SH        Shell script to create config.h
Xdecode.c           Routines common to the binary decoders
Xdecode.h           Public info for the binary decoders.
Xdependencies       A pre-made list of the source's dependencies.
Xedit_dist.c        Routines to find the edit distance between two strings.
Xfilexp.SH          The filename expansion script.
Xfinal.c            Finalization (exit) routines.
Xfinal.h            Public info regarding final.c.
Xhash.c             Hashing routines.
Xhash.h             Public/private info for hashing routines.
Xhead.c             Header parsing routines.
Xhead.h             Public info regarding head.c.
Xhelp.c             Help routines.
Xhelp.h             Public info regarding help.c.
Xinit.c             Initialization (startup) routines.
Xinit.h             Public info regarding init.c.
Xintrp.c            Filename expansion and % interpretation routines.
Xintrp.h            Public info regarding intrp.c.
Xkfile.c            KILL file routines.
Xkfile.h            Public info regarding kfile.c.
Xlast.c             Routines for handling the .rnlast file.
Xlast.h             Public info regarding last.c.
Xmakedepend.SH      Shell script to generate make dependencies.
Xmakedir.SH         Shell script to make nested subdirectories.
Xmbox.saver.SH      Shell script to save an article to a mailbox.
Xndir.c             BSD 4.2 directory routine emulation.
Xndir.h             Public directory info.
Xnewsetup.1         Manual page for newsetup.
Xnewsetup.SH        Shell script to create a .newsrc file.
Xnewsgroups.1       Manual page for newsgroups.
Xnewsgroups.SH      Shell script to list unsubscribed newsgroups.
Xnewsnews.SH        A motd-like file that trn may print at startup.
Xng.c               Routines to display a newsgroup.
Xng.h               Public info regarding ng.c.
Xngdata.c           General data fetching routines for a newsgroup.
Xngdata.h           Public info regarding ngdata.c.
Xnghash.c           Some hashing routines to speed up active file handling.
Xngsrch.c           Routines to search among newsgroups.
Xngsrch.h           Public info regarding ngsrch.c.
Xngstuff.c          Support routines for ng.c.
Xngstuff.h          Public info regarding ng.c.
Xnntp.c             Routines for accessing NNTP commands.
Xnntp.h             Public info regarding the NNTP routines.
Xnntpauth.c         Code to handle NNTP authentication.
Xnntpauth.h         Public info for the authentication routines.
Xnntpclient.c       Custom version of the nntp client library.
Xnntpclient.h       Public info for the nntp client library.
Xnntpinit.c         Routines to implement server_init().
Xnntplist.c         Used by shell scripts to list server resources. (NNTP only)
Xnorm.saver.SH      Shell script to save an article to a normal file.
Xonly.c             Routines to perform newsgroup restriction.
Xonly.h             Public info regarding only.c.
Xoverview.h         Defines for customizing the overview handling.
Xparsedate.y        A yacc script for date parsing.
Xpatchlevel.h       Indicates current patch level.
Xrcln.c             Routines to mung a .newsrc line.
Xrcln.h             Public info regarding rcln.c.
Xrcstuff.c          Routines to mung the .newsrc file.
Xrcstuff.h          Public info regarding rcstuff.c.
Xrespond.c          Various routines for doing things with articles.
Xrespond.h          Public info regarding respond.c.
Xrt-mt.c            Support for the mthread's .thread file format.
Xrt-mt.h            Public/private info for rt-mt.c.
Xrt-ov.c            Support for .overview files.
Xrt-ov.h            Public info for rt-ov.c.
Xrt-page.c          Routines to manipulate pages in the selector.
Xrt-page.h          Public info for rt-page.c.
Xrt-process.c       The thread-processing code.
Xrt-process.h       Public info for rt-process.c.
Xrt-select.c        The thread/subject/article selector.
Xrt-select.h        Public/private info for rt-select.c.
Xrt-util.c          Utility routines for reading threads.
Xrt-util.h          Public info for rt-util.c.
Xrt-wumpus.c        Routines to draw the character-oriented tree display.
Xrt-wumpus.h        Public info for rt-wumpus.c.
Xrthread.c          The basic routines added to init and read threads.
Xrthread.h          Public info for rthread.c.
Xsearch.c           Regular expression processing ala emacs.
Xsearch.h           Public info regarding search.c.
Xstrftime.c         Source for strftime.c, if needed.
Xsw.c               Switch processing routines.
Xsw.h               Public info regarding switch.c.
Xterm.c             Terminal interface routines.
Xterm.h             Public info regarding term.c.
Xtrn.1              Manual pages for trn -- PLEASE READ.
Xtrn.c              The main program.
Xtrn.h              Public info for trn.c.
Xtrn-artchk.c       An article-checking program called from Pnews.
Xunipatch.c         A unified diff filter for use with old versions of patch.
Xunship.c           Decodes ship files.
Xutil.c             Utility routines.
Xutil.h             Public info regarding util.c.
Xutil2.c            Utility routines common to trn and nntplist.
Xutil2.h            Public info regarding util2.c.
Xuudecode.c         Decodes uuencoded files.
Xsamples/subscriptions A sample subscriptions file for the default .newsrc.
Xsupport/trnkill    A script to run all trn's kill files in the background.
SHAR_EOF
  $shar_touch -am 1121153094 'trn-3.6/MANIFEST' &&
  chmod 0644 'trn-3.6/MANIFEST' ||
  echo 'restore of trn-3.6/MANIFEST failed'
  shar_count="`wc -c < 'trn-3.6/MANIFEST'`"
  test 7420 -eq "$shar_count" ||
    echo "trn-3.6/MANIFEST: original size 7420, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/head.c ==============
if test -f 'trn-3.6/head.c' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/head.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/head.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/head.c' &&
X/* $Id: head.c,v 3.0 1992/02/23 21:25:39 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "artio.h"
X#include "cache.h"
X#include "ng.h"
X#include "ngdata.h"
X#include "util.h"
X#include "hash.h"
X#include "rthread.h"
X#include "rt-process.h"
X#include "rt-util.h"
X#include "final.h"
X#include "nntp.h"
X#include "INTERN.h"
X#include "head.h"
X
Xbool first_one;		/* is this the 1st occurance of this header line? */
X
Xstatic char htypeix[26] =
X    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
X
Xvoid
Xhead_init()
X{
X    register int i;
X
X    for (i=HEAD_FIRST+1; i<HEAD_LAST; i++)
X	htypeix[*htype[i].ht_name - 'a'] = i;
X
X    headbuf_size = LBUFLEN * 8;
X    headbuf = safemalloc(headbuf_size);
X}
X
X#ifdef DEBUG
Xvoid
Xdumpheader(where)
Xchar *where;
X{
X    register int i;
X
X    printf("header: %d %s", parsed_art, where);
X
X    for (i=0; i<HEAD_LAST; i++) {
X	printf("%15s %4d %4d %03o\n",htype[i].ht_name,
X	    htype[i].ht_minpos,
X	    htype[i].ht_maxpos,
X	    htype[i].ht_flags) FLUSH;
X    }
X}
X#endif
X
Xint
Xset_line_type(bufptr,colon)
Xchar *bufptr;
Xregister char *colon;
X{
X    char lc[LONGKEY+3];
X    register char *t, *f;
X    register int i, len;
X
X    if (colon-bufptr > LONGKEY+2)
X	return SOME_LINE;
X
X    for (t=lc,f=bufptr; f<colon; f++, t++) {
X	if (isspace(*f))
X	/* guard against space before : */
X	    break;
X	*t = isupper(*f) ? tolower(*f) : *f;
X    }
X    *t = '\0';
X    f = lc;				/* get lc into register */
X    len = t - f;
X
X    /* now scan the headtype table, backwards so we don't have to supply an
X     * extra terminating value, using first letter as index, and length as
X     * optimization to avoid calling subroutine strEQ unnecessarily.  Hauls.
X     */
X    if (*f >= 'a' && *f <= 'z') {
X	for (i = htypeix[*f - 'a']; *htype[i].ht_name == *f; --i) {
X	    if (len == htype[i].ht_length && strEQ(f, htype[i].ht_name)) {
X		return i;
X	    }
X	}
X    }
X    return SOME_LINE;
X}
X
Xvoid
Xstart_header(artnum)
XART_NUM artnum;
X{
X    register int i;
X
X#ifdef DEBUG
X    if (debug & DEB_HEADER)
X	dumpheader("start_header\n");
X#endif
X    for (i=0; i<HEAD_LAST; i++) {
X	htype[i].ht_minpos = -1;
X	htype[i].ht_maxpos = 0;
X    }
X    in_header = SOME_LINE;
X    first_one = FALSE;
X    parsed_art = artnum;
X}
X
Xvoid
Xend_header_line()
X{
X    if (first_one) {		/* did we just pass 1st occurance? */
X	first_one = FALSE;
X	/* remember where line left off */
X	htype[in_header].ht_maxpos = artpos;
X	if (htype[in_header].ht_flags & HT_CACHED) {
X	    ARTICLE *ap = article_ptr(parsed_art);
X	    if (!get_cached_line(ap, in_header, TRUE)) {
X		int start = htype[in_header].ht_minpos
X			  + htype[in_header].ht_length + 1;
X		MEM_SIZE size;
X		while (headbuf[start] == ' ' || headbuf[start] == '\t')
X		    start++;
X		size = artpos - start + 1 - 1;	/* pre-strip newline */
X		if (in_header == SUBJ_LINE)
X		    set_subj_line(ap,headbuf+start,size-1);
X		else {
X		    char *s = safemalloc(size);
X		    *s = '\0';
X		    safecat(s,headbuf+start,size);
X		    set_cached_line(ap,in_header,s);
X		}
X	    }
X	}
X    }
X}
X
Xbool
Xparseline(art_buf,newhide,oldhide)
Xchar *art_buf;
Xint newhide, oldhide;
X{
X    if (*art_buf == ' ' || *art_buf == '\t') {
X					/* header continuation line? */
X	return oldhide;
X    } else {				/* maybe another header line */
X	char *s;
X	end_header_line();
X	s = index(art_buf,':');
X	if (s == Nullch) {	/* is it the end of the header? */
X#ifdef USE_NNTP
X	    /* Did NNTP ship us a mal-formed header line? */
X	    if (*art_buf && *art_buf != '\n') {
X		in_header = SOME_LINE;
X		return newhide;
X	    }
X#endif
X	    in_header = PAST_HEADER;
X	} else {		/* it is a new header line */
X	    in_header = set_line_type(art_buf,s);
X	    first_one = (htype[in_header].ht_minpos < 0);
X	    if (first_one) {
X		htype[in_header].ht_minpos = artpos;
X		if (in_header == DATE_LINE) {
X		    register ARTICLE *ap = article_ptr(parsed_art);
X		    if (!ap->date)
X			ap->date = parsedate(art_buf+6);
X		}
X	    }
X#ifdef DEBUG
X	    if (debug & DEB_HEADER)
X		dumpheader(art_buf);
X#endif
X	    if (htype[in_header].ht_flags & HT_HIDE)
X		return newhide;
X	}
X    }
X    return FALSE;			/* don't hide this line */
X}
X
Xvoid
Xend_header()
X{
X    register ARTICLE *ap = article_ptr(parsed_art);
X
X    end_header_line();
X    in_header = PAST_HEADER;	/* just to be sure */
X
X    if (!ap->subj)
X	set_subj_line(ap,"<NONE>",6);
X
X#ifndef DBM_XREFS
X    if (!ap->xrefs)
X	ap->xrefs = nullstr;
X#endif
X#ifdef USE_NNTP
X    htype[PAST_HEADER].ht_minpos = artpos+1;  /* remember where body starts */
X#else
X    htype[PAST_HEADER].ht_minpos = tellart();
X#endif
X
X    if (ThreadedGroup && !(ap->flags & AF_THREADED)) {
X	if (valid_article(ap)) {
X	    ARTICLE *artp_hold = artp;
X	    references = fetchlines(parsed_art, REFS_LINE);
X	    thread_article(ap);
X	    free(references);
X	    artp = artp_hold;
X	    check_poster(ap);
X	}
X    } else if (!(ap->flags & AF_CACHED)) {
X	cache_article(ap);
X	check_poster(ap);
X    }
X}
X
X/* read the header into memory and parse it if we haven't already */
X
Xbool
Xparseheader(artnum)
XART_NUM artnum;
X{
X    register char *bp;
X    register int len;
X    bool had_nl = TRUE;
X    bool found_nl;
X
X    if (parsed_art == artnum)
X	return TRUE;
X    if (artnum > lastart)
X	return FALSE;
X    spin(20);
X#ifdef USE_NNTP
X    if (!nntp_header(artnum)) {
X	uncache_article(article_ptr(artnum),FALSE);
X	return FALSE;
X    }
X#else
X    if (!artopen(artnum))
X	return FALSE;
X#endif
X    start_header(artnum);
X    artpos = 0;
X    bp = headbuf;
X    while (in_header) {
X	if (headbuf_size < artpos + LBUFLEN) {
X	    len = bp - headbuf;
X	    headbuf_size += LBUFLEN * 4;
X	    headbuf = saferealloc(headbuf,headbuf_size);
X	    bp = headbuf + len;
X	}
X#ifdef USE_NNTP
X	found_nl = nntp_gets(bp,LBUFLEN);
X	if (had_nl && *bp == '.') {
X	    if (!bp[1]) {
X		*bp++ = '\n';		/* tag the end with an empty line */
X		break;
X	    }
X	    strcpy(bp,bp+1);
X	}
X	len = strlen(bp);
X	if (found_nl)
X	    bp[len++] = '\n';
X	bp[len] = '\0';
X#else
X	if (readart(bp,LBUFLEN) == Nullch)
X	    break;
X	len = strlen(bp);
X	found_nl = (bp[len-1] == '\n');
X#endif
X	if (had_nl)
X	    parseline(bp,FALSE,FALSE);
X	had_nl = found_nl;
X	artpos += len;
X	bp += len;
X    }
X    *bp = '\0';   /* this probably isn't needed */
X    end_header();
X    return TRUE;
X}
X
X/* get a header line from an article */
X
Xchar *
Xfetchlines(artnum,which_line)
XART_NUM artnum;				/* article to get line from */
Xint which_line;				/* type of line desired */
X{
X    char *s, *t;
X    register ART_POS firstpos;
X    register ART_POS lastpos;
X    int size;
X
X    /* Only return a cached line if it isn't the current article */
X    if (parsed_art != artnum) {
X	s = fetchcache(artnum,which_line,FILL_CACHE);
X	if (s)
X	    return savestr(s);
X    }
X    if ((firstpos = htype[which_line].ht_minpos) < 0)
X	return savestr(nullstr);
X
X    firstpos += htype[which_line].ht_length + 1;
X    lastpos = htype[which_line].ht_maxpos;
X    size = lastpos - firstpos;
X    t = headbuf + firstpos;
X    while (*t == ' ' || *t == '\t') t++, size--;
X#ifdef DEBUG
X    if (debug && (size < 1 || size > 1000)) {
X	printf("Firstpos = %ld, lastpos = %ld\n",(long)firstpos,(long)lastpos);
X	fgets(cmd_buf, sizeof cmd_buf, stdin);
X    }
X#endif
X    s = safemalloc((MEM_SIZE)size);
X    *s = '\0';
X    safecat(s,t,size);
X    return s;
X}
X
X/* prefetch a header line from one or more articles */
X
Xchar *
Xprefetchlines(artnum,which_line,copy)
XART_NUM artnum;				/* article to get line from */
Xint which_line;				/* type of line desired */
Xbool_int copy;				/* do you want it savestr()ed? */
X{
X    char *s, *t;
X    register ART_POS firstpos;
X    register ART_POS lastpos;
X    int size;
X
X#ifdef USE_NNTP
X    if (parsed_art != artnum) {
X	ARTICLE *ap;
X	int size;
X	register ART_NUM num, priornum, lastnum;
X	bool cached;
X
X	s = fetchcache(artnum,which_line,DONT_FILL_CACHE);
X	if (s) {
X	    if (copy)
X		s = savestr(s);
X	    return s;
X	}
X
X	spin(20);
X	if (copy)
X	    s = safemalloc((MEM_SIZE)(size = LBUFLEN));
X	else {
X	    s = cmd_buf;
X	    size = sizeof cmd_buf;
X	}
X	*s = '\0';
X	priornum = artnum-1;
X	if ((cached = (htype[which_line].ht_flags & HT_CACHED)) != 0) {
X	    lastnum = artnum + PREFETCH_SIZE - 1;
X	    if (lastnum > lastart)
X		lastnum = lastart;
X	    sprintf(ser_line,"XHDR %s %ld-%ld",htype[which_line].ht_name,
X		artnum,lastnum);
X	} else {
X	    lastnum = artnum;
X	    sprintf(ser_line,"XHDR %s %ld",htype[which_line].ht_name,artnum);
X	}
X	nntp_command(ser_line);
X	if (nntp_check(TRUE) == NNTP_CLASS_OK) {
X	    char *line, *last_buf = ser_line;
X	    MEM_SIZE last_buflen = sizeof ser_line;
X	    for (ap = find_article(artnum); ; ) {
X		line = nntp_get_a_line(last_buf,last_buflen,last_buf!=ser_line);
X# ifdef DEBUG
X		if (debug & DEB_NNTP)
X		    printf("<%s", line) FLUSH;
X# endif
X		if (NNTP_LIST_END(line))
X		    break;
X		last_buf = line;
X		last_buflen = buflen_last_line_got;
X		if ((t = index(line, '\r')) != Nullch)
X		    *t = '\0';
X		if (!(t = index(line, ' ')))
X		    continue;
X		t++;
X		num = atol(line);
X		if (num < artnum || num > lastnum)
X		    continue;
X		while (++priornum < num)
X		    uncache_article(ap++,FALSE);
X		if (which_line == SUBJ_LINE)
X		    set_subj_line(ap++, t, strlen(t));
X		else if (cached)
X		    set_cached_line(ap++, which_line, savestr(t));
X		if (num == artnum)
X		    safecat(s,t,size);
X	    }
X	    if (last_buf != ser_line)
X		free(last_buf);
X	} else {
X	    fprintf(stderr,"\nUnexpected close of server socket.\n");
X	    finalize(1);
X	}
X	while (priornum++ < lastnum)
X	    uncache_article(ap++,FALSE);
X	if (copy)
X	    s = saferealloc(s, (MEM_SIZE)strlen(s)+1);
X	return s;
X    }
X#endif /* USE_NNTP */
X
X    /* Only return a cached line if it isn't the current article */
X    s = Nullch;
X    if (parsed_art != artnum)
X	s = fetchcache(artnum,which_line,FILL_CACHE);
X    if ((firstpos = htype[which_line].ht_minpos) < 0)
X	s = nullstr;
X    if (s) {
X	if (copy)
X	    s = savestr(s);
X	return s;
X    }
X
X    firstpos += htype[which_line].ht_length + 1;
X    lastpos = htype[which_line].ht_maxpos;
X    size = lastpos - firstpos;
X    t = headbuf + firstpos;
X    while (*t == ' ' || *t == '\t') t++, size--;
X    if (copy)
X	s = safemalloc((MEM_SIZE)size);
X    else {				/* hope this is okay--we're */
X	s = cmd_buf;			/* really scraping for space here */
X	if (size > sizeof cmd_buf)
X	    size = sizeof cmd_buf;
X    }
X    *s = '\0';
X    safecat(s,t,size);
X    return s;
X}
SHAR_EOF
  $shar_touch -am 1025184394 'trn-3.6/head.c' &&
  chmod 0644 'trn-3.6/head.c' ||
  echo 'restore of trn-3.6/head.c failed'
  shar_count="`wc -c < 'trn-3.6/head.c'`"
  test 10778 -eq "$shar_count" ||
    echo "trn-3.6/head.c: original size 10778, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/head.h ==============
if test -f 'trn-3.6/head.h' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/head.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/head.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/head.h' &&
X/* $Id: head.h,v 3.0 1992/02/01 03:09:32 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#define HEAD_FIRST 1
X
X/* types of header lines (if only C really believed in enums)
X * (These must stay in alphabetic order at least in the first letter.
X * Within each letter it helps to arrange in increasing likelihood.)
X */
X
X#define PAST_HEADER	0			/* body */
X#define SOME_LINE	(PAST_HEADER+1)		/* unrecognized */
X#define ARTID_LINE	(SOME_LINE+1)		/* article-i.d. */
X#define APPR_LINE	(ARTID_LINE+1)		/* approved */
X#define ACAT_LINE	(APPR_LINE+1)		/* ACategory (ClariNet) */
X#define ANPA_LINE	(ACAT_LINE+1)		/* ANPA (ClariNet) */
X#define CODES_LINE	(ANPA_LINE+1)		/* Codes (ClariNet) */
X#define CONTENT_LINE	(CODES_LINE+1)		/* Content-Type (MIME) */
X#define CONTXFER_LINE	(CONTENT_LINE+1)	/* Content-Transfer-Encoding */
X#define CANCEL_LINE	(CONTXFER_LINE+1)	/* cancel */
X#define DIST_LINE	(CANCEL_LINE+1)		/* distribution */
X#define DATE_LINE	(DIST_LINE+1)		/* date */
X#define RECEIVED_LINE	(DATE_LINE+1)		/* date-received */
X#define EXPIR_LINE	(RECEIVED_LINE+1)	/* expires */
X#define FOLLOW_LINE	(EXPIR_LINE+1)		/* followup-to */
X#define FROM_LINE	(FOLLOW_LINE+1)		/* from */
X#define FORM_LINE	(FROM_LINE+1)		/* Format (ClariNet) */
X#define KEYW_LINE	(FORM_LINE+1)		/* keywords */
X#define LINES_LINE	(KEYW_LINE+1)		/* lines */
X#define MESSID_LINE	(LINES_LINE+1)		/* message-id */
X#define NFFR_LINE	(MESSID_LINE+1)		/* nf-from */
X#define NFID_LINE	(NFFR_LINE+1)		/* nf-id */
X#define NGS_LINE	(NFID_LINE+1)		/* newsgroups */
X#define NNTPHOST_LINE	(NGS_LINE+1)		/* nntp-posting-host */
X#define NOTE_LINE	(NNTPHOST_LINE+1)	/* Note (ClariNet) */
X#define ORG_LINE	(NOTE_LINE+1)		/* organization */
X#define PATH_LINE	(ORG_LINE+1)		/* path */
X#define POSTED_LINE	(PATH_LINE+1)		/* posted */
X#define PVER_LINE	(POSTED_LINE+1)		/* posting-version */
X#define PRI_LINE	(PVER_LINE+1)		/* Priority (ClariNet) */
X#define REPLY_LINE	(PRI_LINE+1)		/* reply-to */
X#define REFS_LINE	(REPLY_LINE+1)		/* references */
X#define RVER_LINE	(REFS_LINE+1)		/* relay-version */
X#define SENDER_LINE	(RVER_LINE+1)		/* sender */
X#define SUMRY_LINE	(SENDER_LINE+1)		/* summary */
X#define SUBJ_LINE	(SUMRY_LINE+1)		/* subject */
X#define SUPR_LINE	(SUBJ_LINE+1)		/* supersedes */
X#define SLUG_LINE	(SUPR_LINE+1)		/* Slugword (ClariNet) */
X#define XREF_LINE	(SLUG_LINE+1)		/* xref */
X#define XSUP_LINE	(XREF_LINE+1)		/* X-Supersedes (ClariNet) */
X#define HEAD_LAST	(XSUP_LINE+1)		/* total # of headers */
X
Xstruct headtype {
X    char *ht_name;		/* header line identifier */
X    ART_POS ht_minpos;		/* pointer to beginning of line in article */
X    ART_POS ht_maxpos;		/* pointer to end of line in article */
X    char ht_length;		/* could make these into nybbles but */
X    char ht_flags;		/* it wouldn't save space normally */
X};				/* due to alignment considerations */
X
X#define HT_HIDE   1	/* -h on this line */
X#define HT_MAGIC  2	/* do any special processing on this line */
X#define HT_CACHED 4	/* this information is cached in the article data */
X
X/* This array must stay in the same order as the list above */
X
X#ifndef DOINIT
XEXT struct headtype htype[HEAD_LAST];
X#else
Xstruct headtype htype[HEAD_LAST] = {
X /* name             minpos   maxpos  length   flag */
X    {"BODY",		0,	0,	4,	0		},
X    {"unrecognized",	0,	0,	12,	0		},
X    {"article-i.d.",	0,	0,	12,	HT_HIDE		},
X    {"approved",	0,	0,	8,	HT_HIDE		},
X    {"acategory",	0,	0,	9,	HT_HIDE		},
X    {"anpa",		0,	0,	4,	HT_HIDE		},
X    {"codes",		0,	0,	5,	HT_HIDE		},
X#if defined(MIMESHOW) || defined(MIMESTORE)
X    {"content-type",	0,	0,	12,	HT_MAGIC	},
X    {"content-transfer-encoding",
X			0,	0,	25,	HT_MAGIC	},
X#else
X    {"content-type",	0,	0,	12,	0		},
X    {"content-transfer-encoding",
X			0,	0,	25,	0		},
X#endif
X    {"control",		0,	0,	7,	0		},
X    {"distribution",	0,	0,	12,	0		},
X    {"date",		0,	0,	4,	HT_MAGIC	},
X    {"date-received",	0,	0,	13,	0		},
X    {"expires",		0,	0,	7,	HT_HIDE|HT_MAGIC},
X    {"followup-to",	0,	0,	11,	0		},
X    {"from",		0,	0,	4,	HT_CACHED	},
X    {"format",		0,	0,	6,	HT_HIDE		},
X    {"keywords",	0,	0,	8,	0		},
X    {"lines",		0,	0,	5,	0		},
X    {"message-id",	0,	0,	10,	HT_HIDE|HT_CACHED},
X    {"nf-from",		0,	0,	7,	HT_HIDE		},
X    {"nf-id",		0,	0,	5,	HT_HIDE		},
X#ifdef DBM_XREFS
X    {"newsgroups",	0,	0,	10,	HT_MAGIC|HT_HIDE|HT_CACHED},
X#else
X    {"newsgroups",	0,	0,	10,	HT_MAGIC|HT_HIDE},
X#endif
X    {"nntp-posting-host",0,	0,	17,	HT_HIDE		},
X    {"note",		0,	0,	4,	0,		},
X    {"organization",	0,	0,	12,	0		},
X    {"path",		0,	0,	4,	HT_HIDE		},
X    {"posted",		0,	0,	6,	HT_HIDE		},
X    {"posting-version",	0,	0,	15,	HT_HIDE		},
X    {"priority",	0,	0,	8,	HT_HIDE		},
X    {"reply-to",	0,	0,	8,	HT_HIDE		},
X    {"references",	0,	0,	10,	HT_HIDE		},
X    {"relay-version",	0,	0,	13,	HT_HIDE		},
X    {"sender",		0,	0,	6,	HT_HIDE		},
X    {"summary",		0,	0,	7,	0		},
X    {"subject",		0,	0,	7,	HT_MAGIC|HT_CACHED},
X    {"supersedes",	0,	0,	10,	0		},
X    {"slugword",	0,	0,	8,	HT_HIDE		},
X#ifdef DBM_XREFS
X    {"xref",		0,	0,	4,	HT_HIDE},
X#else
X    {"xref",		0,	0,	4,	HT_HIDE|HT_CACHED},
X#endif
X    {"x-supersedes",	0,	0,	12,	HT_HIDE		}
X};
X#endif
X
XEXT ART_NUM parsed_art INIT(0);		/* the article number we've parsed */
XEXT char in_header INIT(0);		/* are we decoding the header? */
XEXT char *headbuf;
XEXT long headbuf_size;
X
Xvoid	head_init _((void));
Xint	set_line_type _((char*,char*));
Xvoid	start_header _((ART_NUM));
Xvoid	end_header_line _((void));
Xvoid	end_header _((void));
Xbool    parseline _((char*,int,int));
Xbool	parseheader _((ART_NUM));
Xchar	*fetchlines _((ART_NUM,int));	/* returns a malloc'ed string */
Xchar	*prefetchlines _((ART_NUM,int,bool_int));
X
X#ifdef DEBUG
Xvoid	dumpheader _((char*));
X#endif
X
X#ifdef USE_NNTP
X#define PREFETCH_SIZE 5
X#endif
X
X#define fetchsubj(artnum,copy) prefetchlines(artnum,SUBJ_LINE,copy)
X#define fetchfrom(artnum,copy) prefetchlines(artnum,FROM_LINE,copy)
X#ifdef DBM_XREFS
X#define fetchxref(artnum,copy) prefetchlines(artnum,NGS_LINE,copy)
X#else
X#define fetchxref(artnum,copy) prefetchlines(artnum,XREF_LINE,copy)
X#endif
SHAR_EOF
  $shar_touch -am 0402172194 'trn-3.6/head.h' &&
  chmod 0644 'trn-3.6/head.h' ||
  echo 'restore of trn-3.6/head.h failed'
  shar_count="`wc -c < 'trn-3.6/head.h'`"
  test 6564 -eq "$shar_count" ||
    echo "trn-3.6/head.h: original size 6564, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/help.c ==============
if test -f 'trn-3.6/help.c' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/help.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/help.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/help.c' &&
X/* $Id: help.c,v 3.0 1992/02/01 03:09:32 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "trn.h"
X#include "term.h"
X#include "INTERN.h"
X#include "help.h"
X
Xvoid
Xhelp_init()
X{
X    ;
X}
X
Xint
Xhelp_page()
X{
X    int cmd;
X
X#ifdef PAGERHELP
X    doshell(sh,filexp(PAGERHELP));
X#else
X    page_init();
X    if ((cmd = print_lines("\
XPaging commands:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\n\
XSP	Display the next page.\n\
Xx	Display the next page decrypted (rot13).\n\
Xd	Display half a page more.\n\
XCR	Display one more line.\n\
X^R,v,^X	Restart the current article (v=verbose header, ^X=rot13).\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xb	Back up one page.\n\
X^E	Display the last page of the article.\n\
X^L,X	Refresh the screen (X=rot13).\n\
X_C      Switch characterset conversion.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xt	Display the entire article tree and all its subjects.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xg pat	Go to (search forward within article for) pattern.\n\
XG	Search again for current pattern within article.\n\
X^G	Search for next line beginning with \"Subject:\".\n\
XTAB	Search for next line beginning with a different character.\n\
Xq	Quit the pager, go to end of article.  Leave article read or unread.\n\
Xj	Junk this article (mark it read).  Goes to end of article.\n\
X\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XThe following commands skip the rest of the current article, then behave\n\
Xjust as if typed to the 'What next?' prompt at the end of the article:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\n\
Xn	Scan forward for next unread article.\n\
XN	Go to next article.\n\
X^N	Scan forward for next unread article with same title.\n\
Xp,P,^P	Same as n,N,^N, only going backwards.\n\
X-	Go to previously displayed article.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X<, >	Browse the previous/next selected thread.  If no threads are selected,\n\
X	all threads that had unread news upon entry to the group are considered\n\
X	selected for browsing.  Entering an empty group browses all threads.\n\
X[, ]	Go to article's parent/child (try left-/right-arrow also).\n\
X(, )	Go to article's previous/next sibling (try up-/down-arrow also).\n\
X{, }	Go to tree's root/leaf.\n\
X\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XThe following commands also take you to the end of the article.\n\
XType h at end of article for a description of these commands:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\
X	# $ & / = ? c C f F k K ^K J , m M number e r R ^R s S u U v w W Y ^ |\n\
X\n\
X(To return to the middle of the article after one of these commands, type ^L.)\n\
X",NOMARKING)) )
X	return cmd;
X#endif
X    return 0;
X}
X
Xint
Xhelp_art()
X{
X    int cmd;
X#ifdef ARTHELP
X    doshell(sh,filexp(ARTHELP));
X#else
X    page_init();
X    if ((cmd = print_lines("\
XArticle Selection commands:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\n\
Xn,SP	Find next unread article (follows discussion-tree in threaded groups).\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XN	Go to next article.\n\
X^N	Scan forward for next unread article with same subject in date order.\n\
Xp,P,^P	Same as n,N,^N, only going backwards.\n\
X_N,_P	Go to the next/previous article numerically.\n\
X-	Go to previously displayed article.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X<, >	Browse the previous/next selected thread.  If no threads are selected,\n\
X	all threads that had unread news upon entry to the group are considered\n\
X	selected for browsing.  Entering an empty group browses all threads.\n\
X[, ]	Go to article's parent/child (try left-/right-arrow also).\n\
X(, )	Go to article's previous/next sibling (try up-/down-arrow also).\n\
X{, }	Go to tree's root/leaf.\n\
Xt	Display the entire article tree and all its subjects.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xnumber	Go to specified article.\n\
Xrange{,range}:command{:command}\n\
X	Apply one or more commands to one or more ranges of articles.\n\
X	Ranges are of the form: number | number-number.  You may use . for\n\
X	the current article, and $ for the last article.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X 	Valid commands are: e, j, m, M, s, S, t, T, |, +, ++, -, and --.\n\
X:cmd	Perform a command on all the selected articles.\n\
X::cmd	Perform a command on all non-selected articles.\n\
X:.cmd	Perform a command on the current thread or its selected articles.\n\
X::.cmd	Perform a command on the unselected articles in the current thread.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X/pattern/modifiers\n\
X	Scan forward for article containing pattern in the subject line.\n\
X	(Use ?pat? to scan backwards; append f to scan from lines, h to scan\n\
X	whole headers, a to scan entire articles, r to scan read articles, c\n\
X	to make case-sensitive, t to scan from the top of the group.)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X/pattern/modifiers:command{:command}\n\
X	Apply one or more commands to the set of articles matching pattern.\n\
X	Use a K modifier to save entire command to the KILL file for this\n\
X	newsgroup.  Commands m and M, if first, imply an r modifier.\n\
X 	Valid commands are the same as for the range command.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xf,F	Submit a followup article (F = include this article).\n\
Xr,R	Reply through net mail (R = include this article).\n\
X^F	Forward article through net mail.\n\
Xe dir{|command}\n\
X	Extract to directory using /bin/sh, uudecode, unship, or command.\n\
Xs ...	Save to file or pipe via sh.\n\
XS ...	Save via preferred shell.\n\
Xw,W	Like s and S but save without the header.\n\
X| ...	Same as s|...\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XC	Cancel this article, if yours.\n\
X^R,v	Restart article (v=verbose).\n\
X^X	Restart article, rot13 mode.\n\
X_C      Switch characterset conversion.\n\
Xc	Catch up (mark all articles as read).\n\
Xb	Back up one page.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X^E	Display the last page of the article.\n\
X^L	Refresh the screen.  You can get back to the pager with this.\n\
XX	Refresh screen in rot13 mode.\n\
X^	Go to first unread article.  Disables subject search mode.\n\
X$	Go to end of newsgroup.  Disables subject search mode.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("#       Print last article number.\n\
X&	Print current values of command-line switches.\n\
X&switch {switch}\n\
X	Set or unset more switches.\n\
X&&	Print current macro definitions.\n\
X&&def	Define a new macro.\n\
Xj	Junk this article (mark it read).  Stays at end of article.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xm	Mark article as still unread.\n\
XM	Mark article as read but to-return on group exit or Y command.\n\
XY	Yank back articles marked as to-return via the M command.\n\
Xk	Kill current subject (mark articles as read).\n\
X,	Mark current article and its replies as read.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XJ	Junk entire thread (mark all subjects as read in this thread).\n\
XA	Add current subject to memorized commands (selection or killing).\n\
XT	Add current (sub)thread to memorized commands (selection or killing).\n\
XK	Mark current subject as read, and save command in KILL file.\n\
X^K	Edit local KILL file (the one for this newsgroup).\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X=	List subjects of unread articles.\n\
X+	Start the selector in whatever mode it was last in.\n\
X_a	Start the article selector.\n\
X_s	Start the subject selector.\n\
X_t	Start the thread selector.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X_T	Start the thread selector if threaded, else the subject selector.\n\
XU	Unread some news -- prompts for thread, subthread, all, or select.\n\
Xu	Unsubscribe from this newsgroup.\n\
Xq	Quit this newsgroup for now.\n\
XQ	Quit newsgroup, staying at current newsgroup.\n\
X",NOMARKING)) )
X	return cmd;
X#endif
X    return 0;
X}
X
Xint
Xhelp_ng()
X{
X    int cmd;
X#ifdef NGHELP
X    doshell(sh,filexp(NGHELP));
X#else
X    page_init();
X    if (cmd = print_lines("\
XNewsgroup Selection commands:\n\
X",STANDOUT) )
X	return cmd;
X    if (ng != nextrcline) {
X	if ((cmd = print_lines("\
X\n\
Xy	Do this newsgroup now.\n\
XSP	Do this newsgroup, executing the default command listed in []'s.\n\
X.cmd	Do this newsgroup, executing cmd as first command.\n\
X+	Enter this newsgroup through the selector (like typing .+<CR>).\n\
X=	Start this newsgroup, but list subjects before reading articles.\n\
XU	Enter this newsgroup by way of the \"Set unread?\" prompt.\n\
Xu	Unsubscribe from this newsgroup.\n\
X",NOMARKING)) )
X	    return cmd;
X    }
X    if ((cmd = print_lines("\
Xt	Toggle the newsgroup between threaded and unthreaded reading.\n\
Xc	Catch up (mark all articles as read).\n\
XA	Abandon read/unread changes to this newsgroup since you started trn.\n\
Xn	Go to the next newsgroup with unread news.\n\
XN	Go to the next newsgroup.\n\
Xp	Go to the previous newsgroup with unread news.\n\
XP	Go to the previous newsgroup.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X-	Go to the previously displayed newsgroup.\n\
X1	Go to the first newsgroup.\n\
X^	Go to the first newsgroup with unread news.\n\
X$	Go to the end of newsgroups.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xg name	Go to the named newsgroup.  Subscribe to new newsgroups this way too.\n\
X/pat	Search forward for newsgroup matching pattern.\n\
X?pat	Search backward for newsgroup matching pattern.\n\
X	(Use * and ? style patterns.  Append r to include read newsgroups.)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xl pat	List unsubscribed newsgroups containing pattern.\n\
Xm name	Move named newsgroup elsewhere (no name moves current newsgroup).\n\
Xo pat	Only display newsgroups matching pattern.  Omit pat to unrestrict.\n\
XO pat	Like o, but skip empty groups.\n\
Xa pat	Like o, but also scans for unsubscribed newsgroups matching pattern.\n\
XL	List current .newsrc.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X&	Print current command-line switch settings.\n\
X&switch {switch}\n\
X	Set (or unset) more command-line switches.\n\
X&&	Print current macro definitions.\n\
X&&def	Define a new macro.\n\
X!cmd	Shell escape.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xq	Quit trn.\n\
Xx	Quit, restoring .newsrc to its state at startup of trn.\n\
X^K	Edit the global KILL file.  Use commands like /pattern/j to suppress\n\
X	pattern in every newsgroup.\n\
Xv	Print version and the address for reporting bugs.\n\
X",NOMARKING)) )
X	return cmd;
X#endif
X    if (cmd = get_anything())
X	return cmd;
X    show_macros();
X    return 0;
X}
X
X#ifdef ESCSUBS
Xint
Xhelp_subs()
X{
X    int cmd;
X#ifdef SUBSHELP
X    doshell(sh,filexp(SUBSHELP));
X#else
X    page_init();
X    if ((cmd = print_lines("\
XValid substitutions are:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\
X\n\
Xa	Current article number\n\
XA	Full name of current article (%P/%c/%a)\n\
Xb	Destination of last save command, often a mailbox\n\
XB	Bytes to ignore at beginning of last saved article\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xc	Current newsgroup, directory form\n\
XC	Current newsgroup, dot form\n\
Xd	Full name of newsgroup directory (%P/%c)\n\
XD	Distribution line from current article\n\
Xe	The last command executed to extract data from an article\n\
XE	The last extraction directory\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xf	Who the current article is from\n\
XF	Newsgroups to followup to (from Newsgroups and Followup-To)\n\
Xh	(This help message)\n\
XH	Host name (yours)\n\
Xi	Message-I.D. line from current article, with <>\n\
XI	Reference indicator mark (see -F switch)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xl	News administrator's login name, if any\n\
XL	Login name (yours)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xm	Current mode, first letter of (init,newsgroup,thread,article,pager,\n\
X		unread,Add,Catchup,Delete-bogus,Mailbox,Resubscribe)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XM	Number of article marked with M\n\
Xn	Newsgroups from current article\n\
XN	Full name (yours)\n\
Xo	Organization (yours)\n\
XO	Original working directory (where you ran trn from)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xp	Your private news directory (from -d)\n\
XP	Public news spool directory\n\
Xr	Last reference (parent article id)\n\
XR	References list for followup article\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xs	Subject, with all Re's and (nf)'s stripped off\n\
XS	Subject, with one Re stripped off\n\
Xt	New To line derived from From and Reply-To (Internet format)\n\
XT	New To line derived from Path\n\
Xu	Number of unread articles\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XU	Number of unread articles not counting the current article (when\n\
X	threads are selected, the count only reflects selected articles)\n\
Xv	The number of extra (unselected) articles, not counting the current\n\
X	one if it is unselected\n\
XW	Where thread files are saved\n\
Xx	News library directory\n\
XX	Trn library directory\n\
Xz	Length of current article in bytes\n\
XZ	Number of selected threads\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X~	Your home directory\n\
X.	Directory containing the \"dot\" files, such as .newsrc\n\
X#	A counter in multi-article saves\n\
X$	Current process number\n\
X/	Last search string\n\
XESC	Run preceding command through % interpretation\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XPut ^ in the middle to capitalize the first letter: %^C = Rec.humor\n\
XPut _ in the middle to capitalize the last component: %_c = rec/Humor\n\
XPut \\ in the middle to quote regexp and % characters in the resulting string\n\
XPut :FMT in the middle to format the result printf-style:  %:-30.30t\n\
X",NOMARKING)) )
X	return cmd;
X#endif
X    return 0;
X}
X#endif
X
Xint
Xhelp_select()
X{
X    int cmd;
X
X    page_init();
X    if ((cmd = print_lines("\
XSelection commands:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\n\
Xa-z,0-9	Select/deselect the indicated item by its letter or number.  Many of\n\
X	the alpha letters are omitted for the following commands.\n\
XSP	Perform the default command (usually > or Z).\n\
XCR	Start reading.  Selects the current item if nothing is selected.\n\
XZ,TAB	Start reading.  If nothing is selected, read all unread articles.\n\
X.	Toggle the current item's selection.\n\
X*	Same as '.' except that it affects all items with the same subject.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X#	Read the current item only, temporarily ignoring all other selections.\n\
Xk, ','	Mark the current item as killed.\n\
Xm, \\	Unmark the current item.\n\
X-	Set a range, as in d - f.  Repeats the last marking action.\n\
X@	Toggle the selection of all visible items.\n\
XM	Mark the current item's article(s) as to-return and kill the item.\n\
XY	Yank back and select articles marked to return via M.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XE	Toggle exclusion of non-selected items from the selection list.\n\
Xn, ]	Move down to the next item (try down-arrow also).\n\
Xp, [	Move up to the previous item (try up-arrow also).\n\
X<, >	Go to previous/next page (try left-/right-arrow also).\n\
X^, $	Go to first/last page.\n\
XS	Set what the selector displays:  threads, subjects, or articles.\n\
X	If the group is unthreaded, choosing threads will thread it.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X=	Toggle between the article and thread/subject selector.\n\
XO	Set the selector's order.  A separate default is kept for the\n\
X	article and subject/thread selector.\n\
XR	Reverse the current sort order.\n\
XL	Switch the display between a short style without authors and a\n\
X	medium or long style with authors.\n\
XU	Switch between selecting unread/read articles.\n\
XX	Mark all unselected articles as read and start reading.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XD	Mark unselected articles on the current page as read.  Start\n\
X	reading if articles were selected, else go to next page.\n\
XJ	Junk all selected articles (mark them as read).\n\
Xc	Catch up -- marks ALL articles as read without chasing xrefs.\n\
XA	Add current subject to memorized commands (selection or killing).\n\
XT	Add current thread to memorized commands (selection or killing).\n\
X^K	Edit local KILL file (the one for this newsgroup).\n\
XN	Leave this group as-is and go on to the next one.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XP	Leave this group as-is and go on to the previous one.\n\
X:cmd	Perform a command on all the selected articles (use :p to post).\n\
X::cmd	Perform a command on all non-selected articles.\n\
X:.cmd	Perform a command on the current thread or its selected articles.\n\
X::.cmd	Perform a command on the unselected articles in the current thread.\n\
X/pattern/modifiers\n\
X	Scan all articles for a subject containing pattern.\n\
X	(Append f to scan the from line, h to scan whole headers, a to scan\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X	entire articles, c to make it case-sensitive, r to scan read articles\n\
X	(assumed when you are selecting read articles to set unread.)\n\
X/pattern/modifiers:command{:command}\n\
X	Apply one or more commands to the set of articles matching pattern.\n\
X	Use a K modifier to save entire command to the KILL file for this\n\
X	newsgroup.  Commands m and M, if first, imply an r modifier.\n\
X 	Valid commands are: e, E, j, m, M, s, S, t, T, !, =, ',' and the\n\
X	article/thread (de)selection commands: +/++ (-/--).\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X&	View or set command line switches.\n\
X&&	View or set macro definitions.\n\
X!cmd	Escape to a subshell.\n\
Xh, ?	This help message.\n\
XESC, +	Leave the selector but stay in the group (at last visited article).\n\
Xq	Quit the selector and the group.\n\
XQ	Quit group and return to news group selection prompt for this group.\n\
X",NOMARKING)) )
X	return cmd;
X    return 0;
X}
SHAR_EOF
  $shar_touch -am 1118220194 'trn-3.6/help.c' &&
  chmod 0644 'trn-3.6/help.c' ||
  echo 'restore of trn-3.6/help.c failed'
  shar_count="`wc -c < 'trn-3.6/help.c'`"
  test 18041 -eq "$shar_count" ||
    echo "trn-3.6/help.c: original size 18041, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/help.h ==============
if test -f 'trn-3.6/help.h' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/help.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/help.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/help.h' &&
X/* $Id: help.h,v 3.0 1991/09/09 20:18:23 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
Xvoid	help_init _((void));
Xint	help_ng _((void));
Xint	help_art _((void));
Xint	help_page _((void));
X#ifdef ESCSUBS
Xint	help_subs _((void));
X#endif
Xint help_select _((void));
SHAR_EOF
  $shar_touch -am 0711223593 'trn-3.6/help.h' &&
  chmod 0644 'trn-3.6/help.h' ||
  echo 'restore of trn-3.6/help.h failed'
  shar_count="`wc -c < 'trn-3.6/help.h'`"
  test 821 -eq "$shar_count" ||
    echo "trn-3.6/help.h: original size 821, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/init.c ==============
if test -f 'trn-3.6/init.c' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/init.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/init.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/init.c' &&
X/* $Id: init.c,v 3.0 1992/02/01 03:09:32 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "final.h"
X#include "term.h"
X#include "last.h"
X#include "trn.h"
X#include "rcstuff.h"
X#include "ngdata.h"
X#include "only.h"
X#include "intrp.h"
X#include "addng.h"
X#include "sw.h"
X#include "art.h"
X#include "artsrch.h"
X#include "artio.h"
X#include "backpage.h"
X#include "cache.h"
X#include "bits.h"
X#include "head.h"
X#include "help.h"
X#include "kfile.h"
X#include "ngsrch.h"
X#include "ngstuff.h"
X#include "rcln.h"
X#include "respond.h"
X#include "nntp.h"
X#include "rthread.h"
X#include "ng.h"
X#include "decode.h"
X#include "INTERN.h"
X#include "init.h"
X
Xbool
Xinitialize(argc,argv)
Xint argc;
Xchar *argv[];
X{
X    char *tcbuf;
X    register bool foundany = FALSE;
X    char *s;
X#ifdef NOLINEBUF
X    static char std_out_buf[BUFSIZ];	/* must be static or malloced */
X
X    setbuf(stdout, std_out_buf);
X#endif
X
X    tcbuf = safemalloc(1024);		/* make temp buffer for termcap and */
X					/* other initialization stuff */
X    
X    our_pid = getpid();
X
X    /* init terminal */
X    
X    term_init();			/* must precede sw_init() so that */
X					/* ospeed is set for baud-rate */
X					/* switches.  Actually terminal */
X					/* mode setting is in term_set() */
X
X    /* init syntax etc. for searching (must also precede sw_init()) */
X
X    search_init();
X
X    /* we have to know rnlib to look up global switches in %X/INIT */
X
X    homedir = getenv("HOME");
X    if (homedir == Nullch)
X	homedir = getenv("LOGDIR");
X    lib = savestr(filexp(NEWSLIB));
X    rnlib = savestr(filexp(PRIVLIB));
X    tmpdir = getenv("TMPDIR");
X    if (!tmpdir) {
X	tmpdir = getenv("TMP");
X	if (!tmpdir)
X	    tmpdir = "/tmp";
X    }
X
X    /* decode switches */
X
X    sw_init(argc,argv,&tcbuf);          /* must not do % interps! */
X					/* (but may mung environment) */
X
X    /* init signals, status flags */
X
X    final_init();
X    
X    /* start up file expansion and the % interpreter */
X
X    intrp_init(tcbuf);
X    
X    /* now make sure we have a current working directory */
X
X    if (!checkflag)
X	cwd_check();
X    
X    /* now that we know where to save things, cd to news directory */
X
X    if (chdir(spool)) {
X	printf(nocd,spool) FLUSH;
X	finalize(1);
X    }
X
X    /* if we aren't just checking, turn off echo */
X
X    if (!checkflag)
X	term_set(tcbuf);
X
X    /* get info on last rn run, if any */
X
X    if (!checkflag)
X	last_init(tcbuf);
X
X    free(tcbuf);			/* recover 1024 bytes */
X
X    /* make sure we are the sole possessors of .newsrc */
X
X    if (!checkflag)
X	lock_check();
X
X    /* check for news news */
X
X    if (!checkflag)
X	newsnews_check();
X
X#ifdef USE_NNTP
X
X    /* open connection to server if appropriate */
X    if (!nntp_connect(1))
X	finalize(1);
X
X#endif
X
X    /* open active file, etc. */
X
X    ngdata_init();
X
X    /* now read in the .newsrc file */
X
X    foundany = rcstuff_init();
X
X    /* it looks like we will actually read something, so init everything */
X
X    addng_init();
X    art_init();
X    artio_init();
X    artsrch_init();
X    backpage_init();
X    bits_init();
X    cache_init();
X    head_init();
X    help_init();
X    kfile_init();
X    ng_init();
X    ngsrch_init();
X    ngstuff_init();
X    only_init();
X    rcln_init();
X    respond_init();
X    rn_init();
X    decode_init();
X    thread_init();
X    util_init();
X
X#ifdef FINDNEWNG
X	/*
X	 * Skip this check if the -q flag was given.
X	 */
X    if (!quickstart) {
X	if (find_new_groups()) {	/* did we add any new groups? */
X	    foundany = TRUE;		/* let main() know */
X	    starthere = 0;		/* start ng scan from the top */
X	}
X    }
X#endif
X    time(&lasttime);			/* remember when we inited-- */
X					/* ends up back in .rnlast */
X    writelast();			/* in fact, put it there now */
X
X#ifdef FINDNEWNG
X# ifdef ONLY
X    if (maxngtodo)			/* patterns on command line? */
X	foundany |= scanactive();
X# endif
X#endif
X
X/* xterm mouse initialization -- move somewhere different? */
X    /* values of XTERMMOUSE:  y/Y/1 -- if appropriate, use it. */
X    /*                        n/N/0 -- don't ever use it. */
X    /*                        a/A   -- always use it. */
X    s = getval("XTERMMOUSE","-");
X    if (*s == 'y' || *s == 'Y' || *s == '1') {
X	if ((s = getenv("TERM")) != Nullch && strnEQ(s,"xterm",5))
X	    use_xterm_mouse = TRUE;
X    }
X    else if (*s == 'a' || *s == 'A')
X	use_xterm_mouse = TRUE;
X    else if (*s != 'n' && *s != 'N' && *s != '0') {
X	s = argv[0];
X	/* if an 'x' is at the end, enable Xterm mouse tracking */
X	if (s[strlen(s)-1] == 'x')
X	    use_xterm_mouse = TRUE;
X    }
X    return foundany;
X}
X
X/* make sure there is no rn out there already */
X
Xvoid
Xlock_check()
X{
X    lockname = savestr(filexp(LOCKNAME));
X    if (!checkflag) {
X	int processnum = 0;
X	tmpfp = fopen(lockname,"r");
X	if (tmpfp != Nullfp) {
X	    if (fgets(buf,LBUFLEN,tmpfp))
X		processnum = atoi(buf);
X	    fclose(tmpfp);
X	}
X	if (processnum) {
X#ifdef VERBOSE
X	    IF(verbose)
X		printf("You seem to have left a trn running, process %d.\n",
X		    processnum) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		printf("Trn left running, #%d.\n", processnum) FLUSH;
X#endif
X	    if (kill(processnum, 0)) {    /* does process not exist? */
X		sleep(2);
X#ifdef VERBOSE
X		IF(verbose)
X		    fputs("\n\
XThat process does not seem to exist anymore.  The count of read articles\n\
Xmay be incorrect in the last newsgroup accessed by that other (defunct)\n\
Xprocess.\n\n",stdout) FLUSH;
X		ELSE
X#endif
X#ifdef TERSE
X		    fputs("\nProcess crashed.\n",stdout) FLUSH;
X#endif
X		if (*lastngname) {
X#ifdef VERBOSE
X		    IF(verbose)
X			printf("(The last newsgroup accessed was %s.)\n\n",
X			lastngname) FLUSH;
X		    ELSE
X#endif
X#ifdef TERSE
X			printf("(In %s.)\n\n",lastngname) FLUSH;
X#endif
X		}
X		get_anything();
X		putchar('\n') FLUSH;
X	    }
X	    else {
X#ifdef VERBOSE
X		IF(verbose)
X		    fputs("\n\
XYou may not have two copies of [t]rn running simultaneously.  Goodbye.\n\
X",stdout) FLUSH;
X		ELSE
X#endif
X#ifdef TERSE
X		    fputs("\nCan't start another.\n",stdout) FLUSH;
X#endif
X               if (bizarre)
X                 resetty();
X		exit(0);
X	    }
X	}
X	tmpfp = fopen(lockname,"w");
X	if (tmpfp == Nullfp) {
X	    printf(cantcreate,lockname) FLUSH;
X	    sig_catcher(0);
X	}
X	fprintf(tmpfp,"%ld\n",our_pid);
X	fclose(tmpfp);
X    }
X}
X
Xvoid
Xnewsnews_check()
X{
X    char *newsnewsname = filexp(NEWSNEWSNAME);
X
X    if ((tmpfp = fopen(newsnewsname,"r")) != Nullfp) {
X	fstat(fileno(tmpfp),&filestat);
X	if (filestat.st_mtime > lasttime) {
X	    while (fgets(buf,sizeof(buf),tmpfp) != Nullch)
X		fputs(buf,stdout) FLUSH;
X	    get_anything();
X	    putchar('\n') FLUSH;
X	}
X	fclose(tmpfp);
X    }
X}
SHAR_EOF
  $shar_touch -am 1017161694 'trn-3.6/init.c' &&
  chmod 0644 'trn-3.6/init.c' ||
  echo 'restore of trn-3.6/init.c failed'
  shar_count="`wc -c < 'trn-3.6/init.c'`"
  test 7130 -eq "$shar_count" ||
    echo "trn-3.6/init.c: original size 7130, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/init.h ==============
if test -f 'trn-3.6/init.h' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/init.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/init.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/init.h' &&
X/* $Id: init.h,v 3.0 1991/09/09 20:18:23 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
XEXT char *lockname INIT(nullstr);
XEXT long our_pid;
X
Xbool	initialize _((int,char**));
Xvoid	lock_check _((void));
Xvoid	newsnews_check _((void));
SHAR_EOF
  $shar_touch -am 0711223593 'trn-3.6/init.h' &&
  chmod 0644 'trn-3.6/init.h' ||
  echo 'restore of trn-3.6/init.h failed'
  shar_count="`wc -c < 'trn-3.6/init.h'`"
  test 793 -eq "$shar_count" ||
    echo "trn-3.6/init.h: original size 793, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/intrp.c ==============
if test -f 'trn-3.6/intrp.c' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/intrp.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/intrp.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/intrp.c' &&
X/* $Id: intrp.c,v 3.0 1992/02/01 03:09:32 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "util2.h"
X#include "search.h"
X#include "cache.h"
X#include "bits.h"
X#include "head.h"
X#include "trn.h"
X#include "artsrch.h"
X#include "ng.h"
X#include "ngdata.h"
X#include "respond.h"
X#include "rcstuff.h"
X#include "artio.h"
X#include "init.h"
X#include "term.h"
X#include "final.h"
X#include "rthread.h"
X#include "rt-select.h"
X#include "rt-util.h"
X#include "nntp.h"
X#include "INTERN.h"
X#include "intrp.h"
X
Xstatic char * regexp_specials = "^$.*[\\/?%";
X
Xchar orgname[] = ORGNAME;
X
X#ifdef HAS_UNAME
X#include <sys/utsname.h>
Xstruct utsname utsn;
X#endif
X
X#ifdef TILDENAME
Xstatic char *tildename = Nullch;
Xstatic char *tildedir = Nullch;
X#endif
X
X#ifdef CONDSUB
XCOMPEX cond_compex;
Xchar *skipinterp _((char *,char *));
X#endif
X
Xstatic void abort_interp _((void));
X
Xvoid
Xintrp_init(tcbuf)
Xchar *tcbuf;
X{
X    char *getlogin();
X
X#ifdef CONDSUB
X    init_compex(&cond_compex);
X#endif
X    
X    /* get environmental stuff */
X
X#ifdef NEWS_ADMIN
X    {
X#ifdef HAS_GETPWENT
X	struct passwd *getpwnam();
X	struct passwd *pwd = getpwnam(NEWS_ADMIN);
X
X	if (pwd != NULL)
X	    newsuid = pwd->pw_uid;
X#else
X#ifdef TILDENAME
X	char tildenews[2+sizeof NEWS_ADMIN];
X	strcpy(tildenews, "~");
X	strcat(tildenews, NEWS_ADMIN);
X	(void) filexp(tildenews);
X#else
X	??? "Define either HAS_GETPWENT or TILDENAME to get NEWS_ADMIN"
X#endif  /* TILDENAME */
X#endif	/* HAS_GETPWENT */
X    }
X#endif	/* NEWS_ADMIN */
X    /* get home directory */
X
X    homedir = getenv("HOME");
X    if (homedir == Nullch)
X	homedir = getenv("LOGDIR");
X
X    dotdir = getval("DOTDIR",homedir);
X
X    /* get login name */
X
X    loginName = getenv("USER");
X    if (loginName == Nullch) {
X	loginName = getenv("LOGNAME");
X#ifdef GETLOGIN
X	if (loginName == Nullch)
X	    loginName = savestr(getlogin());
X#endif
X    }
X
X    spool = savestr(filexp(NEWSSPOOL));	/* usually /usr/spool/news */
X    threaddir = filexp(THREAD_DIR);
X    if (strEQ(threaddir,spool))
X	threaddir = spool;
X    else
X	threaddir = savestr(threaddir);
X    overviewdir = filexp(OVERVIEW_DIR);
X    if (strEQ(overviewdir,spool))
X	overviewdir = spool;
X    else
X	overviewdir = savestr(overviewdir);
X
X#ifdef NEWS_ADMIN
X    /* if this is the news admin then load his UID into newsuid */
X
X    if (strEQ(loginName,NEWS_ADMIN))
X	newsuid = getuid();
X#endif
X
X    if (checkflag)			/* that getwd below takes ~1/3 sec. */
X	return;				/* and we do not need it for -c */
X    getwd(tcbuf);			/* find working directory name */
X    origdir = savestr(tcbuf);		/* and remember it */
X
X    /* get the real name of the person (%N) */
X    /* Must be done after loginName is read in because BERKNAMES uses that */
X
X    strcpy(tcbuf,getrealname((long)getuid()));
X    realname = savestr(tcbuf);
X
X    /* name of header file (%h) */
X
X    headname = savestr(filexp(HEADNAME));
X
X    /* host name that goes in postings (%H) */
X
X    phostname = PHOSTNAME;
X    if (*phostname == '/' || *phostname == '~') {
X	phostname = filexp(phostname);
X	if ((tmpfp = fopen(phostname,"r")) == NULL) {
X	    printf("Warning: Couldn't open %s to determine hostname!\n",
X		   phostname); 
X	    sig_catcher(0);
X	}
X	fgets(buf, sizeof(buf), tmpfp);
X	if (buf[strlen(buf)-1] == '\n')
X	    buf[strlen(buf)-1] = 0;
X	fclose(tmpfp);
X	phostname = savestr(buf);
X    }
X    else {
X#ifdef HAS_GETHOSTNAME
X	gethostname(buf,sizeof buf);
X#else
X# ifdef HAS_UNAME
X	/* get sysname */
X	uname(&utsn);
X	strcpy(buf,utsn.nodename);
X# else
X#  ifdef PHOSTCMD
X       {
X	FILE *popen();
X	FILE *pipefp = popen(PHOSTCMD,"r");
X	
X	if (pipefp == Nullfp) {
X	    printf("Can't find hostname\n");
X	    sig_catcher(0);
X	}
X	fgets(buf,sizeof buf,pipefp);
X	buf[strlen(buf)-1] = '\0';	/* wipe out newline */
X	pclose(pipefp);
X       }
X#  else
X	*buf = '\0';
X#  endif /* PHOSTCMD */
X# endif /* HAS_UNAME */
X#endif /* HAS_GETHOSTNAME */
X	if (*buf) {
X	    if (*phostname == '.' && phostname[1]) {
X		strcat(buf,phostname);
X	    }
X	    phostname = savestr(buf);
X	}
X    }
X}
X
X/* expand filename via %, ~, and $ interpretation */
X/* returns pointer to static area */
X/* Note that there is a 1-deep cache of ~name interpretation */
X
Xchar *
Xfilexp(s)
Xregister char *s;
X{
X    static char filename[CBUFLEN];
X    char scrbuf[CBUFLEN];
X    register char *d;
X
X#ifdef DEBUG
X    if (debug & DEB_FILEXP)
X	printf("< %s\n",s) FLUSH;
X#endif
X    interp(filename, (sizeof filename), s);	
X					/* interpret any % escapes */
X#ifdef DEBUG
X    if (debug & DEB_FILEXP)
X	printf("%% %s\n",filename) FLUSH;
X#endif
X    s = filename;
X    if (*s == '~') {	/* does destination start with ~? */
X	if (!*(++s) || *s == '/') {
X	    sprintf(scrbuf,"%s%s",homedir,s);
X				/* swap $HOME for it */
X#ifdef DEBUG
X    if (debug & DEB_FILEXP)
X	printf("~ %s\n",scrbuf) FLUSH;
X#endif
X	    strcpy(filename,scrbuf);
X	}
X	else {
X#ifdef TILDENAME
X	    for (d=scrbuf; isalnum(*s); s++,d++)
X		*d = *s;
X	    *d = '\0';
X	    if (tildedir && strEQ(tildename,scrbuf)) {
X		strcpy(scrbuf,tildedir);
X		strcat(scrbuf, s);
X		strcpy(filename, scrbuf);
X#ifdef DEBUG
X		if (debug & DEB_FILEXP)
X		    printf("r %s %s\n",tildename,tildedir) FLUSH;
X#endif
X	    }
X	    else {
X		if (tildename) {
X		    free(tildename);
X		    free(tildedir);
X		}
X		tildedir = Nullch;
X		tildename = savestr(scrbuf);
X#ifdef HAS_GETPWENT	/* getpwnam() is not the paragon of efficiency */
X		{
X#ifdef notdef
X		    struct passwd *getpwnam _((char*));
X#endif
X		    struct passwd *pwd = getpwnam(tildename);
X		    if (pwd == NULL) {
X			printf("%s is an unknown user. Using default.\n",tildename) FLUSH;
X			return Nullch;
X		    }
X		    sprintf(scrbuf,"%s%s",pwd->pw_dir,s);
X		    tildedir = savestr(pwd->pw_dir);
X		    strcpy(filename,scrbuf);
X		    endpwent();
X		}
X#else			/* this will run faster, and is less D space */
X		{	/* just be sure LOGDIRFIELD is correct */
X		    FILE *pfp = fopen("/etc/passwd","r");
X		    char tmpbuf[512];
X		    int i;
X		    
X		    if (pfp == Nullfp) {
X			printf(cantopen,"passwd") FLUSH;
X			sig_catcher(0);
X		    }
X		    while (fgets(tmpbuf,512,pfp) != Nullch) {
X			d = cpytill(scrbuf,tmpbuf,':');
X#ifdef DEBUG
X			if (debug & DEB_FILEXP)
X			    printf("p %s\n",tmpbuf) FLUSH;
X#endif
X			if (strEQ(scrbuf,tildename)) {
X			    for (i=LOGDIRFIELD-2; i; i--) {
X				if (d)
X				    d = index(d+1,':');
X			    }
X			    if (d) {
X				cpytill(scrbuf,d+1,':');
X				tildedir = savestr(scrbuf);
X				strcat(scrbuf,s);
X				strcpy(filename,scrbuf);
X			    }
X			    break;
X			}
X		    }
X		    fclose(pfp);
X		}
X#endif
X	    }
X#else /* !TILDENAME */
X#ifdef VERBOSE
X	    IF(verbose)
X		fputs("~loginname not implemented.\n",stdout) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		fputs("~login not impl.\n",stdout) FLUSH;
X#endif
X#endif
X	}
X    }
X    else if (*s == '$') {	/* starts with some env variable? */
X	d = scrbuf;
X	*d++ = '%';
X	if (s[1] == '{')
X	    strcpy(d,s+2);
X	else {
X	    *d++ = '{';
X	    for (s++; isalnum(*s); s++) *d++ = *s;
X				/* skip over token */
X	    *d++ = '}';
X	    strcpy(d,s);
X	}
X#ifdef DEBUG
X	if (debug & DEB_FILEXP)
X	    printf("$ %s\n",scrbuf) FLUSH;
X#endif
X	interp(filename, (sizeof filename), scrbuf);
X					/* this might do some extra '%'s but */
X					/* that is how the Mercedes Benz */
X    }
X#ifdef DEBUG
X    if (debug & DEB_FILEXP)
X	printf("> %s\n",filename) FLUSH;
X#endif
X    return filename;
X}
X
X#ifdef CONDSUB
X/* skip interpolations */
X
Xchar *
Xskipinterp(pattern,stoppers)
Xregister char *pattern;
Xchar *stoppers;
X{
X
X    while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
X#ifdef DEBUG
X	if (debug & DEB_INTRP)
X	    printf("skipinterp till %s at %s\n",stoppers?stoppers:"",pattern);
X#endif
X	if (*pattern == '%' && pattern[1]) {
X	switch_again:
X	    switch (*++pattern) {
X	    case '^':
X	    case '_':
X	    case '\\':
X	    case '\'':
X	    case '>':
X	    case ')':
X		goto switch_again;
X	    case ':':
X		pattern++;
X		while (*pattern
X		 && (*pattern=='.' || *pattern=='-' || isdigit(*pattern))) {
X		    pattern++;
X		}
X		pattern--;
X		goto switch_again;
X	    case '{':
X		for (pattern++; *pattern && *pattern != '}'; pattern++)
X		    if (*pattern == '\\')
X			pattern++;
X		break;
X	    case '[':
X		for (pattern++; *pattern && *pattern != ']'; pattern++)
X		    if (*pattern == '\\')
X			pattern++;
X		break;
X#ifdef CONDSUB
X	    case '(': {
X		pattern = skipinterp(pattern+1,"!=");
X		if (!*pattern)
X		    goto getout;
X		for (pattern++; *pattern && *pattern != '?'; pattern++)
X		    if (*pattern == '\\')
X			pattern++;
X		if (!*pattern)
X		    goto getout;
X		pattern = skipinterp(pattern+1,":)");
X		if (*pattern == ':')
X		    pattern = skipinterp(pattern+1,")");
X		break;
X	    }
X#endif
X#ifdef BACKTICK
SHAR_EOF
  : || echo 'restore of trn-3.6/intrp.c failed'
fi
echo 'End of archive part 4'
echo 'File trn-3.6/intrp.c is continued in part 5'
echo 5 > _sharseq.tmp
exit 0


