[net.news.notes] Improvements to NYU version of Notesfile

z@rocksvax.FUN (Jim Ziobro) (06/25/86)

I have hacked the Makefile a bit to make the NYU version of notesfile work
better with RCS and also added a program called fast.newsinput which
enters news article much faster then the normal newsinput program.

The Makefile now has a "make depend" function which automagically creates
the dependencies.  It also checks-out source files if not already
checked-out.  The make clean also cleans as much as it possibly can.

The fast.newsinput program avoids the extra copy of the article when
called from the news system.  It cuts the run time in half.

Here is the shar file for my Makefile and fast.newsinput.  Enjoy.

//Z\\
James M. Ziobro
Ziobro.Henr@Xerox.COM
{rochester,amd,sunybcs,ihnp4}!rocksvax!z
Ziobro:henr801g:xerox
#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	Makefile
#	fast.newsinput.c
# This archive created: Tue Jun 24 20:35:49 1986
cat << \SHAR_EOF > Makefile
# $Header$
#	Makefile for University of Illinois Notesfiles

# the following change from site to site
SPOOLDIR=/usr/spool/notes
ARCHDIR=/usr/spool/oldnotes
LIBDIR=/usr/lib/notes
BINDIR=/usr/local/bin
NOTES=notes
NOTESGRP=daemon

CC=cc
CFLAGS=
LFLAGS=
LIBNOTES=lib/libnotes.a
TERMCAP=-ltermcap
CHGRP=chgrp
CHOWN=/etc/chown
LN=ln
BINCMDS=notes nfstats nfprint checknotes
LIBCMDS=mknf rmnf newsinput newsoutput nfarchive nfdump nfrcv inotes\
	fast.newsinput
