home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume19
/
cnews2
/
part19
< prev
next >
Wrap
Text File
|
1989-06-29
|
28KB
|
1,377 lines
Subject: v19i096: Cnews production release, Part19/19
Newsgroups: comp.sources.unix
Sender: sources
Approved: rsalz@uunet.UU.NET
Submitted-by: utzoo!henry
Posting-number: Volume 19, Issue 96
Archive-name: cnews2/part19
: ---CUT HERE---
echo 'rna/readnews.c':
sed 's/^X//' >'rna/readnews.c' <<'!'
X/*
X * readnews
X *
X * Michael Rourke (UNSW) April 1984
X */
X
X#include "defs.h"
X
X#define ARTSEP "/"
X
Xchar postnews[] = POSTNEWS;
Xchar admsub[] = ADMSUB;
Xchar dfltsub[] = DFLTSUB;
Xchar *mailpath = MAIL;
X
X#define MAXARGV 10 /* used in building argv[]s below */
X
X#ifndef NETID
Xchar systemid[DIRSIZ];
X#else
Xchar systemid[] = NETID;
X#endif
X
Xbool iflag; /* -i ignore .newsrc */
Xbool lflag; /* -l print headers only */
Xbool cflag; /* -c check for news only */
Xbool pflag; /* -p print everything selected */
Xchar **uflag; /* -u messagid (unsubscribe from followups) */
Xint usize; /* number of uflag entries */
Xbool Cflag; /* -C verbose -c */
Xbool sflag; /* -s print newsgroup subscription list */
Xbool splus; /* -s+ */
Xbool slistall; /* -s? */
Xbool sminus; /* -s- */
Xchar *sarg; /* arg to -s[+-] */
Xchar *nflag; /* -n newsgroups */
Xextern char *rcgrps; /* -n newsgroups from newsrc file */
Xbool n_on_cline; /* nflag set on command line */
X
Xextern newsrc *rc; /* internal .newsrc */
X
Xactive *alist; /* internal active list */
X
X#if MANGRPS
Xchar *mangrps; /* mandatory subsciption list */
X#endif
X
X#if AUSAM
Xstruct pwent pe; /* current user passwd struct */
Xchar sbuf[SSIZ]; /* passwd strings */
X#else
Xstruct passwd *pp; /* current user passwd struct */
X#endif
Xlong now; /* current time */
Xbool interrupt; /* if interrupt hit */
Xchar *newsdir; /* %news */
Xuid_t newsuid; /* %news uid (not used) */
Xbool su; /* if super user (not used) */
X
Xapplycom list(), check(), commands();
Xvoid *onintr();
Xbool ureject(), seen(), subs(), subsub();
X
X#if MANGRPS
Xchar *getmangrps();
X#endif
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X char buf[BUFSIZ], *p;
X
X setbuf(stdout, buf); /* TODO: remove this? */
X if (options(--argc, ++argv, true)) {
X (void) fprintf(stderr, "Usage: readnews [-n newsgroups] [-i] [-clpC] [-s[-+? [group]]] [-u messageid]\n");
X exit(1);
X }
X now = time(&now);
X
X#if AUSAM
X pe.pw_strings[LNAME] = NEWSROOT;
X if (getpwuid(&pe, sbuf, sizeof(sbuf)) == PWERROR)
X error("Password file error.");
X newsdir = newstr(pe.pw_strings[DIRPATH]);
X newsuid = pe.pw_limits.l_uid;
X#else
X if ((pp = getpwnam(NEWSROOT)) == NULL)
X error("Password file error.");
X newsdir = newstr(pp->pw_dir);
X newsuid = pp->pw_uid;
X#endif
X
X#if AUSAM
X#if MANGRPS
X pe.pw_limits.l_uid = getuid();
X if (getpwlog(&pe, NIL(char), 0) == PWERROR) /* want pw_cmask */
X error("Password file error.");
X#endif
X pwclose();
X#else
X pp = NIL(struct passwd );
X endpwent();
X#endif
X
X#ifndef NETID
X getaddr(G_SYSNAME, systemid);
X#endif
X
X if (!iflag)
X readnewsrc();
X
X if (nflag)
X convgrps(nflag);
X else
X nflag = dfltsub;
X if (rcgrps)
X convgrps(rcgrps);
X if (!n_on_cline) {
X#if MANGRPS
X int addsub();
X
X if (mangrps = getmangrps(pe.pw_cmask))
X applyng(mangrps, addsub, &nflag);
X#endif
X if (!ngmatch(admsub, nflag))
X nflag = newstr3(admsub, NGSEPS, nflag);
X }
X if ((int) sflag + (int) lflag + (int) cflag + (int) pflag > 1)
X error("-clpsC flags are mutually exclusive.");
X if (uflag)
X qsort((char *) uflag, (unsigned) usize, sizeof(char *), strpcmp);
X
X /* user has private mailer? */
X if ((p = getenv("MAILER")) != NULL)
X mailpath = newstr(p);
X
X alist = readactive();
X
X if (sflag) {
X if (subs() && !iflag)
X writenewsrc(alist);
X } else if (lflag)
X apply(alist, nflag, list, false);
X else if (cflag)
X apply(alist, nflag, check, false);
X else {
X if (!pflag) {
X if (signal(SIGINT, SIG_IGN) != SIG_IGN)
X (void) signal(SIGINT, onintr);
X if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
X (void) signal(SIGQUIT, onintr);
X }
X apply(alist, nflag, commands, true);
X if (!iflag)
X writenewsrc(alist);
X }
X exit(0);
X}
X
X#if MANGRPS
X/*
X * make a subscription list of all class groups the user belongs too
X * (mandatory subscription)
X */
Xchar *
Xgetmangrps(cmask)
Xchar *cmask;
X{
X static char *weekday[] = {
X "mon", "tue", "wed", "thu", "fri" };
X register char **classes;
X register char *s, *end;
X register char *grp;
X register int i, size;
X extern char **getclasses();
X
X grp = NIL(char);
X if ((classes = getclasses(cmask)) == NIL(char *))
X error("Can't get classes.");
X while (*classes) {
X if (isdigit(**classes)) {
X /*
X * trim string after numeric class
X * if it is a day of the week
X */
X s = *classes;
X while (isdigit(*s) || *s == '.')
X s++;
X if (*s) {
X end = s;
X while (isalpha(*end))
X end++;
X if (*end && end != s && end - s <= 3) {
X size = end - s;
X for (i = 0; i < 5; i++)
X if (CMPN(s, weekday[i], size) == 0)
X break;
X if (i != 5)
X *s = '\0';
X }
X }
X }
X grp = (grp? catstr2(grp, ",class.", *classes):
X newstr2("class.", *classes));
X classes++;
X }
X return grp;
X}
X
X/*
X * if newsgroup "ng" isn't subscribed to, add it to subscription list
X */
Xaddsub(ng, slist)
Xchar *ng;
Xchar **slist;
X{
X if (!ngmatch(ng, *slist))
X *slist = newstr3(ng, NGSEPS, *slist);
X}
X
X#endif
X
Xvoid *
Xonintr()
X{
X if (signal(SIGINT, SIG_IGN) != SIG_IGN)
X (void) signal(SIGINT, onintr);
X if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
X (void) signal(SIGQUIT, onintr);
X interrupt = true;
X}
X
X/*
X * process options
X * can be called from readnewsrc()
X */
Xoptions(argc, argv, cline)
Xint argc;
Xchar *argv[];
Xbool cline;
X{
X register char c;
X
X /* TODO: use getopt(3) */
X while (argc > 0) {
X if (argv[0][0] != '-')
X break;
X while (c = *(++(argv[0]))) {
X switch (c) {
X case 'n':
X if (cline)
X nflag = argv[1], n_on_cline = true;
X else {
X if (!n_on_cline)
X nflag = (nflag?
X catstr2(nflag, NGSEPS, argv[1]):
X newstr(argv[1]));
X rcgrps = (rcgrps?
X catstr2(rcgrps, NGSEPS, argv[1]):
X newstr(argv[1]));
X }
X argc--, argv++;
X break;
X case 'u':
X usize++;
X uflag = (uflag? (char **)myrealloc((char *)uflag,
X (int)sizeof(char *) * usize):
X (char **)myalloc((int)sizeof(char *)));
X uflag[usize - 1] = newstr(argv[1]);
X argc--, argv++;
X break;
X case 'i':
X iflag = true;
X continue;
X case 's':
X sflag = true;
X switch (argv[0][1]) {
X case '\0':
X continue;
X case '+':
X splus = true;
X break;
X case '?':
X slistall = true, ++(argv[0]);
X continue;
X case '-':
X sminus = true;
X break;
X default:
X argc = -1;
X break;
X }
X if (argc > 0) {
X sarg = newstr(argv[1]);
X argc--, argv++;
X }
X break;
X case 'p':
X pflag = true;
X continue;
X case 'l':
X lflag = true;
X continue;
X case 'c':
X cflag = true;
X continue;
X case 'C':
X cflag = Cflag = true;
X continue;
X default:
X argc = -1;
X break;
X }
X break;
X }
X argc--, argv++;
X }
X return argc != 0;
X}
X
X/*
X * subscription list handling
X * return true if newsrc is to be re-written
X */
Xbool
Xsubs()
X{
X register newsrc *np;
X register active *ap;
X register char *tmp, *com;
X register FILE *f;
X
X if (slistall) {
X (void) printf("Active newsgroups:\n");
X (void) fflush(stdout);
X#ifdef MC /* gok. probably a local paginator */
X com = newstr2("exec ", MC);
X if ((f = popen(com, "w")) == NULL)
X f = stdout;
X free(com);
X#else
X f = stdout;
X com = 0; /* for lint */
X com = com; /* for lint */
X#endif
X for (ap = alist; ap; ap = ap->a_next)
X (void) fprintf(f, "%s\n", ap->a_name);
X#ifdef MC
X if (f != stdout)
X pclose(f);
X#endif
X return false;
X } else if (splus || sminus) {
X if (strpbrk(sarg, BADGRPCHARS)) {
X (void) printf("%s: Illegal char in newsgroup.\n", sarg);
X return false;
X }
X if (ngmatch(sarg, nflag)) {
X /*
X * normally we subscribe, check for an exclusion
X */
X for (np = rc; np; np = np->n_next)
X if (CMP(sarg, np->n_name) == 0)
X break;
X if (np) {
X /*
X * altering subscribe flag is all
X * we need to change
X */
X np->n_subscribe = splus;
X return true;
X }
X if (sminus) {
X /*
X * try deleting from sub list
X */
X if (subsub(sarg, rcgrps))
X return true;
X /*
X * add specific exclusion
X */
X rcgrps = newstr4(rcgrps, NGSEPS, NEGS, sarg);
X return true;
X }
X } else if (splus) {
X /*
X * we don't subscribe,
X * try deleting !sarg first
X */
X tmp = newstr2(NEGS, sarg);
X subsub(tmp, rcgrps);
X if (!ngmatch(sarg, rcgrps))
X /*
X * didn't work, so add explicit subscription
X */
X rcgrps = rcgrps? newstr3(rcgrps, NGSEPS, sarg):
X newstr(sarg);
X return true;
X }
X } else {
X (void) printf("Subscription list: %s", nflag);
X for (np = rc; np; np = np->n_next)
X if (!np->n_subscribe && ngmatch(np->n_name, nflag))
X (void) printf(",!%s", np->n_name);
X (void) printf("\n");
X }
X return false;
X}
X
X
X/*
X * try and delete group from subscription list
X * return true if successful
X */
Xbool
Xsubsub(grp, slist)
Xchar *grp;
Xchar *slist;
X{
X register char *delim;
X
X while (*slist) {
X if (delim = strchr(slist, NGSEPCHAR))
X *delim = '\0';
X if (CMP(grp, slist) == 0) {
X if (delim)
X (void) strcpy(slist, delim + 1);
X else if (slist[-1] = ',')
X slist[-1] = '\0';
X else
X slist[0] = '\0';
X return true;
X }
X if (delim)
X *delim = NGSEPCHAR, slist = delim + 1;
X else
X break;
X }
X return false;
X}
X
X/*
X * list titles command (-l)
X */
Xapplycom
Xlist(ap, np)
Xactive *ap;
Xnewsrc *np;
X{
X static active *lastap;
X static bool first = true;
X register char *fname;
X register FILE *f;
X header h;
X ino_t ino;
X
X np->n_last++;
X fname = convg(newstr5(newsdir, "/", ap->a_name, ARTSEP,
X itoa(np->n_last)));
X ino = 0;
X f = fopen(fname, "r");
X free(fname);
X if (!f || seen(f, &ino))
X return next;
X gethead(f, &h);
X if (uflag && h.h_references && ureject(&h)) {
X freehead(&h);
X return next;
X }
X if (first) {
X (void) printf("News articles:\n");
X first = false;
X }
X if (lastap != ap)
X (void) printf(" %s:\n", ap->a_name);
X lastap = ap;
X (void) printf(" %-4d %s\n", np->n_last, h.h_subject);
X (void) fclose(f);
X freehead(&h);
X if (ino)
X seen(NIL(FILE), &ino);
X return next;
X}
X
X/*
X * check command (-c or -C)
X */
Xapplycom
Xcheck(ap, np)
Xactive *ap;
Xnewsrc *np;
X{
X static bool done;
X register int num;
X
X np->n_last++;
X if (Cflag) {
X if (!done)
X (void) printf("You have news:\n");
X done = true;
X num = ap->a_seq - np->n_last + 1;
X (void) printf("\t%s at most %d article%s\n",
X ap->a_name, num, (num > 1? "s": ""));
X return nextgroup;
X } else {
X (void) printf("You have news.\n");
X exit(0);
X /* NOTREACHED */
X }
X}
X
X
X/*
X * normal command handler (or pflag)
X * commands:
X *
X * \n print current article
X * n go to next article
X * q quit
X * c cancel
X * r reply
X * m [person] mail
X * f followup
X * p postnews
X * N [newsgrp] next newsgroup
X * s [file] save
X * u unsubscribe from followup
X * U unsubscribe from group
X * !stuff shell escape
X * number or . go to number
X * - back to previous article (toggle)
X * x quick exit
X * h long header info
X * H full header
X *
X * inside r, f or p:
X * .e edit
X * .i interpolate
X * . or EOT terminate message
X * .!comd shell escape
X */
Xapplycom
Xcommands(ap, np, last, pushed)
Xactive *ap;
Xnewsrc *np;
Xbool last;
Xbool pushed;
X{
X static char errmess[] = "Incorrect command; Type `?' for help.\n";
X static char form[] = "%s: %s\n";
X
X static char savedsys[BUFSIZ / 2];
X static active *lastap, *rlastap;
X static newsrc lastn;
X static char number[20];
X static active *wantap;
X
X register char *com, *arg;
X register int c, i, size;
X register FILE *f;
X char *fname;
X header h;
X newsrc ntmp;
X ino_t ino;
X bool printed, pheader, verbose, hadinterrupt;
X applycom nextact;
X
X extern char t_from[], t_subject[], t_date[];
X extern char t_newsgroups[], t_path[], t_sender[];
X extern char t_replyto[], t_organization[];
X extern char *strncpy();
X extern active *activep();
X
X
X if (last) {
X /*
X * give user one last chance to
X * see this article
X */
X ap = rlastap;
X np = &lastn;
X wantap = NIL(active);
X if (!ap || pflag)
X return stop;
X } else if (wantap)
X /*
X * doing an "n newsgroup" command
X */
X if (wantap != ap)
X return nextgroup;
X else
X wantap = NIL(active);
X
X fname = convg(newstr5(newsdir, "/", ap->a_name, ARTSEP,
X itoa(np->n_last + 1)));
X f = fopen(fname, "r");
X ino = 0;
X if (!f || !last && !pushed && seen(f, &ino)) {
X if (pushed)
X (void) printf("Article %d (%s) no longer exists.\n",
X np->n_last + 1, ap->a_name);
X else
X np->n_last++;
X if (f)
X (void) fclose(f);
X free(fname);
X return next;
X }
X
X gethead(f, &h);
X if (!pushed && uflag && h.h_references && ureject(&h)) {
X /* unsubscribed followup */
X freehead(&h);
X np->n_last++;
X (void) fclose(f);
X free(fname);
X return next;
X }
X
X (void) printf("\n");
X interrupt = hadinterrupt = verbose = false;
X if (last) {
X (void) printf("No more articles.\n");
X printed = pheader = true;
X } else
X printed = pheader = false;
X
X while (1) {
X if (lastap != ap) {
X size = strlen(ap->a_name) + sizeof("Newsgroup");
X for (i = 0; i < size; i++)
X (void) putc('-', stdout);
X (void) printf("\nNewsgroup %s\n", ap->a_name);
X for (i = 0; i < size; i++)
X (void) putc('-', stdout);
X (void) printf("\n\n");
X }
X lastap = ap;
X if (!pheader) {
X (void) printf("Article %d of %d (%s)",
X np->n_last + 1, ap->a_seq, ap->a_name);
X if (h.h_lines != 0)
X (void) printf(" (%s lines)", h.h_lines);
X (void) printf("\n");
X (void) printf(form, t_subject, h.h_subject);
X (void) printf(form, t_from, h.h_from);
X if (verbose || pflag) {
X (void) printf(form, t_date, h.h_date);
X (void) printf(form, t_newsgroups, h.h_newsgroups);
X (void) printf(form, t_path, h.h_path);
X if (h.h_sender)
X (void) printf(form, t_sender, h.h_sender);
X if (h.h_replyto)
X (void) printf(form, t_replyto, h.h_replyto);
X if (h.h_organisation)
X (void) printf(form, t_organization, h.h_organisation);
X verbose = false;
X }
X pheader = true;
X }
X if (!pushed && number[0])
X /*
X * just returned from a number command
X * and have another to do
X */
X com = number;
X else if (pflag)
X /*
X * just print it
X */
X com = "";
X else
X {
X (void) printf("? ");
X if (fflush(stdout) == EOF) {
X (void) printf("\n? ");
X (void) fflush(stdout);
X }
X interrupt = false;
X if ((com = mgets()) == NIL(char)) {
X if (interrupt)
X if (!hadinterrupt) {
X clearerr(stdin);
X (void) printf("Interrupt\n");
X hadinterrupt = true;
X interrupt = false;
X continue;
X }
X else
X exit(1);
X nextact = stop;
X break;
X }
X hadinterrupt = false;
X }
X if (*com == '!') {
X if (com[1] == '!') {
X (void) printf("!%s\n", savedsys);
X com = savedsys;
X } else
X com++;
X (void) fflush(stdout);
X#ifdef F_SETFD
X (void) fcntl(fileno(f), F_SETFD, 1); /* close on exec */
X#endif
X (void) system(com);
X if (com != savedsys)
X strncpy(savedsys, com, sizeof(savedsys) - 1);
X (void) printf("!\n");
X if (!printed)
X pheader = false;
X continue;
X }
X /*
X * check command syntax
X */
X if (*com && !isdigit(*com) && com[1] && (!isspace(com[1]) ||
X strchr("Nsm", *com) == NULL)) {
X (void) printf(errmess);
X continue;
X }
X if (c = *com) {
X arg = com;
X while (isspace(*++arg))
X ;
X } else
X arg = NULL;
X switch (c) {
X case 0:
X case '.':
X if (!printed || c == '.') {
X if (pflag)
X (void) printf("\n");
X print(&h, f);
X if (pflag) {
X nextact = next;
X break;
X }
X printed = true;
X continue;
X }
X case 'n': /* B compatible */
X case '+':
X case ';':
X nextact = next;
X break;
X case '?':
X help();
X continue;
X case 'c':
X cancelarticle(&h);
X continue;
X case 'r':
X reply(&h, fname);
X continue;
X case 'm':
X if (!arg || !*arg)
X (void) printf("Person argument missing.\n");
X else
X mail(&h, fname, arg);
X continue;
X case 'f':
X followup(&h, fname);
X continue;
X case 'p':
X pnews(fname);
X continue;
X case 'U':
X if (ngmatch(np->n_name, ADMSUB)
X#if MANGRPS
X || ngmatch(np->n_name, mangrps))
X#else
X )
X#endif
X {
X (void) printf("Group \"%s\" can't be unsubscribed.\n",
X np->n_name);
X continue;
X }
X np->n_subscribe = false;
X nextact = nextgroup;
X break;
X case 'u':
X unsubscribe(h.h_references);
X nextact = next;
X break;
X case 'N': /* B compatible */
X if (!*arg) {
X nextact = nextgroup;
X break;
X }
X if ((wantap = activep(arg)) == NIL(active)) {
X (void) printf("%s: non-existent newsgroup.\n", arg);
X continue;
X }
X if (!ngmatch(arg, nflag)) {
X (void) printf("%s: is not subscribed to!\n", arg);
X wantap = NIL(active);
X continue;
X }
X nextact = searchgroup;
X break;
X case 's':
X save(&h, f, arg);
X continue;
X case 'q':
X nextact = stop;
X break;
X case 'x':
X exit(0);
X case 'h':
X verbose = true;
X pheader = false;
X continue;
X case 'H':
X puthead(&h, stdout, printing);
X continue;
X case '-':
X if (pushed) {
X nextact = next;
X break;
X }
X if (!rlastap || !lastn.n_name) {
X (void) printf("Can't go back!\n");
X continue;
X }
X nextact = commands(rlastap, &lastn, false, true);
X /*
X * number commands, after a "-" act on the
X * group of the "-" command
X */
X while (number[0]) {
X ntmp = lastn;
X ntmp.n_last = atoi(number) - 1;
X number[0] = '\0';
X nextact = commands(rlastap, &ntmp, false, true);
X }
X if (nextact != next)
X break;
X (void) printf("\n");
X pheader = false;
X continue;
X default:
X if (isdigit(c)) {
X i = c - '0';
X while (isdigit(*arg))
X i = i * 10 + *arg++ - '0';
X }
X if (!isdigit(c) || *arg != '\0') {
X (void) printf(errmess);
X continue;
X }
X number[0] = '\0';
X if (i < ap->a_low || i > ap->a_seq) {
X (void) printf("Articles in \"%s\" group range %d to %d.\n",
X np->n_name, ap->a_low, ap->a_seq);
X continue;
X }
X if (pushed) {
X sprintf(number, "%d", i);
X nextact = next;
X break;
X }
X ntmp = *np;
X ntmp.n_last = i - 1;
X if ((nextact = commands(ap, &ntmp, false, true)) !=
X next)
X break;
X if (!number[0]) {
X (void) printf("\n");
X pheader = false;
X }
X continue;
X }
X break;
X }
X rlastap = ap;
X lastn = *np;
X if (!pushed && (nextact == next || printed)) {
X np->n_last++;
X if (ino)
X seen(NIL(FILE), &ino);
X }
X freehead(&h);
X (void) fclose(f);
X free(fname);
X return nextact;
X}
X
X
X/*
X * see if this is a followup we are ignoring
X */
Xbool
Xureject(hp)
Xregister header *hp;
X{
X register bool found;
X register char *rp, *ids, c;
X char *key[1];
X
X found = false;
X rp = hp->h_references;
X while (*rp && !found) {
X if (ids = strpbrk(rp, " ,")) {
X c = *ids;
X *ids = '\0';
X }
X key[0] = rp;
X found = (bool) (bsearch((char *) key, (char *) uflag, (unsigned) usize,
X sizeof(char *), strpcmp) != NIL(char));
X if (ids)
X *ids = c, rp = ids + 1;
X else
X break;
X while (isspace(*rp) || *rp == ',')
X rp++;
X }
X return found;
X}
X
X
X/*
X * see if the article has links, if so have we seen it?
X * close file if we return true
X *
X * called twice,
X * first (with f set) to test (and possibly set *ino)
X * again to put *ino in memory
X */
Xbool
Xseen(f, ino)
XFILE *f;
Xino_t *ino;
X{
X static int num;
X static ino_t *ilist;
X struct stat statb;
X register int i;
X
X if (f) {
X if (fstat(fileno(f), &statb) != 0 || statb.st_nlink <= 1)
X return false;
X for (i = 0; i < num; i++)
X if (ilist[i] == statb.st_ino) {
X (void) fclose(f);
X return true;
X }
X *ino = statb.st_ino;
X return false;
X } else if (*ino) {
X num++;
X ilist = (ino_t * ) (ilist ? myrealloc((char *) ilist, (int) sizeof(ino_t) *
X num) : myalloc((int) sizeof(ino_t)));
X ilist[num - 1] = *ino;
X }
X return true;
X}
X
X
X/*
X * print out help file
X */
Xhelp()
X{
X register FILE *f;
X register int c;
X static char helppath[] = HELP;
X
X if ((f = fopen(helppath, "r")) == NIL(FILE)) {
X (void) printf("Can't open %s\n", helppath);
X return;
X }
X while ((c = getc(f)) != EOF)
X (void) putc(c, stdout);
X (void) fclose(f);
X}
X
X/*
X * cancel an article.
X * inews does permission checking.
X */
Xcancelarticle(hp)
Xheader *hp;
X{
X char *argv[MAXARGV];
X
X argv[0] = strrchr(postnews, '/') + 1;
X argv[1] = "-c"; /* TODO: no such option in C news */
X argv[2] = newstr2("cancel ", hp->h_messageid);
X argv[3] = "-n";
X argv[4] = hp->h_newsgroups;
X if (hp->h_distribution) {
X argv[5] = "-d";
X argv[6] = hp->h_distribution;
X argv[7] = NIL(char);
X } else
X argv[5] = NIL(char);
X run(postnews, argv, true);
X free(argv[2]);
X}
X
X/*
X * reply to sender by mail
X */
X/* ARGSUSED fname */
Xreply(hp, fname)
Xheader *hp;
Xchar *fname;
X{
X char *argv[MAXARGV];
X register int argc;
X
X argc = 0;
X argv[argc++] = "mail";
X#ifdef UNSWMAIL
X argv[argc++] = "-s";
X if ((argv[argc++] = getsubject(hp)) == NIL(char))
X return;
X argv[argc++] = "-i";
X argv[argc++] = fname;
X#endif
X
X if ((argv[argc++] = getretaddr(hp)) == NIL(char)) {
X (void) printf("Can't work out an address!\n");
X return;
X }
X
X argv[argc++] = NIL(char);
X
X run(mailpath, argv, false);
X
X free(argv[argc - 2]);
X}
X
X
X/*
X * mail to person
X */
X/* ARGSUSED hp fname */
Xmail(hp, fname, person)
Xheader *hp;
Xchar *fname, *person;
X{
X char *argv[MAXARGV];
X register int argc;
X
X argc = 0;
X argv[argc++] = "mail";
X#ifdef UNSWMAIL
X argv[argc++] = "-i";
X argv[argc++] = fname;
X argv[argc++] = "-s";
X argv[argc++] = hp->h_subject;
X#endif
X argv[argc++] = person;
X argv[argc++] = NIL(char);
X
X run(mailpath, argv, false);
X}
X
X
X/*
X * generate correct headers for a followup article
X * then call inews.
X */
Xfollowup(hp, fname)
Xheader *hp;
Xchar *fname;
X{
X register int argc;
X char *argv[10];
X
X argc = 0;
X argv[argc++] = strrchr(postnews, '/') + 1;
X argv[argc++] = "-i"; /* TODO: what's this in B news? */
X argv[argc++] = fname;
X argv[argc++] = "-r";
X if (hp->h_references && hp->h_messageid)
X argv[argc++] = newstr3(hp->h_references, " ", hp->h_messageid);
X else if (hp->h_messageid)
X argv[argc++] = newstr(hp->h_messageid);
X else
X argc--;
X
X argv[argc++] = "-s";
X if ((argv[argc++] = getsubject(hp)) == NIL(char))
X return;
X
X argv[argc++] = "-n";
X if (hp->h_followupto)
X argv[argc++] = hp->h_followupto;
X else
X argv[argc++] = hp->h_newsgroups;
X argv[argc++] = NIL(char);
X
X run(postnews, argv, false);
X
X if (argc == 10)
X free(argv[4]);
X}
X
X/*
X * get correct "Subject: Re: .." line
X */
Xchar *
Xgetsubject(hp)
Xregister header *hp;
X{
X register char *s;
X
X if (!hp->h_subject) {
X (void) printf("Subject: Re: ");
X (void) fflush(stdout);
X if ((s = mgets()) == NIL(char) || !*s) {
X (void) printf("The Subject field is mandatory.\n");
X return NIL(char);
X }
X return newstr2("Re: ", s);
X } else if (CMPN(hp->h_subject, "Re: ", 4) != 0 && CMPN(hp->h_subject,
X "re: ", 4) != 0)
X return newstr2("Re: ", hp->h_subject);
X else
X return hp->h_subject;
X}
X
X
X/*
X * run a command, optionally closing stdin
X */
Xrun(com, argv, closein)
Xchar *com;
Xchar *argv[];
Xbool closein;
X{
X int pid, status, r;
X
X switch (pid = fork()) {
X default:
X /* parent */
X break;
X case 0:
X /* child */
X if (closein)
X close(fileno(stdin));
X execvp(com, argv);
X error("can't exec %s", com);
X exit(1);
X
X case -1:
X error("can't fork");
X }
X
X if (signal(SIGINT, SIG_IGN) != SIG_IGN)
X (void) signal(SIGINT, SIG_IGN);
X if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
X (void) signal(SIGQUIT, SIG_IGN);
X
X while ((r = wait(&status)) != pid && r != -1)
X ;
X
X if (signal(SIGINT, SIG_IGN) != SIG_IGN)
X (void) signal(SIGINT, onintr);
X if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
X (void) signal(SIGQUIT, onintr);
X}
X
X/*
X * call postnews
X */
Xpnews(fname)
Xchar *fname;
X{
X char *argv[MAXARGV];
X
X argv[0] = strrchr(postnews, '/') + 1;
X argv[1] = "-i"; /* TODO: what's this inews option? */
X argv[2] = fname;
X argv[3] = NIL(char);
X run(postnews, argv, false);
X}
X
X/*
X * save an article
X */
Xsave(hp, f, s)
Xheader *hp;
XFILE *f;
Xchar *s;
X{
X register long pos;
X register int c;
X register char *cp;
X register FILE *sf;
X register char *aname;
X long then;
X extern char *getenv();
X
X if (!*s) {
X if ((aname = getenv("HOME")) == NIL(char)) {
X (void) printf("No $HOME in environment.\n");
X return;
X }
X s = aname = newstr3(aname, "/", ARTICLES);
X } else
X aname = NIL(char);
X if ((sf = fopen(s, "a")) == NIL(FILE)) {
X (void) fprintf(stderr, "readnews: can't open %s\n", s);
X return;
X }
X if (aname)
X free(aname);
X pos = ftell(f);
X rewind(f);
X if (cp = strchr(hp->h_from, ' '))
X *cp = '\0';
X if (hp->h_date)
X then = atot(hp->h_date);
X else
X then = 0L;
X (void) fprintf(sf, "From %s %s", hp->h_from, ctime(then ? &then : &now));
X if (cp)
X *cp = ' ';
X while ((c = getc(f)) != EOF)
X (void) putc(c, sf);
X (void) fclose(sf);
X fseek(f, pos, 0);
X}
X
X
X/*
X * unsubscribe from all followup articles
X * on this topic
X */
Xunsubscribe(id)
Xchar *id;
X{
X register char *s, c;
X
X if (!id || !*id) {
X (void) printf("no references! (warning)\n");
X return;
X }
X while (*id) {
X if (s = strpbrk(id, " ,")) {
X c = *s;
X *s = '\0';
X }
X usize++;
X uflag = (uflag ? (char **) myrealloc((char *) uflag, (int) sizeof(char
X *) * usize) : (char **) myalloc((int) sizeof(char *)));
X uflag[usize - 1] = newstr(id);
X if (s)
X *s = c, id = s + 1;
X else
X break;
X while (isspace(*id) || *id == ',')
X id++;
X }
X qsort((char *) uflag, (unsigned) usize, sizeof(char *), strpcmp);
X}
X
X
X/*
X * print an article, if it's long enough call page()
X */
Xprint(hp, f)
Xheader *hp;
XFILE *f;
X{
X register int c;
X register long pos;
X
X pos = ftell(f);
X if (!pflag
X#ifdef LINESHDRPRESENT
X && hp->h_lines && atoi(hp->h_lines) >= PAGESIZE - 4
X#endif
X )
X page(f);
X else
X while ((c = getc(f)) != EOF)
X (void) putchar(c);
X fseek(f, pos, 0);
X}
X
X
X/*
X * copy article text to stdout, and break into pages
X */
Xpage(f)
XFILE *f;
X{
X register int c;
X register unsigned lineno;
X char lbuf[80];
X struct sgttyb ttybuf;
X
X#ifdef USG
X /* TODO: fill in USG code to turn off echo */
X#else
X gtty(fileno(stdin), &ttybuf);
X if (ttybuf.sg_flags & ECHO) {
X ttybuf.sg_flags &= ~ECHO;
X stty(fileno(stdin), &ttybuf);
X ttybuf.sg_flags |= ECHO;
X }
X#endif
X lineno = 1;
X while (!interrupt) {
X for (; lineno < PAGESIZE - 4 && !interrupt; lineno++) {
X while ((c = getc(f)) != EOF && c != '\n')
X (void) putchar(c);
X if (c == EOF)
X goto fastexit;
X if (lineno < PAGESIZE - 5)
X (void) putchar('\n');
X }
X if (interrupt)
X break;
X#ifdef moremess
X (void) printf(moremess);
X#endif
X if (fflush(stdout) == EOF)
X break;
X if (read(fileno(stdin), lbuf, sizeof(lbuf)) <= 0)
X break;
X#ifdef moremess
X (void) printf("\r%*s\r", sizeof(moremess), " ");
X#else
X putchar('\n');
X#endif
X lineno = 0;
X }
X if (lineno)
X (void) putchar('\n');
X interrupt = false;
Xfastexit:
X#ifdef USG
X ; /* TODO: fill in USG code to turn echo on */
X#else
X if (ttybuf.sg_flags & ECHO)
X stty(fileno(stdin), &ttybuf);
X#endif
X}
X
X/* VARARGS1 */
Xerror(s, a0, a1, a2, a3)
Xchar *s;
X{
X (void) fprintf(stderr, "readnews: ");
X (void) fprintf(stderr, s, a0, a1, a2, a3);
X (void) fprintf(stderr, "\n");
X exit(1);
X}
!
echo 'rna/checknews':
sed 's/^X//' >'rna/checknews' <<'!'
Xexec readnews -c
!
echo done