home *** CD-ROM | disk | FTP | other *** search
- Subject: v19i093: Cnews production release, Part16/19
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: utzoo!henry
- Posting-number: Volume 19, Issue 93
- Archive-name: cnews2/part16
-
- : ---CUT HERE---
- echo 'relay/makefile':
- sed 's/^X//' >'relay/makefile' <<'!'
- X# makefile for C news relaynews
- X
- X# =()<NEWSARTS = @<NEWSARTS>@>()=
- XNEWSARTS = /usr/spool/news
- X# =()<NEWSBIN = @<NEWSBIN>@>()=
- XNEWSBIN = /usr/lib/newsbin
- X# =()<NEWSCTL = @<NEWSCTL>@>()=
- XNEWSCTL = /usr/lib/news
- X# workaround for System V make bug
- XSHELL = /bin/sh
- X
- XBIN=/bin
- XNPROC=2
- X# -DVOID=int for libc.h & old lint libraries
- XDEFINES= -I../include -I. -DVOID=int -DFLUSHEVERY=6
- X#CC=CC +V
- X#CC=gcc -ansi -pedantic -Wall -S
- X#CC=redcc
- XCOPTS= -O # -pg -g
- XCFLAGS=$(DEFINES) $(COPTS)
- XDBM = -ldbm
- XLIBS= $(DBM)
- XLINT=lint
- XLINTFLAGS=-haz $(DEFINES)
- XLLIBS=-llocal
- X# I wish I could make lint shut the fk up about some things. Grrr!
- XLINTFILT=egrep -v '(possible pointer|long assign|can.t take|never used|nnfree|getdate|:$$)'
- XPROPTS=
- XP=stpr
- XPP=pp -Tpsc -fR # lazywriter
- XPPBACK=dps | stps # lazywriter
- X
- XLIBOBJS=../libcnews.a
- XSRC=relaynews.c active.c article.c caches.c mkdirs.c control.c fileart.c \
- X hdrdefs.c hdrcommon.c hdrparse.c hdrmunge.c \
- X history.c io.c msgs.c procart.c \
- X sys.c transmit.c trbatch.c ihave.c $(LIBSRCS)
- XOBJ=relaynews.o active.o article.o caches.o mkdirs.o control.o fileart.o \
- X hdrdefs.o hdrcommon.o hdrparse.o hdrmunge.o \
- X history.o io.o msgs.o procart.o \
- X sys.o transmit.o trbatch.o ihave.o $(LIBOBJS)
- XFILES=$(NONCFILES) $(CFILES)
- XNONCFILES= TODO* README ads/README ads/[0-9]* \
- X sh/inews sh/tear sh/anne.jones sh/defhdrs.awk \
- X sh/realrnews sh/serverrnews makefile
- XCFILES= ../include/*.h \
- X active.h article.h caches.h mkdirs.h control.h cpu.h fileart.h \
- X hdrint.h headers.h history.h system.h transmit.h trbatch.h $(SRC)
- X
- Xall: makefile relaynews
- X
- Xmkfile: makefile
- X sed '/mkfile/d' makefile | mkconv | sed 's/make/mk/g' >$@
- X
- Xrelaynews: $(OBJ)
- X $(CC) $(CFLAGS) $(OBJ) $(LIBS) $(LIBOBJS) -o $@
- Xlint: $(SRC)
- X $(LINT) $(LINTFLAGS) $(SRC) $(LLIBS) | $(LINTFILT)
- Xlint-p: $(SRC)
- X $(LINT) $(LINTFLAGS) -p $(SRC) $(LLIBS) | $(LINTFILT)
- X
- Xnewsinstall:
- X : nothing
- X
- X# bininstall: make directories, install programs
- Xbininstall: install
- Xinstall: $(NEWSBIN)/relay/relaynews
- X$(NEWSBIN)/relay/relaynews: relaynews
- X -mkdir $(NEWSBIN)/relay $(NEWSBIN)/inject $(NEWSBIN)/ctl
- X rm -f $(NEWSBIN)/relay/relaynews
- X cp relaynews $(NEWSBIN)/relay
- X : needs to be news-owned, setuid -- build looks after that
- X chmod +x sh/* aux/* ctl/*
- X cp sh/* $(NEWSBIN)/inject
- X cp ctl/* $(NEWSBIN)/ctl
- X cp aux/* $(NEWSBIN)/relay
- X cp sh/postnews sh/inews $(BIN)
- X
- XTODO.grep: TODO
- X -egrep TODO ../include/*.h *.h *.c sh/* | tr -s " \11" " " >$@
- X -egrep TODO ../lib*/*.[ch] | tr -s " \11" " " >>$@
- X
- Xv7 v8 v9 usg bsd42:
- X test -d libos && exit 1
- X mv lib$@ libos # or ln -s lib$@ libos
- X make
- X
- Xprint: printc printnonc
- X touch $@
- Xprintc: $(CFILES)
- X $(PP) $? | $(PPBACK)
- X touch $@
- Xprintnonc: $(NONCFILES)
- X pr $(PROPTS) $? | $P
- X touch $@
- Xdistr: $(FILES)
- X (echo relaynews update of `date`; echo ""; bundle $?) | /bin/mail cnews-updates
- X touch $@
- Xclean:
- X rm -f core a.out relaynews *.o
- X rm -rf regress/tmp
- X
- Xr: relaynews
- X chmod +x regress/regress
- X cd regress; ./regress
- X
- X# header dependencies follow
- Xactive.o: ../include/libc.h ../include/news.h ../include/config.h
- Xactive.o: active.h
- Xarticle.o: ../include/news.h article.h headers.h
- Xcaches.o: ../include/news.h active.h caches.h transmit.h
- Xmkdirs.o: ../include/libc.h ../include/news.h
- Xcontrol.o: ../include/libc.h ../include/news.h ../include/config.h
- Xcontrol.o: headers.h article.h caches.h history.h
- Xfileart.o: ../include/libc.h ../include/news.h ../include/config.h
- Xfileart.o: active.h mkdirs.h headers.h article.h history.h system.h
- Xhdrcommon.o: ../include/news.h headers.h hdrint.h
- Xhdrdefs.o: ../include/news.h headers.h hdrint.h
- Xhdrmunge.o: ../include/libc.h ../include/news.h fileart.h headers.h
- Xhdrmunge.o: article.h hdrint.h
- Xhdrparse.o: ../include/libc.h ../include/news.h headers.h hdrint.h
- Xhistory.o: ../include/libc.h ../include/news.h ../include/config.h
- Xhistory.o: ../include/fgetmfs.h headers.h article.h history.h
- Xhostname.o: ../include/news.h ../include/config.h
- Xihave.o: ../include/libc.h ../include/news.h ../include/config.h
- Xihave.o: headers.h article.h caches.h history.h
- Xio.o: ../include/news.h headers.h article.h
- Xmsgs.o: ../include/news.h headers.h article.h
- Xprocart.o: ../include/libc.h ../include/news.h active.h control.h
- Xprocart.o: headers.h article.h history.h system.h
- Xrelaynews.o: ../include/libc.h ../include/news.h ../include/config.h
- Xrelaynews.o: ../include/fgetmfs.h active.h caches.h cpu.h headers.h
- Xrelaynews.o: history.h
- Xstring.o: ../include/libc.h ../include/news.h
- Xsys.o: ../include/libc.h ../include/fgetmfs.h ../include/news.h
- Xsys.o: ../include/config.h system.h
- Xtransmit.o: ../include/libc.h ../include/news.h ../include/config.h
- Xtransmit.o: headers.h active.h article.h system.h trbatch.h transmit.h
- Xtrbatch.o: ../include/libc.h ../include/news.h trbatch.h
- !
- echo 'relay/mkdirs.c':
- sed 's/^X//' >'relay/mkdirs.c' <<'!'
- X/*
- X * mkdirs - make the directories implied by `name'
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include "libc.h"
- X#include "news.h"
- X
- X/*
- X * Given a/b/c/d, try to make any of a, a/b, a/b/c and a/b/c/d which are missing;
- X * stop on first failure.
- X * Returns success.
- X */
- Xboolean
- Xmkdirs(name, uid, gid)
- Xregister char *name;
- Xint uid, gid;
- X{
- X register char *cp;
- X register int isthere = YES;
- X struct stat stbuf;
- X
- X for (cp = name; isthere && *cp != '\0'; cp++)
- X if (*cp == FNDELIM) {
- X *cp = '\0';
- X isthere = stat(name, &stbuf) >= 0;
- X if (!isthere) {
- X isthere = mkdir(name, 0777) >= 0;
- X (void) chown(name, uid, gid);
- X }
- X *cp = FNDELIM;
- X }
- X return isthere;
- X}
- !
- echo 'relay/mkdirs.h':
- sed 's/^X//' >'relay/mkdirs.h' <<'!'
- X/* imports from mkdirs.c */
- Xextern boolean mkdirs();
- !
- echo 'relay/mklint':
- sed 's/^X//' >'relay/mklint' <<'!'
- X#! /bin/sh
- Xlint -hazu -I../include -I../include/bsd42 -I../rnews -DSTATIC= $* -llocal |
- X egrep -v '(possible pointer|long assign|can.t take|never used|:$)'
- !
- echo 'relay/msgs.c':
- sed 's/^X//' >'relay/msgs.c' <<'!'
- X/*
- X * print common messages
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include "news.h"
- X#include "headers.h"
- X#include "article.h"
- X#include "msgs.h"
- X
- Xvoid
- Xfulldisk(art, file) /* complain once & set ST_DISKFULL */
- Xregister struct article *art;
- Xchar *file;
- X{
- X if (!(art->a_status&ST_DISKFULL))
- X art->a_status |= prfulldisk(file);
- X}
- X
- Xstatust
- Xprfulldisk(file) /* complain once & return bad status */
- Xchar *file;
- X{
- X warning("error writing `%s', probably the disk filled", file);
- X return ST_DISKFULL|ST_DROPPED;
- X}
- !
- echo 'relay/msgs.h':
- sed 's/^X//' >'relay/msgs.h' <<'!'
- X/* imports from msgs.c */
- Xextern statust prfulldisk();
- Xextern void fulldisk();
- !
- echo 'relay/procart.c':
- sed 's/^X//' >'relay/procart.c' <<'!'
- X/*
- X * process a single incoming article
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include "libc.h"
- X#include "news.h"
- X#include "active.h"
- X#include "control.h"
- X#include "headers.h"
- X#include "article.h"
- X#include "history.h"
- X#include "io.h"
- X#include "msgs.h"
- X#include "system.h"
- X#include "transmit.h"
- X
- X/*
- X * COPYSIZE is the length of a bulk-copying buffer: the bigger the better,
- X * though fewer than 3% of articles exceed 8192 bytes (may 1988).
- X * It holds header lines first, and later holds bytes of the body.
- X * This buffer is allocated once at the start and never deallocated.
- X */
- X#ifndef COPYSIZE
- X#ifdef SMALLMEM
- X#define COPYSIZE BUFSIZ /* conserve memory at the expense of speed */
- X#else
- X#define COPYSIZE 8192 /* big enough even for worst-case 4.2bsd blocks */
- X#endif /* SMALLMEM */
- X#endif /* COPYSIZE */
- X
- Xextern char *exclude; /* for erik */
- Xextern boolean okrefusal; /* flag from command line */
- X
- X/* forwards */
- Xextern void tossorfile(), surveydamage(), reject(), prefuse(), uninsart();
- Xextern char *hdrcopy();
- XFORWARD void copyart(), cpybody(), insart();
- XFORWARD statust snuffmayreturn();
- X
- X/*
- X * Copy the article on "in" to a temporary name in the news spool directory,
- X * unlink temp name; *or* copy into the final names, if known early enough.
- X * (Sets a_tmpf in or near hdrmunge() or hdrdump().)
- X * If the spool file opened, install the article it contains.
- X */
- Xstatust
- Xcpinsart(in, inname, maxima, blvmax)
- XFILE *in;
- Xregister char *inname;
- Xlong maxima;
- Xboolean blvmax; /* believe maxima? */
- X{
- X register struct article *artp;
- X register statust status;
- X struct article art;
- X
- X artp = &art;
- X artinit(artp);
- X artp->a_blvmax = blvmax;
- X artp->a_unread = maxima;
- X
- X /*
- X * copyart() may reject() the article, and may fill the disk.
- X * it calls fileart and logs rejected articles.
- X */
- X copyart(artp, in, inname);
- X
- X if (artp->a_status&ST_REFUSED) {
- X /* no good ngs (in fileart) or reject()ed; not serious */
- X artp->a_status &= ~ST_REFUSED;
- X /* paranoia; shouldn't happen */
- X nnfclose(artp, &artp->a_artf, inname);
- X } else if (artp->a_artf == NULL) {
- X warning("can't open spool file `%s'", artp->a_tmpf);
- X artp->a_status |= ST_DROPPED;
- X } else {
- X nnfclose(artp, &artp->a_artf, inname);
- X insart(artp); /* logs accepted art.s during transmission */
- X if (artp->a_status&ST_JUNKED) { /* yer welcome, henry */
- X artp->a_status &= ~ST_JUNKED;
- X timestamp(stdout, (time_t *)NULL);
- X (void) printf(" %s j %s junked due to groups `%s'\n",
- X sendersite(nullify(artp->h.h_path)),
- X artp->h.h_msgid, artp->h.h_ngs);
- X }
- X }
- X status = artp->a_status;
- X artfree(artp);
- X return status;
- X}
- X
- X/*
- X * Copy the next charcnt bytes of "in" (may be not a disk file)
- X * to a permanent file under a (possibly) temporary name.
- X * After the headers are seen, accept or reject the article.
- X * If rejected and the headers fit in core, no files will be opened.
- X * Must munge certain headers on the way & remember certain values.
- X * hdrmunge() or hdrdump() sets art->a_tmpf & art->a_artf.
- X * Unlink art->a_tmpf, if a temporary link.
- X */
- X/* ARGSUSED inname */
- XSTATIC void
- Xcopyart(art, in, inname)
- Xregister struct article *art;
- Xregister FILE *in;
- Xchar *inname;
- X{
- X boolean installed = YES;
- X char *body;
- X
- X body = hdrcopy(art, in);
- X hdrdeflt(&art->h);
- X tossorfile(art, &installed);
- X /* assertion: header values (art->h) can be forgotten here */
- X cpybody(art, in, body);
- X surveydamage(art, &installed);
- X}
- X
- X/*
- X * The loop copies header lines from input to output or a
- X * header output cache. On exit, hdr will contain the first
- X * non-header line, if any, left over from the end of header copying.
- X *
- X * Some people think the loop is ugly; I'm not sure why.
- X * If the byte count is positive, read a line; if it doesn't return
- X * EOF and is a header, then adjust byte count, stash and munge headers.
- X * strlen(line) must be computed before hdrstash is called,
- X * as hdrstash (and thus hdrdigest) removes newlines.
- X */
- Xchar * /* first body line, from gethdr */
- Xhdrcopy(art, in)
- Xregister struct article *art;
- XFILE *in;
- X{
- X register char *hdr = NULL;
- X long limit;
- X int is_hdr = NO;
- X
- X hdrwretch(); /* reset the header parser */
- X limit = (art->a_blvmax? art->a_unread+1: art->a_unread); /* 1 for NUL */
- X /* 1 is again for NUL */
- X while (limit > 1 && (hdr = gethdr(in, &limit, &is_hdr)) != NULL && is_hdr) {
- X hdrdigest(art, hdr, strlen(hdr));
- X hdr = NULL; /* freed inside gethdr */
- X }
- X /* If we read a body line, gethdr has adjusted limit appropriately. */
- X art->a_unread = limit - 1; /* limit updated by gethdr */
- X if (is_hdr) /* no body: header fills limit */
- X hdr = NULL;
- X return hdr;
- X}
- X
- X/*
- X * Either reject the article described by art, or accept it and file it.
- X * If rejecting it, remove any links and give back assigned #'s
- X * (art->a_artf may still be open; arguably uninsart should close it).
- X * If accepting it, dump any saved headers and file the article.
- X * Unlink art->a_tmpf if it's a temporary link.
- X */
- Xvoid
- Xtossorfile(art, installedp)
- Xregister struct article *art;
- Xboolean *installedp;
- X{
- X reject(art); /* duplicate, etc.? */
- X if (art->a_status&(ST_DROPPED|ST_REFUSED)) {
- X uninsart(art);
- X *installedp = NO;
- X } else
- X hdrdump(art, ALLHDRS); /* ALLHDRS triggers fileart */
- X
- X if (art->a_unlink) {
- X /* a_tmpf has had links made to it, so it can be removed. */
- X if (unlink(art->a_tmpf) < 0) {
- X warning("copyart can't unlink `%s'", art->a_tmpf);
- X art->a_status |= ST_ACCESS;
- X }
- X art->a_unlink = NO; /* caution */
- X }
- X}
- X
- X/*
- X * Copy article body.
- X * body will contain the first non-header line, if any,
- X * left over from the end of header copying. Write it.
- X * Copy at most COPYSIZE bytes of body at a time and exactly art->a_unread
- X * bytes in total, barring EOF or a full disk. Then "block" is no longer needed.
- X * Force the article to disk, mostly for the benefit of control message
- X * processing.
- X *
- X * The copying buffer, block, is static because it is used repeatedly
- X * and persists through most of execution, so dynamic allocation
- X * and deallocation seems wasteful, but also for the benefit
- X * of compilers for odd machines (e.g. PE, 370s) which make
- X * implementing "large" automatic arrays difficult.
- X */
- XSTATIC void
- Xcpybody(art, in, body)
- Xregister struct article *art;
- XFILE *in;
- Xregister char *body;
- X{
- X register int readcnt;
- X static char block[COPYSIZE];
- X
- X if (body != NULL) { /* read too far? */
- X register int bodylen = strlen(body);
- X
- X if (art->a_artf != NULL &&
- X fwrite(body, 1, bodylen, art->a_artf) != bodylen)
- X fulldisk(art, spoolnm(art));
- X art->a_charswritten += bodylen;
- X }
- X for (; art->a_unread > 0 && !(art->a_status&ST_DISKFULL) &&
- X (readcnt=fread(block, 1, (int)min(art->a_unread, COPYSIZE), in)) > 0;
- X art->a_unread -= readcnt, art->a_charswritten += readcnt)
- X if (art->a_artf != NULL &&
- X fwrite(block, 1, readcnt, art->a_artf) != readcnt)
- X fulldisk(art, spoolnm(art));
- X if (art->a_artf != NULL && fflush(art->a_artf) == EOF)
- X fulldisk(art, spoolnm(art));
- X}
- X
- X/*
- X * If not yet uninstalled, and the disk filled, uninstall this article
- X * to remove any zero-length links and decrement the active article number.
- X * The ST_DISKFULL status will prevent a history entry from being generated.
- X */
- Xvoid
- Xsurveydamage(art, installedp)
- Xregister struct article *art;
- Xregister boolean *installedp;
- X{
- X if (art->a_unread > 0 && art->a_blvmax) {
- X (void) fprintf(stderr, "%s: article %s short by %ld bytes\n",
- X progname, (art->h.h_msgid != NULL? art->h.h_msgid: ""),
- X (long)art->a_unread);
- X art->a_status |= ST_SHORT; /* NB.: don't uninstall this art. */
- X }
- X if (*installedp && art->a_status&ST_DISKFULL) {
- X uninsart(art);
- X *installedp = NO;
- X }
- X#ifdef WATCHCORE
- X {
- X char stbot;
- X extern char *sbrk();
- X
- X printf("debugging memory use: top of data=%u", (unsigned)sbrk(0));
- X printf(", bottom of stack=%u\n", (unsigned)&stbot);
- X }
- X#endif
- X}
- X
- X/*
- X * Install the article on art->a_tmpf or art->a_files:
- X * The article should have been accepted and filed in copyart().
- X * Add history entries for the article. Log arrival.
- X * Transmit the article to our neighbours.
- X * Process control mess(age)es. ctlmsg can call transmit(fakeart,x)
- X * and generate log lines for cancels and ihave/sendme.
- X */
- XSTATIC void
- Xinsart(art)
- Xregister struct article *art;
- X{
- X if (!(art->a_status&(ST_DROPPED|ST_REFUSED|ST_DISKFULL))) {
- X if (!art->a_filed) /* paranoia */
- X (void) fprintf(stderr, "%s: %s not filed by copyart!\n",
- X progname, art->h.h_msgid);
- X history(art, STARTLOG);
- X transmit(art, exclude); /* writes systems on stdout */
- X (void) putchar('\n'); /* ends the log line */
- X if (art->h.h_ctlcmd != NULL)
- X ctlmsg(art);
- X#ifdef notdef /* it's only a log file! */
- X (void) fflush(stdout); /* crash-proofness */
- X#endif
- X }
- X art->a_status &= ~ST_REFUSED; /* refusal is quite casual & common */
- X}
- X
- X/*
- X * Reject articles. This can be arbitrarily picky.
- X * Only the headers are used to decide, so this can be called before
- X * the article is filed.
- X * Be sure to put the fastest tests first, especially if they often result
- X * in rejections.
- X */
- Xvoid
- Xreject(art)
- Xregister struct article *art;
- X{
- X if (art->h.h_path == NULL) {
- X prefuse(art);
- X (void) printf("no Path: header\n");
- X } else if (alreadyseen(art->h.h_msgid)) {
- X prefuse(art);
- X (void) printf("duplicate\n");
- X } else if (art->h.h_path != NULL && hopcount(art->h.h_path) > 0 &&
- X !ngmatch(oursys()->sy_ngs, art->h.h_ngs)) {
- X extern boolean histreject;
- X
- X /*
- X * non-local article, with all bad groups.
- X * (local articles with bad groups will be bounced
- X * by fileart when the groups aren't in active.)
- X */
- X if (histreject)
- X history(art, NOLOG);
- X prefuse(art);
- X (void) printf("no subscribed groups in `%s'\n", art->h.h_ngs);
- X } else if (art->h.h_approved == NULL && moderated(art->h.h_ngs)) {
- X prefuse(art);
- X (void) printf("unapproved article in moderated group(s) `%s'\n",
- X art->h.h_ngs);
- X } else
- X return; /* art was accepted */
- X art->a_status |= ST_REFUSED;
- X if (!okrefusal)
- X art->a_status |= ST_DROPPED;
- X}
- X
- X/*
- X * print the leader of a refusal message about the article in "art".
- X */
- Xvoid
- Xprefuse(art)
- Xregister struct article *art;
- X{
- X timestamp(stdout, (time_t *)NULL);
- X (void) printf(" %s - %s ", sendersite(nullify(art->h.h_path)),
- X art->h.h_msgid);
- X}
- X
- X/*
- X * "Uninstall" an article: remove art->a_files (permanent names) and
- X * a_tmpf (temporary name if a_unlink set), and return assigned article #'s.
- X * If a_unlink isn't set, a_tmpf is a copy of the first link in art->a_files.
- X * Must be called before history() is called, else there will be a
- X * history entry for the article, but no spool files.
- X */
- Xvoid
- Xuninsart(art)
- Xregister struct article *art;
- X{
- X if (art->a_unlink && art->a_tmpf != NULL) {
- X (void) unlink(art->a_tmpf); /* I don't wanna know... */
- X art->a_unlink = NO;
- X }
- X /* return article numbers (YES) & ignore unlink errors */
- X (void) snuffmayreturn(art->a_files, YES);
- X}
- X
- Xstatust
- Xsnufffiles(filelist) /* just unlink all files in filelist */
- Xchar *filelist;
- X{
- X /* don't return article numbers (NO) & return unlink errors */
- X return snuffmayreturn(filelist, NO);
- X}
- X
- X/*
- X * Unlink all files in filelist, and optionally return article numbers.
- X * When removing a link, note any failure, but don't issue an error message.
- X * For one thing, cancel controls fail routinely because the article has been
- X * removed manually or never existed (a previous cancel arrived before its
- X * subject and generated a fake history entry).
- X */
- XSTATIC statust
- Xsnuffmayreturn(filelist, artret)
- Xchar *filelist;
- Xboolean artret; /* return article numbers & note unlink errors? */
- X{
- X register statust status = ST_OKAY;
- X register char *arts, *spacep, *slashp, *artnm;
- X
- X /* this is a deadly tedious job and I really should automate it */
- X for (arts = filelist; arts != NULL && arts[0] != '\0';
- X arts = (spacep == NULL? NULL: spacep+1)) {
- X spacep = index(arts, ' ');
- X if (spacep != NULL)
- X spacep[0] = '\0'; /* will be restored below */
- X artnm = strsave(arts);
- X if (spacep != NULL)
- X spacep[0] = ' '; /* restore space */
- X
- X slashp = index(artnm, FNDELIM);
- X if (slashp != NULL)
- X slashp[0] = '\0'; /* will be restored below */
- X if (artret)
- X /* prevartnum will complain on i/o error to active */
- X (void) prevartnum(artnm); /* return assigned # */
- X if (slashp != NULL)
- X slashp[0] = FNDELIM; /* restore slash */
- X
- X mkfilenm(artnm);
- X if (unlink(artnm) < 0)
- X status |= ST_ACCESS;
- X free(artnm);
- X }
- X return status;
- X}
- !
- echo 'relay/relaynews.c':
- sed 's/^X//' >'relay/relaynews.c' <<'!'
- X/*
- X * relaynews - relay Usenet news (version C)
- X * See the file COPYRIGHT for the copyright notice.
- X *
- X * relaynews should be setuid-news, setgid-news. You'll need to install
- X * setnewsids setuid-root if setuid(geteuid()) doesn't work on your
- X * machine (e.g. on V7 and possibly SystemIII).
- X *
- X * Written by Geoff Collyer, 15-20 November 1985 and revised periodically
- X * since.
- X *
- X * relaynews parses article headers, rejects articles by newsgroup &
- X * message-id, files articles, updates the active & history files,
- X * transmits articles, and honours (infrequent) control messages, which do
- X * all sorts of varied and rococo things. Control messages are implemented
- X * by separate programs. relaynews reads a "sys" file to control the
- X * transmission of articles but can function as a promiscuous leaf node
- X * without one. See ARPA Internet RFC 1036 nee 850 for the whole story.
- X *
- X * A truly radical notion: people may over-ride via environment variables
- X * the compiled-in default directories so IHCC kludges are not needed and
- X * testing is possible (and encouraged) in alternate directories. This
- X * does cause a loss of privilege, to avoid spoofing.
- X *
- X * The disused old unbatched ihave/sendme protocol is gone because it was
- X * too wasteful; use the batched form instead (see the ihave sys flag
- X * ("I") instead).
- X *
- X * Portability vs SystemV. relaynews uses dbm(3) and makes no apologies
- X * for so doing. Imitation UNIX (registered trademark of AT&T in the
- X * United States) brand operating systems that lack dbm are going to
- X * have to use my incredibly slow dbm simulation, or another.
- X */
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <signal.h> /* to make locking safe */
- X#include <sys/types.h>
- X
- X#include "libc.h"
- X#include "news.h"
- X#include "config.h"
- X#include "fgetmfs.h"
- X#include "active.h"
- X#include "caches.h"
- X#include "cpu.h"
- X#include "fileart.h"
- X#include "headers.h"
- X#include "history.h"
- X#include "transmit.h"
- X
- X/*
- X * setuid-root program to set ids to news/news & rexec rnews with
- X * NEWSPERMS in the environment to break loops.
- X */
- X#ifndef SETNEWSIDS
- X#define SETNEWSIDS "setnewsids"
- X#endif
- X
- X/* exports */
- Xchar *progname;
- Xboolean okrefusal = YES; /* okay to refuse articles? */
- Xchar *exclude = NULL; /* site to exclude, for erik */
- Xboolean histreject = NO; /* keep history of rejects? */
- X
- X/* internal */
- Xstatic boolean userealids = NO;
- X
- X/* imports */
- Xextern int optind; /* set by getopt */
- Xextern char *optarg;
- Xextern statust cpinsart(); /* from procart.c */
- X
- X/* forwards */
- Xextern void prelude(), setids(), procopts(), redirectlogs(), logfile();
- Xextern void getwdandcd();
- Xextern statust procargs(), relnmprocess(), process(), unbatch();
- Xextern boolean batchln();
- XFORWARD boolean debugon();
- X
- X/*
- X * main - take setuid precautions, switch to "news" ids, ignore signals,
- X * handle options, lock news system, process files & unlock news system.
- X */
- Xint
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X statust status = ST_OKAY;
- X int redirlogs = 0; /* redirect n std output streams to logs */
- X char *origdir = NULL; /* current directory at start */
- X
- X progname = argv[0];
- X#ifdef CSRIMALLOC
- X mal_debug(0); /* was 2; 3 is too slow */
- X mal_leaktrace(0); /* was 1 */
- X#endif
- X prelude(argv); /* various precautions; switch to "news" */
- X
- X /* ignore signals (for locking). relaynews runs quickly, so don't worry. */
- X (void) signal(SIGINT, (sigarg_t)SIG_IGN);
- X (void) signal(SIGQUIT, (sigarg_t)SIG_IGN);
- X (void) signal(SIGHUP, (sigarg_t)SIG_IGN);
- X (void) signal(SIGTERM, (sigarg_t)SIG_IGN);
- X
- X procopts(argc, argv, &redirlogs, &okrefusal);
- X
- X newslock(); /* done here due to dbm internal cacheing */
- X if (redirlogs > 0) {
- X redirectlogs(redirlogs); /* redirect std output streams to logs */
- X#ifdef MANYERRORS
- X (void) putc('\n', stderr); /* leave a blank line */
- X /* prints "Jun 5 12:34:56" */
- X timestamp(stderr, (time_t *)NULL);
- X (void) putc('\n', stderr);
- X#endif
- X }
- X
- X getwdandcd(argc, argv, &origdir);
- X status |= procargs(argc, argv, &origdir);
- X
- X status |= synccaches(); /* being cautious: write & close caches */
- X (void) fflush(stdout); /* log file */
- X (void) fflush(stderr); /* errlog file */
- X
- X#ifdef notdef
- X#ifdef CSRIMALLOC
- X mal_dumpleaktrace(fileno(stderr));
- X#endif
- X#endif
- X newsunlock();
- X exit(status);
- X /* NOTREACHED */
- X}
- X
- X/*
- X * reset various environmental things for safety: umask, alarm,
- X * environment variables (PATH, IFS), standard file descriptors,
- X * user & group ids.
- X */
- Xvoid
- Xprelude(argv) /* setuid daemon prelude */
- Xchar **argv;
- X{
- X register char *newpath;
- X
- X (void) umask(2); /* undo silly umasks, ignore newsumask() */
- X (void) alarm(0); /* cancel any pending alarm */
- X newpath = malloc(STRLEN("PATH=") + strlen(newspath()) + 1);
- X if (newpath == NULL)
- X exit(1); /* no chatter until stdfdopen */
- X (void) strcpy(newpath, "PATH=");
- X (void) strcat(newpath, newspath());
- X if (putenv(newpath) ||
- X putenv("IFS= \t\n"))
- X exit(1); /* no chatter until stdfdopen */
- X closeall(1); /* closes all but std descriptors */
- X stdfdopen(); /* ensure standard descriptors are open */
- X setids(argv); /* change of real and effective ids */
- X}
- X
- X/*
- X * change real and effective ids to real ids if unprivileged() is called,
- X * else to effective ("news") ids. ctlfile((char *)0) will trigger a call
- X * to unprivileged() if any environment variables override the default
- X * path names. unprivileged() in turn sets userealids.
- X *
- X * If setuid(geteuid()) fails, try execing a small, setuid-root program
- X * to just do "getpwnam(), getgrnam() (with NEWSPERMS set), setgid(),
- X * setuid()," and exec this program again. If NEWSPERMS is set,
- X * the failure is a fatal error (recursive loop).
- X * This program (relaynews) can be setuid-news.
- X *
- X * The peculiar tests for failure (getuid() != newsuid) are to work
- X * around a Xenix bug which returns 0 from setuid() upon failure.
- X */
- Xvoid
- Xsetids(argv)
- Xchar **argv;
- X{
- X int newsuid, newsgid;
- X
- X (void) ctlfile((char *)NULL);
- X if (userealids)
- X newsuid = getuid(), newsgid = getgid();
- X else
- X newsuid = geteuid(), newsgid = getegid();
- X if (setgid(newsgid) < 0 || setuid(newsuid) < 0 ||
- X getgid() != newsgid || getuid() != newsuid) {
- X if (getenv("NEWSPERMS") != 0)
- X error("recursive loop setting ids", "");
- X execv(ctlfile(SETNEWSIDS), argv);
- X error("can't exec `%s' to set ids", ctlfile(SETNEWSIDS));
- X /* NOTREACHED */
- X }
- X /* we are now running as news, so you can all relax */
- X}
- X
- X/*
- X * parse options and set flags
- X */
- Xvoid
- Xprocopts(argc, argv, redirlogsp, okrefusalp)
- Xint argc;
- Xchar **argv;
- Xint *redirlogsp;
- Xboolean *okrefusalp;
- X{
- X int c, errflg = 0;
- X
- X while ((c = getopt(argc, argv, "d:inrsx:")) != EOF)
- X switch (c) {
- X case 'd': /* -d debug-options; thanks, henry */
- X if (!debugon(optarg))
- X errflg++; /* debugon has complained */
- X break;
- X case 'i': /* redirect stdout to log (inews) */
- X *redirlogsp = 1; /* just stdout */
- X break;
- X case 'n': /* nntp mode: keep history of rejects */
- X histreject = YES;
- X break;
- X case 'r': /* redirect std. ostreams to logs (rnews) */
- X *redirlogsp = 2; /* stdout & stderr */
- X break;
- X case 's': /* dropping input is serious (inews) */
- X *okrefusalp = NO;
- X break;
- X case 'x': /* -x site: don't send to site */
- X /* you're welcome, erik */
- X /* erik says he only needs one -x per inews */
- X if (exclude != NULL) {
- X (void) fprintf(stderr,
- X "%s: more than one -x site (%s)\n",
- X progname, optarg);
- X errflg++;
- X } else
- X exclude = optarg;
- X break;
- X default:
- X errflg++;
- X break;
- X }
- X if (errflg) {
- X (void) fprintf(stderr, "usage: %s [-inrs][-d fhlmt][-x site]\n",
- X progname);
- X exit(2);
- X }
- X}
- X
- Xvoid
- Xunprivileged() /* called if NEWSARTS, NEWSCTL or NEWSBIN present */
- X{
- X userealids = YES;
- X}
- X
- XSTATIC boolean
- Xdebugon(dbopt)
- Xregister char *dbopt;
- X{
- X statust status = YES;
- X
- X for (; *dbopt != '\0'; dbopt++)
- X switch (*dbopt) {
- X case 'f':
- X filedebug(YES);
- X break;
- X case 'h':
- X hdrdebug(YES);
- X break;
- X case 'l':
- X lockdebug(YES);
- X break;
- X case 'm':
- X matchdebug(YES);
- X break;
- X case 't':
- X transdebug(YES);
- X break;
- X default:
- X status = NO; /* unknown debugging option */
- X (void) fprintf(stderr, "%s: bad -d %c\n",
- X progname, *dbopt);
- X break;
- X }
- X return status;
- X}
- X
- X/*
- X * Redirect stdout or stderr into log files at known locations.
- X */
- Xvoid
- Xredirectlogs(count)
- Xint count;
- X{
- X if (count > 0)
- X logfile(stdout, ctlfile("log"));
- X if (count > 1)
- X logfile(stderr, ctlfile("errlog"));
- X}
- X
- Xvoid
- Xlogfile(stream, name) /* redirect stream into name */
- XFILE *stream;
- Xchar *name;
- X{
- X if (freopen(name, "a", stream) == NULL)
- X errunlock("can't redirect standard stream to `%s'", name);
- X}
- X
- X/*
- X * if argv contains relative file name arguments, save current directory name
- X * in malloced memory, through origdirp.
- X * then change directory to the spool directory ($NEWSARTS).
- X */
- Xvoid
- Xgetwdandcd(argc, argv, origdirp)
- Xint argc;
- Xchar **argv;
- Xchar **origdirp;
- X{
- X register int argind;
- X boolean needpwd = NO;
- X char dirtmp[MAXPATH]; /* much bigger than needed */
- X
- X for (argind = optind; argind < argc; argind++)
- X if (argv[argind][0] != FNDELIM)
- X needpwd = YES;
- X
- X *origdirp = "/???"; /* pessimism */
- X if (needpwd && getcwd(dirtmp, sizeof dirtmp) != 0)
- X *origdirp = dirtmp;
- X *origdirp = strsave(*origdirp); /* save a smaller copy */
- X cd(fullartfile((char *)NULL)); /* move to spool directory */
- X}
- X
- X/*
- X * process files named as arguments (or implied)
- X */
- Xstatust
- Xprocargs(argc, argv, origdirp)
- Xint argc;
- Xchar **argv;
- Xchar **origdirp;
- X{
- X register statust status = ST_OKAY;
- X
- X if (optind == argc)
- X status |= process(stdin, "stdin");
- X else
- X for (; optind < argc; optind++)
- X status |= relnmprocess(argv[optind], *origdirp);
- X nnfree(origdirp);
- X return status;
- X}
- X
- Xstatust
- Xrelnmprocess(name, origdir) /* process a (relative) file name */
- Xchar *name, *origdir;
- X{
- X register statust status = ST_OKAY;
- X register FILE *in;
- X register char *fullname;
- X
- X fullname = nemalloc((unsigned)strlen(origdir) + STRLEN(SFNDELIM) +
- X strlen(name) + 1);
- X fullname[0] = '\0';
- X
- X if (name[0] != FNDELIM) { /* relative path */
- X (void) strcat(fullname, origdir);
- X (void) strcat(fullname, SFNDELIM);
- X }
- X (void) strcat(fullname, name);
- X
- X in = fopenwclex(fullname, "r");
- X if (in != NULL) {
- X status |= process(in, fullname);
- X (void) nfclose(in);
- X }
- X free(fullname);
- X return status;
- X}
- X
- X/*
- X * process - process input file
- X * If it starts with '#', assume it's a batch and unravel it,
- X * else it's a single article, so just inject it.
- X */
- Xstatust
- Xprocess(in, inname)
- XFILE *in;
- Xchar *inname;
- X{
- X register int c;
- X
- X if ((c = getc(in)) == EOF)
- X return ST_OKAY; /* normal EOF */
- X (void) ungetc(c, in);
- X if (c == '#')
- X return unbatch(in, inname);
- X else
- X return cpinsart(in, inname, MAXLONG, NO);
- X}
- X
- X/*
- X * Unwind "in" and insert each article.
- X * For each article, call cpinsart to copy the article from "in" into
- X * a (temporary) file in the news spool directory and rename the temp file
- X * to the correct final name if it isn't right already.
- X *
- X * If the unbatcher gets out of sync with the input batch, the unbatcher
- X * will print and discard each input line until it gets back in sync.
- X */
- Xstatust
- Xunbatch(in, inname)
- Xregister FILE *in;
- Xchar *inname;
- X{
- X register int c;
- X /* register */ char *line;
- X register statust status = ST_OKAY;
- X long charcnt;
- X
- X while (!(status&ST_DISKFULL) && (c = getc(in)) != EOF) {
- X (void) ungetc(c, in);
- X while ((line = fgetms(in)) != NULL &&
- X !batchln(line, &charcnt)) { /* returns charcnt */
- X status |= ST_DROPPED;
- X (void) fprintf(stderr,
- X "%s: unbatcher out of synch, tossing: ",
- X progname);
- X (void) fputs(line, stderr);
- X free(line);
- X }
- X nnfree(&line); /* free "#! rnews n" */
- X if (!feof(in))
- X status |= cpinsart(in, inname, charcnt, YES);
- X }
- X if (ferror(in))
- X errunlock("error reading `%s'", inname);
- X return status;
- X}
- X
- X/*
- X * Is line a batcher-produced line (#! rnews count)?
- X * If so, return the count through charcntp.
- X * This is slightly less convenient than sscanf, but a lot smaller.
- X */
- Xboolean
- Xbatchln(line, charcntp)
- Xregister char *line;
- Xregister long *charcntp;
- X{
- X register char *countp;
- X static char batchtext[] = "#! rnews ";
- X
- X countp = line + STRLEN(batchtext);
- X if (STREQN(line, batchtext, STRLEN(batchtext)) &&
- X isascii(*countp) && isdigit(*countp)) {
- X *charcntp = atol(countp);
- X return YES;
- X } else {
- X *charcntp = 0;
- X return NO;
- X }
- X}
- !
- echo 'relay/sh/anne.jones':
- sed 's/^X//' >'relay/sh/anne.jones' <<'!'
- X#! /bin/sh
- X# anne.jones [file...] - censor headers: munge locally-generated headers in
- X# files, enforce feeble attempts at Usenet security, generate lots of silly
- X# headers.
- X# (after the notorious ring-leader of the Ontario Film and Video Review Board
- X# (nee Ontario Board of Censors), Ontario's very own Mrs. Mary Whitehouse.)
- X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
- X. ${NEWSCONFIG-/usr/lib/news/bin/config}
- Xexport NEWSCTL NEWSBIN NEWSARTS
- XPATH=$NEWSCTL/bin:$NEWSBIN/inject:$NEWSBIN:$NEWSPATH ; export PATH
- Xumask $NEWSUMASK
- X
- X# pass 0 - dredge up defaults
- Xcase "$trversion" in
- Xv[67]) ;;
- X*) echo "$0: trversion is nonsense or missing from environment" >&2
- X exit 1 ;;
- Xesac
- Xif test -r $NEWSCTL/mailname; then
- X mailname="`tr -d ' \11' <$NEWSCTL/mailname`"
- Xelse
- X mailname="`newshostname`"
- X case "$mailname" in
- X *.*) ;; # not a uucp host name
- X *) mailname="$mailname.uucp" ;; # probably a uucp host name
- X esac
- Xfi
- X# badsites="pucc.bitnet!" # tailor, syntax is "host1!host2!...host3!"
- Xhost="$mailname"
- X
- X# dig up user's name (a simple task, you'd think, but you'd be wrong)
- Xcase "$LOGNAME" in
- X"")
- X # "who am i" on many Unixes does "ttyname(0)" and "getpwuid(getuid())"
- X # if that fails - it can be confused by empty utmp entries (per jerqs);
- X # "who am i </dev/null" yields your userid, not your login name.
- X # "tty" does "ttyname(0)"; also fallible.
- X # So, emulate a slightly-modified V7 getlogin(3) (actually ttyslot(3)):
- X # look for tty on /dev/tty, stdin, stdout, stderr (actually via ttyname(3)).
- X for fd in 3 0 1 2 # 3 is /dev/tty on V8
- X do
- X if test -t $fd; then
- X case "$USER" in
- X "") USER="`who am i <&$fd |
- X sed -e 's/[ ].*//' -e '/!/s/^.*!//' `" ;;
- X esac
- X fi
- X done
- X case "$USER" in
- X "") USER="`who am i </dev/null | # last resort: use userid
- X sed -e 's/[ ].*//' -e '/!/s/^.*!//' `" ;;
- X esac
- X ;;
- X*) USER="$LOGNAME" ;;
- Xesac
- Xcase "$NAME" in
- X"")
- X if test -s $HOME/.name; then
- X NAME=`cat $HOME/.name`
- X else
- X NAME=`(grep "^$USER:" /etc/passwd || ypmatch "$USER" passwd) |
- X sed 's/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:]*\).*$/\1/' `
- X # tailor: for BTL RJE format, add
- X # | sed -e 's/^[^-]*- *//' -e 's/ *(.*$//'
- X # otherwise for Berkeley format, use this
- X # (courtesy Rayan Zachariassen):
- X case "$NAME" in
- X *'&'*)
- X # generate Capitalised login name
- X NM=`echo "$USER" | sed -e 's/^\(.\)\(.*\)/\1:\2/'`
- X NM1=`expr "$NM" : '\(.\):.*' |
- X case "$trversion" in
- X v7) tr a-z A-Z ;;
- X v6) tr '[a-z]' '[A-Z]' ;;
- X esac
- X `
- X NMR=`expr "$NM" : '.:\(.*\)'`
- X CAPNM="$NM1$NMR"
- X # turn & into Capitalised login name
- X NAME=`echo "$NAME" | sed "s:&:$CAPNM:"`
- X ;;
- X esac
- X fi
- X ;;
- Xesac
- Xcase "$NAME" in
- X"") fullname="" ;; # no full name, leave it off
- X*) fullname=" ($NAME)" ;;
- Xesac
- Xreallyfrom="$USER@$host$fullname"
- XFROM="$reallyfrom"
- X
- X# generate a few defaults.
- X# RFC 1036 requests a GMT Date:, despite it being hard to read.
- X# Compensate for V6 Uglix date (no -u) tarted up with all that TZ goo.
- Xdate="`
- X set ''\`TZ=GMT0 date\` # give TZ to see if (Uglix) date responds
- X case \"$5\" in
- X GMT) echo $* ;; # Uglix date or V7 date with GMT local time
- X *) date -u ;; # must be V7 date command, it ignored TZ
- X esac
- X`" # for defdate, defmsgid
- Xcase "$ORGANIZATION" in
- X"") deforg="`sed 1q $NEWSCTL/organi[sz]ation`" ;; # look in a file
- X*) deforg="$ORGANIZATION" ;; # look in environment
- Xesac
- X
- X# give defaults and headers to awk
- Xcat $* |
- X # strip invisible chars, a la B news; turn tabs to spaces (RFC1036)
- X case "$trversion" in
- X v7) tr -d '\1-\7\13\14\16-\37';;
- X v6) tr -d '[\1-\7]\13\14[\16-\37]' ;;
- X esac |
- X sed 's/: /: /' |
- X awk -f $NEWSBIN/inject/defhdrs.awk \
- Xdefpath="$badsites$USER" \
- Xdeffrom="$FROM" deforg="$deforg" \
- Xdefdate="` set $date; echo $1, $3 $2 \` echo $6 | sed 's/^..//' \` $4 $5`" \
- Xdefmsgid="`set $date; echo \<$6$2$3.\` echo $4 | tr -d : \`.$$@$host\>`" -
- !
- echo 'relay/sh/ctlrun':
- sed 's/^X//' >'relay/sh/ctlrun' <<'!'
- X#! /bin/sh
- X# ctlrun - run the control messages in control again
- X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
- X. ${NEWSCONFIG-/usr/lib/news/bin/config}
- X# export NEWSCTL NEWSBIN NEWSARTS
- XPATH=$NEWSCTL/bin:$NEWSBIN/ctl:$NEWSBIN:$NEWSPATH ; export PATH
- Xumask $NEWSUMASK
- X
- Xcd $NEWSCTL
- Xnewslock sys LOCK || exit 1 # lock
- X
- Xcd $NEWSARTS/control
- X
- Xfor file in *
- Xdo
- X grep '^Control:' $file |
- X sed 's;^Control:[ ]*;'$NEWSBIN/ctl/';' |
- X grep -v '/cancel ' >/tmp/ctl$$ # cancel needs dbm(3)
- X sh -x /tmp/ctl$$ <$file
- Xdone
- X
- Xrm -f /tmp/ctl$$
- Xrm -f LOCK
- !
- echo 'relay/sh/defhdrs.awk':
- sed 's/^X//' >'relay/sh/defhdrs.awk' <<'!'
- X# defhdrs.awk
- X# pass 1 - note presence | absence of certain headers
- X# a header keyword: remember it and its value
- X/^[^\t ]*:/ {
- X hdrval[$1] = $0
- X keyword=$1
- X next
- X}
- X# a continuation: concatenate this line to the value
- X { hdrval[keyword] = hdrval[keyword] "\n" $0 }
- X
- XEND {
- X # pass 2 - cogitate & omit & emit headers
- X emptyhdrre = "^[^\t ]*:[\t ]*$"
- X subjname = "Subject:"
- X ctlname = "Control:"
- X ngname = "Newsgroups:"
- X msgidname = "Message-ID:"
- X typoname = "Message-Id:"
- X pathname = "Path:"
- X datename = "Date:"
- X fromname = "From:"
- X orgname = "Organization:"
- X distrname = "Distribution:"
- X sendername = "Sender:"
- X
- X # fill in missing headers
- X if (hdrval[typoname] != "") { # spelling hack
- X hdrval[msgidname] = hdrval[typoname]
- X hdrval[typoname] = ""
- X # fix spelling: Message-Id: -> Message-ID:
- X nf = split(hdrval[msgidname], fields); # bust up
- X fields[1] = msgidname; # fix spelling
- X hdrval[msgidname] = fields[1]; # reassemble...
- X for (i = 2; i <= nf; i++)
- X hdrval[msgidname] = hdrval[msgidname] " " fields[i]
- X }
- X if (hdrval[msgidname] == "")
- X hdrval[msgidname] = msgidname " " defmsgid
- X if (hdrval[orgname] == "")
- X hdrval[orgname] = orgname " " deforg
- X
- X # replace users headers (if any)
- X hdrval[datename] = datename " " defdate
- X hdrval[pathname] = pathname " " defpath
- X if (hdrval[fromname] == "")
- X hdrval[fromname] = fromname " " deffrom
- X else if (hdrval[sendername] == "")
- X hdrval[sendername] = sendername " " deffrom
- X
- X # snuff some headers
- X distworld = distrname " world"
- X if (hdrval[distrname] == distworld)
- X hdrval[distrname] = ""
- X
- X # the vile cmsg hack, for the sake of the news readers *only*
- X if (hdrval[ctlname] == "" && \
- X substr(hdrval[subjname], 1, 14) == "Subject: cmsg ")
- X hdrval[ctlname] = ctlname " " substr(hdrval[subjname], 15)
- X
- X # warn if no Newsgroups:
- X if (hdrval[ngname] == "")
- X print "no newsgroups header!" | "cat >&2"
- X
- X # field the all.all.ctl hack, for the sake of the backward only:
- X # clone Subject: to make Control:
- X if (hdrval[ctlname] == "" && hdrval[ngname] ~ /\.ctl(,|$)/)
- X hdrval[ctlname] = ctlname " " substr(hdrval[subjname], 8)
- X
- X # reorder & emit headers
- X
- X # favour Control: & Newsgroups: for future benefit of rnews
- X if (hdrval[ctlname] != "") {
- X print hdrval[ctlname]
- X hdrval[ctlname] = "" # no Control: to print now
- X }
- X if (hdrval[ngname] != "") {
- X print hdrval[ngname]
- X hdrval[ngname] = "" # no Newsgroups: to print now
- X }
- X
- X # B inews kludgery: print Path: before From: to avoid confusing it
- X if (hdrval[pathname] != "") {
- X print hdrval[pathname]
- X hdrval[pathname] = "" # no Path: to print now
- X }
- X if (hdrval[fromname] != "") {
- X print hdrval[fromname]
- X hdrval[fromname] = "" # no From: to print now
- X }
- X
- X # have pity on readers: put Subject: next
- X if (hdrval[subjname] != "") {
- X print hdrval[subjname]
- X hdrval[subjname] = "" # no Subject: to print now
- X }
- X
- X # print misc. non-empty headers in random order
- X for (i in hdrval)
- X if (hdrval[i] != "" && hdrval[i] !~ /^[^\t ]*:[\t ]*$/)
- X print hdrval[i]
- X}
- !
- echo 'relay/sh/inews':
- sed 's/^X//' >'relay/sh/inews' <<'!'
- X#! /bin/sh
- X# inews [-p] [-debug k] [-x site] [-hMD] [-t subj] [-n ng] [-e exp] [-F ref] \
- X# [-d dist] [-a mod] [-f from] [-o org] [-C ng] [file...] - inject news:
- X# censor locally-posted article and field the "inews -C" kludge;
- X# munge the articles, enforce feeble attempts at Usenet security,
- X# generate lots of silly headers.
- X#
- X# Yes, it's big, slow and awkward. The alternative is casting a lot of
- X# local policy in C.
- X
- X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
- X. ${NEWSCONFIG-/usr/lib/news/bin/config}
- Xexport NEWSCTL NEWSBIN NEWSARTS NEWSPATH NEWSUMASK NEWSMASTER NEWSCONFIG
- XPATH=$NEWSCTL/bin:$NEWSBIN/inject:$NEWSBIN/relay:$NEWSBIN:$NEWSPATH; export PATH
- XPASSEDFROM=''; export PASSEDFROM # passed to anne.jones in environ.
- X
- Xdebug='' # flags
- Xexclusion=''
- Xhdrspresent=no
- Xautopost=no
- Xwaitcmd=''
- Xrelayopts=-i # redirect stdout to log
- X
- Xwhoami=/tmp/in$$who # just created to determine effective uid
- Xinput=/tmp/in$$in # uncensored input
- Xinhdrs=/tmp/in$$hdr # generated by tear: headers
- Xinbody=/tmp/in$$body # generated by tear: body
- Xcensart=/tmp/in$$cens # censored input
- Xnglist=/tmp/in$$ngs # newsgroups: list
- Xmodroute=/tmp/in$$route # route to moderator's forwarder
- Xexitflag=/tmp/in$$exit # exit status, if present
- Xoutfile=/tmp/in$$out # relaynews stdout
- Xgrpok=/tmp/in$$grp # flag file: groups okay if present
- Xrmlist="$inhdrs $inbody $input $censart $nglist $modroute $exitflag $outfile $grpok"
- X
- Xumask $NEWSUMASK
- X
- X# "inews -p": invoke rnews
- Xcase "$1" in
- X-p)
- X shift
- X exec rnews $* # rnews, bailing out at or near line 1
- X ;;
- Xesac
- X
- X# process arguments: for options, cat headers onto $input; cat files onto $input
- X>$input
- Xcleanup="test ! -f $HOME/dead.article -o -w $HOME/dead.article &&
- X cat $input >>$HOME/dead.article &&
- X { echo $0: article in $HOME/dead.article >&2; rm -f $rmlist; }; exit 1"
- Xtrap "$cleanup" 0 1 2 3 15
- Xwhile :
- Xdo
- X case $# in
- X 0) break ;; # arguments exhausted
- X esac
- X
- X case "$1" in
- X # peculiar to C news
- X -debug) shift; debug="$1" ;;
- X -A) autopost=yes ;; # wait for free space
- X -V) relayopts= ;; # verbose: don't redirect stdout (or stderr)
- X -W) waitcmd=wait ;; # wait for completion
- X # useful standard options
- X -h) hdrspresent=yes ;;
- X -x) shift; exclusion="-x $1" ;; # you're welcome, erik (2.11)
- X # silly options supplied by newsreaders
- X -a) shift; echo "Approved: $1" >>$input ;;
- X -c) shift; echo "Control: $1" >>$input ;;
- X -d) shift; echo "Distribution: $1" >>$input ;;
- X -e) shift; echo "Expires: $1" >>$input ;;
- X -f) shift; echo "From: $1" >>$input ;;
- X -n) shift; echo "Newsgroups: $1" >>$input ;;
- X -t) shift; echo "Subject: $1" >>$input ;; # aka Title:
- X -D) # obsolete, undocumented: meant "don't check for recordings".
- X # last present in B 2.10.1, invoked by readnews for followups.
- X ;;
- X -F) # undocumented in B 2.10.1, documented in B 2.11.
- X shift; echo "References: $1" >>$input ;;
- X -M) # this apparently just sets From: to the author of the article
- X # instead of the poster (moderator), by leaving the From: line
- X # alone (under -h); easy to implement.
- X ;;
- X
- X # pass next options as environment variables to anne.jones
- X -o) shift; ORGANIZATION="$1"; export ORGANIZATION ;;
- X
- X -C) # megakludge-o-rama
- X # first, permit only to super-users
- X >$whoami
- X case "`ls -l $whoami | awk '{print $3}'`" in
- X root) : a winner ;;
- X *)
- X echo "$0: only super-users may create news groups" >&2
- X exit 1
- X ;;
- X esac
- X rm -f $whoami
- X
- X inewsopt="$1" # for use in message body
- X shift # skip -C to get ng as $1
- X
- X cat <<! >>$input # generate a control message
- XNewsgroups: $1
- XControl: newgroup $1
- XSubject: newgroup $1
- XApproved: above-user@above-host
- X
- XThis article generated by inews $inewsopt $1.
- X!
- X ;;
- X -*)
- X echo "$0: bad option $1" >&2
- X exit 1
- X ;;
- X *) # is a filename; append file
- X # B 2.11 kludge: assume -h if input starts with headers.
- X # apparently the B 2.11 newsreaders assume this.
- X tear /tmp/in$$ <$1
- X if test -s $inhdrs; then
- X hdrspresent=yes
- X fi
- X
- X case "$hdrspresent" in
- X no) echo "" >>$input; hdrspresent=yes ;;
- X esac
- X # capture incoming news in case relaynews fails
- X if cat $inhdrs $inbody >>$input; then
- X : far out
- X else
- X echo "$0: lost news; cat status $?" >&2
- X exit 1
- X fi
- X fileseen=yes
- X ;;
- X esac
- X shift # pass option or filename (any value was done above)
- Xdone
- X
- X# if no files named, read stdin
- Xcase "$fileseen" in
- Xyes) ;;
- X*)
- X # B 2.11 kludge: assume -h if input starts with headers
- X # apparently the B 2.11 newsreaders assume this.
- X tear /tmp/in$$
- X if test -s $inhdrs; then
- X hdrspresent=yes
- X fi
- X
- X case "$hdrspresent" in
- X no) echo "" >>$input; hdrspresent=yes ;;
- X esac
- X # capture incoming news in case relaynews fails
- X if cat $inhdrs $inbody >>$input; then
- X : far out
- X else
- X echo "$0: lost news; cat status $?" >&2
- X exit 1
- X fi
- X ;;
- Xesac
- Xtrap '' 1 2 15 # ignore signals to avoid losing articles
- X
- X# run the remainder in the background for the benefit of impatient people
- X# who lack a window system
- X(
- Xtrap "$cleanup" 0
- Xtear /tmp/in$$ <$input # output in $inhdrs and $inbody
- X# pad zero-line articles, since old B [ir]news are confused by them
- X# and the news readers generate zero-line control messages, alas.
- Xif test ! -s $inbody; then
- X (echo '';
- X echo This article was probably generated by a buggy news reader.) \
- X >$inbody
- Xfi
- X
- X# deduce which tr we have: v6 or v7
- Xcase "`echo B | tr A-Z a-z `" in
- Xb) trversion=v7 ;;
- XB) trversion=v6 ;; # or System V
- Xesac
- Xexport trversion
- X
- X# post with new headers and .signature
- X(anne.jones <$inhdrs # bash headers
- X # echo "Lines: ` # sop to msb, just uncomment to use
- X # if test -r $HOME/.signature; then
- X # (cat $inbody; echo '-- '; sed 4q $HOME/.signature) | wc -l
- X # else
- X # wc -l <$inbody
- X # fi
- X # `"
- X
- X # strip invisible chars from body, a la B news
- X case "$trversion" in
- X v7) tr -d '\1-\7\13\14\16-\37' ;;
- X v6) tr -d '[\1-\7]\13\14[\16-\37]' ;;
- X esac <$inbody
- X
- X if test -r $HOME/.signature; then
- X echo "-- "; sed 4q $HOME/.signature # glue on first bit of signature
- X fi) >$censart
- X
- X# to post or to mail? that is the question; whether 'tis nobler in the mind
- X# to suffer the slings and arrows of outrageous mailers - Bill Shakespeare
- Xif grep -s '^Control:' $inhdrs >/dev/null; then
- X echo "control" # a dreadful hack around all.all.ctl
- Xelse
- X sed -n '
- X/^Newsgroups:[ ]/{
- Xs/^Newsgroups:[ ]*\(.*\)$/\1/p
- Xq
- X}
- X' <$inhdrs
- Xfi >$nglist
- X
- Xif test ! -s $nglist; then # no Newsgroups:
- X exit 1 # anne.jones will have already complained
- Xfi
- X
- X# look up groups in active, to determine disposition of this message.
- X# n, x and (unapproved) m flags are dealt with on the spot; if none are
- X# seen, the article is posted normally.
- X# escape egrep metacharacters. In theory one could add " ' ` \
- Xegreppat="^(` sed -e 's/[.+*()|[]/\\\\&/g' -e 's/,/|/g' <$nglist `) "
- Xegrep "$egreppat" $NEWSCTL/active >/dev/null || {
- X echo "$0: `cat $nglist` matches no groups in $NEWSCTL/active" >&2
- X exit 1
- X}
- Xrm -f $grpok
- Xegrep "$egreppat" $NEWSCTL/active |
- X (while read ng high low flag junk # look at next group's active entry
- X do
- X >>$grpok
- X case "$flag" in
- X [nx])
- X echo "$0: sorry, $ng may not be posted to locally." >&2
- X echo 1 >$exitflag
- X trap 0 # this is a child process - no cleanup
- X exit 1 # dregs in /tmp/in$$*
- X ;;
- X m)
- X if grep -s '^Approved:[ ]' $inhdrs >/dev/null; then
- X rm -f $modroute # just post normally
- X else
- X # un-Approved: mail it to the moderator(s).
- X echo "%s" >$modroute # in case no route
- X # look for route for this group
- X cat $NEWSCTL/mailpaths |
- X while read ngpat route junk
- X do
- X # a dreadful B 2.11 hack:
- X # backbone == all
- X case "$ngpat" in
- X backbone) ngpat="all" ;;
- X esac
- X if gngp -a "$ngpat" $nglist >/dev/null; then
- X echo "$route" >$modroute
- X break # take only 1st match
- X fi
- X done
- X fi
- X # ngpat and route are not set here, damn it!
- X if test -s $modroute; then
- X # an unapproved article in a mod group:
- X # mail the article to this moderator.
- X moderator=`
- X sed "s/%s/\` echo $ng | tr . - \`/" $modroute
- X `
- X echo "$0: mailing your article to $moderator" >&2
- X mail $moderator <$censart
- X rm -f $rmlist
- X echo 0 >$exitflag
- X trap 0 # this is a child process - did cleanup
- X exit 0
- X fi
- X ;;
- X
- X # "" matches short active entries,
- X # to be backward compatible.
- X # * matches garbage flags, to be cautious.
- X y|""|*)
- X # okay so far, but wait until we see all Newsgroups:.
- X ;;
- X esac
- X done
- X trap 0 # paranoia - no clean up
- X )
- Xif test ! -r $grpok; then
- X echo "$0: no active groups in `cat $nglist`" >&2
- X exit 1 # abnormal exit - cleans up, makes dead.article
- Xfi
- Xif test -f $exitflag; then
- X exitstatus="`cat $exitflag`"
- X case "$exitstatus" in
- X 0) trap 0 ;; # normal exit - cleanup done, no dead.article
- X esac
- X exit $exitstatus # trap 0 will cleanup, make dead.article
- Xfi
- X
- X# deal with inadequate free space
- Xcase "$autopost" in
- Xno)
- X if test "`spacefor 1 articles`" -le 0; then
- X echo "$0: too little space free on $NEWSARTS" >&2
- X exit 1 # dregs in /tmp/in$$* for trap 0
- X fi
- X ;;
- X*)
- X iter=0
- X while test "`spacefor 1 articles`" -le 0 -o "`spacefor 1 control`" -le 0
- X do
- X sleep 30
- X iter=`expr $iter + 1`
- X case "$iter" in
- X 3)
- X mail "$NEWSMASTER" <<!
- XSubject: free space too low on $NEWSARTS
- X
- XThere is too little free space on $NEWSARTS for inews to run comfortably.
- X!
- X ;;
- X esac
- X done
- X ;;
- Xesac
- X
- X# to get here, we must have seen no n, x, nor (unapproved) m flags.
- X# <$censart is used rather than a pipe to work around a bug in the 4.2 sh
- X# which made it sometimes return the wrong exit status (that of anne.jones).
- X# execute relaynews commands on the server, for the sake of locking.
- X# may not use "exec" or sh will leave /tmp/sh* files from here docs in /tmp.
- Xme="`hostname`"
- Xserver=`cat $NEWSCTL/server 2>/dev/null`
- Xcase "$server" in
- X"") server="$me" ;; # if no server file, assume this is it
- Xesac
- Xcase "$me" in
- X$server)
- X relaynews $relayopts -s $exclusion -d "$debug" <$censart
- X status=$?
- X# echo "status $? from relaynews" >>/tmp/inewsdebug # DEBUG
- X ;;
- X*)
- X status=`rsh $server \
- X"PATH=$PATH relaynews $relayopts -s $exclusion -d \"$debug\"; echo status $?" \
- X <$censart >$outfile; sed -n '/^status /s///p' $outfile `
- X sed '/^status /d' $outfile # print relaynews's stdout
- X ;;
- Xesac
- Xcase "$status" in
- X0)
- X rm -f $rmlist # far out, it worked: clean up
- X if test ! -f $NEWSCTL/sys; then
- X echo "$0: $NEWSCTL/sys missing; your news can't leave this machine" >&2
- X fi
- X trap 0 # normal exit: cleanup done
- X ;;
- Xesac
- Xexit $status # trap 0 may cleanup, make dead.article
- X) &
- X$waitcmd # wait if -W given
- Xtrap 0 # let the background run on unmolested
- Xexit
- !
- echo done
-
-
-