LIBSRC=lib/*.c

# This is for make depend:
CFILES=\
    access.c adnote.c archiver.c checknotes.c control.c display.c dropt.c\
    dump.c header.c inotes.c limindex.c loadem.c miscio.c mknf.c mstindex.c\
    newsfuncs.c newsinput.c newsoutput.c nfarchive.c nfmail.c nfprint.c\
    nfrcv.c nfstats.c notes.c readem.c rmnf.c tio.c\
    fast.newsinput.c

all:    $(BINCMDS) $(LIBCMDS)

$(LIBNOTES): $(LIBSRC)
	cd lib; make

# RCS commands
.c.c:
	co $<

# User programs

notes:	notes.o control.o mstindex.o dropt.o access.o \
	readem.o adnote.o display.o miscio.o limindex.o tio.o
	cc $(CFLAGS) $(LFLAGS) -o notes \
	notes.o control.o mstindex.o dropt.o access.o \
	readem.o adnote.o display.o miscio.o limindex.o tio.o \
	$(LIBNOTES) $(TERMCAP)

nfmail:	nfmail.o
	cc $(CFLAGS) $(LFLAGS) -o nfmail nfmail.o $(LIBNOTES)

nfstats:	nfstats.o
	cc $(CFLAGS) $(LFLAGS) -o nfstats nfstats.o $(LIBNOTES)

nfprint: nfprint.o
	cc $(CFLAGS) $(LFLAGS) -o nfprint nfprint.o $(LIBNOTES)

checknotes: checknotes.o
	cc $(CFLAGS) $(LFLAGS) -o checknotes checknotes.o $(LIBNOTES)

# Network Transmission and reception

fast.newsinput: fast.newsinput.o header.o newsfuncs.o
	cc $(CFLAGS) $(LFLAGS) -o fast.newsinput \
	fast.newsinput.o header.o newsfuncs.o $(LIBNOTES)

newsinput: newsinput.o header.o newsfuncs.o
	cc $(CFLAGS) $(LFLAGS) -o newsinput \
	newsinput.o header.o newsfuncs.o $(LIBNOTES)

newsoutput: newsoutput.o
	cc $(CFLAGS) $(LFLAGS) -o newsoutput \
	newsoutput.o $(LIBNOTES)

# These programs are defunct

nfxmit:	nfxmit.o nfalias.o nfsend.o
	cc $(CFLAGS) $(LFLAGS) -o nfxmit nfxmit.o nfalias.o nfsend.o \
	$(LIBNOTES)

nfrcv:	nfrcv.o loadem.o
	cc $(CFLAGS) $(LFLAGS) -o nfrcv nfrcv.o loadem.o $(LIBNOTES)

nfdump: dump.o
	cc $(CFLAGS) $(LFLAGS) -o nfdump dump.o $(LIBNOTES)

nfpipe:	nfpipe.o
	cc $(CFLAGS) $(LFLAGS) -o nfpipe nfpipe.o $(LIBNOTES)

# Utility programs

mknf:	mknf.o
	cc $(CFLAGS) $(LFLAGS) -o mknf mknf.o $(LIBNOTES)

rmnf:	rmnf.o
	cc $(CFLAGS) $(LFLAGS) -o rmnf rmnf.o $(LIBNOTES)

nfarchive: nfarchive.o archiver.o
	cc $(CFLAGS) $(LFLAGS) -o nfarchive nfarchive.o archiver.o $(LIBNOTES)

inotes:	inotes.o
	cc $(CFLAGS) $(LFLAGS) -o inotes inotes.o $(LIBNOTES)

install: all
	cp $(LIBCMDS) $(LIBDIR)
	- cd $(LIBDIR); $(CHOWN) $(NOTES) $(LIBCMDS); \
	$(CHGRP) $(NOTESGRP) $(LIBCMDS); chmod 6711 $(LIBCMDS)
	cp $(BINCMDS) $(BINDIR)
	cd $(BINDIR); $(CHOWN) $(NOTES) $(BINCMDS); \
	$(CHGRP) $(NOTESGRP) $(BINCMDS); chmod 2711 $(BINCMDS)
	cp notesmail.sh $(LIBDIR)/notesmail
	cp sendbatch.sh $(LIBDIR)/sendbatch
	chmod 755 $(LIBDIR)/notesmail $(LIBDIR)/sendbatch
	rm -f $(BINDIR)/rnotes
	$(LN) -s $(LIBDIR)/newsinput $(BINDIR)/rnotes
	@echo "Notesfiles installed"

setup: all
	sh install.sh $(NOTES) $(NOTESGRP) $(SPOOLDIR) $(ARCHDIR) $(LIBDIR)

clean:
	- rm -f *.o $(BINCMDS) $(LIBCMDS)
	- rm Makefile.bak
	cd lib; make clean
	@echo
	@echo "Check for checked-in files"
	- for i in `ls RCS | sed -e s/,v//` ;\
	    do  \
		co -q -p $$i | cmp -s - $$i && (echo $$i already in RCS; rm -i $$i ) ; \
	    done

clobber:
	rm -rf $(SPOOLDIR) $(ARCHDIR) $(LIBDIR)
	cd $(BINDIR); rm -f $(BINCMDS)

lint:
	lint notes.c control.c mstindex.c dropt.c access.c \
	readem.c adnote.c display.c miscio.c limindex.c tio.c llib-lnotes.ln
	lint nfstats.c llib-lnotes.ln
	lint nfprint.c llib-lnotes.ln
	lint checknotes.c llib-lnotes.ln
	lint fast.newsinput.c header.c newsfuncs.c llib-lnotes.ln
	lint newsinput.c header.c newsfuncs.c llib-lnotes.ln
	lint mknf.c llib-lnotes.ln
	lint rmnf.c llib-lnotes.ln
	lint nfarchive.c archiver.c llib-lnotes.ln

$(BINCMDS) $(LIBCMDS): $(LIBNOTES)

depend: $(CFILES)
	grep '^#include' ${CFILES} | grep -v '<' | \
	sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' \
	    | \
	awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
		else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
		       else rec = rec " " $$2 } } \
	      END { print rec } ' | \
	sed  \
	    -e 's/[^:]*\.c:/& &:/' \
	    -e 's/\.c/.o/' \
	    -e 's/:://' \
	    > makedep
	echo '$$r makedep' >>eddep
	echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
	echo '$$r makedep' >>eddep
	echo 'w' >>eddep
	- rm Makefile.bak
	cp Makefile Makefile.bak
	ed - Makefile < eddep
	rm eddep makedep

# DO NOT DELETE THIS LINE -- make depend uses it

SHAR_EOF
cat << \SHAR_EOF > fast.newsinput.c
#ifndef lint
static char *RCSid = "$Header: fast.newsinput.c,v 1.1 86/06/24 19:10:04 z Rel $";
#endif

/*
 * $Log:	fast.newsinput.c,v $
 * Revision 1.1  86/06/24  19:10:04  z
 * Initial revision
 * 
 */

