[net.sources] `ctree' - a tiny conference tree

bsa@ncoast.UUCP (The WITNESS) (09/25/84)

I don't expect that this program will win any awards or be widely used,
but it is a curio I wrote that might interest a few people on the net.
After having run a BBS on ncoast for public use, then taking it down
to fix many many bugs in the thing, I got lots of complaints through
the gripe login from people who wanted their BBS back.  Since the original
BBS was a conference-oriented type (not as general as CommuniTree but
more so than most in that there was no fixed number of conferences and
anyone could create a new one at any time), I sought a conference-oriented
replacement.  This set of shell scripts (and a few C programs) is the
result.  Most of it could probably be coded into C, but I didn't feel
like writing a recursive directory descender, so I cheated and used the
find command from the shell.

This beastie is slow, but it works.  You might like this thing even if
it's too slow to be practical.

Anyway, here it is, as a shar archive.  Being itself a set of shell scripts,
it has been written to autoinstall itself.  Just run the archive through
sh and watch it fly.  (Put the shar archive in a directory other than
the one in which you want the actual utree to go -- it will work the
other way, but give lots of spurious error messages from cp.)  The C
programs are simple and should require no modification; they were coded
in C for speed, not utility.  `linelist' miht be a good general utility
as well.

Oh -- one last thing:  it was designed under Xenix and uses V7 standard
stuff only.  I THINK it will run on anything later than V7, but who knows
for certain until it's been tested?

