news 2.10.2 src part 9
Rick Adams
rick at seismo.UUCP
Thu Sep 6 11:12:35 AEST 1984
cat <<'E_O_F'
These four files should replace the ones that were in yesterdays
posting. If you are ever in doubt, the latest sccsid should
be used.
The one I posted yesterday would throw away any mail replies.
Sorry for the confusion.
---rick
E_O_F
if test ! -d src
then
mkdir src
echo mkdir src
fi
rm -f src/defs.dist src/rparams.h src/readr.c src/visual.c src/postnews.c
echo x - src/defs.dist
sed 's/^X//' >src/defs.dist <<'*-*-END-of-src/defs.dist-*-*'
X/*
X * defs.h - defines for news-related programs.
X *
X * If you remove any lines here or in your Makefile, make the change
X * to localize.sh so you won't have to redo it for each news release.
X *
X * If TMAIL is undefined, the -M option will be disabled.
X *
X * By convention, the version of the software you are running is taken
X * to be news_version below.
X */
X
X/* @(#)defs.dist 2.35 9/5/84 */
X
X#define NEWS_VERSION "B 2.10.2 9/5/84"
X
X#define DAYS (60L*60L*24L)
X#define WEEKS (7*DAYS)
X/* Things that very well may require local configuration */
X#ifndef HOME
X#define ROOTID 10 /* uid of person allowed to cancel anything */
X#endif
X#define N_UMASK 000 /* mask for umask call, 022 for secure system */
X#define DFLTEXP 2*WEEKS /* default no. of seconds to expire in */
X#define DFLTSUB "general,all.general" /* default subscription list */
X#define TMAIL "/usr/ucb/Mail" /* Mail program that understands -T */
X#define ADMSUB "general,all.announce" /* Mandatory subscription list */
X#define PAGE "/usr/ucb/more" /* Default pager */
X#define NOTIFY "usenet" /* Tell him about certain ctl messages */
X /* Default xmit command - remove -z if */
X#define DFTXMIT "uux - -r -z %s!rnews < %s" /* your uux can't do it */
X#define UXMIT "uux -r -z -c %s!rnews '<' %s" /* If uux -c is ok */
X#define DFTEDITOR "vi" /* Default editor, see also postnews. */
X/* #define UUPROG "euuname" /* omit for uuname, put in LIBDIR */
X#define MANUALLY /* Don't execute rmgroups, just notify. */
X#define BATCH "unbatch" /* name of unbatcher */
X/* #define LOCALNAME /* There is no full name database. */
X/* #define INTERNET /* Internet mail works locally */
X#define MYDOMAIN ".UUCP" /* Local domain */
X/* #define CHEAP /* don't chown files to news */
X/* #define OLD /* Add extra headers for old neighbors */
X/* #define UNAME /* If uname call is available. */
X/* #define GHNAME /* If gethostname call is available. */
X#define V7MAIL /* Local mail format is V7 ("From ") */
X#define SORTACTIVE /* if you want news presented in the order of the .newsrc */
X#define ZAPNOTES /* if you want old style notes headers moved into the headers */
X/* #define BSD4_2 /* If you are running 4.2 BSD */
X/* #define BSD4_1C /* If you are running 4.1C BSD */
X/* #define SENDMAIL "/usr/lib/sendmail -oi -oem" /* command line to run "sendmail" if you have it */
X#define MYORG "Frobozz Inc., St. Louis" /* My organization. Please */
X /* include your city (and state, and */
X /* country, if not obvious) in MYORG, */
X /* and please keep it short. */
X
X/* Things you might want to change */
X#define NEWSRC ".newsrc" /* name of .newsrc file (in home dir) */
X#define LINES 512 /* maximum no. of lines in .newsrc */
X#define NEGCHAR '!' /* newsgroup negation character */
X#define DEADTIME 45 /* no. of seconds to wait on deadlock */
X#define FMETA '%' /* file meta-character for c option */
X#ifdef pdp11
X# define BUFLEN 128 /* standard buffer size */
X#else
X# define BUFLEN 256 /* standard buffer size */
X#endif
X#define LBUFLEN 1024 /* big buffer size */
X#define SYSPATH "PATH=/local/bin:/bin:/usr/bin" /* default, secure, vanilla path */
X#define LNCNT 16 /* Articles with > LNCNT lines go through pager */
X
X/* Things you probably won't want to change */
X#define PATHLEN 512 /* length of longest source string */
X#define DATELEN 64 /* length of longest allowed date string */
X#define NAMELEN 64 /* length of longest possible message ID */
X#define SNLN 8 /* max significant characters in sysname */
X#define PROTO 'A' /* old protocol name */
X#define NETCHRS "!:.@^%"/* Punct. chars used for various networks */
X#define TRUE 1 /* boolean true */
X#define FALSE 0 /* boolean false */
X#define AFSIZ 5000 /* legal newsgroup file size */
X#define NGDELIM ',' /* delimit character in news group line */
*-*-END-of-src/defs.dist-*-*
echo x - src/rparams.h
sed 's/^X//' >src/rparams.h <<'*-*-END-of-src/rparams.h-*-*'
X/*
X * rparams.h - parameters for readnews, rfuncs, and readr.
X */
X
X/* @(#)rparams.h 2.15 9/5/84 */
X
X#include "params.h"
X
X/* flags for readnews */
X#define pflag options[0].flag
X#define tflag options[1].flag
X#define aflag options[2].flag
X#define nflag options[3].flag
X#define cflag options[4].flag
X#define lflag options[5].flag
X#define rflag options[6].flag
X#define sflag options[7].flag
X#define xflag options[8].flag
X#define hflag options[9].flag
X#define Mflag options[10].flag
X#define fflag options[11].flag
X#define uflag options[12].flag
X#define eflag options[13].flag
X
X#define NEXT 0
X#define SPEC 1
X
X#define FORWARD 0
X#define BACKWARD 1
X
X#define UNKNOWN 0001 /* possible modes for news program */
X#define MAIL 0004
X#define ANY 0007
X
X#define BITMAPSIZE 2048 /* Must be a power of 2 */
X
Xstruct optable { /* options table. */
X char optlet; /* option character. */
X char filchar; /* if to pickup string, fill character. */
X int flag; /* TRUE if have seen this opt. */
X int newstate; /* STRING if takes arg, else OPTION */
X int oldmode; /* OR of legal input modes. */
X int newmode; /* output mode. */
X char *buf; /* string buffer */
X};
X
X/* external declarations specific to readnews */
Xextern char *infile, *outfile, PAGER[];
Xextern char bitmap[], *temprc, *MAILER, *MAILPARSER;
X
X#ifndef ROOTID
Xextern int ROOTID;
X#endif
X
X#ifdef NOTIFY
Xextern char *TELLME;
X#endif
X
Xextern char filename[],coptbuf[],datebuf[],titlebuf[],afline[];
Xextern char newsrc[],groupdir[],rcbuf[],*rcline[],*argvrc[];
Xextern int mode, ngrp, line, newrc(), readmode;
Xextern long bit, obit, last, ngsize, minartno;
Xextern FILE *rcfp,*actfp;
Xextern time_t atime;
Xextern struct stat statbuf;
Xextern struct optable *optpt, options[];
Xextern int actdirect, rcreadok, zapng;
X
X#ifndef lint
X/* lint gets very mad about i-minartno, this is one way of shutting it up */
X/* macros */
X#define get(i) ((i<minartno)? 0 : (bitmap[(i-minartno) >> 3] & (1 << (i-minartno) % 8)))
X#define set(i) if (i>=minartno) bitmap[(i-minartno) >> 3] |= (1 << (i-minartno) % 8);else
X#define clear(i) if (i>=minartno) bitmap[(i-minartno) >> 3] &= ~(1 << (i-minartno) % 8);else
X#endif !lint
X
X#define FCLOSE(fp) {if (fp != NULL) {fclose(fp);fp = NULL;}}
*-*-END-of-src/rparams.h-*-*
echo x - src/readr.c
sed 's/^X//' >src/readr.c <<'*-*-END-of-src/readr.c-*-*'
X/*
X * readr - /bin/mail and msgs interface and associated functions.
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)readr.c 2.46 9/5/84";
X#endif !lint
X
X#include "rparams.h"
X#if defined(BSD4_2) || defined(BSD4_1C)
X#include <sys/dir.h>
X#else
X#include "ndir.h"
X#endif !BSD4_2 && !BSD4_1C
X#include <setjmp.h>
X#include <errno.h>
X
Xextern int errno;
X
Xchar *Progname = "readnews"; /* used by xerror to identify failing program */
X
Xstatic char lbuf[BUFLEN*2];
Xlong atol();
X
X#define saveart oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hptr = h;h = hold;hold = hptr;ongsize = pngsize
X#define NLINES(h, fp) (h->numlines[0] ? h->intnumlines : (h->intnumlines=linecnt(fp),sprintf(h->numlines, "%d", h->intnumlines), h->intnumlines))
X
Xchar *tft = "/tmp/folXXXXXX";
X
X/*
X * These were made static for u370 with its buggy cc.
X * I judged it better to have one copy with no ifdefs than
X * to conditionally compile them as automatic variables
X * in readr (which they originally were). Performance
X * considerations might warrent moving some of the simple
X * things into register variables, but I don't know what
X * breaks the u370 cc.
X */
Xstatic char goodone[BUFLEN]; /* last decent article */
Xstatic char ogroupdir[BUFLEN]; /* last groupdir */
Xstatic char address[PATHLEN]; /* for reply copy */
Xstatic char edcmdbuf[128];
Xstatic int rfq = 0; /* for last article */
Xstatic long ongsize; /* Previous ngsize */
Xstatic long pngsize; /* Printing ngsize */
Xstatic char *bptr; /* temp pointer. */
Xstatic struct srec srec; /* srec for sys file entries */
Xstatic char *tfilename; /* temporary file name */
Xstatic char ofilename1[BUFLEN]; /* previous file name */
Xstatic struct hbuf hbuf1, hbuf2, /* for minusing */
X *h = &hbuf1, /* current header */
X *hold = &hbuf2, /* previous header */
X *hptr; /* temporary */
Xstatic char *ptr1, *ptr2, *ptr3; /* for reply manipulation */
Xstatic int news = 0;
Xstatic int abs = FALSE; /* TRUE if we asked absolutely */
Xstatic char tf[100];
Xstatic long oobit; /* last bit, really */
Xstatic int dgest = 0;
Xstatic FILE *ofp; /* Current output file to terminal*/
Xstatic FILE *fp; /* current article to be printed*/
Xstatic int holdup; /* 1 iff should stop before hdr */
Xstatic int ignorenews; /* 1 iff readnews -p > /dev/null*/
Xstatic time_t timelastsaved; /* time newsrc last written out */
Xstatic jmp_buf sigjmpbuf; /* for signal processing */
Xstatic int canlongjmp; /* TRUE if setjmp on sigjmp valid */
X
Xint catchcont();
X
Xreadr()
X{
X
X#ifdef DEBUG
X fprintf(stderr, "readr()\n");
X#endif
X if (aflag) {
X if (*datebuf) {
X if ((atime = cgtdate(datebuf)) == -1)
X xerror("Cannot parse date string");
X } else
X atime = 0;
X }
X
X if (pflag && ignoring())
X ignorenews = TRUE;
X
X if (xflag)
X uflag = 0;
X if (uflag)
X (void) time(&timelastsaved);
X
X ofp = stdout;
X if (cflag && coptbuf[0] != '\0') {
X umask(022);
X mktemp(outfile); /* get "unique" file name */
X close(creat(outfile,0666));
X ofp = xfopen(outfile, "w");
X umask(N_UMASK);
X cflag = FALSE;
X pflag = TRUE;
X }
X
X /* loop reading articles. */
X fp = NULL;
X obit = -1;
X nextng();
X for ( ;; ) {
X if (getnextart(FALSE))
X break;
X#ifdef DEBUG
X fprintf(stderr,"after getnextart, fp %x, pos %ld, bit %ld, group '%s', filename '%s'\n",
X fp, ftell(fp), bit, groupdir, filename);
X#endif
X strcpy(goodone, filename);
X if (pflag || lflag || eflag) {
X /* This code should be gotten rid of */
X if (sigtrap) {
X qfflush(ofp);
X fprintf(ofp, "\n");
X cdump(ofp);
X xxit(0); /* kludge! drop when qfflush works */
X return;
X }
X clear(bit);
X nextbit();
X FCLOSE(fp);
X continue;
X }
X for ( ;; ) {
X char *pp;
X int nlines;
X int (*ointr)();
X#ifdef SIGCONT
X int (*ocont)();
X#endif
X setjmp(sigjmpbuf);
X canlongjmp = TRUE;
X
X sigtrap = FALSE;
X if (!cflag) {
X if (rfq)
X sprintf(bfr, "Last article. [qfr] ");
X else {
X nlines = NLINES(h, fp);
X if (nlines <= 0) {
X sprintf(bfr, "(0 lines) Next? [nqfr] ");
X FCLOSE(fp);
X } else {
X sprintf(bfr, "(%d lines) More? [ynq] ", nlines);
X }
X }
X } else
X sprintf(bfr, "? ");
X fprintf(ofp, "%s", bfr);
X fflush(ofp);
X bptr = lbuf;
X ointr = signal(SIGINT, catchcont);
X#ifdef SIGCONT
X ocont = signal(SIGCONT, catchcont);
X#endif
X pp = fgets(bptr, BUFLEN, stdin);
X canlongjmp = FALSE;
X signal(SIGINT, ointr);
X#ifdef SIGCONT
X signal(SIGCONT, ocont);
X#endif
X if (pp != NULL)
X break;
X if (!sigtrap)
X return;
X#ifdef SIGCONT
X if (sigtrap != SIGCONT)
X#endif
X fprintf(ofp, "\n");
X }
X nstrip(bptr);
X while (*bptr == ' ' || *bptr == '\t')
X bptr++;
X if (command())
X break;
X }
X
X if (!news)
X fprintf(stderr, "No news.\n");
X cout(ofp);
X}
X
X
X#define EOL() if (*bptr != '\0') { fprintf(ofp, "? for commands.\n"); return FALSE; }
X/*
X * Process one command, which has already been typed in.
X */
Xcommand()
X{
X char *findhist();
X long i;
X
X switch (*bptr++) {
X
X /* No. Go on to next article. */
X case 'n':
X EOL();
X readmode = NEXT;
X if (!cflag)
X FCLOSE(fp);
X fprintf(ofp, "\n");
X clear(bit);
X saveart;
X nextbit();
X break;
X
X /* Undigestify the article. */
X case 'd':
X dgest = 1;
X /* fall through */
X
X /* yes: print this article, go on. */
X case 'y':
X EOL();
X /* fall through. */
X
X /* The user hit return. Default is 'y' unless rfq, then it's 'q'. */
X case '\0':
X if (!bptr[-1] && rfq)
X return TRUE;
X readmode = NEXT;
X showtail(fp);
X clear(bit);
X saveart;
X nextbit();
X break;
X
X /*
X * Unsubscribe to the newsgroup and go on to next group
X */
X case 'u':
X fprintf(ofp, "To unsubscribe, use 'U'\n");
X break;
X
X case 'U':
X fprintf(ofp, "Unsubscribing to newsgroup: %s\n", groupdir);
X obit = -1;
X FCLOSE(fp);
X if (cflag)
X clear(bit);
X else
X putc('\n', ofp);
X rfq = 0;
X zapng = TRUE;
X saveart;
X if (nextng()) {
X if (actdirect == BACKWARD)
X fprintf(ofp, "Can't back up.\n");
X else
X return TRUE;
X }
X break;
X
X /* Print the current version of news */
X case 'v':
X fprintf(ofp, "News version: %s\n", news_version);
X break;
X
X /* reprint the article */
X case 'p':
X EOL();
X if (!cflag)
X goto minus;
X readmode = NEXT;
X if (!cflag) {
X FCLOSE(fp);
X bit = last;
X putc('\n', ofp);
X }
X obit = -1;
X break;
X
X /* decrypt joke */
X case 'D':
X caesar_command();
X readmode = NEXT;
X clear(bit);
X saveart;
X nextbit();
X break;
X
X /* write out the article someplace */
X case 's':
X case 'w':
X {
X char *grn = groupdir;
X tfilename = filename;
X if (*bptr == '-') {
X bptr++;
X grn = ogroupdir;
X if (*ofilename1)
X tfilename = ofilename1;
X }
X if (*bptr != '\0' && *bptr != ' ') {
X fprintf(ofp, "Bad file name.\n");
X break;
X }
X while (*bptr == ' ')
X bptr++;
X if (*bptr != '|' && *bptr != '/') {
X char hetyped[BUFLEN];
X char *boxptr;
X strcpy(hetyped, bptr);
X if (boxptr = getenv("NEWSBOX"))
X if (index(boxptr, '%'))
X sprintf(bptr, boxptr, grn);
X else
X strcpy(bptr, boxptr);
X else if (hetyped[0] == '~' && hetyped[1] == '/') {
X strcpy(hetyped, bptr+2);
X strcpy(bptr, userhome);
X } else
X strcpy(bptr, ".");
X strcat(bptr, "/");
X if (hetyped[0] != '\0')
X strcat(bptr, hetyped);
X else
X strcat(bptr, "Articles");
X }
X fwait(fsubr(save, tfilename, bptr));
X }
X break;
X
X /* back up */
X case '-':
Xminus:
X rfq = 0;
X abs = TRUE;
X if (!*ofilename1) {
X fprintf(ofp, "Can't back up.\n");
X break;
X }
X if (cflag)
X clear(bit);
X else {
X FCLOSE(fp);
X putc('\n', ofp);
X }
X hptr = h;
X h = hold;
X hold = hptr;
X strcpy(bfr, filename);
X strcpy(filename, ofilename1);
X strcpy(ofilename1, bfr);
X obit = bit;
X if (strcmp(groupdir, ogroupdir)) {
X strcpy(bfr, groupdir);
X selectng(ogroupdir, TRUE);
X strcpy(groupdir, ogroupdir);
X strcpy(ogroupdir, bfr);
X ngrp = 1;
X back();
X }
X bit = oobit;
X oobit = obit;
X obit = -1;
X (void) getnextart(TRUE);
X return FALSE;
X
X /* skip forwards */
X case '+':
Xcaseplus:
X if (*bptr == '\0')
X strcat(bptr, "1");
X rfq = 0;
X if (cflag)
X clear(bit);
X saveart;
X last = bit;
X for (i = 0; i < atol(bptr); i++) {
X nextbit();
X if ((bit > pngsize) || (rflag && bit < 1))
X break;
X }
X if (!cflag) {
X putc('\n', ofp);
X FCLOSE(fp);
X }
X obit = -1;
X break;
X
X /* exit - time updated to that of most recently read article */
X case 'q':
X EOL();
X return TRUE;
X
X /* exit - no time update. */
X case 'x':
X EOL();
X xxit(0);
X
X /* cancel the article. */
X case 'c':
X (void) cancel_command();
X break;
X
X /* escape to shell */
X case '!':
X fwait(fsubr(ushell, bptr, (char *)NULL));
X fprintf(ofp, "\n");
X hdr();
X break;
X
X /* mail reply */
X case 'r':
X (void) reply_command();
X break;
X
X /* send to some system */
X case 'X':
X xmit_command();
X break;
X /* mark the rest of the articles in this group as read */
X case 'K':
X saveart;
X while (bit <= pngsize && bit >= minartno) {
X clear(bit);
X nextbit();
X }
X FCLOSE(fp);
X break;
X
X /* next newsgroup */
X case 'P':
X *bptr = '-';
X case 'N':
X FCLOSE(fp);
X if (next_ng_command())
X return TRUE;
X break;
X
X case 'b': /* back up 1 article */
X i = bit - 1;
X goto tryartnum;
X case '0': /* specific no. */
X case '1':
X case '2':
X case '3':
X case '4':
X case '5':
X case '6':
X case '7':
X case '8':
X case '9':
X sscanf(--bptr, "%ld", &i);
X if (i == 0) {
X fprintf(ofp, "Bad article no.\n");
X break;
X }
X if (i > pngsize) {
X fprintf(ofp, "Not that many articles.\n");
X break;
X }
Xtryartnum:
X readmode = SPEC;
X abs = TRUE;
X bit = i;
X obit = -1;
X if (!cflag) {
X putc('\n', ofp);
X FCLOSE(fp);
X }
X rfq = 0;
X break;
X
X /* specific message ID. */
X case '<':
X ptr1 = findhist(--bptr);
X if (ptr1 == NULL) {
X fprintf(ofp, "No such article: %s.\n", bptr);
X break;
X }
X ptr2 = index(ptr1, '\t');
X ptr3 = index(++ptr2, '\t');
X ptr2 = index(++ptr3, ' ');
X if (ptr2)
X *ptr2 = '\0';
X ptr2 = index(ptr3, '/');
X *ptr2++ = '\0';
X abs = TRUE;
X if (cflag)
X clear(bit);
X else {
X FCLOSE(fp);
X putc('\n', ofp);
X }
X saveart;
X strcpy(ogroupdir, ptr3);
X if (strcmp(groupdir, ogroupdir)) {
X strcpy(bfr, groupdir);
X selectng(ogroupdir, TRUE);
X strcpy(groupdir, ogroupdir);
X strcpy(ogroupdir, bfr);
X back();
X }
X sscanf(ptr2, "%ld", &bit);
X oobit = obit;
X obit = -1;
X (void) getnextart(TRUE);
X rfq = 0;
X break;
X
X /* follow-up article */
X case 'f':
X if (*bptr == '-')
X tfilename = ofilename1;
X else
X tfilename = filename;
X sprintf(bfr,"%s/%s %s", BIN, "postnews", tfilename);
X system(bfr);
X break;
X
X /* erase - pretend we haven't seen this article. */
X case 'e':
X if (rfq || *bptr == '-') {
X if (strcmp(groupdir, ogroupdir)) {
X i = bit;
X strcpy(bfr, groupdir);
X selectng(ogroupdir, FALSE);
X set(oobit);
X fprintf(ofp,"Holding article %ld newsgroup %s\n", oobit, ogroupdir),
X strcpy(groupdir, ogroupdir);
X selectng(bfr, FALSE);
X bit = i;
X } else {
X fprintf(ofp,"Holding article %ld\n", oobit);
X set(oobit);
X }
X } else {
X fprintf(ofp,"Holding article %ld\n", bit);
X set(bit);
X goto caseplus; /* skip this article for now */
X }
X break;
X
X case 'H':
X case 'h':
X if (!hflag)
X dash(8, ofp);
X if (*bptr == '-') {
X if (oobit > 0)
X fprintf(ofp, "Article %ld:\n", oobit);
X hprint(hold, ofp, 1 + (bptr[-1]=='H'));
X } else {
X fprintf(ofp, "Article %ld of %ld: %s\n",
X rfq ? oobit : bit, pngsize, h->ident);
X hprint(h, ofp, 1 + (bptr[-1]=='H'));
X }
X if (!hflag)
X dash(8, ofp);
X break;
X
X case '#':
X fprintf(ofp, "Article %ld of %ld: newsgroup %s\n",
X rfq ? oobit : bit, pngsize, rfq ? ogroupdir : groupdir);
X break;
X
X /* error */
X case '?':
X help(ofp);
X break;
X default:
X fprintf(ofp, "? for commands.\n");
X break;
X }
X
X return FALSE;
X}
X
Xcancel_command()
X{
X tfilename = filename;
X hptr = h;
X if (*bptr == '-') {
X if (*ofilename1) {
X tfilename = ofilename1;
X hptr = hold;
X }
X bptr++;
X }
X EOL();
X readmode = SPEC;
X strcpy(rcbuf, hptr->path);
X ptr1 = index(rcbuf, ' ');
X if (ptr1)
X *ptr1 = 0;
X if (uid != ROOTID && strcmp(username, rcbuf)) {
X fprintf(ofp, "Can't cancel what you didn't write.\n");
X return FALSE;
X }
X if (!cancel(ofp, hptr, 0) && hptr == h) {
X clear(bit);
X saveart;
X nextbit();
X obit = -1;
X if (!cflag)
X putc('\n', ofp);
X FCLOSE(fp);
X }
X return TRUE;
X}
X
Xreply_command()
X{
X register char *pathptr;
X int edit = 1;
X char *ed;
X FILE *tfp;
X char curberk[BUFLEN];
X char *replyname();
X char subj[BUFLEN];
X char folbuf[BUFLEN];
X struct stat statb;
X long creatm;
X
X hptr = h;
X while (*bptr && index("d-", *bptr)) {
X switch (*bptr) {
X /* Followup the previous article. */
X case '-':
X hptr = hold;
X break;
X
X /* Don't edit the headers */
X case 'd':
X edit = 0;
X break;
X }
X bptr++;
X }
X EOL();
X ptr1 = index(MAILPARSER, ' ');
X if (ptr1)
X *ptr1 = '\0';
X if (edit && access(MAILPARSER, 1)) {
X#ifdef IHCC
X fprintf(stderr, "Can't edit headers, 'recmail' missing.\n");
X#else
X fprintf(stderr, "Can't edit headers without %s\n", MAILPARSER);
X#endif
X edit = 0;
X }
X if (ptr1)
X *ptr1 = ' ';
X
X *rcbuf = '\0';
X *curberk = '\0';
X pathptr = replyname(hptr);;
X for (ptr1 = address, ptr2 = pathptr; *ptr2; ptr1++, ptr2++) {
X if (index("\"\\$", *ptr2))
X *ptr1++ = '\\';
X *ptr1 = *ptr2;
X }
X *ptr1 = '\0';
X
X folbuf[0] = '\0'; /* References */
X if (hptr->followid[0]) {
X strcpy(folbuf, hptr->followid);
X strcat(folbuf, ", ");
X }
X strcat(folbuf, hptr->ident);
X
X strcpy(subj, hptr->title); /* Subject */
X while (isspace(*bptr))
X bptr++;
X if (*bptr != '\0')
X strcpy(subj, bptr);
X if (!prefix(subj, "Re:")){
X strcpy(bfr, subj);
X sprintf(subj, "Re: %s", bfr);
X }
X if (!edit) {
X fprintf(ofp, "To: %s\n", pathptr);
X ed = index(MAILER, '%');
X if (ed && ed[1] == 's')
X fprintf(ofp, "Subject: %s\n", subj);
X fflush(ofp);
X }
X
X /* Put the user in the editor to create the body of the followup. */
X if (edit) {
X strcpy(tf, tft);
X mktemp(tf);
X
X ed = getenv("EDITOR");
X if (ed == NULL)
X ed = DFTEDITOR;
X
X if ((tfp = fopen(tf, "w")) == NULL) {
X perror(tf);
X creatm = 0L;
X } else {
X fprintf(tfp, "To: %s\n", pathptr);
X fprintf(tfp, "Subject: %s\n", subj);
X fprintf(tfp, "References: %s\n\n", folbuf);
X fstat(fileno(tfp), &statb);
X creatm = statb.st_mtime;
X fclose(tfp);
X }
X
X sprintf(edcmdbuf, "%s %s", ed, tf);
X system(edcmdbuf);
X strcpy(rcbuf, MAILPARSER);
X strcat(rcbuf, " -t");
X strcat(rcbuf, " < ");
X strcat(rcbuf, tf);
X if (access(tf, 4) || stat(tf, &statb)) {
X fprintf(stderr, "Reply not sent: no input file.\n");
X return FALSE;
X }
X if (statb.st_mtime == creatm) {
X fprintf(stderr, "Reply not sent: cancelled.\n");
X unlink(tf);
X return FALSE;
X }
X fprintf(ofp,"Sending reply.\n");
X fflush(stdout);
X if (fork() == 0) {
X system(rcbuf);
X unlink(tf);
X _exit(0);
X }
X } else {
X sprintf(rcbuf, MAILER, hptr->title);
X sprintf(bfr, "%s %s", rcbuf, address);
X system(bfr);
X }
X hdr();
X return TRUE;
X}
X
Xxmit_command()
X{
X tfilename = filename;
X if (*bptr == '-') {
X if (*ofilename1)
X tfilename = ofilename1;
X bptr++;
X }
X if (*bptr != '\0' && *bptr != ' ') {
X fprintf(ofp, "Bad system name.\n");
X return;
X }
X while (*bptr == ' ')
X bptr++;
X if (*bptr == '\0') {
X fprintf(ofp, "Missing system name.\n");
X return;
X }
X if (s_find(&srec, bptr) == NULL) {
X fprintf(ofp, "%s not in SYSFILE\n", bptr);
X return;
X }
X transmit(&srec, tfilename);
X}
X
Xnext_ng_command()
X{
X obit = -1;
X if (!*bptr || *bptr == '-') {
X if (cflag)
X clear(bit);
X else
X putc('\n', ofp);
X if (*bptr)
X actdirect = BACKWARD;
X rfq = 0;
X saveart;
X if (nextng()) {
X if (actdirect == BACKWARD)
X fprintf(ofp, "Can't back up.\n");
X else
X return TRUE;
X }
X return FALSE;
X }
X while (isspace(*bptr))
X bptr++;
X if (!validng(bptr)) {
X fprintf(ofp, "No such group.\n");
X return FALSE;
X }
X if (cflag)
X clear(bit);
X else
X putc('\n', ofp);
X readmode = SPEC;
X rfq = 0;
X saveart;
X back();
X selectng(bptr, TRUE);
X return FALSE;
X}
X
Xcaesar_command()
X{
X char temp[BUFLEN];
X FILE *pfp, *popen();
X
X fprintf(stderr, "Caesar decoding:\n");
X sprintf(temp, "%s/%s", LIB, "caesar");
X if (*bptr) {
X strcat(temp, " ");
X strcat(temp, bptr);
X }
X if (NLINES(h, fp) > LNCNT && *PAGER) {
X strcat(temp, " | ");
X strcat(temp, PAGER);
X }
X pfp = popen(temp, "w");
X tprint(fp, pfp, FALSE);
X FCLOSE(fp);
X pclose(pfp);
X}
X
X/*
X * Show the user the tail, if any, of the message on file
X * descriptor fd, and close fd. The digester is considered,
X * and the pager is used if appropriate.
X */
Xshowtail(fd)
XFILE *fd;
X{
X if (fd == NULL)
X return;
X
X if (dgest) {
X digest(fd, ofp, h);
X } else if (!lflag && !pflag && !eflag) {
X pprint(fd);
X }
X fclose(fd);
X}
X
X/*
X * Print out the rest of the article through the pager.
X */
Xpprint(fd)
XFILE *fd;
X{
X#ifdef PAGE
X /* Filter the tail of long messages through PAGER. */
X if (NLINES(h, fd) > LNCNT && *PAGER) {
X if (!index(PAGER, FMETA)) {
X FILE *pfp, *popen();
X
X pfp = popen(PAGER, "w");
X if (pfp == NULL)
X pfp = ofp;
X /*
X * What follows is an attempt to prevent the
X * next message from scrolling part of this
X * message off the top of the screen before
X * the poor luser can read it.
X */
X tprint(fd, pfp, FALSE);
X pclose(pfp);
X }
X else
X pout(ofp);
X holdup = TRUE;
X }
X else
X#endif
X tprint(fd, ofp, FALSE);
X}
X
X/*
X * Find the next article we want to consider, if we're done with
X * the last one, and show the header.
X */
Xgetnextart(minus)
Xint minus;
X{
X int noaccess;
X register DIR *dirp;
X register struct direct *dir;
X long nextnum, tnum;
X
X noaccess = 0;
X
X if (minus)
X goto nextart2; /* Kludge for "-" command. */
X
X if (bit == obit) /* Return if still on same article as last time */
X return 0;
X
X sigtrap = FALSE;
X
Xnextart:
X#ifdef DEBUG
X fprintf(stderr,"nextart:\n");
X#endif DEBUG
X dgest = 0;
X
X if (bit < minartno && !rflag)
X bit = minartno;
X
X /* If done with this newsgroup, find the next one. */
X while (ngsize <= 0 || ((long) bit > ngsize) || (rflag && bit < minartno)) {
X if (nextng()) {
X if (actdirect == BACKWARD) {
X fprintf(ofp, "Can't back up.\n");
X actdirect = FORWARD;
X continue;
X } else
X if (rfq++ || pflag || cflag)
X return 1;
X }
X if (rflag)
X bit = ngsize + 1;
X else
X bit = minartno - 1;
X if (uflag) {
X time_t now;
X (void) time(&now);
X if (now - timelastsaved > 5*60 /* 5 minutes */) {
X fprintf(stderr,"[Saving .newsrc]\n");
X writeoutrc();
X timelastsaved = now;
X }
X }
X }
X
Xnextart2:
X#ifdef DEBUG
X fprintf(stderr, "article: %s/%ld\n", groupdir, bit);
X#endif
X if (rcreadok)
X rcreadok = 2; /* have seen >= 1 article */
X sprintf(filename, "%s/%ld", dirname(groupdir), bit);
X if (rfq && goodone[0])
X strcpy(filename, goodone);
X if (sigtrap) {
X if (sigtrap == SIGHUP)
X return 1;
X if (!rcreadok)
X xxit(0);
X fprintf(ofp, "Abort (n)? ");
X fflush(ofp);
X gets(bfr);
X if (*bfr == 'y' || *bfr == 'Y')
X xxit(0);
X sigtrap = FALSE;
X }
X#ifdef DEBUG
X fprintf(stderr, "filename = '%s'\n", filename);
X#endif
X /* Decide if we want to show this article. */
X if ((fp = fopen(filename, "r")) == NULL) {
X /* since there can be holes in legal article numbers, */
X /* we wait till we hit 5 consecutive bad articles */
X /* before we haul off and scan the directory */
X if (++noaccess < 5)
X goto badart;
X noaccess = 0;
X dirp = opendir(dirname(groupdir));
X if (dirp == NULL) {
X if (errno != EACCES)
X fprintf(stderr,"Can't open %s", dirname(groupdir));
X goto badart;
X }
X nextnum = rflag ? minartno - 1 : ngsize + 1;
X while ((dir = readdir(dirp)) != NULL) {
X tnum = atol(dir->d_name);
X if (tnum <= 0)
X continue;
X if (rflag ? (tnum > nextnum && tnum < bit)
X : (tnum < nextnum && tnum > bit))
X nextnum = tnum;
X }
X closedir(dirp);
X if (rflag ? (nextnum >= bit) : (nextnum <= bit))
X goto badart;
X#ifdef DEBUG
X fprintf(stderr,"nextnum = %ld\n",nextnum);
X#endif DEBUG
X do {
X clear(bit);
X nextbit();
X } while (rflag ? (nextnum < bit) : (nextnum > bit));
X obit = -1;
X abs = FALSE;
X goto nextart;
X } else
X noaccess = 0;
X
X if (ignorenews || hread(h, fp, TRUE) == NULL
X || (!rfq && !aselect(h, abs))) {
X badart:
X#ifdef DEBUG
X fprintf(stderr, "Bad article '%s'\n", filename);
X#endif
X FCLOSE(fp);
X clear(bit);
X obit = -1;
X nextbit();
X abs = FALSE;
X goto nextart;
X }
X abs = FALSE;
X actdirect = FORWARD;
X news = TRUE;
X hdr();
X if (pflag)
X tprint(fp, ofp, FALSE);
X else if (cflag && !lflag && !eflag) {
X fflush(ofp);
X pprint(fp);
X }
X if (cflag || lflag || eflag || pflag) {
X sigtrap = FALSE;
X FCLOSE(fp);
X }
X obit = bit;
X return 0;
X}
X
X/*
X * Print out whatever the appropriate header is
X */
Xhdr()
X{
X char *briefdate();
X
X if (rfq)
X return;
X
X if (lflag || eflag) {
X hprint(h, ofp, 0);
X return;
X }
X
X /* Print out a header */
X if (ngrp) {
X pngsize = ngsize;
X ngrp--;
X nghprint(groupdir);
X }
X if (!hflag)
X fprintf(ofp, "Article %ld of %ld, %s.\n",
X bit, pngsize, briefdate(h->subdate));
X hprint(h, ofp, pflag ? 1 : 0);
X}
X
Xnghprint(title)
Xchar *title;
X{
X char *tstr = "Newsgroup ";
X int l = strlen(title) + strlen(tstr);
X
X fprintf(ofp, "\n");
X if (!hflag) {
X dash(l, ofp);
X fprintf(ofp, "%s%s\n", tstr, title);
X dash(l, ofp);
X } else {
X fprintf(ofp, "%s%s, ", tstr, title);
X if (bit == pngsize)
X fprintf(ofp, "%ld\n", pngsize);
X else
X fprintf(ofp, "%ld-%ld\n", bit, pngsize);
X }
X fprintf(ofp, "\n");
X}
X
X/*
X * Routine to catch a continue signal.
X */
Xcatchcont(sig)
Xint sig;
X{
X signal(sig, catchcont);
X sigtrap = sig;
X fflush(ofp);
X#ifdef SIGCONT
X if (fp && sig == SIGCONT)
X hdr();
X if (sig != SIGCONT)
X#endif SIGCONT
X putc('\n', ofp);
X if (canlongjmp)
X longjmp(sigjmpbuf,1);
X}
*-*-END-of-src/readr.c-*-*
echo x - src/visual.c
sed 's/^X//' >src/visual.c <<'*-*-END-of-src/visual.c-*-*'
X/*
X * readr - visual news interface.
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)visual.c 1.12 9/5/84";
Xstatic char Author[] = "@(#)visual interface written by Kenneth Almquist";
X#endif !lint
X
X#define GGRMAIL
X#ifdef USG
X#include <termio.h>
X#include <fcntl.h>
X#else
X#include <sgtty.h>
X#endif USG
X
X#include <errno.h>
X#include "rparams.h"
X#if defined(BSD4_2) || defined(BSD4_1C)
X#include <sys/dir.h>
X#else
X#include "ndir.h"
X#endif
X#ifdef BSD4_2
X#define BIT(_a) (1<<((_a)-1))
X#endif
X#ifdef MYDB
X#include "db.h"
X#endif MYDB
X
X#include <errno.h>
X
Xextern int errno;
X
X#ifdef SIGTSTP
X#include <setjmp.h>
X#endif
X
X#define ARTWLEN (ROWS-2)/* number of lines used to display article */
X#define even(cols) ((cols&1) ? cols + 1 : cols)
X#ifdef STATTOP
X#define PRLINE 0 /* prompter line */
X#define SPLINE 1 /* secondary prompt line */
X#define ARTWIN 2 /* first line of article window */
X#define SECPRLEN 81 /* length of secondary prompter */
X#else
X#define PRLINE (ROWS-1)/* prompter line */
X#define SPLINE (ROWS-2)/* secondary prompt line */
X#define ARTWIN 0 /* first line of article window */
X#define SECPRLEN 100 /* length of secondary prompter */
X#endif
X
X#define PIPECHAR '|' /* indicate save command should pipe to program */
X#define META 0200 /* meta character bit (as in emacs) */
X/* print (display) flags */
X#define HDRONLY 0001 /* print header only */
X#define NOPRT 0002 /* don't print at all */
X#define NEWART 0004 /* force article display to be regenerated */
X#define HELPMSG 0010 /* display currently contains help message */
X/* prun flags */
X#define CWAIT 0001 /* type "continue?" and wait for return */
X#define BKGRND 0002 /* run process in the background */
X/* values of curflag */
X#define CURP1 1 /* cursor after prompt */
X#define CURP2 2 /* cursor after secondary prompt */
X#define CURHOME 3 /* cursor at home position */
X/* flags for vsave routine */
X#define SVHEAD 01 /* write out article header */
X#define OVWRITE 02 /* overwrite the file if it already exists */
X/* other files */
X
X#define saveart oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hptr = h;h = hold;hold = hptr;ongsize = pngsize
X#define NLINES(h, fp) (h->numlines[0] ? h->intnumlines : (h->intnumlines=linecnt(fp),sprintf(h->numlines, "%d", h->intnumlines), h->intnumlines))
X
X/* terminal handler stuff */
Xextern int _junked;
X#define clearok(xxx, flag) _junked = flag
Xextern int COLS;
Xextern int ROWS;
Xextern int hasscroll;
X
XFILE *tmpfile();
Xchar *getmailname();
Xchar *findparent();
Xint onint(), onquit();
Xint onstop();
X
X/*
X * Kludge: space so that routines can access beyond
X * the end of arrays without messing me up.
X */
Xstatic char junk[64];
X
Xchar *Progname = "vnews"; /* for xerror */
X
X/* variables shared between vnews routines */
Xstatic char linebuf[LBUFLEN]; /* temporary workspace */
Xstatic FILE *tfp; /* temporary file */
Xstatic char tfname[] = "/tmp/vnXXXXXX"; /* name of temp file */
Xstatic long artbody; /* offset of body into article */
Xstatic int quitflg; /* if set, then quit */
Xstatic int erased; /* current article has been erased */
Xstatic int artlines; /* # lines in article body */
Xstatic int artread; /* entire article has been read */
Xstatic int hdrstart; /* beginning of header */
Xstatic int hdrend; /* end of header */
Xstatic int lastlin; /* number of lines in tempfile */
Xstatic int tflinno = 0; /* next line in tempfile */
Xstatic int maxlinno; /* number of lines in file + folded */
Xstatic char secpr[SECPRLEN]; /* secondary prompt */
Xstatic char prompt[30]; /* prompter */
Xstatic short prflags; /* print flags (controls updscr) */
Xstatic short curflag; /* where to locate cursor */
Xstatic int dlinno; /* top line on screen */
Xstatic char timestr[20]; /* current time */
Xstatic int ismail; /* true if user has mail */
Xstatic char *mailf; /* user's mail file */
Xstatic int alflag; /* set if unprocessed alarm signal */
Xstatic int atend; /* set if at end of article */
Xstatic char cerase; /* erase character */
Xstatic char ckill; /* kill character */
Xstatic char cintr; /* interrupt character */
Xint ospeed; /* terminal speed */
Xstatic int intflag; /* set if interrupt received */
X
X#ifdef SIGTSTP
Xstatic int reading; /* to keep stupid BSD from restarting reads */
Xjmp_buf intjmp, alrmjmp;
X#endif SIGTSTP
X
X#ifdef MYDB
Xstatic int hasdb; /* true if article data base exists */
X#endif
X
X#ifdef DIGPAGE
Xstatic int endsuba; /* end of sub-article in digest */
X#endif
X
X#ifdef MYDEBUG
XFILE *debugf; /* file to write debugging info on */
X#endif
X
Xchar *tft = "/tmp/folXXXXXX";
X
X/*
X * These were made static for u370 with its buggy cc.
X * I judged it better to have one copy with no ifdefs than
X * to conditionally compile them as automatic variables
X * in readr (which they originally were). Performance
X * considerations might warrent moving some of the simple
X * things into register variables, but I don't know what
X * breaks the u370 cc.
X */
Xstatic char goodone[BUFLEN]; /* last decent article */
Xstatic char ogroupdir[BUFLEN]; /* last groupdir */
Xstatic char edcmdbuf[128];
Xstatic int rfq = 0; /* for last article */
Xstatic long ongsize; /* Previous ngsize */
Xstatic long pngsize; /* Printing ngsize */
Xstatic char *bptr; /* temp pointer. */
Xstatic char *tfilename; /* temporary file name */
Xstatic char ofilename1[BUFLEN]; /* previous file name */
Xstatic struct hbuf hbuf1, hbuf2; /* for minusing */
Xstatic struct hbuf *h = &hbuf1, /* current header */
X *hold = &hbuf2, /* previous header */
X *hptr; /* temporary */
Xstatic char *ptr1, *ptr2, *ptr3; /* for reply manipulation */
Xstatic int news = 0;
Xstatic int aabs = FALSE; /* TRUE if we asked absolutely */
Xstatic char *ed, tf[100];
Xstatic long oobit; /* last bit, really */
Xstatic int dgest = 0;
Xstatic FILE *fp; /* current article to be printed*/
X
Xreadr()
X{
X
X#ifdef MYDEBUG
X debugf = fopen("DEBUG", "w");
X setbuf(debugf, (char *)NULL);
X#endif
X if (aflag) {
X if (*datebuf) {
X if ((atime = cgtdate(datebuf)) == -1)
X xerror("Cannot parse date string");
X } else
X atime = 0;
X }
X
X if (sigtrap)
X xxit(1);
X mktemp(tfname);
X close(creat(tfname,0666));
X if ((tfp = fopen(tfname, "w+")) == NULL)
X xerror("Can't create temp file");
X unlink(tfname);
X mailf = getmailname();
X#ifdef MYDB
X if (opendb() >= 0) {
X hasdb = 1;
X fputs("Using article data base\n", stderr); /*DEBUG*/
X getng();
X }
X#endif
X ttysave();
X signal(SIGINT, onint);
X signal(SIGQUIT, onquit);
X if (sigtrap)
X xxit(1);
X ttyraw();
X timer();
X
X /* loop reading articles. */
X fp = NULL;
X obit = -1;
X nextng();
X quitflg = 0;
X while (quitflg == 0) {
X if (getnextart(FALSE))
X break;
X strcpy(goodone, filename);
X if (sigtrap)
X return;
X vcmd();
X }
X
X if (news)
X botscreen();
X ttycooked();
X if (!news)
X fprintf(stderr, "No news.\n");
X}
X
X/*
X * Read and execute a command.
X */
X
Xvcmd() {
X register c;
X char *p;
X long count;
X int countset;
X
X appfile(fp, dlinno + ARTWLEN + 1);
X#ifdef DIGPAGE
X endsuba = findend(dlinno);
X if (artlines > dlinno + ARTWLEN
X || endsuba > 0 && endsuba < artlines
X#else
X if (artlines > dlinno + ARTWLEN
X#endif
X || (prflags & HDRONLY) && artlines > hdrend) {
X atend = 0;
X if (prflags&HDRONLY)
X strcpy(prompt,"more? ");
X else
X sprintf(prompt,"more(%d%%)? ",((dlinno+ARTWLEN-hdrend)*100)/maxlinno);
X } else {
X atend = 1;
X strcpy(prompt, "next? ");
X if (!erased)
X clear(bit); /* article read */
X }
X curflag = CURP1;
X p = prompt + strlen(prompt);
X countset = 0;
X count = 0;
X while ((c = vgetc()) >= '0' && c <= '9' || c==cerase || c ==ckill) {
X if (c == cerase) {
X count /= 10;
X if (count == 0)
X countset = 0;
X continue;
X }
X if (c == ckill) {
X countset = 0;
X count = 0;
X continue;
X }
X count = (count * 10) + (c - '0');
X sprintf(p, "%ld", count);
X countset = 1;
X }
X if (c == '\033') { /* escape */
X strcat(prompt, "M-");
X c = vgetc();
X if (c != cintr)
X c |= META;
X }
X secpr[0] = '\0';
X if (countset == 0)
X count = 1;
X docmd(c, count);
X if (c != '?' && c != 'H') /* UGGH */
X prflags &=~ HELPMSG;
X if (dlinno > hdrstart)
X prflags &=~ HDRONLY;
X}
X
X
X/*
X * Process one command, which has already been typed in.
X */
Xdocmd(c, count)
Xchar c;
Xlong count;
X{
X int i;
X long nart;
X char *findhist();
X
X switch (c) {
X
X /* Show more of current article, or advance to next article */
X case '\n':
X case ' ':
X case '\06': /* Control-F for vi compat */
X prflags &=~ NOPRT;
X if (atend)
X goto next;
X else if (prflags & HDRONLY) {
X prflags &=~ HDRONLY;
X if (hasscroll)
X dlinno = hdrstart;}
X#ifdef DIGPAGE
X else if (endsuba > 0)
X dlinno = endsuba;
X#endif
X else if ((appfile(fp, dlinno + 2 * ARTWLEN), artread)
X && hasscroll && artlines - dlinno <= ARTWLEN + 2)
X dlinno = artlines - ARTWLEN;
X else
X dlinno += ARTWLEN;
X break;
X
X /* No. Go on to next article. */
X case '.': /* useful if you have a keypad */
Xnext: case 'n':
X readmode = NEXT;
X FCLOSE(fp);
X clear(bit);
X saveart;
X nextbit();
X break;
X
X
X /* Back up count pages */
X case META|'v':
X case '\2': /* Control-B */
X dlinno -= ARTWLEN * count;
X if (dlinno < 0)
X dlinno = 0;
X break;
X
X /* forward half a page */
X case '\4': /* Control-D, as in vi */
X dlinno += ARTWLEN/2 * count;
X break;
X
X /* backward half a page */
X case '\25': /* Control-U */
X dlinno -= ARTWLEN/2 * count;
X if (dlinno < 0)
X dlinno = 0;
X break;
X
X /* forward count lines */
X case '\16': /* Control-N */
X case '\32': /* Control-Z */
X dlinno += count;
X break;
X
X /* backwards count lines */
X case '\20': /* Control-P */
X case '\31': /* Control-Y */
X dlinno -= count;
X if (dlinno < 0)
X dlinno = 0;
X break;
X
X /* Turn displaying of article back on */
X case 'l':
X case 'd':
X prflags &=~ NOPRT;
X break;
X
X /* display header */
X case 'h':
X dlinno = hdrstart;
X prflags |= HDRONLY;
X prflags &=~ NOPRT;
X break;
X
X /*
X * Unsubscribe to the newsgroup and go on to next group
X */
X
X case 'U':
X case 'u':
X strcat(prompt, "u");
X c = vgetc();
X if (c == 'g') {
X obit = -1;
X FCLOSE(fp);
X zapng = TRUE;
X saveart;
X if (nextng()) {
X if (actdirect == BACKWARD)
X msg("Can't back up.");
X else
X quitflg = 1; /* probably unnecessary */
X }
X } else {
X if (c != cintr && c != ckill)
X msg("Illegal command");
X }
X break;
X
X /* Print the current version of news */
X case 'v':
X msg("News version: %s", news_version);
X break;
X
X
X /* Decrypt joke. Always does rot 13 */
X case 'D':
X appfile(fp, 32767);
X for (i = hdrend ; i < artlines ; i++) {
X register char ch, *p;
X tfget(linebuf, i);
X for (p = linebuf ; (ch = *p) != '\0' ; p++) {
X if (ch >= 'a' && c <= 'z')
X *p = (ch - 'a' + 13) % 26 + 'a';
X else if (ch >= 'A' && c <= 'Z')
X *p = (ch - 'A' + 13) % 26 + 'A';
X }
X tfput(linebuf, i);
X }
X prflags |= NEWART;
X prflags &=~ (HDRONLY|NOPRT);
X break;
X
X /* write out the article someplace */
X /* w writes out without the header */
X case 's':
X case 'w': {
X char *grn = groupdir;
X int wflags;
X
X msg("file: ");
X curflag = CURP2;
X while ((wflags = vgetc()) == ' ');
X if (wflags == cintr) {
X secpr[0] = '\0';
X break;
X }
X if (wflags == '|') {
X linebuf[0] = '|';
X if (prget("| ", linebuf+1))
X break;
X } else {
X pushback(wflags);
X if (prget("file: ", linebuf))
X break;
X }
X wflags = 0;
X if (c == 's')
X wflags |= SVHEAD;
X if (count != 1)
X wflags |= OVWRITE;
X bptr = linebuf;
X while( *bptr == ' ')
X bptr++; /* strip leading spaces */
X
X if (*bptr != PIPECHAR && *bptr != '/') {
X char hetyped[BUFLEN];
X char *boxptr;
X strcpy(hetyped, bptr);
X if (boxptr = getenv("NEWSBOX"))
X if (index(boxptr, '%'))
X sprintf(bptr, boxptr, grn);
X else
X strcpy(bptr, boxptr);
X else if (hetyped[0] == '~' && hetyped[1] == '/') {
X strcpy(hetyped, bptr+2);
X strcpy(bptr, userhome);
X } else
X bptr[0] = '\0';
X if (bptr[0])
X strcat(bptr, "/");
X if (hetyped[0] != '\0')
X strcat(bptr, hetyped);
X else
X strcat(bptr, "Articles");
X }
X vsave(bptr, wflags);
X break;
X }
X
X /* back up */
X case '-':
X aabs = TRUE;
X if (!*ofilename1) {
X msg("Can't back up.");
X break;
X }
X FCLOSE(fp);
X hptr = h;
X h = hold;
X hold = hptr;
X strcpy(bfr, filename);
X strcpy(filename, ofilename1);
X strcpy(ofilename1, bfr);
X obit = bit;
X if (strcmp(groupdir, ogroupdir)) {
X strcpy(bfr, groupdir);
X selectng(ogroupdir, FALSE);
X strcpy(groupdir, ogroupdir);
X strcpy(ogroupdir, bfr);
X ngrp = 1;
X back();
X }
X bit = oobit;
X oobit = obit;
X obit = -1;
X getnextart(TRUE);
X return FALSE;
X
X /* skip forwards */
X case '+':
Xcaseplus: if (count == 0)
X break;
X saveart;
X last = bit;
X for (i = 0; i < count; i++) {
X nextbit();
X if ((bit > pngsize) || (rflag && bit < 1))
X break;
X }
X FCLOSE(fp);
X obit = -1;
X break;
X
X /* exit - time updated to that of most recently read article */
X case 'q':
X quitflg = 1;
X break;
X
X case 'x':
X onquit();
X break;
X
X /* cancel the article. */
X case 'c':
X strcpy(prompt, "cancel [n]? ");
X if (vgetc() != 'y') {
X msg("Article not cancelled");
X break;
X }
X cancel_command();
X break;
X
X /* escape to shell */
X case '!': {
X register char *p;
X int flags;
X
X p = linebuf;
X if (prget("!", p))
X break;
X flags = CWAIT;
X if (*p == '\0') {
X strcpy(linebuf, SHELL);
X flags = 0;
X }
X while (*p) p++;
X while (p > linebuf && p[-1] == ' ')
X p--;
X if (*--p == '&') {
X *p = '\0';
X flags = BKGRND;
X } else if (*p == '|') {
X *p = '\0';
X sprintf(bfr, "(%s)|mail '%s'", linebuf, username);
X strcpy(linebuf, bfr);
X flags |= BKGRND;
X } else {
X prflags |= NOPRT;
X }
X shcmd(linebuf, flags);
X break;
X }
X
X /* mail reply */
X case 'r':
X reply();
X break;
X
X
X /* next newsgroup */
X case 'N':
X FCLOSE(fp);
X if (next_ng_command())
X quitflg = 1;
X break;
X
X /* mark the rest of the articles in this group as read */
X case 'K':
X saveart;
X while (bit <= ngsize && bit > minartno) {
X clear(bit);
X nextbit();
X }
X FCLOSE(fp);
X break;
X
X /* Print the full header */
X case 'H':
X {
X if (fp == NULL) {
X msg("No current article");
X break;
X }
X move(ARTWIN, 0);
X fseek(fp, 0L, 0);
X for (i=0;i<ARTWLEN;i++) {
X if (fgets(linebuf, COLS, fp) == NULL)
X break;
X if (linebuf[0] == '\n')
X break;
X linebuf[COLS] = '\0';
X addstr(linebuf);
X }
X for(;i<ARTWLEN; i++)
X addstr(linebuf);
X prflags |= HELPMSG|NEWART;
X }
X break;
X case 'b': /* backup 1 article */
X count = bit - 1;
X /* NO BREAK */
X
X case 'A': /* specific number */
X if (count > pngsize) {
X msg("not that many articles");
X break;
X }
X readmode = SPEC;
X aabs = TRUE;
X bit = count;
X obit = -1;
X FCLOSE(fp);
X break;
X
X /* display parent article */
X case 'p':
X#ifdef MYDB
X if (hasdb && (ptr3 = findparent(h->ident, &nart)) != NULL) {
X msg("parent: %s/%ld", ptr3, nart); /*DEBUG*/
X updscr(); /*DEBUG*/
X goto selectart;
X }
X#endif
X if (h->followid[0] == '\0') {
X msg("no references line");
X break;
X }
X if ((ptr1 = rindex(h->followid, ' ')) != NULL)
X ptr1++;
X else
X ptr1 = h->followid;
X strcpy(linebuf, ptr1);
X msg("%s", linebuf);
X curflag = CURP2;
X updscr(); /* may take this out later */
X goto searchid;
X
X /* specific message ID. */
X case '<':
X /* could improve this */
X linebuf[0] = '<';
X if (prget("<", linebuf+1))
X break;
Xsearchid: secpr[0] = '\0';
X if (index(linebuf, '@') == NULL && index(linebuf, '>') == NULL) {
X ptr1 = linebuf;
X if (*ptr1 == '<')
X ptr1++;
X ptr2 = index(ptr1, '.');
X if (ptr2 != NULL) {
X *ptr2++ = '\0';
X sprintf(bfr, "<%s@%s.UUCP>", ptr2, ptr1);
X strcpy(linebuf, bfr);
X }
X }
X if (index(linebuf, '>') == NULL)
X strcat(linebuf, ">");
X
X ptr1 = findhist(linebuf);
X if (ptr1 == NULL) {
X msg("%s not found", linebuf);
X break;
X }
X ptr2 = index(ptr1, '\t');
X ptr3 = index(++ptr2, '\t');
X ptr2 = index(++ptr3, ' ');
X if (ptr2)
X *ptr2 = '\0';
X ptr2 = index(ptr3, '/');
X *ptr2++ = '\0';
X sscanf(ptr2, "%ld", &nart);
X
X /*
X * Go to a given article. Ptr3 specifies the newsgroup
X * and nart specifies the article number.
X */
Xselectart: aabs = TRUE;
X FCLOSE(fp);
X saveart;
X strcpy(ogroupdir, ptr3);
X if (strcmp(groupdir, ogroupdir)) {
X strcpy(bfr, groupdir);
X selectng(ogroupdir, TRUE);
X strcpy(groupdir, ogroupdir);
X strcpy(ogroupdir, bfr);
X back();
X }
X bit = nart;
X oobit = obit;
X obit = -1;
X getnextart(TRUE);
X rfq = 0;
X break;
X
X /* follow-up article */
X case 'f':
X sprintf(bfr, "%s/%s %s", BIN, "postnews", goodone);
X shcmd(bfr, CWAIT);
X break;
X
X /* erase - pretend we haven't seen this article. */
X case 'e':
X erased = 1;
X set(bit);
X goto caseplus; /* skip this article for now */
X
X case '#':
X msg("Article %ld of %ld", rfq ? oobit : bit, pngsize);
X break;
X
X /* error */
X case '?':
X {
X FILE *helpf;
X sprintf(linebuf, "%s/vnews.help", LIB);
X if ((helpf = fopen(linebuf, "r")) == NULL) {
X msg("Can't open help file");
X break;
X }
X move(ARTWIN, 0);
X while (fgets(linebuf, LBUFLEN, helpf) != NULL)
X addstr(linebuf);
X fclose(helpf);
X prflags |= HELPMSG|NEWART;
X }
X break;
X
X default:
X if (c != ckill && c != cintr)
X msg("Illegal command");
X break;
X }
X
X return FALSE;
X}
X
Xcancel_command()
X{
X tfilename = filename;
X /*readmode = SPEC; bug? */
X strcpy(rcbuf, h->path);
X ptr1 = index(rcbuf, ' ');
X if (ptr1)
X *ptr1 = 0;
X if (uid != ROOTID && strcmp(username, rcbuf)) {
X msg("Can't cancel what you didn't write.");
X return;
X }
X if (!cancel(stderr, h, 0)) {
X clear(bit);
X saveart;
X nextbit();
X obit = -1;
X fp = NULL;
X }
X FCLOSE(fp);
X}
X
X/*
X * Generate replies
X */
X
Xreply()
X{
X char *arg[4];
X register FILE *rfp;
X char subj[132];
X char *nogomsg;
X register char *p;
X char *replyname();
X struct stat statb;
X time_t creatm;
X
X /* Put the user in the editor to create the body of the reply. */
X ed = getenv("EDITOR");
X if (ed == NULL || *ed == '\0')
X ed = DFTEDITOR;
X if (ed == NULL) {
X msg("You don't have an editor");
X return;
X }
X
X arg[0] = "/bin/sh";
X arg[1] = "-c";
X
X strcpy(tf, tft);
X mktemp(tf);
X close(creat(tf,0666));
X if ((rfp = fopen(tf, "w")) == NULL) {
X msg("Can't create %s", tf) ;
X return;
X }
X strcpy(subj, h->title);
X if (!prefix(subj, "Re:")){
X strcpy(bfr, subj);
X sprintf(subj, "Re: %s", bfr);
X }
X
X#ifdef INTERNET
X if (h->sender[0])
X p = h->sender;
X else
X#endif
X p = replyname(h);
X fprintf(rfp, "To: %s\n", p);
X fprintf(rfp, "Subject: %s\n", subj);
X fprintf(rfp, "In-reply-to: your article %s\n", h->ident);
X sprintf(rcbuf, "exec %s -t < %s; rm %s", MAILPARSER, tf, tf);
X nogomsg = "Mail not sent";
X putc('\n', rfp);
X fstat(fileno(rfp), &statb);
X creatm = statb.st_mtime;
X fclose(rfp);
X
X sprintf(edcmdbuf, "exec %s %s", ed, tf);
X arg[2] = edcmdbuf;
X arg[3] = NULL;
X if (prun(arg, 0) != 0) {
X msg("Couldn't run editor");
X unlink(tf);
X return;
X }
X
X if (access(tf, 4) || stat(tf, &statb)) {
X msg("%s: no input file.", nogomsg);
X unlink(tf);
X return;
X }
X if (statb.st_mtime == creatm) {
X msg("%s: cancelled.", nogomsg);
X unlink(tf);
X return;
X }
X
X arg[2] = rcbuf;
X arg[3] = NULL;
X prun(arg, BKGRND);
X prflags |= NOPRT;
X}
X
Xnext_ng_command()
X{
X obit = -1;
X if (prget("group? ", linebuf))
X return FALSE;
X bptr = linebuf;
X if (!*bptr || *bptr == '-') {
X if (*bptr)
X actdirect = BACKWARD;
X saveart;
X if (nextng()) {
X if (actdirect == BACKWARD)
X msg("Can't back up.");
X else
X return TRUE;
X }
X return FALSE;
X }
X while (isspace(*bptr))
X bptr++;
X if (!validng(bptr)) {
X msg("No such group.");
X return FALSE;
X }
X readmode = SPEC;
X saveart;
X back();
X selectng(bptr, TRUE);
X return FALSE;
X}
X
X/*
X * Find the next article we want to consider, if we're done with
X * the last one, and show the header.
X */
Xgetnextart(minus)
Xint minus;
X{
X int noaccess;
X register DIR *dirp;
X register struct direct *dir;
X long nextnum, tnum;
X long atol();
X
X noaccess = 0;
X if (minus)
X goto nextart2; /* Kludge for "-" command. */
X
X if (bit == obit) /* Return if still on same article as last time */
X return 0;
X
Xnextart:
X if (news) {
X curflag = CURHOME;
X _amove(0, 0);
X vflush();
X }
X dgest = 0;
X
X /* If done with this newsgroup, find the next one. */
X while (ngsize <= 0 || ((long) bit > ngsize) || (rflag && bit < minartno)) {
X if (nextng()) {
X if (actdirect == BACKWARD) {
X msg("Can't back up.");
X actdirect = FORWARD;
X continue;
X }
X else /* if (rfq++ || pflag || cflag) */
X return 1;
X }
X if (rflag)
X bit = ngsize + 1;
X else
X bit = -1;
X noaccess = 2;
X }
X
X /* speed things up by not searching for article -1 */
X if (bit < 0) {
X bit = minartno - 1;
X nextbit();
X aabs = FALSE;
X goto nextart;
X }
X
Xnextart2:
X if (rcreadok)
X rcreadok = 2; /* have seen >= 1 article */
X sprintf(filename, "%s/%ld", dirname(groupdir), bit);
X if (rfq && goodone[0]) /* ??? */
X strcpy(filename, goodone);
X if (sigtrap == SIGHUP)
X return 1;
X /* Decide if we want to show this article. */
X if ((fp = fopen(filename, "r")) == NULL) {
X /* since there can be holes in legal article numbers, */
X /* we wait till we hit 5 consecutive bad articles */
X /* before we haul off and scan the directory */
X if (++noaccess < 5)
X goto badart;
X noaccess = 0;
X dirp = opendir(dirname(groupdir));
X if (dirp == NULL) {
X if (errno != EACCES)
X msg("Can't open %s", dirname(groupdir));
X goto nextart;
X }
X nextnum = rflag ? minartno - 1 : ngsize + 1;
X while ((dir = readdir(dirp)) != NULL) {
X if (!dir->d_ino)
X continue;
X tnum = atol(dir->d_name);
X if (tnum <= 0)
X continue;
X if (rflag ? (tnum > nextnum && tnum < bit)
X : (tnum < nextnum && tnum > bit))
X nextnum = tnum;
X }
X closedir(dirp);
X if (rflag ? (nextnum >= bit) : (nextnum <= bit))
X goto badart;
X do {
X clear(bit);
X nextbit();
X } while (rflag ? (nextnum < bit) : (nextnum > bit));
X obit = -1;
X aabs = FALSE;
X goto nextart;
X } else
X noaccess = 0;
X
X if (hread(h, fp, TRUE) == NULL || (!rfq && !aselect(h, aabs))) {
Xbadart:
X FCLOSE(fp);
X clear(bit);
X obit = -1;
X nextbit();
X aabs = FALSE;
X goto nextart;
X }
X aabs = FALSE;
X actdirect = FORWARD;
X news = TRUE;
X { /* strip off any notesfile header */
X register c;
X register char *p = h->title + strlen(h->title) - 5;
X if (p > h->title
X && (strcmp(p, " (nf)") == 0 || strcmp(p, "(nf)\"") == 0)) {
X if ((c = getc(fp)) != '#') {
X ungetc(c, fp);
X } else {
X while ((c = getc(fp)) != '\n' && c != EOF);
X while ((c = getc(fp)) != '\n' && c != EOF);
X while ((c = getc(fp)) != '\n' && c != EOF);
X }
X }
X }
X artbody = ftell(fp);
X fmthdr();
X artlines = lastlin;
X artread = 0;
X prflags |= NEWART;
X prflags &=~ NOPRT;
X if (! cflag && hdrend < ARTWLEN && !cflag)
X prflags |= HDRONLY;
X dlinno = 0;
X maxlinno = NLINES(h, fp);
X erased = 0;
X
X obit = bit;
X return 0;
X}
X
X/*
X * Print out whatever the appropriate header is
X */
Xfmthdr() {
X char *briefdate();
X
X lastlin = 0;
X if (ngrp) {
X pngsize = ngsize;
X ngrp--;
X if (!hflag) {
X sprintf(linebuf, "Newsgroup %s", groupdir); tfappend(linebuf);
X tfappend("");
X }
X }
X hdrstart = lastlin;
X if (!hflag) {
X sprintf(linebuf, "Article %s %s",
X h->ident, briefdate(h->subdate));
X tfappend(linebuf);
X }
X vhprint(h, pflag ? 1 : 0);
X sprintf(linebuf, "(%d lines)", NLINES(h, fp)); tfappend(linebuf);
X tfappend("");
X hdrend = lastlin;
X}
X
X/*
X * Print the file header to the temp file.
X */
Xvhprint(hp, verbose)
Xregister struct hbuf *hp;
Xint verbose;
X{
X register char *p1, *p2;
X int i;
X char fname[BUFLEN];
X char *tailpath();
X
X fname[0] = '\0'; /* init name holder */
X
X p1 = index(hp->from, '('); /* Find the sender's full name. */
X if (p1 == NULL && hp->path[0])
X p1 = index(hp->path, '(');
X if (p1 != NULL) {
X strcpy(fname, p1+1);
X p2 = index(fname, ')');
X if (p2 != NULL)
X *p2 = '\0';
X }
X
X sprintf(linebuf, "Subject: %s", hp->title);
X if ((i = strlen(linebuf) - 7) > 9
X && strcmp(linebuf + i, " - (nf)") == 0
X && (strncmp(linebuf+9, "Re: ", 4) != 0 || i < 9+39))
X linebuf[i] = '\0'; /* clobber "- (nf)" */
X tfappend(linebuf);
X if (!hflag && hp->keywords[0])
X sprintf(linebuf, "Keywords: %s", hp->keywords), tfappend(linebuf);
X if (verbose) {
X sprintf(linebuf, "From: %s", hp->from); tfappend(linebuf);
X sprintf(linebuf, "Path: %s", hp->path); tfappend(linebuf);
X if (hp->organization[0])
X sprintf(linebuf, "Organization: %s", hp->organization), tfappend(linebuf);
X }
X else {
X if (p1 != NULL)
X *--p1 = '\0'; /* bump over the '(' */
X#ifdef INTERNET
X /*
X * Prefer Path line if it's in internet format, or if we don't
X * understand internet format here, or if there is no reply-to.
X */
X sprintf(linebuf, "From: %s", hp->from);
X#else
X sprintf(linebuf, "Path: %s", tailpath(hp));
X#endif
X if (fname[0] || hp->organization[0]) {
X strcat(linebuf, " (");
X if (fname[0] == '\0') {
X strcpy(fname,hp->from);
X p2 = index(fname,'@');
X if (p2)
X *p2 = '\0';
X }
X strcat(linebuf, fname);
X if (hp->organization[0] && !hflag) {
X strcat(linebuf, " @ ");
X strcat(linebuf, hp->organization);
X }
X strcat(linebuf, ")");
X }
X tfappend(linebuf);
X if (p1 != NULL)
X *p1 = ' ';
X if (hp->ctlmsg[0]) {
X sprintf(linebuf, "Control: %s", hp->ctlmsg);
X tfappend(linebuf);
X }
X }
X
X strcpy(bfr, hp->nbuf);
X ngdel(bfr);
X if (verbose) {
X sprintf(linebuf, "Newsgroups: %s", bfr); tfappend(linebuf);
X sprintf(linebuf, "Date: %s", hp->subdate); tfappend(linebuf);
X if (hp->sender[0])
X sprintf(linebuf, "Sender: %s", hp->sender), tfappend(linebuf);
X if (hp->replyto[0])
X sprintf(linebuf, "Reply-To: %s", hp->replyto), tfappend(linebuf);
X if (hp->followto[0])
X sprintf(linebuf, "Followup-To: %s", hp->followto), tfappend(linebuf);
X }
X else if (strcmp(bfr, groupdir) != 0)
X sprintf(linebuf, "Newsgroups: %s", bfr), tfappend(linebuf);
X}
X
X
X
X
X#ifdef MYDB
X
X
Xchar *
Xfindparent(id, num)
Xchar *id;
Xlong *num;
X{
X register char *rcp;
X struct artrec a;
X char idbuf[BUFSIZE];
X char *ngname();
X
X strcpy(idbuf, id);
X rcp = idbuf;
X while(*++rcp)
X if (isupper(*rcp))
X *rcp = tolower(*rcp);
X
X if (lookart(id, &a) == DNULL)
X return NULL;
X if (a.parent == DNULL)
X return NULL;
X readrec(a.parent, &a);
X *num = a.groups[0].artno;
X return ngname(a.groups[0].newsgroup);
X}
X
X#endif
X
X
X/*
X * Append file to temp file, handling control characters, folding lines, etc.
X * We don't grow the temp file to more than nlines so that a user won't have
X * to wait for 20 seconds to read in a monster file from net.sources.
X * What we really want is coroutines--any year now.
X */
X
X#define ULINE 0200
Xstatic char *maxcol;
X
Xappfile(iop, nlines)
Xregister FILE *iop;
X{
X register int c;
X register char *icol; /* &linebuf[0] <= icol <= maxcol */
X
X if (artread || artlines >= nlines || iop == NULL)
X return;
X maxcol = linebuf;
X icol = linebuf;
X while ((c = getc(iop)) != EOF) {
X switch (c) {
X case ' ':
X if (icol == maxcol && icol < linebuf + LBUFLEN - 1) {
X *icol++ = ' ';
X maxcol = icol;
X } else {
X icol++;
X }
X break;
X case '\t':
X icol = (icol - linebuf &~ 07) + 8 + linebuf;
X growline(icol);
X break;
X case '\b':
X if (icol > linebuf) --icol;
X break;
X case '\n':
X outline();
X if (artlines >= nlines)
X return;
X icol = linebuf;
X break;
X case '\r':
X icol = linebuf;
X break;
X case '\f':
X outline(); outline(); outline();
X if (artlines >= nlines)
X return;
X icol = linebuf;
X break;
X default:
X if (c < ' ' || c > '~')
X break;
X else if (icol >= linebuf + LBUFLEN - 1)
X icol++;
X else if (icol == maxcol) {
X *icol++ = c;
X maxcol = icol; }
X else if (*icol == ' ')
X *icol++ = c;
X else if (c == '_')
X *icol++ |= ULINE;
X else
X *icol++ = (c | ULINE);
X break;
X }
X }
X if (maxcol != linebuf) /* file not terminated with newline */
X outline();
X artread++;
X}
X
Xgrowline(col)
Xchar *col;
X{
X while (maxcol < col && maxcol < linebuf + LBUFLEN - 1)
X *maxcol++ = ' ';
X}
X
Xoutline()
X{
X *maxcol = '\0';
X if (strncmp(linebuf, ">From ", 6) == 0) {
X register char *p;
X for (p = linebuf ; (*p = p[1]) != '\0' ; p++);
X }
X tfappend(linebuf);
X if (maxcol > linebuf)
X artlines = lastlin;
X maxcol = linebuf;
X}
X
Xprget(prompter, buf)
Xchar *prompter, *buf;
X{
X char *p, *q, *r;
X int c, lastc;
X
X curflag = CURP2;
X r = buf;
X lastc = '\0';
X for (;;) {
X *r = '\0';
X p = secpr;
X for (q = prompter ; *q ; q++)
X *p++ = *q;
X for (q = buf ; *q ; q++) {
X if (p < &secpr[SECPRLEN-1] && *q >= ' ' && *p <= '~')
X *p++ = *q;
X }
X *p = '\0';
X c = vgetc();
X if (c == '\n' || c == cintr) {
X break;
X }
X if (c == cerase) {
X if (lastc == '\\')
X r[-1] = c;
X else if (r > buf)
X r--;
X } else if (c == ckill) {
X if (lastc == '\\')
X r[-1] = c;
X else
X r = buf;
X } else {
X *r++ = c;
X }
X lastc = c;
X }
X curflag = CURHOME;
X secpr[0] = '\0';
X return (c == cintr);
X}
X
X
X
X/*
X * Execute a shell command.
X */
X
Xshcmd(cmd, flags)
Xchar *cmd;
X{
X char *arg[4];
X
X arg[0] = SHELL, arg[1] = "-c", arg[2] = cmd, arg[3] = NULL;
X return prun(arg, flags);
X}
X
X
Xprun(args, flags)
Xchar **args;
X{
X int pid;
X int i;
X int (*savequit)();
X char *env[100], **envp;
X char a[BUFLEN + 2];
X extern char **environ;
X int pstatus, retval;
X
X if (!(flags & BKGRND)) {
X botscreen();
X ttycooked();
X#ifdef SIGTSTP
X signal(SIGTSTP, SIG_DFL);
X signal(SIGTTIN, SIG_DFL);
X signal(SIGTTOU, SIG_DFL);
X#endif
X }
X while ((pid = fork()) == -1)
X sleep(1); /* must not clear alarm */
X if (pid == 0) {
X for (i = 3 ; i < 20 ; i++)
X close(i);
X if (flags & BKGRND) {
X signal(SIGINT, SIG_IGN);
X signal(SIGQUIT, SIG_IGN);
X#ifdef SIGTSTP
X signal(SIGTSTP, SIG_IGN);
X signal(SIGTTIN, SIG_IGN);
X signal(SIGTTOU, SIG_IGN);
X#endif
X close(0); close(1);
X open("/dev/null", 2);
X dup(0);
X }
X /* set $A */
X sprintf(a, "A=%s", filename);
X env[0] = a;
X for (envp = env + 1 ; *environ != NULL && envp < env + 98 ; environ++)
X if ((*environ)[0] != 'A' || (*environ)[1] != '=')
X *envp++ = *environ;
X *envp = NULL;
X
X umask(savmask);
X execve(args[0], args, env);
X fprintf(stderr, "%s: not found\n", args[0]);
X exit(20);
X }
X if (!(flags & BKGRND)) {
X savequit = signal(SIGQUIT, SIG_IGN);
X while ((i = wait(&pstatus)) != pid && (i != -1 || errno == EINTR))
X ;
X if (i == -1)
X retval = 1;
X else
X retval = pstatus;
X if (flags & CWAIT) {
X fprintf(stderr, "continue? ");
X while ((errno = 0, i = getchar()) != '\n'
X && (i != EOF || errno == EINTR));
X }
X signal(SIGQUIT, savequit);
X ttyraw();
X clearok(curscr, 1);
X#ifdef SIGTSTP
X signal(SIGTSTP, onstop);
X signal(SIGTTIN, onstop);
X signal(SIGTTOU, onstop);
X#endif
X return retval;
X } else
X return 0;
X}
X
X#ifdef DIGPAGE
X
X
X/*
X * Find end of current subarticle in digest.
X */
X
Xfindend(l)
X{
X register i;
X register char *p;
X
X for (i = l ; i < l + ARTWLEN && i < lastlin ; i++) {
X tfget(linebuf, i);
X for (p = linebuf ; *p == '-' ; p++);
X if (p > linebuf + 24)
X return i + 1;
X }
X return 0;
X}
X
X#endif
X
X
X/*** Routines for handling temporary file ***/
X
X/*
X * Append to temp file.
X * Long lines are folded.
X */
X
Xtfappend(tline)
Xchar *tline;
X{
X while (strlen(tline) > COLS) {
X tfput(tline, lastlin++);
X tline += COLS;
X maxlinno++;
X }
X tfput(tline, lastlin++);
X}
X
X
Xtfput(tline, linno)
Xchar *tline;
X{
X register char *p;
X register FILE *rtfp; /* try to make it a litte faster */
X register int i;
X
X p = tline, i = even(COLS);
X tfseek(linno, 1);
X rtfp = tfp;
X while (--i >= 0) {
X if (*p)
X putc(*p++, rtfp);
X else
X putc('\0', rtfp);
X }
X tflinno++;
X}
X
X
Xtfget(tline, linno)
Xchar *tline;
X{
X tfseek(linno, 0);
X fread(tline, even(COLS), 1, tfp);
X tline[COLS] = '\0';
X tflinno++;
X}
X
X
Xtfseek(linno, wrflag)
X{
X static int lastwrflag = 1;
X
X if (linno != tflinno || wrflag != lastwrflag) {
X fseek(tfp, (long)linno * even(COLS), 0);
X tflinno = linno;
X lastwrflag = wrflag;
X }
X}
X
X/* VARARGS1 */
Xmsg(s, a1, a2, a3, a4)
Xchar *s;
X{
X sprintf(secpr, s, a1, a2, a3, a4);
X}
X
X
X/*
X * Update the display.
X * The display is entirely controlled by this routine,
X * which means that this routine may get pretty snarled.
X */
X
Xstatic int savelinno = -1; /* dlinno on last call to updscr */
Xstatic int savepr; /* prflags on last call */
X
Xupdscr()
X{
X int count;
X int i;
X
X if (checkin())
X return;
X if ((prflags & HELPMSG) == 0
X && (dlinno != savelinno || savepr != prflags)
X && quitflg == 0) {
X if (dlinno != savelinno)
X prflags &=~ NOPRT;
X count = ARTWLEN;
X if (prflags & NOPRT)
X count = 0;
X if ((prflags & HDRONLY) && count > hdrend)
X count = hdrend - dlinno;
X#ifdef DIGPAGE
X if (endsuba > 0 && count > endsuba - dlinno)
X count = endsuba - dlinno;
X#endif
X if ((prflags & NEWART) == 0)
X ushift(ARTWIN, ARTWIN+ARTWLEN-1, dlinno - savelinno);
X if (count > lastlin - dlinno)
X count = lastlin - dlinno;
X for (i = ARTWIN ; i < ARTWIN + ARTWLEN ; i++)
X clrline(i);
X for (i = 0 ; i < count ; i++) {
X tfget(linebuf, dlinno + i);
X mvaddstr(ARTWIN + i, 0, linebuf);
X }
X prflags &=~ NEWART;
X savepr = prflags;
X savelinno = dlinno;
X }
X clrline(SPLINE), clrline(PRLINE);
X#ifdef STATTOP
X mvaddstr(PRLINE, 0, prompt);
X#else
X if (strlen(secpr) <= COLS)
X mvaddstr(PRLINE, 0, prompt);
X#endif
X mvaddstr(PRLINE, 48, timestr);
X mvaddstr(PRLINE, 20, groupdir);
X addch(' '); addnum(bit); addch('/'); addnum(pngsize); addch(' ');
X if (ismail)
X mvaddstr(PRLINE, 62, ismail > 1? "MAIL" : "mail");
X mvaddstr(SPLINE, 0, secpr);
X if (curflag == CURP1)
X move(PRLINE, strlen(prompt));
X else if (curflag == CURHOME)
X move(0, 0);
X refresh();
X}
X
X
Xaddnum(n)
Xregister long n;
X{
X if (n >= 10)
X addnum(n / 10);
X addch((char)(n % 10 + '0'));
X}
X
X
X
X/*** alarm handler ***/
X
X/*
X * Called on alarm signal.
X * Simply sets flag, signal processed later.
X */
X
Xonalarm()
X{
X#ifdef SIGTSTP
X int dojump = reading;
X
X reading = FALSE;
X alflag++;
X if (dojump)
X longjmp(alrmjmp, 1);
X#else !SIGTSTP
X alflag++;
X#endif
X}
X
X
X/*
X * Process alarm signal (or start clock)
X */
X
Xtimer()
X{
X time_t tod;
X int hour;
X int i;
X struct tm *t;
X struct stat statb;
X struct tm *localtime();
X static char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
X static long oldmsize = 1000000L;
X static int rccount = 10;
X
X alflag = 0;
X signal(SIGALRM, onalarm);
X (void) time(&tod);
X t = localtime(&tod);
X i = 60 - t->tm_sec;
X alarm(i > 30? 30 : i); /* reset alarm */
X hour = t->tm_hour % 12;
X if (hour == 0) hour = 12;
X sprintf(timestr, "%.3s %d %d:%02d",
X months + 3 * t->tm_mon, t->tm_mday, hour, t->tm_min);
X#ifdef GGRMAIL
X if (mailf == NULL || stat(mailf, &statb) < 0) {
X statb.st_size = 0;
X }
X if(statb.st_size > oldmsize) {
X ismail = 1;
X beep();
X } else if (statb.st_size < oldmsize) {
X ismail = 0;
X }
X#else
X ismail = 0;
X if (mailf != NULL && stat(mailf, &statb) >= 0 && statb.st_size > 0L) {
X ismail = 1;
X if (oldmsize < statb.st_size) {
X ismail = 2; /* new mail */
X beep();
X }
X } else {
X statb.st_size = 0L;
X }
X#endif
X oldmsize = statb.st_size;
X if (uflag && !xflag && --rccount < 0) {
X writeoutrc();
X if (secpr[0] == '\0')
X strcpy(secpr, ".newsrc updated");
X rccount = 10;
X }
X}
X
X
Xchar *
Xgetmailname()
X{
X static char mailname[32];
X register char *p;
X
X if( (p = getenv("MAIL")) != NULL)
X return p;
X if (username[0] == '\0' || strlen(username) > 15)
X return NULL;
X#ifdef USG
X sprintf(mailname, "/usr/mail/%s", username);
X#else
X sprintf(mailname, "/usr/spool/mail/%s", username);
X#endif
X return mailname;
X}
X
X
X
X/*** Terminal I/O ***/
X
X#define INBUFSIZ 8
X
Xchar inbuf[INBUFSIZ]; /* input buffer */
Xchar outbuf[BUFSIZ]; /* output buffer */
Xint innleft = 0; /* # of chars in input buffer */
Xint outnleft = BUFSIZ; /* room left in output buffer */
Xchar *innext; /* next input character */
Xchar *outnext = outbuf; /* next space in output buffer */
X#ifdef USG
Xint oflags; /* fcntl flags (for nodelay read) */
X#endif
X
X
X/*
X * Input a character
X */
X
Xvgetc()
X{
X register c;
X#if defined(BSD4_2) || defined(BSD4_1C)
X int readfds, exceptfds;
X#endif
X
Xrecurse:
X if (--innleft >= 0) {
X c = *innext++;
X } else {
X if (alflag)
X timer();
X updscr(); /* update the display */
X for (;;) {
X if (innleft > 0 || alflag)
X goto recurse;
X intflag = 0;
X#ifdef USG
X if (oflags & O_NDELAY) {
X oflags &=~ O_NDELAY;
X fcntl(0, F_SETFL, oflags);
X }
X#endif
X#ifdef SIGTSTP
X if (setjmp(alrmjmp))
X continue;
X if (setjmp(intjmp))
X return cintr;
X reading = TRUE;
X#endif SIGTSTP
X#if defined(BSD4_2) || defined(BSD4_1C)
X /* Use a select because it can be interrupted. */
X readfds = 1; exceptfds = 1;
X select(1, &readfds, (int *)0, &exceptfds, (int *)0);
X if (!(readfds & 1))
X break;
X#endif
X innleft = read(0, inbuf, INBUFSIZ);
X#ifdef SIGTSTP
X reading = FALSE;
X#endif SIGTSTP
X if (innleft > 0)
X break;
X if (innleft == 0) {
X quitflg++;
X return cintr;
X }
X if (errno != EINTR)
X abort(); /* "Can't happen" */
X if (intflag) {
X intflag--;
X return cintr;
X }
X }
X innext = inbuf + 1;
X innleft--;
X c = inbuf[0];
X }
X#ifndef USG
X#ifndef CBREAK
X c &= 0177;
X if (c == '\034') /* FS character */
X onquit();
X#endif
X#endif
X if (c == '\f') {
X clearok(curscr, 1);
X goto recurse;
X }
X if (c == '\r')
X c = '\n';
X return c;
X}
X
X
X/*
X * Push a character back onto the input stream.
X */
X
Xpushback(c)
X{
X if (innext <= inbuf)
X abort();
X *--innext = c;
X innleft++;
X}
X
X/*
X * Check for terminal input
X */
X
Xcheckin()
X{
X#ifdef FIONREAD
X int count;
X#endif
X#ifdef STATTOP
X if (innleft > 0)
X#else
X if (innleft > 0 || alflag)
X#endif
X return 1;
X#if defined(USG) || defined(FIONREAD)
X if (ospeed == B9600)
X return 0;
X vflush();
X if (ospeed <= B300)
X ttyowait();
X#ifdef USG
X if ((oflags & O_NDELAY) == 0) {
X oflags |= O_NDELAY;
X fcntl(0, F_SETFL, oflags);
X }
X if ((innleft = read(0, inbuf, INBUFSIZ)) > 0) {
X innext = inbuf;
X return 1;
X }
X#endif
X#ifdef FIONREAD
X count = 0; /* in case FIONREAD fails */
X ioctl(0, FIONREAD, (char *)&count);
X if (count)
X return 1;
X#endif
X#endif
X return 0;
X}
X
X
X
X/*
X * flush terminal input queue.
X */
X
Xclearin()
X{
X#ifdef USG
X ioctl(0, TCFLSH, (char *)0);
X#else
X#ifdef TIOCFLUSH
X ioctl(0, TIOCFLUSH, (char *)0);
X#else
X struct sgttyb tty;
X ioctl(0, TIOCGETP, &tty);
X ioctl(0, TIOCSETP, &tty);
X#endif
X#endif
X innleft = 0;
X}
X
Xvputc(c)
X{
X if (--outnleft < 0) {
X vflush();
X outnleft--;
X }
X *outnext++ = c;
X}
X
X/*
X * Flush the output buffer
X */
X
Xvflush()
X{
X register char *p;
X register int i;
X unsigned oalarm;
X
X oalarm = alarm(0);
X for (p = outbuf ; p < outnext ; p += i) {
X if ((i = write(1, p, outnext - p)) < 0) {
X if (errno != EINTR)
X abort(); /* "Can't happen" */
X i = 0;
X }
X }
X outnleft = BUFSIZ;
X outnext = outbuf;
X alarm(oalarm);
X}
X
X
X
X
X/*** terminal modes ***/
X
X#ifdef USG
Xstatic struct termio oldtty, newtty;
X
X/*
X * Save tty modes
X */
X
Xttysave()
X{
X if (ioctl(1, TCGETA, &oldtty) < 0)
X xerror("Can't get tty modes");
X newtty = oldtty;
X newtty.c_iflag &=~ (INLCR|IGNCR|ICRNL);
X newtty.c_oflag &=~ (OPOST);
X newtty.c_lflag &=~ (ICANON|ECHO|ECHOE|ECHOK|ECHONL);
X newtty.c_lflag |= (NOFLSH);
X newtty.c_cc[VMIN] = 1;
X newtty.c_cc[VTIME] = 0;
X cerase = oldtty.c_cc[VERASE];
X ckill = oldtty.c_cc[VKILL];
X cintr = oldtty.c_cc[VINTR];
X ospeed = oldtty.c_cflag & CBAUD;
X initterm();
X}
X
X
X/*
X * Set tty modes for visual processing
X */
X
Xttyraw()
X{
X while (ioctl(1, TCSETAF, &newtty) < 0 && errno == EINTR)
X ;
X rawterm();
X}
X
Xttyowait()
X{ /* wait for output queue to drain */
X while (ioctl(1, TCSETAW, &newtty) < 0 && errno == EINTR)
X ;
X}
X
X/*
X * Restore tty modes
X */
X
Xttycooked()
X{
X cookedterm();
X while (ioctl(1, TCSETAF, &oldtty) < 0 && errno == EINTR)
X ;
X oflags &=~ O_NDELAY;
X fcntl(0, F_SETFL, oflags) ;
X}
X
X#else
X
Xstatic struct sgttyb oldtty, newtty;
X
X/*
X * Save tty modes
X */
X
Xttysave()
X{
X#ifdef CBREAK
X struct tchars tchars; /* special characters, including interrupt */
X#endif
X#ifdef SIGTSTP
X /* How to get/change terminal modes in a job control environment.
X This code is right from the 4.1 bsd jobs(3) manual page.
X */
X int tpgrp, getpgrp();
X
Xretry:
X#ifdef BSD4_2
X sigblock(BIT(SIGTSTP)|BIT(SIGTTIN)|BIT(SIGTTOU));
X#else !BSD4_2
X signal(SIGTSTP, SIG_HOLD);
X signal(SIGTTIN, SIG_HOLD);
X signal(SIGTTOU, SIG_HOLD);
X#endif !BSD4_2
X if (ioctl(2, TIOCGPGRP, (char *)&tpgrp) < 0)
X goto nottty;
X if (tpgrp != getpgrp(0)) { /* not in foreground */
X signal(SIGTTOU, SIG_DFL);
X#ifdef BSD4_2
X sigsetmask(sigblock(0) & ~BIT(SIGTTOU));
X#endif BSD4_2
X kill(0, SIGTTOU);
X /* job stops here waiting for SIGCONT */
X goto retry;
X }
X signal(SIGTTIN, onstop);
X signal(SIGTTOU, onstop);
X signal(SIGTSTP, onstop);
X#ifdef BSD4_2
X sigsetmask(sigblock(0) & ~(BIT(SIGTSTP)|BIT(SIGTTIN)|BIT(SIGTTOU)));
X#endif BSD4_2
X#endif SIGTSTP
X if (ioctl(1, TIOCGETP, (char *)&oldtty) < 0)
Xnottty: xerror("Can't get tty modes");
X newtty = oldtty;
X newtty.sg_flags &=~ (CRMOD|ECHO|XTABS);
X#ifdef CBREAK
X newtty.sg_flags |= CBREAK;
X ioctl(1, TIOCGETC, (char *)&tchars);
X cintr = tchars.t_intrc;
X#else !CBREAK
X newtty.sg_flags |= RAW;
X cintr = '\0177'; /* forcibly this on V6 systems */
X#endif !CBREAK
X cerase = oldtty.sg_erase;
X ckill = oldtty.sg_kill;
X ospeed = oldtty.sg_ospeed;
X initterm();
X}
X
X
X/*
X * Set tty modes for visual processing
X */
X
Xttyraw()
X{
X while (ioctl(1, TIOCSETN, (char *)&newtty) < 0 && errno == EINTR)
X ;
X rawterm();
X}
X
Xttyowait()
X{ /* wait for output queue to drain */
X#ifdef TIOCDRAIN /* This ioctl is a local mod on linus */
X ioctl(1, TIOCDRAIN, (char *)0);
X#endif
X}
X
X
X/*
X * Restore tty modes
X */
X
Xttycooked()
X{
X cookedterm();
X while (ioctl(1, TIOCSETN, (char *)&oldtty) < 0 && errno == EINTR)
X ;
X}
X
X#endif
X
X
X
X/*** signal handlers ***/
X
Xonint() {
X#ifdef SIGTSTP
X int dojump = reading;
X
X reading = FALSE;
X#endif SIGTSTP
X if (!news) {
X ttycooked();
X xxit(1);
X }
X signal(SIGINT, onint);
X clearin(); /* flush input queue */
X#ifdef SIGTSTP
X if (dojump)
X longjmp(intjmp, 1);
X#endif SIGTSTP
X intflag++;
X}
X
Xonquit()
X{
X botscreen();
X vflush();
X ttycooked();
X#ifdef SORTACTIVE
X unlink(ACTIVE);
X#endif SORTACTIVE
X#ifdef COREDUMP
X abort();
X#else
X exit(0);
X#endif
X}
X
X#ifdef SIGTSTP
X
Xonstop(signo)
Xint signo;
X{
X /* restore old terminal state */
X botscreen();
X vflush();
X ttycooked();
X signal(signo, SIG_DFL);
X#ifdef BSD4_2
X sigblock(BIT(SIGALRM)|BIT(SIGINT));
X sigsetmask(sigblock(0) & ~BIT(signo));
X#endif BSD4_2
X kill(0, signo); /* stop here until continued */
X
X fprintf(stderr,"Vnews restarted.");
X signal(signo, onstop);
X /* restore our special terminal state */
X ttyraw();
X clearok(curscr, 1);
X updscr();
X#ifdef BSD4_2
X sigsetmask(sigblock(0) & ~(BIT(SIGALRM)|BIT(SIGINT)));
X#endif BSD4_2
X}
X
X#endif
X
X
X/*** stolen from rfuncs2.c and modified ***/
X
Xvsave(to, flags)
Xregister char *to;
X{
X register FILE *ufp;
X int isprogram = 0;
X int isnew = 1;
X long saveoff;
X char temp[20];
X char *fname;
X char prog[BUFLEN + 24];
X
X saveoff = ftell(fp);
X fseek(fp, artbody, 0);
X fname = to;
X if (*to == PIPECHAR) {
X if (strlen(to) > BUFLEN) {
X msg("Command name too long");
X goto out;
X }
X flags |= OVWRITE;
X strcpy(temp, "/tmp/vnXXXXXX");
X mktemp(temp);
X fname = temp;
X _amove(ROWS - 1, 0);
X vflush();
X }
X if ((flags & OVWRITE) == 0) {
X ufp = fopen(fname, "r");
X if (ufp != NULL) {
X fclose(ufp);
X isnew = 0;
X }
X }
X umask(savmask);
X
X if (*to == PIPECHAR)
X isprogram++;
X if ((ufp = fopen(fname, (flags & OVWRITE) == 0? "a" : "w")) == NULL) {
X msg("Cannot open %s", fname);
X goto out;
X }
X /*
X * V7MAIL code is here to conform to V7 mail format.
X * If you need a different format to be able to
X * use your local mail command (such as four ^A's
X * on the end of articles) substitute it here.
X */
X if (flags & SVHEAD) {
X#ifdef V7MAIL
X h->subtime = cgtdate(h->subdate);
X fprintf(ufp, "From %s %s",
X#ifdef INTERNET
X h->from,
X#else
X h->path,
X#endif
X ctime(&h->subtime));
X#endif
X hprint(h, ufp, 2);
X#ifdef V7MAIL
X tprint(fp, ufp, TRUE);
X putc('\n', ufp); /* force blank line at end (ugh) */
X#else
X tprint(fp, ufp, FALSE);
X#endif
X } else {
X tprint(fp, ufp, FALSE);
X }
X
X fclose(ufp);
X if (isprogram) {
X sprintf(prog, "(%s)<%s", to + 1, fname);
X shcmd(prog, CWAIT);
X prflags |= NOPRT;
X } else {
X if ((flags & OVWRITE) == 0)
X msg("file: %s %s", to, isnew ? "created" : "appended");
X else
X msg("file: %s written", to);
X }
X
Xout:
X if (isprogram) {
X unlink(fname);
X }
X umask(N_UMASK);
X fseek(fp, saveoff, 0);
X}
*-*-END-of-src/visual.c-*-*
echo x - src/postnews.c
sed 's/^X//' >src/postnews.c <<'*-*-END-of-src/postnews.c-*-*'
X/*
X * Postnews: post a news message to Usenet. This C version replaces a shell
X * script, and does more intelligent prompting and filtering than possible
X * in a shell script.
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)postnews.c 1.13 9/5/84";
X#endif !lint
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <pwd.h>
X#ifdef USG
Xstruct passwd *getpwent(), *getpwuid(), *getpwnam();
X#endif USG
X#include "defs.h"
X#define ARCHIVES_DEF "NEWSARCHIVE"
X
Xchar tempfname[50]; /* file name used for making article */
Xchar original[BUFLEN]; /* file name of original, used in followup */
Xchar homedir[BUFLEN]; /* HOME environment setting */
Xchar ccname[BUFLEN]; /* file name for article copy */
X
X/* article header information */
Xchar subject[BUFLEN];
Xchar distribution[BUFLEN];
Xchar references[BUFLEN];
Xchar newsgroups[BUFLEN];
Xchar moderator[BUFLEN];
X
Xchar *Progname = "postnews"; /* for xerror */
X
Xtime_t fmodtime;
Xint ismod = 0;
Xextern char *LIB, *SPOOL, *ACTIVE, *MAILPARSER;
Xchar buf[BUFLEN];
X
Xstruct distr {
X char abbr[24];
X char descr[128];
X} distr[16];
X
XFILE *xfopen();
X
Xmain(argc, argv)
Xchar *argv[];
X{
X init();
X
X if (argc == 2) {
X if (strncmp(SPOOL, argv[1], strlen(SPOOL)))
X xerror("Can only followup to articles in %s", SPOOL);
X followup(argv[1]);
X strcpy(original, argv[1]);
X } else
X if (askyes("Is this message in response to some other message? ","no")) {
X char ng[BUFLEN], num[BUFLEN];
X long i, j;
X register char *c;
X int fd;
X char canpost;
X
X getpr("In what newsgroup was the article posted? ",ng);
X if (!valid_ng(ng, &i, &j, &canpost))
X if (canpost != 'n' )
X byebye("There is no such newsgroup.");
X else
X byebye("You are not allowed to post to that group.");
X
X printf("Valid article numbers are from %ld to %ld\n", j, i);
X
X for(;;) {
X getpr("\nWhat was the article number? ", num);
X if (num == 0)
X continue;
X sprintf(original, "%s/%s", SPOOL, ng);
X for (c=original+strlen(SPOOL)+1; *c ;++c)
X if (*c == '.')
X *c = '/';
X strcat(original, "/");
X strcat(original, num);
X
X if ((fd=open(original,0)) >= 0) {
X close(fd);
X printf("\narticle %s\n", original);
X if (article_line(original, "From: ", buf))
X printf("%s\n", buf);
X if (article_line(original, "Subject: ", buf))
X printf("%s\n", buf);
X if (askyes("Is this the one you want? ", ""))
X break;
X } else
X printf("I can't find that article.\n");
X }
X
X followup(original);
X } else {
X do {
X getpr("Subject: ", subject);
X } while (*subject == '\0');
X
X while (!get_newsgroup())
X ;
X get_distribution();
X }
X
X if (pre_checks())
X exit(1);
X edit_article();
X post_checks();
X
X save_article();
X post_article();
X}
X
X/*
X * Find out the topic of interest.
X */
Xget_newsgroup()
X{
X int n;
X long i;
X char canpost;
X
X printf("Newsgroups (enter one at a time, end with a blank line):\n");
X printf("For a list of newsgroups, type ?\n");
X n = 0;
X newsgroups[0] = '\0';
X
X for(;;) {
X getpr("> ", buf);
X if (buf[0] == '\0')
X if (n == 0)
X return FALSE;
X else
X return TRUE;
X if (buf[0] == '?'){
X /* too lazy to do it myself.... */
X printf("These are the currently active groups:\n");
X sprintf(buf,"exec cat %s/newsgroups", LIB);
X system(buf);
X continue;
X }
X if (valid_ng(buf, &i, &i, &canpost)) {
X if (n++ != 0)
X strcat(newsgroups, ",");
X strcat(newsgroups, buf);
X } else {
X if (canpost == 'n')
X printf("You are not allowed to post to %s\n",
X buf);
X else
X printf("%s is not a valid newsgroup.\n", buf);
X }
X }
X}
X
X/*
X * Find out how widely the author wants the message distributed.
X */
Xget_distribution()
X{
X register int i;
X register char *r;
X char def[BUFLEN];
X char *index();
X
X strcpy(def, newsgroups);
X r = index(def, '.');
X if (r) {
X *r = '\0';
X if (strcmp(def, "net") == 0)
X strcpy(def, "world");
X } else
X strcpy(def, "local");
X
X if (strcmp(def,"to") == 0) {
X distribution[0] = '\0';
X return; /* He's probably testing something */
X }
X if (ngmatch("net.test", newsgroups))
X strcpy(def, "local");
X for(;;) {
X sprintf(buf, "Distribution (default='%s', '?' for help) : ", def);
X getpr(buf, distribution);
X if (distribution[0] == '\0')
X strcpy(distribution, def);
X
X /* Did the user ask for help? */
X if (distribution[0] == '?') {
X printf("How widely should your article be distributed?\n");
X for (i=0; distr[i].abbr[0]; i++)
X printf("%s\t%s\n", distr[i].abbr, distr[i].descr);
X continue;
X }
X
X /* Check that it's a proper distribution */
X for (i=0; distr[i].abbr[0]; i++) {
X if (strncmp(distr[i].abbr, distribution, sizeof(distr[0].abbr)) == 0) {
X /* Found a match. Do any special rewriting. */
X if (strcmp(distribution, "world") == 0)
X strcpy(distribution, "net");
X return;
X }
X }
X
X printf("Type ? for help.\n");
X }
X}
X
X/*
X * Do sanity checks before the author types in the message.
X */
Xpre_checks()
X{
X check_mod();
X if (recording(newsgroups))
X return 1;
X return 0;
X}
X
X/*
X * Check to see if the newsgroup is moderated.
X */
Xcheck_mod()
X{
X register FILE *fd;
X char ng[64], mod[BUFLEN];
X
X sprintf(buf, "%s/%s", LIB, "moderators");
X fd = xfopen(buf, "r");
X
X while (!feof(fd)) {
X if (fgets(buf, sizeof buf, fd) == NULL) {
X fclose(fd);
X return;
X }
X twosplit(buf, ng, mod);
X if (ngmatch(newsgroups, ng)) {
X strcpy(moderator, mod);
X ismod = 1;
X return;
X }
X }
X}
X
X/*
X * Set up the temp file with headers.
X */
Xedit_article()
X{
X FILE *tf, *of;
X char *editor;
X char *endflag = "";
X char *p;
X char *getenv();
X struct stat stbuf;
X
X editor = getenv("EDITOR");
X strcpy(tempfname, "/tmp/postXXXXXX");
X mktemp(tempfname);
X
X /* insert a header */
X tf = xfopen(tempfname, "w");
X fprintf(tf, "Subject: %s\n", subject);
X fprintf(tf, "Newsgroups: %s\n", newsgroups);
X if (distribution[0] != '\0')
X fprintf(tf, "Distribution: %s\n", distribution);
X if (ismod)
X fprintf(tf, "To: %s\n", moderator);
X
X if (references[0] != '\0') {
X fprintf(tf, "References: %s\n\n", references);
X
X of = xfopen(original, "r");
X while (fgets(buf, BUFSIZ, of) != NULL)
X if (buf[0] == '\n') /* skip headers */
X break;
X while (fgets(buf, BUFSIZ, of) != NULL)
X fprintf(tf, "> %s", buf);
X fclose(of);
X }
X
X fprintf(tf, "\n*** REPLACE THIS LINE WITH YOUR MESSAGE ***\n");
X fflush(tf);
X fstat(fileno(tf), &stbuf);
X fmodtime = stbuf.st_mtime;
X fclose(tf);
X
X /* edit the file */
X if (editor == NULL)
X editor = DFTEDITOR;
X
X p = editor + strlen(editor) - 2;
X if (strcmp(p, "vi") == 0 && references[0] == '\0')
X endflag = "+";
X
X sprintf(buf, "exec %s %s %s", editor, endflag, tempfname);
X
X system(buf);
X}
X
X/*
X * Do sanity checks after the author has typed in the message.
X */
Xpost_checks()
X{
X char group[BUFLEN];
X char *c;
X struct stat stbuf;
X
X if (stat(tempfname, &stbuf) < 0) {
X printf("File deleted - no message posted.\n");
X unlink(tempfname);
X exit(1);
X }
X
X if (stbuf.st_mtime == fmodtime || stbuf.st_size < 5) {
X printf("File not modified - no message posted.\n");
X unlink(tempfname);
X exit(1);
X }
X
X /* Sanity checks for certain newsgroups */
X if (ngmatch(newsgroups, "all.wanted") && ngmatch(distribution,"net,na,usa,att,btl")) {
X printf("Is your message something that might go in your local\n");
X printf("newspaper, for example a used car ad, or an apartment\n");
X printf("for rent? ");
X if (askyes("","")) {
X printf("It's pointless to distribute your article widely, since\n");
X printf("people more than a hundred miles away won't be interested.\n");
X printf("Please use a more restricted distribution.\n");
X get_distribution();
X modify_article(tempfname,"Distribution: ",distribution,"replace");
X }
X }
X
X if (ngmatch(newsgroups, "all.jokes")) {
X if (askyes("Could this be offensive to anyone? ","")) {
X getpr("Whom might it offend? ", group);
X sprintf(buf," - offensive to %s (ROT13)",group);
X modify_article(tempfname, "Subject: ", buf, "append");
X encode(tempfname);
X }
X }
X
X if (ngmatch(newsgroups, "net.general")) {
X c = newsgroups;
X while (*c != ',' && *c)
X ++c;
X if (*c == ',') {
X printf("Everybody reads net.general, so it doesn't make sense to\n");
X printf("post to newsgroups in addition to net.general. If your\n");
X printf("article belongs in one of these other newsgroups, then you\n");
X printf("should not post to net.general. If it is important enough\n");
X printf("for net.general, then you shouldn't post it in other places\n");
X printf("as well. Please reenter the newsgroups.\n");
X get_newsgroup();
X modify_article(tempfname,"Newsgroups: ",newsgroups,"replace");
X }
X else {
X printf("net.general is for important announcements.\n");
X printf("It is not for items for which you couldn't think\n");
X printf("of a better place - those belong in net.misc.\n");
X if (!askyes("Are you sure your message belongs in net.general? ","")) {
X get_newsgroup();
X modify_article(tempfname, "Newsgroups: ", newsgroups, "replace");
X }
X }
X }
X}
X
X/*
X * Save a copy of the article in the users NEWSARCHIVE directory.
X */
Xsave_article()
X{
X FILE *in, *out;
X int c;
X time_t timenow, time();
X char *today, *ctime();
X
X
X in = xfopen(tempfname, "r");
X out = xfopen(ccname, "a");
X timenow = time((time_t)0);
X today = ctime(&timenow);
X fprintf(out,"From postnews %s",today);
X while ((c=getc(in)) != EOF)
X putc(c, out);
X putc('\n', out);
X fclose(in);
X fclose(out);
X}
X
X/*
X * Post the article to the net.
X */
Xpost_article()
X{
X int status;
X
X printf("%s article...\n", ismod ? "Mailing" : "Posting" );
X if (ismod)
X sprintf(buf, "exec %s -t < %s", MAILPARSER, tempfname);
X else
X sprintf(buf, "exec %s/%s -h < %s", LIB, "inews", tempfname);
X status = system(buf);
X
X if (status)
X printf("Article not %s - exit status %d\n", ismod ? "mailed" : "posted", status);
X else
X printf("Article %s successfully.\n", ismod ? "mailed" : "posted" );
X
X if (ccname[0])
X printf("A copy has been saved in %s\n", ccname);
X
X unlink(tempfname);
X}
X
X/*
X * Initialization.
X */
Xinit()
X{
X FILE *fd;
X register char *p;
X int i;
X char *getenv();
X
X references[0] = '\0';
X distribution[0] = '\0';
X
X p = getenv("HOME");
X if (p == NULL) {
X p = getenv("LOGDIR");
X if (p == NULL) {
X struct passwd *pw;
X pw = getpwuid(getuid());
X if (pw == NULL) {
X fprintf(stderr,"You're not in /etc/passwd\n");
X exit(1);
X }
X p = pw->pw_dir;
X }
X }
X strcpy(homedir, p);
X
X
X p = getenv(ARCHIVES_DEF);
X if (p == NULL)
X sprintf(ccname, "%s/author_copy", homedir);
X else
X strcpy(ccname, p);
X
X pathinit();
X sprintf(buf, "%s/%s", LIB, "distributions");
X fd = xfopen(buf, "r");
X for (i=0; !feof(fd); i++) {
X if (fgets(buf, sizeof buf, fd) == NULL)
X break;
X twosplit(buf, distr[i].abbr,distr[i].descr);
X }
X fclose(fd);
X}
X
X/*
X * Split a line of the form
X * text whitespace text
X * into two strings. Also trim off any trailing newline.
X * This is destructive on src.
X */
Xtwosplit(src, dest1, dest2)
Xchar *src, *dest1, *dest2;
X{
X register char *p;
X
X nstrip(src);
X for (p=src; isalnum(*p) || ispunct(*p); p++)
X ;
X *p++ = 0;
X for ( ; isspace(*p); p++)
X ;
X strcpy(dest1, src);
X strcpy(dest2, p);
X}
X
X/*
X * Get a yes or no answer to a question. A default may be used.
X */
Xaskyes(msg, def)
Xchar *msg, *def;
X{
X
X printf("%s", msg);
X buf[0] = 0;
X gets(buf);
X switch(buf[0]) {
X case 'y':
X case 'Y':
X return TRUE;
X case 'n':
X case 'N':
X return FALSE;
X case '\0':
X switch(*def) {
X case 'y':
X case 'Y':
X return TRUE;
X case 'n':
X case 'N':
X return FALSE;
X }
X default:
X printf("Please answer yes or no.\n");
X return askyes(msg, def);
X }
X}
X
X/*
X * Get a character string into buf, using prompt msg.
X */
Xgetpr(msg, bfr)
Xchar *msg, *bfr;
X{
X static int numeof = 0;
X printf("%s", msg);
X gets(bfr);
X nstrip(bfr);
X if (feof(stdin)) {
X if (numeof++ > 3) {
X fprintf(stderr,"Too many EOFs\n");
X exit(1);
X }
X clearerr(stdin);
X }
X}
X
Xbyebye(mesg)
Xchar *mesg;
X{
X printf("%s\n", mesg);
X exit(1);
X}
X
X/*
X * make a modification to the header of an article
X *
X * fname -- name of article
X * field -- header field to modify
X * line -- modification line
X * how -- 'a' or 'A' to append line to existing header line
X * anything else to replace existing line
X *
X * example:
X * modify_article("/tmp/article" , "Subject: " , "new subject" , "replace");
X *
X *
X */
Xmodify_article(fname, field, line, how)
Xchar *fname, *field, *line, *how;
X{
X FILE *fpart, *fptmp;
X char *temp2fname = "/tmp/postXXXXXX";
X int i;
X
X mktemp(temp2fname);
X
X fptmp = xfopen(temp2fname, "w");
X fpart = xfopen(fname, "r");
X
X i = strlen(field);
X while (fgets(buf, BUFLEN, fpart) != NULL) {
X if (strncmp(field, buf, i) == 0) {
X nstrip(buf);
X if (*how=='a' || *how=='A')
X /* append to current field */
X sprintf(buf, "%s%s\n", buf, line);
X else
X /* replace current field */
X sprintf(buf, "%s%s\n", field, line);
X }
X fputs(buf, fptmp);
X }
X
X fclose(fpart);
X fclose(fptmp);
X
X fptmp = xfopen(temp2fname, "r");
X fpart = xfopen(fname, "w");
X
X i = strlen(field);
X while (fgets(buf,BUFLEN,fptmp) != NULL)
X fputs(buf, fpart);
X
X fclose(fpart);
X fclose(fptmp);
X unlink(temp2fname);
X}
X
X
X/* verify that newsgroup exists, and get number of entries */
Xvalid_ng(ng, maxart, minart, canpost)
Xchar *ng;
Xlong *maxart, *minart;
Xchar *canpost;
X{
X char ng_check[BUFLEN], ng_read[BUFLEN];
X FILE *fp;
X
X fp = xfopen(ACTIVE, "r");
X while (fgets(ng_read, BUFLEN, fp) != NULL) {
X sscanf(ng_read, "%s %ld %ld %c", ng_check, maxart, minart, canpost);
X if (strcmp(ng_check, ng) == 0) {
X fclose(fp);
X if (*canpost == 'y')
X return TRUE;
X else
X return FALSE;
X }
X }
X *canpost = 'i';
X *maxart = 0;
X *minart = 0;
X fclose(fp);
X return FALSE;
X}
X
X/* get the line specified by field from an article */
Xarticle_line(article, field, line)
Xchar *article, *field, *line;
X{
X FILE *fp;
X char *c;
X int i = strlen(field);
X
X fp = xfopen(article,"r");
X while ((c=fgets(line,BUFLEN,fp)) != NULL && strncmp(field,line,i) != 0)
X ;
X fclose(fp);
X if (c != NULL) {
X nstrip(line);
X return TRUE;
X } else {
X line[0] = '\0';
X return FALSE;
X }
X}
X
X
X/* get the header information for a followup article */
Xfollowup(baseart)
Xregister char *baseart;
X{
X /* subject */
X if (article_line(baseart, "Subject: ", buf))
X sprintf(subject, "Re: %s", buf+9);
X else
X strcpy(subject, "Re: orphan response");
X
X /* newsgroup */
X if (article_line(baseart, "Newsgroups: ", buf))
X strcpy(newsgroups, buf+12);
X if (ngmatch(newsgroups, "net.general"))
X strcpy(newsgroups,"net.followup");
X
X /* distribution */
X if (article_line(baseart, "Distribution: ", buf))
X strcpy(distribution, buf+14);
X
X /* references */
X if (article_line(baseart, "References: ", buf)) {
X strcpy(references, buf+12);
X strcat(references, " ");
X }
X if (article_line(baseart, "Message-ID: ", buf))
X strcat(references, buf+12);
X}
X
Xencode(article)
Xchar *article;
X{
X FILE *fpart, *fphead, *fpcoded;
X char *headerfile = "/tmp/pheadXXXXXX";
X char *codedfile = "/tmp/pcodeXXXXXX";
X
X mktemp(headerfile);
X mktemp(codedfile);
X
X fpart = xfopen(article, "r");
X
X /* place article header in "headerfile" file */
X fphead = xfopen(headerfile, "w");
X while (fgets(buf, BUFLEN, fpart) != NULL) {
X fputs(buf, fphead);
X if (buf[0] == '\n')
X break;
X }
X fclose(fphead);
X
X /* place article body in "codedfile" file */
X fpcoded = xfopen(codedfile, "w");
X while (fgets(buf, BUFLEN, fpart) != NULL)
X fputs(buf, fpcoded);
X fclose(fpcoded);
X fclose(fpart);
X
X /* encode body and put back together with header */
X unlink(article);
X link(headerfile, article);
X unlink(headerfile);
X
X sprintf(buf,"exec %s/%s 13 < %s >> %s\n", LIB, "caesar", codedfile, article);
X printf("Encoding article -- please stand by\n");
X if (system(buf)) {
X printf("encoding failed");
X exit(2);
X }
X unlink(codedfile);
X}
X
X
X/*
X * Print a recorded message warning the poor luser what he is doing
X * and demand that he understands it before proceeding. Only do
X * this for newsgroups listed in LIBDIR/recording.
X */
Xrecording(ngrps)
Xchar *ngrps;
X{
X char recbuf[BUFLEN];
X FILE *fd;
X char nglist[BUFLEN], fname[BUFLEN];
X int c, n, yes;
X
X sprintf(recbuf, "%s/%s", LIB, "recording");
X fd = fopen(recbuf, "r");
X if (fd == NULL)
X return 0;
X while ((fgets(recbuf, sizeof recbuf, fd)) != NULL) {
X sscanf(recbuf, "%s %s", nglist, fname);
X if (ngmatch(ngrps, nglist)) {
X fclose(fd);
X if (fname[0] == '/')
X strcpy(recbuf, fname);
X else
X sprintf(recbuf, "%s/%s", LIB, fname);
X fd = fopen(recbuf, "r");
X if (fd == NULL)
X return 0;
X while ((c = getc(fd)) != EOF)
X putc(c, stderr);
X fprintf(stderr, "Do you understand this? Hit <return> to proceed, <BREAK> to abort: ");
X n = read(2, recbuf, 100);
X c = recbuf[0];
X yes = (c=='y' || c=='Y' || c=='\n' || c=='\n' || c==0);
X if (n <= 0 || !yes)
X return -1;
X }
X }
X return 0;
X}
X
Xxxit(i)
X{
X exit(i);
X}
*-*-END-of-src/postnews.c-*-*
exit
More information about the Comp.sources.unix
mailing list