/*
 * This program will accept a series of news article file names specified
 * on the command line.
 * The articles will then be inserted in
 * the notefile(s) which match the newsgroup(s) for each article.  
 *
 * This program is just a fast variant of newsinput.c and is to be called
 * out of the news "sys" file with a line like:
    NOTES:net,mod,ny:U:/usr/lib/notes/fast.newsinput %s
 *
 * Note: Everything other than the main routine is a copy from newsinput.c.
 *
 */

#include "parms.h"
#include "structs.h"
#include "header.h"

#define	NUMGROUPS	5

static char title[TITLEN];			/* title */
static int has_suffix;
static int re_seen;
static long savepos;

FILE *hread();
char *malloc();
char *index();
long ftell();
long atol();
time_t cgtdate();


/*
 * driving routine to handle a processed article
 * (all the headers are already in place)
 *
 */
main(argc,argv)
int argc;
char *argv[];
{
	register long size;
	int nart;

	initenv();

	for( nart=1; nart<=argc; nart++) proc2(argv[nart]);

	exit(GOOD);
}

static struct hbuf hb;

/*
 * a processed message is in a file
 * get the header and process each notesfile in turn.
 */
proc2(file)
	char *file;
{
	FILE *rawnews;
	struct hbuf *hp = &hb;
	int i, c;
	struct io_f io;
	char nf[NNLEN];				/* the notefile */
	char ngroup[NUMGROUPS][WDLEN];		/* newsgroups name */
	int numgroups;			/* number of groups to post to */
	char line[CMDLEN];		/* scratch */
	char *p, *q;
	int errs, status, ret;

	/* open up the article */
	if ((rawnews = fopen(file, "r")) == NULL) {
		log("newsinput: can not process %s", file);
		return;
	}
	/* Parse the header */
	if (hread(&hb, rawnews, TRUE) == NULL) {
		log("newsinput: %s garbled header", hb.ident);
		return;
	}
	hp = &hb;

	savepos = ftell(rawnews);

	/* check if this is a notes generated article */
	status = isnotes(hp, rawnews);
	gettitle(hp->title);

	/* get the date */
	hp->subtime = cgtdate(hp->subdate);
	time(&hp->rectime);

	/* get the newsgroups */
	p = hp->nbuf; 
	numgroups = 0;
	errs = 0;
	while (numgroups < NUMGROUPS) {
		while (*p == ' ' || *p == '\t' || *p == NGDELIM)
			p++;
		if (*p == 0)
			break;
		q = ngroup[numgroups];
		while (c = *p++) {
			if (c == NGDELIM || c == ' ' || c == '\t')
				break;
			*q++ = c;
		}
		*q = 0;
		if (!invalid(ngroup[numgroups]))
			numgroups++;
		else
			errs++;
	}
	/* insert in junk notesfile only if we have no valid entries */
	if (errs && numgroups == 0) {
		strcpy(ngroup[0], JUNK);
		numgroups = 1;
	}

	for (i = 0; i < numgroups; i++) {
		newsgroup(ngroup[i], nf);
#ifdef CTRLMSG
		if (strlen(hp->ctlmsg) != 0) {
			/* SHOULD DO ALOT MORE HERE */
			/* dump control messages */
			strcpy(nf, CTRLMSG);
		}
#endif CTRLMSG
		/* well is it there? */
		ret = init(&io, nf);
#ifdef AUTOCREATE
		if (ret == QUITNEX) {
			/* try to create the notes file - RLS */
			sprintf(line, "%s/mknf", LIBDIR);
			dosystem(line, "-on", nf, NOSTR);
			if ((ret = init(&io, nf)) < 0) {
				sprintf(line, "notesfile: %s, newsgroup %s\n",
				    ngroup[i], nf);
				nfcomment(NOSUCHWARN, line, "Failure", 0, 0);
				log("created failed: %s", nf);
				continue;
			}
			sprintf(line, "Created: %s\n", nf);
			nfcomment(NOSUCHWARN, line, line, 0, 0);
			log("created: %s", nf);
		}
#endif
		if (ret < 0) {
			sprintf(line, "notesfile: %s, newsgroup %s\n",
			    ngroup[i], nf);
			nfcomment(NOSUCHWARN, line, "Failure", 0, 0);
			log("%s: open failed: %s", hp->ident, nf);
			continue;
		}

		if ((io.descr.d_stat & NETWRKD) == 0) {
			/* not networked */
			log("%s: %s not networked", hp->ident, nf);
			finish(&io);
			continue;
		}

		if (insertart(&io, hp, rawnews) < 0) {
			finish(&io);
			continue;
		}

		lock(&io, 'n');
		getdscr(&io, &io.descr);
		io.descr.netwrkins++;		/* count as net in */
		putdscr(&io, &io.descr);
		unlock(&io, 'n');
		finish(&io);
	}
	fclose(rawnews);
}

