Fixes for bugs in 2.10 readnews
Steven M. Kramer
smk at linus.UUCP
Tue Jun 7 05:38:56 AEST 1983
I have modified this fix to readr.c to work with the -ldir stuff.
You have to compile readnews with the -ldir flag in the Makefile and
have to enable the -DMITRE stuff. Also in readr.c are all the current
fixes to now, so I'll post the whole thing. If you don't enable -DMITRE,
you get the original source. Remember, the -ldir lib that has
been posted a few times must be used or opendir and readdir will be
undefined.
readr.c:
--------------------------
/*
* readr - /bin/mail and msgs interface and associated functions.
*/
static char *SccsId = "@(#)readr.c 2.26 5/3/83";
#include "rparams.h"
#ifdef MITRE
#include <ndir.h>
#endif
static char lbuf[BUFLEN*2];
#define saveart oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hbufcp(&hbuf1, &h);ongsize = pngsize
#define NLINES(h, fp) (h.numlines[0] ? h.intnumlines : (h.intnumlines=linecnt(fp),sprintf(h.numlines, "%d", h.intnumlines), h.intnumlines))
#ifdef MITRE
/* Some systems don't have a /usr/tmp because it is a nuisance to
have two publically writable directories to clear out
periodically and /tmp is a file system of adequate size.
*/
char *tft = "/tmp/folXXXXXX";
#else
char *tft = "/usr/tmp/folXXXXXX";
#endif
static int hascaught = 0;
static catchintr()
{
hascaught = 1;
printf("\n");
fflush(stdout);
}
/*
* These were made static for u370 with its buggy cc.
* I judged it better to have one copy with no ifdefs than
* to conditionally compile them as automatic variables
* in readr (which they originally were). Performance
* considerations might warrent moving some of the simple
* things into register variables, but I don't know what
* breaks the u370 cc.
*/
static char goodone[BUFLEN]; /* last decent article */
static char ogroupdir[BUFLEN]; /* last groupdir */
static char address[PATHLEN]; /* for reply copy */
static char edcmdbuf[128];
static char folbuf[160];
static int rfq = 0; /* for last article */
static long ongsize; /* Previous ngsize */
static long pngsize; /* Printing ngsize */
static char *bptr; /* temp pointer. */
static struct srec srec; /* srec for sys file entries */
static char *tfilename; /* temporary file name */
static char ofilename1[BUFLEN]; /* previous file name */
static struct hbuf hbuf1, hbuf2, *hptr; /* for minusing */
static char *ptr1, *ptr2, *ptr3; /* for reply manipulation */
static int news = 0;
static int abs = FALSE; /* TRUE if we asked absolutely */
static char *ed, tf[100];
static struct hbuf h; /* ditto. */
static int i;
static int oobit; /* last bit, really */
static char *oldsig;
static int dgest = 0;
static FILE *ofp; /* Current output file to terminal*/
static FILE *fp; /* current article to be printed*/
static int holdup; /* 1 iff should stop before hdr */
static int ignorenews; /* 1 iff readnews -p > /dev/null*/
static long timelastsaved; /* time newsrc last written out */
int catchcont();
readr()
{
#ifdef DEBUG
fprintf(stderr, "readr()\n");
#endif
if (aflag) {
if (*datebuf) {
if ((atime = cgtdate(datebuf)) == -1)
xerror("Cannot parse date string");
} else
atime = 0L;
}
if (pflag && ignoring())
ignorenews = TRUE;
if (uflag)
time(&timelastsaved);
ofp = stdout;
if (cflag && coptbuf[0] != '\0') {
umask(022);
mktemp(outfile); /* get "unique" file name */
ofp = xfopen(outfile, "w");
umask(N_UMASK);
cflag = FALSE;
pflag = TRUE;
}
/* loop reading articles. */
fp = NULL;
obit = -1;
nextng();
for ( ;; ) {
if (getnextart(FALSE))
break;
#ifdef DEBUG
printf("after getnextart, fp %x, pos %d, bit %d, group '%s', filename '%s'\n",
fp, ftell(fp), bit, groupdir, filename);
#endif
strcpy(goodone, filename);
if (pflag || lflag || eflag) {
/* This code should be gotten rid of */
if (sigtrap) {
qfflush(ofp);
fprintf(ofp, "\n");
cdump(ofp);
_exit(0); /* kludge! drop when qfflush works */
return;
}
clear(bit);
nextbit();
if (fp) {
fclose(fp);
fp = NULL;
}
continue;
}
for ( ;; ) {
char *pp;
#ifdef SIGCONT
int (*ocont)();
#endif
sigtrap = FALSE;
if (!cflag) {
if (rfq)
fprintf(ofp, "Last article. [qfr] ");
else
fprintf(ofp, "(%d lines) More? [ynq] ", NLINES(h, fp));
} else
fprintf(ofp, "? ");
fflush(ofp);
bptr = lbuf;
#ifdef SIGCONT
ocont = signal(SIGCONT, catchcont);
#endif
pp = fgets(bptr, BUFLEN, stdin);
#ifdef SIGCONT
signal(SIGCONT, ocont);
#endif
if (pp != NULL)
break;
if (!sigtrap)
return;
#ifdef SIGCONT
if (sigtrap != SIGCONT)
#endif
fprintf(ofp, "\n");
}
nstrip(bptr);
while (*bptr == ' ' || *bptr == '\t')
bptr++;
i = command();
if (i)
break;
}
if (!news)
fprintf(stderr, "No news.\n");
cout(ofp);
}
#define EOL() if (*bptr != '\0') { fprintf(ofp, "? for commands.\n"); return FALSE; }
/*
* Process one command, which has already been typed in.
*/
command()
{
char *findhist();
switch (i = *bptr++) {
/* No. Go on to next article. */
case 'n':
EOL();
itsbeenseen(h.ident);
readmode = NEXT;
if (!cflag) {
fclose(fp);
fp = NULL;
}
fprintf(ofp, "\n");
clear(bit);
saveart;
nextbit();
break;
/* Undigestify the article. */
case 'd':
dgest = 1;
/* fall through */
/* yes: print this article, go on. */
case 'y':
EOL();
/* fall through. */
/* The user hit return. Default is 'y' unless rfq, then it's 'q'. */
case '\0':
if (!bptr[-1] && rfq)
return;
readmode = NEXT;
showtail(fp);
clear(bit);
saveart;
nextbit();
break;
/*
* Unsubscribe to the newsgroup and go on to next group
*/
case 'u':
fprintf(ofp, "To unsubscribe, use 'U'\n");
break;
case 'U':
fprintf(ofp, "Unsubscribing to newsgroup: %s\n", groupdir);
obit = -1;
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
if (cflag)
clear(bit);
else
putc('\n', ofp);
rfq = 0;
zapng = TRUE;
saveart;
if (nextng()) {
if (actdirect == BACKWARD)
fprintf(ofp, "Can't back up.\n");
else
return TRUE;
}
break;
/* Print the current version of news */
case 'v':
fprintf(ofp, "News version: %s\n", news_version);
break;
/* reprint the article */
case 'p':
EOL();
if (!cflag)
goto minus;
readmode = NEXT;
if (!cflag) {
fclose(fp);
fp = NULL;
bit = last;
putc('\n', ofp);
}
obit = -1;
break;
/* decrypt joke */
case 'D':
caesar_command();
readmode = NEXT;
clear(bit);
saveart;
nextbit();
break;
/* write out the article someplace */
case 's':
case 'w':
{
char *grn = groupdir;
tfilename = filename;
if (*bptr == '-') {
bptr++;
grn = ogroupdir;
if (*ofilename1)
tfilename = ofilename1;
}
if (*bptr != '\0' && *bptr != ' ') {
fprintf(ofp, "Bad file name.\n");
break;
}
while (*bptr == ' ')
bptr++;
if (*bptr != '|' && *bptr != '/') {
char hetyped[BUFLEN];
char *boxptr;
strcpy(hetyped, bptr);
if (boxptr = getenv("NEWSBOX"))
if (index(boxptr, '%'))
sprintf(bptr, boxptr, grn);
else
strcpy(bptr, boxptr);
else if (hetyped[0] == '~' && hetyped[1] == '/') {
strcpy(hetyped, bptr+2);
strcpy(bptr, userhome);
} else
strcpy(bptr, ".");
strcat(bptr, "/");
if (hetyped[0] != '\0')
strcat(bptr, hetyped);
else
strcat(bptr, "Articles");
}
fwait(fsubr(save, tfilename, bptr));
}
break;
/* back up */
case '-':
minus:
rfq = 0;
abs = TRUE;
if (!*ofilename1) {
fprintf(ofp, "Can't back up.\n");
break;
}
if (cflag)
clear(bit);
else {
fclose(fp);
fp = NULL;
putc('\n', ofp);
}
hbufcp(&hbuf2, &h);
hbufcp(&h, &hbuf1);
hbufcp(&hbuf1, &hbuf2);
strcpy(bfr, filename);
strcpy(filename, ofilename1);
strcpy(ofilename1, bfr);
obit = bit;
if (strcmp(groupdir, ogroupdir)) {
strcpy(bfr, groupdir);
selectng(ogroupdir);
strcpy(groupdir, ogroupdir);
strcpy(ogroupdir, bfr);
ngrp = 1;
back();
}
bit = oobit;
oobit = obit;
obit = -1;
getnextart(TRUE);
return FALSE;
/* skip forwards */
case '+':
caseplus:
if (*bptr == '\0')
strcat(bptr, "1");
rfq = 0;
if (cflag)
clear(bit);
saveart;
last = bit;
for (i = 0; i < atoi(bptr); i++) {
nextbit();
if ((bit > pngsize) || (rflag && bit < 1))
break;
}
if (!cflag) {
putc('\n', ofp);
fclose(fp);
fp = NULL;
}
obit = -1;
break;
/* exit - time updated to that of most recently read article */
case 'q':
EOL();
return TRUE;
/* exit - no time update. */
case 'x':
EOL();
xxit(0);
/* cancel the article. */
case 'c':
cancel_command();
break;
/* escape to shell */
case '!':
fwait(fsubr(ushell, bptr, (char *)NULL));
fprintf(ofp, "\n");
hdr();
break;
/* mail reply */
case 'r':
reply_command();
break;
/* send to some system */
case 'X':
xmit_command();
break;
/* next newsgroup */
case 'P':
*bptr = '-';
case 'N':
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
if (next_ng_command())
return TRUE;
break;
/* specific no. */
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
sscanf(--bptr, "%d", &i);
if (i == 0) {
fprintf(ofp, "Bad article no.\n");
break;
}
if (i > pngsize) {
fprintf(ofp, "Not that many articles.\n");
break;
}
readmode = SPEC;
abs = TRUE;
bit = i;
obit = -1;
if (!cflag) {
putc('\n', ofp);
fclose(fp);
fp = NULL;
}
rfq = 0;
break;
/* specific message ID. */
case '<':
ptr1 = findhist(--bptr);
if (ptr1 == NULL) {
fprintf(ofp, "No such article: %s.\n", bptr);
break;
}
ptr2 = index(ptr1, '\t');
ptr3 = index(++ptr2, '\t');
ptr2 = index(++ptr3, ' ');
if (ptr2)
*ptr2 = '\0';
ptr2 = index(ptr3, '/');
*ptr2++ = '\0';
abs = TRUE;
if (cflag)
clear(bit);
else {
fclose(fp);
fp = NULL;
putc('\n', ofp);
}
hbufcp(&hbuf1, &h);
saveart;
strcpy(ogroupdir, ptr3);
if (strcmp(groupdir, ogroupdir)) {
strcpy(bfr, groupdir);
selectng(ogroupdir);
strcpy(groupdir, ogroupdir);
strcpy(ogroupdir, bfr);
back();
}
sscanf(ptr2, "%d", &bit);
oobit = obit;
obit = -1;
getnextart(TRUE);
rfq = 0;
break;
/* follow-up article */
case 'f':
followup_command();
break;
/* erase - pretend we haven't seen this article. */
case 'e':
if (rfq || *bptr == '-') {
if (strcmp(groupdir, ogroupdir)) {
i = bit;
strcpy(bfr, groupdir);
selectng(ogroupdir);
set(oobit);
printf("Holding article %d newsgroup %s\n", oobit, ogroupdir),
strcpy(groupdir, ogroupdir);
selectng(bfr);
bit = i;
} else {
printf("Holding article %d\n", oobit),
set(oobit);
}
} else {
printf("Holding article %d\n", bit),
set(bit);
goto caseplus; /* skip this article for now */
}
break;
case 'H':
case 'h':
if (!hflag)
dash(8, ofp);
if (*bptr == '-') {
if (oobit > 0)
fprintf(ofp, "Article %d:\n", oobit);
hprint(&hbuf1, ofp, 1 + (i=='H'));
} else {
fprintf(ofp, "Article %d of %ld: %s\n",
rfq ? oobit : bit, pngsize, h.ident);
hprint(&h, ofp, 1 + (i=='H'));
}
if (!hflag)
dash(8, ofp);
break;
case '#':
fprintf(ofp, "Article %d of %ld: newsgroup %s\n",
rfq ? oobit : bit, pngsize, rfq ? ogroupdir : groupdir);
break;
/* error */
case '?':
help(ofp);
break;
default:
fprintf(ofp, "? for commands.\n");
break;
}
return FALSE;
}
cancel_command()
{
tfilename = filename;
hptr = &h;
if (*bptr == '-') {
if (*ofilename1) {
tfilename = ofilename1;
hptr = &hbuf1;
}
bptr++;
}
EOL();
readmode = SPEC;
strcpy(rcbuf, hptr->path);
ptr1 = index(rcbuf, ' ');
if (ptr1)
*ptr1 = 0;
if (uid == ROOTID)
i = 0; /* root gets to cancel */
else
i = strcmp(username, rcbuf);
if (i != 0) {
fprintf(ofp, "Can't cancel what you didn't write.\n");
return;
}
if (!cancel(ofp, hptr, i) && hptr == &h) {
clear(bit);
saveart;
nextbit();
obit = -1;
fp = NULL;
if (!cflag)
putc('\n', ofp);
}
if (fp != NULL)
fclose(fp);
fp = NULL;
}
reply_command()
{
register char *pathptr, *ptr;
int edit = 1;
char *ed;
FILE *tfp;
char curberk[BUFLEN];
char *replyname();
char subj[100];
char folbuf[100];
extern char MAILPARSER[];
hptr = &h;
while (*bptr && index("d-", *bptr)) {
switch (*bptr) {
/* Followup the previous article. */
case '-':
hptr = &hbuf1;
break;
/* Don't edit the headers */
case 'd':
edit = 0;
break;
}
bptr++;
}
EOL();
if (edit && access(MAILPARSER, 1)) {
#ifdef IHCC
fprintf(stderr, "Can't edit headers, 'recmail' missing.\n");
#else
fprintf(stderr, "Can't edit headers without %s\n", MAILPARSER);
#endif
edit = 0;
}
*rcbuf = '\0';
*curberk = '\0';
pathptr = replyname(hptr);;
ptr = pathptr - 1;
i = 0;
for (ptr1 = address, ptr2 = pathptr; *ptr2; ptr1++, ptr2++) {
if (index("\"\\$", *ptr2))
*ptr1++ = '\\';
*ptr1 = *ptr2;
}
*ptr1 = '\0';
folbuf[0] = 0; /* References */
if (hptr->followid[0]) {
strcpy(folbuf, hptr->followid);
#ifdef MITRE
/* The usenet standards document (doc/standard
in the 2.10 distribution) specifies that
followups should use blanks to separate the
references in the header. */
strcat(folbuf, " ");
#else
strcat(folbuf, ", ");
#endif
}
strcat(folbuf, hptr->ident);
strcpy(subj, hptr->title); /* Subject */
while (isspace(*bptr))
bptr++;
if (*bptr != '\0')
strcpy(subj, bptr);
if (!prefix(subj, "Re:") && !prefix(subj, "re:")) {
strcpy(bfr, subj);
sprintf(subj, "Re: %s", bfr);
}
if (!edit) {
fprintf(ofp, "To: %s\n", pathptr);
ed = index(MAILER, '%');
if (ed && ed[1] == 's')
fprintf(ofp, "Subject: %s\n", subj);
fflush(ofp);
}
/* Put the user in the editor to create the body of the followup. */
if (edit) {
strcpy(tf, tft);
mktemp(tf);
ed = getenv("EDITOR");
if (ed == NULL)
ed = DFTEDITOR;
#ifdef MITRE
/* The original code failed to test the value
returned by fopen when using the template
tft. This is a bad practice, since fopen
for a file could fail due to kernel table
exhaustion or an existing file of the same
name with no permission, etc.
*/
if ((tfp = fopen(tf, "w")) == NULL)
perror(tf);
else {
fprintf(tfp, "To: %s\n", pathptr);
fprintf(tfp, "Subject: %s\n", subj);
fprintf(tfp, "References: %s\n\n", folbuf);
fclose(tfp);
}
#else
tfp = fopen(tf, "w");
fprintf(tfp, "To: %s\n", pathptr);
fprintf(tfp, "Subject: %s\n", subj);
fprintf(tfp, "References: %s\n\n", folbuf);
fclose(tfp);
#endif
sprintf(edcmdbuf, "%s %s", ed, tf);
system(edcmdbuf);
strcpy(rcbuf, MAILPARSER);
strcat(rcbuf, " -t");
strcat(rcbuf, " < ");
strcat(rcbuf, tf);
if (access(tf, 4)) {
fprintf(stderr, "Reply not sent: no input file.\n");
return;
}
printf("Sending reply.\n");
fflush(stdout);
if (fork() == 0) {
system(rcbuf);
unlink(tf);
_exit(0);
}
} else {
sprintf(rcbuf, MAILER, hptr->title);
sprintf(bfr, "%s %s", rcbuf, address);
system(bfr);
}
hdr();
}
xmit_command()
{
tfilename = filename;
if (*bptr == '-') {
if (*ofilename1)
tfilename = ofilename1;
bptr++;
}
if (*bptr != '\0' && *bptr != ' ') {
fprintf(ofp, "Bad system name.\n");
return;
}
while (*bptr == ' ')
bptr++;
if (*bptr == '\0') {
fprintf(ofp, "Missing system name.\n");
return;
}
if (s_find(&srec, bptr) == NULL) {
fprintf(ofp, "%s not in SYSFILE\n", bptr);
return;
}
transmit(&srec, tfilename);
}
next_ng_command()
{
if (!*bptr || *bptr == '-') {
obit = -1;
if (cflag)
clear(bit);
else
putc('\n', ofp);
if (*bptr)
actdirect = BACKWARD;
rfq = 0;
saveart;
if (nextng()) {
if (actdirect == BACKWARD)
fprintf(ofp, "Can't back up.\n");
else
return TRUE;
}
return FALSE;
}
while (isspace(*bptr))
bptr++;
if (!validng(bptr)) {
fprintf(ofp, "No such group.\n");
return FALSE;
}
obit = -1;
if (cflag)
clear(bit);
else
putc('\n', ofp);
readmode = SPEC;
rfq = 0;
saveart;
back();
selectng(bptr);
return FALSE;
}
followup_command()
{
int edit = 1;
char subj[100];
char folbuf[100];
char *ng;
FILE *tfp;
hptr = &h;
while (*bptr && index("d-", *bptr)) {
switch (*bptr) {
/* Followup the previous article. */
case '-':
hptr = &hbuf1;
break;
/* Don't edit the headers */
case 'd':
edit = 0;
break;
}
bptr++;
}
/* Figure out the subject, newsgroups, and references for the followup. */
ng = hptr->nbuf; /* Newsgroups */
if (hptr->followto[0])
ng = hptr->followto;
launder(ng);
folbuf[0] = 0; /* References */
if (hptr->followid[0]) {
strcpy(folbuf, hptr->followid);
#ifdef MITRE
/* The usenet standards document (doc/standard
in the 2.10 distribution) specifies that
followups should use blanks to separate the
references in the header. */
strcat(folbuf, " ");
#else
strcat(folbuf, ", ");
#endif
}
strcat(folbuf, hptr->ident);
strcpy(subj, hptr->title); /* Subject */
while (isspace(*bptr))
bptr++;
if (*bptr != '\0')
strcpy(subj, bptr);
if (!prefix(subj, "Re:") && !prefix(subj, "re:")) {
strcpy(bfr, subj);
sprintf(subj, "Re: %s", bfr);
}
/* Determine the command line for the shell. */
if (edit) {
sprintf(bfr, "%s -h -D", FOLLOWUP);
} else {
sprintf(bfr, "%s -D -F '%s' -n %s -t \'", FOLLOWUP, folbuf, ng);
strqcat(bfr, subj);
strcat(bfr, "\'");
}
/* backslash special characters */
for (ptr1 = rcbuf, ptr2 = bfr; *ptr2; ptr1++, ptr2++) {
if (index("\\", *ptr2))
*ptr1++ = '\\';
*ptr1 = *ptr2;
}
*ptr1 = '\0';
/* Let the user know what's going on. */
fprintf(ofp, "Posting followup article to network. Please use\n");
fprintf(ofp, "reply ('r') instead unless your article is of general\n");
fprintf(ofp, "interest. (To abort press BREAK.)\n");
fprintf(ofp, "Subject: %s\n", subj);
fprintf(ofp, "Newsgroups: %s\n", ng);
fprintf(ofp, "Hit <return> to continue, BREAK to abort: ");
fflush(ofp);
/* Give the user a chance to hit BREAK and back out. */
hascaught = 0;
oldsig = (char *) signal(SIGINT, catchintr);
gets(edcmdbuf);
signal(SIGINT, oldsig);
if (hascaught)
return;
/* Play obnoxious warnings, if necessary. */
if (recording(hptr->nbuf, 0))
return;
/* Put the user in the editor to create the body of the followup. */
ed = getenv("EDITOR");
if (ed == NULL || *ed == '\0')
ed = DFTEDITOR;
if (ed) {
strcpy(tf, tft);
mktemp(tf);
#ifdef MITRE
/* The original code failed to test the value
returned by fopen when using the template
tft. This is a bad practice, since fopen
for a file could fail due to kernel table
exhaustion or an existing file of the same
name with no permission, etc.
*/
if ((tfp = fopen(tf, "w")) == NULL)
perror(tf);
else {
if (edit) {
fprintf(tfp, "Newsgroups: %s\n", ng);
fprintf(tfp, "Subject: %s\n", subj);
fprintf(tfp, "References: %s\n", folbuf);
if (hptr->keywords[0])
fprintf(tfp, "Keywords: %s\n",
hptr->keywords);
fprintf(tfp, "\n");
}
fclose(tfp);
}
#else
tfp = fopen(tf, "w");
if (edit) {
fprintf(tfp, "Newsgroups: %s\n", ng);
fprintf(tfp, "Subject: %s\n", subj);
fprintf(tfp, "References: %s\n", folbuf);
if (hptr->keywords[0])
fprintf(tfp, "Keywords: %s\n", hptr->keywords);
fprintf(tfp, "\n");
}
fclose(tfp);
#endif
sprintf(edcmdbuf, "%s %s", ed, tf);
system(edcmdbuf);
strcat(rcbuf, "< ");
strcat(rcbuf, tf);
if (access(tf, 4)) {
fprintf(stderr, "Article not posted: no input file.\n");
return;
}
printf("Posting article.\n");
fflush(stdout);
if (fork() == 0) {
system(rcbuf);
unlink(tf);
_exit(0);
}
} else {
printf("%s\n", rcbuf);
system(rcbuf);
}
hdr();
}
caesar_command()
{
char temp[100];
char *pp = bptr;
FILE *pfp, *popen();
fprintf(stderr, "Caesar decoding:\n");
strcpy(temp, CAESAR);
if (*bptr) {
strcat(temp, " ");
strcat(temp, bptr);
}
if (NLINES(h, fp) > LNCNT && *PAGER) {
strcat(temp, " | ");
strcat(temp, PAGER);
}
pfp = popen(temp, "w");
tprint(fp, pfp, FALSE);
itsbeenseen(h.ident);
fclose(fp);
fp = NULL;
pclose(pfp);
}
/*
* Show the user the tail, if any, of the message on file
* descriptor fd, and close fd. The digester is considered,
* and the pager is used if appropriate.
*/
showtail(fd)
FILE *fd;
{
if (fd == NULL)
return;
if (dgest) {
digest(fd, ofp, &h);
} else if (!lflag && !pflag && !eflag) {
#ifdef PAGE
/* Filter the tail of long messages through PAGER. */
if (NLINES(h, fd) > LNCNT && *PAGER) {
if (!index(PAGER, FMETA)) {
FILE *pfp, *popen();
int cnt;
pfp = popen(PAGER, "w");
if (pfp == NULL)
pfp = ofp;
/*
* What follows is an attempt to prevent the
* next message from scrolling part of this
* message off the top of the screen before
* the poor luser can read it.
*/
tprint(fd, pfp, FALSE);
itsbeenseen(h.ident);
pclose(pfp);
}
else
pout(ofp);
holdup = TRUE;
#ifndef MITRE
fprintf(ofp, ":");
fflush(ofp);
#endif
}
else
#endif
tprint(fd, ofp, FALSE), itsbeenseen(h.ident);
}
fclose(fd);
}
/*
* Find the next article we want to consider, if we're done with
* the last one, and show the header.
*/
getnextart(minus)
int minus;
{
#ifdef MITRE
int noaccess = 0;
DIR *dfp;
struct direct *entry;
long nextnum, tnum;
long atol();
#endif
if (minus)
goto nextart2; /* Kludge for "-" command. */
if (bit == obit) /* Return if still on same article as last time */
return 0;
sigtrap = FALSE;
nextart:
dgest = 0;
if (bit < 1 && !rflag)
bit = 1;
/* If done with this newsgroup, find the next one. */
while (((long) bit > ngsize) || (rflag && bit < 1)) {
int i;
if (i=nextng()) {
if (actdirect == BACKWARD) {
fprintf(ofp, "Can't back up.\n");
actdirect = FORWARD;
continue;
}
else if (rfq++ || pflag || cflag)
return 1;
}
if (rflag)
bit = ngsize + 1L;
else
bit = -1;
if (uflag) {
long now;
time(&now);
if (now - timelastsaved > 5*60 /* 5 minutes */) {
printf("[Saving .newsrc]\n");
fflush(stdout);
writeoutrc();
timelastsaved = now;
}
}
}
nextart2:
#ifdef DEBUG
fprintf(stderr, "article: %s/%d\n", groupdir, bit);
#endif
if (rcreadok)
rcreadok = 2; /* have seen >= 1 article */
sprintf(filename, "%s/%d", dirname(groupdir), bit);
if (rfq && goodone[0])
strcpy(filename, goodone);
if (sigtrap) {
if (sigtrap == SIGHUP)
return 1;
if (!rcreadok)
xxit(0);
fprintf(ofp, "Abort (n)? ");
fflush(ofp);
gets(bfr);
if (*bfr == 'y' || *bfr == 'Y')
xxit(0);
sigtrap = FALSE;
}
#ifdef DEBUG
fprintf(stderr, "filename = '%s'\n", filename);
#endif
/* Decide if we want to show this article. */
#ifdef MITRE
/* This modification is to speed up readnews when you
first start reading a group for the first time.
On sites that expire articles, you eventually get
lots of articles that don't exist. You start
reading news for the first time, and you get to a
popular group with current articles in the 1000's,
and readnews says "Oh, an new group! Let's see,
is article 1 there? nope. Is article 2 there? nope.
Is article 3 there? nope..." and so on and so on,
so it does over 1000 calls to access(2), which is
really a waste. This modification solves this.
When readnews finds 5 consecutive articles that
don't exist, it hauls off and opens up the directory,
and reads it in and finds the next article to show.
*/
if (access(filename, 4)) {
/* since there can be holes in legal article numbers, */
/* we wait till we hit 5 consecutive bad articles */
/* before we haul off and scan the directory */
if (++noaccess < 5)
goto badart;
dfp = opendir(dirname(groupdir));
if (dfp == (DIR *) NULL) {
#ifdef DEBUG
fprintf(stderr, "can't open groupdir (%s)\n", dirname(groupdir));
#endif
noaccess = 0;
goto badart;
}
nextnum = rflag ? 0 : ngsize;
while ((entry = readdir (dfp)) != NULL) {
tnum = atol(entry->d_name);
#ifdef DEBUG
fprintf(stderr, "art %s (%ld) next %ld\n",
entry->d_name, tnum, nextnum);
#endif DEBUG
if (tnum <= 0)
continue;
if (rflag ? (tnum > nextnum && tnum < bit)
: (tnum < nextnum && tnum > bit))
nextnum = tnum;
}
closedir(dfp);
if (rflag ? (nextnum >= bit) : (nextnum <= bit))
goto badart;
do {
clear(bit);
nextbit();
} while (rflag ? (nextnum < bit) : (nextnum > bit));
obit = -1;
abs = FALSE;
goto nextart;
#ifdef DEBUG
fprintf(stderr, "bit %d nextnum %ld\n", bit, nextnum);
#endif DEBUG
} else
noaccess = 0;
#endif
if (ignorenews
#ifndef MITRE
|| access(filename, 4)
#endif
|| ((fp = fopen(filename, "r")) == NULL)
|| (hread(&h, fp, TRUE) == NULL)
|| (!rfq && !select(&h, abs))) {
#ifdef MITRE
badart:
#endif
#ifdef DEBUG
fprintf(stderr, "Bad article '%s'\n", filename);
#endif
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
clear(bit);
obit = -1;
nextbit();
abs = FALSE;
goto nextart;
}
abs = FALSE;
actdirect = FORWARD;
news = TRUE;
hdr();
if ((cflag && !lflag && !eflag) || pflag)
tprint(fp, ofp, FALSE);
#ifdef MITRE
/* Readnews with the -c, -l, and -e options will list
each article posted to multiple news groups once
for each group, rather than just once for the
session. */
if (cflag || lflag || eflag || pflag) {
#else
if (cflag && lflag && eflag || pflag) {
#endif
itsbeenseen(h.ident);
sigtrap = FALSE;
fclose(fp);
fp = NULL;
}
obit = bit;
return 0;
}
/*
* Print out whatever the appropriate header is
*/
hdr()
{
if (rfq)
return;
/* Wait for user to read previous article. */
if (holdup) {
holdup = FALSE;
#ifdef MITRE
/* If the last article is piped through the pager,
it prints a ':', but does not wait for any input.
*/
fprintf(ofp, ":");
fflush(ofp);
#endif
gets(bfr);
if (bfr[0])
explaincolon();
}
if (lflag || eflag) {
hprint(&h, ofp, 0);
return;
}
/* Print out a header */
if (ngrp) {
pngsize = ngsize;
ngrp--;
nghprint(groupdir);
}
if (!hflag)
#ifdef MITRE
/* Trivial fix to allow header line to show the
current newsgroup (which can be forgotten in
long newsgroups). */
fprintf(ofp, "Article %d of %ld, %s; %s.\n",
bit, pngsize, groupdir, briefdate(h.subdate));
#else
fprintf(ofp, "Article %d of %ld, %s.\n",
bit, pngsize, briefdate(h.subdate));
#endif
hprint(&h, ofp, pflag ? 1 : 0);
}
explaincolon()
{
fprintf(ofp, "\n'%s' ignored.\n", bfr);
fprintf(ofp, "The colon is to give you a chance to finish reading the\n");
fprintf(ofp, "previous article before the next header scrolls it off\n");
fprintf(ofp, "the top of the screen. You should hit `return' or `newline'\n");
fprintf(ofp, "when you are ready to go on to the next article.\n\n");
fflush(ofp);
}
nghprint(title)
char *title;
{
char *tstr = "Newsgroup ";
int l = strlen(title) + strlen(tstr);
fprintf(ofp, "\n");
if (!hflag) {
dash(l, ofp);
fprintf(ofp, "%s%s\n", tstr, title);
dash(l, ofp);
} else {
fprintf(ofp, "%s%s, ", tstr, title);
if (bit == pngsize)
#ifdef MITRE
/* The variable pngsize is long, yet
this prints it via %d instead of %ld.
*/
fprintf(ofp, "%ld\n", pngsize);
#else
fprintf(ofp, "%d\n", pngsize);
#endif
else
#ifdef MITRE
/* The variable pngsize is long, yet
this prints it via %d instead of %ld.
*/
fprintf(ofp, "%d-%ld\n", bit, pngsize);
#else
fprintf(ofp, "%d-%d\n", bit, pngsize);
#endif
}
fprintf(ofp, "\n");
}
/*
* Routine to catch a continue signal.
*/
catchcont()
{
#ifdef SIGCONT
signal(SIGCONT, catchcont);
sigtrap = SIGCONT;
#endif
hdr();
}
More information about the Comp.sources.unix
mailing list