Thread View: news.software.notes
1 messages
1 total messages
Started by rs
Mon, 11 May 1987 22:25
Better news->notes gateway code
Author: rs
Date: Mon, 11 May 1987 22:25
Date: Mon, 11 May 1987 22:25
1867 lines
57977 bytes
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 ¬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
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