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 ¬e.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, ¬e.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, ¬e.n_id, ¬e2)) == 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, ¬e, &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, ¬e2.n_addr); /* the text */
X gettime (¬e2.n_rcvd); /* update timestamp */
X gettime (¬e2.n_lmod); /* time stamp it */
X copyauth (&auth, ¬e2.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, ¬e2); /* 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, ¬e.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, ¬e.n_id, ¬e2);
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 ¬e, ¬e.n_auth, NOPOLICY, NOLOCKIT, NOADDID,
X fromsys, ADDTIME); /* insert him */
X io -> norphans++; /* orphan census */
X getnrec (io, notenum, ¬e2); /* 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, ¬e2, notenum) == 0)
X { /* none, insert it */
X status |= FRMNEWS;
X pagein (io, body, &where);
X i = putresp (io, &where, status, notenum, &entered, &auth,
X ¬e, 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, ¬e.n_id, ¬e2); /* try normal */
X if (notenum == 0) /* try -100 trick */
X {
X note.n_id.uniqid = newsid.uniqid = newsseq * -100;
X notenum = chknote (io, ¬e.n_id, ¬e2);
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, ¬e2.n_addr); /* collect text */
X gettime (¬e2.n_rcvd); /* current tod */
X gettime (¬e2.n_lmod); /* last touched */
X copyauth (&auth, ¬e2.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, ¬e2); /* 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, ¬e2)))/* WANT ASSIGN */
X break; /* yes! */
X
X baseid.uniqid = baseseq * -100; /* try news source */
X if ((notenum = chknote (io, &baseid, ¬e2)))/* 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, ¬e2); /* 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, ¬e2, notenum))
X { /* no copy here */
X pagein (io, body, &where);
X gettime (&whentime);
X i = putresp (io, &where, status, notenum, &entered, &auth, ¬e,
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, ¬e,
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