[news.software.notes] Better news->notes gateway code

rs@mirror.UUCP (05/12/87)

I have recently been hacking on the News->Notes gateway code.  Below is
a shar (diffs are too big, sorry) of three files.  Here's the features:

  BNEWSHEAD.C NEWSGATE.H
    Add "Summary:" header; fix bug in type() routine; don't add domain
    if one is already there.

  NEWSINPUT.C
    Fix for more stringent check on old-style notes headers; copyauth()
    bugfix; try hard to get a message-id, use a CRC or current time as a
    last resort; scan the news active file for legal groups, to avoid
    creating bogus groups; and -- the BIG THING -- allow newsinput to
    accept batched input:
	newsinput -b file		file is list of articles to read
	newsinput file			file is one article
	newsinput <file			article is on stdin
    Also has provisions for processing news CONTROL messages; someone
    else will have to write this...

Bug reports, comments, complaints encouraged.
	/r$

#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If this archive is complete, you will see the message:
#		"End of shell archive."
# Contents:  bnewshead.c newsgate.h newsinput.c
# Wrapped by rs@mirror on Mon May 11 17:45:08 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo shar: Extracting \"bnewshead.c\" \(12682 characters\)
if test -f bnewshead.c ; then 
  echo shar: Will not over-write existing file \"bnewshead.c\"
