🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: news.software.notes
1 messages
1 total messages Started by rs Mon, 11 May 1987 22:25
Better news->notes gateway code
#70
Author: rs
Date: Mon, 11 May 1987 22:25
1867 lines
57977 bytes

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
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads