rsalz@uunet.uu.net (Rich Salz) (06/30/89)
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 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.