else
sed "s/^X//" >bnewshead.c <<'END_OF_bnewshead.c'
X/*
X * header.c - header functions plus some other goodies
X *
X *	TAKEN FROM BNEWS 2.10 6/24/83
X *
X */
X
X#ifdef	RCSIDENT
Xstatic char *SccsId = "@(#)header.c	2.20	6/24/83";
Xstatic char *RCSid = "$Header: bnewshead.c,v 1.3 87/05/11 17:41:50 rs Exp $";
X#endif	RCSIDENT
X
X#include <stdio.h>
X#include <sys/types.h>
X#include	"parms.h"				/* from notes */
X#include	"structs.h"				/* ditto */
X							/* above maybe unused */
X#include	"newsgate.h"
X
X
Xchar   *hfgets ();
X
Xstatic int  seenrelay;
Xstatic char bfr[PATHLEN];				/* header buffer */
X
X/*
X * Read header from file fp into *hp.  If wholething is FALSE,
X * it's an incremental read, otherwise start from scratch.
X * Return (FILE *) if header okay, else NULL.
X */
X
Xnewsheader (hp, fp, wholething)
Xregister struct hbuf   *hp;
XFILE * fp;
Xint     wholething;
X{
X    register int    len;
X
X    if (wholething)					/* from scratch */
X	bclear ((char *) hp, sizeof (*hp));
X
X    seenrelay = 0;
X
X/*
X *	Check that it's a B news style header.
X */
X    if (((hfgets (bfr, PATHLEN, fp) != NULL &&
X		    *bfr >= 'A' && *bfr <= 'Z') && index (bfr, ':')))
X	if (frmread (fp, hp))
X	    goto strip;
X
X/*
X * It's not.  Try A news (begins with PROTO).
X */
X    if (*bfr != PROTO)
X	return (0);
X
X/*
X *	Read in an A news format article.
X */
X    strncpy (hp -> oident, &(bfr[1]), NAMELEN);		/* file name */
X    if (!nstrip (hp -> oident))
X	return (0);
X    hfgets (hp -> nbuf, BUFLEN, fp);			/* newsgroup list */
X    if (!nstrip (hp -> nbuf))
X	return (0);
X    ngcat (hp -> nbuf);					/* trailing delim */
X    hfgets (hp -> path, PATHLEN, fp);			/* source path */
X    if (!nstrip (hp -> path))
X	return (0);
X    hfgets (hp -> subdate, DATELEN, fp);		/* date */
X    if (!nstrip (hp -> subdate))
X	return (0);
X    hfgets (hp -> title, BUFLEN, fp);			/* title */
X    if (!nstrip (hp -> title))
X	return (0);
X
X/*
X * strip off sys! from front of path.
X */
Xstrip: 
X    strcpy (bfr, System);
X    if (strncmp (bfr, hp -> path, (len = strlen (bfr))) == 0
X	    && index (NETCHRS, hp -> path[len]))
X	strcpy (hp -> path, &(hp -> path[len + 1]));
X
X    if (wholething && hp -> from[0] == '\0')		/* intuit the from: */
X	intuitfrom (hp);				/* if wasn't there */
X
X    if (wholething)					/* Get message ID's. */
X	fixid (hp);
X    return (1);
X}
X
X
X/*
X * Get header info from mail-format file.
X * Return non-zero on success.
X */
X
X#include <ctype.h>
X#define FROM 		1
X#define NEWSGROUP 	2
X#define TITLE 		3
X#define SUBMIT		4
X#define RECEIVE		5
X#define EXPIRE		6
X#define ARTICLEID	7
X#define MESSAGEID	8
X#define REPLYTO		9
X#define FOLLOWID	10
X#define CONTROL		11
X#define SENDER		12
X#define FOLLOWTO	13
X#define PATH		14
X#define POSTVERSION	15
X#define RELAYVERSION	16
X#define DISTRIBUTION	17
X#define ORGANIZATION	18
X#define NUMLINES	19
X#define KEYWORDS	20
X#define APPROVED	21
X
X#define	NLINE1		22
X#define	NLINE2		23
X
X#define SUMMARY		24
X
X#define OTHER		99
X
X
Xchar   *malloc ();
X
Xfrmread (fp, hp)
Xregister    FILE * fp;
Xregister struct hbuf   *hp;
X{
X    int     unreccnt = 0;
X    register int    i;
X    long    curpos;
X    int     hdrlineno = 0;
X    int     iu;
X
X    for (iu = 0; iu < NUNREC; iu++)
X	hp -> unrec[iu] = NULL;
X
X    i = type (bfr);
X    do
X    {
X	curpos = ftell (fp);
X	hdrlineno++;
X	switch (i)
X	{
X	    case PATH: 
X		getfield (hp -> path);
X		break;
X	    case FROM: 
X		getfield (hp -> from);
X		break;
X	    case NEWSGROUP: 
X		getfield (hp -> nbuf);
X		break;
X	    case TITLE: 
X		getfield (hp -> title);
X		break;
X	    case SUBMIT: 
X		getfield (hp -> subdate);
X		break;
X	    case RECEIVE: 
X		getfield (hp -> recdate);
X		break;
X	    case EXPIRE: 
X		getfield (hp -> expdate);
X		break;
X	    case ARTICLEID: 
X		getfield (hp -> oident);
X		break;
X	    case MESSAGEID: 
X		getfield (hp -> ident);
X		break;
X	    case REPLYTO: 
X		getfield (hp -> replyto);
X		break;
X	    case FOLLOWID: 
X		getfield (hp -> followid);
X		break;
X	    case SENDER: 
X		getfield (hp -> sender);
X		break;
X	    case FOLLOWTO: 
X		getfield (hp -> followto);
X		break;
X	    case CONTROL: 
X		getfield (hp -> ctlmsg);
X		break;
X	    case POSTVERSION: 
X		getfield (hp -> postversion);
X		break;
X	    case DISTRIBUTION: 
X		getfield (hp -> distribution);
X		break;
X	    case ORGANIZATION: 
X		getfield (hp -> organization);
X		break;
X	    case NUMLINES: 
X		getfield (hp -> numlines);
X		hp -> intnumlines = atoi (hp -> numlines);
X		break;
X	    case KEYWORDS: 
X		getfield (hp -> keywords);
X		break;
X	    case SUMMARY: 
X		getfield (hp -> summary);
X		break;
X	    case APPROVED: 
X		getfield (hp -> approved);
X		break;
X	    case NLINE1: 				/* notes-specific */
X		getfield (hp -> nline1);
X		break;
X	    case NLINE2: 				/* notes-specific */
X		getfield (hp -> nline2);
X		break;
X	    case RELAYVERSION: 
X		/* 
X		 * Only believe a relay version if it's the first
X		 * line, otherwise it probably got passed through
X		 * by some old neighbor.
X		 */
X		if (hdrlineno == 1)
X		{
X		    getfield (hp -> relayversion);
X		    seenrelay = 1;
X		}
X		break;
X	    case OTHER: 
X		if (unreccnt < NUNREC)
X		{
X		    hp -> unrec[unreccnt] = malloc (strlen (bfr) + 1);
X		    strcpy (hp -> unrec[unreccnt], bfr);
X		    unreccnt++;
X		}
X		break;
X	}
X    } while ((i = type (hfgets (bfr, LBUFLEN, fp))) > 0);
X
X    if (*bfr != '\n')
X    {
X	printf ("Bizzaro header line: %s\n", bfr);
X	return (0);
X    }
X
X/*
X *	Check to see if the REQUIRED headers are present.  If so, return
X *	that we found a message. Otherwise barf.
X */
X    if ((hp -> from[0] || hp -> path[0]) &&
X	    hp -> subdate[0] &&
X	    (hp -> ident[0] || hp -> oident[0]))
X    {
X	return TRUE;
X    }
X    return FALSE;
X}
X
X/*
X * There was no From: line in the message (because it was generated by
X * an old news program).  Guess what it should have been and create it.
X */
X
Xintuitfrom (hp)
Xregister struct hbuf   *hp;
X{
X    char   *tp;
X    char   *user,
X           *host,
X           *fullname;
X    char   *tailpath ();
X    char   *at,
X           *dot;
X
X    tp = tailpath (hp);
X    user = rindex (tp, '!');
X    if (user == NULL)
X	user = tp;
X    else
X	*user++ = '\0';
X
X    /* Check for an existing Internet address on the end. */
X    at = index (user, '@');
X    if (at)
X    {
X	dot = index (at, '.');
X	if (dot)
X	{
X	    strcpy (hp -> from, user);
X	    return;
X	}
X/* @ signs are illegal except for the biggie, so */
X	*at = '%';
X    }
X
X    if (tp[0] == '.')
X	host = index (tp, '!') + 1;
X    else
X	if (user == tp)
X	    host = System;
X	else
X	    host = tp;
X
X    tp = index (host, '@');
X    if (tp != NULL)
X	*tp = 0;
X    if (index (host, '.') != NULL)
X	/* Already got a domain there. */
X	sprintf (hp -> from, "%s@%s", user, host);
X    else
X	sprintf (hp -> from, "%s@%s.%s", user, host, DFLTDOMAIN);
X
X    fullname = index (hp -> path, '(');
X    if (fullname != NULL)
X    {
X	fullname--;
X	strcat (hp -> from, fullname);
X	*fullname = 0;
X    }
X}
X
X/*
X * If the message has only one of ident/oident, guess what
X * the other one should be and fill them both in.
X */
X
Xfixid (hp)
Xregister struct hbuf   *hp;
X{
X    char    lbuf[100];
X    char   *p;
X#ifdef	OLD
X    char   *q;
X#endif	OLD
X
X    if (hp -> ident[0] == '\0' && hp -> oident[0] != '\0')
X    {
X	strcpy (lbuf, hp -> oident);
X	p = index (lbuf, '.');
X	if (p == 0)
X	{
X	    strcpy (hp -> ident, hp -> oident);
X	    return;
X	}
X	*p++ = '\0';
X	/* 
X	 * It may seem strange that we hardwire ".UUCP" in
X	 * here instead of DFLTDOMAIN.  However, we are trying
X	 * to guess what the domain was on the posting system,
X	 * not the local system.  Since we don't really know
X	 * what the posting system does, we just go with the
X	 * majority - almost everyone will be a .UUCP if they
X	 * didn't fill in their Message-ID.
X	 */
X	sprintf (hp -> ident, "<%s@%s%s>", p, lbuf, ".UUCP");
X    }
X
X#ifdef OLD
X    if (hp -> oident[0] == '\0' && hp -> ident[0] != '\0')
X    {
X	strcpy (lbuf, hp -> ident);
X	p = index (lbuf, '@');
X	if (p == 0)
X	{
X	    strcpy (hp -> oident, hp -> ident);
X	    return;
X	}
X	*p++ = '\0';
X	q = index (p, '.');
X	if (!q)
X	    q = index (p, '>');
X	if (q)
X	    *q++ = '\0';
X	p[SNLN] = '\0';
X	sprintf (hp -> oident, "%s.%s", p, lbuf + 1);
X    }
X#endif
X}
X
X/*
X * Get the given field of a header (char * parm) from bfr, but only
X * if there's something actually there (after the colon).  Don't
X * bother if we already have an entry for this field.
X */
X
Xgetfield (hpfield)
Xchar   *hpfield;
X{
X    char   *ptr;
X
X    if (hpfield[0])
X	return;
X    for (ptr = index (bfr, ':'); isspace (*++ptr);)
X	;
X    if (*ptr != '\0')
X    {
X	strcpy (hpfield, ptr);
X	nstrip (hpfield);
X    }
X    return;
X}
X
X
X/*
X *	Determine the type of the header
X */
X
X#define	its(type) (!strncmp(ptr,type,strlen(type)))
X
Xtype (ptr)
Xchar   *ptr;
X{
X    char   *colon, *space;
X
X    if (!isalpha (*ptr) && strncmp (ptr, "From ", 5))
X	return FALSE;
X    if (its ("From: "))
X	if (index (ptr, '@') && !index (ptr, '!') && seenrelay)
X	    return FROM;
X	else
X	    return PATH;
X    if (its ("Path: "))
X	return PATH;
X    if (its ("Newsgroups: "))
X	return NEWSGROUP;
X    if (its ("Subject: ") || its ("Title: "))
X	return TITLE;
X    if (its ("Posted: ") || its ("Date: "))
X	return SUBMIT;
X    if (its ("Date-Received: ") || its ("Received: "))
X	return RECEIVE;
X    if (its ("Expires: "))
X	return EXPIRE;
X    if (its ("Article-I.D.: "))
X	return ARTICLEID;
X    if (its ("Message-ID: "))
X	return MESSAGEID;
X    if (its ("Reply-To: "))
X	return REPLYTO;
X    if (its ("References: "))
X	return FOLLOWID;
X    if (its ("Control: "))
X	return CONTROL;
X    if (its ("Sender: "))
X	return SENDER;
X    if (its ("Followup-To: "))
X	return FOLLOWTO;
X    if (its ("Posting-Version: "))
X	return POSTVERSION;
X    if (its ("Relay-Version: "))
X	return RELAYVERSION;
X    if (its ("Distribution: "))
X	return DISTRIBUTION;
X    if (its ("Organization: "))
X	return ORGANIZATION;
X    if (its ("Lines: "))
X	return NUMLINES;
X    if (its ("Keywords: "))
X	return KEYWORDS;
X    if (its ("Approved: "))
X	return APPROVED;
X    if (its ("Summary:"))
X	return SUMMARY;
X    if (its ("Nf-ID: "))
X	return NLINE1;
X    if (its ("Nf-From: "))
X	return NLINE2;
X    colon = index (ptr, ':');
X    space = index (ptr, ' ');
X    if (!colon || space && space < colon)
X	return FALSE;
X    return OTHER;
X}
X
X/*
X * Set nc bytes, starting at cp, to zero.
X */
X
Xbclear (cp, nc)
Xregister char  *cp;
Xregister int    nc;
X{
X    while (nc--)
X	*cp++ = 0;
X}
X
X/*
X * Strip trailing newlines, blanks, and tabs from 's'.
X * Return TRUE if newline was found, else FALSE.
X */
X
Xnstrip (s)
Xregister char  *s;
X{
X    register char  *p;
X    register int    rc;
X
X    rc = FALSE;
X    p = s;
X    while (*p)
X	if (*p++ == '\n')
X	    rc = TRUE;
X    while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t'));
X    *++p = '\0';
X    return (rc);
X}
X
X/*
X * Append NGDELIM to string.
X */
X
Xngcat (s)
Xregister char  *s;
X{
X    if (*s)
X    {
X	while (*s++);
X	s -= 2;
X	if (*s++ == NGDELIM)
X	    return;
X    }
X    *s++ = NGDELIM;
X    *s = '\0';
X}
X
X/*
X * Return a compact representation of the person who posted the given
X * message.  A sender or internet name will be used, otherwise
X * the last part of the path is used preceeded by an optional ".."
X */
Xchar   *
X        tailpath (hp)
Xstruct hbuf *hp;
X{
X    char   *p,
X           *r;
X    static char resultbuf[BUFLEN];
X    char    pathbuf[PATHLEN];
X    char   *malloc ();
X
X    /* 
X     * This only happens for articles posted by old news software
X     * in non-internet format.
X     */
X    resultbuf[0] = '\0';
X    strcpy (pathbuf, hp -> path);
X    p = index (pathbuf, ' ');
X    if (p)
X	*p = '\0';					/* Chop off trailing " (name)" */
X    r = rindex (pathbuf, '!');
X    if (r == 0)
X    {
X	r = pathbuf;
X    }
X    else
X    {
X	while (r > pathbuf && *--r != '!')
X	    ;
X	if (r > pathbuf)
X	{
X	    r++;
X	    strcpy (resultbuf, "..!");
X	}
X    }
X    strcat (resultbuf, r);
X    return resultbuf;
X}
X
X
X
X/*
X * hfgets is like fgets, but deals with continuation lines.
X * It also ensures that even if a line that is too long is
X * received, the remainder of the line is thrown away
X * instead of treated like a second line.
X */
X
Xchar   *hfgets (buf, len, fp)
Xchar   *buf;
Xint     len;
XFILE * fp;
X{
X    register int    c;
X    register char  *cp,
X                   *tp;
X
X    cp = fgets (buf, len, fp);
X    if (cp == NULL)
X	return NULL;
X
X    tp = cp + strlen (cp);
X    if (tp[-1] != '\n')
X    {
X	/* 
X	 * Line too long - part read didn't fit into a newline
X	 */
X	while ((c = getc (fp)) != '\n' && c != EOF)
X	    ;
X    }
X    else
X	*--tp = '\0';					/* clobber newline */
X
X    while ((c = getc (fp)) == ' ' || c == '\t')		/* continuation */
X    {
X	/* 
X	 * Continuation line.
X	 */
X	while ((c = getc (fp)) == ' ' || c == '\t')	/* skip white space */
X	    ;
X	if (tp - cp < len)
X	{
X	    *tp++ = ' ';
X	    *tp++ = c;
X	}
X	while ((c = getc (fp)) != '\n' && c != EOF)
X	    if (tp - cp < len)
X		*tp++ = c;
X    }
X    *tp++ = '\n';
X    *tp++ = '\0';
X    if (c != EOF)
X	ungetc (c, fp);					/* push back char */
X    return cp;
X}
END_OF_bnewshead.c
if test 12682 -ne `wc -c <bnewshead.c`; then
    echo shar: \"bnewshead.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: Extracting \"newsgate.h\" \(5317 characters\)
