home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume19 / cnews2 / part16 < prev    next >
Text File  |  1989-06-29  |  51KB  |  1,742 lines

  1. Subject:  v19i093:  Cnews production release, Part16/19
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: utzoo!henry
  7. Posting-number: Volume 19, Issue 93
  8. Archive-name: cnews2/part16
  9.  
  10. : ---CUT HERE---
  11. echo 'relay/makefile':
  12. sed 's/^X//' >'relay/makefile' <<'!'
  13. X# makefile for C news relaynews
  14. X
  15. X# =()<NEWSARTS = @<NEWSARTS>@>()=
  16. XNEWSARTS = /usr/spool/news
  17. X# =()<NEWSBIN = @<NEWSBIN>@>()=
  18. XNEWSBIN = /usr/lib/newsbin
  19. X# =()<NEWSCTL = @<NEWSCTL>@>()=
  20. XNEWSCTL = /usr/lib/news
  21. X# workaround for System V make bug
  22. XSHELL = /bin/sh
  23. X
  24. XBIN=/bin
  25. XNPROC=2
  26. X# -DVOID=int for libc.h & old lint libraries
  27. XDEFINES= -I../include -I. -DVOID=int -DFLUSHEVERY=6
  28. X#CC=CC +V
  29. X#CC=gcc -ansi -pedantic -Wall -S
  30. X#CC=redcc
  31. XCOPTS= -O # -pg -g
  32. XCFLAGS=$(DEFINES) $(COPTS)
  33. XDBM = -ldbm
  34. XLIBS= $(DBM)
  35. XLINT=lint
  36. XLINTFLAGS=-haz $(DEFINES)
  37. XLLIBS=-llocal
  38. X# I wish I could make lint shut the fk up about some things.  Grrr!
  39. XLINTFILT=egrep -v '(possible pointer|long assign|can.t take|never used|nnfree|getdate|:$$)'
  40. XPROPTS=
  41. XP=stpr
  42. XPP=pp -Tpsc -fR # lazywriter
  43. XPPBACK=dps | stps # lazywriter
  44. X
  45. XLIBOBJS=../libcnews.a
  46. XSRC=relaynews.c active.c article.c caches.c mkdirs.c control.c fileart.c \
  47. X    hdrdefs.c hdrcommon.c hdrparse.c hdrmunge.c \
  48. X    history.c io.c msgs.c procart.c \
  49. X    sys.c transmit.c trbatch.c ihave.c $(LIBSRCS)
  50. XOBJ=relaynews.o active.o article.o caches.o mkdirs.o control.o fileart.o \
  51. X    hdrdefs.o hdrcommon.o hdrparse.o hdrmunge.o \
  52. X    history.o io.o msgs.o procart.o \
  53. X    sys.o transmit.o trbatch.o ihave.o $(LIBOBJS)
  54. XFILES=$(NONCFILES) $(CFILES)
  55. XNONCFILES= TODO* README ads/README ads/[0-9]* \
  56. X    sh/inews sh/tear sh/anne.jones sh/defhdrs.awk \
  57. X    sh/realrnews sh/serverrnews makefile
  58. XCFILES= ../include/*.h \
  59. X    active.h article.h caches.h mkdirs.h control.h cpu.h fileart.h \
  60. X    hdrint.h headers.h history.h system.h transmit.h trbatch.h $(SRC)
  61. X
  62. Xall: makefile relaynews
  63. X
  64. Xmkfile: makefile
  65. X    sed '/mkfile/d' makefile | mkconv | sed 's/make/mk/g' >$@
  66. X
  67. Xrelaynews: $(OBJ)
  68. X    $(CC) $(CFLAGS) $(OBJ) $(LIBS) $(LIBOBJS) -o $@
  69. Xlint: $(SRC)
  70. X    $(LINT) $(LINTFLAGS) $(SRC) $(LLIBS) | $(LINTFILT)
  71. Xlint-p: $(SRC)
  72. X    $(LINT) $(LINTFLAGS) -p $(SRC) $(LLIBS) | $(LINTFILT)
  73. X
  74. Xnewsinstall:
  75. X    : nothing
  76. X
  77. X# bininstall: make directories, install programs
  78. Xbininstall: install
  79. Xinstall: $(NEWSBIN)/relay/relaynews
  80. X$(NEWSBIN)/relay/relaynews: relaynews
  81. X    -mkdir $(NEWSBIN)/relay $(NEWSBIN)/inject $(NEWSBIN)/ctl
  82. X    rm -f $(NEWSBIN)/relay/relaynews
  83. X    cp relaynews $(NEWSBIN)/relay
  84. X    : needs to be news-owned, setuid -- build looks after that
  85. X    chmod +x sh/* aux/* ctl/*
  86. X    cp sh/* $(NEWSBIN)/inject
  87. X    cp ctl/* $(NEWSBIN)/ctl
  88. X    cp aux/* $(NEWSBIN)/relay
  89. X    cp sh/postnews sh/inews $(BIN)
  90. X
  91. XTODO.grep: TODO
  92. X    -egrep TODO ../include/*.h *.h *.c sh/* | tr -s " \11" " " >$@
  93. X    -egrep TODO ../lib*/*.[ch] | tr -s " \11" " " >>$@
  94. X
  95. Xv7 v8 v9 usg bsd42:
  96. X    test -d libos && exit 1
  97. X    mv lib$@ libos # or ln -s lib$@ libos
  98. X    make
  99. X
  100. Xprint: printc printnonc
  101. X    touch $@
  102. Xprintc: $(CFILES)
  103. X    $(PP) $? | $(PPBACK)
  104. X    touch $@
  105. Xprintnonc: $(NONCFILES)
  106. X    pr $(PROPTS) $? | $P
  107. X    touch $@
  108. Xdistr: $(FILES)
  109. X    (echo relaynews update of `date`; echo ""; bundle $?) | /bin/mail cnews-updates
  110. X    touch $@
  111. Xclean:
  112. X    rm -f core a.out relaynews *.o    
  113. X    rm -rf regress/tmp
  114. X
  115. Xr:    relaynews
  116. X    chmod +x regress/regress
  117. X    cd regress; ./regress
  118. X    
  119. X# header dependencies follow
  120. Xactive.o: ../include/libc.h ../include/news.h ../include/config.h
  121. Xactive.o: active.h
  122. Xarticle.o: ../include/news.h article.h headers.h
  123. Xcaches.o: ../include/news.h active.h caches.h transmit.h
  124. Xmkdirs.o: ../include/libc.h ../include/news.h
  125. Xcontrol.o: ../include/libc.h ../include/news.h ../include/config.h
  126. Xcontrol.o: headers.h article.h caches.h history.h
  127. Xfileart.o: ../include/libc.h ../include/news.h ../include/config.h
  128. Xfileart.o: active.h mkdirs.h headers.h article.h history.h system.h
  129. Xhdrcommon.o: ../include/news.h headers.h hdrint.h
  130. Xhdrdefs.o: ../include/news.h headers.h hdrint.h
  131. Xhdrmunge.o: ../include/libc.h ../include/news.h fileart.h headers.h
  132. Xhdrmunge.o: article.h hdrint.h
  133. Xhdrparse.o: ../include/libc.h ../include/news.h headers.h hdrint.h
  134. Xhistory.o: ../include/libc.h ../include/news.h ../include/config.h
  135. Xhistory.o: ../include/fgetmfs.h headers.h article.h history.h
  136. Xhostname.o: ../include/news.h ../include/config.h
  137. Xihave.o: ../include/libc.h ../include/news.h ../include/config.h
  138. Xihave.o: headers.h article.h caches.h history.h
  139. Xio.o: ../include/news.h headers.h article.h
  140. Xmsgs.o: ../include/news.h headers.h article.h
  141. Xprocart.o: ../include/libc.h ../include/news.h active.h control.h
  142. Xprocart.o: headers.h article.h history.h system.h
  143. Xrelaynews.o: ../include/libc.h ../include/news.h ../include/config.h
  144. Xrelaynews.o: ../include/fgetmfs.h active.h caches.h cpu.h headers.h
  145. Xrelaynews.o: history.h
  146. Xstring.o: ../include/libc.h ../include/news.h
  147. Xsys.o: ../include/libc.h ../include/fgetmfs.h ../include/news.h
  148. Xsys.o: ../include/config.h system.h
  149. Xtransmit.o: ../include/libc.h ../include/news.h ../include/config.h
  150. Xtransmit.o: headers.h active.h article.h system.h trbatch.h transmit.h
  151. Xtrbatch.o: ../include/libc.h ../include/news.h trbatch.h
  152. !
  153. echo 'relay/mkdirs.c':
  154. sed 's/^X//' >'relay/mkdirs.c' <<'!'
  155. X/*
  156. X * mkdirs - make the directories implied by `name'
  157. X */
  158. X
  159. X#include <stdio.h>
  160. X#include <sys/types.h>
  161. X#include <sys/stat.h>
  162. X#include "libc.h"
  163. X#include "news.h"
  164. X
  165. X/*
  166. 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;
  167. X * stop on first failure.
  168. X * Returns success.
  169. X */
  170. Xboolean
  171. Xmkdirs(name, uid, gid)
  172. Xregister char *name;
  173. Xint uid, gid;
  174. X{
  175. X    register char *cp;
  176. X    register int isthere = YES;
  177. X    struct stat stbuf;
  178. X
  179. X    for (cp = name; isthere && *cp != '\0'; cp++)
  180. X        if (*cp == FNDELIM) {
  181. X            *cp = '\0';
  182. X            isthere = stat(name, &stbuf) >= 0;
  183. X            if (!isthere) {
  184. X                isthere = mkdir(name, 0777) >= 0;
  185. X                (void) chown(name, uid, gid);
  186. X            }
  187. X            *cp = FNDELIM;
  188. X        }
  189. X    return isthere;
  190. X}
  191. !
  192. echo 'relay/mkdirs.h':
  193. sed 's/^X//' >'relay/mkdirs.h' <<'!'
  194. X/* imports from mkdirs.c */
  195. Xextern boolean mkdirs();
  196. !
  197. echo 'relay/mklint':
  198. sed 's/^X//' >'relay/mklint' <<'!'
  199. X#! /bin/sh
  200. Xlint -hazu -I../include -I../include/bsd42 -I../rnews -DSTATIC= $* -llocal |
  201. X    egrep -v '(possible pointer|long assign|can.t take|never used|:$)'
  202. !
  203. echo 'relay/msgs.c':
  204. sed 's/^X//' >'relay/msgs.c' <<'!'
  205. X/*
  206. X * print common messages
  207. X */
  208. X
  209. X#include <stdio.h>
  210. X#include <sys/types.h>
  211. X#include "news.h"
  212. X#include "headers.h"
  213. X#include "article.h"
  214. X#include "msgs.h"
  215. X
  216. Xvoid
  217. Xfulldisk(art, file)        /* complain once & set ST_DISKFULL */
  218. Xregister struct article *art;
  219. Xchar *file;
  220. X{
  221. X    if (!(art->a_status&ST_DISKFULL))
  222. X        art->a_status |= prfulldisk(file);
  223. X}
  224. X
  225. Xstatust
  226. Xprfulldisk(file)        /* complain once & return bad status */
  227. Xchar *file;
  228. X{
  229. X    warning("error writing `%s', probably the disk filled", file);
  230. X    return ST_DISKFULL|ST_DROPPED;
  231. X}
  232. !
  233. echo 'relay/msgs.h':
  234. sed 's/^X//' >'relay/msgs.h' <<'!'
  235. X/* imports from msgs.c */
  236. Xextern statust prfulldisk();
  237. Xextern void fulldisk();
  238. !
  239. echo 'relay/procart.c':
  240. sed 's/^X//' >'relay/procart.c' <<'!'
  241. X/*
  242. X * process a single incoming article
  243. X */
  244. X
  245. X#include <stdio.h>
  246. X#include <sys/types.h>
  247. X#include "libc.h"
  248. X#include "news.h"
  249. X#include "active.h"
  250. X#include "control.h"
  251. X#include "headers.h"
  252. X#include "article.h"
  253. X#include "history.h"
  254. X#include "io.h"
  255. X#include "msgs.h"
  256. X#include "system.h"
  257. X#include "transmit.h"
  258. X
  259. X/*
  260. X * COPYSIZE is the length of a bulk-copying buffer: the bigger the better,
  261. X * though fewer than 3% of articles exceed 8192 bytes (may 1988).
  262. X * It holds header lines first, and later holds bytes of the body.
  263. X * This buffer is allocated once at the start and never deallocated.
  264. X */
  265. X#ifndef COPYSIZE
  266. X#ifdef SMALLMEM
  267. X#define COPYSIZE BUFSIZ        /* conserve memory at the expense of speed */
  268. X#else
  269. X#define COPYSIZE 8192        /* big enough even for worst-case 4.2bsd blocks */
  270. X#endif                /* SMALLMEM */
  271. X#endif                /* COPYSIZE */
  272. X
  273. Xextern char *exclude;        /* for erik */
  274. Xextern boolean okrefusal;    /* flag from command line */
  275. X
  276. X/* forwards */
  277. Xextern void tossorfile(), surveydamage(), reject(), prefuse(), uninsart();
  278. Xextern char *hdrcopy();
  279. XFORWARD void copyart(), cpybody(), insart();
  280. XFORWARD statust snuffmayreturn();
  281. X
  282. X/*
  283. X * Copy the article on "in" to a temporary name in the news spool directory,
  284. X * unlink temp name; *or* copy into the final names, if known early enough.
  285. X * (Sets a_tmpf in or near hdrmunge() or hdrdump().)
  286. X * If the spool file opened, install the article it contains.
  287. X */
  288. Xstatust
  289. Xcpinsart(in, inname, maxima, blvmax)
  290. XFILE *in;
  291. Xregister char *inname;
  292. Xlong maxima;
  293. Xboolean blvmax;                /* believe maxima? */
  294. X{
  295. X    register struct article *artp;
  296. X    register statust status;
  297. X    struct article art;
  298. X
  299. X    artp = &art;
  300. X    artinit(artp);
  301. X    artp->a_blvmax = blvmax;
  302. X    artp->a_unread = maxima;
  303. X
  304. X    /*
  305. X     * copyart() may reject() the article, and may fill the disk.
  306. X     * it calls fileart and logs rejected articles.
  307. X     */
  308. X    copyart(artp, in, inname);
  309. X
  310. X    if (artp->a_status&ST_REFUSED) {
  311. X        /* no good ngs (in fileart) or reject()ed; not serious */
  312. X        artp->a_status &= ~ST_REFUSED;
  313. X        /* paranoia; shouldn't happen */
  314. X        nnfclose(artp, &artp->a_artf, inname);
  315. X    } else if (artp->a_artf == NULL) {
  316. X        warning("can't open spool file `%s'", artp->a_tmpf);
  317. X        artp->a_status |= ST_DROPPED;
  318. X    } else {
  319. X        nnfclose(artp, &artp->a_artf, inname);
  320. X        insart(artp);    /* logs accepted art.s during transmission */
  321. X        if (artp->a_status&ST_JUNKED) {    /* yer welcome, henry */
  322. X            artp->a_status &= ~ST_JUNKED;
  323. X            timestamp(stdout, (time_t *)NULL);
  324. X            (void) printf(" %s j %s junked due to groups `%s'\n",
  325. X                sendersite(nullify(artp->h.h_path)),
  326. X                artp->h.h_msgid, artp->h.h_ngs);
  327. X        }
  328. X    }
  329. X    status = artp->a_status;
  330. X    artfree(artp);
  331. X    return status;
  332. X}
  333. X
  334. X/*
  335. X * Copy the next charcnt bytes of "in" (may be not a disk file)
  336. X * to a permanent file under a (possibly) temporary name.
  337. X * After the headers are seen, accept or reject the article.
  338. X * If rejected and the headers fit in core, no files will be opened.
  339. X * Must munge certain headers on the way & remember certain values.
  340. X * hdrmunge() or hdrdump() sets art->a_tmpf & art->a_artf.
  341. X * Unlink art->a_tmpf, if a temporary link.
  342. X */
  343. X/* ARGSUSED inname */
  344. XSTATIC void
  345. Xcopyart(art, in, inname)
  346. Xregister struct article *art;
  347. Xregister FILE *in;
  348. Xchar *inname;
  349. X{
  350. X    boolean installed = YES;
  351. X    char *body;
  352. X
  353. X    body = hdrcopy(art, in);
  354. X    hdrdeflt(&art->h);
  355. X    tossorfile(art, &installed);
  356. X    /* assertion: header values (art->h) can be forgotten here */
  357. X    cpybody(art, in, body);
  358. X    surveydamage(art, &installed);
  359. X}
  360. X
  361. X/*
  362. X * The loop copies header lines from input to output or a
  363. X * header output cache.  On exit, hdr will contain the first
  364. X * non-header line, if any, left over from the end of header copying.
  365. X *
  366. X * Some people think the loop is ugly; I'm not sure why.
  367. X * If the byte count is positive, read a line; if it doesn't return
  368. X * EOF and is a header, then adjust byte count, stash and munge headers.
  369. X * strlen(line) must be computed before hdrstash is called,
  370. X * as hdrstash (and thus hdrdigest) removes newlines.
  371. X */
  372. Xchar *                        /* first body line, from gethdr */
  373. Xhdrcopy(art, in)
  374. Xregister struct article *art;
  375. XFILE *in;
  376. X{
  377. X    register char *hdr = NULL;
  378. X    long limit;
  379. X    int is_hdr = NO;
  380. X
  381. X    hdrwretch();                /* reset the header parser */
  382. X    limit = (art->a_blvmax? art->a_unread+1: art->a_unread); /* 1 for NUL */
  383. X    /* 1 is again for NUL */
  384. X    while (limit > 1 && (hdr = gethdr(in, &limit, &is_hdr)) != NULL && is_hdr) {
  385. X            hdrdigest(art, hdr, strlen(hdr));
  386. X        hdr = NULL;            /* freed inside gethdr */
  387. X    }
  388. X    /* If we read a body line, gethdr has adjusted limit appropriately. */
  389. X    art->a_unread = limit - 1;        /* limit updated by gethdr */
  390. X    if (is_hdr)                /* no body: header fills limit */
  391. X        hdr = NULL;
  392. X    return hdr;
  393. X}
  394. X
  395. X/*
  396. X * Either reject the article described by art, or accept it and file it.
  397. X * If rejecting it, remove any links and give back assigned #'s
  398. X * (art->a_artf may still be open; arguably uninsart should close it).
  399. X * If accepting it, dump any saved headers and file the article.
  400. X * Unlink art->a_tmpf if it's a temporary link.
  401. X */
  402. Xvoid
  403. Xtossorfile(art, installedp)
  404. Xregister struct article *art;
  405. Xboolean *installedp;
  406. X{
  407. X    reject(art);                /* duplicate, etc.? */
  408. X    if (art->a_status&(ST_DROPPED|ST_REFUSED)) {
  409. X        uninsart(art);
  410. X        *installedp = NO;
  411. X    } else
  412. X        hdrdump(art, ALLHDRS);        /* ALLHDRS triggers fileart */
  413. X
  414. X    if (art->a_unlink) {
  415. X        /* a_tmpf has had links made to it, so it can be removed. */
  416. X        if (unlink(art->a_tmpf) < 0) {
  417. X            warning("copyart can't unlink `%s'", art->a_tmpf);
  418. X            art->a_status |= ST_ACCESS;
  419. X        }
  420. X        art->a_unlink = NO;        /* caution */
  421. X    }
  422. X}
  423. X
  424. X/*
  425. X * Copy article body.
  426. X * body will contain the first  non-header line, if any,
  427. X * left over from the end of header copying.  Write it.
  428. X * Copy at most COPYSIZE bytes of body at a time and exactly art->a_unread
  429. X * bytes in total, barring EOF or a full disk. Then "block" is no longer needed.
  430. X * Force the article to disk, mostly for the benefit of control message
  431. X * processing.
  432. X *
  433. X * The copying buffer, block, is static because it is used repeatedly
  434. X * and persists through most of execution, so dynamic allocation
  435. X * and deallocation seems wasteful, but also for the benefit
  436. X * of compilers for odd machines (e.g. PE, 370s) which make
  437. X * implementing "large" automatic arrays difficult.
  438. X */
  439. XSTATIC void
  440. Xcpybody(art, in, body)
  441. Xregister struct article *art;
  442. XFILE *in;
  443. Xregister char *body;
  444. X{
  445. X    register int readcnt;
  446. X    static char block[COPYSIZE];
  447. X
  448. X    if (body != NULL) {            /* read too far? */
  449. X        register int bodylen = strlen(body);
  450. X
  451. X        if (art->a_artf != NULL &&
  452. X            fwrite(body, 1, bodylen, art->a_artf) != bodylen)
  453. X            fulldisk(art, spoolnm(art));
  454. X        art->a_charswritten += bodylen;
  455. X    }
  456. X    for (; art->a_unread > 0 && !(art->a_status&ST_DISKFULL) &&
  457. X        (readcnt=fread(block, 1, (int)min(art->a_unread, COPYSIZE), in)) > 0;
  458. X        art->a_unread -= readcnt, art->a_charswritten += readcnt)
  459. X        if (art->a_artf != NULL &&
  460. X            fwrite(block, 1, readcnt, art->a_artf) != readcnt)
  461. X            fulldisk(art, spoolnm(art));
  462. X    if (art->a_artf != NULL && fflush(art->a_artf) == EOF)
  463. X        fulldisk(art, spoolnm(art));
  464. X}
  465. X
  466. X/*
  467. X * If not yet uninstalled, and the disk filled, uninstall this article
  468. X * to remove any zero-length links and decrement the active article number.
  469. X * The ST_DISKFULL status will prevent a history entry from being generated.
  470. X */
  471. Xvoid
  472. Xsurveydamage(art, installedp)
  473. Xregister struct article *art;
  474. Xregister boolean *installedp;
  475. X{
  476. X    if (art->a_unread > 0 && art->a_blvmax) {
  477. X        (void) fprintf(stderr, "%s: article %s short by %ld bytes\n",
  478. X            progname, (art->h.h_msgid != NULL? art->h.h_msgid: ""),
  479. X            (long)art->a_unread);
  480. X        art->a_status |= ST_SHORT;    /* NB.: don't uninstall this art. */
  481. X    }
  482. X    if (*installedp && art->a_status&ST_DISKFULL) {
  483. X        uninsart(art);
  484. X        *installedp = NO;
  485. X    }
  486. X#ifdef WATCHCORE
  487. X    {
  488. X        char stbot;
  489. X        extern char *sbrk();
  490. X
  491. X        printf("debugging memory use: top of data=%u", (unsigned)sbrk(0));
  492. X        printf(", bottom of stack=%u\n", (unsigned)&stbot);
  493. X    }
  494. X#endif
  495. X}
  496. X
  497. X/*
  498. X * Install the article on art->a_tmpf or art->a_files:
  499. X * The article should have been accepted and filed in copyart().
  500. X * Add history entries for the article.  Log arrival.
  501. X * Transmit the article to our neighbours.
  502. X * Process control mess(age)es.  ctlmsg can call transmit(fakeart,x)
  503. X * and generate log lines for cancels and ihave/sendme.
  504. X */
  505. XSTATIC void
  506. Xinsart(art)
  507. Xregister struct article *art;
  508. X{
  509. X    if (!(art->a_status&(ST_DROPPED|ST_REFUSED|ST_DISKFULL))) {
  510. X        if (!art->a_filed)            /* paranoia */
  511. X            (void) fprintf(stderr, "%s: %s not filed by copyart!\n",
  512. X                progname, art->h.h_msgid);
  513. X        history(art, STARTLOG);
  514. X        transmit(art, exclude);        /* writes systems on stdout */
  515. X        (void) putchar('\n');        /* ends the log line */
  516. X        if (art->h.h_ctlcmd != NULL)
  517. X            ctlmsg(art);
  518. X#ifdef notdef                    /* it's only a log file! */
  519. X        (void) fflush(stdout);        /* crash-proofness */
  520. X#endif
  521. X    }
  522. X    art->a_status &= ~ST_REFUSED;    /* refusal is quite casual & common */
  523. X}
  524. X
  525. X/*
  526. X * Reject articles.  This can be arbitrarily picky.
  527. X * Only the headers are used to decide, so this can be called before
  528. X * the article is filed.
  529. X * Be sure to put the fastest tests first, especially if they often result
  530. X * in rejections.
  531. X */
  532. Xvoid
  533. Xreject(art)
  534. Xregister struct article *art;
  535. X{
  536. X    if (art->h.h_path == NULL) {
  537. X        prefuse(art);
  538. X        (void) printf("no Path: header\n");
  539. X    } else if (alreadyseen(art->h.h_msgid)) {
  540. X        prefuse(art);
  541. X        (void) printf("duplicate\n");
  542. X    } else if (art->h.h_path != NULL && hopcount(art->h.h_path) > 0 &&
  543. X        !ngmatch(oursys()->sy_ngs, art->h.h_ngs)) {
  544. X        extern boolean histreject;
  545. X
  546. X        /*
  547. X         * non-local article, with all bad groups.
  548. X         * (local articles with bad groups will be bounced
  549. X         * by fileart when the groups aren't in active.)
  550. X         */
  551. X        if (histreject)
  552. X            history(art, NOLOG);
  553. X        prefuse(art);
  554. X        (void) printf("no subscribed groups in `%s'\n", art->h.h_ngs);
  555. X    } else if (art->h.h_approved == NULL && moderated(art->h.h_ngs)) {
  556. X        prefuse(art);
  557. X        (void) printf("unapproved article in moderated group(s) `%s'\n",
  558. X            art->h.h_ngs);
  559. X    } else
  560. X        return;            /* art was accepted */
  561. X    art->a_status |= ST_REFUSED;
  562. X    if (!okrefusal)
  563. X        art->a_status |= ST_DROPPED;
  564. X}
  565. X
  566. X/*
  567. X * print the leader of a refusal message about the article in "art".
  568. X */
  569. Xvoid
  570. Xprefuse(art)
  571. Xregister struct article *art;
  572. X{
  573. X    timestamp(stdout, (time_t *)NULL);
  574. X    (void) printf(" %s - %s ", sendersite(nullify(art->h.h_path)),
  575. X        art->h.h_msgid);
  576. X}
  577. X
  578. X/*
  579. X * "Uninstall" an article: remove art->a_files (permanent names) and
  580. X * a_tmpf (temporary name if a_unlink set), and return assigned article #'s.
  581. X * If a_unlink isn't set, a_tmpf is a copy of the first link in art->a_files.
  582. X * Must be called before history() is called, else there will be a
  583. X * history entry for the article, but no spool files.
  584. X */
  585. Xvoid
  586. Xuninsart(art)
  587. Xregister struct article *art;
  588. X{
  589. X    if (art->a_unlink && art->a_tmpf != NULL) {
  590. X        (void) unlink(art->a_tmpf);    /* I don't wanna know... */
  591. X        art->a_unlink = NO;
  592. X    }
  593. X    /* return article numbers (YES) & ignore unlink errors */
  594. X    (void) snuffmayreturn(art->a_files, YES);
  595. X}
  596. X
  597. Xstatust
  598. Xsnufffiles(filelist)        /* just unlink all files in filelist */
  599. Xchar *filelist;
  600. X{
  601. X    /* don't return article numbers (NO) & return unlink errors */
  602. X    return snuffmayreturn(filelist, NO);
  603. X}
  604. X
  605. X/*
  606. X * Unlink all files in filelist, and optionally return article numbers.
  607. X * When removing a link, note any failure, but don't issue an error message.
  608. X * For one thing, cancel controls fail routinely because the article has been
  609. X * removed manually or never existed (a previous cancel arrived before its
  610. X * subject and generated a fake history entry).
  611. X */
  612. XSTATIC statust
  613. Xsnuffmayreturn(filelist, artret)
  614. Xchar *filelist;
  615. Xboolean artret;        /* return article numbers & note unlink errors? */
  616. X{
  617. X    register statust status = ST_OKAY;
  618. X    register char *arts, *spacep, *slashp, *artnm;
  619. X
  620. X    /* this is a deadly tedious job and I really should automate it */
  621. X    for (arts = filelist; arts != NULL && arts[0] != '\0';
  622. X         arts = (spacep == NULL? NULL: spacep+1)) {
  623. X        spacep = index(arts, ' ');
  624. X        if (spacep != NULL)
  625. X            spacep[0] = '\0';    /* will be restored below */
  626. X        artnm = strsave(arts);
  627. X        if (spacep != NULL)
  628. X            spacep[0] = ' ';    /* restore space */
  629. X
  630. X        slashp = index(artnm, FNDELIM);
  631. X        if (slashp != NULL)
  632. X            slashp[0] = '\0';    /* will be restored below */
  633. X        if (artret)
  634. X            /* prevartnum will complain on i/o error to active */
  635. X            (void) prevartnum(artnm); /* return assigned # */
  636. X        if (slashp != NULL)
  637. X            slashp[0] = FNDELIM;    /* restore slash */
  638. X
  639. X        mkfilenm(artnm);
  640. X        if (unlink(artnm) < 0)
  641. X            status |= ST_ACCESS;
  642. X        free(artnm);
  643. X    }
  644. X    return status;
  645. X}
  646. !
  647. echo 'relay/relaynews.c':
  648. sed 's/^X//' >'relay/relaynews.c' <<'!'
  649. X/*
  650. X * relaynews - relay Usenet news (version C)
  651. X * See the file COPYRIGHT for the copyright notice.
  652. X *
  653. X * relaynews should be setuid-news, setgid-news.  You'll need to install
  654. X * setnewsids setuid-root if setuid(geteuid()) doesn't work on your
  655. X * machine (e.g. on V7 and possibly SystemIII).
  656. X *
  657. X * Written by Geoff Collyer, 15-20 November 1985 and revised periodically
  658. X * since.
  659. X *
  660. X * relaynews parses article headers, rejects articles by newsgroup &
  661. X * message-id, files articles, updates the active & history files,
  662. X * transmits articles, and honours (infrequent) control messages, which do
  663. X * all sorts of varied and rococo things.  Control messages are implemented
  664. X * by separate programs.  relaynews reads a "sys" file to control the
  665. X * transmission of articles but can function as a promiscuous leaf node
  666. X * without one.  See ARPA Internet RFC 1036 nee 850 for the whole story.
  667. X *
  668. X * A truly radical notion: people may over-ride via environment variables
  669. X * the compiled-in default directories so IHCC kludges are not needed and
  670. X * testing is possible (and encouraged) in alternate directories.  This
  671. X * does cause a loss of privilege, to avoid spoofing.
  672. X *
  673. X * The disused old unbatched ihave/sendme protocol is gone because it was
  674. X * too wasteful; use the batched form instead (see the ihave sys flag
  675. X * ("I") instead).
  676. X *
  677. X * Portability vs SystemV.  relaynews uses dbm(3) and makes no apologies
  678. X * for so doing.  Imitation UNIX (registered trademark of AT&T in the
  679. X * United States) brand operating systems that lack dbm are going to
  680. X * have to use my incredibly slow dbm simulation, or another.
  681. X */
  682. X
  683. X#include <stdio.h>
  684. X#include <ctype.h>
  685. X#include <signal.h>        /* to make locking safe */
  686. X#include <sys/types.h>
  687. X
  688. X#include "libc.h"
  689. X#include "news.h"
  690. X#include "config.h"
  691. X#include "fgetmfs.h"
  692. X#include "active.h"
  693. X#include "caches.h"
  694. X#include "cpu.h"
  695. X#include "fileart.h"
  696. X#include "headers.h"
  697. X#include "history.h"
  698. X#include "transmit.h"
  699. X
  700. X/*
  701. X * setuid-root program to set ids to news/news & rexec rnews with
  702. X * NEWSPERMS in the environment to break loops.
  703. X */
  704. X#ifndef SETNEWSIDS
  705. X#define SETNEWSIDS "setnewsids"
  706. X#endif
  707. X
  708. X/* exports */
  709. Xchar *progname;
  710. Xboolean okrefusal = YES;            /* okay to refuse articles? */
  711. Xchar *exclude = NULL;                /* site to exclude, for erik */
  712. Xboolean histreject = NO;            /* keep history of rejects? */
  713. X
  714. X/* internal */
  715. Xstatic boolean userealids = NO;
  716. X
  717. X/* imports */
  718. Xextern int optind;            /* set by getopt */
  719. Xextern char *optarg;
  720. Xextern statust cpinsart();        /* from procart.c */
  721. X
  722. X/* forwards */
  723. Xextern void prelude(), setids(), procopts(), redirectlogs(), logfile();
  724. Xextern void getwdandcd();
  725. Xextern statust procargs(), relnmprocess(), process(), unbatch();
  726. Xextern boolean batchln();
  727. XFORWARD boolean debugon();
  728. X
  729. X/*
  730. X * main - take setuid precautions, switch to "news" ids, ignore signals,
  731. X * handle options, lock news system, process files & unlock news system.
  732. X */
  733. Xint
  734. Xmain(argc, argv)
  735. Xint argc;
  736. Xchar *argv[];
  737. X{
  738. X    statust status = ST_OKAY;
  739. X    int redirlogs = 0;        /* redirect n std output streams to logs */
  740. X    char *origdir = NULL;        /* current directory at start */
  741. X
  742. X    progname = argv[0];
  743. X#ifdef CSRIMALLOC
  744. X    mal_debug(0);    /* was 2; 3 is too slow */
  745. X    mal_leaktrace(0);    /* was 1 */
  746. X#endif
  747. X    prelude(argv);        /* various precautions; switch to "news" */
  748. X
  749. X    /* ignore signals (for locking). relaynews runs quickly, so don't worry. */
  750. X    (void) signal(SIGINT, (sigarg_t)SIG_IGN);
  751. X    (void) signal(SIGQUIT, (sigarg_t)SIG_IGN);
  752. X    (void) signal(SIGHUP, (sigarg_t)SIG_IGN);
  753. X    (void) signal(SIGTERM, (sigarg_t)SIG_IGN);
  754. X
  755. X    procopts(argc, argv, &redirlogs, &okrefusal);
  756. X
  757. X    newslock();            /* done here due to dbm internal cacheing */
  758. X    if (redirlogs > 0) {
  759. X        redirectlogs(redirlogs); /* redirect std output streams to logs */
  760. X#ifdef MANYERRORS
  761. X        (void) putc('\n', stderr);    /* leave a blank line */
  762. X        /* prints "Jun  5 12:34:56" */
  763. X        timestamp(stderr, (time_t *)NULL);
  764. X        (void) putc('\n', stderr);
  765. X#endif
  766. X    }
  767. X
  768. X    getwdandcd(argc, argv, &origdir);
  769. X    status |= procargs(argc, argv, &origdir);
  770. X
  771. X    status |= synccaches();        /* being cautious: write & close caches */
  772. X    (void) fflush(stdout);        /* log file */
  773. X    (void) fflush(stderr);        /* errlog file */
  774. X
  775. X#ifdef notdef
  776. X#ifdef CSRIMALLOC
  777. X    mal_dumpleaktrace(fileno(stderr));
  778. X#endif
  779. X#endif
  780. X    newsunlock();
  781. X    exit(status);
  782. X    /* NOTREACHED */
  783. X}
  784. X
  785. X/*
  786. X * reset various environmental things for safety: umask, alarm,
  787. X * environment variables (PATH, IFS), standard file descriptors,
  788. X * user & group ids.
  789. X */
  790. Xvoid
  791. Xprelude(argv)                /* setuid daemon prelude */
  792. Xchar **argv;
  793. X{
  794. X    register char *newpath;
  795. X
  796. X    (void) umask(2);        /* undo silly umasks, ignore newsumask() */
  797. X    (void) alarm(0);        /* cancel any pending alarm */
  798. X    newpath = malloc(STRLEN("PATH=") + strlen(newspath()) + 1);
  799. X    if (newpath == NULL)
  800. X        exit(1);        /* no chatter until stdfdopen */
  801. X    (void) strcpy(newpath, "PATH=");
  802. X    (void) strcat(newpath, newspath());
  803. X    if (putenv(newpath) ||
  804. X        putenv("IFS= \t\n"))
  805. X        exit(1);        /* no chatter until stdfdopen */
  806. X    closeall(1);            /* closes all but std descriptors */
  807. X    stdfdopen();            /* ensure standard descriptors are open */
  808. X    setids(argv);            /* change of real and effective ids */
  809. X}
  810. X
  811. X/*
  812. X * change real and effective ids to real ids if unprivileged() is called,
  813. X * else to effective ("news") ids.  ctlfile((char *)0) will trigger a call
  814. X * to unprivileged() if any environment variables override the default
  815. X * path names.  unprivileged() in turn sets userealids.
  816. X *
  817. X * If setuid(geteuid()) fails, try execing a small, setuid-root program
  818. X * to just do "getpwnam(), getgrnam() (with NEWSPERMS set), setgid(),
  819. X * setuid()," and exec this program again.  If NEWSPERMS is set,
  820. X * the failure is a fatal error (recursive loop).
  821. X * This program (relaynews) can be setuid-news.
  822. X *
  823. X * The peculiar tests for failure (getuid() != newsuid) are to work
  824. X * around a Xenix bug which returns 0 from setuid() upon failure.
  825. X */
  826. Xvoid
  827. Xsetids(argv)
  828. Xchar **argv;
  829. X{
  830. X    int newsuid, newsgid;
  831. X
  832. X    (void) ctlfile((char *)NULL);
  833. X    if (userealids)
  834. X        newsuid = getuid(), newsgid = getgid();
  835. X    else
  836. X        newsuid = geteuid(), newsgid = getegid();
  837. X    if (setgid(newsgid) < 0 || setuid(newsuid) < 0 ||
  838. X        getgid() != newsgid || getuid() != newsuid) {
  839. X        if (getenv("NEWSPERMS") != 0)
  840. X            error("recursive loop setting ids", "");
  841. X        execv(ctlfile(SETNEWSIDS), argv);
  842. X        error("can't exec `%s' to set ids", ctlfile(SETNEWSIDS));
  843. X        /* NOTREACHED */
  844. X    }
  845. X    /* we are now running as news, so you can all relax */
  846. X}
  847. X
  848. X/*
  849. X * parse options and set flags
  850. X */
  851. Xvoid
  852. Xprocopts(argc, argv, redirlogsp, okrefusalp)
  853. Xint argc;
  854. Xchar **argv;
  855. Xint *redirlogsp;
  856. Xboolean *okrefusalp;
  857. X{
  858. X    int c, errflg = 0;
  859. X
  860. X    while ((c = getopt(argc, argv, "d:inrsx:")) != EOF)
  861. X        switch (c) {
  862. X        case 'd':        /* -d debug-options; thanks, henry */
  863. X            if (!debugon(optarg))
  864. X                errflg++;    /* debugon has complained */
  865. X            break;
  866. X        case 'i':        /* redirect stdout to log (inews) */
  867. X            *redirlogsp = 1; /* just stdout */
  868. X            break;
  869. X        case 'n':        /* nntp mode: keep history of rejects */
  870. X            histreject = YES;
  871. X            break;
  872. X        case 'r':        /* redirect std. ostreams to logs (rnews) */
  873. X            *redirlogsp = 2; /* stdout & stderr */
  874. X            break;
  875. X        case 's':        /* dropping input is serious (inews) */
  876. X            *okrefusalp = NO;
  877. X            break;
  878. X        case 'x':        /* -x site: don't send to site */
  879. X            /* you're welcome, erik */
  880. X            /* erik says he only needs one -x per inews */
  881. X            if (exclude != NULL) {
  882. X                (void) fprintf(stderr,
  883. X                    "%s: more than one -x site (%s)\n",
  884. X                    progname, optarg);
  885. X                errflg++;
  886. X            } else
  887. X                exclude = optarg;
  888. X            break;
  889. X        default:
  890. X            errflg++;
  891. X            break;
  892. X        }
  893. X    if (errflg) {
  894. X        (void) fprintf(stderr, "usage: %s [-inrs][-d fhlmt][-x site]\n",
  895. X            progname);
  896. X        exit(2);
  897. X    }
  898. X}
  899. X
  900. Xvoid
  901. Xunprivileged()        /* called if NEWSARTS, NEWSCTL or NEWSBIN present */
  902. X{
  903. X    userealids = YES;
  904. X}
  905. X
  906. XSTATIC boolean
  907. Xdebugon(dbopt)
  908. Xregister char *dbopt;
  909. X{
  910. X    statust status = YES;
  911. X
  912. X    for (; *dbopt != '\0'; dbopt++)
  913. X        switch (*dbopt) {
  914. X        case 'f':
  915. X            filedebug(YES);
  916. X            break;
  917. X        case 'h':
  918. X            hdrdebug(YES);
  919. X            break;
  920. X        case 'l':
  921. X            lockdebug(YES);
  922. X            break;
  923. X        case 'm':
  924. X            matchdebug(YES);
  925. X            break;
  926. X        case 't':
  927. X            transdebug(YES);
  928. X            break;
  929. X        default:
  930. X            status = NO;    /* unknown debugging option */
  931. X            (void) fprintf(stderr, "%s: bad -d %c\n",
  932. X                progname, *dbopt);
  933. X            break;
  934. X        }
  935. X    return status;
  936. X}
  937. X
  938. X/*
  939. X * Redirect stdout or stderr into log files at known locations.
  940. X */
  941. Xvoid
  942. Xredirectlogs(count)
  943. Xint count;
  944. X{
  945. X    if (count > 0)
  946. X        logfile(stdout, ctlfile("log"));
  947. X    if (count > 1)
  948. X        logfile(stderr, ctlfile("errlog"));
  949. X}
  950. X
  951. Xvoid
  952. Xlogfile(stream, name)            /* redirect stream into name */
  953. XFILE *stream;
  954. Xchar *name;
  955. X{
  956. X    if (freopen(name, "a", stream) == NULL)
  957. X        errunlock("can't redirect standard stream to `%s'", name);
  958. X}
  959. X
  960. X/*
  961. X * if argv contains relative file name arguments, save current directory name
  962. X * in malloced memory, through origdirp.
  963. X * then change directory to the spool directory ($NEWSARTS).
  964. X */
  965. Xvoid
  966. Xgetwdandcd(argc, argv, origdirp)
  967. Xint argc;
  968. Xchar **argv;
  969. Xchar **origdirp;
  970. X{
  971. X    register int argind;
  972. X    boolean needpwd = NO;
  973. X    char dirtmp[MAXPATH];            /* much bigger than needed */
  974. X
  975. X    for (argind = optind; argind < argc; argind++)
  976. X        if (argv[argind][0] != FNDELIM)
  977. X            needpwd = YES;
  978. X
  979. X    *origdirp = "/???";            /* pessimism */
  980. X    if (needpwd && getcwd(dirtmp, sizeof dirtmp) != 0)
  981. X        *origdirp = dirtmp;
  982. X    *origdirp = strsave(*origdirp);        /* save a smaller copy */
  983. X    cd(fullartfile((char *)NULL));        /* move to spool directory */
  984. X}
  985. X
  986. X/*
  987. X * process files named as arguments (or implied)
  988. X */
  989. Xstatust
  990. Xprocargs(argc, argv, origdirp)
  991. Xint argc;
  992. Xchar **argv;
  993. Xchar **origdirp;
  994. X{
  995. X    register statust status = ST_OKAY;
  996. X
  997. X    if (optind == argc)
  998. X        status |= process(stdin, "stdin");
  999. X    else
  1000. X        for (; optind < argc; optind++)
  1001. X            status |= relnmprocess(argv[optind], *origdirp);
  1002. X    nnfree(origdirp);
  1003. X    return status;
  1004. X}
  1005. X
  1006. Xstatust
  1007. Xrelnmprocess(name, origdir)        /* process a (relative) file name */
  1008. Xchar *name, *origdir;
  1009. X{
  1010. X    register statust status = ST_OKAY;
  1011. X    register FILE *in;
  1012. X    register char *fullname;
  1013. X
  1014. X    fullname = nemalloc((unsigned)strlen(origdir) + STRLEN(SFNDELIM) +
  1015. X        strlen(name) + 1);
  1016. X    fullname[0] = '\0';
  1017. X
  1018. X    if (name[0] != FNDELIM) {    /* relative path */
  1019. X        (void) strcat(fullname, origdir);
  1020. X        (void) strcat(fullname, SFNDELIM);
  1021. X    }
  1022. X    (void) strcat(fullname, name);
  1023. X
  1024. X    in = fopenwclex(fullname, "r");
  1025. X    if (in != NULL) {
  1026. X        status |= process(in, fullname);
  1027. X        (void) nfclose(in);
  1028. X    }
  1029. X    free(fullname);
  1030. X    return status;
  1031. X}
  1032. X
  1033. X/*
  1034. X * process - process input file
  1035. X * If it starts with '#', assume it's a batch and unravel it,
  1036. X * else it's a single article, so just inject it.
  1037. X */
  1038. Xstatust
  1039. Xprocess(in, inname)
  1040. XFILE *in;
  1041. Xchar *inname;
  1042. X{
  1043. X    register int c;
  1044. X
  1045. X    if ((c = getc(in)) == EOF)
  1046. X        return ST_OKAY;         /* normal EOF */
  1047. X    (void) ungetc(c, in);
  1048. X    if (c == '#')
  1049. X        return unbatch(in, inname);
  1050. X    else
  1051. X        return cpinsart(in, inname, MAXLONG, NO);
  1052. X}
  1053. X
  1054. X/*
  1055. X * Unwind "in" and insert each article.
  1056. X * For each article, call cpinsart to copy the article from "in" into
  1057. X * a (temporary) file in the news spool directory and rename the temp file
  1058. X * to the correct final name if it isn't right already.
  1059. X *
  1060. X * If the unbatcher gets out of sync with the input batch, the unbatcher
  1061. X * will print and discard each input line until it gets back in sync.
  1062. X */
  1063. Xstatust
  1064. Xunbatch(in, inname)
  1065. Xregister FILE *in;
  1066. Xchar *inname;
  1067. X{
  1068. X    register int c;
  1069. X    /* register */ char *line;
  1070. X    register statust status = ST_OKAY;
  1071. X    long charcnt;
  1072. X
  1073. X    while (!(status&ST_DISKFULL) && (c = getc(in)) != EOF) {
  1074. X        (void) ungetc(c, in);
  1075. X        while ((line = fgetms(in)) != NULL &&
  1076. X            !batchln(line, &charcnt)) {        /* returns charcnt */
  1077. X            status |= ST_DROPPED;
  1078. X            (void) fprintf(stderr,
  1079. X                "%s: unbatcher out of synch, tossing: ",
  1080. X                progname);
  1081. X                (void) fputs(line, stderr);
  1082. X            free(line);
  1083. X        }
  1084. X        nnfree(&line);            /* free "#! rnews n" */
  1085. X        if (!feof(in))
  1086. X            status |= cpinsart(in, inname, charcnt, YES);
  1087. X    }
  1088. X    if (ferror(in))
  1089. X        errunlock("error reading `%s'", inname);
  1090. X    return status;
  1091. X}
  1092. X
  1093. X/*
  1094. X * Is line a batcher-produced line (#! rnews count)?
  1095. X * If so, return the count through charcntp.
  1096. X * This is slightly less convenient than sscanf, but a lot smaller.
  1097. X */
  1098. Xboolean
  1099. Xbatchln(line, charcntp)
  1100. Xregister char *line;
  1101. Xregister long *charcntp;
  1102. X{
  1103. X    register char *countp;
  1104. X    static char batchtext[] = "#! rnews ";
  1105. X
  1106. X    countp = line + STRLEN(batchtext);
  1107. X    if (STREQN(line, batchtext, STRLEN(batchtext)) &&
  1108. X        isascii(*countp) && isdigit(*countp)) {
  1109. X        *charcntp = atol(countp);
  1110. X        return YES;
  1111. X    } else {
  1112. X        *charcntp = 0;
  1113. X        return NO;
  1114. X    }
  1115. X}
  1116. !
  1117. echo 'relay/sh/anne.jones':
  1118. sed 's/^X//' >'relay/sh/anne.jones' <<'!'
  1119. X#! /bin/sh
  1120. X# anne.jones [file...] - censor headers: munge locally-generated headers in
  1121. X#  files, enforce feeble attempts at Usenet security, generate lots of silly
  1122. X#  headers.
  1123. X# (after the notorious ring-leader of the Ontario Film and Video Review Board
  1124. X# (nee Ontario Board of Censors), Ontario's very own Mrs. Mary Whitehouse.)
  1125. X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
  1126. X. ${NEWSCONFIG-/usr/lib/news/bin/config}
  1127. Xexport NEWSCTL NEWSBIN NEWSARTS
  1128. XPATH=$NEWSCTL/bin:$NEWSBIN/inject:$NEWSBIN:$NEWSPATH ; export PATH
  1129. Xumask $NEWSUMASK
  1130. X
  1131. X# pass 0 - dredge up defaults
  1132. Xcase "$trversion" in
  1133. Xv[67])    ;;
  1134. X*)    echo "$0: trversion is nonsense or missing from environment" >&2
  1135. X    exit 1 ;;
  1136. Xesac
  1137. Xif test -r $NEWSCTL/mailname; then
  1138. X    mailname="`tr -d ' \11' <$NEWSCTL/mailname`"
  1139. Xelse
  1140. X    mailname="`newshostname`"
  1141. X    case "$mailname" in
  1142. X    *.*)    ;;            # not a uucp host name
  1143. X    *)    mailname="$mailname.uucp" ;;    # probably a uucp host name
  1144. X    esac
  1145. Xfi
  1146. X# badsites="pucc.bitnet!"        # tailor, syntax is "host1!host2!...host3!"
  1147. Xhost="$mailname"
  1148. X
  1149. X# dig up user's name (a simple task, you'd think, but you'd be wrong)
  1150. Xcase "$LOGNAME" in
  1151. X"")
  1152. X    # "who am i" on many Unixes does "ttyname(0)" and "getpwuid(getuid())"
  1153. X    # if that fails - it can be confused by empty utmp entries (per jerqs);
  1154. X    # "who am i </dev/null" yields your userid, not your login name.
  1155. X    # "tty" does "ttyname(0)"; also fallible.
  1156. X    # So, emulate a slightly-modified V7 getlogin(3) (actually ttyslot(3)):
  1157. X    # look for tty on /dev/tty, stdin, stdout, stderr (actually via ttyname(3)).
  1158. X    for fd in 3 0 1 2            # 3 is /dev/tty on V8
  1159. X    do
  1160. X        if test -t $fd; then
  1161. X            case "$USER" in
  1162. X            "")    USER="`who am i <&$fd |
  1163. X                    sed -e 's/[     ].*//' -e '/!/s/^.*!//' `" ;;
  1164. X            esac
  1165. X        fi
  1166. X    done
  1167. X    case "$USER" in
  1168. X    "")    USER="`who am i </dev/null |    # last resort: use userid
  1169. X            sed -e 's/[     ].*//' -e '/!/s/^.*!//' `" ;;
  1170. X    esac
  1171. X    ;;
  1172. X*)    USER="$LOGNAME" ;;
  1173. Xesac
  1174. Xcase "$NAME" in
  1175. X"")
  1176. X    if test -s $HOME/.name; then
  1177. X        NAME=`cat $HOME/.name`
  1178. X    else
  1179. X        NAME=`(grep "^$USER:" /etc/passwd || ypmatch "$USER" passwd) |
  1180. X            sed 's/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:]*\).*$/\1/'  `
  1181. X        # tailor: for BTL RJE format, add
  1182. X        #    | sed -e 's/^[^-]*- *//' -e 's/ *(.*$//'
  1183. X        # otherwise for Berkeley format, use this
  1184. X        # (courtesy Rayan Zachariassen):
  1185. X        case "$NAME" in
  1186. X        *'&'*)
  1187. X            # generate Capitalised login name
  1188. X            NM=`echo "$USER" | sed -e 's/^\(.\)\(.*\)/\1:\2/'`
  1189. X            NM1=`expr "$NM" : '\(.\):.*' |
  1190. X                case "$trversion" in
  1191. X                v7)    tr a-z A-Z ;;
  1192. X                v6)    tr '[a-z]' '[A-Z]' ;;
  1193. X                esac
  1194. X                `
  1195. X            NMR=`expr "$NM" : '.:\(.*\)'`
  1196. X            CAPNM="$NM1$NMR"
  1197. X            # turn & into Capitalised login name
  1198. X            NAME=`echo "$NAME" | sed "s:&:$CAPNM:"`
  1199. X            ;;
  1200. X        esac
  1201. X    fi
  1202. X    ;;
  1203. Xesac
  1204. Xcase "$NAME" in
  1205. X"")    fullname="" ;;        # no full name, leave it off
  1206. X*)    fullname=" ($NAME)" ;;
  1207. Xesac
  1208. Xreallyfrom="$USER@$host$fullname"
  1209. XFROM="$reallyfrom"
  1210. X
  1211. X# generate a few defaults.
  1212. X# RFC 1036 requests a GMT Date:, despite it being hard to read.
  1213. X# Compensate for V6 Uglix date (no -u) tarted up with all that TZ goo.
  1214. Xdate="`
  1215. X    set ''\`TZ=GMT0 date\`    # give TZ to see if (Uglix) date responds
  1216. X    case \"$5\" in
  1217. X    GMT)    echo $* ;;    # Uglix date or V7 date with GMT local time
  1218. X    *)    date -u ;;    # must be V7 date command, it ignored TZ
  1219. X    esac
  1220. X`"                # for defdate, defmsgid
  1221. Xcase "$ORGANIZATION" in
  1222. X"")    deforg="`sed 1q $NEWSCTL/organi[sz]ation`" ;;    # look in a file
  1223. X*)    deforg="$ORGANIZATION" ;;    # look in environment
  1224. Xesac
  1225. X
  1226. X# give defaults and headers to awk
  1227. Xcat $* |
  1228. X    # strip invisible chars, a la B news; turn tabs to spaces (RFC1036)
  1229. X    case "$trversion" in
  1230. X    v7)    tr -d '\1-\7\13\14\16-\37';;
  1231. X    v6)    tr -d '[\1-\7]\13\14[\16-\37]' ;;
  1232. X    esac |
  1233. X    sed 's/:    /: /' |
  1234. X    awk -f $NEWSBIN/inject/defhdrs.awk \
  1235. Xdefpath="$badsites$USER" \
  1236. Xdeffrom="$FROM" deforg="$deforg" \
  1237. Xdefdate="` set $date; echo $1, $3 $2 \` echo $6 | sed 's/^..//' \` $4 $5`" \
  1238. Xdefmsgid="`set $date; echo \<$6$2$3.\`  echo $4 | tr -d : \`.$$@$host\>`" -
  1239. !
  1240. echo 'relay/sh/ctlrun':
  1241. sed 's/^X//' >'relay/sh/ctlrun' <<'!'
  1242. X#! /bin/sh
  1243. X# ctlrun - run the control messages in control again
  1244. X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
  1245. X. ${NEWSCONFIG-/usr/lib/news/bin/config}
  1246. X# export NEWSCTL NEWSBIN NEWSARTS
  1247. XPATH=$NEWSCTL/bin:$NEWSBIN/ctl:$NEWSBIN:$NEWSPATH ; export PATH
  1248. Xumask $NEWSUMASK
  1249. X
  1250. Xcd $NEWSCTL
  1251. Xnewslock sys LOCK || exit 1    # lock
  1252. X
  1253. Xcd $NEWSARTS/control
  1254. X
  1255. Xfor file in *
  1256. Xdo
  1257. X    grep '^Control:' $file |
  1258. X        sed 's;^Control:[     ]*;'$NEWSBIN/ctl/';' |
  1259. X        grep -v '/cancel ' >/tmp/ctl$$    # cancel needs dbm(3)
  1260. X    sh -x /tmp/ctl$$ <$file
  1261. Xdone
  1262. X
  1263. Xrm -f /tmp/ctl$$    
  1264. Xrm -f LOCK
  1265. !
  1266. echo 'relay/sh/defhdrs.awk':
  1267. sed 's/^X//' >'relay/sh/defhdrs.awk' <<'!'
  1268. X# defhdrs.awk
  1269. X# pass 1 - note presence | absence of certain headers
  1270. X# a header keyword: remember it and its value
  1271. X/^[^\t ]*:/ {
  1272. X    hdrval[$1] = $0
  1273. X    keyword=$1
  1274. X    next
  1275. X}
  1276. X# a continuation: concatenate this line to the value
  1277. X    { hdrval[keyword] = hdrval[keyword] "\n" $0 }
  1278. X
  1279. XEND {
  1280. X    # pass 2 - cogitate & omit & emit headers
  1281. X    emptyhdrre = "^[^\t ]*:[\t ]*$"
  1282. X    subjname = "Subject:"
  1283. X    ctlname = "Control:"
  1284. X    ngname = "Newsgroups:"
  1285. X    msgidname = "Message-ID:"
  1286. X    typoname =  "Message-Id:"
  1287. X    pathname = "Path:"
  1288. X    datename = "Date:"
  1289. X    fromname = "From:"
  1290. X    orgname = "Organization:"
  1291. X    distrname = "Distribution:"
  1292. X    sendername = "Sender:"
  1293. X
  1294. X    # fill in missing headers
  1295. X    if (hdrval[typoname] != "") {    # spelling hack
  1296. X        hdrval[msgidname] = hdrval[typoname]
  1297. X        hdrval[typoname] = ""
  1298. X        # fix spelling: Message-Id: -> Message-ID:
  1299. X        nf = split(hdrval[msgidname], fields);    # bust up
  1300. X        fields[1] = msgidname;        # fix spelling
  1301. X        hdrval[msgidname] = fields[1];    # reassemble...
  1302. X        for (i = 2; i <= nf; i++)
  1303. X            hdrval[msgidname] = hdrval[msgidname] " " fields[i]
  1304. X    }
  1305. X    if (hdrval[msgidname] == "")
  1306. X        hdrval[msgidname] = msgidname " " defmsgid
  1307. X    if (hdrval[orgname] == "")
  1308. X        hdrval[orgname] = orgname " " deforg
  1309. X
  1310. X    # replace users headers (if any)
  1311. X    hdrval[datename] = datename " " defdate
  1312. X    hdrval[pathname] = pathname " " defpath
  1313. X    if (hdrval[fromname] == "")
  1314. X        hdrval[fromname] = fromname " " deffrom
  1315. X    else if (hdrval[sendername] == "")
  1316. X        hdrval[sendername] = sendername " " deffrom
  1317. X
  1318. X    # snuff some headers
  1319. X    distworld = distrname " world"
  1320. X    if (hdrval[distrname] == distworld)
  1321. X        hdrval[distrname] = ""
  1322. X
  1323. X    # the vile cmsg hack, for the sake of the news readers *only*
  1324. X    if (hdrval[ctlname] == "" && \
  1325. X        substr(hdrval[subjname], 1, 14) == "Subject: cmsg ")
  1326. X        hdrval[ctlname] = ctlname " " substr(hdrval[subjname], 15)
  1327. X
  1328. X    # warn if no Newsgroups:
  1329. X    if (hdrval[ngname] == "")
  1330. X        print "no newsgroups header!" | "cat >&2"
  1331. X
  1332. X    # field the all.all.ctl hack, for the sake of the backward only:
  1333. X    # clone Subject: to make Control:
  1334. X    if (hdrval[ctlname] == "" && hdrval[ngname] ~ /\.ctl(,|$)/)
  1335. X        hdrval[ctlname] = ctlname " " substr(hdrval[subjname], 8)
  1336. X
  1337. X    # reorder & emit headers
  1338. X
  1339. X    # favour Control: & Newsgroups: for future benefit of rnews
  1340. X    if (hdrval[ctlname] != "") {
  1341. X        print hdrval[ctlname]
  1342. X        hdrval[ctlname] = ""    # no Control: to print now
  1343. X    }
  1344. X    if (hdrval[ngname] != "") {
  1345. X        print hdrval[ngname]
  1346. X        hdrval[ngname] = ""    # no Newsgroups: to print now
  1347. X    }
  1348. X
  1349. X    # B inews kludgery: print Path: before From: to avoid confusing it
  1350. X    if (hdrval[pathname] != "") {
  1351. X        print hdrval[pathname]
  1352. X        hdrval[pathname] = ""    # no Path: to print now
  1353. X    }
  1354. X    if (hdrval[fromname] != "") {
  1355. X        print hdrval[fromname]
  1356. X        hdrval[fromname] = ""    # no From: to print now
  1357. X    }
  1358. X
  1359. X    # have pity on readers: put Subject: next
  1360. X    if (hdrval[subjname] != "") {
  1361. X        print hdrval[subjname]
  1362. X        hdrval[subjname] = ""    # no Subject: to print now
  1363. X    }
  1364. X
  1365. X    # print misc. non-empty headers in random order
  1366. X    for (i in hdrval)
  1367. X        if (hdrval[i] != "" && hdrval[i] !~ /^[^\t ]*:[\t ]*$/)
  1368. X            print hdrval[i]
  1369. X}
  1370. !
  1371. echo 'relay/sh/inews':
  1372. sed 's/^X//' >'relay/sh/inews' <<'!'
  1373. X#! /bin/sh
  1374. X# inews [-p] [-debug k] [-x site] [-hMD] [-t subj] [-n ng] [-e exp] [-F ref] \
  1375. X#  [-d dist] [-a mod] [-f from] [-o org] [-C ng] [file...] - inject news:
  1376. X#    censor locally-posted article and field the "inews -C" kludge;
  1377. X#    munge the articles, enforce feeble attempts at Usenet security,
  1378. X#    generate lots of silly headers.
  1379. X#
  1380. X# Yes, it's big, slow and awkward.  The alternative is casting a lot of
  1381. X# local policy in C.
  1382. X
  1383. X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
  1384. X. ${NEWSCONFIG-/usr/lib/news/bin/config}
  1385. Xexport NEWSCTL NEWSBIN NEWSARTS NEWSPATH NEWSUMASK NEWSMASTER NEWSCONFIG
  1386. XPATH=$NEWSCTL/bin:$NEWSBIN/inject:$NEWSBIN/relay:$NEWSBIN:$NEWSPATH; export PATH
  1387. XPASSEDFROM='';    export PASSEDFROM    # passed to anne.jones in environ.
  1388. X
  1389. Xdebug=''            # flags
  1390. Xexclusion=''
  1391. Xhdrspresent=no
  1392. Xautopost=no
  1393. Xwaitcmd=''
  1394. Xrelayopts=-i            # redirect stdout to log
  1395. X
  1396. Xwhoami=/tmp/in$$who        # just created to determine effective uid
  1397. Xinput=/tmp/in$$in        # uncensored input
  1398. Xinhdrs=/tmp/in$$hdr        # generated by tear: headers
  1399. Xinbody=/tmp/in$$body        # generated by tear: body
  1400. Xcensart=/tmp/in$$cens        # censored input
  1401. Xnglist=/tmp/in$$ngs        # newsgroups: list
  1402. Xmodroute=/tmp/in$$route        # route to moderator's forwarder
  1403. Xexitflag=/tmp/in$$exit        # exit status, if present
  1404. Xoutfile=/tmp/in$$out        # relaynews stdout
  1405. Xgrpok=/tmp/in$$grp        # flag file: groups okay if present
  1406. Xrmlist="$inhdrs $inbody $input $censart $nglist $modroute $exitflag $outfile $grpok"
  1407. X
  1408. Xumask $NEWSUMASK
  1409. X
  1410. X# "inews -p": invoke rnews
  1411. Xcase "$1" in
  1412. X-p)
  1413. X    shift
  1414. X    exec rnews $*        # rnews, bailing out at or near line 1
  1415. X    ;;
  1416. Xesac
  1417. X
  1418. X# process arguments: for options, cat headers onto $input; cat files onto $input
  1419. X>$input
  1420. Xcleanup="test ! -f $HOME/dead.article -o -w $HOME/dead.article &&
  1421. X  cat $input >>$HOME/dead.article &&
  1422. X  { echo $0: article in $HOME/dead.article >&2; rm -f $rmlist; }; exit 1"
  1423. Xtrap "$cleanup" 0 1 2 3 15
  1424. Xwhile :
  1425. Xdo
  1426. X    case $# in
  1427. X    0)    break ;;        # arguments exhausted
  1428. X    esac
  1429. X
  1430. X    case "$1" in
  1431. X    # peculiar to C news
  1432. X    -debug)    shift; debug="$1" ;;
  1433. X    -A)    autopost=yes ;;        # wait for free space
  1434. X    -V)    relayopts= ;;        # verbose: don't redirect stdout (or stderr)
  1435. X    -W)    waitcmd=wait ;;        # wait for completion
  1436. X    # useful standard options
  1437. X    -h)    hdrspresent=yes ;;
  1438. X    -x)    shift; exclusion="-x $1" ;;    # you're welcome, erik (2.11)
  1439. X    # silly options supplied by newsreaders
  1440. X    -a)    shift; echo "Approved: $1" >>$input ;;
  1441. X    -c)    shift; echo "Control: $1" >>$input ;;
  1442. X    -d)    shift; echo "Distribution: $1" >>$input ;;
  1443. X    -e)    shift; echo "Expires: $1" >>$input ;;
  1444. X    -f)    shift; echo "From: $1" >>$input ;;
  1445. X    -n)    shift; echo "Newsgroups: $1" >>$input ;;
  1446. X    -t)    shift; echo "Subject: $1" >>$input ;;    # aka Title:
  1447. X    -D)    # obsolete, undocumented: meant "don't check for recordings".
  1448. X        # last present in B 2.10.1, invoked by readnews for followups.
  1449. X        ;;
  1450. X    -F)    # undocumented in B 2.10.1, documented in B 2.11.
  1451. X        shift; echo "References: $1" >>$input ;;
  1452. X    -M)    # this apparently just sets From: to the author of the article
  1453. X        # instead of the poster (moderator), by leaving the From: line
  1454. X        # alone (under -h); easy to implement.
  1455. X        ;;
  1456. X
  1457. X    # pass next options as environment variables to anne.jones
  1458. X    -o)    shift; ORGANIZATION="$1"; export ORGANIZATION ;;
  1459. X
  1460. X    -C)    # megakludge-o-rama
  1461. X        # first, permit only to super-users
  1462. X        >$whoami
  1463. X        case "`ls -l $whoami | awk '{print $3}'`" in
  1464. X        root)    : a winner ;;
  1465. X        *)
  1466. X            echo "$0: only super-users may create news groups" >&2
  1467. X            exit 1
  1468. X            ;;
  1469. X        esac
  1470. X        rm -f $whoami
  1471. X
  1472. X        inewsopt="$1"        # for use in message body
  1473. X        shift            # skip -C to get ng as $1
  1474. X
  1475. X        cat <<! >>$input    # generate a control message
  1476. XNewsgroups: $1
  1477. XControl: newgroup $1
  1478. XSubject: newgroup $1
  1479. XApproved: above-user@above-host
  1480. X
  1481. XThis article generated by inews $inewsopt $1.
  1482. X!
  1483. X        ;;
  1484. X    -*)
  1485. X        echo "$0: bad option $1" >&2
  1486. X        exit 1
  1487. X        ;;
  1488. X    *)                    # is a filename; append file
  1489. X        # B 2.11 kludge: assume -h if input starts with headers.
  1490. X        # apparently the B 2.11 newsreaders assume this.
  1491. X        tear /tmp/in$$ <$1
  1492. X        if test -s $inhdrs; then
  1493. X            hdrspresent=yes
  1494. X        fi
  1495. X
  1496. X        case "$hdrspresent" in
  1497. X        no)    echo "" >>$input; hdrspresent=yes ;;
  1498. X        esac
  1499. X        # capture incoming news in case relaynews fails
  1500. X        if cat $inhdrs $inbody >>$input; then
  1501. X            : far out
  1502. X        else
  1503. X            echo "$0: lost news; cat status $?" >&2
  1504. X            exit 1
  1505. X        fi
  1506. X        fileseen=yes
  1507. X        ;;
  1508. X    esac
  1509. X    shift        # pass option or filename (any value was done above)
  1510. Xdone
  1511. X
  1512. X# if no files named, read stdin
  1513. Xcase "$fileseen" in
  1514. Xyes)    ;;
  1515. X*)
  1516. X    # B 2.11 kludge: assume -h if input starts with headers
  1517. X    # apparently the B 2.11 newsreaders assume this.
  1518. X    tear /tmp/in$$
  1519. X    if test -s $inhdrs; then
  1520. X        hdrspresent=yes
  1521. X    fi
  1522. X
  1523. X    case "$hdrspresent" in
  1524. X    no)    echo "" >>$input; hdrspresent=yes ;;
  1525. X    esac
  1526. X    # capture incoming news in case relaynews fails
  1527. X    if cat $inhdrs $inbody >>$input; then
  1528. X        : far out
  1529. X    else
  1530. X        echo "$0: lost news; cat status $?" >&2
  1531. X        exit 1
  1532. X    fi
  1533. X    ;;
  1534. Xesac
  1535. Xtrap '' 1 2 15            # ignore signals to avoid losing articles
  1536. X
  1537. X# run the remainder in the background for the benefit of impatient people
  1538. X# who lack a window system
  1539. X(
  1540. Xtrap "$cleanup" 0
  1541. Xtear /tmp/in$$ <$input        # output in $inhdrs and $inbody
  1542. X# pad zero-line articles, since old B [ir]news are confused by them
  1543. X# and the news readers generate zero-line control messages, alas.
  1544. Xif test ! -s $inbody; then
  1545. X    (echo '';
  1546. X     echo This article was probably generated by a buggy news reader.) \
  1547. X     >$inbody
  1548. Xfi
  1549. X
  1550. X# deduce which tr we have: v6 or v7
  1551. Xcase "`echo B | tr A-Z a-z `" in
  1552. Xb)    trversion=v7 ;;
  1553. XB)    trversion=v6 ;;            # or System V
  1554. Xesac
  1555. Xexport trversion
  1556. X
  1557. X# post with new headers and .signature
  1558. X(anne.jones <$inhdrs        # bash headers
  1559. X # echo "Lines: `        # sop to msb, just uncomment to use
  1560. X # if test -r $HOME/.signature; then
  1561. X #    (cat $inbody; echo '-- '; sed 4q $HOME/.signature) | wc -l
  1562. X # else
  1563. X #    wc -l <$inbody
  1564. X # fi
  1565. X # `"
  1566. X
  1567. X # strip invisible chars from body, a la B news
  1568. X case "$trversion" in
  1569. X v7)    tr -d '\1-\7\13\14\16-\37' ;;
  1570. X v6)    tr -d '[\1-\7]\13\14[\16-\37]' ;;
  1571. X esac <$inbody
  1572. X
  1573. X if test -r $HOME/.signature; then
  1574. X    echo "-- "; sed 4q $HOME/.signature    # glue on first bit of signature
  1575. X fi) >$censart
  1576. X
  1577. X# to post or to mail? that is the question; whether 'tis nobler in the mind
  1578. X# to suffer the slings and arrows of outrageous mailers - Bill Shakespeare
  1579. Xif grep -s '^Control:' $inhdrs >/dev/null; then
  1580. X    echo "control"            # a dreadful hack around all.all.ctl
  1581. Xelse
  1582. X    sed -n '
  1583. X/^Newsgroups:[     ]/{
  1584. Xs/^Newsgroups:[     ]*\(.*\)$/\1/p
  1585. Xq
  1586. X}
  1587. X' <$inhdrs
  1588. Xfi >$nglist
  1589. X
  1590. Xif test ! -s $nglist; then        # no Newsgroups:
  1591. X    exit 1                # anne.jones will have already complained
  1592. Xfi
  1593. X
  1594. X# look up groups in active, to determine disposition of this message.
  1595. X# n, x and (unapproved) m flags are dealt with on the spot; if none are
  1596. X# seen, the article is posted normally.
  1597. X# escape egrep metacharacters.  In theory one could add " ' ` \
  1598. Xegreppat="^(` sed -e 's/[.+*()|[]/\\\\&/g' -e 's/,/|/g' <$nglist `) "
  1599. Xegrep "$egreppat" $NEWSCTL/active >/dev/null || {
  1600. X    echo "$0: `cat $nglist` matches no groups in $NEWSCTL/active" >&2
  1601. X    exit 1
  1602. X}
  1603. Xrm -f $grpok
  1604. Xegrep "$egreppat" $NEWSCTL/active |
  1605. X    (while read ng high low flag junk    # look at next group's active entry
  1606. X    do
  1607. X        >>$grpok
  1608. X        case "$flag" in
  1609. X        [nx])
  1610. X            echo "$0: sorry, $ng may not be posted to locally." >&2
  1611. X            echo 1 >$exitflag
  1612. X            trap 0        # this is a child process - no cleanup
  1613. X            exit 1        # dregs in /tmp/in$$*
  1614. X            ;;
  1615. X        m)
  1616. X            if grep -s '^Approved:[     ]' $inhdrs >/dev/null; then
  1617. X                rm -f $modroute        # just post normally
  1618. X            else
  1619. X                # un-Approved: mail it to the moderator(s).
  1620. X                echo "%s" >$modroute    # in case no route
  1621. X                # look for route for this group
  1622. X                cat $NEWSCTL/mailpaths |
  1623. X                    while read ngpat route junk
  1624. X                    do
  1625. X                        # a dreadful B 2.11 hack:
  1626. X                        # backbone == all
  1627. X                        case "$ngpat" in
  1628. X                        backbone) ngpat="all" ;;
  1629. X                        esac
  1630. X                        if gngp -a "$ngpat" $nglist >/dev/null; then
  1631. X                            echo "$route" >$modroute
  1632. X                            break    # take only 1st match
  1633. X                        fi
  1634. X                    done
  1635. X            fi
  1636. X            # ngpat and route are not set here, damn it!
  1637. X            if test -s $modroute; then
  1638. X                # an unapproved article in a mod group:
  1639. X                # mail the article to this moderator.
  1640. X                moderator=`
  1641. X                 sed "s/%s/\` echo $ng | tr . - \`/" $modroute
  1642. X                `
  1643. X                echo "$0: mailing your article to $moderator" >&2
  1644. X                mail $moderator <$censart
  1645. X                rm -f $rmlist
  1646. X                echo 0 >$exitflag
  1647. X                trap 0    # this is a child process - did cleanup
  1648. X                exit 0
  1649. X            fi
  1650. X            ;;
  1651. X
  1652. X            # "" matches short active entries,
  1653. X            #    to be backward compatible.
  1654. X            # * matches garbage flags, to be cautious.
  1655. X        y|""|*)
  1656. X            # okay so far, but wait until we see all Newsgroups:.
  1657. X            ;;
  1658. X        esac
  1659. X    done
  1660. X    trap 0                    # paranoia - no clean up
  1661. X    )
  1662. Xif test ! -r $grpok; then
  1663. X    echo "$0: no active groups in `cat $nglist`" >&2
  1664. X    exit 1            # abnormal exit - cleans up, makes dead.article
  1665. Xfi
  1666. Xif test -f $exitflag; then
  1667. X    exitstatus="`cat $exitflag`"
  1668. X    case "$exitstatus" in
  1669. X    0)    trap 0 ;;    # normal exit - cleanup done, no dead.article
  1670. X    esac
  1671. X    exit $exitstatus    # trap 0 will cleanup, make dead.article
  1672. Xfi
  1673. X
  1674. X# deal with inadequate free space
  1675. Xcase "$autopost" in
  1676. Xno)
  1677. X    if test "`spacefor 1 articles`" -le 0; then
  1678. X        echo "$0: too little space free on $NEWSARTS" >&2
  1679. X        exit 1            # dregs in /tmp/in$$* for trap 0
  1680. X    fi
  1681. X    ;;
  1682. X*)
  1683. X    iter=0
  1684. X    while test "`spacefor 1 articles`" -le 0 -o "`spacefor 1 control`" -le 0
  1685. X    do
  1686. X        sleep 30
  1687. X        iter=`expr $iter + 1`
  1688. X        case "$iter" in
  1689. X        3)
  1690. X            mail "$NEWSMASTER" <<!
  1691. XSubject: free space too low on $NEWSARTS
  1692. X
  1693. XThere is too little free space on $NEWSARTS for inews to run comfortably.
  1694. X!
  1695. X            ;;
  1696. X        esac
  1697. X    done
  1698. X    ;;
  1699. Xesac
  1700. X
  1701. X# to get here, we must have seen no n, x, nor (unapproved) m flags.
  1702. X# <$censart is used rather than a pipe to work around a bug in the 4.2 sh
  1703. X# which made it sometimes return the wrong exit status (that of anne.jones).
  1704. X# execute relaynews commands on the server, for the sake of locking.
  1705. X# may not use "exec" or sh will leave /tmp/sh* files from here docs in /tmp.
  1706. Xme="`hostname`"
  1707. Xserver=`cat $NEWSCTL/server 2>/dev/null`
  1708. Xcase "$server" in
  1709. X"")    server="$me" ;;            # if no server file, assume this is it
  1710. Xesac
  1711. Xcase "$me" in
  1712. X$server)
  1713. X    relaynews $relayopts -s $exclusion -d "$debug" <$censart
  1714. X    status=$?
  1715. X#    echo "status $? from relaynews" >>/tmp/inewsdebug # DEBUG
  1716. X    ;;
  1717. X*)
  1718. X    status=`rsh $server \
  1719. X"PATH=$PATH relaynews $relayopts -s $exclusion -d \"$debug\"; echo status $?" \
  1720. X        <$censart >$outfile; sed -n '/^status /s///p' $outfile `
  1721. X    sed '/^status /d' $outfile    # print relaynews's stdout
  1722. X    ;;
  1723. Xesac
  1724. Xcase "$status" in
  1725. X0)
  1726. X    rm -f $rmlist            # far out, it worked: clean up
  1727. X    if test ! -f $NEWSCTL/sys; then
  1728. X        echo "$0: $NEWSCTL/sys missing; your news can't leave this machine" >&2
  1729. X    fi
  1730. X    trap 0                # normal exit: cleanup done
  1731. X    ;;
  1732. Xesac
  1733. Xexit $status                # trap 0 may cleanup, make dead.article
  1734. X) &
  1735. X$waitcmd                # wait if -W given
  1736. Xtrap 0                    # let the background run on unmolested
  1737. Xexit
  1738. !
  1739. echo done
  1740.  
  1741.  
  1742.