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

  1. Subject:  v19i094:  Cnews production release, Part17/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 94
  8. Archive-name: cnews2/part17
  9.  
  10. : ---CUT HERE---
  11. echo 'relay/sh/postnews':
  12. sed 's/^X//' >'relay/sh/postnews' <<'!'
  13. X#! /bin/sh
  14. X# postnews - post news article
  15. X
  16. X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
  17. X. ${NEWSCONFIG-/usr/lib/news/bin/config}
  18. X
  19. XPATH=$NEWSCTL/bin:$NEWSBIN:$NEWSPATH    # but do not export it
  20. Xumask 077                # private
  21. X
  22. Xtmp=/tmp/pn$$
  23. Xterm="rm -f $tmp ; exit 0"
  24. Xtrap "$term" 0 1 2
  25. X
  26. Xif test " $VISUAL" != " "; then
  27. X    edit="$VISUAL"
  28. Xelif test " $EDITOR" != " "; then
  29. X    edit="$EDITOR"
  30. Xelse
  31. X    edit=/bin/ed
  32. Xfi
  33. X
  34. Xcase $# in
  35. X0)
  36. X    if test -r $NEWSCTL/postdefltgroup
  37. X    then
  38. X        defg="`cat $NEWSCTL/postdefltgroup`"
  39. X        dprompt=" [$defg]"
  40. X    else
  41. X        defg=
  42. X        dprompt=
  43. X    fi
  44. X    ans=
  45. X    while test " $ans" = " "
  46. X    do
  47. X        echo "Newsgroup(s)$dprompt? " | tr -d '\012'
  48. X        read ans
  49. X        case "$ans" in
  50. X        '')    if test " $defg" != " "
  51. X            then
  52. X                ans="$defg"
  53. X            fi
  54. X            ;;
  55. X        esac
  56. X    done
  57. X    echo "Newsgroups: $ans" >>$tmp
  58. X    ;;
  59. X
  60. X1)
  61. X    echo "Newsgroups: $1" >>$tmp
  62. X    ;;
  63. X
  64. X*)
  65. X    echo 'Usage: postnews [newsgroups]' >&2
  66. X    exit 2
  67. X    ;;
  68. Xesac
  69. X
  70. Xsubj=
  71. Xwhile test " $subj" = " "
  72. Xdo
  73. X    echo 'Subject: ' | tr -d '\012'
  74. X    read subj
  75. Xdone
  76. Xecho "Subject: $subj" >>$tmp
  77. Xif test -r $NEWSCTL/postdefltdist
  78. Xthen
  79. X    echo "Distribution: `cat $NEWSCTL/postdefltdist`" >>$tmp
  80. Xfi
  81. X
  82. Xecho >>$tmp
  83. Xecho DELETE THIS LINE "(but DO NOT delete the blank line after the headers above)" >>$tmp
  84. Xif test -r $NEWSCTL/postdefltdist
  85. Xthen
  86. X    echo 'DELETE THIS LINE (You may want to change the "Distribution" header)' >>$tmp
  87. Xfi
  88. Xecho REPLACE THIS LINE WITH YOUR TEXT >>$tmp
  89. X
  90. Xtrap : 2
  91. X$edit $tmp
  92. Xtrap "$term" 2
  93. X
  94. Xwhile egrep '^(DELETE|REPLACE) THIS LINE' $tmp >/dev/null
  95. Xdo
  96. X    echo 'This posting does not appear to have been edited properly.'
  97. X    echo 'Abandon it [y] ? ' | tr -d '\012'
  98. X    read ans
  99. X    case "$ans" in
  100. X    ''|y*|Y*)
  101. X        rm -f $tmp
  102. X        exit 0
  103. X        ;;
  104. X    esac
  105. X
  106. X    echo 'Editing again...  Please check it over carefully.'
  107. X    trap : 2
  108. X    $edit $tmp
  109. X    trap "$term" 2
  110. Xdone
  111. X
  112. Xecho 'Posting...'
  113. Xinews -h <$tmp
  114. !
  115. echo 'relay/sh/tear':
  116. sed 's/^X//' >'relay/sh/tear' <<'!'
  117. X#! /bin/sh
  118. X# tear prefix [file...] - tear RFC822 header and body apart
  119. X#    output files are $1hdr and $1body
  120. XPATH=/bin:/usr/bin; export PATH
  121. X
  122. Xcase $# in
  123. X0)
  124. X    echo "usage: tear prefix [file...]" >&2
  125. X    exit 1
  126. X    ;;
  127. Xesac
  128. X
  129. Xhdr="$1hdr"
  130. Xbody="$1body"
  131. Xshift
  132. X
  133. X>>$hdr                    # create files just in case
  134. X>>$body
  135. Xcase $# in
  136. X0)    args="-" ;;    # awk needs a filename due to cmd. line assignments
  137. X*)    args="$@" ;;
  138. Xesac
  139. Xexec awk 'inbody == 0 && $0 ~ /^([ \t]|[^ \t]*:)/ { print >hdr; next }
  140. X                    { inbody = 1; print >body }
  141. X' hdr="$hdr" body="$body" $args
  142. !
  143. echo 'relay/sys.c':
  144. sed 's/^X//' >'relay/sys.c' <<'!'
  145. X/*
  146. X * news sys file reading functions
  147. X */
  148. X
  149. X#include <stdio.h>
  150. X#include <ctype.h>
  151. X#include <sys/types.h>
  152. X#include <sys/stat.h>
  153. X#include "libc.h"
  154. X#include "fgetmfs.h"
  155. X#include "news.h"
  156. X#include "config.h"
  157. X#include "system.h"
  158. X
  159. X#define BTCHDIR "out.going/"    /* prefix of relative batch file name */
  160. X#define BTCHPFX BTCHDIR        /* prefix of default batch file name */
  161. X#define BTCHSFX "/togo"        /* suffix of same */
  162. X#define CMDPFX "uux - -r -z "    /* prefix of default command */
  163. X#define CMDSFX "!rnews"        /* suffix of same */
  164. X
  165. X/* private */
  166. Xstatic FILE *fp = NULL;            /* stream for ctlfile(filerelname) */
  167. Xstatic char filerelname[] = "sys";    /* filename relative to $NEWSCTL */
  168. X
  169. X/* forward decls */
  170. XFORWARD char *parsecolon(), *reparse();
  171. XFORWARD void readsys(), parsesysln(), parse(), parseflags();
  172. X
  173. X/* exports */
  174. Xstruct system *firstsys = NULL;    /* cache: 1st sys of in-core sys file */
  175. Xstruct system *currsys = NULL;    /* current system */
  176. X
  177. X/* imports */
  178. Xextern boolean justone;
  179. Xextern struct system *mysysincache();
  180. Xextern void rewsys(), remmysys(), freecurrsys();
  181. X
  182. Xstruct system *
  183. Xoursys()            /* return our sys entry */
  184. X{
  185. X    register struct system *sys = mysysincache();
  186. X    static struct system fakesys;
  187. X
  188. X    if (sys == NULL) {
  189. X        rewsys(fp);
  190. X        while ((sys = nextsys()) != NULL &&
  191. X            !STREQ(sys->sy_name, hostname()))
  192. X            ;
  193. X        if (sys == NULL) {
  194. X            /* no entry: cook one up; no need to malloc members */
  195. X            fakesys.sy_name = hostname();
  196. X            fakesys.sy_excl = NULL;
  197. X            fakesys.sy_ngs = "all";
  198. X            fakesys.sy_distr = "all";
  199. X            fakesys.sy_flags = 0;
  200. X            fakesys.sy_lochops = 0;
  201. X            fakesys.sy_cmd = "";
  202. X            fakesys.sy_next = NULL;
  203. X            sys = &fakesys;
  204. X        }
  205. X        remmysys(sys);            /* for future reference */
  206. X    }
  207. X    return sys;
  208. X}
  209. X
  210. X/*
  211. X * Return the next sys entry, which may span multiple lines.
  212. X * Returned pointer points at a static struct whose members
  213. X * point at static storage.
  214. X *
  215. X * It would be clearer to rewrite the justone/nextsys/readsys dance
  216. X * to get rid of justone, but I haven't the energy.  Sorry.  Beware that
  217. X * justone is set in either ../libbig/sys.fast.c or ../libsmall/sys.slow.c.
  218. X */
  219. Xstruct system *
  220. Xnextsys()
  221. X{
  222. X    struct system *retsys;
  223. X
  224. X    if (firstsys == NULL && fp == NULL)
  225. X        if ((fp = fopenwclex(ctlfile(filerelname), "r")) == NULL)
  226. X            return NULL;
  227. X    if (fp != NULL && firstsys == NULL)
  228. X        readsys();
  229. X    retsys = currsys;
  230. X    if (currsys != NULL)
  231. X        currsys = currsys->sy_next;
  232. X    return retsys;
  233. X}
  234. X
  235. X/*
  236. X * If justone, read one entry; else read whole sys file (done once only).
  237. X * Ignores '#' comments and blank lines; uses cfgetms to read possibly-
  238. X * continued lines of arbitrary length.
  239. X */
  240. XSTATIC void
  241. Xreadsys()
  242. X{
  243. X    register char *sysline;
  244. X
  245. X    if (justone)
  246. X        freecurrsys();
  247. X    else
  248. X        rewind(fp);
  249. X    while ((sysline = cfgetms(fp)) != NULL) {
  250. X        if (sysline[0] != '#' && sysline[0] != '\n')
  251. X            parsesysln(sysline);
  252. X        free(sysline);
  253. X        if (justone && firstsys != NULL) {    /* parsed an entry */
  254. X            firstsys = NULL;
  255. X            return;
  256. X        }
  257. X    }
  258. X    (void) nfclose(fp);
  259. X    fp = NULL;
  260. X    rewsys(fp);
  261. X}
  262. X
  263. Xstatic char *curr, *next;            /* parsing state */
  264. X
  265. X/*
  266. X * Parse (and modify) sysline into *currsys, which is malloced here
  267. X * and freed iff "justone", in readsys(), see freecursys().
  268. X *
  269. X * Side-effect: sysline has a trailing newline removed.
  270. X */
  271. XSTATIC void
  272. Xparsesysln(sysline)
  273. Xregister char *sysline;
  274. X{
  275. X    register struct system *sysp =(struct system *)nemalloc(sizeof *sysp);
  276. X    char *flagstring;
  277. X
  278. X    trim(sysline);
  279. X    next = sysline;
  280. X    parse(&sysp->sy_name);
  281. X    parse(&sysp->sy_ngs);
  282. X    parse(&flagstring);
  283. X    parse(&sysp->sy_cmd);
  284. X    /* could check for extra fields here */
  285. X
  286. X    parseflags(flagstring, sysp);
  287. X    free(flagstring);        /* malloced by parse */
  288. X    sysp->sy_next = NULL;
  289. X
  290. X    /* reparse for embedded slashes */
  291. X    sysp->sy_excl = reparse(sysp->sy_name, '/');
  292. X    sysp->sy_distr = reparse(sysp->sy_ngs, '/');
  293. X    if (sysp->sy_distr == NULL)    /* default distr is ngs... */
  294. X        sysp->sy_distr = sysp->sy_ngs;
  295. X
  296. X    sysdeflt(sysp);            /* fill in any defaults */
  297. X
  298. X    /* stash *sysp away on the tail of the current list of systems */
  299. X    if (firstsys == NULL)
  300. X        firstsys = sysp;
  301. X    else
  302. X        currsys->sy_next = sysp;
  303. X    currsys = sysp;
  304. X}
  305. X
  306. X/*
  307. X * fill in defaults in sysp.
  308. X *
  309. X * expand a name of "ME" to hostname().
  310. X * If an empty batch file name was given, supply a default
  311. X * ($NEWSARTS/BTCHPFX system BTCHSFX).
  312. X * Prepend $NEWSARTS/BTCHDIR to relative file names.
  313. X * If an empty command was given, supply a default (uux - -r -z system!rnews).
  314. X * (This *is* yucky and uucp-version-dependent.)
  315. X */
  316. Xvoid
  317. Xsysdeflt(sysp)
  318. Xregister struct system *sysp;
  319. X{
  320. X    if (STREQ(sysp->sy_name, "ME")) {
  321. X        free(sysp->sy_name);    /* malloced by parse */
  322. X        sysp->sy_name = strsave(hostname());
  323. X    }
  324. X    if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] == '\0') {
  325. X        register char *deffile = nemalloc((unsigned) STRLEN(BTCHPFX) +
  326. X            strlen(sysp->sy_name) + STRLEN(BTCHSFX) + 1);
  327. X
  328. X        (void) strcpy(deffile, BTCHPFX);
  329. X        (void) strcat(deffile, sysp->sy_name);
  330. X        (void) strcat(deffile, BTCHSFX);
  331. X        free(sysp->sy_cmd);    /* malloced by parse */
  332. X        sysp->sy_cmd = strsave(fullartfile(deffile));
  333. X        free(deffile);
  334. X    }
  335. X    if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] != FNDELIM) {
  336. X        register char *absfile = nemalloc((unsigned) STRLEN(BTCHDIR) +
  337. X            strlen(sysp->sy_cmd) + 1);
  338. X
  339. X        (void) strcpy(absfile, BTCHDIR);
  340. X        (void) strcat(absfile, sysp->sy_cmd);
  341. X        free(sysp->sy_cmd);    /* malloced by parse */
  342. X        sysp->sy_cmd = strsave(artfile(absfile));
  343. X        free(absfile);
  344. X    }
  345. X    if (!(sysp->sy_flags&FLG_BATCH) && sysp->sy_cmd[0] == '\0') {
  346. X        free(sysp->sy_cmd);    /* malloced by parse */
  347. X        sysp->sy_cmd = nemalloc((unsigned) STRLEN(CMDPFX) +
  348. X            strlen(sysp->sy_name) + STRLEN(CMDSFX) + 1);
  349. X        (void) strcpy(sysp->sy_cmd, CMDPFX);
  350. X        (void) strcat(sysp->sy_cmd, sysp->sy_name);
  351. X        (void) strcat(sysp->sy_cmd, CMDSFX);
  352. X    }
  353. X}
  354. X
  355. X/*
  356. X * Parse "next" to colon into malloced storage, return its ptr via "into".
  357. X * *into is freed iff "justone", in readsys(), see freecursys().
  358. X */
  359. XSTATIC void
  360. Xparse(into)
  361. Xregister char **into;
  362. X{
  363. X    curr = next;
  364. X    if (curr == NULL)
  365. X        *into = strsave("");
  366. X    else {
  367. X        next = parsecolon(curr);
  368. X        *into = strsave(curr);
  369. X    }
  370. X}
  371. X
  372. XSTATIC char *
  373. Xparsecolon(line)        /* return NULL or ptr. to byte after colon */
  374. Xchar *line;
  375. X{
  376. X    register char *colon;
  377. X
  378. X    INDEX(line, ':', colon);
  379. X    if (colon != NULL)
  380. X        *colon++ = '\0';
  381. X    return colon;
  382. X}
  383. X
  384. X/*
  385. X * replace "delim" in "field" with a NUL and return the address of the byte
  386. X * after the NUL (the address of the second subfield), or NULL if no
  387. X * "delim" was present.
  388. X */
  389. XSTATIC char *
  390. Xreparse(field, delim)
  391. Xchar *field;
  392. Xint delim;
  393. X{
  394. X    register char *delimp = index(field, delim);
  395. X
  396. X    if (delimp != NULL)
  397. X        *delimp++ = '\0';
  398. X    return delimp;
  399. X}
  400. X
  401. X/*
  402. X * Parse sys file flags into sysp.
  403. X */
  404. XSTATIC void
  405. Xparseflags(flags, sysp)
  406. Xregister char *flags;
  407. Xregister struct system *sysp;
  408. X{
  409. X    sysp->sy_flags = 0;
  410. X    sysp->sy_lochops = 0;        /* default L value */
  411. X    for (; *flags != '\0'; flags++)
  412. X        switch (*flags) {
  413. X        case 'A':
  414. X            errunlock("A news format not supported", "");
  415. X            /* NOTREACHED */
  416. X        case 'B':        /* mostly harmless */
  417. X            break;
  418. X        case 'f':
  419. X            sysp->sy_flags |= FLG_BATCH|FLG_SZBATCH;
  420. X            break;
  421. X        case 'F':
  422. X            sysp->sy_flags |= FLG_BATCH;
  423. X            break;
  424. X        case 'I':        /* NNTP hook: write msgids, !files */
  425. X            sysp->sy_flags |= FLG_BATCH|FLG_IHAVE;
  426. X            break;
  427. X        case 'L':        /* Ln */
  428. X            sysp->sy_flags |= FLG_LOCAL;
  429. X            sysp->sy_lochops = 0;
  430. X            while (isascii(flags[1]) && isdigit(flags[1])) {
  431. X                sysp->sy_lochops *= 10;
  432. X                sysp->sy_lochops += *++flags - '0';
  433. X            }
  434. X            break;
  435. X        case 'm':        /* send only moderated groups */
  436. X            sysp->sy_flags |= FLG_MOD;
  437. X            break;
  438. X        case 'N':
  439. X            errunlock(
  440. X    "The N flag is a wasteful old kludge; see the I flag instead.", "");
  441. X            /* NOTREACHED */
  442. X        case 'n':        /* NNTP hook: write files+msgids */
  443. X            sysp->sy_flags |= FLG_BATCH|FLG_NBATCH;
  444. X            break;
  445. X        case 'u':        /* send only unmoderated groups */
  446. X            sysp->sy_flags |= FLG_UNMOD;
  447. X            break;
  448. X        case 'U':        /* mostly harmless */
  449. X            break;
  450. X        case 'H':        /* bugger off */
  451. X        case 'S':        /* bugger off */
  452. X        case 'M':        /* multicast: obs., see batcher */
  453. X        case 'O':        /* multicast: obs., see batcher */
  454. X        default:
  455. X            errunlock("unknown sys flag `%s' given", flags);
  456. X            /* NOTREACHED */
  457. X        }
  458. X}
  459. X
  460. Xvoid
  461. Xrewndsys()
  462. X{
  463. X    rewsys(fp);
  464. X}
  465. !
  466. echo 'relay/system.h':
  467. sed 's/^X//' >'relay/system.h' <<'!'
  468. X/*
  469. X * parsed form of the "sys" file
  470. X * Beware that in C++, struct system collides with system(3) in transmit.c
  471. X * This can be fixed by using "::system(...)" or by renaming struct system.
  472. X */
  473. Xstruct system {
  474. X    char *sy_name;        /* machine name */
  475. X    char *sy_excl;        /* exclusion list of machines */
  476. X    char *sy_ngs;        /* newsgroup subscription list */
  477. X    char *sy_distr;        /* distribution list */
  478. X    char *sy_cmd;        /* command to transmit articles */
  479. X    unsigned sy_lochops;    /* flags Ln value: local hops */
  480. X    char sy_flags;        /* ornaments, encoded as bits */
  481. X    struct system *sy_next;    /* link to next system */
  482. X};
  483. X
  484. X/* sy_flags bits */
  485. X#define FLG_BATCH    (1<<0)        /* F: sy_cmd is batch filename */
  486. X#define FLG_SZBATCH    (1<<1)        /* f: F, and include byte count */
  487. X#define FLG_IHAVE    (1<<2)        /* I: NNTP ihave - F, write msg. ids */
  488. X#define FLG_LOCAL    (1<<3)        /* L: send local articles only */
  489. X#define FLG_MOD        (1<<4)        /* m: send moderated groups only */
  490. X#define FLG_UNMOD    (1<<5)        /* u: send unmoderated groups only */
  491. X#define FLG_NBATCH    (1<<6)        /* n: NNTP batch: filename & msg-id */
  492. X
  493. X/* imports from system.c */
  494. Xextern struct system *oursys(), *nextsys();
  495. Xextern void sysdeflt(), rewndsys();
  496. !
  497. echo 'relay/transmit.c':
  498. sed 's/^X//' >'relay/transmit.c' <<'!'
  499. X/*
  500. X * transmit - transmit incoming articles to neighbouring machines
  501. X */
  502. X
  503. X#include <stdio.h>
  504. X#include <sys/types.h>
  505. X#include "libc.h"
  506. X#include "news.h"
  507. X#include "config.h"
  508. X#include "headers.h"
  509. X#include "active.h"
  510. X#include "article.h"
  511. X#include "msgs.h"
  512. X#include "system.h"
  513. X#include "trbatch.h"
  514. X#include "transmit.h"
  515. X
  516. X/* forwards */
  517. XFORWARD boolean oktransmit();
  518. XFORWARD void ejaculate(), trappend();
  519. X
  520. X/* private */
  521. Xstatic boolean debug = NO;
  522. X
  523. Xvoid
  524. Xtransdebug(state)
  525. Xboolean state;
  526. X{
  527. X    debug = state;
  528. X}
  529. X
  530. X/*
  531. X * For each system in "sys" other than this one,
  532. X * transmit this article when its ng pattern matches
  533. X * art->h.h_distr (which may be just a copy of art->h.h_ngs).
  534. X */
  535. Xvoid
  536. Xtransmit(art, exclude)
  537. Xregister struct article *art;
  538. Xchar *exclude;                    /* no copy to this site */
  539. X{
  540. X    register struct system *sys;
  541. X    register int bsysno = 0;    /* ordinal # of batch sys entry */
  542. X
  543. X    rewndsys();
  544. X    if (debug)
  545. X        (void) fprintf(stderr, "just rewound sys file\n");
  546. X    while ((sys = nextsys()) != NULL) {
  547. X        if (debug)
  548. X            (void) fprintf(stderr,
  549. X                "sy_name=%s sy_ngs=%s sy_distr=%s\n",
  550. X                sys->sy_name, sys->sy_ngs, sys->sy_distr);
  551. X        if (oktransmit(art, sys, exclude))
  552. X            ejaculate(art, sys, bsysno);
  553. X        if (sys->sy_flags&FLG_BATCH)
  554. X            ++bsysno;
  555. X    }
  556. X    if (debug)
  557. X        (void) fprintf(stderr, "just finished reading sys file\n");
  558. X}
  559. X
  560. X/*
  561. X * Is it okay to send the article corresponding to "art" to site "sys",
  562. X * excluding site "exclude"?
  563. X *
  564. X * If L(n) flag is on, must have been posted within n hops of here.
  565. X * Never send to this site, nor the "exclude" site, nor any site with a host
  566. X * in sys->sy_excl named in Path:, nor any site named in Path:.
  567. X *
  568. X * Newsgroups: must match sys's subscription list.
  569. X * Distribution: must match sys's distribution list.  (RFC 850 is wrong:
  570. X * Distribution:s are *not* patterns, they are lists.  See RFC 1036.)
  571. X *
  572. X * If m flag is on, group(s) must be moderated; if u flag is on,
  573. X * must be unmoderated.  (If both are on, act as if neither is on.)
  574. X */
  575. XSTATIC boolean
  576. Xoktransmit(art, sys, exclude)
  577. Xregister struct article *art;
  578. Xregister struct system *sys;
  579. Xchar *exclude;                /* no copy to him */
  580. X{
  581. X    register int flags = sys->sy_flags;
  582. X    register char *site = sys->sy_name;
  583. X    register char *path =
  584. X        canonpath(art->h.h_path, art->h.h_approved, art->h.h_sender);
  585. X    register int result;
  586. X
  587. X    if (flags&FLG_LOCAL && hopcount(path) > sys->sy_lochops ||
  588. X        STREQ(hostname(), site) ||
  589. X        exclude != NULL && STREQ(exclude, site) || hostin(site, path) ||
  590. X        sys->sy_excl != NULL && anyhostin(sys->sy_excl, path) ||
  591. X        !ngmatch(sys->sy_ngs, art->h.h_ngs) ||
  592. X        !ngmatch(sys->sy_distr, art->h.h_distr))
  593. X        result = NO;
  594. X    else if (flags&(FLG_MOD|FLG_UNMOD)) {    /* u, m flag selection */
  595. X        if ((flags&(FLG_MOD|FLG_UNMOD)) == (FLG_MOD|FLG_UNMOD))
  596. X            result = YES;        /* too silly */
  597. X        else
  598. X            result = (flags&FLG_MOD? moderated(art->h.h_ngs):
  599. X                        !moderated(art->h.h_ngs));
  600. X    } else
  601. X        result = YES;
  602. X    free(path);
  603. X    return result;
  604. X}
  605. X
  606. X/*
  607. X * Send the article denoted by art to the system denoted by sys.
  608. X *
  609. X * When a filename is needed, we use the first one in art->a_files
  610. X * rather than art->a_tmpf because we want a permanent name, and
  611. X * translate it to a full path name to avoid ambiguity.
  612. X *
  613. X * Side-effect: prints the system name on stdout for logging.
  614. X */
  615. XSTATIC void
  616. Xejaculate(art, sys, bsysno)
  617. Xregister struct article *art;
  618. Xregister struct system *sys;
  619. Xint bsysno;
  620. X{
  621. X    register char *fullname;    /* sometimes is a message-id */
  622. X
  623. X    if (debug)
  624. X        (void) fprintf(stderr, "transmitting %s to %s\n",
  625. X            art->h.h_msgid, sys->sy_name);
  626. X        (void) printf(" %s", sys->sy_name);    /* logging */
  627. X    if (sys->sy_flags&FLG_IHAVE)
  628. X        fullname = art->h.h_msgid;
  629. X    else {
  630. X        register char *filename = first(art->a_files);
  631. X
  632. X        mkfilenm(filename);
  633. X            fullname = fullartfile(filename);
  634. X        free(filename);
  635. X    }
  636. X#ifdef PARANOID
  637. X    fullname = strsave(fullname);
  638. X#endif
  639. X    if (sys->sy_flags&FLG_BATCH)
  640. X            trbatch(art, sys, fullname, bsysno);
  641. X    else
  642. X        trcmd(art, sys, fullname);
  643. X#ifdef PARANOID
  644. X    free(fullname);
  645. X#endif
  646. X}
  647. X
  648. X/*
  649. X * Execute sys->sy_cmd with the current article as stdin
  650. X * and filename substituted for %s in sys->sy_cmd (if any).
  651. X *
  652. X * Search path includes $NEWSCTL/bin and $NEWSBIN/relay.
  653. X * redirect stdin to prevent consuming my stdin & so cmd's stdin
  654. X * is filename by default.
  655. X *
  656. X * We use strcat instead of sprintf if syscmd contains no %.
  657. X * this avoids the 128-byte restriction on printf output
  658. X * (see printf(3) BUGS, at least in V7).
  659. X */
  660. Xvoid
  661. Xtrcmd(art, sys, filename)
  662. Xstruct article *art;
  663. Xstruct system *sys;
  664. Xchar *filename;
  665. X{
  666. X    register char *cmd;
  667. X    int exitstat;
  668. X    char *syscmd = sys->sy_cmd, *percent;
  669. X    static char *ctlcmd = NULL, *bincmd = NULL;
  670. X
  671. X    if (ctlcmd == NULL)
  672. X        ctlcmd = strsave(ctlfile("bin"));
  673. X    if (bincmd == NULL)
  674. X        bincmd = strsave(binfile("relay"));
  675. X    cmd = nemalloc((unsigned)(STRLEN("PATH=") + strlen(ctlcmd) +
  676. X        STRLEN(":") + strlen(bincmd) + STRLEN(":") + strlen(newspath()) +
  677. X        STRLEN(" <") + strlen(filename) + STRLEN(" ") +
  678. X        strlen(syscmd) + strlen(filename) + 1));
  679. X    (void) strcpy(cmd, "PATH=");
  680. X    (void) strcat(cmd, ctlcmd);
  681. X    (void) strcat(cmd, ":");
  682. X    (void) strcat(cmd, bincmd);
  683. X    (void) strcat(cmd, ":");
  684. X    (void) strcat(cmd, newspath());
  685. X    (void) strcat(cmd, " <");
  686. X    (void) strcat(cmd, filename);
  687. X    (void) strcat(cmd, " ");
  688. X    percent = index(syscmd, '%');
  689. X    if (percent == NULL)
  690. X        (void) strcat(cmd, syscmd);
  691. X    else {
  692. X        char *pcent2;
  693. X
  694. X        ++percent;
  695. X        pcent2 = index(percent, '%');
  696. X        if (pcent2 != NULL) {
  697. X            art->a_status |= ST_DROPPED;
  698. X            (void) fprintf(stderr, "%s: `%s' contains two %%'s\n",
  699. X                progname, cmd);
  700. X        } else if (*percent != 's' && *percent != '%') {
  701. X            art->a_status |= ST_DROPPED;
  702. X            (void) fprintf(stderr, "%s: `%s' contains %%%c, not %%s\n",
  703. X                progname, cmd, *percent);
  704. X        } else
  705. X            (void) sprintf(cmd+strlen(cmd), syscmd, filename);
  706. X    }
  707. X    exitstat = system(cmd);
  708. X    if (exitstat != 0) {
  709. X        art->a_status |= ST_DROPPED;
  710. X        (void) fprintf(stderr, "%s: `%s' returned exit status 0%o\n",
  711. X            progname, cmd, exitstat);
  712. X    }
  713. X    free(cmd);
  714. X}
  715. X
  716. X/*
  717. X * Append "filename" to sys->sy_cmd.  bsysno is the ordinal # of this batch
  718. X * sys line.  If bsysno is low enough, use the batchfile cache of batch file
  719. X * descriptors.
  720. X */
  721. Xvoid
  722. Xtrbatch(art, sys, filename, bsysno)
  723. Xregister struct article *art;
  724. Xstruct system *sys;
  725. Xchar *filename;
  726. Xregister int bsysno;
  727. X{
  728. X    register struct batchfile *bf = bfopen(sys->sy_cmd, bsysno);
  729. X
  730. X    if (bf == NULL || bf->bf_str == NULL)
  731. X        art->a_status |= ST_DROPPED;
  732. X    else {
  733. X        trappend(art, sys, bf, filename);
  734. X        art->a_status |= bffkclose(bsysno);
  735. X    }
  736. X}
  737. X
  738. X/*
  739. X * write filename, message-id or size on batch file "bf".
  740. X * under the 'f' flag (FLG_SZBATCH), include the size in bytes of the article
  741. X * after "name" to assist the C news batcher.  under the 'n' flag (FLG_NBATCH),
  742. X * write the article's message-id.  afterward, flush "bf" in case
  743. X * the machine crashes before the stream is closed.
  744. X */
  745. XSTATIC void
  746. Xtrappend(art, sys, bf, name)
  747. Xregister struct article *art;
  748. Xregister struct system *sys;
  749. Xregister struct batchfile *bf;
  750. Xchar *name;
  751. X{
  752. X    if (fputs(name, bf->bf_str) == EOF)
  753. X        fulldisk(art, bf->bf_name);
  754. X    if (sys->sy_flags&FLG_SZBATCH &&
  755. X        fprintf(bf->bf_str, " %ld", art->a_charswritten) == EOF)
  756. X        fulldisk(art, bf->bf_name);
  757. X    if (sys->sy_flags&FLG_NBATCH &&
  758. X        fprintf(bf->bf_str, " %s", art->h.h_msgid) == EOF)
  759. X        fulldisk(art, bf->bf_name);
  760. X
  761. X    /* don't check putc return value for portability; use ferror */
  762. X    (void) putc('\n', bf->bf_str);
  763. X    if (ferror(bf->bf_str) || bfflush(bf) == EOF)
  764. X        fulldisk(art, bf->bf_name);        
  765. X}
  766. X
  767. X/*
  768. X * really close all the open batch files
  769. X */
  770. Xstatust
  771. Xtrclose()
  772. X{
  773. X    return bfrealclose();
  774. X}
  775. !
  776. echo 'relay/transmit.h':
  777. sed 's/^X//' >'relay/transmit.h' <<'!'
  778. X/* imports from transmit.c */
  779. Xextern statust trclose();
  780. Xextern void transdebug(), transmit(), trcmd(), trbatch();
  781. !
  782. echo 'relay/trbatch.c':
  783. sed 's/^X//' >'relay/trbatch.c' <<'!'
  784. X/* 
  785. X * transmit batch file management
  786. X */
  787. X#include <stdio.h>
  788. X#include <sys/types.h>
  789. X#include "libc.h"
  790. X#include "news.h"
  791. X#include "msgs.h"
  792. X#include "trbatch.h"
  793. X
  794. X/* tunable parameters */
  795. X#ifndef FLUSHEVERY
  796. X#define FLUSHEVERY 1    /* fflush batch files every this many lines */
  797. X#endif            /* FLUSHEVERY */
  798. X#ifndef NOPENBFS
  799. X#define NOPENBFS 10    /* # batchfiles kept open for batching (arbitrary) */
  800. X#endif            /* NOPENBFS */
  801. X
  802. Xstatic struct batchfile batchfile[NOPENBFS];    /* try to keep open always */
  803. X#define lastbf &batchfile[NOPENBFS-1]
  804. X/*
  805. X * More than one pointer in ordtobfs may point at a given batchfile,
  806. X * to permit sharing of open batch files among multiple sys entries.
  807. X * ordtobfs[ordinal # of batch sys entry] -> (usually open) batch file,
  808. X * if the index is in range.
  809. X */
  810. Xstatic struct batchfile *ordtobfs[NOPENBFS];
  811. Xstatic struct batchfile fakebatf;    /* for non-cached batch files */
  812. X
  813. X/* forwards */
  814. XFORWARD statust bfclose(), bfrclose();
  815. XFORWARD struct batchfile *bfincache(), *fakebf();
  816. X
  817. X/*
  818. X * open "name" for appending, for batch sys entry with ordinal # "ord".
  819. X *
  820. X * if ord is too big, see if any batchfile has been assigned to "name" yet;
  821. X * if not, set up a fake batchfile for temporary use.  if ord is in range,
  822. X * ensure that (name, ord) are mapped to a batchfile.
  823. X *
  824. X * if an attempt to open the batchfile's stream fails, close a random
  825. X * batchfile stream and retry the open.
  826. X */
  827. Xstruct batchfile *
  828. Xbfopen(name, ord)
  829. Xregister char *name;
  830. Xregister int ord;
  831. X{
  832. X    register struct batchfile *bf;
  833. X
  834. X    if (ord >= NOPENBFS) {            /* no mapping possible */
  835. X        bf = bfisopen(name);
  836. X        if (bf == NULL)
  837. X            bf = fakebf((FILE *)NULL, name);
  838. X    } else
  839. X        bf = bfincache(name, ord);
  840. X
  841. X    if (bf->bf_str == NULL)
  842. X        bf->bf_str = fopenclex(name, "a");
  843. X    if (bf->bf_str == NULL) {
  844. X        if (bfrclose() != ST_OKAY)
  845. X            return NULL;
  846. X        bf->bf_str = fopenwclex(name, "a");    /* retry, may bitch */
  847. X    }
  848. X    return bf;
  849. X}
  850. X
  851. X/*
  852. X * returns a batchfile, never NULL, corresponding to name and ord.
  853. X * if ord isn't mapped, search the batchfile cache for name;
  854. X * if missing, initialise batchfile[ord] and map ord to it.
  855. X * if ord wasn't mapped, but name was in the cache, map ord to the cache hit.
  856. X */
  857. XSTATIC struct batchfile *
  858. Xbfincache(name, ord)
  859. Xchar *name;
  860. Xint ord;
  861. X{
  862. X    register struct batchfile *bf = ordtobfs[ord];
  863. X
  864. X    if (bf == NULL) {
  865. X        bf = bfisopen(name);
  866. X        if (bf == NULL) {
  867. X            /* establish new mapping for a new file */
  868. X            bf = &batchfile[ord];
  869. X            bf->bf_name = strsave(name);
  870. X            bf->bf_str = NULL;    /* paranoia */
  871. X#ifdef notdef
  872. X            bf->bf_ref = 0;
  873. X#endif
  874. X            bf->bf_lines = FLUSHEVERY;
  875. X        }
  876. X        ordtobfs[ord] = bf;
  877. X    }
  878. X    /* mapping is now set (ord -> bf) */
  879. X    return bf;
  880. X}
  881. X
  882. Xstatust
  883. Xbffkclose(ord)                /* close ord's batchfile, if fake */
  884. Xint ord;
  885. X{
  886. X    register statust status = ST_OKAY;
  887. X
  888. X    if (ord >= NOPENBFS)
  889. X        status |= bfclose(&fakebatf);
  890. X    return status;
  891. X}
  892. X
  893. XSTATIC statust
  894. Xbfclose(bf)
  895. Xregister struct batchfile *bf;
  896. X{
  897. X    register statust status = ST_OKAY;
  898. X
  899. X    if (nfclose(bf->bf_str) == EOF)
  900. X        status = prfulldisk(bf->bf_name);
  901. X    bf->bf_str = NULL;    /* prevent accidents; mark as closed */
  902. X    return status;
  903. X}
  904. X
  905. XSTATIC struct batchfile *
  906. Xfakebf(stream, name)
  907. XFILE *stream;
  908. Xchar *name;
  909. X{
  910. X    fakebatf.bf_name = name;
  911. X    fakebatf.bf_str = stream;
  912. X    return &fakebatf;
  913. X}
  914. X
  915. X/*
  916. X * search the batchfile cache for "name"; return the hit, if any.
  917. X */
  918. Xstruct batchfile *
  919. Xbfisopen(name)
  920. Xregister char *name;
  921. X{
  922. X    register struct batchfile *bf;
  923. X
  924. X    for (bf = batchfile; bf <= lastbf; bf++)
  925. X        if (bf->bf_name != NULL && STREQ(name, bf->bf_name))
  926. X            return bf;
  927. X    return NULL;
  928. X}
  929. X
  930. X/*
  931. X * a performance hack: only fflush bf->bf_str every FLUSHEVERY calls.
  932. X */
  933. Xint
  934. Xbfflush(bf)
  935. Xregister struct batchfile *bf;
  936. X{
  937. X    register int ret = 0;
  938. X
  939. X    if (--bf->bf_lines <= 0) {
  940. X        bf->bf_lines = FLUSHEVERY;
  941. X        ret = fflush(bf->bf_str);
  942. X    }
  943. X    return ret;
  944. X}
  945. X
  946. XSTATIC statust
  947. Xbfrclose()                /* close a random batchfile */
  948. X{
  949. X    register struct batchfile *bf;
  950. X    register statust status = ST_OKAY;
  951. X
  952. X    for (bf = batchfile; bf <= lastbf; bf++)
  953. X        if (bf->bf_str != NULL) {
  954. X            status |= bfclose(bf);
  955. X            break;
  956. X        }
  957. X    return status;
  958. X}
  959. X
  960. Xstatust
  961. Xbfrealclose()                /* close all open batch files */
  962. X{
  963. X    register struct batchfile *bf;
  964. X    register statust status = ST_OKAY;
  965. X
  966. X    for (bf = batchfile; bf <= lastbf; bf++) {
  967. X        if (bf->bf_str != NULL)        /* batch file stream open */
  968. X            status |= bfclose(bf);
  969. X        nnfree(&bf->bf_name);
  970. X#ifdef notdef
  971. X        bf->bf_ref = 0;
  972. X#endif
  973. X        ordtobfs[bf - batchfile] = NULL;    /* unmap batch file */
  974. X    }
  975. X    return status;
  976. X}
  977. !
  978. echo 'relay/trbatch.h':
  979. sed 's/^X//' >'relay/trbatch.h' <<'!'
  980. X/*
  981. X * interface to the transmit batch files
  982. X */
  983. X
  984. Xstruct batchfile {
  985. X#ifdef notdef
  986. X    int bf_ref;            /* reference count */
  987. X#endif
  988. X    FILE *bf_str;            /* stream */
  989. X    char *bf_name;            /* file name */
  990. X    int bf_lines;            /* until fflush */
  991. X};
  992. X
  993. X/* imports from trbatch.c */
  994. Xextern struct batchfile *bfopen(), *bfisopen();
  995. Xextern statust bffkclose(), bfrealclose();
  996. Xextern int bfflush();
  997. !
  998. echo 'relay/ihave.not.c':
  999. sed 's/^X//' >'relay/ihave.not.c' <<'!'
  1000. X/*
  1001. X * Reject the Usenet ihave/sendme control messages.
  1002. X */
  1003. X
  1004. X#include <stdio.h>
  1005. X#include <sys/types.h>
  1006. X
  1007. X#include "news.h"
  1008. X#include "headers.h"
  1009. X#include "article.h"
  1010. X
  1011. Xstatic void
  1012. Xignore(cmd, args)
  1013. Xchar *cmd, *args;
  1014. X{
  1015. X    (void) fprintf(stderr, "%s: `%s %s' control ignored\n", progname, cmd, args);
  1016. X}
  1017. X
  1018. X/* ARGSUSED art */
  1019. Xvoid
  1020. Xihave(args, art)
  1021. Xchar *args;
  1022. Xstruct article *art;
  1023. X{
  1024. X    ignore("ihave", args);
  1025. X}
  1026. X
  1027. X/* ARGSUSED art */
  1028. Xvoid
  1029. Xsendme(args, art)
  1030. Xchar *args;
  1031. Xstruct article *art;
  1032. X{
  1033. X    ignore("sendme", args);
  1034. X}
  1035. !
  1036. echo 'relay/README.relay':
  1037. sed 's/^X//' >'relay/README.relay' <<'!'
  1038. X``yer about to be boarded, ye scurvy network news dogs! har har ...''
  1039. X        -- Oliver Wendell Jones, Bloom County Hacker & Cracker
  1040. X
  1041. X``No news is good news.''
  1042. X``When bigger machines are built, netnews will saturate them.''
  1043. X``USENET -- All the news that's fit to `N'.''
  1044. X        -- /usr/games/fortune
  1045. X
  1046. X``Net news is the television of computing.''
  1047. X        -- Geoff Collyer
  1048. X
  1049. XOn older systems, you will to also install a small program, setnewids,
  1050. Xsetuid-root.  If this worries you, read setnewsids.c; all it does is
  1051. Xexecute setgid(), setuid() to the "news" group and user if they exist,
  1052. Xotherwise relaynews's real ids.  Setnewsids can be found in ../conf.
  1053. X
  1054. XYou can test relaynews by giving NEWSCTL, NEWSBIN or NEWSARTS
  1055. Xenvironment variables to change the library, binary or spool
  1056. Xdirectories and I encourage this.
  1057. X
  1058. XIf you plan to run rn, you'll need the rn patches to allow Xref: to
  1059. Xwork without Relay-Version:, which has been banished.
  1060. X
  1061. XYou will need to put your site name in /usr/lib/news/mailname (../conf/build
  1062. Xlooks after all this).  No upper case letters in your name
  1063. Xplease, there is no call for it and it just looks ugly.
  1064. X
  1065. XYou must only permit relaynews to run on file servers since newsboot clears
  1066. Xall locks in /usr/lib/news.
  1067. X
  1068. XYou'll need compress for compressing or uncompressing batches of news.
  1069. XSee the contact person of your news feed or the moderator of the
  1070. Xnewsgroup comp.sources.unix (try uunet!sources).
  1071. X
  1072. XSee the anews directory for conversion filters from A to B and back.
  1073. X
  1074. XYou'll need to install /usr/lib/newsbin/gngp (see ../misc) before inews
  1075. Xwill work.
  1076. X
  1077. XB-2.11-isms.  Your /usr/lib/news/mailpaths file must be updated to
  1078. Xpoint at your nearest backbone site.  A 5th sys file field for
  1079. XDistribution:  patterns is available (add them in sys after the
  1080. Xsubscription list, separated by "/"), and a 6th field for excluded
  1081. Xhosts is also, separated by "/" from the system name.
  1082. X
  1083. XGood Luck.
  1084. X
  1085. X                Geoff Collyer, 8 June 1989
  1086. !
  1087. echo 'rna/README':
  1088. sed 's/^X//' >'rna/README' <<'!'
  1089. XThis is the "Australian readnews", written by Michael Rourke at UNSW.
  1090. XIt's a simple and reasonably well-put-together news reader suitable for
  1091. Xgiving to naive users who aren't going to be reading news much.
  1092. X
  1093. XYou'll need to fiddle defs.h for your machine, then type "make".
  1094. X
  1095. XNote that README.aus assumes you are installing the entire UNSW news
  1096. Xsystem, not just readnews; some of it is inapplicable.
  1097. !
  1098. echo 'rna/README.aus':
  1099. sed 's/^X//' >'rna/README.aus' <<'!'
  1100. XThe files in this distribution are:
  1101. X
  1102. X    Makefile
  1103. X    README
  1104. X    active.c
  1105. X    at.h
  1106. X    defs.h
  1107. X    expire.c
  1108. X    funcs.c
  1109. X    header.c
  1110. X    history.c
  1111. X    lib
  1112. X    lib/bsearch.c
  1113. X    lib/memset.c
  1114. X    lib/strpbrk.c
  1115. X    lib/tmpfile.c
  1116. X    lib/tmpnam.c
  1117. X    maketime.c
  1118. X    man
  1119. X    man/postnews.1
  1120. X    man/readnews.1
  1121. X    man/uurec.8
  1122. X    man/uusend.8
  1123. X    mtempnam.c
  1124. X    news.help
  1125. X    newsrc.c
  1126. X    postnews.c
  1127. X    readnews.c
  1128. X    sample.sys
  1129. X    uurec.c
  1130. X    uusend.c
  1131. X
  1132. XThis news system is modelled on the USENET news system
  1133. Xby Mark Horton (and others).
  1134. X
  1135. XApart from some minor programs the system has been completely re-written.
  1136. XThe aim of re-writing was to produce a system that was:
  1137. X    1. smaller
  1138. X    2. cleaner
  1139. X    3. faster
  1140. X    4. was compatible at the site <--> site level with USENET
  1141. X    5. had a better user interface ("readnews" and "postnews")
  1142. X
  1143. XThese goals have been met.
  1144. XThe programs "readnews" and "postnews" are 1/3 the previous size, and
  1145. Xdoes not require separate I/D space to run on pdp11/70's.
  1146. XAlso far fewer processes are needed to use "postnews".
  1147. X
  1148. XThis system is compatible with USENET at the site <--> site level, provided
  1149. Xcommunication is done with Version B format messages (the current 'standard').
  1150. XThe messages meet the Standard for the format of ARPA Internet Text messages
  1151. X(RFC 822).
  1152. X
  1153. X"postnews" methods of editing messages is compatible with our local "mail"
  1154. Xprogram (also re-written locally).
  1155. X
  1156. XTo aid someone familiar with USENET to find his/her way around the source:
  1157. X    Program changes:
  1158. X    "checknews" has become a function of "readnews" (readnews -cC)
  1159. X    "postnews" and "inews" are combined into "postnews"
  1160. X    "readnews" has the same function (simplified user interface)
  1161. X    "expire" has the same function (simplified arguments)
  1162. X    "recnews" is not needed
  1163. X    "sendnews" has been renamed "uusend" (and simplified)
  1164. X    "uurec" has the same function
  1165. X    Files:
  1166. X    The layout of the news database is the same, except that articles
  1167. X    are named #<number> rather than <number>, so that numbers can
  1168. X    be a valid newsgroup (like class.6.621).
  1169. X
  1170. X    "/usr/lib/news/active" has an extra field - the lowest numbered article
  1171. X    present in a newsgroup.
  1172. X    "/usr/lib/news/history" has a sightly different format.
  1173. X    "/usr/lib/news/sys" is compatible, except that the third field
  1174. X    is ignored (always expects format B site); colons are allowed in
  1175. X    the last field.
  1176. X
  1177. XTo setup the news system:
  1178. X    1. edit the "defs.h" file and make any changes necessary
  1179. X       in particular: MYDOMAIN, MYORG and the paths of SEQ, SYS etc.
  1180. X       MANGRPS should not be defined without making suitable
  1181. X       modifications to getmangrps() in readnews.c
  1182. X       UNSWMAIL is set if you have the version of mail from UNSW,
  1183. X       in particular it allows arguments "-s subject -i include_file"
  1184. X       to specify the subject, and make include_file available to
  1185. X       a ".i" command (like postnews).
  1186. X       AUSAM should not be set unless you have the hashed passwd file,
  1187. X       and locked file facilities of AUSAM.
  1188. X    1a. edit "Makefile" for the pathnames of LIBDIR, BINDIR and NETDIR.
  1189. X    2. create the account NEWSROOT (defined in defs.h) (this is where
  1190. X       the messages are kept).
  1191. X    3. Run the makefile. If you don't have the routines found in
  1192. X       lib/* (bsearch, memset etc.) these can be compiled and
  1193. X       linked in as required.
  1194. X    4. Create any groups (using "postnews -c 'newgroup <name>'"),
  1195. X       that require immediate local posting, otherwise groups will
  1196. X       be created automatically when news is received from other sites.
  1197. X       Root and NEWSROOT can also mail to non-existent groups, and
  1198. X       will be asked whether or not to create the new group.
  1199. X    5. Set up a pseudo user "rnews" to direct received news into
  1200. X       "postnews -p" (with uid set to NEWSROOT).
  1201. X       How this is done will depend on your network implementation.
  1202. X       It may require a deamon emptying a mail box regularly
  1203. X       (see rnews.sh in this case).
  1204. X       If a mail interface is required, series of messages can be
  1205. X       piped into /usr/lib/news/uurec instead.
  1206. X    6. Set up "/usr/lib/news/sys". See sample.sys for an example.
  1207. X       Each line in the "sys" file specifies:
  1208. X        host name
  1209. X        distribution newsgroups
  1210. X        (empty field (system assumes type B interchange))
  1211. X        the command needed to send the item to the host.
  1212. X       Note the current host must have the first two fields also.
  1213. X       News transmission can be via "mail" or directly as a
  1214. X       network file transfer.
  1215. X    7. Test the system by posting to "to.mysite".
  1216. X    8. Arrange for "expire" to be run periodically (via "cron" or "at").
  1217. X
  1218. XIf you had an existing (old) news system, and wish to transfer the
  1219. Xarticles. The best way to do it is run the command:
  1220. X
  1221. X    find oldnewsdir -type f -a -print ^
  1222. X    while read F
  1223. X    do
  1224. X        postnews -p < $F
  1225. X    done
  1226. X
  1227. XMichael Rourke
  1228. XUniversity of New South Wales, Australia    13 June 1984
  1229. X(decvax!mulga!michaelr:elecvax)
  1230. X(vax135!mulga!michaelr:elecvax)
  1231. !
  1232. echo 'rna/active.c':
  1233. sed 's/^X//' >'rna/active.c' <<'!'
  1234. X/*
  1235. X * active file handling routines
  1236. X *
  1237. X * format of file:
  1238. X *    <groupname> ' ' <5 digit #> ' ' <5 digit #> ' ' flag '\n'
  1239. X *              (seq)          (low)
  1240. X */
  1241. X
  1242. X#include "defs.h"
  1243. X
  1244. Xstatic char actname[]     = ACTIVE;
  1245. Xstatic int lineno;
  1246. Xstatic active    *alist;
  1247. X
  1248. X/*
  1249. X * getseq - Get next sequence number for this group
  1250. X *        and update active file.
  1251. X *        If group missing append to file.
  1252. X */
  1253. Xchar *
  1254. Xgetseq(group)
  1255. Xchar *group;
  1256. X{
  1257. X    register FILE    *f;
  1258. X    register int i;
  1259. X    char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
  1260. X    extern char *itoa();
  1261. X
  1262. X    f = fopenl(actname);
  1263. X    lineno = 0;
  1264. X    while (getline(f, gbuf, dbuf, dbuf2))
  1265. X        if (CMP(gbuf, group) == 0) {
  1266. X            i = atoi(dbuf);
  1267. X            i++;
  1268. X            fseek(f, -12L, 1);
  1269. X            (void) fprintf(f, "%05d", i);
  1270. X            fclose(f);
  1271. X#if !AUSAM
  1272. X            unlock(actname);
  1273. X#endif
  1274. X            return itoa(i);
  1275. X        }
  1276. X    (void) fprintf(f, "%s 00001 00001 y\n", group);
  1277. X    fclose(f);
  1278. X#if !AUSAM
  1279. X    unlock(actname);
  1280. X#endif
  1281. X    return itoa(1);
  1282. X}
  1283. X
  1284. X
  1285. Xstatic
  1286. Xgetline(f, g, d, d2)
  1287. Xregister FILE *f;
  1288. Xchar *g, *d, *d2;
  1289. X{
  1290. X    register int c;
  1291. X    register char *s;
  1292. X
  1293. X    lineno++;
  1294. X    s = g;
  1295. X    while ((c = getc(f)) != ' ' && c != EOF)
  1296. X        *s++ = c;
  1297. X    *s = '\0';
  1298. X
  1299. X    if (c != EOF) {
  1300. X        s = d;
  1301. X        while ((c = getc(f)) != EOF && isdigit(c))
  1302. X            *s++ = c;
  1303. X        *s = '\0';
  1304. X
  1305. X        s = d2;
  1306. X        if (c == ' ')
  1307. X            while ((c = getc(f)) != EOF && isdigit(c))
  1308. X                *s++ = c;
  1309. X        *s = '\0';
  1310. X
  1311. X        if (c == ' ')
  1312. X            while ((c = getc(f)) != EOF && c != '\n')
  1313. X                ;        /* eat flag */
  1314. X    }
  1315. X
  1316. X    if (c != EOF && (c != '\n' || !*d || !*d2))
  1317. X        error("%s: bad format: line %d", actname, lineno);
  1318. X    return c != EOF;
  1319. X}
  1320. X
  1321. X
  1322. X/*
  1323. X * build internal active file structure
  1324. X */
  1325. Xactive *
  1326. Xreadactive()
  1327. X{
  1328. X    register FILE    *f;
  1329. X    register active    *ap, *last;
  1330. X    char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
  1331. X
  1332. X    alist = last = NIL(active);
  1333. X    f = fopenf(actname, "r");
  1334. X    lineno = 0;
  1335. X    while (getline(f, gbuf, dbuf, dbuf2)) {
  1336. X        ap = NEW(active);
  1337. X        ap->a_name = newstr(gbuf);
  1338. X        ap->a_seq = atoi(dbuf);
  1339. X        ap->a_low = atoi(dbuf2);
  1340. X        ap->a_next = NIL(active);
  1341. X        if (!alist)
  1342. X            alist = ap;
  1343. X        else
  1344. X            last->a_next = ap;
  1345. X        last = ap;
  1346. X    }
  1347. X    fclose(f);
  1348. X    return alist;
  1349. X}
  1350. X
  1351. X
  1352. X/*
  1353. X * return pointer to named group
  1354. X */
  1355. Xactive *
  1356. Xactivep(grp)
  1357. Xregister char *grp;
  1358. X{
  1359. X    register active    *ap;
  1360. X
  1361. X    for (ap = alist; ap; ap = ap->a_next)
  1362. X        if (CMP(grp, ap->a_name) == 0)
  1363. X            break;
  1364. X    return ap;
  1365. X}
  1366. X
  1367. X
  1368. X/*
  1369. X * setlow - set the low number for this group
  1370. X */
  1371. Xsetlow(group, low)
  1372. Xchar *group;
  1373. Xint low;
  1374. X{
  1375. X    register FILE    *f;
  1376. X    char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
  1377. X    extern char *itoa();
  1378. X
  1379. X    f = fopenl(actname);
  1380. X    lineno = 0;
  1381. X    while (getline(f, gbuf, dbuf, dbuf2))
  1382. X        if (CMP(gbuf, group) == 0) {
  1383. X            fseek(f, -6L, 1);
  1384. X            (void) fprintf(f, "%05d", low);
  1385. X            break;
  1386. X        }
  1387. X    fclose(f);
  1388. X#if !AUSAM
  1389. X    unlock(actname);
  1390. X#endif
  1391. X}
  1392. X
  1393. X
  1394. X
  1395. X/*
  1396. X * initgrp - initialise an entry for this group
  1397. X */
  1398. Xinitgrp(group)
  1399. Xchar *group;
  1400. X{
  1401. X    register FILE    *f;
  1402. X    char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
  1403. X
  1404. X    f = fopenl(actname);
  1405. X    lineno = 0;
  1406. X    while (getline(f, gbuf, dbuf, dbuf2))
  1407. X        if (CMP(gbuf, group) == 0) {
  1408. X#if !AUSAM
  1409. X            unlock(actname);
  1410. X#endif
  1411. X            return;
  1412. X        }
  1413. X    (void) fprintf(f, "%s 00000 00001\n", group);
  1414. X
  1415. X}
  1416. !
  1417. echo 'rna/at.h':
  1418. sed 's/^X//' >'rna/at.h' <<'!'
  1419. X#define SECINWEEK    604800L
  1420. X#define SECINDAY     86400L
  1421. X#define SECINHOUR      3600L
  1422. X#define SECINMIN        60L
  1423. X#define    DAYSTO1983    (10*365 + 3*366)
  1424. X#define MAXTIME        0x7fffffffL
  1425. X
  1426. X/*
  1427. X * frequencies
  1428. X */
  1429. X#define HOURLY        1
  1430. X#define DAILY        2
  1431. X#define WEEKLY        3
  1432. X#define MONTHLY        4
  1433. X#define BOOT        5
  1434. X#define BATCHTIME    6    /* not really a frequency - just looks like one */
  1435. X
  1436. X/*
  1437. X * time types recognised
  1438. X */
  1439. X#define DAYS        0    /* days only */
  1440. X#define TIMES        1    /* days, times */
  1441. X#define FULL        2    /* days, times, frequencies */
  1442. X#define STIMES        3    /* days, times - be silent about errors */
  1443. !
  1444. echo 'rna/defs.h':
  1445. sed 's/^X//' >'rna/defs.h' <<'!'
  1446. X#include <sys/types.h>
  1447. X#include <sys/stat.h>
  1448. X#include <sys/dir.h>
  1449. X#include <stdio.h>
  1450. X#include <ctype.h>
  1451. X#include <time.h>
  1452. X#ifdef USG
  1453. X#include <fcntl.h>
  1454. X#endif
  1455. X#include <signal.h>
  1456. X#include <sgtty.h>
  1457. X#include "at.h"
  1458. X
  1459. X#define NEWSVERSION     "B UNSW 1.1 19 Sep 1984"
  1460. X
  1461. X/* Things that very well may require local configuration */
  1462. X
  1463. X#define TIMEZONE    "EST"        /* name of time zone */
  1464. X
  1465. X#define DFLTSUB "general,general.all"    /* default subscription list    */
  1466. X#define    ADMSUB    "general"        /* Mandatory subscription list */
  1467. X#define MODGROUPS "mod.all,all.mod,all.announce"    /* Moderated groups */
  1468. X#define DFLTGRP    "general"        /* default newsgroup (for postnews) */
  1469. X/* #define MANGRPS     1        /* if you have mandatory subscriptions
  1470. X                       tailored per-person (uses
  1471. X                       getclasses()) */
  1472. X/*#define OZ    1*/            /* if on Australian network, used
  1473. X                       in readnews to get correct return
  1474. X                       address */
  1475. X/*#define AUSAM    1*/            /* hashed passwd file, locked files */
  1476. X#if AUSAM
  1477. X#include <passwd.h>
  1478. X#else
  1479. X#include <pwd.h>
  1480. X#endif
  1481. X
  1482. X#ifdef vax
  1483. X/* #define NETPATH    1        /* if you have path finding program
  1484. X                       /bin/netpath */
  1485. X#endif
  1486. X/*#define UNSWMAIL 1*/            /* if you have UNSW "mail" which
  1487. X                       allows "-s subject -i include_file"
  1488. X                       arguments */
  1489. X#define NETID "utzoo"
  1490. X#ifndef NETID
  1491. X#define NETID "utstat"            /* else define it here */
  1492. X#endif
  1493. X
  1494. X#ifndef NETID
  1495. X#include <table.h>            /* UNSW only */
  1496. X#endif
  1497. X
  1498. X/* #define MC "/usr/bin/p"            /* pager */
  1499. X#define UUNAME "/usr/bin/uuname"
  1500. X#define RNEWS    "exec rnews"        /* rnews for uurec to fork */
  1501. X#define POSTNEWS "/usr/bin/inews"
  1502. X#define CHOWN    "/etc/chown"        /* pathname of chown command */
  1503. X#define SHELL    "/bin/sh"        /* if not bourne shell see postnews.c */
  1504. X#define MKDIR    "/bin/mkdir"
  1505. X#define MAIL    "/bin/mail"
  1506. X#if UNSWMAIL
  1507. X#define FASTMAIL    "/bin/mail"
  1508. X#else
  1509. X#define FASTMAIL    MAIL
  1510. X#endif
  1511. X
  1512. X#define HELP    "/usr/lib/news/help.readnews"        /* Help text */
  1513. X#define SEQ    "/usr/lib/news/seq"        /* Next sequence number */
  1514. X#define SYS    "/usr/lib/news/sys"        /* System subscription lists */
  1515. X#define ACTIVE    "/usr/lib/news/active"        /* Active newsgroups */
  1516. X#define HISTORY "/usr/lib/news/history"        /* Current articles */
  1517. X
  1518. X#define MYDOMAIN "uucp"            /* Local domain */
  1519. X#define MYORG    "U of Toronto Zoology" /* My organization */
  1520. X#define NEWSROOT "news"            /* news editor */
  1521. X
  1522. X/* Things you might want to change */
  1523. X
  1524. X#define NEWSRC  ".newsrc"        /* name of .newsrc file */
  1525. X#define    PAGESIZE 24            /* lines on screen */
  1526. X#define ARTICLES "articles"        /* default place to save articles */
  1527. X#define NEGCHAR    '!'            /* newsgroup negation character    */
  1528. X#define NEGS    "!"            /* ditto (string) */
  1529. X#define BADGRPCHARS "/#!"        /* illegal chars in group name */
  1530. X#define BUFLEN    256            /* standard buffer size */
  1531. X#define ED    "/bin/ed"        /* default, if $EDITOR not set */
  1532. X
  1533. X/* Things you probably won't want to change */
  1534. X
  1535. X#define    NGSEPCHAR ','    /* delimit character in news group line        */
  1536. X#define NGSEPS    ","    /* ditto */
  1537. X#define PSEPS "!"    /* separator in Path: */
  1538. X#define PSEPCHAR '!'    /* ditto */
  1539. X#define PATHPREF "..!"    /* prefix for addresses worked out from Path: */
  1540. X#define TRUE    1
  1541. X#define FALSE    0
  1542. X
  1543. X#ifndef F_SETFD
  1544. X#ifdef F_SETFL
  1545. X#define F_SETFD F_SETFL        /* SETFL becomes SETFD (close on exec arg
  1546. X                   to fcntl) */
  1547. X#endif
  1548. X#endif
  1549. X
  1550. Xtypedef enum booltype { false = 0, true } bool;
  1551. Xtypedef enum applytype { stop, next, nextgroup, searchgroup } applycom;
  1552. Xtypedef applycom (*apcmfunc)();
  1553. Xtypedef enum pheadtype { printing, passing, making } pheadcom;
  1554. X
  1555. X/*
  1556. X * header structure
  1557. X */
  1558. Xtypedef struct header {
  1559. X    /* mandatory fields */
  1560. X    char    *h_relayversion;
  1561. X    char    *h_postversion;
  1562. X    char    *h_from;
  1563. X    char    *h_date;
  1564. X    char    *h_newsgroups;
  1565. X    char    *h_subject;
  1566. X    char    *h_messageid;
  1567. X    char    *h_path;
  1568. X    /* optional fields */
  1569. X    char    *h_replyto;
  1570. X    char    *h_sender;
  1571. X    char    *h_followupto;
  1572. X    char    *h_datereceived;
  1573. X    char    *h_expires;
  1574. X    char    *h_references;
  1575. X    char    *h_control;
  1576. X    char    *h_distribution;
  1577. X    char    *h_organisation;
  1578. X    char    *h_lines;
  1579. X    /* any we don't recognise */
  1580. X    char    *h_others;
  1581. X} header;
  1582. X
  1583. X/*
  1584. X * internal structure for active file
  1585. X */
  1586. Xtypedef struct active active;
  1587. Xstruct active {
  1588. X    char    *a_name;
  1589. X    short    a_seq;
  1590. X    short    a_low;
  1591. X    active    *a_next;
  1592. X};
  1593. X
  1594. X/*
  1595. X * internal struct for newsrc file
  1596. X */
  1597. Xtypedef struct newsrc newsrc;
  1598. Xstruct newsrc {
  1599. X    char    *n_name;
  1600. X    bool    n_subscribe;
  1601. X    short    n_last;
  1602. X    newsrc    *n_next;
  1603. X};
  1604. X
  1605. Xchar    *strrchr(), *strchr(), *strcat(), *strcpy(), *strpbrk();
  1606. Xchar    *itoa(), *convg(), *ngsquash(), *ttoa(), *mgets(), *rconvg();
  1607. Xchar    *newstr(), *newstr2(), *newstr3(), *newstr4(), *newstr5(), *catstr();
  1608. Xchar    *catstr2(), *bsearch(), *mtempnam(), *newstr6();
  1609. Xchar    *getunique(), *getretaddr(), *getsubject();
  1610. XFILE    *fopenl(), *fopenf();
  1611. Xchar    *memset(), *myalloc(), *myrealloc();
  1612. Xlong    time(), atol(), atot();
  1613. Xint    strpcmp();
  1614. Xactive    *readactive();
  1615. Xchar *getenv();
  1616. X
  1617. X#define NIL(type)    ((type *) 0)
  1618. X#define NEW(type)    ((type *) myalloc(sizeof(type)))
  1619. X#define CMP(a, b)    (*(a) != *(b) ? *(a) - *(b) : strcmp(a, b))
  1620. X#define CMPN(a, b, n)    (*(a) != *(b) ? *(a) - *(b) : strncmp(a, b, n))
  1621. X
  1622. X/* bw 9/15/84 */
  1623. X#define uid_t int
  1624. X#define index strchr
  1625. X#define rindex strrchr
  1626. !
  1627. echo 'rna/funcs.c':
  1628. sed 's/^X//' >'rna/funcs.c' <<'!'
  1629. X#include "defs.h"
  1630. X
  1631. X/*
  1632. X * string handling functions
  1633. X */
  1634. Xchar *
  1635. Xmyalloc(size)
  1636. Xint size;
  1637. X{
  1638. X    register char *cp;
  1639. X
  1640. X    extern char *malloc();
  1641. X
  1642. X    if ((cp = malloc((unsigned) size)) == NIL(char))
  1643. X        error("No more memory.");
  1644. X    return cp;
  1645. X}
  1646. X
  1647. X
  1648. Xchar *
  1649. Xmyrealloc(ptr, size)
  1650. Xchar *ptr;
  1651. Xint size;
  1652. X{
  1653. X    register char *cp;
  1654. X
  1655. X    extern char *realloc();
  1656. X
  1657. X    if ((cp = realloc(ptr, (unsigned) size)) == NIL(char))
  1658. X        error("No more memory.");
  1659. X    return cp;
  1660. X}
  1661. X
  1662. X
  1663. Xchar *
  1664. Xnewstr(s)
  1665. Xchar *s;
  1666. X{
  1667. X    return strcpy(myalloc(strlen(s) + 1), s);
  1668. X}
  1669. X
  1670. X
  1671. Xchar *
  1672. Xnewstr2(s1, s2)
  1673. Xchar *s1, *s2;
  1674. X{
  1675. X    return strcat(strcpy(myalloc(strlen(s1) + strlen(s2) + 1), s1), s2);
  1676. X}
  1677. X
  1678. X
  1679. Xchar *
  1680. Xnewstr3(s1, s2, s3)
  1681. Xchar *s1, *s2, *s3;
  1682. X{
  1683. X    return strcat(strcat(strcpy(myalloc(strlen(s1) + strlen(s2) + strlen(s3) +
  1684. X        1), s1), s2), s3);
  1685. X}
  1686. X
  1687. X
  1688. Xchar *
  1689. Xnewstr4(s1, s2, s3, s4)
  1690. Xchar *s1, *s2, *s3, *s4;
  1691. X{
  1692. X    return strcat(strcat(strcat(strcpy(myalloc(strlen(s1) + strlen(s2) +
  1693. X        strlen(s3) + strlen(s4) + 1), s1), s2), s3), s4);
  1694. X}
  1695. X
  1696. X
  1697. Xchar *
  1698. Xnewstr5(s1, s2, s3, s4, s5)
  1699. Xchar *s1, *s2, *s3, *s4, *s5;
  1700. X{
  1701. X    return strcat(strcat(strcat(strcat(strcpy(myalloc(strlen(s1) + strlen(s2) +
  1702. X        strlen(s3) + strlen(s4) + strlen(s5) + 1), s1), s2), s3), s4), s5);
  1703. X}
  1704. X
  1705. X
  1706. Xchar *
  1707. Xnewstr6(s1, s2, s3, s4, s5, s6)
  1708. Xchar *s1, *s2, *s3, *s4, *s5, *s6;
  1709. X{
  1710. X    return strcat(strcat(strcat(strcat(strcat(strcpy(myalloc(strlen(s1) +
  1711. X        strlen(s2) + strlen(s3) + strlen(s4) + strlen(s5) + strlen(s6) + 1),
  1712. X         s1), s2), s3), s4), s5), s6);
  1713. X}
  1714. X
  1715. X
  1716. Xchar *
  1717. Xcatstr(old, s)
  1718. Xchar *old, *s;
  1719. X{
  1720. X    return strcat(myrealloc(old, strlen(old) + strlen(s) + 1), s);
  1721. X}
  1722. X
  1723. X
  1724. Xchar *
  1725. Xcatstr2(old, s1, s2)
  1726. Xchar *old, *s1, *s2;
  1727. X{
  1728. X    return strcat(strcat(myrealloc(old, strlen(old) + strlen(s1) + strlen(s2) +
  1729. X        1), s1), s2);
  1730. X}
  1731. X
  1732. X
  1733. X/*
  1734. X * News group matching.
  1735. X *
  1736. X * nglist is a list of newsgroups.
  1737. X * sublist is a list of subscriptions.
  1738. X * sublist may have "meta newsgroups" in it.
  1739. X * All fields are NGSEPCHAR separated.
  1740. X *
  1741. X * sublist uses "all" like shell uses "*", and "." like shell uses "/"
  1742. X * if subscription X matches Y, it also matches Y.anything
  1743. X */
  1744. Xngmatch(nglist, sublist)
  1745. Xchar *nglist, *sublist;
  1746. X{
  1747. X    register char *n, *s, *nd, *sd;
  1748. X    register int rc;
  1749. X
  1750. X    rc = 0;
  1751. X    n = nglist;
  1752. X    while (*n && rc == 0) {
  1753. X        if (nd = strchr(n, NGSEPCHAR))
  1754. X            *nd = '\0';
  1755. X        s = sublist;
  1756. X        while (*s) {
  1757. X            if (sd = strchr(s, NGSEPCHAR))
  1758. X                *sd = '\0';
  1759. X            if (*s != NEGCHAR)
  1760. X                rc |= ptrncmp(s, n);
  1761. X            else
  1762. X                rc &= ~ptrncmp(s + 1, n);
  1763. X            if (sd)
  1764. X                *sd = NGSEPCHAR, s = sd + 1;
  1765. X            else
  1766. X                break;
  1767. X        }
  1768. X        if (nd)
  1769. X            *nd = NGSEPCHAR, n = nd + 1;
  1770. X        else
  1771. X            break;
  1772. X    }
  1773. X    return rc;
  1774. X}
  1775. X
  1776. X
  1777. X/*
  1778. X * Compare two newsgroups for equality.
  1779. X * The first one may be a "meta" newsgroup.
  1780. X */
  1781. Xstatic
  1782. Xptrncmp(ng1, ng2)
  1783. Xregister char *ng1, *ng2;
  1784. X{
  1785. X
  1786. X    while (1) {
  1787. X        if (ng1[0] == 'a' && ng1[1] == 'l' && ng1[2] == 'l' && (ng1[3] ==
  1788. X            '\0' || ng1[3] == '.')) {
  1789. X            if (ng1[3] == '\0')    /* "all" matches anything */
  1790. X                return 1;
  1791. X            while (*ng2 && *ng2 != '.')
  1792. X                ng2++;
  1793. X            if (*ng2 != '.')        /* "all." doesn't match "xx" */
  1794. X                return 0;
  1795. X            ng1 += 4, ng2++;
  1796. X            continue;
  1797. X        }
  1798. X        while (*ng1 && *ng1 != '.' && *ng1 == *ng2)
  1799. X            ng1++, ng2++;
  1800. X        if (*ng1 == '.') {
  1801. X            if (*ng2 != '.' && *ng2 != '\0')
  1802. X                return 0;    /* "."'s don't line up */
  1803. X            if (*ng2)
  1804. X                ng2++;
  1805. X            ng1++;            /* "."'s line up - keep going */
  1806. X        } else if (*ng1 == '\0')
  1807. X            return (*ng2 == '\0' || *ng2 == '.');
  1808. X            /* full match or X matching X.thing */
  1809. X        else
  1810. X            return 0;
  1811. X    }
  1812. X    /* NOTREACHED */
  1813. X}
  1814. X
  1815. X
  1816. X/*
  1817. X * return new newsgroup composed of only those from 'nglist'
  1818. X * subscribed to by 'sublist'
  1819. X * return NULL for empty list
  1820. X */
  1821. Xchar *
  1822. Xngsquash(nglist, sublist)
  1823. Xregister char *nglist, *sublist;
  1824. X{
  1825. X    register char *delim;
  1826. X    register char *newg;
  1827. X
  1828. X    newg = NIL(char);
  1829. X    while (*nglist) {
  1830. X        if (delim = strchr(nglist, NGSEPCHAR))
  1831. X            *delim = '\0';
  1832. X        if (ngmatch(nglist, sublist))
  1833. X            newg = (newg ? catstr2(newg, NGSEPS, nglist) : newstr(nglist));
  1834. X        if (delim)
  1835. X            *delim = NGSEPCHAR, nglist = delim + 1;
  1836. X        else
  1837. X            break;
  1838. X    }
  1839. X    return newg;
  1840. X}
  1841. X
  1842. X
  1843. X/*
  1844. X * get unique sequence number from SEQ
  1845. X */
  1846. Xchar *
  1847. Xgetunique()
  1848. X{
  1849. X    register long number;
  1850. X    register FILE    *f;
  1851. X    static char buf[12];
  1852. X
  1853. X    f = fopenl(SEQ);
  1854. X    if (fread(buf, 1, sizeof(buf), f) > 0)
  1855. X        number = atol(buf);
  1856. X    else
  1857. X        number = 1;
  1858. X
  1859. X    rewind(f);
  1860. X    (void) fprintf(f, "%ld\n", number + 1);
  1861. X    fclose(f);
  1862. X#if !AUSAM
  1863. X    unlock(SEQ);
  1864. X#endif
  1865. X
  1866. X    sprintf(buf, "%ld", number);
  1867. X    return buf;
  1868. X}
  1869. X
  1870. X
  1871. X/*
  1872. X * open a locked file (or create) for reading and writing
  1873. X */
  1874. XFILE *
  1875. Xfopenl(fname)
  1876. Xchar *fname;
  1877. X{
  1878. X    register FILE    *f;
  1879. X#ifdef AUSAM
  1880. X    struct stat sbuf;
  1881. X#endif
  1882. X
  1883. X    extern uid_t    newsuid;
  1884. X
  1885. X    if ((f = fopen(fname, "r+")) == NIL(FILE) && (f = fopen(fname, "w+")) ==
  1886. X        NIL(FILE))
  1887. X        error("Can't open %s", fname);
  1888. X
  1889. X#if AUSAM
  1890. X    if (fstat(fileno(f), &sbuf) != 0)
  1891. X        error("Can't stat %s", fname);
  1892. X    if ((sbuf.st_mode & S_IFMT) != S_IFALK && (chmod(fname, (int) (sbuf.st_mode
  1893. X        &~S_IFMT) | S_IFALK) != 0 || chown(fname, (int) newsuid, (int) newsuid) !=
  1894. X        0 || fclose(f) == EOF || (f = fopen(fname, "r+")) == NIL(FILE)))
  1895. X        error("Can't create %s", fname);
  1896. X#else
  1897. X    chown(fname, (int) newsuid, (int) newsuid);
  1898. X    lock(fname);
  1899. X#endif
  1900. X
  1901. X    return f;
  1902. X}
  1903. X
  1904. X
  1905. X#if !AUSAM
  1906. X
  1907. X#define LSUFFIX    ".lock"        /* suffix for lock files */
  1908. X
  1909. Xlock(fname)
  1910. Xchar *fname;
  1911. X{
  1912. X    register char *lname;
  1913. X    register int i, f;
  1914. X
  1915. X    lname = newstr2(fname, LSUFFIX);
  1916. X    for (i = 0; i < 10; i++) {
  1917. X        if ((f = creat(lname, 0)) != -1) {
  1918. X            close(f);
  1919. X            free(lname);
  1920. X            return;
  1921. X        }
  1922. X        sleep(2);
  1923. X    }
  1924. X    error("Can't creat %s after %d tries", lname, i);
  1925. X}
  1926. X
  1927. X
  1928. Xunlock(fname)
  1929. Xchar *fname;
  1930. X{
  1931. X    register char *lname;
  1932. X
  1933. X    lname = newstr2(fname, LSUFFIX);
  1934. X    unlink(lname);
  1935. X    free(lname);
  1936. X}
  1937. X
  1938. X
  1939. X#endif
  1940. X
  1941. X/*
  1942. X * open a file
  1943. X */
  1944. XFILE *
  1945. Xfopenf(name, mode)
  1946. Xchar *name, *mode;
  1947. X{
  1948. X    register FILE    *f;
  1949. X
  1950. X    if ((f = fopen(name, mode)) == NIL(FILE))
  1951. X        error("Can't %s %s", *mode == 'r' ? "open" : "create", name);
  1952. X    return f;
  1953. X}
  1954. X
  1955. X
  1956. X/*
  1957. X * replace all '.''s with '/'
  1958. X */
  1959. Xchar *
  1960. Xconvg(s)
  1961. Xregister char *s;
  1962. X{
  1963. X    register char *sav;
  1964. X
  1965. X    sav = s;
  1966. X    while (s = strchr(s, '.'))
  1967. X        *s = '/';
  1968. X    return sav;
  1969. X}
  1970. X
  1971. X
  1972. X/*
  1973. X * replace all '/''s with '.'
  1974. X */
  1975. Xchar *
  1976. Xrconvg(s)
  1977. Xregister char *s;
  1978. X{
  1979. X    register char *sav;
  1980. X
  1981. X    sav = s;
  1982. X    while (s = strchr(s, '/'))
  1983. X        *s = '.';
  1984. X    return sav;
  1985. X}
  1986. X
  1987. X
  1988. X/*
  1989. X * get a line from stdin
  1990. X * trim leading and trailing blanks
  1991. X */
  1992. Xchar *
  1993. Xmgets()
  1994. X{
  1995. X    register char *s;
  1996. X    static char buf[BUFSIZ];
  1997. X
  1998. X    fflush(stdout);
  1999. X    if (fgets(buf, sizeof(buf), stdin) == NIL(char)) {
  2000. X        (void) printf("\n");
  2001. X        return NIL(char);
  2002. X    }
  2003. X    if (s = strchr(buf, '\n'))
  2004. X        while (isspace(*s) && s > buf)
  2005. X            *s-- = '\0';
  2006. X    else
  2007. X     {
  2008. X        (void) printf("Input line too long.\n");
  2009. X        return NIL(char);
  2010. X    }
  2011. X    s = buf;
  2012. X    while (isspace(*s))
  2013. X        s++;
  2014. X    return s;
  2015. X}
  2016. X
  2017. X
  2018. Xreadln(f)
  2019. XFILE *f;
  2020. X{
  2021. X    register int c;
  2022. X
  2023. X    if (feof(f) || ferror(f))
  2024. X        return;
  2025. X    while ((c = getc(f)) != '\n' && c != EOF)
  2026. X        ;
  2027. X}
  2028. X
  2029. X
  2030. X/*
  2031. X * compare string pointers
  2032. X */
  2033. Xstrpcmp(a, b)
  2034. Xchar **a, **b;
  2035. X{
  2036. X    return CMP(*a, *b);
  2037. X}
  2038. X
  2039. X
  2040. X/*
  2041. X * apply the given function to each member in the newsgroup
  2042. X */
  2043. X/* VARARGS2 */
  2044. Xapplyng(ng, func, arg1)
  2045. Xregister char *ng;
  2046. Xregister int (*func)();
  2047. Xchar *arg1;
  2048. X{
  2049. X    register char *delim;
  2050. X    register int err;
  2051. X
  2052. X    err = 0;
  2053. X    while (*ng) {
  2054. X        if (delim = strchr(ng, NGSEPCHAR))
  2055. X            *delim = '\0';
  2056. X        err += (*func)(ng, arg1);
  2057. X        if (delim)
  2058. X            *delim = NGSEPCHAR, ng = delim + 1;
  2059. X        else
  2060. X            break;
  2061. X    }
  2062. X    return err;
  2063. X}
  2064. X
  2065. X
  2066. X/*
  2067. X * generate a return address
  2068. X */
  2069. Xchar *
  2070. Xgetretaddr(hp)
  2071. Xheader *hp;
  2072. X{
  2073. X    register char *ra;
  2074. X
  2075. X    extern char *getpath(), *exaddress();
  2076. X#ifdef NETPATH
  2077. X    extern char *getnetpath();
  2078. X#endif
  2079. X
  2080. X    if (hp->h_replyto)
  2081. X        ra = exaddress(hp->h_replyto);
  2082. X    else if (hp->h_from)
  2083. X        ra = exaddress(hp->h_from);
  2084. X    else
  2085. X        ra = NIL(char);
  2086. X    if (hp->h_path && !ra)
  2087. X        ra = getpath(hp->h_path);
  2088. X#ifdef NETPATH
  2089. X    if (CMPN(ra, PATHPREF, sizeof(PATHPREF) - 1) == 0)
  2090. X        ra = getnetpath(ra);
  2091. X#endif
  2092. X    return ra;
  2093. X}
  2094. X
  2095. X
  2096. X/*
  2097. X * try and make a proper address
  2098. X */
  2099. Xchar *
  2100. Xexaddress(addr)
  2101. Xchar *addr;
  2102. X{
  2103. X    register char *space, *dot, *at;
  2104. X    register char *raddr;
  2105. X
  2106. X    raddr = NIL(char);
  2107. X    if (space = strchr(addr, ' '))
  2108. X        *space = '\0';
  2109. X    if (at = strchr(addr, '@')) {
  2110. X        *at = '\0';
  2111. X        if (dot = strchr(at + 1, '.')) {
  2112. X            *dot = '\0';
  2113. X#if OZ
  2114. X            if (CMP(dot + 1, MYDOMAIN) == 0)
  2115. X                raddr = newstr3(addr, ":", at + 1);
  2116. X            else
  2117. X#endif
  2118. X                raddr = newstr4(PATHPREF, at + 1, PSEPS, addr);
  2119. X            *dot = '.';
  2120. X        }
  2121. X        *at = '@';
  2122. X    }
  2123. X    if (space)
  2124. X        *space = ' ';
  2125. X    return raddr;
  2126. X
  2127. X}
  2128. X
  2129. X
  2130. X/*
  2131. X * return the last two components of the path
  2132. X */
  2133. Xchar *
  2134. Xgetpath(path)
  2135. Xchar *path;
  2136. X{
  2137. X    register char *exlast, *ex;
  2138. X    register char *raddr;
  2139. X
  2140. X    if (exlast = strrchr(path, PSEPCHAR)) {
  2141. X        *exlast = '\0';
  2142. X        if (ex = strrchr(path, PSEPCHAR))
  2143. X            raddr = newstr4(PATHPREF, ex + 1, PSEPS, exlast + 1);
  2144. X        else
  2145. X            raddr = newstr3(path, PSEPS, exlast + 1);
  2146. X        *exlast = PSEPCHAR;
  2147. X    } else
  2148. X        raddr = NIL(char);
  2149. X    return raddr;
  2150. X}
  2151. X
  2152. X
  2153. X#ifdef NETPATH
  2154. X/*
  2155. X * try and work out a path from our "netpath" database
  2156. X */
  2157. Xchar *
  2158. Xgetnetpath(path)
  2159. Xchar *path;
  2160. X{
  2161. X    FILE         * f;
  2162. X    register char *ex1, *ex2, *com, *new;
  2163. X    char buf[BUFSIZ];
  2164. X
  2165. X    if ((ex1 = strchr(path, PSEPCHAR)) && (ex2 = strchr(ex1 + 1, PSEPCHAR))) {
  2166. X        *ex2 = '\0';
  2167. X        com = newstr4("exec ", NETPATH, " mulga ", ex1 + 1);
  2168. X        if ((f = popen(com, "r")) == NIL(FILE))
  2169. X            (void) printf("Couldn't run \"%s\"\n", com);
  2170. X        else
  2171. X         {
  2172. X            fread(buf, sizeof(buf), 1, f);
  2173. X            if (pclose(f) != 0) {
  2174. X                (void) printf("Error in running \"%s\"\n", com);
  2175. X                fflush(stdout);
  2176. X            } else if (CMPN(buf, "mulga!", 6) == 0) {
  2177. X                if (ex1 = strchr(buf, '\n'))
  2178. X                    *ex1 = '\0';
  2179. X                new = newstr4(buf + 6, PSEPS, ex2 + 1, ":mulga");
  2180. X                free(path);
  2181. X                path = new;
  2182. X            }
  2183. X        }
  2184. X        free(com);
  2185. X        *ex2 = PSEPCHAR;
  2186. X    }
  2187. X    return path;
  2188. X
  2189. X}
  2190. X
  2191. X
  2192. X#endif
  2193. X
  2194. X/*
  2195. X * remove extra spaces, and insert separators if necessary in
  2196. X * newsgroups specification
  2197. X */
  2198. Xconvgrps(sp)
  2199. Xregister char *sp;
  2200. X{
  2201. X    register char *sep;
  2202. X
  2203. X    sep = NIL(char);
  2204. X    while (*sp) {
  2205. X        if (sep)
  2206. X            sp++;
  2207. X        while (*sp && (isspace(*sp) || *sp == NGSEPCHAR))
  2208. X            strcpy(sp, sp + 1);
  2209. X        if (sep)
  2210. X            *sep = (*sp ? NGSEPCHAR : '\0');
  2211. X        while (*sp && !isspace(*sp) && *sp != NGSEPCHAR)
  2212. X            sp++;
  2213. X        sep = sp;
  2214. X    }
  2215. X}
  2216. X
  2217. X
  2218. !
  2219. echo done
  2220.  
  2221.  
  2222.