if test -f newsgate.h ; then 
  echo shar: Will not over-write existing file \"newsgate.h\"
else
sed "s/^X//" >newsgate.h <<'END_OF_newsgate.h'
X#if	defined(RCSIDENT) && defined(MAINLINE)
Xstatic char *zznewsgate = "$Header: newsgate.h,v 1.8 87/05/11 17:41:35 rs Exp $";
X#endif	defined(RCSIDENT) && defined(MAINLINE)
X
X/*
X *	newsgate.h
X *
X *	This file contains the definitions needed for the notesfile/news
X *	gateway features.
X *
X *	The new (April 4) implementation allows gateing from news to 
X *	notesfiles at ANY site. Gateing from notes to news is allowed 
X *	by a SINGLE site (for any given newsgroup) per notesfile 'subnet'.
X *
X *	An example:
X *	4 sites running notesfiles: A,B,C and D.
X *
X *	Both A and B run news alongside the notesfile program.
X *	A and B both gateway news into notesfiles; this is safe
X *	and does not generate duplicate articles.
X *	Neither C nor D run news; they do want the articles they
X *	have written to go to the news system beyond A and B.
X *	Sites A and B should at least gateway their locally generated
X *	articles to news.  Sites C and D should each make their own
X *	arrangements to have their articles passed to the news
X *	networks.  Good criteria for choosing the site include
X *	the load of the machine to gateway, how well it is connected
X *	to the rest of the network and who runs the machine.
X *	In this case, suppose C goes with A and D goes with B.
X *	The gateway scripts will look something like:
X *
X *	On A:
X *		newsoutput list			(local articles (A))
X *		newsoutput -sC list		(C's articles)
X *
X *	On B:
X *		newsoutput list			(local articles (B))
X *		newsoutput -sD list		(D's articles)
X *
X *
X *	Original Coding:	Ray Essick	April 4, 1982
X *
X */
X
X/*
X *	Definitions that are likely to change between sites:
X */
X
X#define		DFLTRNEWS		"rnews"		/* if getnet fails */
X#undef		EXPANDPATH				/* do indirect links */
X#define		DFLTDOMAIN	"UUCP"			/* if undomained */
X#define		PATHMAP		"/etc/usemap"		/* path to the paths */
X
X/*
X *	definitions that aren't likely to be changed.
X */
X
X#define RNEWSNAME	"Usenet"			/* getnet pseudohost */
X#define	NEWSSYS		"Anysystem"			/* news' sequencer */
X#define	NEWSSEQ		"News"				/* prefix for above */
X#define	NEWSALIAS	"newsgroups"			/* mapping file */
X#define	NGRPLEN		30				/* longest newsgroup */
X#define	NEWSNF		1				/* alias news->nf */
X#define	NFBASENEWS	2				/* alias nf->news */
X#define	NFRESPNEWS	3				/* alias nf->news */
X#define	OLDSUFFIX	"- from a notesfile"		/* catch loops */
X#define	NFSUFFIX	"- (nf)"			/* catch nf-news-nf */
X#define	CTL		".ctl"				/* control msgs */
X#define	SLEEPTIME	10				/* between rnews' */
X#define	GATEMAX		100				/* for newsoutput -c */
X
X/*
X *	classes to send back
X */
X
X#define		NEWS_ALLSEND	001			/* all non-local */
X#define		NEWS_LOCALSEND	002			/* local articles */
X
X
X/*
X *	stuff to be compatible with Salkind/Spickelmier work
X *	Most of these are carried over from the news system.
X */
X
X#define	NGDELIM		','
X#define	NEGCHAR		'!'				/* negation */
X#define	PROTO		'A'				/* A-news protocol */
X#define	NUMGROUPS	5
X
X/*
X *	Definitions for the New and Improved version thanks to
X *	Tw Cook of Hewlett-Packard.
X */
X
X#define		NFLINE1	"Nf-ID"				/* parent, etc */
X#define		NFLINE2	"Nf-From"			/* author,dates */
X
X
Xextern char *tzone ();					/* in newsdump.c */
Xextern char *getpath ();				/* in newspath.c */
Xextern char *Version;					/* in newsdump.c */
Xextern char rnewscmd[];					/* in newsoutput.c */
Xextern int  sendclass;					/* classes to send */
X
X/*
X *	The following lines are from the B-news program.
X *
X * header.h - Article header format
X *
X *	@(#)header.h	2.11	4/24/83";
X */
X
X#define		NUNREC 		50			/* bnews:header.h */
X#define		BUFLEN		256			/* bnews:defs.h */
X#define		PATHLEN		512			/* bnews:defs.h */
X#define		NAMELEN		64			/* bnews:defs.h */
X#define		NETCHRS		"!:.@^%"		/* bnews:defs.h */
X#define		LBUFLEN		1024			/* bnews:defs.h */
X#define		BDATE		64			/* bnews:defs.h */
X							/* was DATELEN */
X
Xstruct hbuf						/* article header */
X{							/* bnews:header.h */
X    char    from[BUFLEN];				/* From: */
X    char    path[PATHLEN];				/* Path: */
X    char    nbuf[BUFLEN];				/* Newsgroups: */
X    char    snbuf[BUFLEN];				/* Squashed nbuf. */
X    char    title[BUFLEN];				/* Subject: */
X    char    oident[BUFLEN];				/* Article-I.D.: */
X    char    ident[BUFLEN];				/* Message-ID: */
X    char    replyto[BUFLEN];				/* Reply-To: */
X    char    followid[BUFLEN];				/* References: */
X    char    subdate[BDATE];				/* (submitted) Date: */
X    long    subtime;					/* subdate in secs */
X    char    recdate[BDATE];				/* Date-Received: */
X    long    rectime;					/* recdate in secs */
X    char    expdate[BDATE];				/* Expires: */
X    long    exptime;					/* expdate in secs */
X    char    ctlmsg[PATHLEN];				/* Control: */
X    char    sender[BUFLEN];				/* Sender: */
X    char    followto[BUFLEN];				/* Followup-to: */
X    char    postversion[BUFLEN];			/* Post-Version: */
X    char    relayversion[BUFLEN];			/* Relay-Version: */
X    char    distribution[BUFLEN];			/* Distribution: */
X    char    organization[BUFLEN];			/* Organization: */
X    char    numlines[8];				/* Lines: */
X    int     intnumlines;				/* Integer version */
X    char    keywords[BUFLEN];				/* Keywords: */
X    char    approved[BUFLEN];				/* Approved: */
X    char    summary[BUFLEN];				/* Approved: */
X    char    nline1[BUFLEN];				/* NF-Id: */
X    char    nline2[BUFLEN];				/* NF-From: */
X    char   *unrec[NUNREC];				/* unrecognized lines */
X};
END_OF_newsgate.h
if test 5317 -ne `wc -c <newsgate.h`; then
    echo shar: \"newsgate.h\" unpacked with wrong size!?
