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