v23i073: TRN, version of RN that follows conversation threads, Part14/14

Rich Salz rsalz at bbn.com
Tue Dec 4 07:28:28 AEST 1990


Submitted-by: Wayne Davison <davison at dri.com>
Posting-number: Volume 23, Issue 73
Archive-name: trn/part14

---- Cut Here and unpack ----
#!/bin/sh
# this is part 14 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file term.c continued
#
CurArch=14
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file term.c"
sed 's/^X//' << 'SHAR_EOF' >> term.c
X	    putchar('^');
X	    putchar(*s | 64);
X	}
X	else
X	    putchar(*s);
X    }
X}
X
X#if defined(CLEAREOL) || defined(USETHREADS)
Xvoid
Xhome_cursor()
X{
X    char *tgoto();
X
X    if (!*HO) {			/* no home sequence? */
X	if (!*CM) {		/* no cursor motion either? */
X	    fputs ("\n\n\n", stdout);
X	    return;		/* forget it. */
X	}
X	tputs (tgoto (CM, 0, 0), 1, putchr);	/* go to home via CM */
X	return;
X    }
X    else {			/* we have home sequence */
X	tputs (HO, 1, putchr);	/* home via HO */
X    }
X}
X#endif
X
X#ifdef USETHREADS
Xvoid
Xgoto_line(from,to)	/* assumes caller is already at beginning of line */
Xint from,to;
X{
X    char *tgoto(), *str;
X    int cmcost;
X
X    if (from == to) {
X	return;
X    }
X    if (*CM) {
X	cmcost = strlen(str = tgoto(CM,0,to));
X    } else {
X	cmcost = 9999;
X    }
X    if (to > from) {
X      go_down:
X	if (to - from <= cmcost) {
X	    while(from++ < to) {
X		putchar('\n');
X	    }
X	    return;
X	}
X    } else if(*UP) {
X	if ((from - to) * upcost <= cmcost) {
X	    while(from-- > to) {
X		tputs(UP,1,putchr);
X	    }
X	    return;
X	}
X    } else if (cmcost == 9999) {
X	home_cursor();
X	from = 0;
X	goto go_down;
X    }
X    tputs(str,1,putchr);
X}
X#endif
X
X
Xvoid
Xline_col_calcs()
X{
X     if (LINES > 0) {			/* is this a crt? */
X	  if ((!initlines) || (!initlines_specified))
X	       /* no -i or unreasonable value for initlines */
X	       if (ospeed >= B9600) 	/* whole page at >= 9600 baud */
X		    initlines = LINES;
X	       else if (ospeed >= B4800)/* 16 lines at 4800 */
X		    initlines = 16;
X	       else			/* otherwise just header */
X		    initlines = 8;
X     }
X     else {				/* not a crt */
X	  LINES = 30000;		/* so don't page */
X	  CL = "\n\n";			/* put a couple of lines between */
X	  if ((!initlines) || (!initlines_specified))
X	       /* make initlines reasonable */
X	       initlines = 8;
X     }
X     if (COLS <= 0)
X	  COLS = 80;
X}
X
X
X#ifdef SIGWINCH
Xint
Xwinch_catcher()
X{
X     /* Come here if window size change signal received */
X#ifdef TIOCGWINSZ
X     struct winsize ws;
X
X     if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
X          LINES = ws.ws_row;
X          COLS = ws.ws_col;
X          line_col_calcs();
X     }
X#else
X     ???????
X     /* Well, if SIGWINCH is defined, but TIOCGWINSZ isn't, there's    */
X     /* almost certainly something wrong.  Figure it out for yourself, */
X     /* because I don't know now to deal :-)                           */
X#endif
X}
X#endif
SHAR_EOF
echo "File term.c is complete"
chmod 0660 term.c || echo "restore of term.c fails"
echo "x - extracting term.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > term.h &&
X/* $Header: term.h,v 4.3.3.1 90/06/20 22:40:34 davison Trn $
X *
X * $Log:	term.h,v $
X * Revision 4.3.3.1  90/06/20  22:40:34  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.2  90/04/06  20:35:34  sob
X * Added fixes for SCO Xenix sent by ronald at robobar.co.uk.
X * 
X * Revision 4.3.2.1  89/11/28  01:54:03  sob
X * Added better support for SIGWINCH.
X * 
X * Revision 4.3.1.2  85/05/13  15:52:05  lwall
X * Declared devtty on TERMIO system.
X * 
X * Revision 4.3.1.1  85/05/10  11:41:24  lwall
X * Branch for patches.
X * 
X * Revision 4.3  85/05/01  11:51:36  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#ifdef PUSHBACK
XEXT char circlebuf[PUSHSIZE];
XEXT int nextin INIT(0);
XEXT int nextout INIT(0);
X#ifdef PENDING
X#ifdef FIONREAD
XEXT long iocount INIT(0);
X#ifndef lint
X#define input_pending() (nextin!=nextout || (ioctl(0, FIONREAD, &iocount),(int)iocount))
X#else
X#define input_pending() bizarre
X#endif /* lint */
X#else /* FIONREAD */
X#ifdef RDCHK
X#define input_pending() (rdchk(0) > 0)		/* boolean only */
X#else /*  RDCHK */
Xint circfill();
XEXT int devtty INIT(0);
X#ifndef lint
X#define input_pending() (nextin!=nextout || circfill())
X#else
X#define input_pending() bizarre
X#endif /* lint */
X#endif /* RDCHK */
X#endif /* FIONREAD */
X#else /* PENDING */
X#ifndef lint
X#define input_pending() (nextin!=nextout)
X#else
X#define input_pending() bizarre
X#endif /* lint */
X#endif /* PENDING */
X#else /* PUSHBACK */
X#ifdef PENDING
X#ifdef FIONREAD	/* must have FIONREAD or O_NDELAY for input_pending() */
X#define read_tty(addr,size) read(0,addr,size)
X#ifndef lint
X#define input_pending() (ioctl(0, FIONREAD, &iocount),(int)iocount)
X#else
X#define input_pending() bizarre
X#endif /* lint */
XEXT long iocount INIT(0);
X
X#else /* FIONREAD */
X
X#ifdef RDCHK
X#define input_pending() (rdchk(0) > 0)		/* boolean only */
X#else /*  RDCHK */
X
XEXT int devtty INIT(0);
XEXT bool is_input INIT(FALSE);
XEXT char pending_ch INIT(0);
X#ifndef lint
X#define input_pending() (is_input || (is_input=read(devtty,&pending_ch,1)))
X#else
X#define input_pending() bizarre
X#endif /* lint */
X#endif /*  RDCHK */
X#endif /* FIONREAD */
X#else /* PENDING */
X#define read_tty(addr,size) read(0,addr,size)
X#define input_pending() (FALSE)
X#endif /* PENDING */
X#endif /* PUSHBACK */
X
X/* stuff wanted by terminal mode diddling routines */
X
X#ifdef TERMIO
XEXT struct termio _tty, _oldtty;
X#else
XEXT struct sgttyb _tty;
XEXT int _res_flg INIT(0);
X#endif
X
XEXT int _tty_ch INIT(2);
XEXT bool bizarre INIT(FALSE);			/* do we need to restore terminal? */
X
X/* terminal mode diddling routines */
X
X#ifdef TERMIO
X
X#define crmode() ((bizarre=1),_tty.c_lflag &=~ICANON,_tty.c_cc[VMIN] = 1,ioctl(_tty_ch,TCSETAF,&_tty))
X#define nocrmode() ((bizarre=1),_tty.c_lflag |= ICANON,_tty.c_cc[VEOF] = CEOF,stty(_tty_ch,&_tty))
X#define echo()	 ((bizarre=1),_tty.c_lflag |= ECHO, ioctl(_tty_ch, TCSETA, &_tty))
X#define noecho() ((bizarre=1),_tty.c_lflag &=~ECHO, ioctl(_tty_ch, TCSETA, &_tty))
X#define nl()	 ((bizarre=1),_tty.c_iflag |= ICRNL,_tty.c_oflag |= ONLCR,ioctl(_tty_ch, TCSETAW, &_tty))
X#define nonl()	 ((bizarre=1),_tty.c_iflag &=~ICRNL,_tty.c_oflag &=~ONLCR,ioctl(_tty_ch, TCSETAW, &_tty))
X#define	savetty() (ioctl(_tty_ch, TCGETA, &_oldtty),ioctl(_tty_ch, TCGETA, &_tty))
X#define	resetty() ((bizarre=0),ioctl(_tty_ch, TCSETAF, &_oldtty))
X#define unflush_output()
X
X#else
X
X#define raw()	 ((bizarre=1),_tty.sg_flags|=RAW, stty(_tty_ch,&_tty))
X#define noraw()	 ((bizarre=1),_tty.sg_flags&=~RAW,stty(_tty_ch,&_tty))
X#define crmode() ((bizarre=1),_tty.sg_flags |= CBREAK, stty(_tty_ch,&_tty))
X#define nocrmode() ((bizarre=1),_tty.sg_flags &= ~CBREAK,stty(_tty_ch,&_tty))
X#define echo()	 ((bizarre=1),_tty.sg_flags |= ECHO, stty(_tty_ch, &_tty))
X#define noecho() ((bizarre=1),_tty.sg_flags &= ~ECHO, stty(_tty_ch, &_tty))
X#define nl()	 ((bizarre=1),_tty.sg_flags |= CRMOD,stty(_tty_ch, &_tty))
X#define nonl()	 ((bizarre=1),_tty.sg_flags &= ~CRMOD, stty(_tty_ch, &_tty))
X#define	savetty() (gtty(_tty_ch, &_tty), _res_flg = _tty.sg_flags)
X#define	resetty() ((bizarre=0),_tty.sg_flags = _res_flg, stty(_tty_ch, &_tty))
X#ifdef LFLUSHO
X#ifndef lint
XEXT int lflusho INIT(LFLUSHO);
X#else
XEXT long lflusho INIT(LFLUSHO);
X#endif /* lint */
X#define unflush_output() (ioctl(_tty_ch,TIOCLBIC,&lflusho))
X#else
X#define unflush_output()
X#endif /* LFLUSHO */
X#endif /* TERMIO */
X
X#ifdef TIOCSTI
X#ifdef lint
X#define forceme(c) ioctl(_tty_ch,TIOCSTI,Null(long*))	/* ghad! */
X#else
X#define forceme(c) ioctl(_tty_ch,TIOCSTI,c) /* pass character in " " */
X#endif /* lint */
X#else
X#define forceme(c)
X#endif
X
X/* termcap stuff */
X
X/*
X * NOTE: if you don't have termlib you'll either have to define these strings
X *    and the tputs routine, or you'll have to redefine the macros below
X */
X
X#ifdef HAVETERMLIB
XEXT char *BC INIT(Nullch);		/* backspace character */
XEXT char *UP INIT(Nullch);		/* move cursor up one line */
XEXT char *CR INIT(Nullch);		/* get to left margin, somehow */
XEXT char *VB INIT(Nullch);		/* visible bell */
XEXT char *CL INIT(Nullch);		/* home and clear screen */
XEXT char *CE INIT(Nullch);		/* clear to end of line */
X#ifdef CLEAREOL
XEXT char *CM INIT(Nullch);		/* cursor motion -- PWP */
XEXT char *HO INIT(Nullch);		/* home cursor -- PWP */
XEXT char *CD INIT(Nullch);		/* clear to end of display -- PWP */
X#endif /* CLEAREOL */
XEXT char *SO INIT(Nullch);		/* begin standout mode */
XEXT char *SE INIT(Nullch);		/* end standout mode */
XEXT int SG INIT(0);		/* blanks left by SO and SE */
XEXT char *US INIT(Nullch);		/* start underline mode */
XEXT char *UE INIT(Nullch);		/* end underline mode */
XEXT char *UC INIT(Nullch);		/* underline a character, if that's how it's done */
XEXT int UG INIT(0);		/* blanks left by US and UE */
XEXT bool AM INIT(FALSE);		/* does terminal have automatic margins? */
XEXT bool XN INIT(FALSE);		/* does it eat 1st newline after automatic wrap? */
XEXT char PC INIT(0);		/* pad character for use by tputs() */
XEXT short ospeed INIT(0);	/* terminal output speed, for use by tputs() */
XEXT int LINES INIT(0), COLS INIT(0);	/* size of screen */
XEXT int just_a_sec INIT(960);			/* 1 sec at current baud rate */
X					/* (number of nulls) */
X
X/* define a few handy macros */
X
X#define backspace() tputs(BC,0,putchr) FLUSH
X#define clear() tputs(CL,LINES,putchr) FLUSH
X#define erase_eol() tputs(CE,1,putchr) FLUSH
X#ifdef CLEAREOL
X#define clear_rest() tputs(CD,LINES,putchr) FLUSH	/* PWP */
X#define maybe_eol() if(erase_screen&&can_home_clear)tputs(CE,1,putchr) FLUSH
X#endif /* CLEAREOL */
X#define underline() tputs(US,1,putchr) FLUSH
X#define un_underline() tputs(UE,1,putchr) FLUSH
X#define underchar() tputs(UC,0,putchr) FLUSH
X#define standout() tputs(SO,1,putchr) FLUSH
X#define un_standout() tputs(SE,1,putchr) FLUSH
X#define up_line() tputs(UP,1,putchr) FLUSH
X#define carriage_return() tputs(CR,1,putchr) FLUSH
X#define dingaling() tputs(VB,1,putchr) FLUSH
X#else
X  ????????		/* up to you */
X#endif
X
XEXT int page_line INIT(1);	/* line number for paging in print_line (origin 1) */
X
Xvoid	term_init();
Xvoid	term_set();
X#ifdef PUSHBACK
Xvoid	pushchar();
Xvoid	mac_init();
Xvoid	mac_line();
Xvoid	show_macros();
X#endif
Xchar	putchr();	/* routine for tputs to call */
Xbool	finish_command();
Xvoid	eat_typeahead();
Xvoid	settle_down();
X#ifndef read_tty
X    int		read_tty();
X#endif
Xvoid	underprint();
X#ifdef NOFIREWORKS
X    void	no_sofire();
X    void	no_ulfire();
X#endif
Xvoid	getcmd();
Xint	get_anything();
Xvoid	in_char();
Xint	print_lines();
Xvoid	page_init();
Xvoid	pad();
Xvoid	printcmd();
Xvoid	rubout();
Xvoid	reprint();
X#if defined(CLEAREOL) || defined(USETHREADS)
Xvoid	home_cursor();
X#endif
X#ifdef USETHREADS
Xvoid	goto_line();
X#endif
X#ifdef SIGWINCH
Xint	winch_catcher();
X#endif /* SIGWINCH */
SHAR_EOF
chmod 0660 term.h || echo "restore of term.h fails"
echo "x - extracting threads.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > threads.c &&
X/* $Header: threads.c,v 4.3.3.1 90/07/21 20:33:23 davison Trn $
X**
X** $Log:	threads.c,v $
X** Revision 4.3.3.1  90/07/21  20:33:23  davison
X** Initial Trn Release
X** 
X*/
X
X#include "EXTERN.h"
X#include "common.h"
X#include "threads.h"
X
X#ifdef USETHREADS
X
X/* Change a newsgroup name into the name of the thread data file.  We
X** subsitute any '.'s in the group name into '/'s (unless LONG_THREAD_NAMES
X** is defined), prepend the path, and append the '/.thread' (or '.th') on to
X** the end.
X*/
Xchar *
Xthread_name( group )
Xchar *group;
X{
X    register char *ptr;
X    static char name_buff[256];
X#ifndef LONG_THREAD_NAMES
X    char group_buff[256];
X
X    strcpy( group_buff, group);
X    ptr = group = group_buff;
X    while( (ptr = index( ptr, '.' )) ) {
X	*ptr = '/';
X    }
X#endif
X#ifdef SUFFIX
X    sprintf( name_buff, "%s/%s%s", THREAD_DIR, group, SUFFIX );
X#else
X    sprintf( name_buff, "%s/%s", THREAD_DIR, group );
X#endif
X
X    return name_buff;
X}
X
X/* Determine this machine's byte map for WORDs and LONGs.  A byte map is an
X** array of BYTEs (sizeof (WORD) or sizeof (LONG) of them) with the 0th BYTE
X** being the byte number of the high-order byte in my <type>, and so forth.
X*/
Xvoid
Xmybytemap( map )
XBMAP *map;
X{
X    union {
X	BYTE b[sizeof (LONG)];
X	WORD w;
X	LONG l;
X    } u;
X    register BYTE *mp;
X    register int i, j;
X
X    mp = &map->w[sizeof (WORD)];
X    u.w = 1;
X    for( i = sizeof (WORD); i > 0; i-- ) {
X	for( j = 0; j < sizeof (WORD); j++ ) {
X	    if( u.b[j] != 0 ) {
X		break;
X	    }
X	}
X	if( j == sizeof (WORD) ) {
X	    goto bad_news;
X	}
X	*--mp = j;
X	while (u.b[j] != 0) {
X	    u.w <<= 1;
X	}
X    }
X
X    mp = &map->l[sizeof (LONG)];
X    u.l = 1;
X    for( i = sizeof (LONG); i > 0; i-- ) {
X	for( j = 0; j < sizeof (LONG); j++ ) {
X	    if( u.b[j] != 0 ) {
X		break;
X	    }
X	}
X	if( j == sizeof (LONG) ) {
X	  bad_news:
X	    /* trouble -- set both to *something* consistent */
X	    for( j = 0; j < sizeof (WORD); j++ ) {
X		map->w[j] = j;
X	    }
X	    for( j = 0; j < sizeof (LONG); j++ ) {
X		map->l[j] = j;
X	    }
X	    return;
X	}
X	*--mp = j;
X	while (u.b[j] != 0) {
X	    u.l <<= 1;
X	}
X    }
X}
X
X#endif /* USETHREADS */
SHAR_EOF
chmod 0660 threads.c || echo "restore of threads.c fails"
echo "x - extracting threads.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > threads.h &&
X/* $Header: threads.h,v 4.3.3.1 90/06/20 22:56:18 davison Trn $
X**
X** $Log:	threads.h,v $
X** Revision 4.3.3.1  90/06/20  22:56:18  davison
X** Initial Trn Release
X** 
X*/
X
Xtypedef char		BYTE;
Xtypedef short		WORD;
Xtypedef long		LONG;
X
X#define ROOT_ARTICLE	0x0001		/* article flag definitions */
X#define NEW_ARTICLE	0x0002		/* to avoid stat'ing new articles */
X
Xtypedef struct Article {
X    ART_NUM num;
X    char *id;
X    struct Domain *domain;
X    struct Subject *subject;
X    struct Author *author;
X    struct Article *parent, *children, *siblings;
X    struct Root *root;
X    struct Article *id_link;
X    time_t date;
X    WORD child_cnt;
X    WORD flags;
X    WORD seq;
X} ARTICLE;
X
Xtypedef struct Domain {
X    char *name;
X    ARTICLE *ids;
X    struct Domain *link;
X} DOMAIN;
X
Xtypedef struct Author {
X    struct Author *link;		/* this link MUST be first */
X    char *name;
X    WORD seq;
X    WORD count;
X} AUTHOR;
X
Xtypedef struct Subject {
X    struct Subject *link;
X    char *str;
X    WORD seq;
X    WORD count;
X} SUBJECT;
X
Xtypedef struct Root {
X    struct Root *link;			/* this link MUST be first */
X    ARTICLE *articles;
X    SUBJECT *subjects;
X    ART_NUM root_num;
X    WORD thread_cnt;
X    WORD subject_cnt;
X    WORD seq;
X} ROOT;
X
Xtypedef struct {
X    LONG root_num;
X    WORD articles;
X    WORD thread_cnt;
X    WORD subject_cnt;
X} PACKED_ROOT;
X
Xtypedef struct {
X    LONG num;
X    LONG date;
X    WORD subject, author;
X    WORD flags;
X    WORD child_cnt;
X    WORD parent, children, siblings;
X    WORD root;
X} PACKED_ARTICLE;
X
Xtypedef struct Total {
X    LONG first, last;
X    LONG string1;
X    LONG string2;
X    WORD root;
X    WORD article;
X    WORD subject;
X    WORD author;
X    WORD domain;
X} TOTAL;
X
Xtypedef struct {
X    BYTE l[sizeof (LONG)];
X    BYTE w[sizeof (WORD)];
X    BYTE version;
X} BMAP;
SHAR_EOF
chmod 0660 threads.h || echo "restore of threads.h fails"
echo "x - extracting util.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > util.c &&
X/* $Header: util.c,v 4.3.3.1 90/07/21 20:34:10 davison Trn $
X *
X * $Log:	util.c,v $
X * Revision 4.3.3.1  90/07/21  20:34:10  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.6  90/04/23  00:24:42  sob
X * A bit of clean up.
X * 
X * Revision 4.3.2.5  90/03/17  21:34:21  sob
X * Reworked VOIDSIG into SIGRET.
X * 
X * Revision 4.3.2.4  89/12/14  23:58:54  sob
X * Fixed small bug reported by fletcher at cs.utexas.edu in getwd().
X * 
X * Revision 4.3.2.3  89/11/08  04:47:11  sob
X * Added VOIDSIG handling for SunOS 4.X
X * 
X * Revision 4.3.2.2  89/11/07  23:19:35  sob
X * Bug fixes for SIGSTP problems
X * 
X * Revision 4.3.2.1  89/11/06  01:03:21  sob
X * Added RRN support from NNTP 1.5
X * 
X * Revision 4.3.1.2  85/05/15  14:44:27  lwall
X * Last arg of execl changed from 0 to Nullch [(char*)0].
X * 
X * Revision 4.3.1.1  85/05/10  11:41:30  lwall
X * Branch for patches.
X * 
X * Revision 4.3  85/05/01  11:51:44  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "final.h"
X#include "ndir.h"
X#include "INTERN.h"
X#include "util.h"
X
Xvoid
Xutil_init()
X{
X    ;
X}
X    
X/* fork and exec a shell command */
X
Xint
Xdoshell(shl,s)
Xchar *s, *shl;
X{
X    int status, pid, w;
X    SIGRET (*signal())();
X    char *shell;
X
X#ifdef SIGTSTP
X    sigset(SIGTSTP,SIG_DFL);
X    sigset(SIGTTOU,SIG_DFL);
X    sigset(SIGTTIN,SIG_DFL);
X#endif
X    if (shl != Nullch)
X	shell = shl;
X    else if ((shell = getenv("SHELL")) == Nullch || !*shell)
X	shell = PREFSHELL;
X    if ((pid = vfork()) == 0) {
X#ifdef SERVER
X        int i;
X
X	/* This is necessary to keep bourne shell from puking */
X
X        for (i = 3; i < 10; ++i)
X                close(i);
X#endif /* SERVER */
X
X	if (*s)
X	    execl(shell, shell, "-c", s, Nullch);
X	else
X	    execl(shell, shell, Nullch, Nullch, Nullch);
X	_exit(127);
X    }
X    signal(SIGINT, SIG_IGN);
X    signal(SIGQUIT, SIG_IGN);
X    waiting = TRUE;
X    while ((w = wait(&status)) != pid && w != -1)
X	;
X    if (w == -1)
X	status = -1;
X    waiting = FALSE;
X    sigset(SIGINT, int_catcher);	/* always catch interrupts */
X    signal(SIGQUIT, SIG_DFL);
X#ifdef SIGTSTP
X    sigset(SIGTSTP,stop_catcher);
X    sigset(SIGTTOU,stop_catcher);
X    sigset(SIGTTIN,stop_catcher);
X#endif
X    return status;
X}
X
Xstatic char nomem[] = "rn: out of memory!\n";
X
X/* paranoid version of malloc */
X
Xchar *
Xsafemalloc(size)
XMEM_SIZE size;
X{
X    char *ptr;
X    char *malloc();
X
X    ptr = malloc(size ? size : (MEM_SIZE)1);
X    if (ptr != Nullch)
X	return ptr;
X    else {
X	fputs(nomem,stdout) FLUSH;
X	sig_catcher(0);
X    }
X    /*NOTREACHED*/
X}
X
X/* paranoid version of realloc */
X
Xchar *
Xsaferealloc(where,size)
Xchar *where;
XMEM_SIZE size;
X{
X    char *ptr;
X    char *realloc();
X
X    ptr = realloc(where,size?size:1);	/* realloc(0) is NASTY on our system */
X    if (ptr != Nullch)
X	return ptr;
X    else {
X	fputs(nomem,stdout) FLUSH;
X	sig_catcher(0);
X    }
X    /*NOTREACHED*/
X}
X
X/* safe version of string copy */
X
Xchar *
Xsafecpy(to,from,len)
Xchar *to;
Xregister char *from;
Xregister int len;
X{
X    register char *dest = to;
X
X    if (from != Nullch) 
X	for (len--; len && (*dest++ = *from++); len--) ;
X    *dest = '\0';
X    return to;
X}
X
X/* safe version of string concatenate, with \n deletion and space padding */
X
Xchar *
Xsafecat(to,from,len)
Xchar *to;
Xregister char *from;
Xregister int len;
X{
X    register char *dest = to;
X
X    len--;				/* leave room for null */
X    if (*dest) {
X	while (len && *dest++) len--;
X	if (len) {
X	    len--;
X	    *(dest-1) = ' ';
X	}
X    }
X    if (from != Nullch)
X	while (len && (*dest++ = *from++)) len--;
X    if (len)
X	dest--;
X    if (*(dest-1) == '\n')
X	dest--;
X    *dest = '\0';
X    return to;
X}
X
X/* copy a string up to some (non-backslashed) delimiter, if any */
X
Xchar *
Xcpytill(to,from,delim)
Xregister char *to, *from;
Xregister int delim;
X{
X    for (; *from; from++,to++) {
X	if (*from == '\\' && from[1] == delim)
X	    from++;
X	else if (*from == delim)
X	    break;
X	*to = *from;
X    }
X    *to = '\0';
X    return from;
X}
X
X/* return ptr to little string in big string, NULL if not found */
X
Xchar *
Xinstr(big, little)
Xchar *big, *little;
X
X{
X    register char *t, *s, *x;
X
X    for (t = big; *t; t++) {
X	for (x=t,s=little; *s; x++,s++) {
X	    if (!*x)
X		return Nullch;
X	    if (*s != *x)
X		break;
X	}
X	if (!*s)
X	    return t;
X    }
X    return Nullch;
X}
X
X/* effective access */
X
X#ifdef SETUIDGID
Xint
Xeaccess(filename, mod)
Xchar *filename;
Xint mod;
X{
X    int protection, euid;
X    
X    mod &= 7;				/* remove extraneous garbage */
X    if (stat(filename, &filestat) < 0)
X	return -1;
X    euid = geteuid();
X    if (euid == ROOTID)
X	return 0;
X    protection = 7 & (filestat.st_mode >>
X      (filestat.st_uid == euid ? 6 :
X        (filestat.st_gid == getegid() ? 3 : 0)
X      ));
X    if ((mod & protection) == mod)
X	return 0;
X    errno = EACCES;
X    return -1;
X}
X#endif
X
X/*
X * Get working directory
X */
X#ifdef GETCWD
Xchar *
Xgetwd(np)
Xchar *np;
X{
X    char * name;
X	extern char * getcwd();
X    name = getcwd(np,1024);
X    return(name);
X}
X#else
X#ifndef GETWD
Xchar *
Xgetwd(np)			/* shorter but slower */
Xchar *np;
X{
X    FILE *popen();
X    FILE *pipefp = popen("/bin/pwd","r");
X
X    if (pipefp == Nullfp) {
X	printf("Can't run /bin/pwd\n") FLUSH;
X	finalize(1);
X    }
X    fgets(np,512,pipefp);
X    np[strlen(np)-1] = '\0';	/* wipe out newline */
X    pclose(pipefp);
X    return np;
X}
X#endif
X#endif
X/* just like fgets but will make bigger buffer as necessary */
X
Xchar *
Xget_a_line(original_buffer,buffer_length,fp)
Xchar *original_buffer;
Xregister int buffer_length;
XFILE *fp;
X{
X    register int bufix = 0;
X    register int nextch;
X    register char *some_buffer_or_other = original_buffer;
X
X    do {
X	if (bufix >= buffer_length) {
X	    buffer_length *= 2;
X	    if (some_buffer_or_other == original_buffer) {
X					/* currently static? */
X		some_buffer_or_other = safemalloc((MEM_SIZE)buffer_length+1);
X		strncpy(some_buffer_or_other,original_buffer,buffer_length/2);
X					/* so we must copy it */
X	    }
X	    else {			/* just grow in place, if possible */
X		some_buffer_or_other = saferealloc(some_buffer_or_other,
X		    (MEM_SIZE)buffer_length+1);
X	    }
X	}
X	if ((nextch = getc(fp)) == EOF)
X	    return Nullch;
X	some_buffer_or_other[bufix++] = (char) nextch;
X    } while (nextch && nextch != '\n');
X    some_buffer_or_other[bufix] = '\0';
X    len_last_line_got = bufix;
X    return some_buffer_or_other;
X}
X
X/* copy a string to a safe spot */
X
Xchar *
Xsavestr(str)
Xchar *str;
X{
X    register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1));
X
X    strcpy(newaddr,str);
X    return newaddr;
X}
X
Xint
Xmakedir(dirname,nametype)
Xregister char *dirname;
Xint nametype;
X{
X#ifdef MAKEDIR
X    register char *end;
X    register char *s;
X    char tmpbuf[1024];
X    register char *tbptr = tmpbuf+5;
X
X    for (end = dirname; *end; end++) ;	/* find the end */
X    if (nametype == MD_FILE) {		/* not to create last component? */
X	for (--end; end != dirname && *end != '/'; --end) ;
X	if (*end != '/')
X	    return 0;			/* nothing to make */
X	*end = '\0';			/* isolate file name */
X    }
X    strcpy(tmpbuf,"mkdir");
X
X    s = end;
X    for (;;) {
X	if (stat(dirname,&filestat) >= 0 && (filestat.st_mode & S_IFDIR)) {
X					/* does this much exist as a dir? */
X	    *s = '/';			/* mark this as existing */
X	    break;
X	}
X	s = rindex(dirname,'/');	/* shorten name */
X	if (!s)				/* relative path! */
X	    break;			/* hope they know what they are doing */
X	*s = '\0';			/* mark as not existing */
X    }
X    
X    for (s=dirname; s <= end; s++) {	/* this is grody but efficient */
X	if (!*s) {			/* something to make? */
X	    sprintf(tbptr," %s",dirname);
X	    tbptr += strlen(tbptr);	/* make it, sort of */
X	    *s = '/';			/* mark it made */
X	}
X    }
X    if (nametype == MD_DIR)		/* don't need final slash unless */
X	*end = '\0';			/*  a filename follows the dir name */
X
X    return (tbptr==tmpbuf+5 ? 0 : doshell(sh,tmpbuf));
X					/* exercise our faith */
X#else
X    sprintf(cmd_buf,"%s %s %d", filexp(DIRMAKER), dirname, nametype);
X    return doshell(sh,cmd_buf);
X#endif
X}
X
X#ifdef SETENV
Xstatic bool firstsetenv = TRUE;
Xextern char **environ;
X
Xvoid
Xsetenv(nam,val)
Xchar *nam, *val;
X{
X    register int i=envix(nam);		/* where does it go? */
X
X    if (!environ[i]) {			/* does not exist yet */
X	if (firstsetenv) {		/* need we copy environment? */
X	    int j;
X#ifndef lint
X	    char **tmpenv = (char**)	/* point our wand at memory */
X		safemalloc((MEM_SIZE) (i+2) * sizeof(char*));
X#else
X	    char **tmpenv = Null(char **);
X#endif /* lint */
X    
X	    firstsetenv = FALSE;
X	    for (j=0; j<i; j++)		/* copy environment */
X		tmpenv[j] = environ[j];
X	    environ = tmpenv;		/* tell exec where it is now */
X	}
X#ifndef lint
X	else
X	    environ = (char**) saferealloc((char*) environ,
X		(MEM_SIZE) (i+2) * sizeof(char*));
X					/* just expand it a bit */
X#endif /* lint */
X	environ[i+1] = Nullch;	/* make sure it's null terminated */
X    }
X    environ[i] = safemalloc((MEM_SIZE) strlen(nam) + strlen(val) + 2);
X					/* this may or may not be in */
X					/* the old environ structure */
X    sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
X}
X
Xint
Xenvix(nam)
Xchar *nam;
X{
X    register int i, len = strlen(nam);
X
X    for (i = 0; environ[i]; i++) {
X	if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
X	    break;			/* strnEQ must come first to avoid */
X    }					/* potential SEGV's */
X    return i;
X}
X#endif
X
Xvoid
Xnotincl(feature)
Xchar *feature;
X{
X    printf("\nNo room for feature \"%s\" on this machine.\n",feature) FLUSH;
X}
X
Xchar *
Xgetval(nam,def)
Xchar *nam,*def;
X{
X    char *val;
X
X    if ((val = getenv(nam)) == Nullch || !*val)
X	val = def;
X    return val;
X}
X
X/* grow a static string to at least a certain length */
X
Xvoid
Xgrowstr(strptr,curlen,newlen)
Xchar **strptr;
Xint *curlen;
Xint newlen;
X{
X    if (newlen > *curlen) {		/* need more room? */
X	if (*curlen)
X	    *strptr = saferealloc(*strptr,(MEM_SIZE)newlen);
X	else
X	    *strptr = safemalloc((MEM_SIZE)newlen);
X	*curlen = newlen;
X    }
X}
X
Xvoid
Xsetdef(buffer,dflt)
Xchar *buffer,*dflt;
X{
X#ifdef STRICTCR
X    if (*buffer == ' ')
X#else
X    if (*buffer == ' ' || *buffer == '\n')
X#endif
X    {
X	if (*dflt == '^' && isupper(dflt[1]))
X	    *buffer = Ctl(dflt[1]);
X	else
X	    *buffer = *dflt;
X    }
X}
SHAR_EOF
chmod 0660 util.c || echo "restore of util.c fails"
echo "x - extracting util.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > util.h &&
X/* $Header: util.h,v 4.3 85/05/01 11:51:58 lwall Exp $
X *
X * $Log:	util.h,v $
X * Revision 4.3  85/05/01  11:51:58  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
XEXT bool waiting INIT(FALSE);		/* are we waiting for subprocess (in doshell)? */
XEXT int len_last_line_got INIT(0);
X			/* strlen of some_buf after */
X			/*  some_buf = get_a_line(bufptr,buffersize,fp) */
X
X/* is the string for makedir a directory name or a filename? */
X
X#define MD_DIR 0
X#define MD_FILE 1
X
Xvoid	util_init();
Xint	doshell();
Xchar	*safemalloc();
Xchar	*saferealloc();
Xchar	*safecpy();
Xchar	*safecat();
Xchar	*cpytill();
Xchar	*instr();
X#ifdef SETUIDGID
X    int		eaccess();
X#endif
Xchar	*getwd();
Xvoid	cat();
Xvoid	prexit();
Xchar	*get_a_line();
Xchar	*savestr();
Xint	makedir();
Xvoid	setenv();
Xint	envix();
Xvoid	notincl();
Xchar	*getval();
Xvoid	growstr();
Xvoid	setdef();
SHAR_EOF
chmod 0660 util.h || echo "restore of util.h fails"
echo "x - extracting uudecode.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > uudecode.c &&
X/* $Header: uudecode.c,v 4.3.3.1 90/06/20 22:48:21 davison Trn $
X**
X** $Log:	uudecode.c,v $
X** Revision 4.3.3.1  90/06/20  22:48:21  davison
X** Initial Trn Release
X** 
X** Decode one or more uuencoded articles back to binary form.
X**
X** Trn version created by Wayne Davison.
X** Adapted from the nn version by Kim Storm.
X** From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
X*/
X
X#include "EXTERN.h"
X#include "common.h"
X#include "INTERN.h"
X#include "uudecode.h"
X
X#if 000
Xexport char *decode_header_file = "Decode.Headers";
X#endif
X
X#define MAXCHAR 256
X#define NORMLEN 60	/* allows for 80 encoded chars per line */
X
X#define SEQMAX 'z'
X#define SEQMIN 'a'
X
Xstatic char seqc;
Xstatic int first, secnd, check, numl;
X
Xstatic char *target;
Xstatic char dest[MAXFILENAME];
Xstatic char blank;
Xstatic int chtbl[MAXCHAR], cdlen[NORMLEN + 3];
Xstatic int state;
Xstatic bool Xflag;
X
X#define	NO_ADVANCE		0x10
X
X#define	FIND_BEGIN		0x01
X#define	FIND_BEGIN_AFTER_ERROR	0x02
X#define	DECODE_TEXT		0x03
X#define	SKIP_TRAILING	       (0x04 | NO_ADVANCE)
X#define	SKIP_LEADING		0x05
X#define	FOUND_END	       (0x06 | NO_ADVANCE)
X#define DECODE_ERROR	       (0x07 | NO_ADVANCE)
X#define OTHER_ERROR	       (0x08 | NO_ADVANCE)
X#define NEW_BEGIN	       (0x09 | NO_ADVANCE)
X
Xuud_start(dir)
Xchar *dir;
X{
X    target = dir;
X    uu_out = Nullfp;
X    Xflag = FALSE;
X    seqc = SEQMAX;
X    check = 1;
X    first = 1;
X    secnd = 0;
X    state = FIND_BEGIN;
X}
X
Xuud_end()
X{
X    if (uu_out != Nullfp) {
X	fclose(uu_out);
X	uu_out = Nullfp;
X	printf("\n%s INCOMPLETE -- removed\n", dest);
X	unlink(dest);
X    }
X}
X
X
Xuudecode(in)
XFILE *in;
X{
X    int mode, onedone, lens;
X    char buff[LBUFLEN];
X
X    numl = onedone = 0;
X
X    if (state == FIND_BEGIN)
X	inittbls();
X
X    /*
X     * search for header or translation table line.
X     */
X
X    while ((state & NO_ADVANCE) || fgets(buff, sizeof buff, in) != Nullch) {
X	numl++;
X
X	switch (state) {
X	 case NEW_BEGIN:
X	    if (uu_out != Nullfp) {
X		printf("INCOMPLETE FILE: %s -- removed\n", dest);
X		sleep(2);
X		fclose(uu_out);
X		uu_out = Nullfp;
X		Xflag = FALSE;
X		unlink(dest);
X	    }
X	    /* fall thru */
X
X	 case FIND_BEGIN:
X	 case FIND_BEGIN_AFTER_ERROR:
X	    if (strnEQ(buff, "table ", 6)) {
X		gettable(in);
X		continue;
X	    }
X
X	    if (strnEQ(buff, "begin ", 6)
X	     || strnEQ(buff, "Xbegin ", 7)) {
X		lens = strlen(buff)-1;
X		if (buff[lens] == '\n')
X		    buff[lens] = '\0';
X
X		if(sscanf(buff+6,"%o%s", &mode, uu_fname) != 2)
X		    continue;
X
X		Xflag = (*buff == 'X');
X
X		if (target != Nullch)
X		    sprintf(dest, "%s/%s", target, uu_fname);
X		else
X		    strcpy(dest, uu_fname);
X
X		if ((uu_out = fopen(dest, "w")) == Nullfp) {
X		    printf("Cannot create file: %s\n", dest);
X		    goto err;
X		}
X		chmod(dest, mode);
X
X#if 000
X		if (decode_header_file)
X		    store_header(ah, in, target, decode_header_file);
X#endif
X
X		printf("Decoding: %s\n", uu_fname);
X		state = DECODE_TEXT;
X	    }
X	    continue;
X
X	 case SKIP_LEADING:
X	    state = decode_line(buff);
X	    continue;
X
X	 case DECODE_TEXT:
X	    state = decode_line(buff);
X	    onedone = 1;
X	    continue;
X
X	 case FOUND_END:
X	    fclose(uu_out);
X	    uu_out = Nullfp;
X	    Xflag = FALSE;
X	    state = FIND_BEGIN;
X	    printf("Done.\n");
X	    continue;
X
X	 case SKIP_TRAILING:
X	    printf("(Continued)\n");
X	    state = SKIP_LEADING;
X	    return 0;
X
X	 case DECODE_ERROR:
X	    state = SKIP_TRAILING;
X	    continue;
X
X	 case OTHER_ERROR:
X	    fclose(uu_out);
X	    uu_out = Nullfp;
X	    Xflag = FALSE;
X	    state = FIND_BEGIN_AFTER_ERROR;
X	    goto err;
X	}
X    }
X
X    if (onedone) {
X	if (state == DECODE_TEXT)
X	    state = SKIP_LEADING;
X	return 0;
X    }
X
X    if (state == FIND_BEGIN_AFTER_ERROR)
X	return -1;
X    printf("Couldn't find anything to decode.\n");
X
X err:
X    sleep(2);
X    return -1;
X}
X
X/*
X * decode one line, write on uu_out file
X */
X
Xstatic decode_line(buff)
Xchar *buff;
X{
X    char outl[LBUFLEN];
X    register char *bp, *ut;
X    register int *trtbl = chtbl;
X    register int n;
X    register int blen;		/* binary length (from decoded file) */
X    register int rlen;		/* calculated input line length */
X    register int len;		/* actual input line length */
X
X    if (Xflag) {
X	if (*buff == 'X')
X	    buff++;
X	else
X	    *buff = 'x';	/* force a mis-parse of a non-x'ed line */
X    }
X    len = strlen(buff);
X    if (--len < 0)
X	return state;
X
X    buff[len] = '\0';
X
X    /*
X     * Get the binary line length.
X     */
X    if ((blen = trtbl[buff[0]]) < 0) {
X	if (state == SKIP_LEADING) {
X	    if (strnEQ(buff, "begin ", 6))
X		return NEW_BEGIN;
X
X	    return SKIP_LEADING;
X	}
X	/*
X	 * end of uuencoded file ?
X	 */
X	if (strnEQ(buff, "end", 3))
X	    return FOUND_END;
X
X	/*
X	 * end of current file ? : get next one.
X	 */
X	if (strnEQ(buff, "include", 7)) {
X	    printf("Cannot handle 'include' lines -- unpack with uud\n");
X	    return OTHER_ERROR;
X	}
X
X	/*
X	 * trailing garbage
X	 */
X	return SKIP_TRAILING;
X    }
X
X    rlen = cdlen[blen];
X    if (state == SKIP_LEADING && len != rlen && len != rlen+1)
X	return SKIP_LEADING;
X
X    /*
X     * Is it the empty line before the end line ?
X     */
X    if (blen == 0)
X	return state;
X
X    if (len > rlen + 5)
X	return SKIP_TRAILING;
X
X    /*
X     * Pad with blanks.
X     */
X    for (bp = buff + len, n = rlen - len; --n >= 0; )
X	*bp++ = blank;
X
X    /*
X     * Verify
X     */
X    for (n = rlen, bp = buff; --n >= 0; bp++)
X	if (trtbl[*bp] < 0) {
X	    if (state == SKIP_LEADING)
X		return SKIP_LEADING;
X	    return DECODE_ERROR;
X	}
X
X    /*
X     * Check for uuencodes that append a 'z' to each line....
X     */
X    if (check)
X	if (secnd) {
X	    secnd = 0;
X	    if (buff[rlen] == SEQMAX)
X		check = 0;
X	} else if (first) {
X	    first = 0;
X	    secnd = 1;
X	    if (buff[rlen] != SEQMAX)
X		check = 0;
X	}
X
X    /*
X     * There we check.
X     */
X    if (check) {
X	if (buff[rlen] != seqc) {
X	    if (state == SKIP_LEADING)
X		return SKIP_LEADING;
X	    return DECODE_ERROR;
X	}
X
X	if (--seqc < SEQMIN)
X	    seqc = SEQMAX;
X    }
X
X    /*
X     * output a group of 3 bytes (4 input characters).
X     * the input chars are pointed to by p, they are to
X     * be output to file f. blen is used to tell us not to
X     * output all of them at the end of the file.
X     */
X    ut = outl;
X    n = blen;
X    bp = &buff[1];
X    while (--n >= 0) {
X	*(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
X	if (n > 0) {
X	    *(ut++) = (trtbl[bp[1]] << 4) | (trtbl[bp[2]] >> 2);
X	    n--;
X	}
X	if (n > 0) {
X	    *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
X	    n--;
X	}
X	bp += 4;
X    }
X    if (fwrite(outl, 1, blen, uu_out) <= 0) {
X	printf("Error on writing decoded file\n");
X	return OTHER_ERROR;
X    }
X
X    return DECODE_TEXT;
X}
X
X
X
X/*
X * Install the table in memory for later use.
X */
Xstatic inittbls()
X{
X    register int i, j;
X
X    /*
X     * Set up the default translation table.
X     */
X    for (i = 0; i < ' '; i++)
X	chtbl[i] = -1;
X    for (i = ' ', j = 0; i < ' ' + 64; i++, j++)
X	chtbl[i] = j;
X    for (i = ' ' + 64; i < MAXCHAR; i++)
X	chtbl[i] = -1;
X    chtbl['`'] = chtbl[' '];	/* common mutation */
X    chtbl['~'] = chtbl['^'];	/* another common mutation */
X    blank = ' ';
X    /*
X     * set up the line length table, to avoid computing lotsa * and / ...
X     */
X    cdlen[0] = 1;
X    for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
X	cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
X}
X
Xstatic gettable(in)
XFILE *in;
X{
X    char buff[LBUFLEN];
X    register int c, n = 0;
X    register char *cpt;
X
X    for (c = 0; c <= MAXCHAR; c++)
X	chtbl[c] = -1;
X
X    for (;;) {
X	if (fgets(buff, sizeof buff, in) == Nullch) {
X	    printf("EOF while in translation table.\n");
X	    return -1;
X	}
X	numl++;
X	if (strnEQ(buff, "begin", 5)) {
X	    printf("Incomplete translation table.\n");
X	    return -1;
X	}
X	cpt = buff + strlen(buff) - 1;
X	*cpt = ' ';
X	while (*cpt == ' ') {
X	    *cpt = 0;
X	    cpt--;
X	}
X	cpt = buff;
X	while (c = *cpt) {
X	    if (chtbl[c] != -1) {
X		printf("Duplicate char in translation table.\n");
X		return -1;
X	    }
X	    if (n == 0)
X		blank = c;
X	    chtbl[c] = n++;
X	    if (n >= 64)
X		return 0;
X	    cpt++;
X	}
X    }
X}
X
SHAR_EOF
chmod 0660 uudecode.c || echo "restore of uudecode.c fails"
echo "x - extracting uudecode.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > uudecode.h &&
X/* $Header: uudecode.h,v 4.3.3.1 90/06/20 22:49:08 davison Trn $
X**
X** $Log:	uudecode.h,v $
X** Revision 4.3.3.1  90/06/20  22:49:08  davison
X** Initial Trn Release
X** 
X*/
X
XEXT FILE *uu_out INIT(NULL);
XEXT char uu_fname[MAXFILENAME];
SHAR_EOF
chmod 0660 uudecode.h || echo "restore of uudecode.h fails"
echo "x - extracting Wishlist (Text)"
sed 's/^X//' << 'SHAR_EOF' > Wishlist &&
XGeneralized article set manipulation
X	Interface to subject listing.
X	Recursive newsgroup visitation.
XVirtual article abstract type to allow the following:
X	Personalized header munging via % subs.
X	Undigestification.
X	Personal archive perusal.
X	Mail handling.
XParent command (waiting for ARTFILE interface and recursive newsgroups).
XMerge Pnews and postnews.
XVnews duplicate suppression algorithm for sites that can't do Xref patch.
XDynamic allocation of stuff currently restricted by MAXRCLINE.
X	(And pull parallel arrays into array of structs).
XSeparation of .newsrc functions and newsgroup functions to separate processes
X	communicating via pipes (to make fit on non-separate-I-and-D pdp11,
X	or unreasonable facsimiles thereof).
XFaster!!!
XSmaller!!!
XMore general!!!
XPerfect?
X----------
X			Better NNTP Support
X
XThe current NNTP support requires a duplicate database be maintained on each
Xclient machine.  Currently, this requires each client to run the NNTP version
Xof mthreads to access all the articles headers to create the local copy of the
Xthread database.  There are a number of ways this could be improved:
X
X   o	Create the database on the server host and distribute the finished
X	thread files to all the client hosts at regular intervals using ftp,
X	mail, uucp, etc.
X
X   o	Write an adjunct to NNTP that would serve to distribute thread data.
X
X   o	Cajole the NNTP people to include a command to distribe an authorized
X	list of files other than news articles (e.g. thread files).
X
X   o	Eliminate the need for a thread database.
X
XAll these options are left as an exercise for the reader.
SHAR_EOF
chmod 0660 Wishlist || echo "restore of Wishlist fails"
rm -f s2_seq_.tmp
echo "You have unpacked the last part"
exit 0

exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list