Enough babbling -- without further ado, I present...
----------------CUT---------------------------------CUT---------------------
: This is a shar archive.  Extract with sh not csh.
echo 'sh - indechof.c'
sed 's/^X//' <<'________This_Is_The_END________' >>indechof.c
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
Xstruct stat sb;
Xextern char *index(), *basename();
Xchar *mtimeof();
X
Xmain(argc, argv) char **argv; {
X	FILE *f;
X	char usagefile[1024], *cp;
X	int usage, cnt;
X
X	if (argc != 3) {
X		fprintf(stderr, "Usage: indechof file indmark\n");
X		exit(0);
X	}
X	sprintf(usagefile, "%s/.users", argv[1]);
X	if ((f = fopen(usagefile, "r")) == NULL) {
X		fprintf(stderr, "Who?\n");
X		exit(-1);
X	}
X	fscanf(f, "%d", &usage);
X	fclose(f);
X	if (strcmp(argv[1], argv[2]) == 0) {
X		printf("%-.14s\nUsers: %4d Created: %.16s\n\n", basename(argv[1]), usage, mtimeof(argv[1]));
X		exit(0);
X	}
X	cnt = 0, cp = argv[1];
X	while (argv[1][cnt] == argv[2][cnt])
X		cnt ++, cp ++;
X	cnt = 2;
X	while ((cp = index(cp + 1, '/')) != NULL)
X		cnt += 2;
X	printf("%*s%-.14s\nUsers: %4d Created: %.16s\n\n", cnt, "", basename(argv[1]), usage, mtimeof(argv[1]));
X}
X
Xchar *mtimeof(file) char *file; {
X	static char timestr[80];
X
X	if(stat(file, &sb) < 0)
X		return("Never created or modified.");
X	sprintf(timestr, "%.16s\n", ctime(&(sb.st_mtime)));
X	return(timestr);
X}
X
Xchar *rindex();
X
Xchar *basename(file) char *file; {
X	char *f;
X
X	return((f = rindex(file, '/')) == NULL? file : f + 1);
X}
________This_Is_The_END________
echo 'sh - linelist.c'
sed 's/^X//' <<'________This_Is_The_END________' >>linelist.c
X#include <stdio.h>
Xmain(argc, argv) char **argv; {
X	int lineno;
X	FILE *f;
X	char line[256];
X
X	if (argc != 2)
X		f = stdin;
X	else if ((f = fopen(argv[1], "r")) == NULL)
X		exit(-1);
X	lineno = 0;
X	while (fgets(line, 256, f) != NULL)
X		printf("Line %d:\n%s\n", ++lineno, line);
X	fclose(f);
X}
________This_Is_The_END________
echo 'sh - mtimeof.c'
sed 's/^X//' <<'________This_Is_The_END________' >>mtimeof.c
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
Xstruct stat sb;
X
Xmain(argc, argv) char **argv; {
X	if (argc != 2) {
X		fprintf(stderr, "Usage: mtimeof file\n");
X		exit(-1);
X	}
X	if(stat(argv[1], &sb) < 0) {
X		printf("Never created or modified.");
X		exit(0);
X	}
X	printf("%.16s\n", ctime(&(sb.st_mtime)));
X}
________This_Is_The_END________
echo 'sh - utaddto'
sed 's/^X//' <<'________This_Is_The_END________' >>utaddto
X:
X: utaddto - add to a utree conference
X:
X
Xtrap 'stty eofc "^D"; rm /tmp/ut[ab]$$ >/dev/null 2>&1; exit 0' 2
Xtrap '' 15 3
X
Xif [ $# -eq 0 ]
Xthen	echo "Missing conference name."
X	exit
Xfi
X
XCONF=`echo $1 | tr 'a-z' 'A-Z' | tr -cd 'A-Za-z-_@0-9'`
XCDIR=`find $UTREE -name $CONF -print 2>/dev/null | sh -c 'read a junk; echo $a'`
X
Xif [ "$CDIR" = "" ]
Xthen	echo "No such conference - $CONF"
X	exit
Xfi
X
Xcat <<%%%
X
XEnter the lines of your message; press the ESCAPE key to exit.
X
X%%%
Xstty eofc '^['
Xcat >/tmp/uta$$
Xwhile true
Xdo	echo
X	echo -n "Editor command (L, C, E, S, A, ?): "
X	read cmd junk
X	case "$cmd" in
X	L | l )
X		linelist /tmp/uta$$ ;;
X	C | c )
X		echo
X		echo 'Enter your lines; press ESCAPE to exit.'
X		echo
X		cat >>/tmp/uta$$ ;;
X	E | e )
X		while true
X		do	echo -n "Enter the line # to replace, or ENTER to exit: "
X			read cmd junk
X			if [ "$cmd" = "" ]
X			then	break
X			fi
X			echo "Enter the replacement line, or ENTER to abort:"
X			read line
X			if [ "$line" != "" ]
X			then	sed "${cmd}c\\\
X$line\\\
X." </tmp/uta$$ > /tmp/utb$$
X				mv /tmp/utb$$ /tmp/uta$$
X			fi
X		done ;;
X	A | a )
X		rm /tmp/uta$$
X		break ;;
X	S | s )
X		echo -n "Enter the name of this conference, or ENTER to abort: "
X		read conf junk
X		if [ "$conf" != "" ]
X		then	conf=`echo $conf | tr 'a-z' 'A-Z' | tr -cd 'A-Z0-9-_@'`
X			newc=`find $UTREE -type d -name $conf -print`
X			if [ "$newc" != "" ]
X			then	echo "Sorry, that name's in use."
X			else	mkdir $CDIR/$conf
X				mv /tmp/uta$$ $CDIR/$conf/.message
X				echo 0 >$CDIR/$conf/.users
X				break
X			fi
X		fi ;;
X	'?' )
X		cat <<%%%
X
XEditor commands
X---------------
XL	List message
XE	Edit message
XS	Save message
XA	Abort without saving message
XC	Continue entering message
X
X%%%
X		echo ;;
X	esac
Xdone
Xstty eofc '^D'
Xexit
________This_Is_The_END________
echo 'sh - utbrowse'
sed 's/^X//' <<'________This_Is_The_END________' >>utbrowse
X:
X: utbrowse - conference browse utility for utree
X:
X
Xtrap 'exit 0' 2
Xtrap '' 15 3
X
Xif [ $# -eq 0 ]
Xthen	echo "Missing conference name."
X	exit
Xfi
X
XCONF=`echo $1 | tr 'a-z' 'A-Z' | tr -cd 'A-Za-z-_@0-9'`
XCDIR=`find $UTREE -name $CONF -print 2>/dev/null | sh -c 'read a junk; echo $a'`
X
Xif [ "$CDIR" = "" ]
Xthen	echo "No such conference - $CONF"
X	exit
Xfi
X
Xcase "$2" in
X"" )
X	utcat -b $CDIR
X	echo
X	echo "Subconferences:"
X	echo
X	lc $CDIR
X	echo ;;
X"C" | "c" | "COMPLETE" | "complete" )
X	find $CDIR -type d -exec utcat -b '{}' ';'
X	echo ;;
X"A" | "a" | "AFTER" | "after" )
X	if [ $# -ne 3 ]
X	then	echo "Missing days parameter."
X		exit
X	fi
X	find $CDIR -type d -mtime $3 -exec utcat -b '{}' ';'
X	echo ;;
X* )
X	echo "No such option." ;;
Xesac
Xexit
________This_Is_The_END________
echo 'sh - utcat'
sed 's/^X//' <<'________This_Is_The_END________' >>utcat
X:
X: utcat - display a conference for utree
X: browse option shows the first 2 lines of a conference
X:
X
Xtrap 'exit 0' 2
Xtrap '' 15 3
X
Xif [ $# -eq 0 ]
Xthen	echo "Usage: $0 [-b] conference-dir-path"
X	exit
Xfi
X
Xif [ "$1" = "-b" ]
Xthen	cmd="head -2"
X	shift
Xelse	cmd=cat
Xfi
X
XUSERS=`cat $1/.users`
XCONF=`basename $1`
X
Xcat <<%%%
X
X*** $CONF *****************************
XCreated: `mtimeof $1`            Users: $USERS
X
X%%%
Xexpr $USERS + 1 >$1/.users
Xexec $cmd $1/.message
________This_Is_The_END________
echo 'sh - utindex'
sed 's/^X//' <<'________This_Is_The_END________' >>utindex
X:
X: utindex - index a utree
X:
X
Xtrap 'exit 0' 2
Xtrap '' 15 3
X
Xif [ $# -eq 0 ]
Xthen	echo "Missing conference name."
X	exit
Xfi
X
XCONF=`echo $1 | tr 'a-z' 'A-Z' | tr -cd 'A-Za-z-_@0-9'`
XCDIR=`find $UTREE -name $CONF -print 2>/dev/null | sh -c 'read a junk; echo $a'`
X
Xif [ "$CDIR" = "" ]
Xthen	echo "No such conference - $CONF"
X	exit
Xfi
X
Xcase "$2" in
X"" )
X	indechof $CDIR $CDIR
X	echo
X	echo "Subconferences:"
X	echo
X	lc $CDIR
X	echo ;;
X"C" | "c" | "COMPLETE" | "complete" )
X	find $CDIR -type d -exec indechof '{}' $CDIR ';'
X	echo ;;
X"A" | "a" | "AFTER" | "after" )
X	if [ $# -ne 3 ]
X	then	echo "Missing days parameter."
X		exit
X	fi
X	find $CDIR -type d -mtime -$3 -exec indechof '{}' $CDIR ';'
X	echo ;;
X* )
X	echo "No such option." ;;
Xesac
Xexit
________This_Is_The_END________
echo 'sh - utmake'
sed 's/^X//' <<'________This_Is_The_END________' >>utmake
X
X:
X: Make a utree structure
X:
X
Xecho -n "What directory is to be the root? "
Xread utroot
Xsed "s/%R%/$utroot/" <utree.sh >utree.tmp
Xecho -n "In what directory will the command files reside? "
Xread utpath
Xsed "s/%P%/$utpath/" <utree.tmp >utree
Xrm utree.tmp
Xchmod +x ut*
Xmkdir $utroot $utroot/CONFERENCES
Xecho 0 >$utroot/CONFERENCES/.users
Xcat <<%%% >$utroot/CONFERENCES/.message
XCurrent messages in this Unix Tree are:
X%%%
Xfor file in *.c
Xdo	cc $file -o `basename $file .c`
Xdone
XUTREE=$utroot utindex CONFERENCES COMPLETE
Xchmod 777 $utroot/CONFERENCES $utroot/CONFERENCES/.[um]*
Xcp indechof utaddto utread utbrowse utcat utindex linelist mtimeof $utpath
Xcp utree $utpath
Xexit
________This_Is_The_END________
echo 'sh - utread'
sed 's/^X//' <<'________This_Is_The_END________' >>utread
X:
X: utread - conference read utility for utree
X:
X
Xtrap 'exit 0' 2
Xtrap '' 15 3
Xif [ $# -eq 0 ]
Xthen	echo "Missing conference name."
X	exit
Xfi
X
XCONF=`echo $1 | tr 'a-z' 'A-Z' | tr -cd 'A-Za-z-_@0-9'`
XCDIR=`find $UTREE -name $CONF -print 2>/dev/null | sh -c 'read a junk; echo $a'`
X
Xif [ "$CDIR" = "" ]
Xthen	echo "No such conference - $CONF"
X	exit
Xfi
X
Xcase "$2" in
X"" )
X	utcat $CDIR
X	echo
X	echo "Subconferences:"
X	echo
X	lc $CDIR
X	echo ;;
X"C" | "c" | "COMPLETE" | "complete" )
X	find $CDIR -type d -exec utcat '{}' ';'
X	echo ;;
X"A" | "a" | "AFTER" | "after" )
X	if [ $# -ne 3 ]
X	then	echo "Missing days parameter."
X		exit
X	fi
X	find $CDIR -type d -mtime -$3 -exec utcat '{}' ';'
X	echo ;;
X* )
X	echo "No such option." ;;
Xesac
Xexit
________This_Is_The_END________
echo 'sh - utree.sh'
sed 's/^X//' <<'________This_Is_The_END________' >>utree.sh
X:
X: utree - Unix conference tree
X: This program is loosely based on the Conference Tree program by the
X: CommuniTree Group.
X:
X
XUTREE=%R%
XPATH=:/bin:/usr/bin:%P%
Xexport UTREE PATH
XQUIT=n
X
Xtrap '' 15 3 2
Xumask 0
Xcat <<%%%
X
XThe Unix Tree - A Simple Conference-Oriented Communications Package
XPrograms (ut*) by Brandon Allbery, September 18, 1984.
X
X%%%
Xwhile [ $QUIT = n ]
Xdo	echo -n "Enter command (R, I, A, B, G, ?): "
X	read cmd argA argB argC
X	case "$cmd" in
X	r | R | read | READ )
X		utread $argA $argB $argC ;;
X	i | I | index | INDEX )
X		utindex $argA $argB $argC ;;
X	a | A | addto | ADDTO )
X		utaddto $argA $argB $argC ;;
X	b | B | browse | BROWSE )
X		utbrowse $argA $argB $argC ;;
X	g | G | goodbye | GOODBYE )
X		QUIT=y ;;
X	'?' )
X		cat <<%%%
X
XUnix Tree Commands
X------------------
X(Each command may be abbreviated to its first letter.)
X
XREAD	Read a conference
XINDEX	Index a conference
XADDTO	Add to a conference
XBROWSE	Browse a conference
XGOODBYE	Exit the Unix Tree
X?	Print this help message
X
XThe READ, INDEX, and BROWSE commands may use one of the following modifiers:
X
XCOMPLETE	Read the specified conference and all subconferences
XAFTER days	Read all subconferences less than <days> days old
X
XThese modifiers may be abbreviated to their first letters.  Only one may be
Xused in a single command.
X
XExamples:
X
X	READ CONFERENCES
X	INDEX CONFERENCES AFTER 5
X	R CONFERENCES A 15
X
XThe commands may run slowly, as shell scripts are limited in speed.  You may
Xexit a command by typing a rubout.
X
X%%%
X		echo ;;
X	* )
X		echo "No such command." ;;
X	esac
Xdone
Xecho
Xecho "Goodbye -- call again soon!"
Xexit
________This_Is_The_END________
sh utmake