fi
# end of overwriting check
fi
if test -f newsinput.c ; then 
  echo shar: Will not over-write existing file \"newsinput.c\"
else
echo shar: Extracting \"newsinput.c\" \(33276 characters\)
sed "s/^X//" >newsinput.c <<'END_OF_newsinput.c'
X/*
X *	newsinput
X *
X *	A total re-coding of the original.  Makes use of the
X *	work that Lou Salkind and Tw Cook have done.  Lou rearranged
X *	a bunch of stuff and Tw put the notes headers into the
X *	news header.
X *
X *	Severely hacked on by Rich $alz, mirror!rs, who also snarfed code
X *	from Bob Tracy, rct@occrsh.att.com.
X */
X
X#define	MAINLINE
X#include "parms.h"
X#include "structs.h"
X#include "newsgate.h"
X#include <sys/file.h>
X#include <errno.h>
X
X#ifdef	RCSIDENT
Xstatic char rcsid[] = "$Header: newsinput.c,v 1.7 87/05/11 18:10:04 rs Exp $";
X#endif	RCSIDENT
X
X
X/*
X**  The name of the program to get control messages.  Not implemented
X**  yet, sorry -- see the notesctl() routine, below.
X*/
X#define NOTESCTL	"/usr/spool/notes/.utilities/notesctl"
X
X/*
X**  The active file, NEWS's list of all valid newsgroups.
X*/
X#define ACTIVE_FILE	"/usr/lib/news/active"
X
X/*
X**  Default name of file with list of NEWS articles to process.
X*/
X#define BATCH_FILE	"/usr/spool/batch/notes"
X
X/*
X**  If we can't parse the existing message-id, we look for one like
X**  foo@bar, and build a 32-bit CRC of "foo" as the message id, and
X**  consider bar to be the site.  This code is from Bob Tracy,
X**  rct@occrsh.ATT.COM 2/9/87.  Descended from "rsb.c" of 1/1/87 of
X**  ZMODEM by Check Forsberg at Omen Technology, which comes from code:
X**	Copyright (C) 1986 Gary S. Brown.  You may use this program, or
X**	code or tables extracted from it, as desired without restriction.
X*/
X#define CRC_AS_ID
X/* Need an unsigned type capable of holding 32 bits. */
Xtypedef unsigned long UNS32;
X
X/*
X**  What do we do if we can't parse the message ID?  This is a
X**  last-ditch approach if EVERYTHING fails.  Since a notes/news
X**  gateway won't put this article back out into news, the worst
X**  problem is that if there are two news/notes gateways, then that
X**  group of sites will see the article twice.  So be it.
X*/
X#define TIME_AS_ID
X#include <sys/types.h>
Xextern time_t time();
X
X
Xstatic char title[TITLEN + 1];				/* hold titles */
Xextern char fromsys[SYSSZ + 1];				/* gave it to us */
Xstatic struct when_f    entered;			/* date written */
Xextern char origsys[SYSSZ + 1];				/* originator */
Xextern char authname[NAMESZ + 1];			/* author */
Xstatic int  has_suffix;					/* had -(nf) suffix */
Xstatic FILE *active;					/* active file */
X
X/* Debugging printf's; make it easy to change via ADB. */
Xint debug = 1;
X#define	dprintf		if (debug) printf
X
X/*
X**  Is this a notes auxiliary header?
X*/
X#define NOTES_AUX_HDR(p) ((p)[0] == '#' && ((p)[1] == 'N' || (p)[1] == 'R'))
X
X
X/*
X**  At one time this routine did lots more cleanup, now it technically
X**  isn't necessary; since we only open the active file for reading we
X**  could let the kernel close it for us.
X*/
XExit(x)
X    int x;
X{
X    if (active)
X	fclose(active);
X    exit(x);
X}
X
X
Xmain (argc, argv)
Xint     argc;
Xregister char  **argv;
X{
X    register FILE *F;
X    register char *name;
X    register char *p;
X    register int i;
X    register int status;
X    char line[BUFSIZ];
X    char workfile[256];
X
X    setuid (geteuid ());				/* force to "notes" */
X    startup (argc, argv);				/* comon init */
X    umask (0);
X    for (status = 0, i = 3; i < 20; i++)		/* close all extras */
X	close (i);
X
X    /* If we're operating in "batch" mode open the file. */
X    if (argv[1] && strcmp(argv[1], "-b") == 0) {
X	/* Get the name of the batch file. */
X#ifdef	BATCH_FILE
X	name = argv[2] ? argv[2] : BATCH_FILE;
X#else
X	if (argv[2] == NULL) {
X	    printf("What is the name of the batch file?\n");
X	    Exit(0);
X	}
X#endif	/* BATCH_FILE */
X
X	/* Shamelessly taken from 2.11 News (thanks, Rick).  Rename the
X	   real file to work name to avoid race conditions.  If work
X	   file already exists, skip renaming for crash recovery --
X	   next time we're invoked we'll get around to really reading
X	   the batch file. */
X	(void)strcat(strcpy(workfile, name), ".work");
X	if (access(workfile, 0) < 0) {
X	    if (access(name, 0) < 0 && errno == ENOENT)
X		Exit(0);
X	    (void)unlink(workfile);
X	    if (link(name, workfile) < 0 || unlink(name) < 0) {
X		perror("NOTESINPUT");
X		printf("Rename(%s,%s) failed", name, workfile);
X		Exit(1);
X	    }
X	    name = workfile;
X	}
X
X	if ((F = fopen(name, "r")) == NULL) {
X	    printf("Can't open '%s' for input\n", name);
X	    Exit(0);
X	}
X
X
X	/* Read each line in the batch file. */
X	while (fgets(line, sizeof line, F))
X	    if ((p = index(line, '\n')) == NULL)
X		printf("Line too long, skipping:\n  '%s'\n", line);
X	    else {
X		*p = '\0';
X		/* Skip blank lines. */
X		if (p > line)
X		    status += process(line);
X	    }
X	fclose(F);
X	(void)unlink(name);
X    }
X    else if (argv[1] == NULL) {
X	/* Undocumented compatibility option. */
X	extern char *mktemp();
X	static char tempfile[] = "/tmp/newsinXXXXXX";
X	register int f;
X
X	/* This is not strictly portable to old Unices... */
X	f = open(mktemp(tempfile), O_WRONLY | O_CREAT | O_TRUNC, 0666);
X	while ((i = read(0, line, sizeof line)) > 0)
X	    write(f, line, i);
X	close(f);
X	status += process(tempfile);
X	unlink(tempfile);
X    }
X    else
X	/* Process all arguments as the names of news articles. */
X	while (*++argv)
X	    status += process(*argv);
X
X    Exit(status);
X}
X
X
X/*
X**  Process one article coming in from news.  Return TRUE if we
X**  had any problems.
X*/
Xprocess(name)
X    char *name;
X{
X    register FILE * article;
X    register long startpos;
X    struct io_f io;
X    struct hbuf header;
X    char    nf[WDLEN];
X    struct nflist_f *nfptr;				/* expand newsgroups */
X    char   *tail;
X
X    dprintf("Processing %s\n", name);
X    if ((article = fopen(name, "r")) == NULL) {
X	printf("Can't open %s to read news\n", article);
X	return(1);
X    }
X/*
X *	Parse the Header.  Follow all the USENET standards
X *	for doing this.  Result is left in a fun little
X *	structure.
X *	Internalize some of the information to help us figure out
X *	some things quickly.
X */
X    if (!newsheader (&header, article, TRUE))		/* read the headers */
X    {
X	printf ("Incoming news has bad header.\n");
X	fclose(article);
X	return (1);
X    }
X
X/*
X *	Parse things like origsys, fromsys, author, date written
X */
X    parsepath (header.path, header.from);		/* systems, authors */
X    parsetime (header.subdate, &entered);		/* submitted */
X    dprintf ("Origsys: %s\n", origsys);
X    dprintf ("fromsys: %s\n", fromsys);
X    dprintf ("Date Written:");
X    if (debug)
X	prdate (&entered);
X    dprintf ("\nauthor: %s\n", authname);
X
X/*
X *	See if this might be a control message. Notes readers don't
X *	care to see these.
X *
X *	News code also recognizes titles with first 5 characters set 
X *	to "cmsg " as control messages. We should clean them up too.
X */
X    if (header.ctlmsg[0] || strncmp(header.title, "cmsg", 4) == 0)
X    {
X#ifdef	NOTESCTL
X	notesctl(name);
X#else
X	printf ("Control message (ignored): %s\n", header.ctlmsg);
X#endif	/* NOTESCTL */
X	fclose(article);
X	return (0);					/* "success" */
X    }
X
X    /* Remember where the article body started. */
X    startpos = ftell(article);
X
X/*
X *	Now run through the specified list of newsgroups,
X *	re-scan the body and such each time.
X */
X
X    expand (header.nbuf);				/* expand groups */
X    while ((nfptr = nextgroup ()) != (struct nflist_f *) NULL)
X    {
X	newsgroup (nfptr -> nf_name, nf, NEWSNF);	/* map it */
X	dprintf ("Newsgroup %s maps to notesfile %s\n", nfptr -> nf_name, nf);
X	tail = rindex (nfptr -> nf_name, '.');		/* catch ctl msgs */
X	if (tail && strcmp (tail, CTL) == 0)/* it is one */
X	{
X	    char    pbuf[256];				/* for title fixing */
X
X	    strcpy (nf, NFMAINT);			/* map it */
X	    dprintf ("Control newsgroup %s mapped to %s\n",
X		    nfptr -> nf_name, nf);
X	    sprintf (pbuf, "%s:%s", nfptr -> nf_name, header.title);
X	    strncpy (header.title, pbuf, BUFLEN);	/* prefix title */
X	    header.title[BUFLEN - 1] = '\0';		/* ensure terminater */
X#ifdef	NOTESCTL
X	    notesctl(name);
X#endif	/* NOTESCTL */
X	}
X
X	/* Move back to where the article proper starts. */
X	fseek(article, startpos, 0);
X
X	if (init (&io, nf) < 0)				/* open the nf */
X	{
X	    char    pbuf[512];
X	    char    tbuf[128];
X
X	    /* Make sure the newsgroup is in the active file. */
X	    if (!inactivefile(nfptr -> nf_name)) {
X		dprintf ("Newsgroup %s not in active file\n", nfptr -> nf_name);
X		continue;
X	    }
X#ifdef AUTOCREATE
X	    sprintf (pbuf,
X		    "Notesfile: %s\nNewsgroup: %s\n\nCreated by newsinput\n",
X		    nf, nfptr -> nf_name);
X	    sprintf (tbuf, "New NF: %s", nf);
X	    nfcomment (NFMAINT, pbuf, tbuf, 0, 0);
X	    buildnf (nf, Mstdir, 0, 1, 1);		/* open and networked */
X	    x (init (&io, nf) < 0, "newsinput: open newly created notesfile");
X#else
X	    sprintf (pbuf, "Notesfile: %s, newsgroup %s\n",
X		    nf, nfptr -> nf_name);
X	    sprintf (tbuf, "New newsgroup %s", nfptr -> nf_name);
X	    nfcomment (NFMAINT, pbuf, tbuf, 0, 0);
X	    printf ("Inserting into %s\n", NEWNEWS);
X	    strcpy (nf, NEWNEWS);			/* Change newsgroup */
X	    if (init (&io, nf) < 0)
X		return (1);				/* Give up */
X	    printf ("Open of %s suceeded\n", nf);
X#endif AUTOCREATE
X	}
X
X	if (nfgen (&io, &header, article) < 0) /* not from notes */
X	{
X	    dprintf ("Article not from NOTES\n");
X	    /* Move back to where the article proper starts. */
X	    fseek(article, startpos, 0);
X	    if (bnewsgen (&io, &header, article) < 0)	/* or news */
X	    {
X		dprintf ("Article not from NEWS, either\n");
X		fclose(article);
X		return (1);
X	    }
X	}
X	finish (&io);
X    }
X
X    fclose(article);
X    return (0);
X}
X
X
X/*
X**  See if this newsgroup is in the news active file.
X*/
Xinactivefile(name)
X    register char	*name;
X{
X#ifdef	ACTIVE_FILE
X    register int	 length;
X    char		 line[BUFSIZ];
X
X    if (active == NULL
X     && (active = fopen(ACTIVE_FILE, "r")) == NULL) {
X	printf("newsinput: can't open %s\n", ACTIVE_FILE);
X	Exit(1);
X    }
X    rewind(active);
X    for (length = strlen(name); fgets(line, sizeof line, active); )
X	/* See if the line has the newsgroup name, then whitespace. */
X	if (line[0] == name[0] && strncmp(line, name, length) == 0
X	 && (line[length] == ' ' || line[length] == '\t'))
X	    return(TRUE);
X    return(FALSE);
X#else
X    /* If no active file, then we can have it all... */
X    return(TRUE);
X#endif	/* ACTIVE_FILE */
X}
X
X
X#ifdef	NOTESCTL
X/*
X**  Call the "notes control-message handler" program.  This should use
X**  dounix(), but for now...
X*/
Xnotesctl(p)
X    char	*p;
X{
X    char	 buff[1000];
X
X    (void)sprintf(buff, "exec echo %s %s>>/tmp/ctl-list", NOTESCTL, p);
X    (void)system(buff);
X}
X#endif	/* NOTESCTL */
X
X
X/*
X *	nfgen(&io,&header,&FILE)
X *
X *	parse a notesfile-generated article.  Check the fields of
X *	header and look for # lines in the body of the article to
X *	determine if it came from notes.
X *	
X *	returns:	0 no permission for author
X *			> 0 signifies note or response where it wound up
X *			-1 if the article wasn't generated by notes
X */
X
Xnfgen (io, header, body)
Xstruct io_f *io;
Xstruct hbuf *header;
XFILE * body;
X{
X    register int    i;
X    register char  *p;
X    struct note_f   note;
X    struct note_f   note2;
X    struct id_f respid;
X    struct daddr_f  where;
X    struct when_f   whentime;
X    struct auth_f   auth;				/* author */
X    int     found;
X    char   *suffix;
X    int     notenum;
X    int     status;
X    int     fosterstat;					/* for foster parents */
X    int     count;
X    char    hline1[BUFLEN];				/* in-text header */
X    char    hline2[BUFLEN];				/* in-text header 2 */
X    int     onechar;					/* scratch character */
X    char    field1[100],				/* scanf tmps */
X            field2[100];
X
X/* 
X * Check for titles ending in "- nf".
X * We always remove these.
X */
X    suffix = rindex (header -> title, '-');		/* find last */
X    if (suffix)
X	if (!strcmp (suffix, NFSUFFIX) || !strcmp (suffix, OLDSUFFIX))
X	{
X	    if (--suffix > header -> title)		/* if we can */
X		*suffix = '\0';				/* strip "- (nf)" */
X	    has_suffix++;				/* flag it */
X	}
X/*
X *	at this point we should check for embodied #N.... lines and
X *	remove them.  This is conditional on having a "- (nf)" in the
X *	title of the note.
X */
X
X    hline1[0] = '\0';
X    hline2[0] = '\0';
X    if (has_suffix)					/* look for embedded */
X    {
X	long    position,				/* place marker */
X	        ftell ();				/* for types */
X
X	position = ftell (body);			/* save it */
X	while (fgets (hline1, sizeof hline1, body) != NULL)
X	    if (NOTES_AUX_HDR(hline1))
X		break;					/* found one */
X	if (!NOTES_AUX_HDR(hline1))			/* actually didn't */
X	{
X	    fseek (body, position, 0);			/* rewind */
X	    hline1[0] = '\0';				/* empty it */
X	}
X	else
X	{						/* grab line 2 */
X	    fgets (hline2, sizeof hline2, body);
X	    while ((onechar = getc (body)) != '\n' && onechar != EOF)
X		;					/* zap separator line */
X	}
X    }
X
X    if (strlen (header -> nline1) == 0)			/* no new headers */
X    {
X	/* 
X	 * No notes header in the B news article header...
X	 * If title ends with "- nf", look for the
X	 * header in the body of the text.
X	 * (for backwards compatability)
X	 */
X	if (has_suffix == 0)				/* not from notes */
X	{
X	    dprintf ("No NFSUFFIX and no header lines\n");
X	    return (-1);
X	}
X	found = 0;
X	if (hline1[0] == '#')				/* got them earlier */
X	{
X	    strcpy (header -> nline1, hline1);		/* first line */
X	    strcpy (header -> nline2, hline2);		/* second line */
X	    found++;					/* and mark it */
X	}
X	while (!found &&				/* search body */
X		fgets (header -> nline1, sizeof header -> nline1, body))
X	{
X	    if (header -> nline1[0] == '#')		/* bingo */
X	    {
X		found++;
X		break;
X	    }
X	}
X	if (!found ||
X		fgets (header -> nline2, sizeof header -> nline2, body) == NULL)
X	{
X	    dprintf ("no header lines in text body\n");
X	    return (-1);				/* not from notes */
X	}
X    }
X
X/* 
X * We now have the header lines.
X * Check validity and do the appropriate action.
X */
X    if (header -> nline1[0] != '#')
X    {
X	dprintf ("Invalid first header line\n");
X	return (-1);
X    }
X    dprintf ("First line is: %s\n", header -> nline1);
X    dprintf ("Second line is: %s\n", header -> nline2);
X    strncpy (title, header -> title, TITLEN);		/* get title */
X    title[TITLEN - 1] = '\0';				/* terminate for sure */
X
X    switch (header -> nline1[1])			/* parse it */
X    {
X	case 'N': 					/* base note */
X	    if (sscanf (header -> nline1, "#N:%99[^:]:%ld:%o:%d", field1,
X			&note.n_id.uniqid, &status, &count) != 4)
X	    {
X		return (-1);				/* no good */
X	    }
X	    strncpy (note.n_id.sys, field1, SYSSZ);	/* copy */
X	    note.n_id.sys[SYSSZ - 1] = '\0';		/* and terminate */
X	    status |= FRMNEWS;				/* it's been there */
X
X	    /* 
X	     * parse the second header line
X	     */
X
X	    p = header -> nline2;
X	    for (i = 0; (i < HOMESYSSZ - 1) && (*p != '!' && *p != '\0'); i++)
X		auth.asystem[i] = *p++;			/* get the author */
X	    auth.asystem[i] = '\0';			/* terminate */
X	    while (*p != '!' && *p != '\0')
X		p++;					/* skip to end of system */
X	    if (*p == '!')
X		p++;					/* skip the ! */
X	    for (i = 0; (i < NAMESZ - 1) && (*p != ' ' && *p != '\0'); i++)
X		auth.aname[i] = *p++;			/* get the author */
X	    auth.aname[i] = '\0';			/* terminate */
X	    auth.aid = Anonuid;
X
X	    while (*p != ' ' && *p)
X		p++;					/* drop rest of author */
X	    while (*p == ' ')				/* find the date */
X		p++;
X	    parsetime (p, &note.n_date);		/* and parse it */
X
X	    getperms (io, 1, note.n_id.sys);		/* check permissions */
X	    if (allow (io, WRITOK) == 0)		/* not a chance */
X		return (0);				/* sort of success */
X
X	    locknf (io, DSCRLOCK);			/* MUTEX */
X	    if ((notenum = chknote (io, &note.n_id, &note2)) == 0)
X	    {						/* not in data base */
X		pagein (io, body, &where);		/* grab text */
X		status |= FRMNEWS;			/* through news */
X		strcpy (note.n_from, fromsys);		/* who gave it to us */
X		i = putnote (io, &where, title, status, &note, &auth,
X			NOPOLICY, NOLOCKIT, NOADDID, fromsys, ADDTIME);
X		io -> nnotrcvd++;			/* count it */
X		unlocknf (io, DSCRLOCK);		/* MUTEX done */
X		return (i);				/* return notenum */
X	    }
X	    if ((note2.n_stat & ORPHND) && (status & ORPHND) == 0)
X	    {						/* replace foster */
X							/* with true parent */
X		pagein (io, body, &note2.n_addr);	/* the text */
X		gettime (&note2.n_rcvd);		/* update timestamp */
X		gettime (&note2.n_lmod);		/* time stamp it */
X		copyauth (&auth, &note2.n_auth);	/* correct author */
X		note2.n_stat = status | FRMNEWS;	/* and status bits */
X		strncpy (note2.ntitle, title, TITLEN);
X		note2.n_date = entered;
X		strcpy (note2.n_from, fromsys);
X		putnrec (io, notenum, &note2);		/* and replace */
X		io -> adopted++;			/* count adoption */
X		io -> nnotrcvd++;			/* count in */
X		unlocknf (io, DSCRLOCK);
X		printf ("Orphaned response chain adopted\n");
X		return (notenum);			/* note number */
X	    }
X	    else
X		printf ("Duplicate note handed back by news\n");
X	    unlocknf (io, DSCRLOCK);
X	    return (0);					/* mark resolved */
X
X	case 'R': 					/* response */
X	    if (sscanf (header -> nline1, "#R:%99[^:]:%ld:%99[^:]:%ld:%o:%d",
X			field1, &note.n_id.uniqid, field2,
X			&respid.uniqid, &status, &count) != 6)
X	    {
X		return (-1);				/* no good */
X	    }
X	    strncpy (note.n_id.sys, field1, SYSSZ);	/* copy them */
X	    strncpy (respid.sys, field2, SYSSZ);	/* both and */
X	    note.n_id.sys[SYSSZ - 1] = respid.sys[SYSSZ - 1] = '\0';/* stop */
X	    status |= FRMNEWS;				/* it's been there */
X
X	    getperms (io, 1, respid.sys);		/* check modes */
X	    if (allow (io, RESPOK) == 0)		/* not a chance */
X		return (0);				/* resolved */
X
X	    p = header -> nline2;			/* second line */
X	    for (i = 0; (i < HOMESYSSZ - 1) && (*p != '!' && *p != '\0'); i++)
X		auth.asystem[i] = *p++;			/* get the author */
X	    auth.asystem[i] = '\0';			/* terminate */
X	    while (*p != '!' && *p != '\0')
X		p++;					/* skip to end of system */
X	    if (*p == '!')
X		p++;					/* skip the ! */
X	    for (i = 0; (i < NAMESZ - 1) && (*p != ' ' && *p != '\0'); i++)
X		auth.aname[i] = *p++;			/* parse author */
X	    auth.aname[i] = '\0';			/* terminate */
X	    auth.aid = Anonuid;				/* default */
X	    while (*p != ' ' && *p)
X		p++;					/* rest of author */
X	    while (*p == ' ')				/* find the date */
X		p++;
X	    parsetime (p, &entered);			/* and parse it */
X
X	    locknf (io, DSCRLOCK);			/* MUTEX */
X	    notenum = chknote (io, &note.n_id, &note2);
X	    if (notenum == 0)				/* found parent? */
X	    {						/* build foster */
X		printf ("Orphaned response handed in by news\n");
X		strcpy (note.n_from, fromsys);		/* make basic info */
X		note.n_nresp = 0;
X		note.n_auth.aid = Anonuid;
X		strcpy (note.n_auth.aname, "Unknown");
X		strcpy (note.n_auth.asystem, note.n_id.sys);/* system */
X		note.n_date = entered;
X		gettime (&whentime);			/* current time */
X		fosterstat = ORPHND | FRMNEWS;		/* combo there */
X#ifdef	notdef
X		strcpy (note.ntitle, "(Orphan) ");	/* prefix */
X#else
X		note.ntitle[0] = '\0';			/* empty */
X#endif	/* notdef */
X		i = strlen (note.ntitle);		/* index */
X		for (p = header -> title; i < TITLEN && *p; i++, p++)/* rest of title */
X		    note.ntitle[i] = *p;		/* basic title */
X		if (i < TITLEN)
X		    note.ntitle[i] = '\0';		/* null it */
X		else
X		    note.ntitle[TITLEN - 1] = '\0';	/* null */
X		where.addr = 0;				/* no text */
X		where.textlen = 0;			/* still no text */
X		notenum = putnote (io, &where, note.ntitle, fosterstat,
X			&note, &note.n_auth, NOPOLICY, NOLOCKIT, NOADDID,
X			fromsys, ADDTIME);		/* insert him */
X		io -> norphans++;			/* orphan census */
X		getnrec (io, notenum, &note2);		/* get good one */
X	    }
X/*
X *	At this point we know we have a parent because if there wasn't
X *	one before, we built a foster parent.
X */
X	    if (chkresp (io, &respid, &note2, notenum) == 0)
X	    {						/* none, insert it */
X		status |= FRMNEWS;
X		pagein (io, body, &where);
X		i = putresp (io, &where, status, notenum, &entered, &auth,
X			&note, NOLOCKIT, &respid, NOADDID, fromsys,
X			ADDTIME, &whentime);
X		io -> nrsprcvd++;			/* count him in */
X		unlocknf (io, DSCRLOCK);		/* UNMUTEX */
X		return (i);				/* resp number */
X	    }
X	    else
X		printf ("Duplicate response handed back by news\n");
X	    unlocknf (io, DSCRLOCK);
X	    return (0);					/* resolved */
X
X    }
X    return (-1);
X}
X
X
X#ifdef	CRC_AS_ID
X/*
X** First, the polynomial itself and its table of feedback terms.  The  
X** polynomial is                                                       
X** X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 
X** Note that we take it "backwards" and put the highest-order term in  
X** the lowest-order bit.  The X^32 term is "implied"; the LSB is the   
X** X^31 term, etc.  The X^0 term (usually shown as "+1") results in    
X** the MSB being 1.                                                    
X**
X** Note that the usual hardware shift register implementation, which   
X** is what we're using (we're merely optimizing it by doing eight-bit  
X** chunks at a time) shifts bits into the lowest-order term.  In our   
X** implementation, that means shifting towards the right.  Why do we   
X** do it this way?  Because the calculated CRC must be transmitted in  
X** order from highest-order term to lowest-order term.  UARTs transmit 
X** characters in order from LSB to MSB.  By storing the CRC this way,  
X** we hand it to the UART in the order low-byte to high-byte; the UART 
X** sends each low-bit to hight-bit; and the result is transmission bit 
X** by bit from highest- to lowest-order term without requiring any bit 
X** shuffling on our part.  Reception works similarly.                  
X**
X** The feedback terms table consists of 256, 32-bit entries.  Notes:   
X**     The table can be generated at runtime if desired; code to do so 
X**     is shown later.  It might not be obvious, but the feedback      
X**     terms simply represent the results of eight shift/xor opera-    
X**     tions for all combinations of data and CRC register values.     
X**     The values must be right-shifted by eight bits by the "updcrc"  
X**     logic; the shift must be unsigned (bring in zeroes).  On some   
X**     hardware you could probably optimize the shift in assembler by  
X**     using byte-swap instructions.                                   
X*/
X
Xstatic UNS32 crc_32_tab[] = {
X    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
X    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
X    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
X    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
X    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
X    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
X    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
X    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
X    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
X    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
X    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
X    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
X    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
X    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
X    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
X    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
X    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
X    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
X    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
X    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
X    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
X    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
X    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
X    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
X    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
X    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
X    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
X    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
X    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
X    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
X    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
X    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
X    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
X    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
X    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
X    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
X    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
X    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
X    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
X    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
X    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
X    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
X    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
X};
X
X#define UPDC32(octet, crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
X
XUNS32
Xcrc32(p, i)
X    register char	*p;
X    register int	 i;
X{
X    register UNS32	 crc;
X
X    
X    for (crc = 0xffffffff; --i >= 0; p++)
X	crc = UPDC32((*p & 0377), crc);
X    return(crc);
X}
X#endif	/* CRC_AS_ID */
X
X
X/*
X *	bnewsgen(&io,&header,&FILE)
X *
X *	parse an article that came through B-news.  We've already
X *	checked to see if it was a notesfile generated article
X *	so all we have to do is decide if it's a note/response
X *	and put it in the appropriate place.
X */
X
Xbnewsgen (io, header, body)
Xstruct io_f *io;
Xstruct hbuf *header;
XFILE * body;
X{
X    register int    i;
X    char   *p;
X    struct note_f   note;
X    struct note_f   note2;
X    struct when_f   whentime;
X    struct daddr_f  where;
X    int     notenum;
X    int     status;
X    char    pbuf[BUFLEN];				/* scratch */
X    long    newsseq;
X    char    newssys[SYSSZ];
X    struct id_f newsid;
X    struct auth_f   auth;
X    char   *lead,
X           *trail;					/* references */
X    char    basesys[SYSSZ];				/* references */
X    long    baseseq;					/* ditto */
X    struct id_f baseid;					/* ditto ditto */
X    char    field1[100];				/* scanf tmps */
X
X    getperms (io, 1, origsys);
X    if (allow (io, WRITOK) == 0)			/* let him* */
X    {
X	printf ("System %s not allowed to write notes\n", origsys);
X	return (0);					/* NO! */
X    }
X
X    i = sscanf (header -> ident, "<%ld@%99[^>]>", &newsseq, field1, pbuf);
X    if (i < 2)						/* try old */
X	i = sscanf (header -> ident, "%99[^.].%ld", field1, &newsseq);
X    /* for sendmail-type article ID's -- rs@mirror. */
X    if (i < 2)
X	i = sscanf (header -> ident, "<%*[^.].%*[A-Z]%ld@%99[^>]>",
X		    &newsseq, field1);
X    if (i < 2)
X	i = sscanf (header -> ident, "<%ld%*s@%99[^>]>", &newsseq, field1);
X
X#ifdef	USE_CRC_ID
X    if (i < 2)		/* Try "<X@Y>" where 'X' is not all digits. */
X    {
X	i = sscanf (header->ident, "<%99[^@]@%99[^>]>", field2, field1);
X	if (i == 2)
X	{
X	    newsseq = crc32(field2, strlen(field2));
X	    dprintf ("article ID: %s\nnewsseq: %ld\n", header->ident, newsseq);
X	}
X    }
X#endif	/* USE_CRC_ID */
X
X    if (i < 2)						/* no id */
X    {
X	dprintf ("can't fathom article ID: %s\n", header -> ident);
X#ifdef	TIME_AS_ID
X	i = 2;
X	(void)time(&newsseq);
X#else
X	return(-1);
X#endif	/* TIME_AS_ID */
X    }
X    strncpy (newssys, field1, SYSSZ);			/* copy */
X    newssys[SYSSZ - 1] = '\0';				/* and truncate */
X
X    note.n_date = entered;
X    strcpy (note.n_from, fromsys);
X    strncpy (auth.aname, authname, NAMESZ);		/* fill in author */
X    strncpy (auth.asystem, origsys, HOMESYSSZ);		/* system */
X    auth.asystem[HOMESYSSZ - 1] = auth.aname[NAMESZ - 1] = '\0';
X    auth.aid = Anonuid;
X    status = FRMNEWS;					/* came through news */
X    strncpy (title, header -> title, TITLEN);		/* move new title */
X    title[TITLEN - 1] = '\0';				/* sure it stops */
X
X    locknf (io, DSCRLOCK);				/* MUTEX */
X/*
X *	first thing is to see if it's a base note somewhere.
X */
X    strcpy (newsid.sys, newssys);			/* build uniq id */
X    strcpy (note.n_id.sys, newssys);			/* build descriptor */
X    note.n_id.uniqid = newsid.uniqid = newsseq;
X    notenum = chknote (io, &note.n_id, &note2);		/* try normal */
X    if (notenum == 0)					/* try -100 trick */
X    {
X	note.n_id.uniqid = newsid.uniqid = newsseq * -100;
X	notenum = chknote (io, &note.n_id, &note2);
X    }
X    if (notenum != 0)
X    {
X	if (!(note2.n_stat & ORPHND))
X	{
X	    printf ("Duplicate news article received\n");
X	    io -> nnotdrop++;				/* count as dropped */
X	    unlocknf (io, DSCRLOCK);
X	    return (0);					/* done with it */
X	}
X	/* 
X	 *	 replace foster parent
X	 */
X	pagein (io, body, &note2.n_addr);		/* collect text */
X	gettime (&note2.n_rcvd);			/* current tod */
X	gettime (&note2.n_lmod);			/* last touched */
X	copyauth (&auth, &note2.n_auth);		/* fill in author */
X	note2.n_stat |= FRMNEWS;			/* brand it */
X	strncpy (note2.ntitle, title, TITLEN);		/* move title */
X	note2.n_date = entered;
X	strcpy (note2.n_from, fromsys);			/* who sent it to us */
X	putnrec (io, notenum, &note2);			/* and replace */
X	io -> adopted++;				/* count it */
X	io -> nnotrcvd++;				/* count in */
X	unlocknf (io, DSCRLOCK);
X	printf ("Orphaned Response Chain adopted\n");
X	return (notenum);				/* correctly placed */
X    }
X
X/*
X *	See if we can turn this into a response to some base note.
X *	First priority is to match it to any of the articles listed
X *	in a References field if there is one.
X */
X
X    notenum = 0;					/* init to not found */
X    if (header -> followid[0])				/* references */
X    {
X	trail = header -> followid;
X	while ((lead = index (trail, '<')) && (trail = index (lead, '>')))
X	{						/* delimited id */
X	    i = sscanf (lead, "<%ld@%99[^>]>", &baseseq, field1, pbuf);
X	    if (i < 2)					/* try old format */
X		i = sscanf (lead, "%99[^.].%ld", field1, &baseseq);
X	    if (i < 2)
X		continue;				/* try next one */
X	    strncpy (basesys, field1, SYSSZ);
X	    basesys[SYSSZ - 1] = '\0';			/* and truncate */
X
X	    strcpy (baseid.sys, basesys);		/* build goal */
X	    baseid.uniqid = baseseq;			/* try notes source */
X	    if ((notenum = chknote (io, &baseid, &note2)))/* WANT ASSIGN */
X		break;					/* yes! */
X
X	    baseid.uniqid = baseseq * -100;		/* try news source */
X	    if ((notenum = chknote (io, &baseid, &note2)))/* WANT ASSIGN */
X		break;					/* yes! */
X
X	    notenum = 0;				/* ensure "unfound" */
X	}
X    }
X
X/*
X *	If References did any good, "notenum" is positive non-zero.
X *	Otherwise it didn't help out at all and we have to resort to
X *	parsing the title for "re:" prefixes
X *	If we can find a base title, use the title search code to
X *	scan for it.
X */
X
X    if (notenum == 0 &&					/* not found */
X	    !strncmp (header -> title, "re: ", 4) ||	/* and looks like */
X	    !strncmp (header -> title, "Re: ", 4) ||	/* a response */
X	    !strncmp (header -> title, "RE: ", 4))
X    {
X	dprintf ("Looking at titles\n");
X	p = header -> title;
X	do
X	{
X	    for (p += 3; *p == ' ' || *p == '\t'; p++);	/* drop spaces */
X	} while (!strncmp (p, "re: ", 4) ||
X		!strncmp (p, "Re: ", 4) ||
X		!strncmp (p, "RE: ", 4));
X	strncpy (io -> xstring, p, TITLEN);		/* load it */
X	io -> xstring[TITLEN - 1] = '\0';		/* and terminate it */
X	notenum = findtitle (io, io -> descr.d_nnote, FALSE);/* start at back */
X	if (notenum > 0)				/* found one */
X	    getnrec (io, notenum, &note2);		/* get a ptr to it */
X    }
X
X/*
X *	OK. By now, we have a "notenum" if the article can be pegged
X *	as a response to one of our notes.
X *	Otherwise, notenum==0 and we'll have to turn it into
X *	a base note.
X */
X
X    if (notenum > 0)
X    {
X	dprintf ("Looking in response chain for note %d\n", notenum);
X	if (!chkresp (io, &newsid, &note2, notenum))
X	{						/* no copy here */
X	    pagein (io, body, &where);
X	    gettime (&whentime);
X	    i = putresp (io, &where, status, notenum, &entered, &auth, &note,
X		    NOLOCKIT, &newsid, NOADDID, fromsys, ADDTIME, &whentime);
X	    unlocknf (io, DSCRLOCK);			/* un-MUTEX */
X	    return (i);
X	}
X	else
X	{						/* copy there */
X	    unlocknf (io, DSCRLOCK);			/* all done */
X	    printf ("Duplicate Response handed back by news\n");
X	    io -> nrspdrop++;				/* bong it */
X	    return (0);					/* count as done */
X	}
X    }
X/*
X *	If we are going to do things this way, here is the point
X *	where we should check about turning a news-generated 
X *	article into an orphaned response.
X *
X *	Basically, look for a non-empty references line and
X *	make a foster parent with the first article id on that
X *	line.
X */
X
X/*
X *	by this point, it's obvious that we can't turn the note into
X *	a response.  We can skip the check to see if it is already
X *	there because we did that at the very top of this loop
X *	and since we've locked the notesfile up while we're doing this,
X *	we know that nobody added a note.
X */
X    dprintf ("Processing article as a base note\n");
X    pagein (io, body, &where);
X    notenum = putnote (io, &where, title, status, &note,
X	    &auth, NOPOLICY, NOLOCKIT, NOADDID, fromsys, ADDTIME);
X    io -> nnotrcvd++;					/* count it */
X    unlocknf (io, DSCRLOCK);
X    return (notenum);
X}
END_OF_newsinput.c
if test 33276 -ne `wc -c <newsinput.c`; then
    echo shar: \"newsinput.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
--
Rich $alz					"Drug tests p**s me off"
Mirror Systems, Cambridge Massachusetts		rs@mirror.TMC.COM
{cbosgd, cca.cca.com, harvard!wjh12, ihnp4, mit-eddie, seismo}!mirror!rs