/*
 * Notesfile specific processing
 */
insertart(io, hp, rawnews)
	struct io_f *io;
	struct hbuf *hp;
	FILE *rawnews;
{
	struct note_f note;
	struct note_f note2;
	int notenum;
	char psys[SYSSZ], puniq[IDSZ];

	parseid(hp->ident, puniq, psys);
	getperms(io, 1, psys);
	if (allow(io, WRITOK) == 0) {
		log("%s: %s: %s may not write notes", io->nf, hp->ident, psys);
		return(-1);
	}

	strcpy(note.n_title, title);
	note.n_msg.m_stat = FRMNEWS;		/* came from news system */

	lock(io, 'n');
	notenum = chknote(io, hp->ident, &note2);
	if (notenum > 0) {
		if ((note2.n_msg.m_stat & ORPHND) == 0) {
			log("%s: %s: duplicate note", io->nf, hp->ident);
			unlock(io, 'n');
			return(-1);
		}
		/* replace foster parent */
		puthdr(io, &note.n_msg, hp);
		pagein(io, rawnews, &note.n_msg.m_addr);   /* collect text */
		note2.n_msg = note.n_msg;
		note2.n_lmod = hp->rectime;
		putnrec(io, notenum, &note2);	/* and replace */
		unlock(io, 'n');
		log("%s: %s: orhpan replaced", io->nf, hp->ident);
		return(0);
	}
	/*
	 * For notesfiles where we always post with the same title!
	 *	e.g., ai-list or news
	 */
	if (re_seen) {
		strcpy(io->xstring, title);
		notenum = findtitle(io, io->descr.d_nnote);
		if (notenum > 0)
			getnrec(io, notenum, &note2);
	}
	fseek(rawnews, savepos, 0);
	if (re_seen == 0 || notenum <= 0) {
		puthdr(io, &note.n_msg, hp);
		pagein(io, rawnews, &note.n_msg.m_addr);
		notenum = putnote(io, &note, NOPOLICY, ADDTIME);
		/* count as networked in */
		log("%s: %s note inserted", io->nf, hp->ident);
		io->nnotrcvd++;
	} else if (notenum > 0 && !chkresp(io, hp->ident, &note2, notenum)) {
		puthdr(io, &note.n_msg, hp);
		pagein(io, rawnews, &note.n_msg.m_addr);
		putresp(io, notenum, &note2, &note.n_msg, ADDTIME);
		log("%s: %s response inserted", io->nf, hp->ident);
		io->nrsprcvd++;
	} else
		log("%s: %s duplicate response", io->nf, hp->ident);
	unlock(io, 'n');
	return(0);
}

