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

  1. Subject:  v19i096:  Cnews production release, Part19/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 96
  8. Archive-name: cnews2/part19
  9.  
  10. : ---CUT HERE---
  11. echo 'rna/readnews.c':
  12. sed 's/^X//' >'rna/readnews.c' <<'!'
  13. X/*
  14. X * readnews
  15. X *
  16. X *    Michael Rourke (UNSW) April 1984
  17. X */
  18. X
  19. X#include "defs.h"
  20. X
  21. X#define ARTSEP "/"
  22. X
  23. Xchar postnews[]     = POSTNEWS;
  24. Xchar admsub[]     = ADMSUB;
  25. Xchar dfltsub[]     = DFLTSUB;
  26. Xchar *mailpath     = MAIL;
  27. X
  28. X#define    MAXARGV    10        /* used in building argv[]s below */
  29. X
  30. X#ifndef NETID
  31. Xchar systemid[DIRSIZ];
  32. X#else
  33. Xchar systemid[] = NETID;
  34. X#endif
  35. X
  36. Xbool iflag;        /* -i ignore .newsrc */
  37. Xbool lflag;        /* -l print headers only */
  38. Xbool cflag;        /* -c check for news only */
  39. Xbool pflag;        /* -p print everything selected */
  40. Xchar **uflag;        /* -u messagid (unsubscribe from followups) */
  41. Xint usize;        /* number of uflag entries */
  42. Xbool Cflag;        /* -C verbose -c */
  43. Xbool sflag;        /* -s print newsgroup subscription list */
  44. Xbool splus;        /* -s+ */
  45. Xbool slistall;        /* -s? */
  46. Xbool sminus;        /* -s- */
  47. Xchar *sarg;        /* arg to -s[+-] */
  48. Xchar *nflag;        /* -n newsgroups */
  49. Xextern char *rcgrps;    /* -n newsgroups from newsrc file */
  50. Xbool n_on_cline;    /* nflag set on command line */
  51. X
  52. Xextern newsrc    *rc;        /* internal .newsrc */
  53. X
  54. Xactive *alist;        /* internal active list */
  55. X
  56. X#if MANGRPS
  57. Xchar *mangrps;    /* mandatory subsciption list */
  58. X#endif
  59. X
  60. X#if AUSAM
  61. Xstruct pwent pe;        /* current user passwd struct */
  62. Xchar sbuf[SSIZ];    /* passwd strings */
  63. X#else
  64. Xstruct passwd *pp;        /* current user passwd struct */
  65. X#endif
  66. Xlong now;        /* current time */
  67. Xbool interrupt;        /* if interrupt hit */
  68. Xchar *newsdir;        /* %news */
  69. Xuid_t newsuid;        /* %news uid (not used) */
  70. Xbool su;        /* if super user (not used) */
  71. X
  72. Xapplycom list(), check(), commands();
  73. Xvoid *onintr();
  74. Xbool ureject(), seen(), subs(), subsub();
  75. X
  76. X#if MANGRPS
  77. Xchar *getmangrps();
  78. X#endif
  79. X
  80. Xmain(argc, argv)
  81. Xint argc;
  82. Xchar *argv[];
  83. X{
  84. X    char buf[BUFSIZ], *p;
  85. X
  86. X    setbuf(stdout, buf);            /* TODO: remove this? */
  87. X    if (options(--argc, ++argv, true)) {
  88. X        (void) fprintf(stderr, "Usage: readnews [-n newsgroups] [-i] [-clpC] [-s[-+? [group]]] [-u messageid]\n");
  89. X        exit(1);
  90. X    }
  91. X    now = time(&now);
  92. X
  93. X#if AUSAM
  94. X    pe.pw_strings[LNAME] = NEWSROOT;
  95. X    if (getpwuid(&pe, sbuf, sizeof(sbuf)) == PWERROR)
  96. X        error("Password file error.");
  97. X    newsdir = newstr(pe.pw_strings[DIRPATH]);
  98. X    newsuid = pe.pw_limits.l_uid;
  99. X#else
  100. X    if ((pp = getpwnam(NEWSROOT)) == NULL)
  101. X        error("Password file error.");
  102. X    newsdir = newstr(pp->pw_dir);
  103. X    newsuid = pp->pw_uid;
  104. X#endif
  105. X
  106. X#if AUSAM
  107. X#if MANGRPS
  108. X    pe.pw_limits.l_uid = getuid();
  109. X    if (getpwlog(&pe, NIL(char), 0) == PWERROR)    /* want pw_cmask */
  110. X        error("Password file error.");
  111. X#endif
  112. X    pwclose();
  113. X#else
  114. X    pp = NIL(struct passwd );
  115. X    endpwent();
  116. X#endif
  117. X
  118. X#ifndef NETID
  119. X    getaddr(G_SYSNAME, systemid);
  120. X#endif
  121. X
  122. X    if (!iflag)
  123. X        readnewsrc();
  124. X
  125. X    if (nflag)
  126. X        convgrps(nflag);
  127. X    else
  128. X        nflag = dfltsub;
  129. X    if (rcgrps)
  130. X        convgrps(rcgrps);
  131. X    if (!n_on_cline) {
  132. X#if MANGRPS
  133. X        int addsub();
  134. X
  135. X        if (mangrps = getmangrps(pe.pw_cmask))
  136. X            applyng(mangrps, addsub, &nflag);
  137. X#endif
  138. X        if (!ngmatch(admsub, nflag))
  139. X            nflag = newstr3(admsub, NGSEPS, nflag);
  140. X    }
  141. X    if ((int) sflag + (int) lflag + (int) cflag + (int) pflag > 1)
  142. X        error("-clpsC flags are mutually exclusive.");
  143. X    if (uflag)
  144. X        qsort((char *) uflag, (unsigned) usize, sizeof(char *), strpcmp);
  145. X
  146. X    /* user has private mailer? */
  147. X    if ((p = getenv("MAILER")) != NULL)
  148. X        mailpath = newstr(p);
  149. X
  150. X    alist = readactive();
  151. X
  152. X    if (sflag) {
  153. X        if (subs() && !iflag)
  154. X            writenewsrc(alist);
  155. X    } else if (lflag)
  156. X        apply(alist, nflag, list, false);
  157. X    else if (cflag)
  158. X        apply(alist, nflag, check, false);
  159. X    else {
  160. X        if (!pflag) {
  161. X            if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  162. X                (void) signal(SIGINT, onintr);
  163. X            if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  164. X                (void) signal(SIGQUIT, onintr);
  165. X        }
  166. X        apply(alist, nflag, commands, true);
  167. X        if (!iflag)
  168. X            writenewsrc(alist);
  169. X    }
  170. X    exit(0);
  171. X}
  172. X
  173. X#if MANGRPS
  174. X/*
  175. X * make a subscription list of all class groups the user belongs too
  176. X * (mandatory subscription)
  177. X */
  178. Xchar *
  179. Xgetmangrps(cmask)
  180. Xchar *cmask;
  181. X{
  182. X    static char *weekday[] = { 
  183. X        "mon", "tue", "wed", "thu", "fri"     };
  184. X    register char **classes;
  185. X    register char *s, *end;
  186. X    register char *grp;
  187. X    register int i, size;
  188. X    extern char **getclasses();
  189. X
  190. X    grp = NIL(char);
  191. X    if ((classes = getclasses(cmask)) == NIL(char *))
  192. X        error("Can't get classes.");
  193. X    while (*classes) {
  194. X        if (isdigit(**classes)) {
  195. X            /*
  196. X             * trim string after numeric class
  197. X             * if it is a day of the week
  198. X             */
  199. X            s = *classes;
  200. X            while (isdigit(*s) || *s == '.')
  201. X                s++;
  202. X            if (*s) {
  203. X                end = s;
  204. X                while (isalpha(*end))
  205. X                    end++;
  206. X                if (*end && end != s && end - s <= 3) {
  207. X                    size = end - s;
  208. X                    for (i = 0; i < 5; i++)
  209. X                        if (CMPN(s, weekday[i], size) == 0)
  210. X                            break;
  211. X                    if (i != 5)
  212. X                        *s = '\0';
  213. X                }
  214. X            }
  215. X        }
  216. X        grp = (grp? catstr2(grp, ",class.", *classes):
  217. X            newstr2("class.", *classes));
  218. X        classes++;
  219. X    }
  220. X    return grp;
  221. X}
  222. X
  223. X/*
  224. X * if newsgroup "ng" isn't subscribed to, add it to subscription list
  225. X */
  226. Xaddsub(ng, slist)
  227. Xchar *ng;
  228. Xchar **slist;
  229. X{
  230. X    if (!ngmatch(ng, *slist))
  231. X        *slist = newstr3(ng, NGSEPS, *slist);
  232. X}
  233. X
  234. X#endif
  235. X
  236. Xvoid *
  237. Xonintr()
  238. X{
  239. X    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  240. X        (void) signal(SIGINT, onintr);
  241. X    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  242. X        (void) signal(SIGQUIT, onintr);
  243. X    interrupt = true;
  244. X}
  245. X
  246. X/*
  247. X * process options
  248. X * can be called from readnewsrc()
  249. X */
  250. Xoptions(argc, argv, cline)
  251. Xint argc;
  252. Xchar *argv[];
  253. Xbool cline;
  254. X{
  255. X    register char c;
  256. X
  257. X    /* TODO: use getopt(3) */
  258. X    while (argc > 0) {
  259. X        if (argv[0][0] != '-')
  260. X            break;
  261. X        while (c = *(++(argv[0]))) {
  262. X            switch (c) {
  263. X            case 'n':
  264. X                if (cline)
  265. X                    nflag = argv[1], n_on_cline = true;
  266. X                else {
  267. X                    if (!n_on_cline)
  268. X                        nflag = (nflag?
  269. X                            catstr2(nflag, NGSEPS, argv[1]):
  270. X                            newstr(argv[1]));
  271. X                    rcgrps = (rcgrps?
  272. X                        catstr2(rcgrps, NGSEPS, argv[1]):
  273. X                        newstr(argv[1]));
  274. X                }
  275. X                argc--, argv++; 
  276. X                break;
  277. X            case 'u':
  278. X                usize++;
  279. X                uflag = (uflag? (char **)myrealloc((char *)uflag,
  280. X                        (int)sizeof(char *) * usize):
  281. X                    (char **)myalloc((int)sizeof(char *)));
  282. X                uflag[usize - 1] = newstr(argv[1]);
  283. X                argc--, argv++; 
  284. X                break;
  285. X            case 'i':
  286. X                iflag = true; 
  287. X                continue;
  288. X            case 's':
  289. X                sflag = true;
  290. X                switch (argv[0][1]) {
  291. X                case '\0':
  292. X                    continue;
  293. X                case '+':
  294. X                    splus = true; 
  295. X                    break;
  296. X                case '?':
  297. X                    slistall = true, ++(argv[0]); 
  298. X                    continue;
  299. X                case '-':
  300. X                    sminus = true; 
  301. X                    break;
  302. X                default:
  303. X                    argc = -1; 
  304. X                    break;
  305. X                }
  306. X                if (argc > 0) {
  307. X                    sarg = newstr(argv[1]);
  308. X                    argc--, argv++;
  309. X                }
  310. X                break;
  311. X            case 'p':
  312. X                pflag = true; 
  313. X                continue;
  314. X            case 'l':
  315. X                lflag = true; 
  316. X                continue;
  317. X            case 'c':
  318. X                cflag = true; 
  319. X                continue;
  320. X            case 'C':
  321. X                cflag = Cflag = true; 
  322. X                continue;
  323. X            default:
  324. X                argc = -1; 
  325. X                break;
  326. X            }
  327. X            break;
  328. X        }
  329. X        argc--, argv++;
  330. X    }
  331. X    return argc != 0;
  332. X}
  333. X
  334. X/*
  335. X * subscription list handling
  336. X * return true if newsrc is to be re-written
  337. X */
  338. Xbool
  339. Xsubs()
  340. X{
  341. X    register newsrc    *np;
  342. X    register active    *ap;
  343. X    register char *tmp, *com;
  344. X    register FILE *f;
  345. X
  346. X    if (slistall) {
  347. X        (void) printf("Active newsgroups:\n");
  348. X        (void) fflush(stdout);
  349. X#ifdef    MC            /* gok. probably a local paginator */
  350. X        com = newstr2("exec ", MC);
  351. X        if ((f = popen(com, "w")) == NULL)
  352. X            f = stdout;
  353. X        free(com);
  354. X#else
  355. X        f = stdout;
  356. X        com = 0;        /* for lint */
  357. X        com = com;        /* for lint */
  358. X#endif
  359. X        for (ap = alist; ap; ap = ap->a_next)
  360. X            (void) fprintf(f, "%s\n", ap->a_name);
  361. X#ifdef    MC
  362. X        if (f != stdout)
  363. X            pclose(f);
  364. X#endif
  365. X        return false;
  366. X    } else if (splus || sminus) {
  367. X        if (strpbrk(sarg, BADGRPCHARS)) {
  368. X            (void) printf("%s: Illegal char in newsgroup.\n", sarg);
  369. X            return false;
  370. X        }
  371. X        if (ngmatch(sarg, nflag)) {
  372. X            /*
  373. X             * normally we subscribe, check for an exclusion
  374. X             */
  375. X            for (np = rc; np; np = np->n_next)
  376. X                if (CMP(sarg, np->n_name) == 0)
  377. X                    break;
  378. X            if (np) {
  379. X                /*
  380. X                 * altering subscribe flag is all
  381. X                 * we need to change
  382. X                 */
  383. X                np->n_subscribe = splus;
  384. X                return true;
  385. X            }
  386. X            if (sminus) {
  387. X                /*
  388. X                 * try deleting from sub list
  389. X                 */
  390. X                if (subsub(sarg, rcgrps))
  391. X                    return true;
  392. X                /*
  393. X                 * add specific exclusion
  394. X                 */
  395. X                rcgrps = newstr4(rcgrps, NGSEPS, NEGS, sarg);
  396. X                return true;
  397. X            }
  398. X        } else if (splus) {
  399. X            /*
  400. X             * we don't subscribe,
  401. X             * try deleting !sarg first
  402. X             */
  403. X            tmp = newstr2(NEGS, sarg);
  404. X            subsub(tmp, rcgrps);
  405. X            if (!ngmatch(sarg, rcgrps))
  406. X                /*
  407. X                 * didn't work, so add explicit subscription
  408. X                 */
  409. X                rcgrps = rcgrps? newstr3(rcgrps, NGSEPS, sarg):
  410. X                    newstr(sarg);
  411. X            return true;
  412. X        }
  413. X    } else {
  414. X        (void) printf("Subscription list: %s", nflag);
  415. X        for (np = rc; np; np = np->n_next)
  416. X            if (!np->n_subscribe && ngmatch(np->n_name, nflag))
  417. X                (void) printf(",!%s", np->n_name);
  418. X        (void) printf("\n");
  419. X    }
  420. X    return false;
  421. X}
  422. X
  423. X
  424. X/*
  425. X * try and delete group from subscription list
  426. X * return true if successful
  427. X */
  428. Xbool
  429. Xsubsub(grp, slist)
  430. Xchar *grp;
  431. Xchar *slist;
  432. X{
  433. X    register char *delim;
  434. X
  435. X    while (*slist) {
  436. X        if (delim = strchr(slist, NGSEPCHAR))
  437. X            *delim = '\0';
  438. X        if (CMP(grp, slist) == 0) {
  439. X            if (delim)
  440. X                (void) strcpy(slist, delim + 1);
  441. X            else if (slist[-1] = ',')
  442. X                slist[-1] = '\0';
  443. X            else
  444. X                slist[0] = '\0';
  445. X            return true;
  446. X        }
  447. X        if (delim)
  448. X            *delim = NGSEPCHAR, slist = delim + 1;
  449. X        else
  450. X            break;
  451. X    }
  452. X    return false;
  453. X}
  454. X
  455. X/*
  456. X * list titles command (-l)
  457. X */
  458. Xapplycom
  459. Xlist(ap, np)
  460. Xactive *ap;
  461. Xnewsrc *np;
  462. X{
  463. X    static active *lastap;
  464. X    static bool first = true;
  465. X    register char *fname;
  466. X    register FILE *f;
  467. X    header h;
  468. X    ino_t ino;
  469. X
  470. X    np->n_last++;
  471. X    fname = convg(newstr5(newsdir, "/", ap->a_name, ARTSEP,
  472. X        itoa(np->n_last)));
  473. X    ino = 0;
  474. X    f = fopen(fname, "r");
  475. X    free(fname);
  476. X    if (!f || seen(f, &ino))
  477. X        return next;
  478. X    gethead(f, &h);
  479. X    if (uflag && h.h_references && ureject(&h)) {
  480. X        freehead(&h);
  481. X        return next;
  482. X    }
  483. X    if (first) {
  484. X        (void) printf("News articles:\n");
  485. X        first = false;
  486. X    }
  487. X    if (lastap != ap)
  488. X        (void) printf("  %s:\n", ap->a_name);
  489. X    lastap = ap;
  490. X    (void) printf("    %-4d %s\n", np->n_last, h.h_subject);
  491. X    (void) fclose(f);
  492. X    freehead(&h);
  493. X    if (ino)
  494. X        seen(NIL(FILE), &ino);
  495. X    return next;
  496. X}
  497. X
  498. X/*
  499. X * check command (-c or -C)
  500. X */
  501. Xapplycom
  502. Xcheck(ap, np)
  503. Xactive *ap;
  504. Xnewsrc *np;
  505. X{
  506. X    static bool done;
  507. X    register int num;
  508. X
  509. X    np->n_last++;
  510. X    if (Cflag) {
  511. X        if (!done)
  512. X            (void) printf("You have news:\n");
  513. X        done = true;
  514. X        num = ap->a_seq - np->n_last + 1;
  515. X        (void) printf("\t%s at most %d article%s\n",
  516. X            ap->a_name, num, (num > 1? "s": ""));
  517. X        return nextgroup;
  518. X    } else {
  519. X        (void) printf("You have news.\n");
  520. X        exit(0);
  521. X        /* NOTREACHED */
  522. X    }
  523. X}
  524. X
  525. X
  526. X/*
  527. X * normal command handler (or pflag)
  528. X * commands:
  529. X *
  530. X * \n         print current article
  531. X * n         go to next article
  532. X * q        quit
  533. X * c        cancel
  534. X * r        reply
  535. X * m [person]    mail
  536. X * f         followup
  537. X * p         postnews
  538. X * N [newsgrp]    next newsgroup
  539. X * s [file]    save
  540. X * u        unsubscribe from followup
  541. X * U        unsubscribe from group
  542. X * !stuff    shell escape
  543. X * number or .    go to number
  544. X * -         back to previous article (toggle)
  545. X * x        quick exit
  546. X * h        long header info
  547. X * H        full header
  548. X *
  549. X * inside r, f or p:
  550. X *    .e    edit
  551. X *    .i    interpolate
  552. X *    . or EOT terminate message
  553. X *    .!comd    shell escape
  554. X */
  555. Xapplycom
  556. Xcommands(ap, np, last, pushed)
  557. Xactive *ap;
  558. Xnewsrc *np;
  559. Xbool last;
  560. Xbool pushed;
  561. X{
  562. X    static char errmess[] = "Incorrect command; Type `?' for help.\n";
  563. X    static char form[]    = "%s: %s\n";
  564. X
  565. X    static char savedsys[BUFSIZ / 2];
  566. X    static active    *lastap, *rlastap;
  567. X    static newsrc    lastn;
  568. X    static char number[20];
  569. X    static active    *wantap;
  570. X
  571. X    register char *com, *arg;
  572. X    register int c, i, size;
  573. X    register FILE     *f;
  574. X    char *fname;
  575. X    header        h;
  576. X    newsrc        ntmp;
  577. X    ino_t        ino;
  578. X    bool printed, pheader, verbose, hadinterrupt;
  579. X    applycom    nextact;
  580. X
  581. X    extern char t_from[], t_subject[], t_date[];
  582. X    extern char t_newsgroups[], t_path[], t_sender[];
  583. X    extern char t_replyto[], t_organization[];
  584. X    extern char *strncpy();
  585. X    extern active    *activep();
  586. X
  587. X
  588. X    if (last) {
  589. X        /*
  590. X         * give user one last chance to
  591. X         * see this article
  592. X         */
  593. X        ap = rlastap;
  594. X        np = &lastn;
  595. X        wantap = NIL(active);
  596. X        if (!ap || pflag)
  597. X            return stop;
  598. X    } else if (wantap)
  599. X        /*
  600. X         * doing an "n newsgroup" command
  601. X         */
  602. X        if (wantap != ap)
  603. X            return nextgroup;
  604. X        else
  605. X            wantap = NIL(active);
  606. X
  607. X    fname = convg(newstr5(newsdir, "/", ap->a_name, ARTSEP,
  608. X        itoa(np->n_last + 1)));
  609. X    f = fopen(fname, "r");
  610. X    ino = 0;
  611. X    if (!f || !last && !pushed && seen(f, &ino)) {
  612. X        if (pushed)
  613. X            (void) printf("Article %d (%s) no longer exists.\n",
  614. X                np->n_last + 1, ap->a_name);
  615. X        else
  616. X            np->n_last++;
  617. X        if (f)
  618. X            (void) fclose(f);
  619. X        free(fname);
  620. X        return next;
  621. X    }
  622. X
  623. X    gethead(f, &h);
  624. X    if (!pushed && uflag && h.h_references && ureject(&h)) {
  625. X        /* unsubscribed followup */
  626. X        freehead(&h);
  627. X        np->n_last++;
  628. X        (void) fclose(f);
  629. X        free(fname);
  630. X        return next;
  631. X    }
  632. X
  633. X    (void) printf("\n");
  634. X    interrupt = hadinterrupt = verbose = false;
  635. X    if (last) {
  636. X        (void) printf("No more articles.\n");
  637. X        printed = pheader = true;
  638. X    } else
  639. X        printed = pheader = false;
  640. X
  641. X    while (1) {
  642. X        if (lastap != ap) {
  643. X            size = strlen(ap->a_name) + sizeof("Newsgroup");
  644. X            for (i = 0; i < size; i++)
  645. X                (void) putc('-', stdout);
  646. X            (void) printf("\nNewsgroup %s\n", ap->a_name);
  647. X            for (i = 0; i < size; i++)
  648. X                (void) putc('-', stdout);
  649. X            (void) printf("\n\n");
  650. X        }
  651. X        lastap = ap;
  652. X        if (!pheader) {
  653. X            (void) printf("Article %d of %d (%s)",
  654. X                np->n_last + 1, ap->a_seq, ap->a_name);
  655. X            if (h.h_lines != 0)
  656. X                (void) printf(" (%s lines)", h.h_lines);
  657. X            (void) printf("\n");
  658. X            (void) printf(form, t_subject, h.h_subject);
  659. X            (void) printf(form, t_from, h.h_from);
  660. X            if (verbose || pflag) {
  661. X                (void) printf(form, t_date, h.h_date);
  662. X                (void) printf(form, t_newsgroups, h.h_newsgroups);
  663. X                (void) printf(form, t_path, h.h_path);
  664. X                if (h.h_sender)
  665. X                    (void) printf(form, t_sender, h.h_sender);
  666. X                if (h.h_replyto)
  667. X                    (void) printf(form, t_replyto, h.h_replyto);
  668. X                if (h.h_organisation)
  669. X                    (void) printf(form, t_organization, h.h_organisation);
  670. X                verbose = false;
  671. X            }
  672. X            pheader = true;
  673. X        }
  674. X        if (!pushed && number[0])
  675. X            /*
  676. X             * just returned from a number command
  677. X             * and have another to do
  678. X             */
  679. X            com = number;
  680. X        else if (pflag)
  681. X            /*
  682. X             * just print it
  683. X             */
  684. X            com = "";
  685. X        else
  686. X         {
  687. X            (void) printf("? ");
  688. X            if (fflush(stdout) == EOF) {
  689. X                (void) printf("\n? ");
  690. X                (void) fflush(stdout);
  691. X            }
  692. X            interrupt = false;
  693. X            if ((com = mgets()) == NIL(char)) {
  694. X                if (interrupt)
  695. X                    if (!hadinterrupt) {
  696. X                        clearerr(stdin);
  697. X                        (void) printf("Interrupt\n");
  698. X                        hadinterrupt = true;
  699. X                        interrupt = false;
  700. X                        continue;
  701. X                    }
  702. X                    else
  703. X                        exit(1);
  704. X                nextact = stop;
  705. X                break;
  706. X            }
  707. X            hadinterrupt = false;
  708. X        }
  709. X        if (*com == '!') {
  710. X            if (com[1] == '!') {
  711. X                (void) printf("!%s\n", savedsys);
  712. X                com = savedsys;
  713. X            } else
  714. X                com++;
  715. X            (void) fflush(stdout);
  716. X#ifdef F_SETFD
  717. X            (void) fcntl(fileno(f), F_SETFD, 1);    /* close on exec */
  718. X#endif
  719. X            (void) system(com);
  720. X            if (com != savedsys)
  721. X                strncpy(savedsys, com, sizeof(savedsys) - 1);
  722. X            (void) printf("!\n");
  723. X            if (!printed)
  724. X                pheader = false;
  725. X            continue;
  726. X        }
  727. X        /*
  728. X         * check command syntax
  729. X         */
  730. X        if (*com && !isdigit(*com) && com[1] && (!isspace(com[1]) ||
  731. X            strchr("Nsm", *com) == NULL)) {
  732. X            (void) printf(errmess);
  733. X            continue;
  734. X        }
  735. X        if (c = *com) {
  736. X            arg = com;
  737. X            while (isspace(*++arg))
  738. X                ;
  739. X        } else
  740. X            arg = NULL;
  741. X        switch (c) {
  742. X        case 0:
  743. X        case '.':
  744. X            if (!printed || c == '.') {
  745. X                if (pflag)
  746. X                    (void) printf("\n");
  747. X                print(&h, f);
  748. X                if (pflag) {
  749. X                    nextact = next;
  750. X                    break;
  751. X                }
  752. X                printed = true;
  753. X                continue;
  754. X            }
  755. X        case 'n':            /* B compatible */
  756. X        case '+':
  757. X        case ';':
  758. X            nextact = next;
  759. X            break;
  760. X        case '?':
  761. X            help();
  762. X            continue;
  763. X        case 'c':
  764. X            cancelarticle(&h);
  765. X            continue;
  766. X        case 'r':
  767. X            reply(&h, fname);
  768. X            continue;
  769. X        case 'm':
  770. X            if (!arg || !*arg)
  771. X                (void) printf("Person argument missing.\n");
  772. X            else
  773. X                mail(&h, fname, arg);
  774. X            continue;
  775. X        case 'f':
  776. X            followup(&h, fname);
  777. X            continue;
  778. X        case 'p':
  779. X            pnews(fname);
  780. X            continue;
  781. X        case 'U':
  782. X            if (ngmatch(np->n_name, ADMSUB)
  783. X#if MANGRPS
  784. X             || ngmatch(np->n_name, mangrps))
  785. X#else
  786. X                )
  787. X#endif
  788. X                 {
  789. X                    (void) printf("Group \"%s\" can't be unsubscribed.\n",
  790. X                                              np->n_name);
  791. X                    continue;
  792. X                }
  793. X            np->n_subscribe = false;
  794. X            nextact = nextgroup;
  795. X            break;
  796. X        case 'u':
  797. X            unsubscribe(h.h_references);
  798. X            nextact = next;
  799. X            break;
  800. X        case 'N':            /* B compatible */
  801. X            if (!*arg) {
  802. X                nextact = nextgroup;
  803. X                break;
  804. X            }
  805. X            if ((wantap = activep(arg)) == NIL(active)) {
  806. X                (void) printf("%s: non-existent newsgroup.\n", arg);
  807. X                continue;
  808. X            }
  809. X            if (!ngmatch(arg, nflag)) {
  810. X                (void) printf("%s: is not subscribed to!\n", arg);
  811. X                wantap = NIL(active);
  812. X                continue;
  813. X            }
  814. X            nextact = searchgroup;
  815. X            break;
  816. X        case 's':
  817. X            save(&h, f, arg);
  818. X            continue;
  819. X        case 'q':
  820. X            nextact = stop;
  821. X            break;
  822. X        case 'x':
  823. X            exit(0);
  824. X        case 'h':
  825. X            verbose = true;
  826. X            pheader = false;
  827. X            continue;
  828. X        case 'H':
  829. X            puthead(&h, stdout, printing);
  830. X            continue;
  831. X        case '-':
  832. X            if (pushed) {
  833. X                nextact = next;
  834. X                break;
  835. X            }
  836. X            if (!rlastap || !lastn.n_name) {
  837. X                (void) printf("Can't go back!\n");
  838. X                continue;
  839. X            }
  840. X            nextact = commands(rlastap, &lastn, false, true);
  841. X            /*
  842. X             * number commands, after a "-" act on the
  843. X             * group of the "-" command
  844. X             */
  845. X            while (number[0]) {
  846. X                ntmp = lastn;
  847. X                ntmp.n_last = atoi(number) - 1;
  848. X                number[0] = '\0';
  849. X                nextact = commands(rlastap, &ntmp, false, true);
  850. X            }
  851. X            if (nextact != next)
  852. X                break;
  853. X            (void) printf("\n");
  854. X            pheader = false;
  855. X            continue;
  856. X        default:
  857. X            if (isdigit(c)) {
  858. X                i = c - '0';
  859. X                while (isdigit(*arg))
  860. X                    i = i * 10 + *arg++ - '0';
  861. X            }
  862. X            if (!isdigit(c) || *arg != '\0') {
  863. X                (void) printf(errmess);
  864. X                continue;
  865. X            }
  866. X            number[0] = '\0';
  867. X            if (i < ap->a_low || i > ap->a_seq) {
  868. X                (void) printf("Articles in \"%s\" group range %d to %d.\n",
  869. X                                         np->n_name, ap->a_low, ap->a_seq);
  870. X                continue;
  871. X            }
  872. X            if (pushed) {
  873. X                sprintf(number, "%d", i);
  874. X                nextact = next;
  875. X                break;
  876. X            }
  877. X            ntmp = *np;
  878. X            ntmp.n_last = i - 1;
  879. X            if ((nextact = commands(ap, &ntmp, false, true)) !=
  880. X                next)
  881. X                break;
  882. X            if (!number[0]) {
  883. X                (void) printf("\n");
  884. X                pheader = false;
  885. X            }
  886. X            continue;
  887. X        }
  888. X        break;
  889. X    }
  890. X    rlastap = ap;
  891. X    lastn = *np;
  892. X    if (!pushed && (nextact == next || printed)) {
  893. X        np->n_last++;
  894. X        if (ino)
  895. X            seen(NIL(FILE), &ino);
  896. X    }
  897. X    freehead(&h);
  898. X    (void) fclose(f);
  899. X    free(fname);
  900. X    return nextact;
  901. X}
  902. X
  903. X
  904. X/*
  905. X * see if this is a followup we are ignoring
  906. X */
  907. Xbool
  908. Xureject(hp)
  909. Xregister header *hp;
  910. X{
  911. X    register bool found;
  912. X    register char *rp, *ids, c;
  913. X    char *key[1];
  914. X
  915. X    found = false;
  916. X    rp = hp->h_references;
  917. X    while (*rp && !found) {
  918. X        if (ids = strpbrk(rp, " ,")) {
  919. X            c = *ids;
  920. X            *ids = '\0';
  921. X        }
  922. X        key[0] = rp;
  923. X        found = (bool) (bsearch((char *) key, (char *) uflag, (unsigned) usize,
  924. X             sizeof(char *), strpcmp) != NIL(char));
  925. X        if (ids)
  926. X            *ids = c, rp = ids + 1;
  927. X        else
  928. X            break;
  929. X        while (isspace(*rp) || *rp == ',')
  930. X            rp++;
  931. X    }
  932. X    return found;
  933. X}
  934. X
  935. X
  936. X/*
  937. X * see if the article has links, if so have we seen it?
  938. X * close file if we return true
  939. X *
  940. X * called twice,
  941. X *    first (with f set) to test (and possibly set *ino)
  942. X *    again to put *ino in memory
  943. X */
  944. Xbool
  945. Xseen(f, ino)
  946. XFILE *f;
  947. Xino_t *ino;
  948. X{
  949. X    static int num;
  950. X    static ino_t    *ilist;
  951. X    struct stat statb;
  952. X    register int i;
  953. X
  954. X    if (f) {
  955. X        if (fstat(fileno(f), &statb) != 0 || statb.st_nlink <= 1)
  956. X            return false;
  957. X        for (i = 0; i < num; i++)
  958. X            if (ilist[i] == statb.st_ino) {
  959. X                (void) fclose(f);
  960. X                return true;
  961. X            }
  962. X        *ino = statb.st_ino;
  963. X        return false;
  964. X    } else if (*ino) {
  965. X        num++;
  966. X        ilist = (ino_t * ) (ilist ? myrealloc((char *) ilist, (int) sizeof(ino_t) *
  967. X            num) : myalloc((int) sizeof(ino_t)));
  968. X        ilist[num - 1] = *ino;
  969. X    }
  970. X    return true;
  971. X}
  972. X
  973. X
  974. X/*
  975. X * print out help file
  976. X */
  977. Xhelp()
  978. X{
  979. X    register FILE    *f;
  980. X    register int c;
  981. X    static char helppath[]     = HELP;
  982. X
  983. X    if ((f = fopen(helppath, "r")) == NIL(FILE)) {
  984. X        (void) printf("Can't open %s\n", helppath);
  985. X        return;
  986. X    }
  987. X    while ((c = getc(f)) != EOF)
  988. X        (void) putc(c, stdout);
  989. X    (void) fclose(f);
  990. X}
  991. X
  992. X/*
  993. X * cancel an article.
  994. X * inews does permission checking.
  995. X */
  996. Xcancelarticle(hp)
  997. Xheader *hp;
  998. X{
  999. X    char *argv[MAXARGV];
  1000. X
  1001. X    argv[0] = strrchr(postnews, '/') + 1;
  1002. X    argv[1] = "-c";        /* TODO: no such option in C news */
  1003. X    argv[2] = newstr2("cancel ", hp->h_messageid);
  1004. X    argv[3] = "-n";
  1005. X    argv[4] = hp->h_newsgroups;
  1006. X    if (hp->h_distribution) {
  1007. X        argv[5] = "-d";
  1008. X        argv[6] = hp->h_distribution;
  1009. X        argv[7] = NIL(char);
  1010. X    } else
  1011. X        argv[5] = NIL(char);
  1012. X    run(postnews, argv, true);
  1013. X    free(argv[2]);
  1014. X}
  1015. X
  1016. X/*
  1017. X * reply to sender by mail
  1018. X */
  1019. X/* ARGSUSED fname */
  1020. Xreply(hp, fname)
  1021. Xheader *hp;
  1022. Xchar *fname;
  1023. X{
  1024. X    char *argv[MAXARGV];
  1025. X    register int argc;
  1026. X
  1027. X    argc = 0;
  1028. X    argv[argc++] = "mail";
  1029. X#ifdef UNSWMAIL
  1030. X    argv[argc++] = "-s";
  1031. X    if ((argv[argc++] = getsubject(hp)) == NIL(char))
  1032. X        return;
  1033. X    argv[argc++] = "-i";
  1034. X    argv[argc++] = fname;
  1035. X#endif
  1036. X
  1037. X    if ((argv[argc++] = getretaddr(hp)) == NIL(char)) {
  1038. X        (void) printf("Can't work out an address!\n");
  1039. X        return;
  1040. X    }
  1041. X
  1042. X    argv[argc++] = NIL(char);
  1043. X
  1044. X    run(mailpath, argv, false);
  1045. X
  1046. X    free(argv[argc - 2]);
  1047. X}
  1048. X
  1049. X
  1050. X/*
  1051. X * mail to person
  1052. X */
  1053. X/* ARGSUSED hp fname */
  1054. Xmail(hp, fname, person)
  1055. Xheader *hp;
  1056. Xchar *fname, *person;
  1057. X{
  1058. X    char *argv[MAXARGV];
  1059. X    register int argc;
  1060. X
  1061. X    argc = 0;
  1062. X    argv[argc++] = "mail";
  1063. X#ifdef UNSWMAIL
  1064. X    argv[argc++] = "-i";
  1065. X    argv[argc++] = fname;
  1066. X    argv[argc++] = "-s";
  1067. X    argv[argc++] = hp->h_subject;
  1068. X#endif
  1069. X    argv[argc++] = person;
  1070. X    argv[argc++] = NIL(char);
  1071. X
  1072. X    run(mailpath, argv, false);
  1073. X}
  1074. X
  1075. X
  1076. X/*
  1077. X * generate correct headers for a followup article
  1078. X * then call inews.
  1079. X */
  1080. Xfollowup(hp, fname)
  1081. Xheader *hp;
  1082. Xchar *fname;
  1083. X{
  1084. X    register int argc;
  1085. X    char *argv[10];
  1086. X
  1087. X    argc = 0;
  1088. X    argv[argc++] = strrchr(postnews, '/') + 1;
  1089. X    argv[argc++] = "-i";        /* TODO: what's this in B news? */
  1090. X    argv[argc++] = fname;
  1091. X    argv[argc++] = "-r";
  1092. X    if (hp->h_references && hp->h_messageid)
  1093. X        argv[argc++] = newstr3(hp->h_references, " ", hp->h_messageid);
  1094. X    else if (hp->h_messageid)
  1095. X        argv[argc++] = newstr(hp->h_messageid);
  1096. X    else
  1097. X        argc--;
  1098. X
  1099. X    argv[argc++] = "-s";
  1100. X    if ((argv[argc++] = getsubject(hp)) == NIL(char))
  1101. X        return;
  1102. X
  1103. X    argv[argc++] = "-n";
  1104. X    if (hp->h_followupto)
  1105. X        argv[argc++] = hp->h_followupto;
  1106. X    else
  1107. X        argv[argc++] = hp->h_newsgroups;
  1108. X    argv[argc++] = NIL(char);
  1109. X
  1110. X    run(postnews, argv, false);
  1111. X
  1112. X    if (argc == 10)
  1113. X        free(argv[4]);
  1114. X}
  1115. X
  1116. X/*
  1117. X * get correct "Subject: Re: .." line
  1118. X */
  1119. Xchar *
  1120. Xgetsubject(hp)
  1121. Xregister header *hp;
  1122. X{
  1123. X    register char *s;
  1124. X
  1125. X    if (!hp->h_subject) {
  1126. X        (void) printf("Subject: Re: ");
  1127. X        (void) fflush(stdout);
  1128. X        if ((s = mgets()) == NIL(char) || !*s) {
  1129. X            (void) printf("The Subject field is mandatory.\n");
  1130. X            return NIL(char);
  1131. X        }
  1132. X        return newstr2("Re: ", s);
  1133. X    } else if (CMPN(hp->h_subject, "Re: ", 4) != 0 && CMPN(hp->h_subject,
  1134. X         "re: ", 4) != 0)
  1135. X        return newstr2("Re: ", hp->h_subject);
  1136. X    else
  1137. X        return hp->h_subject;
  1138. X}
  1139. X
  1140. X
  1141. X/*
  1142. X * run a command, optionally closing stdin
  1143. X */
  1144. Xrun(com, argv, closein)
  1145. Xchar *com;
  1146. Xchar *argv[];
  1147. Xbool closein;
  1148. X{
  1149. X    int pid, status, r;
  1150. X
  1151. X    switch (pid = fork()) {
  1152. X    default:
  1153. X        /* parent */
  1154. X        break;
  1155. X    case 0:
  1156. X        /* child */
  1157. X        if (closein)
  1158. X            close(fileno(stdin));
  1159. X        execvp(com, argv);
  1160. X        error("can't exec %s", com);
  1161. X        exit(1);
  1162. X
  1163. X    case -1:
  1164. X        error("can't fork");
  1165. X    }
  1166. X
  1167. X    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  1168. X        (void) signal(SIGINT, SIG_IGN);
  1169. X    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  1170. X        (void) signal(SIGQUIT, SIG_IGN);
  1171. X
  1172. X    while ((r = wait(&status)) != pid && r != -1)
  1173. X        ;
  1174. X
  1175. X    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  1176. X        (void) signal(SIGINT, onintr);
  1177. X    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  1178. X        (void) signal(SIGQUIT, onintr);
  1179. X}
  1180. X
  1181. X/*
  1182. X * call postnews
  1183. X */
  1184. Xpnews(fname)
  1185. Xchar *fname;
  1186. X{
  1187. X    char *argv[MAXARGV];
  1188. X
  1189. X    argv[0] = strrchr(postnews, '/') + 1;
  1190. X    argv[1] = "-i";        /* TODO: what's this inews option? */
  1191. X    argv[2] = fname;
  1192. X    argv[3] = NIL(char);
  1193. X    run(postnews, argv, false);
  1194. X}
  1195. X
  1196. X/*
  1197. X * save an article
  1198. X */
  1199. Xsave(hp, f, s)
  1200. Xheader *hp;
  1201. XFILE *f;
  1202. Xchar *s;
  1203. X{
  1204. X    register long pos;
  1205. X    register int c;
  1206. X    register char *cp;
  1207. X    register FILE    *sf;
  1208. X    register char *aname;
  1209. X    long then;
  1210. X    extern char *getenv();
  1211. X
  1212. X    if (!*s) {
  1213. X        if ((aname = getenv("HOME")) == NIL(char)) {
  1214. X            (void) printf("No $HOME in environment.\n");
  1215. X            return;
  1216. X        }
  1217. X        s = aname = newstr3(aname, "/", ARTICLES);
  1218. X    } else
  1219. X        aname = NIL(char);
  1220. X    if ((sf = fopen(s, "a")) == NIL(FILE)) {
  1221. X        (void) fprintf(stderr, "readnews: can't open %s\n", s);
  1222. X        return;
  1223. X    }
  1224. X    if (aname)
  1225. X        free(aname);
  1226. X    pos = ftell(f);
  1227. X    rewind(f);
  1228. X    if (cp = strchr(hp->h_from, ' '))
  1229. X        *cp = '\0';
  1230. X    if (hp->h_date)
  1231. X        then = atot(hp->h_date);
  1232. X    else
  1233. X        then = 0L;
  1234. X    (void) fprintf(sf, "From %s %s", hp->h_from, ctime(then ? &then : &now));
  1235. X    if (cp)
  1236. X        *cp = ' ';
  1237. X    while ((c = getc(f)) != EOF)
  1238. X        (void) putc(c, sf);
  1239. X    (void) fclose(sf);
  1240. X    fseek(f, pos, 0);
  1241. X}
  1242. X
  1243. X
  1244. X/*
  1245. X * unsubscribe from all followup articles
  1246. X * on this topic
  1247. X */
  1248. Xunsubscribe(id)
  1249. Xchar *id;
  1250. X{
  1251. X    register char *s, c;
  1252. X
  1253. X    if (!id || !*id) {
  1254. X        (void) printf("no references! (warning)\n");
  1255. X        return;
  1256. X    }
  1257. X    while (*id) {
  1258. X        if (s = strpbrk(id, " ,")) {
  1259. X            c = *s;
  1260. X            *s = '\0';
  1261. X        }
  1262. X        usize++;
  1263. X        uflag = (uflag ? (char **) myrealloc((char *) uflag, (int) sizeof(char
  1264. X            *) * usize) : (char **) myalloc((int) sizeof(char *)));
  1265. X        uflag[usize - 1] = newstr(id);
  1266. X        if (s)
  1267. X            *s = c, id = s + 1;
  1268. X        else
  1269. X            break;
  1270. X        while (isspace(*id) || *id == ',')
  1271. X            id++;
  1272. X    }
  1273. X    qsort((char *) uflag, (unsigned) usize, sizeof(char *), strpcmp);
  1274. X}
  1275. X
  1276. X
  1277. X/*
  1278. X * print an article, if it's long enough call page()
  1279. X */
  1280. Xprint(hp, f)
  1281. Xheader *hp;
  1282. XFILE *f;
  1283. X{
  1284. X    register int c;
  1285. X    register long pos;
  1286. X
  1287. X    pos = ftell(f);
  1288. X    if (!pflag
  1289. X#ifdef LINESHDRPRESENT
  1290. X     && hp->h_lines && atoi(hp->h_lines) >= PAGESIZE - 4
  1291. X#endif
  1292. X     )
  1293. X        page(f);
  1294. X    else
  1295. X        while ((c = getc(f)) != EOF)
  1296. X            (void) putchar(c);
  1297. X    fseek(f, pos, 0);
  1298. X}
  1299. X
  1300. X
  1301. X/*
  1302. X * copy article text to stdout, and break into pages
  1303. X */
  1304. Xpage(f)
  1305. XFILE *f;
  1306. X{
  1307. X    register int c;
  1308. X    register unsigned lineno;
  1309. X    char lbuf[80];
  1310. X    struct sgttyb ttybuf;
  1311. X
  1312. X#ifdef USG
  1313. X    /* TODO: fill in USG code to turn off echo */
  1314. X#else
  1315. X    gtty(fileno(stdin), &ttybuf);
  1316. X    if (ttybuf.sg_flags & ECHO) {
  1317. X        ttybuf.sg_flags &= ~ECHO;
  1318. X        stty(fileno(stdin), &ttybuf);
  1319. X        ttybuf.sg_flags |= ECHO;
  1320. X    }
  1321. X#endif
  1322. X    lineno = 1;
  1323. X    while (!interrupt) {
  1324. X        for (; lineno < PAGESIZE - 4 && !interrupt; lineno++) {
  1325. X            while ((c = getc(f)) != EOF && c != '\n')
  1326. X                (void) putchar(c);
  1327. X            if (c == EOF)
  1328. X                goto fastexit;
  1329. X            if (lineno < PAGESIZE - 5)
  1330. X                (void) putchar('\n');
  1331. X        }
  1332. X        if (interrupt)
  1333. X            break;
  1334. X#ifdef moremess
  1335. X        (void) printf(moremess);
  1336. X#endif
  1337. X        if (fflush(stdout) == EOF)
  1338. X            break;
  1339. X        if (read(fileno(stdin), lbuf, sizeof(lbuf)) <= 0)
  1340. X            break;
  1341. X#ifdef moremess
  1342. X        (void) printf("\r%*s\r", sizeof(moremess), " ");
  1343. X#else
  1344. X        putchar('\n');
  1345. X#endif
  1346. X        lineno = 0;
  1347. X    }
  1348. X    if (lineno)
  1349. X        (void) putchar('\n');
  1350. X    interrupt = false;
  1351. Xfastexit:
  1352. X#ifdef USG
  1353. X    ;    /* TODO: fill in USG code to turn echo on */
  1354. X#else
  1355. X    if (ttybuf.sg_flags & ECHO)
  1356. X        stty(fileno(stdin), &ttybuf);
  1357. X#endif
  1358. X}
  1359. X
  1360. X/* VARARGS1 */
  1361. Xerror(s, a0, a1, a2, a3)
  1362. Xchar *s;
  1363. X{
  1364. X    (void) fprintf(stderr, "readnews: ");
  1365. X    (void) fprintf(stderr, s, a0, a1, a2, a3);
  1366. X    (void) fprintf(stderr, "\n");
  1367. X    exit(1);
  1368. X}
  1369. !
  1370. echo 'rna/checknews':
  1371. sed 's/^X//' >'rna/checknews' <<'!'
  1372. Xexec readnews -c
  1373. !
  1374. echo done
  1375.  
  1376.  
  1377.