Vnews part 6 (of 7)
sources-request at genrad.UUCP
sources-request at genrad.UUCP
Sun Jan 27 01:46:11 AEST 1985
# From: ka at hou3c
#
# Welcome to vnews release 2.11-B 1/17/85.
# This is part 6 out of 7.
# Feed me into sh (NOT csh).
if test ! -d postnews
then mkdir postnews
fi
if test ! -d vnews
then mkdir vnews
fi
cat > postnews/postnm5.c <<\!E!O!F!
/*
* STRING SCANNING ROUTINES:
* These routines act on a subject string which is pointed to by scanp.
*
* scchr Skip over characters contained in string.
* scnchr Skip over characters not in string.
* skipbl Skip over spaces, tabs, and newlines.
* scomment Skip to the end of a comment.
* scqnchr Like scnchr, but skips over any char if inside quotes.
* skipsw Skip over spaces, tabs, newlines, and comments.
* parseaddr Parse an address, setting up pointers to various parts.
* getval Return the characters between two pointers.
*
* Copyright 1984 by Kenneth Almquist. All rights reserved.
* Permission is granted for anyone to use and distribute, but not
* sell, this program provided that this copyright notice is retained.
*/
#include "postnm.h"
char *scanp;
scchr(chars)
char *chars;
{
int flag = 0;
while (*scanp && index(chars, *scanp)) {
flag++;
scanp++;
}
return flag;
}
scnchr(chars)
char *chars;
{
int flag = 0;
while (index(chars, *scanp) == NULL) {
flag++;
scanp++;
}
return flag;
}
skipbl() {
register char c;
while ((c = *scanp) == ' ' || c == '\t' || c == '\n')
scanp++;
}
scomment() {
int nest;
register char *p;
if (*(p = scanp) != '(')
return 0;
nest = 0;
for (;;) {
if (*p == '(')
nest++;
else if (*p == ')') {
if (--nest == 0)
break;
} else {
if (*p == '\\')
p++;
if (*p == '\0')
jsynerr("Nonterminated comment");
}
p++;
}
scanp = p;
return 1;
}
scqnchr(chars)
char *chars;
{
register char *p = scanp;
for (;;) {
if (*p == '"') {
p++;
while (*p != '"') {
if (*p == '\\')
p++;
if (*p++ == '\0')
jsynerr("Nonterminated string");
}
} else {
if (index(chars, *p))
break;
}
p++;
}
if (p == scanp)
return 0;
else {
scanp = p;
return 1;
}
}
skipws(chars)
char *chars;
{
for (;;) {
if (*scanp == '(')
scomment();
else if (*scanp == '\0' || index(chars, *scanp) == NULL)
break;
scanp++;
}
}
/*
* Parse an address.
*/
char *begreal, *endreal; /* real name */
char *begaddr, *endaddr; /* machine address */
char *beglocal, *endlocal; /* local part */
char *begdomain, *enddomain; /* domain part */
parseaddr() {
char *startp = scanp;
char *p;
begreal = begdomain = NULL;
if (*scanp == '.')
syntax: jsynerr("Illegal address syntax");
begaddr = beglocal = scanp;
if (*scanp == '<') {
routeaddr:
scanp++;
skipbl();
begaddr = beglocal = scanp;
scqnchr(":>");
if (*scanp == ':') {
scanp++;
skipbl();
beglocal = scanp;
scqnchr(">");
}
if (*scanp != '>')
goto syntax;
scanp = beglocal;
scqnchr("@>");
endlocal = scanp;
while (index(" \t\n", *(endlocal - 1)))
endlocal--;
if (endlocal <= beglocal)
goto syntax;
if (*scanp == '@') {
scanp++;
skipbl();
begdomain = scanp;
scqnchr(">");
enddomain = scanp;
while (index(" \t\n", *(enddomain - 1)))
enddomain--;
if (enddomain <= begdomain)
goto syntax;
}
if (*scanp != '>')
goto syntax;
scanp++;
} else {
scqnchr(" \t\n@(,<");
if (scanp == startp)
jsynerr("Program bug");
endlocal = scanp;
skipbl();
if (*scanp == '@') {
scanp++;
skipbl();
begdomain = scanp;
if (scnchr(" \t\n(,<") == 0)
goto syntax;
enddomain = scanp;
if (enddomain[-1] == '.')
goto syntax;
} else {
do p = scanp, skipbl();
while (scqnchr(" \t\n@(,<"));
if (*scanp != '<') {
scanp = endlocal;
} else {
begreal = beglocal, endreal = p;
goto routeaddr;
}
}
}
if (begdomain)
endaddr = enddomain;
else
endaddr = endlocal;
if (begreal == NULL) {
p = scanp;
skipbl();
if (*scanp != '(') {
scanp = p;
} else {
begreal = scanp + 1;
scomment();
endreal = scanp;
scanp++; /* skip over ')' */
}
}
}
char *
getval(p, q, buf)
char *p, *q, *buf;
{
if (buf == NULL)
buf = ckmalloc(q - p + 1);
bcopy(p, buf, q - p);
buf[q - p] = '\0';
return buf;
}
!E!O!F!
cat > postnews/postreply.c <<\!E!O!F!
/*
* This program handles replies and followups for vnews.
* Synopsys:
* reply -r file # mail a reply
* reply -f file # generate a followup
*/
#include <stdio.h>
#include <sys/types.h>
#include "config.h"
#include "newsdefs.h"
#include "libextern.h"
#include "arthead.h"
#include <sys/stat.h>
#include <signal.h>
#include <ctype.h>
#define NOPOST 22
int followup;
char *original;
char *references;
int vnews;
struct arthead h;
int checksum;
int nchars;
FILE *tfp;
char tempfile[16];
char tempout[16];
int outfd;
FILE *ckfopen();
char *savestr();
int nopost();
main(argc, argv)
char **argv;
{
int c;
int pid;
extern char *optarg;
signal(SIGQUIT, SIG_IGN);
while ((c = getopt(argc, argv, "r:f:v")) != EOF) {
switch (c) {
case 'r':
followup = 0;
original = optarg;
break;
case 'f':
followup = 1;
original = optarg;
break;
case 'v':
vnews = 1;
break;
}
}
if (original == NULL)
xerror("-f or -r must be specified");
signal(SIGINT, nopost);
pathinit();
getuser();
writetemp(followup);
edit();
if (samefile())
nopost();
/* fork off a child and let parent terminate */
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
#ifdef SIGTSTP
signal(SIGTSTP, SIG_IGN); /* I hope this works */
#endif
if ((pid = fork()) == -1)
fprintf(stderr, "postreply: can't fork\n");
if (pid > 0)
_exit(0);
nice(4);
sprintf(bfr, "%s.BAK", tempfile);
unlink(bfr);
postit();
xxit(0);
}
/*
* Print a recorded message warning the poor luser what he is doing
* and demand that he understands it before proceeding. Only do
* this for newsgroups listed in LIBDIR/recording.
*/
recording(ngrps)
char *ngrps;
{
char recbuf[BUFLEN];
FILE *fd;
char nglist[BUFLEN], fname[BUFLEN];
int c, n, yes;
sprintf(recbuf, "%s/recording", LIB);
fd = fopen(recbuf, "r");
if (fd == NULL)
return 0;
while ((fgets(recbuf, sizeof recbuf, fd)) != NULL) {
sscanf(recbuf, "%s %s", nglist, fname);
if (ngmatch(ngrps, nglist)) {
fclose(fd);
if (fname[0] == '/')
strcpy(recbuf, fname);
else
sprintf(recbuf, "%s/%s", LIB, fname);
fd = fopen(recbuf, "r");
if (fd == NULL)
return 0;
while ((c = getc(fd)) != EOF)
putc(c, stderr);
fclose(fd);
fprintf(stderr, "Do you understand this? Hit <return> to proceed, <BREAK> to abort: ");
n = read(2, recbuf, BUFLEN);
c = recbuf[0];
yes = (c=='y' || c=='Y' || c=='\n' || c=='\n' || c==0);
if (n <= 0 || !yes)
return -1;
else
return 0;
}
}
fclose(fd);
return 0;
}
/*
* Generate replies and followups.
*/
writetemp() {
FILE *artfp;
char subj[132];
char *p;
char *replyname();
checksum = 0;
nchars = 0;
artfp = ckfopen(original, "r");
if (gethead(&h, artfp) == NULL)
xerror("Original article has garbled header");
fclose(artfp);
scopyn(h.h_title, subj, 128);
if (!prefix(subj, "Re:") && !prefix(subj, "re:")) {
strcpy(bfr, subj);
sprintf(subj, "Re: %s", bfr);
}
p = h.h_nbuf;
if (hset(h.h_followto))
p = h.h_followto;
strcpy(bfr, p);
launder(bfr);
if (followup && recording(bfr))
nopost();
gentemp(tempfile);
tfp = ckfopen(tempfile, "w");
wstr("Command: %s\n", followup? "followup" : "reply");
wstr("Newsgroups: %s\n", bfr);
wstr("To: %s\n", replyname(&h, bfr));
wstr("Subject: %s\n", subj);
if (hset(h.h_keywords))
wstr("Keywords: %s\n", h.h_keywords);
wstr("Distribution: %s\n", hset(h.h_distribution)? h.h_distribution : "");
bfr[0] = 0; /* References */
if (hset(h.h_references)) {
strcpy(bfr, h.h_references);
strcat(bfr, " ");
}
strcat(bfr, h.h_ident);
references = savestr(bfr);
wstr("References: %s\n", bfr);
wstr("\n");
fclose(tfp);
}
wstr(fmt, a1, a2, a3, a4)
char *fmt;
{
char buf[1024];
register char *p;
sprintf(buf, fmt, a1, a2, a3, a4);
for (p = buf ; *p ; ) {
checksum += *p++;
nchars++;
}
fputs(buf, tfp);
}
/*
* Check to see if the newsgroup is moderated. If so, the moderator's
* name is returned in moderator.
*/
#ifdef notdef
check_mod(newsgroups, moderator)
char *newsgroups;
char *moderator;
{
register FILE *fd;
char ng[64], mod[BUFLEN];
sprintf(bfr, "%s/%s", LIB, "moderators");
if ((fd = fopen(bfr, "r")) == NULL)
return 0;
while (1) {
if (fgets(bfr, LBUFLEN, fd) == NULL) {
fclose(fd);
return 0;
}
twosplit(bfr, ng, mod);
if (ngmatch(newsgroups, ng)) {
strcpy(moderator, mod);
fclose(fd);
return 1;
}
}
}
/*
* Split a line of the form
* text whitespace text
* into two strings. Also trim off any trailing newline.
* This is destructive on src.
*/
twosplit(src, dest1, dest2)
char *src, *dest1, *dest2;
{
register char *p;
nstrip(src);
for (p=src; isalnum(*p) || ispunct(*p); p++)
;
*p++ = 0;
for ( ; isspace(*p); p++)
;
strcpy(dest1, src);
strcpy(dest2, p);
}
#endif
edit() {
char *p;
int pid;
int status;
char *arg[5];
register char **ap;
char *getenv(), *rindex();
if ((arg[0] = getenv("EDITOR")) == NULL)
arg[0] = DFTEDITOR;
if ((p = rindex(arg[0], '/')) != NULL)
p++;
else
p = arg[0];
ap = &arg[1];
if (strcmp(p, "vi") == 0) {
*ap++ = "+";
*ap++ = tempfile;
*ap++ = original;
} else if (strcmp(p, "gmacs") == 0
|| strcmp(p, "gemacs") == 0
|| strcmp(p, "gem") == 0) {
*ap++ = original;
*ap++ = tempfile;
} else {
*ap++ = tempfile;
*ap++ = original;
}
*ap = NULL;
if ((pid = fork()) == -1)
xerror("Can't fork");
if (pid == 0) {
signal(SIGQUIT, SIG_DFL);
execvp(arg[0], arg);
_exit(124);
}
signal(SIGINT, SIG_IGN);
status = pwait(pid);
if (status == 124 << 8)
xerror("Can't exec %s", arg[0]);
}
samefile() {
struct stat statb;
register FILE *fp;
register int c;
if (stat(tempfile, &statb) < 0)
xerror("%s has vanished!", tempfile);
if (statb.st_size == 0L)
return 1;
if (statb.st_size != nchars)
return 0;
fp = ckfopen(tempfile, "r");
while ((c = getc(fp)) != EOF)
checksum -= c;
return (checksum == 0);
}
postit() {
int artfd;
int i;
gentemp(tempout);
if ((outfd = creat(tempout, 0644)) < 0) {
fprintf(stderr, "\7\nCan't create %s\nreply failed\n\7", tempout);
xxit(1);
}
if (followup)
writestr("Subject: followup failed\n\n", outfd);
else
writestr("Subject: reply failed\n\n", outfd);
if (runpost()) {
if ((artfd = open(tempfile, 0)) < 0)
writestr("postreply: can't reopen article\n", outfd);
else {
writestr("\nYour article follows:\n", outfd);
while ((i = read(artfd, bfr, LBUFLEN)) > 0)
write(outfd, bfr, i);
close(artfd);
}
close(outfd);
unlink(tempfile);
close(0);
if (open(tempout, 0) != 0) {
fprintf(stderr, "\7Fatal error in reply!\nCan't reopen %s\7\n", tempout);
exit(1);
}
#ifdef MAILER
execl(MAILER, MAILER, username, (char *)0);
#endif
execl("/bin/mail", "mail", username, (char *)0);
fprintf(stderr, "\7Fatal error in reply!\nCan't exec mail program!\7\n");
exit(1);
}
}
runpost() {
int pid;
int status;
int fildes[2];
FILE *fp;
int inewsfail;
static char prog[] = POSTNM;
if (pipe(fildes) < 0) {
writestr("can't create pipe\n", outfd);
return -1;
}
while ((pid = fork()) == -1)
sleep(10);
if (pid == 0) {
#ifdef notdef
close(0);
if (open(tempfile, 0) != 0) {
sprintf(bfr, "postreply: can't open %s\n", tempfile);
writestr(bfr, outfd);
_exit(2);
}
#endif
if (fildes[1] != 1) {
close(1);
dup(fildes[1]);
close(fildes[1]);
}
close(fildes[0]);
close(2);
dup(1);
execl(prog, prog, "-wiR", references, tempfile, (char *)0);
writestr("postreply: can't exec postnm\n", 1);
_exit(2);
}
close(fildes[1]);
fp = fdopen(fildes[0], "r");
inewsfail = 0;
while (fgets(bfr, LBUFLEN, fp) != NULL) {
writestr(bfr, outfd);
if (prefix(bfr, "inews:"))
inewsfail = 1;
}
status = pwait(pid);
if (status != 0 || inewsfail) {
if ((status & 0377) == 0)
sprintf(bfr, "Exit status %d from postnm\n", status >> 8);
else
sprintf(bfr, "postreply: postnm died with signal %d\n", status & 077);
writestr(bfr, outfd);
return -1;
}
return 0;
}
#ifdef notdef
/*
* Save a copy of the article in the users NEWSARCHIVE file.
* The article is saved only if the user explicitly sets NEWSARCHIVE.
* Currently, we save both news and mail replies, which is
* rather questionable.
*/
save_article()
{
register FILE *in, *out;
register int c;
time_t timenow, time();
char *today, *ctime();
char *ccname;
if ((ccname = getenv("NEWSARCHIVE")) == NULL || ccname[0] == '\0')
return 0;
if ((in = fopen(tempfile, "r")) == NULL) {
writestr("Can't reopen temp file for article save\n", outfd);
return -1;
}
if ((out = fopen(ccname, "a")) == NULL) {
sprintf(bfr, "Can't open %s to save article\n", ccname);
writestr(bfr, outfd);
return -1;
}
timenow = time((time_t)0);
today = ctime(&timenow);
fprintf(out, "From postreply %s", today);
while ((c=getc(in)) != EOF)
putc(c, out);
putc('\n', out);
fclose(in);
fclose(out);
return 0;
}
#endif
writestr(s, fd)
char *s;
int fd;
{
write(fd, s, strlen(s));
}
pwait(pid) {
int status;
while (wait(&status) != pid);
return status;
}
gentemp(s)
char s[16];
{
strcpy(s, "/tmp/repXXXXXX");
mktemp(s);
}
xerror(fmt, a1, a2, a3, a4)
char *fmt;
{
int c;
fputs("postreply: ", stderr);
fprintf(stderr, fmt, a1, a2, a3, a4);
fputs("\nContinue?", stderr);
while ((c = getchar()) != '\n' && c != EOF);
xxit(1);
}
xxit(status) {
if (tempfile[0])
unlink(tempfile);
if (tempout[0])
unlink(tempout);
exit(status);
}
nopost() {
xxit(NOPOST);
}
!E!O!F!
cat > vnews/2.11features <<\!E!O!F!
+ Erase and kill processing performed on count.
+ Newsgroups presented in the order in which they appear in .newsrc. This
allows newsgroup presentation order to be set on an individual basis.
+ Articles are now presented grouped by discussion. Within a discussion,
articles are sorted by date.
+ An index page is now available. The -A option will cause the index page
to be shown on entry to each group. Scrolling off the end of the index
page using space gets you to the first article in the newsgroup. You can
execute practically all vnews commands on the index page; the scrolling
commands scroll the index page and the other commands apply to the current
article. The 'a' command will toggle you to/from the index page.
+ There is now an article list stack. The "N newsgroup" command will save
the current newsgroup on the stack so that when you reach the end of the
newsgroup all the articles in the newsgroup you just left will still be
there. Currently, the "N newsgroup" command empties the stack before
beginning in order to keep things simple for the user. The parent and
'<' commands create an article list containing one article. Unless the
current article list contains a single article, the current article list
will be saved on the stack, so that you will automaticly return to where
you were.
+ The "N newsgroup command" will now work even with unsubscribed groups.
!E!O!F!
cat > vnews/ToDo <<\!E!O!F!
Read in next newsgroups during idle time. May not be able to store in
memory, but could write record to temp file, and do sort when actually
enter group.
Chdir to spool directory while running.
Add .rnlock checking. (Use .newsrc.lck since rn use SIGEMT.)
Make N- get real previous group.
Make jd command save discussion for later.
Make t command get you to first unread article.
Make xerror do a longjmp to the code that resets the tty modes and updates
the .newsrc file. Save a copy of the .newsrc file in .newsrc.bak.
!E!O!F!
cat > vnews/artseq.c <<\!E!O!F!
#include "vnews.h"
#ifdef SMALL /* try to avoid running out of core */
#define MAXNUMARTS 100 /* max arts we can read in one newsgroup */
#endif
static struct svartlist alstack[10]; /* stack of article lists */
struct svartlist *alptr = alstack; /* stack pointer for above */
static int readmode = NEXT; /* currently unused */
static struct ngentry *ngindex; /* current location in .newsrc file */
/*
* set or clear the unread article flag
*/
setnew(on) {
if (alptr->al_type != SVNEWSGROUP)
return;
if (on)
setunread(curart->i_artnum);
else
clrunread(curart->i_artnum);
}
/*
* Go to a particular article number
*/
setartno(num)
int num;
{
if (num <= 0) {
msg("Bad article no.");
return;
}
if (num > numthisng) {
msg("Not that many articles.");
return;
}
curart = &thisng[num - 1];
setupart();
}
/*
* Advance the counter to the next unread article.
*/
nextart(count, zapthem)
{
if (count <= 0)
return FALSE;
while (--count >= 0) {
if (zapthem)
setnew(0);
if (readmode == SPEC || xflag) {
curart++, curind++;
} else {
while (++curart, ++curind <= numthisng && !isunread(curart->i_artnum))
;
}
if (curind > numthisng)
return getnxtng(FORWARD);
}
setupart();
return FALSE;
}
/*
* Vnews article list stack. Pushal(type) pushes the current article list
* onto the stack. Type is the type of the replacement article list. Popal
* restores an article list from the stack. Setupart should be called after
* popal.
*/
struct alsave {
int a_numthisng;
int a_curind;
struct ngentry *a_curng;
int a_iwartlin;
int a_indexpg;
int a_maxartno;
};
pushal(type) {
struct alsave als;
if (alptr >= alstack + 9) {
msg("newsgroups nested too deeply");
alptr->al_type = type;
return;
}
alptr->al_tfoffset = tfoffset;
als.a_numthisng = numthisng;
als.a_curind = curind;
als.a_curng = curng;
als.a_iwartlin = indexwin.w_artlin;
als.a_indexpg = indexpg;
als.a_maxartno = maxartno;
fseek(tfp, (long)tfoffset, 0);
fwrite((char *)&als, sizeof als, 1, tfp);
fwrite((char *)thisng, sizeof *thisng, numthisng, tfp);
tfoffset = ftell(tfp);
tflinno = -1;
(++alptr)->al_type = type;
}
popal() {
struct alsave als;
tfoffset = (--alptr)->al_tfoffset;
fseek(tfp, (long)tfoffset, 0);
fread((char *)&als, sizeof als, 1, tfp);
numthisng = als.a_numthisng;
curind = als.a_curind;
indexwin.w_artlin = als.a_iwartlin;
indexpg = als.a_indexpg;
fread((char *)thisng, sizeof *thisng, numthisng, tfp);
indexwin.w_force = 2;
tflinno = -1;
if ((alptr+1)->al_type == SVNEWSGROUP)
setupgrp(als.a_curng, als.a_maxartno);
setartno(curind);
}
switchng(ngp) /* go to specific newsgroup */
struct ngentry *ngp;
{
if (alptr >= alstack + 8) {
msg("Nesting too deep.");
return;
}
if (alptr->al_type == SVARTICLE)
popal();
pushal(SVNEWSGROUP);
readinng(ngp, 1);
if (numthisng <= 0) {
popal();
msg("group? %s: empty", ngp->ng_name);
} else {
ngrp++;
}
setupart();
}
spclgrp(dp, a)
DPTR dp;
struct artrec *a;
{
if (alptr->al_type != SVARTICLE)
pushal(SVARTICLE);
scopyn(a->a_title, thisng[0].i_title, 36);
scopyn(a->a_from, thisng[0].i_from, 29);
thisng[0].i_nlines = a->a_nlines;
thisng[0].i_artnum = a->a_group[0].a_artno;
thisng[0].i_dptr = dp;
numthisng = 1;
curart = thisng;
setupart();
sprintf(filename, "%s/%s", SPOOL, a->a_file);
indexpg = 0;
}
getnxtng(direct) {
if (direct == FORWARD && alptr > alstack) { /* al stack stuff */
popal();
setupart();
/* advance to next article if current one read */
if ((alptr+1)->al_type == SVNEWSGROUP
&& isunread(curart->i_artnum) == 0)
return nextart(1, 0);
return FALSE;
}
while (alptr > alstack) /* for backwards, clear al stack */
popal();
for (;;) {
if (direct == FORWARD) {
if ((ngindex = nextgrp(ngindex)) == NULL) {
quitflg++;
return TRUE;
}
} else {
if ((ngindex = prevgrp(ngindex)) == NULL) {
msg("Can't back up.");
direct = FORWARD;
continue;
}
}
if (ngindex->ng_unsub || !wewant(ngindex->ng_name))
continue;
readinng(ngindex, 0);
if (numthisng > 0)
break;
}
ngrp++;
setupart();
return FALSE;
}
setupart() {
if (ngrp) {
pngsize = maxartno;
if (Aflag)
indexpg = 1;
if (indexpg)
ngrp = 0;
}
curind = curart - thisng + 1;
#ifdef DEBUG
fprintf(stderr, "getnextart settles on #%d, bit %d\n", curind, curart->i_artnum);
#endif
dirname(curng->ng_name, filename);
sprintf(filename + strlen(filename), "/%d", curart->i_artnum);
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
news = TRUE;
indexwin.w_force |= 1;
erased = 0;
}
/*
* Read in the newsgroup.
*/
readinng(ngp, all)
struct ngentry *ngp;
{
register struct artinfo *ip;
struct artrec a, a2;
DPTR dp, dp2;
int ngnum = ng_num(ngp);
ARTNO bit, oldbit;
int first;
int i;
static int thisngsize = 20;
int cmppart();
char *ckmalloc(), *realloc();
if (news) {
curflag = CURHOME;
#ifdef CURSES
move(0, 0); /* let user know we are thinking */
refresh();
#else
_amove(0, 0); /* let user know we are thinking */
vflush();
#endif
}
if (thisng == NULL) {
thisng = ckmalloc(20 * sizeof thisng[0]);
}
numthisng = 0;
oldbit = 0;
first = 1;
BKWD_GROUP(ngnum, bit, dp, a) {
if (first) {
setupgrp(ngp, bit);
first = 0;
}
while (--oldbit > bit) /* clear intermediate bits */
clrunread(oldbit);
oldbit = bit;
if (bit < minartno && !all)
break;
if (!(all || isunread(bit)))
continue;
/* later: rethink the handling of all */
if ((a.a_flags & A_NOFILE) || !aselect(&a, 0) || haveunsub(dp)) {
skipit: clrunread(bit);
continue;
}
a2.a_subtime = a.a_subtime;
for (dp2 = a.a_parent, i = 0 ; dp2 != DNULL && ++i < 100 ; dp2 = a2.a_parent) {
if (haveunsub(dp2))
goto skipit;
readrec(dp2, &a2);
}
if (i == 100)
fprintf(stderr, "Parent loop %s %s \r\n", a.a_ident, a2.a_ident); /*DEBUG*/
if (numthisng >= thisngsize) {
thisngsize += 4;
if ((thisng = realloc((char *)thisng, thisngsize * sizeof thisng[0])) == NULL)
xerror("Out of space");
}
ip = &thisng[numthisng];
ip->i_artnum = bit;
ip->i_subtime = a.a_subtime;
ip->i_basetime = a2.a_subtime;
scopyn(a.a_title, ip->i_title, 37);
scopyn(a.a_from, ip->i_from, 29);
ip->i_dptr = dp;
ip->i_nlines = a.a_nlines;
#ifndef DEBUG
if (debugging > 1)
#endif
fprintf(stderr, "storing %d in %d, subtime %d\n", bit, numthisng, ip->i_subtime);
numthisng++;
#ifdef MAXNUMARTS
if (numthisng >= MAXNUMARTS) {
printf("Warning - more than %d new articles, missing some.\n", MAXNUMARTS);
goto nomore; /* exit loop */
}
#endif
}
while (--oldbit >= minartno)
clrunread(oldbit);
nomore:
if (numthisng > 0) {
qsort((char *)thisng, numthisng, sizeof thisng[0], cmppart);
}
curart = thisng; /* go to start of group */
indexwin.w_artlin = 0;
indexwin.w_force = 2;
}
/*
* Check whether we ahve unsubscribed to the discussion.
*/
haveunsub(dp)
DPTR dp;
{
register DPTR *p;
register int i;
for (i = ndunsub, p = dunsub ; --i >= 0 ; p++)
if (*p == dp)
return 1;
return 0;
}
/*
* Compare two articles, and determine if they are in the same discussion.
* If not, we sort by time of base article.
*/
cmppart(n1, n2)
register struct artinfo *n1, *n2;
{
if (n1->i_basetime > n2->i_basetime)
return 1; /* different discussions */
else if (n1->i_basetime < n2->i_basetime)
return -1; /* different discussions */
else if (n1->i_subtime > n2->i_subtime)
return 1; /* same discussion */
else if (n1->i_subtime < n2->i_subtime)
return -1; /* same discussion */
else
return 0; /* same discussion */
}
/*
* Return TRUE if the user has not ruled out this article.
*/
aselect(a, insist)
register struct artrec *a;
int insist;
{
extern char *titles[];
if (insist)
return TRUE;
if (tflag && !titmat(a->a_title, titles))
return FALSE;
if (aflag && a->a_rectime < atime)
return FALSE;
if (a->a_ngroups > 1 && !rightgroup(a))
return FALSE;
if (fflag && a->a_parent != DNULL)
return FALSE;
return TRUE;
}
/*
* Code to avoid showing multiple articles for vnews.
* Works even if you exit vnews.
* Returns nonzero if we should show this article.
*/
rightgroup(a)
struct artrec *a;
{
int i, flag;
struct ngentry *ngp;
flag = 1;
for (i = 0 ; i < a->a_ngroups ; i++) {
ngp = ngtable + a->a_group[i].a_ngnum;
if (ngp == curng)
return flag;
if (wewant(ngp->ng_name) && ngp->ng_unsub == 0) {
flag = 0;
}
}
/* "Can't happen" */
return 1;
}
/*
* Return true if the newsgroup was specified in the -n option.
*/
wewant(name)
char *name;
{
return ngmatch(name, sublist);
}
!E!O!F!
cat > vnews/curterm.c <<\!E!O!F!
/*
* Additions to curses.
*/
#include <stdio.h>
#include <curses.h>
/*
* move to the bottom of the screen.
*/
botscreen() {
move(LINES-1, 0);
refresh();
putchar('\n');
fflush(stdout);
}
/*
* Clear a line.
*/
clrline(linno) {
move(linno, 0);
clrtoeol();
}
#ifdef ACURSES
/*
* Ring the bell on the terminal.
*/
beep() {
putchar('\007');
fflush(stdout);
}
#endif
!E!O!F!
cat > vnews/dispcntl.c <<\!E!O!F!
#include "vnews.h"
#ifdef STATTOP
#define PRLINE 0 /* prompter line */
#define SPLINE 1 /* secondary prompt line */
#define ARTWIN 2 /* first line of article window */
#else
#define PRLINE (ROWS-1)/* prompter line */
#define SPLINE (ROWS-2)/* secondary prompt line */
#define ARTWIN 0 /* first line of article window */
#endif
int dumpart(), dumpheaders(), dumphelp(), dumphdr();
int nullsub();
struct window artwin = { /* window containing article */
0, 0, dumpart, 2};
struct window indexwin = { /* window containing article index */
0, 0, dumpheaders, 2};
struct window helpwin = { /* window containing help message */
0, 0, dumphelp, 2};
struct window emptywin = { /* empty window */
0, 0, nullsub, 2};
struct window hdrwin = { /* window containing header */
0, 0, dumphdr, 2};
extern struct svartlist *alptr; /* article list stack */
/*
* Open the current article. Returns nonzero on failure.
*/
openart() {
struct stat statb;
FILE *gethead();
if (fp != NULL)
return 0;
#ifdef CURSES
move(0, 0); /* let user know we are thinking */
refresh();
#else
_amove(0, 0); /* let user know we are thinking */
vflush();
#endif
artwin.w_force = 2;
lastlin = 0;
fp = fopen(filename, "r");
if (fp == NULL) {
msg("Can't open %s", filename);
artlines = 0;
artread = 1;
return TRUE;
}
fstat(fileno(fp), &statb);
artlength = statb.st_size;
if (gethead(&h, fp) == NULL) {
msg("Garbled header");
fclose(fp);
fp = NULL;
artlines = 0;
artread = 1;
return TRUE;
}
{ /* strip off any notesfile header */
register c;
register char *p = h.h_title + strlen(h.h_title) - 5;
if (p > h.h_title
&& (strcmp(p, " (nf)") == 0 || strcmp(p, "(nf)\"") == 0)) {
if ((c = getc(fp)) != '#') {
ungetc(c, fp);
} else {
while ((c = getc(fp)) != '\n' && c != EOF);
while ((c = getc(fp)) != '\n' && c != EOF);
while ((c = getc(fp)) != '\n' && c != EOF);
}
}
}
artbody = ftell(fp);
fmthdr();
artlines = lastlin;
artread = 0;
if (! cflag && hdrend < ARTWLEN)
hdronly = 1;
artwin.w_artlin = 0;
return 0;
}
/*
* Print out whatever the appropriate header is
*/
fmthdr() {
char *vbriefdate();
char date[64];
if (ngrp) {
ngrp = 0;
if (!hflag) {
sprintf(bfr, "Newsgroup %s", curng->ng_name); tfappend(bfr);
tfappend("");
}
}
hdrstart = lastlin;
if (!hflag) {
sprintf(bfr, "Article %s %s",
h.h_ident, vbriefdate(h.h_subdate, date));
tfappend(bfr);
}
vhprint(&h, pflag ? 1 : 0);
sprintf(bfr, "(%d lines)", curart->i_nlines); tfappend(bfr);
tfappend("");
hdrend = lastlin;
}
/* Arpa format: Sat, 14-May-83 03:45:14 EDT */
/* Bugs: doesn't work on article with non-arpa dates */
char *
vbriefdate(q, date)
register char *q;
char *date;
{
register char *p;
register i;
char day[2];
p = date;
if (q[3] == ',') {
for (i = 3 ; --i >= 0 ; )
*p++ = *q++;
*p++ = ' ';
q += 2;
}
day[0] = *q++;
if (*q != ' ' && *q != '-') day[1] = *q++;
else day[1] = '\0';
q++;
for (i = 3 ; --i >= 0 ; )
*p++ = *q++;
*p++ = ' ';
*p++ = day[0];
if (day[1]) *p++ = day[1];
q += 5;
*p++ = ' ';
if (q[-1] != '0') *p++ = q[-1];
for (i = 4 ; --i >= 0 ; )
*p++ = *q++;
*p++ = '\0';
return date;
}
/*
* Print the file header to the temp file.
*/
vhprint(hp, verbose)
register struct arthead *hp;
int verbose;
{
register char *p1, *p2;
int i;
char fname[BUFLEN];
fname[0] = '\0'; /* init name holder */
p1 = index(hp->h_from, '('); /* Find the sender's full name. */
if (p1 == NULL && hset(hp->h_path))
p1 = index(hp->h_path, '(');
if (p1 != NULL) {
strcpy(fname, p1+1);
p2 = index(fname, ')');
if (p2 != NULL)
*p2 = '\0';
}
sprintf(bfr, "Subject: %s", hp->h_title);
if ((i = strlen(bfr) - 7) > 9
&& strcmp(bfr + i, " - (nf)") == 0
&& (strncmp(bfr+9, "Re: ", 4) != 0 || i < 9+39))
bfr[i] = '\0'; /* clobber "- (nf)" */
tfappend(bfr);
if (!hflag && hset(hp->h_keywords))
sprintf(bfr, "Keywords: %s", hp->h_keywords), tfappend(bfr);
if (verbose) {
sprintf(bfr, "From: %s", hp->h_from); tfappend(bfr);
sprintf(bfr, "Path: %s", hp->h_path); tfappend(bfr);
if (hset(hp->h_organization))
sprintf(bfr, "Organization: %s", hp->h_organization), tfappend(bfr);
}
else {
if (p1 != NULL)
*--p1 = '\0'; /* bump over the '(' */
#ifdef INTERNET
/*
* Prefer Path line if it's in internet format, or if we don't
* understand internet format here, or if there is no reply-to.
*/
sprintf(bfr, "From: %s", hp->h_from);
#else
sprintf(bfr, "Path: %s", tailpath(hp));
#endif
if (fname[0] != '\0') {
strcat(bfr, " (");
strcat(bfr, fname);
if (hset(hp->h_organization) && !hflag) {
strcat(bfr, " @ ");
strcat(bfr, hp->h_organization);
}
strcat(bfr, ")");
}
tfappend(bfr);
if (p1 != NULL)
*p1 = ' ';
if (hset(hp->h_ctlmsg)) {
sprintf(bfr, "Control: %s", hp->h_ctlmsg);
tfappend(bfr);
}
}
if (verbose) {
sprintf(bfr, "Newsgroups: %s", hp->h_nbuf); tfappend(bfr);
sprintf(bfr, "Date: %s", hp->h_subdate); tfappend(bfr);
if (hset(hp->h_sender))
sprintf(bfr, "Sender: %s", hp->h_sender), tfappend(bfr);
if (hset(hp->h_replyto))
sprintf(bfr, "Reply-To: %s", hp->h_replyto), tfappend(bfr);
if (hset(hp->h_followto))
sprintf(bfr, "Followup-To: %s", hp->h_followto), tfappend(bfr);
}
else if (strcmp(hp->h_nbuf, curng->ng_name) != 0)
sprintf(bfr, "Newsgroups: %s", hp->h_nbuf), tfappend(bfr);
}
/*
* Append file to temp file, handling control characters, folding lines, etc.
* We don't grow the temp file to more than nlines so that a user won't have
* to wait for 20 seconds to read in a monster file from net.sources.
* What we really want is coroutines--any year now.
*/
#define ULINE 0200
static char *maxcol;
appfile(iop, nlines)
register FILE *iop;
{
register int c;
register char *icol; /* &bfr[0] <= icol <= maxcol */
if (artread || artlines >= nlines)
return;
maxcol = bfr;
icol = bfr;
while ((c = getc(iop)) != EOF) {
switch (c) {
case ' ':
if (icol == maxcol && icol < bfr + LBUFLEN - 1) {
*icol++ = ' ';
maxcol = icol;
} else {
icol++;
}
break;
case '\t':
icol = (icol - bfr &~ 07) + 8 + bfr;
growline(icol);
break;
case '\b':
if (icol > bfr) --icol;
break;
case '\n':
outline();
if (artlines >= nlines)
return;
icol = bfr;
break;
case '\r':
icol = bfr;
break;
case '\f':
outline(); outline(); outline();
if (artlines >= nlines)
return;
icol = bfr;
break;
default:
if (c < ' ' || c > '~')
break;
else if (icol >= bfr + LBUFLEN - 1)
icol++;
else if (icol == maxcol) {
*icol++ = c;
maxcol = icol; }
else if (*icol == ' ')
*icol++ = c;
else if (c == '_')
*icol++ |= ULINE;
else
*icol++ = (c | ULINE);
break;
}
}
if (maxcol != bfr) /* file not terminated with newline */
outline();
artread++;
}
growline(col)
char *col;
{
while (maxcol < col && maxcol < bfr + LBUFLEN - 1)
*maxcol++ = ' ';
}
outline() {
*maxcol = '\0';
if (strncmp(bfr, ">From ", 6) == 0) {
register char *p;
for (p = bfr ; (*p = p[1]) != '\0' ; p++);
}
tfappend(bfr);
if (maxcol > bfr)
artlines = lastlin;
maxcol = bfr;
}
prget(prompter, buf)
char *prompter, *buf;
{
char *p, *q, *r;
int c, lastc;
curflag = CURP2;
r = buf;
lastc = '\0';
for (;;) {
*r = '\0';
p = secpr;
for (q = prompter ; *q ; q++)
*p++ = *q;
for (q = buf ; *q ; q++) {
if (p < &secpr[SECPRLEN-1] && *q >= ' ' && *p <= '~')
*p++ = *q;
}
*p = '\0';
c = vgetc();
if (c == '\n' || c == INTR) {
break;
}
if (c == cerase) {
if (lastc == '\\')
r[-1] = c;
else if (r > buf)
r--;
} else if (c == ckill) {
if (lastc == '\\')
r[-1] = c;
else
r = buf;
} else if (r < buf + SECPRLEN - 1) {
*r++ = c;
} else {
beep();
}
lastc = c;
}
curflag = CURHOME;
secpr[0] = '\0';
if (c == INTR) {
nextwin = curwin;
return 1;
} else
return 0;
}
/*** Routines for handling temporary file ***/
/*
* Append to temp file.
* Long lines are folded.
*/
tfappend(line)
char *line;
{
while (strlen(line) > COLS) {
tfput(line, lastlin++);
line += COLS;
}
tfput(line, lastlin++);
}
tfput(line, linno)
char *line;
{
register char *p;
register FILE *rtfp; /* try to make it a litte faster */
register int i;
p = line;
#if BSDREL > 7
i = (COLS + 1) &~ 1;
#else
i = COLS;
#endif
tfseek(linno, 1);
rtfp = tfp;
while (--i >= 0) {
if (*p)
putc(*p++, rtfp);
else
putc('\0', rtfp);
}
tflinno++;
}
tfget(line, linno)
char *line;
{
tfseek(linno, 0);
#if BSDREL > 7
fread(line, (COLS + 1) &~ 1, 1, tfp);
#else
fread(line, COLS, 1, tfp);
#endif
line[COLS] = '\0';
tflinno++;
}
tfseek(linno, wrflag) {
static int last = 1;
if (linno != tflinno || wrflag != last) {
#if BSDREL > 7
fseek(tfp, (long)linno * (COLS + 1 &~ 1) + tfoffset, 0);
#else
fseek(tfp, (long)linno * COLS + tfoffset, 0);
#endif
tflinno = linno;
last = wrflag;
}
}
/*** display management ***/
msg(s, a1, a2, a3, a4, a5, a6) char *s; {
sprintf(secpr, s, a1, a2, a3, a4, a5, a6);
}
scroll(amount) {
register struct window *w;
w = &artwin;
if (indexpg)
w = &indexwin;
if ((w->w_artlin += amount) < 0)
w->w_artlin = 0;
}
/*
* Update the display.
* The display is entirely controlled by this routine,
* which means that this routine may get pretty snarled.
*/
static struct window *savewin; /* window on last call to updscr */
updscr() {
int i;
register struct window *w = curwin;
char buf[40];
if (checkin())
return;
if (w != savewin)
w->w_force = 2;
if ((w->w_force || w->w_artlin != w->w_svartlin)
&& (quitflg == 0 || w == &emptywin)) {
#ifndef CURSES
if (w->w_force < 2)
ushift(ARTWIN, ARTWIN+ARTWLEN-1, w->w_artlin - w->w_svartlin);
#endif
for (i = ARTWIN ; i < ARTWIN + ARTWLEN ; i++)
clrline(i);
(*w->w_dump)(w->w_artlin, ARTWIN, ARTWLEN);
w->w_force = 0;
w->w_svartlin = w->w_artlin;
savewin = w;
}
clrline(SPLINE), clrline(PRLINE);
#ifdef STATTOP
mvaddstr(PRLINE, 0, prompt);
#else
if (strlen(secpr) <= COLS)
mvaddstr(PRLINE, 0, prompt);
#endif
mvaddstr(PRLINE, 48, timestr);
if (alptr->al_type == SVARTICLE)
sprintf(buf, "%.18s", curng->ng_name);
else
sprintf(buf, "%.18s %d/%d ", curng->ng_name, curind, numthisng);
mvaddstr(PRLINE, 20, buf);
if (ismail)
mvaddstr(PRLINE, 62, ismail > 1? "MAIL" : "mail");
mvaddstr(SPLINE, 0, secpr);
if (curflag == CURP1)
move(PRLINE, strlen(prompt));
else if (curflag == CURHOME)
move(0, 0);
refresh();
}
addnum(n) {
if (n >= 10)
addnum(n / 10);
addch(n % 10 + '0');
}
/*
* Dump the article to the screen. Updscr has already cleared the region.
*/
dumpart(artlin, scrlin, count) {
register int i;
if (hdronly && count > hdrend - artlin)
count = hdrend - artlin;
#ifdef DIGPAGE
if (endsuba > 0 && count > endsuba - artlin)
count = endsuba - artlin;
#endif
if (count > lastlin - artlin)
count = lastlin - artlin;
for (i = 0 ; i < count ; i++) {
tfget(bfr, artlin + i);
mvaddstr(scrlin + i, 0, bfr);
}
}
/*
* All headers command: show headers for this group.
*/
dumpheaders(artlin, scrlin, count)
{
register int i;
for (i = count ; --i >= 0 ; artlin++, scrlin++) {
if (artlin == 0) {
sprintf(bfr, " IND FILE LINES Newsgroup %s, %d articles", curng->ng_name, numthisng);
mvaddstr(scrlin, 0, bfr);
} else if (artlin >= 2 && artlin < numthisng + 2) {
move(scrlin, 0);
addch(artlin-1 == curind ? '>' :
(xflag || isunread(thisng[artlin-2].i_artnum) ? ' ': 'D'));
sprintf(bfr, "%3d%5d%5d %-36s %s",
artlin-1, thisng[artlin-2].i_artnum, thisng[artlin-2].i_nlines,
thisng[artlin-2].i_title, thisng[artlin-2].i_from);
bfr[COLS] = '\0';
addstr(bfr);
}
}
}
/*
* Dump the help message to the screen. The help msg can't be scrolled.
*/
dumphelp(artlin, scrlin, count) {
FILE *helpf;
#ifndef VHELP
char VHELP[FPATHLEN];
#endif
#ifndef VHELP
sprintf(VHELP, "%s/vnews.help", LIB);
#endif
if ((helpf = fopen(VHELP, "r")) == NULL) {
addstr("Can't open help file");
return;
}
while (fgets(bfr, LBUFLEN, helpf) != NULL) {
nstrip(bfr);
mvaddstr(scrlin, 0, bfr);
scrlin++;
}
fclose(helpf);
}
/*
* Dump the full header on the screen. The header cannot be scrolled.
* We use the routine appfile to append to the file, which forces us
* to do some juggling to return to the article.
*/
dumphdr(artlin, scrlin, count) {
long saveoff;
int svartread, svartlines, svlastlin;
int stoppos = scrlin + count - 1 ;
register int i;
saveoff = ftell(fp);
fseek(fp, 0L, 0);
svartread = artread, svartlines = artlines, svlastlin = lastlin;
artread = 0;
appfile(fp, artlines + count);
if (count > lastlin - svlastlin)
count = lastlin - svlastlin;
for (i = 0 ; i < count ; i++) {
tfget(bfr, svlastlin + i);
if (bfr[0] == '\0')
break;
mvaddstr(scrlin + i, 0, bfr);
}
nochange(i + 1, stoppos) ;
artread = svartread, artlines = svartlines, lastlin = svlastlin;
fseek(fp, saveoff, 0);
}
nullsub() {;}
!E!O!F!
cat > vnews/genmakefile <<\!E!O!F!
: This shell procedure generates the vnews makefile.
LIB=../lib
if test ! -f $LIB/makedefs
then echo "$LIB/makedefs not does not exist"
exit 1
fi
exec > temp
. $LIB/makedefs
cat <<!
# Vnews makefile 2.11-B 1/18/85
# definitions
!
cat $LIB/makedefs
sed -e 's:$LIB:'$LIB:g <<\!
LOGDIR =
IBMFLAGS =
DEBUG = -O
CFLAGS = $(DEBUG) $(IBMFLAGS) -I$LIB
LFLAGS = -i $(DEBUG) $(IBMFLAGS)
VOBJECTS = readnews.o vextern.o $(LOGDIR) vreadr.o dispcntl.o artseq.o termio.o virtterm.o
# dependencies
all: makefile vnews
makefile: genmakefile $LIB/makedefs
genmakefile
@echo 'Makefile changed, so restart make.'
@sh -c 'exit 22'
install: all
-/bin/mv $(BINDIR)/vnews $(BINDIR)/ovnews
/bin/cp vnews $(BINDIR)/vnews
-/bin/mv $(LIBDIR)/vnews.help $(LIBDIR)/ovnews.help
/bin/cp vnews.help $(LIBDIR)/vnews.help
clean:
rm -f core *.o
readnews.o: readnews.c rparams.h
$(CC) $(CFLAGS) -c readnews.c
rfuncs.o: rfuncs.c rparams.h
$(CC) $(CFLAGS) -c rfuncs.c
logdir.o: logdir.c
$(CC) $(CFLAGS) -c logdir.c
vnews: $(VOBJECTS) $LIB/rpathinit.o $LIB/rlib.a
$(CC) $(LFLAGS) $(VOBJECTS) $LIB/rpathinit.o $LIB/rlib.a $(TERMCAP) -o $@
vreadr.o dispcntl.o artseq.o termio.o: vnews.h rparams.h
vextern.o: vextern.c rparams.h
VNEWSLINT = artseq.c dispcntl.c readnews.c vextern.c rfuncs.c\
termio.c virtterm.c vreadr.c\
$LIB/addrc.c $LIB/afopen.c $LIB/allgroups.c $LIB/bcopy.s\
$LIB/bfr.c $LIB/bzero.c $LIB/cancel.c $LIB/ckfopen.c\
$LIB/ckmalloc.c $LIB/dirname.c $LIB/findgroup.c\
$LIB/genafopen.c $LIB/gethead.c $LIB/getuser.c $LIB/gfopen.c\
$LIB/hash.c $LIB/hfgets.c $LIB/isadmin.c $LIB/lookup.c\
$LIB/makehimask.c $LIB/mypathinit.c $LIB/nextgrp.c\
$LIB/ngchain.c $LIB/ngmatch.c $LIB/nsavestr.c $LIB/nstrip.c\
$LIB/openrc.c $LIB/pgetuser.c $LIB/prefix.c $LIB/prevgrp.c\
$LIB/process.c $LIB/read.c $LIB/readinrc.c $LIB/rename.c\
$LIB/roptions.c $LIB/savestr.c $LIB/scopyn.c $LIB/setupgrp.c\
$LIB/titmat.c
vnewslint:
lint -I$LIB -DSPOOLDIR=\"$(SPOOLDIR) -DLIBDIR=\"$(LIBDIR) $(VNEWSLINT) # You must be masochistic
!
mv temp makefile
!E!O!F!
chmod +x vnews/genmakefile
cat > vnews/readnews.c <<\!E!O!F!
/*
* readnews - read news articles.
*/
/* static char *SccsId = "%W% %G%"; */
#include "rparams.h"
#include "artfile.h"
#include "ng.h"
/*
* readnews - article reading program
*/
/*
* Authors:
* Matt Glickman ucbvax!glickman
* Mark Horton cbosg!mark
* Stephen Daniels duke!swd
* Tom Truscott duke!trt
*/
main(argc, argv)
int argc;
register char **argv;
{
FILE *rcfp;
FILE *openrc();
time_t convdate() ;
/* set up defaults and initialize. */
pathinit();
#ifndef SHELL
if ((SHELL = getenv("SHELL")) == NULL)
SHELL = "/bin/sh";
#endif
getuser();
rcfp = openrc();
roptions(argv, rcfp);
if (datebuf) {
atime = convdate(datebuf) ;
free(datebuf) ;
}
/*
* ALL of the command line has now been processed. (!)
*/
if (sflag) {
printf("Subscription list: %s\n", sublist);
xxit(0);
}
afopen();
if (xflag)
readinrc((FILE *)NULL);
else {
fseek(rcfp, 0L, 0);
readinrc(rcfp);
}
fclose(rcfp);
#ifdef DEBUG
fprintf(stderr, "sublist = %s\n", sublist);
#endif
readr();
fflush(stdout);
if (xflag || lflag || tflag)
xxit(0);
writeoutrc();
xxit(0);
/* Camel, R.O.H. */
}
/*
* convert a date to UNIX internal format.
*/
time_t
convdate(s)
char *s ;
{
char buf[512] ;
FILE *datefp, *popen() ;
long cgtdate() ;
long atol() ;
sprintf(buf, "%s/cgtdate '%s'", LIB, s) ;
if ((datefp = popen(buf, "r")) == NULL || fgets(buf, 512, datefp) == NULL)
xerror("Can't convert -a date") ;
return atol(buf) ;
}
!E!O!F!
cat > vnews/rfuncs.c <<\!E!O!F!
/*
* rfuncs - functions for readnews.
*/
static char *SccsId = "@(#)rfuncs.c 2.9 3/7/83";
#include "rparams.h"
#include "newsrc.h"
#ifdef notdef
/*
* Figure out the number of the largest article in newsgroup ng,
* and return that value.
*/
long
findngsize(ng)
char *ng;
{
FILE *af;
long s;
char buf[100], n[100];
af = xfopen(ACTIVE, "r");
while (fgets(buf, sizeof buf, af)) {
sscanf(buf, "%s %ld", n, &s);
if (strcmp(n, ng) == 0) {
fclose(af);
return s;
}
}
return 0;
}
#endif
xxit(status)
int status;
{
exit(status);
}
/*
* Return true if the newsgroup was specified in the -n option.
*/
wewant(name)
char *name;
{
return ngmatch(name, sublist);
}
!E!O!F!
cat > vnews/rparams.h <<\!E!O!F!
/*
* rparams.h - parameters for readnews, rfuncs, and readr.
*/
/* static char *Rparams = "@(#)rparams.h 2.8 5/28/83"; */
#include "config.h"
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#ifdef SIGXCPU
/* 4.2BSD moved this file, grumble grumble */
#include <sys/time.h>
#else
#include <time.h>
#endif
#include "defs.h"
#include "arthead.h"
#include "libextern.h"
#include "roptions.h"
#define NEXT 0
#define SPEC 1
#define FORWARD 0
#define BACKWARD 1
/* external declarations stolen from params.h */
#ifndef SHELL
extern char *SHELL;
#endif
/* external function declarations */
extern char *strcpy(), *strncpy(), *strcat(), *index(), *rindex();
extern char *ctime(), *mktemp(), *malloc(), *realloc(), *getenv();
extern char *arpadate(), *dirname();
extern time_t time(), getdate(), cgtdate();
extern int broadcast(), save(), newssave(), ushell(), pshell(), onsig();
extern long atol();
char *savestr();
/* external declarations specific to readnews */
extern int mode;
extern time_t atime;
!E!O!F!
cat > vnews/termio.c <<\!E!O!F!
#include "vnews.h"
#if USGREL >= 30
#include <termio.h>
#include <fcntl.h>
#else
#include <sgtty.h>
#endif
#include <errno.h>
extern int errno;
static int alflag; /* set if unprocessed alarm signal */
static int intflag; /* set if interrupt received */
#ifdef SIGTSTP
static int inraw; /* true if in raw mode */
#endif
int onstop();
/*** Terminal I/O ***/
#define INBUFSIZ 8
char inbuf[INBUFSIZ]; /* input buffer */
char outbuf[BUFSIZ]; /* output buffer */
int innleft = 0; /* # of chars in input buffer */
int outnleft = BUFSIZ; /* room left in output buffer */
char *innext; /* next input character */
char *outnext = outbuf; /* next space in output buffer */
#ifndef CURSES
#if USGREL >= 30
int oflags; /* fcntl flags (for nodelay read) */
#endif
#endif
/*
* Input a character
*/
vgetc() {
register c;
#if BSDREL >= 42
int readfds, exceptfds;
#endif
recurse:
if (--innleft >= 0) {
c = *innext++;
} else {
if (alflag)
timer();
updscr(); /* update the display */
for (;;) {
if (innleft > 0 || alflag)
goto recurse;
intflag = 0;
#ifndef CURSES
#if USGREL >= 30
if (oflags & O_NDELAY) {
oflags &=~ O_NDELAY;
fcntl(0, F_SETFL, oflags);
}
#endif
#endif
#if BSDREL >= 42
/* Use a select because can be interrupted */
readfds = 1; exceptfds = 1;
innleft = select(1, &readfds, 0, &exceptfds, 0);
if (innleft > 0) {
if ((innleft = read(0, inbuf, INBUFSIZ)) > 0)
break;
}
#else
if ((innleft = read(0, inbuf, INBUFSIZ)) > 0)
break;
#endif
if (hupflag)
return INTR;
if (innleft == 0 || errno != EINTR)
abort(); /* "Can't happen" */
if (intflag) {
intflag--;
return INTR;
}
}
innext = inbuf + 1;
innleft--;
c = inbuf[0];
}
#ifdef V6
c &= 0177;
if (c == '\034') /* FS character */
onquit();
if (c == '\177') /* DEL */
onint();
#endif
if (c == '\f') {
clearok(curscr, 1);
goto recurse;
}
if (c == '\r')
c = '\n';
return c;
}
/*
* Push a character back onto the input stream.
*/
pushback(c) {
if (innext <= inbuf)
abort();
*--innext = c;
innleft++;
}
/*
* Check for terminal input
*/
checkin() {
#ifndef CURSES
#if BSDREL > 7
long count;
#endif
#endif
#ifdef STATTOP
if (innleft > 0)
#else
if (innleft > 0 || alflag)
#endif
return 1;
#if !defined(CURSES) && (USGREL >= 30 || BSDREL > 7)
if (ospeed == B9600)
return 0;
vflush();
if (ospeed <= B300)
ttyowait();
#if USGREL >= 30
if ((oflags & O_NDELAY) == 0) {
oflags |= O_NDELAY;
fcntl(0, F_SETFL, oflags);
}
if ((innleft = read(0, inbuf, INBUFSIZ)) > 0) {
innext = inbuf;
return 1;
}
#else
count = 0; /* in case FIONREAD fails */
ioctl(0, FIONREAD, &count);
if (count)
return 1;
#endif
#endif
return 0;
}
/*
* flush terminal input queue.
*/
clearin() {
#if USGREL >= 30
ioctl(0, TCFLSH, 0);
#else
#ifdef TIOCFLUSH
ioctl(0, TIOCFLUSH, 0);
#else
struct sgttyb tty;
gtty(0, &tty);
stty(0, &tty);
#endif
#endif
innleft = 0;
}
vputc(c) {
if (--outnleft < 0) {
vflush();
outnleft--;
}
*outnext++ = c;
}
/*
* Flush the output buffer
*/
vflush() {
register char *p;
register int i;
#if BSDREL <= 7 && USGREL < 30
int svalarm = alarm(0); /* signals cause UNIX to drop characters */
#endif
for (p = outbuf ; p < outnext ; p += i) {
if (hupflag)
break;
if ((i = write(1, p, outnext - p)) < 0) {
if (errno != EINTR)
abort(); /* "Can't happen" */
i = 0;
}
}
outnleft = BUFSIZ;
outnext = outbuf;
#if BSDREL <= 7 && USGREL < 30
alarm(svalarm);
#endif
}
/*** terminal modes ***/
#ifndef CURSES
#if USGREL >= 30
static struct termio oldtty, newtty;
/*
* Save tty modes
*/
ttysave() {
if (ioctl(1, TCGETA, &oldtty) < 0)
xerror("Can't get tty modes");
newtty = oldtty;
newtty.c_iflag &=~ (INLCR|IGNCR|ICRNL);
newtty.c_oflag &=~ (OPOST);
newtty.c_lflag &=~ (ICANON|ECHO|ECHOE|ECHOK|ECHONL);
newtty.c_lflag |= (NOFLSH);
newtty.c_cc[VMIN] = 1;
newtty.c_cc[VTIME] = 0;
cerase = oldtty.c_cc[VERASE];
ckill = oldtty.c_cc[VKILL];
ospeed = oldtty.c_cflag & CBAUD;
initterm();
}
/*
* Set tty modes for visual processing
*/
ttyraw() {
while (ioctl(1, TCSETAF, &newtty) < 0 && errno == EINTR);
rawterm();
}
ttyowait() { /* wait for output queue to drain */
while (ioctl(1, TCSETAW, &newtty) < 0 && errno == EINTR);
}
/*
* Restore tty modes
*/
ttycooked() {
cookedterm();
while (ioctl(1, TCSETAF, &oldtty) < 0 && errno == EINTR);
oflags &=~ O_NDELAY;
fcntl(0, F_SETFL, oflags) ;
}
#else
static struct sgttyb oldtty, newtty;
#if BSDREL >= 40 && BSDREL <= 41
static struct tchars oldtchars, newtchars;
#endif
/*
* Save tty modes
*/
ttysave() {
#ifdef SIGTSTP
/* How to get/change terminal modes in a job control environment.
This code is right from the 4.1 bsd jobs(3) manual page.
*/
#if BSDREL >= 42
int tpgrp, getpgrp();
#else
short tpgrp, getpgrp();
#endif
retry:
#if BSDREL >= 42
sigblock(1<<(SIGTSTP-1) | 1<<(SIGTTIN-1) | 1<<(SIGTTOU-1));
#else
sigset(SIGTSTP, SIG_HOLD);
sigset(SIGTTIN, SIG_HOLD);
sigset(SIGTTOU, SIG_HOLD);
#endif
if (ioctl(2, TIOCGPGRP, &tpgrp) != 0)
goto nottty;
if (tpgrp != getpgrp(0)) { /* not in foreground */
sigset(SIGTTOU, SIG_DFL);
#if BSDREL >= 42
sigsetmask(sigblock(0) & ~(1<<(SIGTTOU-1)));
#endif
kill(0, SIGTTOU);
/* job stops here waiting for SIGCONT */
goto retry;
}
sigset(SIGTTIN, onstop);
sigset(SIGTTOU, onstop);
sigset(SIGTSTP, onstop);
#if BSDREL >= 42
sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1) | 1<<(SIGTTIN-1) | 1<<(SIGTTOU-0)));
#endif
#endif
if (gtty(1, &oldtty) < 0)
nottty: xerror("Can't get tty modes");
newtty = oldtty;
newtty.sg_flags &=~ (CRMOD|ECHO|XTABS);
#if BSDREL >= 7
newtty.sg_flags |= CBREAK;
#else
newtty.sg_flags |= RAW;
#endif
cerase = oldtty.sg_erase;
ckill = oldtty.sg_kill;
ospeed = oldtty.sg_ospeed;
#if BSDREL >= 40 && BSDREL <= 41
ioctl(1, TIOCGETC, (char *)&oldtchars);
newtchars = oldtchars;
if (oldtchars.t_intrc == '\7')
newtchars.t_intrc = -1;
#endif
initterm();
}
/*
* Set tty modes for visual processing
*/
ttyraw() {
#ifdef SIGTSTP
inraw = 1;
#endif
while (stty(1, &newtty) < 0 && errno == EINTR);
#if BSDREL >= 40 && BSDREL <= 41
ioctl(1, TIOCSETC, (char *) &newtchars);
#endif
rawterm();
}
ttyowait() { /* wait for output queue to drain */
#ifdef TIOCDRAIN /* This ioctl is a local mod on linus */
ioctl(1, TIOCDRAIN, 0);
#endif
}
/*
* Restore tty modes
*/
ttycooked() {
cookedterm();
while (stty(1, &oldtty) < 0 && errno == EINTR);
#if BSDREL >= 40 && BSDREL <= 41
ioctl(1, TIOCSETC, (char *) &oldtchars);
#endif
#ifdef SIGTSTP
inraw = 0;
#endif
}
#endif
#else
#ifdef HCURSES
ttysave() {
initscr();
idlok(stdscr, 1);
intrflush(curscr, 0);
cerase = erasechar();
ckill = killchar();
}
ttyraw() {
reset_prog_mode();
cbreak();
nonl();
noecho();
}
ttycooked() {
reset_shell_mode();
}
int _endwin; /* [expletives deleted] */
#else
ttysave() {
#if USGREL >= 30
struct termio tty;
#else
struct sgttyb tty;
#endif
initscr();
#if USGREL >= 30
ioctl(0, TCGETA, &tty);
cerase = tty.c_cc[VERASE];
ckill = tty.c_cc[VKILL];
#else
gtty(0, &tty);
cerase = tty.sg_erase;
ckill = tty.sg_kill;
#endif
}
ttyraw() {
/*
* Vnews really isn't designed to work with RAW mode, so if you
* have anything approaching CBREAK mode, use it.
*/
#ifdef CBREAK
crmode();
#else
raw();
#endif
nonl();
noecho();
}
ttycooked() {
resetty();
}
#endif
#endif CURSES
/*** signal handlers ***/
onint() {
signal(SIGINT, onint);
clearin(); /* flush input queue */
#if BSDREL >= 40 && BSDREL <= 41
ioctl(0, TIOCSTI, "\7");
#else
intflag++;
#endif
}
onhup() {
signal(SIGHUP, onhup);
hupflag++;
}
onquit() {
botscreen();
vflush();
ttycooked();
#ifdef COREDUMP
abort();
#else
exit(0);
#endif
}
#ifdef SIGTSTP
onstop(signo)
int signo;
{
int restore = inraw;
int e = errno;
/* restore old terminal state */
if (restore) {
botscreen();
vflush();
ttycooked();
}
sigset(signo, SIG_DFL);
#if BSDREL >= 42
sigsetmask(sigblock(0) & ~(1<<(signo-1)));
#endif
kill(getpid(), signo); /* stop here until continued */
/* fprintf(stderr,"Vnews restarted."); */
sigset(signo, onstop);
/* restore our special terminal state */
if (restore) {
ttyraw();
#ifdef TIOCSTI
ioctl(0, TIOCSTI, "\f");
#else
clearok(curscr, 1); /* doesn't seem to work */
#endif
}
errno = e;
}
#endif
/*** alarm handler ***/
/* #include <time.h> */
/*
* Called on alarm signal.
* Simply sets flag, signal processed later.
*/
onalarm() {
alflag++;
}
/*
* Process alarm signal (or start clock)
*/
timer() {
long tod;
int hour;
int i;
struct tm *t;
struct stat statb;
long time();
static char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
static long oldmsize = 1000000L;
static int rccount = 10;
alflag = 0;
signal(SIGALRM, onalarm);
time(&tod);
t = localtime(&tod);
i = 60 - t->tm_sec;
alarm(i > 30? 30 : i); /* reset alarm */
hour = t->tm_hour % 12;
if (hour == 0) hour = 12;
sprintf(timestr, "%.3s %d %d:%02d",
months + 3 * t->tm_mon, t->tm_mday, hour, t->tm_min);
#ifdef GGRMAIL
if (mailf == NULL || stat(mailf, &statb) < 0) {
statb.st_size = 0;
}
if(statb.st_size > oldmsize) {
ismail = 1;
needbeep++;
} else if (statb.st_size < oldmsize) {
ismail = 0;
}
oldmsize = statb.st_size;
#else
ismail = 0;
if (mailf != NULL && stat(mailf, &statb) >= 0 && statb.st_size > 0L) {
ismail = 1;
if (oldmsize < statb.st_size) {
ismail = 2; /* new mail */
needbeep++;
}
} else {
statb.st_size = 0L;
}
oldmsize = statb.st_size;
#endif
if (uflag && --rccount < 0) {
writeoutrc();
if (secpr[0] == '\0')
strcpy(secpr, ".newsrc updated");
rccount = 10;
}
}
!E!O!F!
cat > vnews/vextern.c <<\!E!O!F!
/*
* rextern - external definitions for readnews
*/
/* static char *SccsId = "@(#)rextern.c 2.5 3/30/83"; */
#include "rparams.h"
time_t atime;
#ifndef SHELL
char *SHELL;
#endif
!E!O!F!
echo Part 6 of 7 extracted.
More information about the Mod.sources
mailing list