/*
 * pull out relevant fields from the notes header
 * (currently only the status word)
 * if this is an old style note header (in the body of the text),
 * read past these lines.
 */
isnotes(hp, rawnews)
	struct hbuf *hp;
	FILE *rawnews;
{
	int status;
	int found;
	int i;

	if (strlen(hp->nf_id) == 0) {
		/*
		 * No notes header in the B news article header...
		 * If title ends with "- nf", look for the
		 * header in the body of the text.
		 * (for backwards compatability)
		 */
		if (has_suffix == 0)
			return(0);
		found = 0;
		while (fgets(hp->nf_id, sizeof hp->nf_id, rawnews)) {
			if (hp->nf_id[0] == '#') {
				found++;
				break;
			}
		}
		if (!found ||
		    fgets(hp->nf_from, sizeof hp->nf_from, rawnews) == NULL)
			goto bad;
		savepos = ftell(rawnews);
	}

	if (hp->nf_id[0] != '#')
		goto bad;
	if (hp->nf_id[1] == 'N') {
		/* base note coming through news */
		i = sscanf(hp->nf_id, "#N:%*[^:]:%*ld:%o:%*d", &status);
		if (i == 4)
			return(status);
	} else if (hp->nf_id[1] == 'R') {
		/* response coming through news */
		i = sscanf(hp->nf_id,
		    "#R:%*[^:]:%*ld:%*[^:]:%*ld:%o:%*d", &status);
		if (i == 6)
			return(status);
	}
bad:
	return(0);
}

/*
 * A quick hack to check newsgroup name validity.
 * Eventually this needs to allow wildcards (either like the
 * subscribe/unsubscribe facility or the sys file in B news).
 */
invalid(name)
	char *name;
{
	register int i;
	FILE *f;
	char buf[CMDLEN];

	sprintf(buf, "%s/%s", LIBDIR, INVALID);
	if ((f = fopen(buf, "r")) == NULL)
		return(0);
	while (fgets(buf, sizeof buf, f)) {
		i = strlen(buf) - 1;
		if (strncmp(name, buf, i) == 0) {
			fclose(f);
			return(1);
		}
	}
	fclose(f);
	return(0);
}

/*
 * get the generic notes title
 */
gettitle(s)
	char *s;
{
	register char *p, *q;

	/*
	 * see if a followup; strip all "Re:"'s
	 */
	p = s;
	while ((p[0] == 'R' || p[0] == 'r') && (p[1] == 'e' || p[1] == 'E') &&
	    p[2] == ':') {
		p += 3;
		/* Skip Spaces */
		while (*p == ' ' || *p == '\t')
			p++;
		re_seen = 1;
	}
	safecpy(title, p, TITLEN);
	/*
	 * Check for titles ending in "- nf".
	 * We always remove these.
	 */
	p = q = title;
	while (*p) {
		if (*p == '-')
			q = p;
		p++;
	}
	has_suffix = 0;
	if (strcmp(q, NFSUFFIX) == 0 || strcmp(q, OLDSUFFIX) == 0) {
		if (--q > title)
			*q = '\0';	/* remove " - (nf)" suffix */
		has_suffix++;
	}
}
SHAR_EOF
#	End of shell archive
exit 0