vnews bug fixes (visual.c)
chuqui at nsc.UUCP
chuqui at nsc.UUCP
Sat Jun 2 00:22:18 AEST 1984
There have been a large number of bug fixes to vnews. Rather than to try to
figure out how to diff it and things, I'm going to post my copy which has
all of the bug fixes I've seen that I found to work. This version should
run on all associated systems if the proper ifdefs are set up including 4.2
with the wonderful new signal mechanisms. This file is visual.c, the next
message will contain virtterm.c.
chuq
----- visual.c -----
/*
* readr - visual news interface.
*/
static char SccsId[] = "@(#)visual.c 2.26.1 7/12/83";
static char Author[] = "@(#)visual interface written by Kenneth Almquist";
/*
* visual.c: version 1.7 of 5/25/84
*
*/
# ifdef SCCS
static char *sccsid = "@(#)visual.c 1.7 (NSC) 5/25/84";
# endif
/*
* Changes to visual.c (W. Sebok astrovax!wls)
*
* 1) Added 'H' command to print out full header.
* 2) Interrupt character was hard-wired to Rubout. Replaced this with
* interrupt (and quit) characters obtained from terminal ioctl's.
* 3) fixed 4.1 BSD bug which would cause the interrupt character to be
* ignored anyway unless set differently than vnews is expecting. This
* bug is produced by the fact that the terminal read is *not* aborted
* by an interrupt signal in 4.1 BSD when the new signal mechanism is used.
* 4) Added handling of delete and kill characters to the entry of a number
* used as a command parameter.
* 5) Cleaned up behavior of `s' command when environment variable NEWSBOX
* is present:
* a) when %s is present in NEWSBOX string added directory creation when
* directory is not present. It also recognizes and rejects the case
* when the "directory" is present but not a directory.
* b) formerly, saving at article at ~/file would cause the article to
* saved at newsdir/groupname/~/file where "newsdir" is the news
* directory and groupname is the name of the news group. This has
* been fixed to instead save the article at $HOME/file.
* 6) Applied many of the bug fixes given on the net. This includes the bug fix
* I posted to make ^Z not hang vnews when given from the editor invoked by
* the "r" or "f" commands.
*
* 7) Fixed it for 4.2 signal package. All sigsets()'s chaned to signal.
* Added statement to clear sigmask in SIGSTP handler. Changed
* vgetc to use select since that is interrupted by a signal whereas
* read isn't (from Mark Calloe -- qubix!msc)
*
* 8) Added code from W. Sebok to access pathalias data base for return
* addresses.
*/
#ifdef NETPATHS
#include <dbm.h>
#endif NETPATHS
/* ack! dbm defines null, and causes compiler noises. This shuts it up! */
#ifdef NULL
#undef NULL
#endif NULL
#define STATTOP
#ifdef USG
#include <termio.h>
#include <fcntl.h>
#else
#include <sgtty.h>
#ifdef CBREAK /* is this BSD or V7? */
# define BSD 1
#else
# define V7 1
#endif
#endif USG
#define BSD4_2 1 /* remember to turn this off for non 4.2 sites! */
#ifdef BSD4_2
# define BIT(_a) (1<<((_a)-1))
#endif
#include <errno.h>
#include "rparams.h"
#include "dir.h"
#ifdef MYDB
#include "db.h"
#endif
#define even(cols) ((cols&1) ? cols + 1 : cols)
#define ARTWLEN (ROWS-2)/* number of lines used to display article */
#ifdef STATTOP
#define PRLINE 0 /* prompter line */
#define SPLINE 1 /* secondary prompt line */
#define ARTWIN 2 /* first line of article window */
#define SECPRLEN 81 /* length of secondary prompter */
#else
#define PRLINE (ROWS-1)/* prompter line */
#define SPLINE (ROWS-2)/* secondary prompt line */
#define ARTWIN 0 /* first line of article window */
#define SECPRLEN 100 /* length of secondary prompter */
#endif
#define PIPECHAR '|' /* indicate save command should pipe to program */
/* #define INTR 0177 /* returned by vgetc on interrupt */
#define META 0200 /* meta chatacter bit (as in emacs) */
/* print (display) flags */
#define HDRONLY 0001 /* print header only */
#define NOPRT 0002 /* don't print at all */
#define NEWART 0004 /* force article display to be regenerated */
#define HELPMSG 0010 /* display currently contains help message */
/* prun flags */
#define CWAIT 0001 /* type "continue?" and wait for return */
#define BKGRND 0002 /* run process in the background */
/* values of curflag */
#define CURP1 1 /* cursor after prompt */
#define CURP2 2 /* cursor after secondary prompt */
#define CURHOME 3 /* cursor at home position */
/* flags for vsave routine */
#define SVHEAD 01 /* write out article header */
#define OVWRITE 02 /* overwrite the file if it already exists */
/* shell procedures to reply and post followups */
#ifndef REPLYPROG
#define REPLYPROG "reply"
#endif
#ifndef FOLLOWPROG
#define FOLLOWPROG "follow"
#endif
/* other files */
#ifndef VHELP
#define VHELP "/usr/lib/news/vnews.help"
#endif
#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))
/* terminal handler stuff */
extern int _junked;
#define clearok(xxx, flag) _junked = flag
extern int COLS;
extern int ROWS;
extern int hasscroll;
extern int errno;
FILE *tmpfile();
char *getmailname();
char *findparent();
int onint(), onquit();
int onstop(), catchcont();
/*
* Kludge: space so that routines can access beyond
* the end of arrays without messing me up.
*/
static char junk[64];
/* variables shared between vnews routines */
static char linebuf[LBUFLEN]; /* temporary workspace */
static FILE *tfp; /* temporary file */
static char tfname[] = "/tmp/vnXXXXXX"; /* name of temp file */
static long artbody; /* offset of body into article */
static int quitflg; /* if set, then quit */
static int erased; /* current article has been erased */
static int artlines; /* # lines in article body */
static int artread; /* entire article has been read */
static int hdrstart; /* beginning of header */
static int hdrend; /* end of header */
static int lastlin; /* number of lines in tempfile */
static int tflinno = 0; /* next line in tempfile */
static char secpr[SECPRLEN]; /* secondary prompt */
static char prompt[30]; /* prompter */
static short prflags; /* print flags (controls updscr) */
static short curflag; /* where to locate cursor */
static int dlinno; /* top line on screen */
static char timestr[20]; /* current time */
static int ismail; /* true if user has mail */
static char *mailf; /* user's mail file */
static int alflag; /* set if unprocessed alarm signal */
static int atend; /* set if at end of article */
static char cerase; /* erase character */
static char ckill; /* kill character */
static char cintr = 0177; /* (WLS) */ /* interrupt character */
int ospeed; /* terminal speed */
static int pstatus; /* status return form process */
static int intflag; /* set if interrupt received */
#ifdef MYDB
static int hasdb; /* true if article data base exists */
#endif
#ifdef DIGPAGE
static int endsuba; /* end of sub-article in digest */
#endif
#ifdef MYDEBUG
FILE *debugf; /* file to write debugging info on */
#endif
char *tft = "/tmp/folXXXXXX";
/*
* 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 int rfq = 0; /* for last article */
static long ongsize; /* Previous ngsize */
static long pngsize; /* Printing ngsize */
static char *bptr; /* temp pointer. */
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 aabs = 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 *fp; /* current article to be printed*/
static int holdup; /* 1 iff should stop before hdr */
readr()
{
#ifdef MYDEBUG
debugf = fopen("DEBUG", "w");
setbuf(debugf, NULL);
#endif
if (aflag) {
if (*datebuf) {
if ((atime = cgtdate(datebuf)) == -1)
xerror("Cannot parse date string");
} else
atime = 0L;
}
if (sigtrap)
xxit(1);
mktemp(tfname);
if ((tfp = fopen(tfname, "w+")) == NULL)
xerror("Can't create temp file");
unlink(tfname);
mailf = getmailname();
#ifdef MYDB
if (opendb() >= 0) {
hasdb = 1;
fputs("Using article data base\n", stderr); /*DEBUG*/
getng();
}
#endif
ttysave();
signal(SIGINT, onint);
signal(SIGQUIT, onquit);
if (sigtrap)
xxit(1);
ttyraw();
timer();
/* loop reading articles. */
fp = NULL;
obit = -1;
nextng();
quitflg = 0;
while (quitflg == 0) {
if (getnextart(FALSE))
break;
strcpy(goodone, filename);
if (sigtrap)
return;
vcmd();
}
if (news)
botscreen();
ttycooked();
if (!news)
fprintf(stderr, "No news.\n");
}
/*
* Read and execute a command.
*/
vcmd() {
register c;
char *p;
int count;
int countset;
#ifdef DIGPAGE
appfile(fp, dlinno + ARTWLEN + 1);
endsuba = findend(dlinno);
if (artlines > dlinno + ARTWLEN
|| endsuba > 0 && endsuba < artlines
#else
if ((appfile(fp, dlinno + ARTWLEN + 1), artlines > dlinno + ARTWLEN)
#endif
|| (prflags & HDRONLY) && artlines > hdrend) {
atend = 0;
strcpy(prompt, "more? ");
} else {
atend = 1;
strcpy(prompt, "next? ");
if (! erased)
clear(bit); /* article read */
}
curflag = CURP1;
p = prompt + strlen(prompt);
count = 0;
countset = 0;
while ( ( (c = vgetc()) >= '0' && c <= '9') || c==cerase || c==ckill) {
if (c==cerase) {
count /= 10;
}
if (c==ckill || count==0) {
countset = 0;
count = 0;
}
if (c!=cerase && c!=ckill) {
count = (count * 10) + (c - '0');
countset = 1;
}
*p = '\0';
if (count!=0)
sprintf(p, "%d", count);
}
if (c == '\033') { /* escape */
strcat(prompt, "M-");
c = vgetc();
if (c != cintr)
c |= META;
}
secpr[0] = '\0';
if (countset == 0)
count = 1;
docmd(c, count);
if (c != '?' && c != 'H') /* UGGH */
prflags &=~ HELPMSG;
if (dlinno > hdrstart)
prflags &=~ HDRONLY;
}
/*
* Process one command, which has already been typed in.
*/
docmd(c, count)
{
int i;
char *findhist();
switch (c) {
/* Show more of current article, or advance to next article */
case '\n':
case ' ':
prflags &=~ NOPRT;
if (atend)
goto next;
else if (prflags & HDRONLY) {
prflags &=~ HDRONLY;
if (hasscroll)
dlinno = hdrstart;}
#ifdef DIGPAGE
else if (endsuba > 0)
dlinno = endsuba;
#endif
else if ((appfile(fp, dlinno + 2 * ARTWLEN), artread)
&& hasscroll && artlines - dlinno <= ARTWLEN + 2)
dlinno = artlines - ARTWLEN;
else
dlinno += ARTWLEN;
break;
/* No. Go on to next article. */
next: case 'n':
readmode = NEXT;
if (fp != NULL) { /* always false? */
fclose(fp);
fp = NULL;
}
clear(bit);
saveart;
nextbit();
break;
/* Back up count pages */
case META|'v':
case '\2': /* Control-B */
dlinno -= ARTWLEN * count;
if (dlinno < 0)
dlinno = 0;
break;
/* forward half a page */
case '\4': /* Control-D, as in vi */
dlinno += ARTWLEN/2 * count;
break;
/* backward half a page */
case '\25': /* Control-U */
dlinno -= ARTWLEN/2 * count;
if (dlinno < 0)
dlinno = 0;
break;
/* forward count lines */
case '\16': /* Control-N */
case '\32': /* Control-Z */
dlinno += count;
break;
/* backwards count lines */
case '\20': /* Control-P */
case '\31': /* Control-Y */
dlinno -= count;
if (dlinno < 0)
dlinno = 0;
break;
/* Turn displaying of article back on */
case 'l':
case 'd':
prflags &=~ NOPRT;
break;
/* display header */
case 'h':
dlinno = hdrstart;
prflags |= HDRONLY;
prflags &=~ NOPRT;
break;
/*
* Unsubscribe to the newsgroup and go on to next group
*/
case 'U':
case 'u':
strcat(prompt, "u");
c = vgetc();
if (c == 'g') {
obit = -1;
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
zapng = TRUE;
saveart;
if (nextng()) {
if (actdirect == BACKWARD)
msg("Can't back up.");
else
quitflg = 1; /* probably unnecessary */
}
} else {
if (c != cintr && c != ckill)
msg("Illegal command");
}
break;
/* Print the current version of news */
case 'v':
msg("News version: %s", news_version);
break;
/* Decrypt joke. Always does rot 13 */
case 'D':
appfile(fp, 32767);
for (i = hdrend ; i < artlines ; i++) {
register char c, *p;
tfget(linebuf, i);
for (p = linebuf ; (c = *p) != '\0' ; p++) {
if (c >= 'a' && c <= 'z')
*p = (c - 'a' + 13) % 26 + 'a';
else if (c >= 'A' && c <= 'Z')
*p = (c - 'A' + 13) % 26 + 'A';
}
tfput(linebuf, i);
}
prflags |= NEWART;
prflags &=~ (HDRONLY|NOPRT);
break;
/* write out the article someplace */
/* w writes out without the header */
case 's':
case 'w': {
char *grn = groupdir;
int wflags;
msg("file: ");
curflag = CURP2;
while ((wflags = vgetc()) == ' ');
if (wflags == cintr) {
secpr[0] = '\0';
break;
}
if (wflags == '|') {
linebuf[0] = '|';
if (prget("| ", linebuf+1))
break;
} else {
pushback(wflags);
if (prget("file: ", linebuf))
break;
}
wflags = 0;
if (c == 's')
wflags |= SVHEAD;
if (count != 1)
wflags |= OVWRITE;
bptr = linebuf;
if (*bptr != PIPECHAR && *bptr != '/') {
char hetyped[BUFLEN];
char *boxptr;
struct stat stbf;
strcpy(hetyped, bptr);
if (hetyped[0] == '~' && hetyped[1] == '/') {
strcpy(hetyped, bptr+2);
strcpy(bptr, userhome);
} else {
if (boxptr = getenv("NEWSBOX")) {
if (index(boxptr, '%')) {
sprintf(bptr, boxptr, grn);
if (stat(bptr,&stbf)<0) {
int status, pid;
if ((pid=fork())<=0) {
setuid(getuid());
setgid(getgid());
close(1); close(2);
open("/dev/null",2); dup(1);
execl("/bin/mkdir","mkdir",
bptr,0);
exit(127);
}
while ( wait(&status) != pid);
if (status != 0) {
msg("Cannot create directory %s",bptr);
break;
}
} else {
if ((stbf.st_mode&S_IFMT)
!= S_IFDIR ) {
msg("%s not a directory",bptr);
break;
}
}
} else {
strcpy(bptr, boxptr);
}
} else {
bptr[0] = '\0';
}
}
if (bptr[0])
strcat(bptr, "/");
if (hetyped[0] != '\0')
strcat(bptr, hetyped);
else
strcat(bptr, "Articles");
}
vsave(bptr, wflags);
break;
}
/* back up */
case '-':
case 'b':
minus:
aabs = TRUE;
if (!*ofilename1) {
msg("Can't back up.");
break;
}
if (fp != NULL) { /* always true? */
fclose(fp);
fp = NULL;
}
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 (count == 0)
break;
saveart;
last = bit;
for (i = 0; i < count; i++) {
nextbit();
if ((bit > pngsize) || (rflag && bit < 1))
break;
}
if (fp != NULL) { /* always true? */
fclose(fp);
fp = NULL;
}
obit = -1;
break;
/* exit - time updated to that of most recently read article */
case 'q':
quitflg = 1;
break;
/* cancel the article. */
case 'c':
strcpy(prompt, "cancel [n]? ");
if (vgetc() != 'y') {
msg("article not cancelled");
break;
}
cancel_command();
break;
/* escape to shell */
case '!': {
register char *p;
int flags;
p = linebuf;
if (prget("!", p))
break;
flags = CWAIT;
if (*p == '\0') {
strcpy(linebuf, SHELL);
flags = 0;
}
while (*p) p++;
while (p > linebuf && p[-1] == ' ')
p--;
if (*--p == '&') {
*p = '\0';
flags = BKGRND;
} else if (*p == '|') {
*p = '\0';
sprintf(bfr, "(%s)|mail '%s'", linebuf, username);
strcpy(linebuf, bfr);
flags |= BKGRND;
} else {
prflags |= NOPRT;
}
shcmd(linebuf, flags);
break;
}
/* mail reply */
case 'r':
reply(0);
break;
/* punt rest of newsgroup */
case 'K':
saveart;
while (bit <= ngsize && bit > 0) {
clear(bit);
nextbit();
}
break;
/* next newsgroup */
case 'N':
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
if (next_ng_command())
quitflg = 1;
break;
/* sepecific number */
case 'A':
if (count > pngsize) {
msg("not that many articles");
break;
}
readmode = SPEC;
aabs = TRUE;
bit = count;
obit = -1;
if (fp) {
fclose(fp);
fp = NULL;
}
break;
/* display parent article */
case 'p':
#ifdef MYDB
if (hasdb && (ptr3 = findparent(h.ident, &i)) != NULL) {
msg("parent: %s/%d", ptr3, i); /*DEBUG*/
updscr(); /*DEBUG*/
goto selectart;
}
#endif
if (h.followid[0] == '\0') {
msg("no references line");
break;
}
if ((ptr1 = rindex(h.followid, ' ')) != NULL)
ptr1++;
else
ptr1 = h.followid;
strcpy(linebuf, ptr1);
msg("%s", linebuf);
curflag = CURP2;
updscr(); /* may take this out later */
goto searchid;
/* specific message ID. */
case '<':
/* could improve this */
linebuf[0] = '<';
if (prget("<", linebuf+1))
break;
searchid: secpr[0] = '\0';
if (index(linebuf, '@') == NULL && index(linebuf, '>') == NULL) {
ptr1 = linebuf;
if (*ptr1 == '<')
ptr1++;
ptr2 = index(ptr1, '.');
if (ptr2 != NULL) {
*ptr2++ = '\0';
sprintf(bfr, "<%s@%s.UUCP>", ptr2, ptr1);
strcpy(linebuf, bfr);
}
}
if (index(linebuf, '>') == NULL)
strcat(linebuf, ">");
ptr1 = findhist(linebuf);
if (ptr1 == NULL) {
msg("%s not found", linebuf);
break;
}
ptr2 = index(ptr1, '\t');
ptr3 = index(++ptr2, '\t');
ptr2 = index(++ptr3, ' ');
if (ptr2)
*ptr2 = '\0';
ptr2 = index(ptr3, '/');
*ptr2++ = '\0';
sscanf(ptr2, "%d", &i);
/*
* Go to a given article. Ptr3 specifies the newsgroup
* and i specifies the article number.
*/
selectart: aabs = TRUE;
if (fp != NULL) { /* always true */
fclose(fp);
fp = NULL;
}
hbufcp(&hbuf1, &h);
saveart;
strcpy(ogroupdir, ptr3);
if (strcmp(groupdir, ogroupdir)) {
strcpy(bfr, groupdir);
selectng(ogroupdir);
strcpy(groupdir, ogroupdir);
strcpy(ogroupdir, bfr);
back();
}
bit = i;
oobit = obit;
obit = -1;
getnextart(TRUE);
rfq = 0;
break;
/* follow-up article */
case 'f':
reply(1);
break;
/* erase - pretend we haven't seen this article. */
case 'e':
erased = 1;
set(bit);
goto caseplus; /* skip this article for now */
break;
case '#':
msg("Article %d of %ld",
rfq ? oobit : bit, pngsize);
break;
/* error */
case '?':
{
FILE *helpf;
if ((helpf = fopen(VHELP, "r")) == NULL) {
msg("Can't open help file");
break;
}
move(ARTWIN, 0);
while (fgets(linebuf, 1000, helpf) != NULL)
addstr(linebuf);
fclose(helpf);
prflags |= HELPMSG|NEWART;
}
break;
case 'H':
{
long oldpos, ftell();
if (fp == NULL) {
msg("Bad FP");
break;
}
move(ARTWIN, 0);
oldpos = ftell(fp);
fseek(fp,0l,0);
for (i=0; i<ARTWLEN ; i++) {
if (fgets(linebuf, COLS, fp) == NULL) break;
if (linebuf[0] == '\n') break;
linebuf[COLS] = '\0';
addstr(linebuf);
}
for (; i<ARTWLEN ; i++) {
addstr("\n");
}
fseek(fp,oldpos,0);
prflags |= HELPMSG|NEWART;
}
break;
default:
if (c != ckill && c != cintr)
msg("Illegal command");
break;
}
return FALSE;
}
cancel_command()
{
tfilename = filename;
hptr = &h;
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) {
msg("Can't cancel what you didn't write.");
return;
}
if (!cancel(stderr, hptr, i) && hptr == &h) {
clear(bit);
saveart;
nextbit();
obit = -1;
/* fix suggested by watcgl!dmmartindale */
if (fp != NULL)
fclose(fp);
fp = NULL;
/* end fix */
}
}
/*
* Generate replies and followups.
* We generate a file and then call a shell procedure to do the work.
*/
#define MODGROUPS "fa.all,mod.all,all.mod,all.announce,"
reply(followup) {
char *arg[8];
FILE *tfp;
char subj[132];
char frprog[64];
char *p;
char *replyname();
#ifdef NETPATHS
/* Stuff for finding paths in data base */
static int dbmopen = 0;
static char newspaths[] = NETPATHS;
datum key, result;
register char *p1, *p2;
char sitename[100];
/* end of stuff for finding paths in data base */
#endif NETPATHS
strcpy(tf, tft);
mktemp(tf);
if ((tfp = fopen(tf, "w")) == NULL) {
msg("Can't create %s", tf) ;
return;
}
strcpy(subj, h.title);
if (!prefix(subj, "Re:") && !prefix(subj, "re:")) {
strcpy(bfr, subj);
sprintf(subj, "Re: %s", bfr);
}
arg[0] = "/bin/sh";
/* test for moderated group */
if (followup) {
strcpy(linebuf, h.nbuf);
ngcat(linebuf);
if (ngmatch(linebuf, MODGROUPS))
followup = 2;
}
if (followup != 1) { /* send mail */
#ifdef INTERNET
if (followup == 2 && h.sender[0])
p = h.sender;
else
#endif
p = replyname(&h);
#ifdef NETPATHS
/* Use data base to find a return path to a site */
/* W. Sebok, 11/13/83 */
if (Oflag && dbmopen == 0)
dbmopen = (dbminit(newspaths)==0) ? 1 : -1 ;
if (dbmopen > 0) {
for (p1=p; (p2 = index(p1,'!'))!= NULL; p1 = p2+1);
if (p!= p1) {
key.dptr = sitename;
p1--;
do {
for (p2 = p1 ; (p1 != p) && (*--p1!='!'); );
key.dsize = p2 - p1;
strncpy(sitename,p1+1, key.dsize);
sitename[key.dsize-1] = '\0';
result = fetch(key);
} while ( (p1 != p) && result.dptr == NULL);
}
}
if (dbmopen > 0 && result.dptr != NULL) {
fprintf(tfp,"To: ");
fprintf(tfp,result.dptr,p2+1);
fprintf(tfp,"\nSubject: %s\n",subj);
if (followup != 2)
fprintf(tfp,"In-reply-to: your article %s\n",h.ident);
} else
#endif NETPATHS
{
fprintf(tfp, "To: %s\n", p);
fprintf(tfp, "Subject: %s\n", subj);
if (followup != 2)
fprintf(tfp, "In-reply-to: your article %s\n", h.ident);
}
/* end of stuff for finding return paths in data base */
sprintf(frprog,"%s/%s",LIB,REPLYPROG);
arg[1] = frprog;;
arg[4] = p;
} else {
p = h.nbuf;
if (h.followto[0])
p = h.followto;
strcpy(linebuf, p);
launder(linebuf);
fprintf(tfp, "Newsgroups: %s\n", linebuf);
fprintf(tfp, "Subject: %s\n", subj);
if (h.keywords[0])
fprintf(tfp, "Keywords: %s\n", h.keywords);
if (h.distribution[0])
fprintf(tfp, "Distribution: %s\n", h.distribution);
sprintf(frprog,"%s/%s",LIB,FOLLOWPROG);
arg[1] = frprog;
arg[4] = linebuf;
}
if (followup != 0) {
bfr[0] = 0; /* References */
if (h.followid[0]) {
strcpy(bfr, h.followid);
strcat(bfr, " ");
}
strcat(bfr, h.ident);
fprintf(tfp, "References: %s\n", bfr);
}
putc('\n', tfp);
fclose(tfp);
arg[2] = tf;
arg[3] = filename;
/* arg[4] (name or newsgroup) set above */
arg[5] = NULL;
prun(arg, 0);
if (pstatus != 0) {
if (pstatus != 22 << 8)
p = "Command failed";
else if (followup == 1)
p = "Article not posted";
else
p = "Mail not sent";
msg(p);
}
prflags |= NOPRT;
}
next_ng_command()
{
if (prget("group? ", linebuf))
return FALSE;
bptr = linebuf;
if (!*bptr || *bptr == '-') {
obit = -1;
if (*bptr)
actdirect = BACKWARD;
saveart;
if (nextng()) {
if (actdirect == BACKWARD)
msg("Can't back up.");
else
return TRUE;
}
return FALSE;
}
while (isspace(*bptr))
bptr++;
if (!validng(bptr)) {
msg("No such group.");
return FALSE;
}
obit = -1;
/* readmode = SPEC; tekgds!charliep thinks this is a bug */
saveart;
back();
selectng(bptr);
return FALSE;
}
/*
* Find the next article we want to consider, if we're done with
* the last one, and show the header.
*/
getnextart(minus)
int minus;
{
int noaccess;
register DIR *dirp;
register struct direct *dir;
long nextnum, tnum;
long atol();
noaccess = 0;
if (minus)
goto nextart2; /* Kludge for "-" command. */
if (bit == obit) /* Return if still on same article as last time */
return 0;
nextart:
if (news) {
curflag = CURHOME;
_amove(0, 0);
vflush();
}
dgest = 0;
/* If done with this newsgroup, find the next one. */
while ((!rflag && (long) bit > ngsize) || (rflag && bit < 1)) {
/* tekgds!charliep thinks these two lines are in error
while (((long) bit > ngsize) || (rflag && bit < 1)) {
int i;
*/
if (i=nextng()) {
if (actdirect == BACKWARD) {
msg("Can't back up.");
actdirect = FORWARD;
continue;
}
else /* if (rfq++ || pflag || cflag) */
return 1;
}
if (rflag)
bit = ngsize + 1L;
else
bit = -1;
noaccess = 2;
}
/* speed things up by not searching for article -1 */
if (bit < 0) {
bit = 0;
nextbit();
aabs = FALSE;
goto nextart;
}
nextart2:
if (rcreadok)
rcreadok = 2; /* have seen >= 1 article */
sprintf(filename, "%s/%d", dirname(groupdir), bit);
if (rfq && goodone[0]) /* ??? */
strcpy(filename, goodone);
if (sigtrap == SIGHUP)
return 1;
/* Decide if we want to show this article. */
if ((fp = fopen(filename, "r")) == NULL) {
/* 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;
dirp = opendir(dirname(groupdir));
if (dirp == NULL) {
msg("Can't open %s", dirname(groupdir));
noaccess = 0;
goto badart;
}
nextnum = rflag ? 0 : ngsize + 1;
while ((dir = readdir(dirp)) != NULL) {
if (!dir->d_ino)
continue;
tnum = atol(dir->d_name);
if (tnum <= 0)
continue;
if (rflag ? (tnum > nextnum && tnum < bit)
: (tnum < nextnum && tnum > bit))
nextnum = tnum;
}
closedir(dirp);
if (rflag ? (nextnum >= bit) : (nextnum <= bit))
goto badart;
do {
clear(bit);
nextbit();
} while (rflag ? (nextnum < bit) : (nextnum > bit));
obit = -1;
aabs = FALSE;
goto nextart;
} else
noaccess = 0;
if (hread(&h, fp, TRUE) == NULL
|| (!rfq && !vselect(&h, aabs))) {
badart:
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
clear(bit);
obit = -1;
nextbit();
aabs = FALSE;
goto nextart;
}
aabs = FALSE;
actdirect = FORWARD;
news = TRUE;
{ /* strip off any notesfile header */
register c;
register char *p = h.title + strlen(h.title) - 5;
if (p > 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;
prflags |= NEWART;
prflags &=~ NOPRT;
if (! cflag && hdrend < ARTWLEN && !cflag)
prflags |= HDRONLY;
dlinno = 0;
erased = 0;
obit = bit;
return 0;
}
/*
* Print out whatever the appropriate header is
*/
hdr() { abort(); }
fmthdr() {
char *vbriefdate();
lastlin = 0;
if (ngrp) {
pngsize = ngsize;
ngrp--;
if (!hflag) {
sprintf(linebuf, "Newsgroup %s", groupdir); tfappend(linebuf);
tfappend("");
}
}
hdrstart = lastlin;
if (!hflag) {
sprintf(linebuf, "Article %s %s",
h.ident, vbriefdate(h.subdate));
tfappend(linebuf);
}
vhprint(&h, pflag ? 1 : 0);
sprintf(linebuf, "(%d lines)", NLINES(h, fp)); tfappend(linebuf);
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)
register char *q;
{
register char *p;
register i;
char day[2];
p = bfr;
for (i = 3 ; --i >= 0 ; )
*p++ = *q++;
*p++ = ' ';
q += 2;
day[0] = *q++;
if (*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 bfr;
}
/*
* Print the file header to the temp file.
*/
vhprint(hp, verbose)
register struct hbuf *hp;
int verbose;
{
register char *p1, *p2;
int i;
char fname[BUFLEN];
char *tailpath();
fname[0] = '\0'; /* init name holder */
p1 = index(hp->from, '('); /* Find the sender's full name. */
if (p1 == NULL && hp->path[0])
p1 = index(hp->path, '(');
if (p1 != NULL) {
strcpy(fname, p1+1);
p2 = index(fname, ')');
if (p2 != NULL)
*p2 = '\0';
}
sprintf(linebuf, "Subject: %s", hp->title);
if ((i = strlen(linebuf) - 7) > 9
&& strcmp(linebuf + i, " - (nf)") == 0
&& (strncmp(linebuf+9, "Re: ", 4) != 0 || i < 9+39))
linebuf[i] = '\0'; /* clobber "- (nf)" */
tfappend(linebuf);
if (!hflag && hp->keywords[0])
sprintf(linebuf, "Keywords: %s", hp->keywords), tfappend(linebuf);
if (verbose) {
sprintf(linebuf, "From: %s", hp->from); tfappend(linebuf);
sprintf(linebuf, "Path: %s", hp->path); tfappend(linebuf);
if (hp->organization[0])
sprintf(linebuf, "Organization: %s", hp->organization), tfappend(linebuf);
}
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(linebuf, "From: %s", hp->from);
#else
sprintf(linebuf, "Path: %s", tailpath(hp));
#endif
if (fname[0] != '\0') {
strcat(linebuf, " (");
strcat(linebuf, fname);
if (hp->organization[0] && !hflag) {
strcat(linebuf, " @ ");
strcat(linebuf, hp->organization);
}
strcat(linebuf, ")");
}
tfappend(linebuf);
if (p1 != NULL)
*p1 = ' ';
if (hp->ctlmsg[0]) {
sprintf(linebuf, "Control: %s", hp->ctlmsg);
tfappend(linebuf);
}
}
ngdel(strcpy(bfr, hp->nbuf));
if (verbose) {
sprintf(linebuf, "Newsgroups: %s", bfr); tfappend(linebuf);
sprintf(linebuf, "Date: %s", hp->subdate); tfappend(linebuf);
if (hp->sender[0])
sprintf(linebuf, "Sender: %s", hp->sender), tfappend(linebuf);
if (hp->replyto[0])
sprintf(linebuf, "Reply-To: %s", hp->replyto), tfappend(linebuf);
if (hp->followto[0])
sprintf(linebuf, "Followup-To: %s", hp->followto), tfappend(linebuf);
}
else if (strcmp(bfr, groupdir) != 0)
sprintf(linebuf, "Newsgroups: %s", bfr), tfappend(linebuf);
}
#ifdef MYDB
char *
findparent(id, num)
char *id;
int (*num);
{
struct artrec a;
char *ngname();
if (lookart(id, &a) == DNULL)
return NULL;
if (a.parent == DNULL)
return NULL;
readrec(a.parent, &a);
(*num) = a.groups[0].artno;
return ngname(a.groups[0].newsgroup);
}
#endif
/*
* 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; /* &linebuf[0] <= icol <= maxcol */
if (artread || artlines >= nlines)
return;
maxcol = linebuf;
icol = linebuf;
while ((c = getc(iop)) != EOF) {
switch (c) {
case ' ':
if (icol == maxcol && icol < linebuf + LBUFLEN - 1) {
*icol++ = ' ';
maxcol = icol;
} else {
icol++;
}
break;
case '\t':
icol = (icol - linebuf &~ 07) + 8 + linebuf;
growline(icol);
break;
case '\b':
if (icol > linebuf) --icol;
break;
case '\n':
outline();
if (artlines >= nlines)
return;
icol = linebuf;
break;
case '\r':
icol = linebuf;
break;
case '\f':
outline(); outline(); outline();
if (artlines >= nlines)
return;
icol = linebuf;
break;
default:
if (c < ' ' || c > '~')
break;
else if (icol >= linebuf + 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 != linebuf) /* file not terminated with newline */
outline();
artread++;
}
growline(col)
char *col;
{
while (maxcol < col && maxcol < linebuf + LBUFLEN - 1)
*maxcol++ = ' ';
}
outline() {
*maxcol = '\0';
if (strncmp(linebuf, ">From ", 6) == 0) {
register char *p;
for (p = linebuf ; (*p = p[1]) != '\0' ; p++);
}
tfappend(linebuf);
if (maxcol > linebuf)
artlines = lastlin;
maxcol = linebuf;
}
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 == cintr) {
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 {
*r++ = c;
}
lastc = c;
}
curflag = CURHOME;
secpr[0] = '\0';
return (c == cintr);
}
/*
* Execute a shell command.
*/
shcmd(cmd, flags)
char *cmd;
{
char *arg[4];
arg[0] = SHELL, arg[1] = "-c", arg[2] = cmd, arg[3] = NULL;
prun(arg, flags);
}
prun(args, flags)
char **args;
{
int pid;
int i;
int (*savequit)();
char *env[100], **envp;
char a[BUFLEN + 2];
extern char **environ;
#ifdef SIGTSTP/* ^Z bug fix Sept 17,1983 W.Sebok */
signal(SIGTSTP, SIG_DFL);
signal(SIGTTIN, SIG_DFL);
signal(SIGTTOU, SIG_DFL);
#endif
if (!(flags & BKGRND)) {
botscreen();
ttycooked();
}
while ((pid = fork()) == -1)
sleep(1); /* must not clear alarm */
if (pid == 0) {
for (i = 3 ; i < 20 ; i++)
close(i);
if (flags & BKGRND) {
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
close(0), close(1), close(2);
open("/dev/null", 2);
dup(0), dup(0);
}
/* set $A */
sprintf(a, "A=%s", filename);
env[0] = a;
for (envp = env + 1 ; *environ != NULL && envp < env + 98 ; environ++)
if ((*environ)[0] != 'A' || (*environ)[1] != '=')
*envp++ = *environ;
*envp = NULL;
umask(savmask);
execve(args[0], args, env);
fprintf(stderr, "%s: not found\n", args[0]);
exit(20);
}
if (!(flags & BKGRND)) {
savequit = signal(SIGQUIT, SIG_IGN);
while ((i = wait(&pstatus)) != pid && (i != -1 || errno == EINTR));
if (flags & CWAIT) {
fprintf(stderr, "continue? ");
while ((errno = 0, i = getchar()) != '\n'
&& (i != EOF || errno == EINTR));
}
signal(SIGQUIT, savequit);
ttyraw();
clearok(curscr, 1);
#ifdef SIGTSTP/* ^Z bug fix Sept 17,1983 W.Sebok */
signal(SIGTSTP, onstop);
signal(SIGTTIN, onstop);
signal(SIGTTOU, onstop);
#endif
}
}
#ifdef DIGPAGE
/*
* Find end of current subarticle in digest.
*/
findend(l) {
register i;
register char *p;
for (i = l ; i < l + ARTWLEN && i < lastlin ; i++) {
tfget(linebuf, i);
for (p = linebuf ; *p == '-' ; p++);
if (p > linebuf + 24)
return i + 1;
}
return 0;
}
#endif
/*** 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, i = even(COLS);
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);
fread(line, even(COLS), 1, tfp);
line[COLS] = '\0';
tflinno++;
}
tfseek(linno, wrflag) {
static int last = 1;
if (linno != tflinno || wrflag != last) {
fseek(tfp, (long)linno * even(COLS), 0);
tflinno = linno;
last = wrflag;
}
}
msg(s, a1, a2, a3, a4) char *s; {
sprintf(secpr, s, a1, a2, a3, a4);
}
/*
* Update the display.
* The display is entirely controlled by this routine,
* which means that this routine may get pretty snarled.
*/
static int savelinno = -1; /* dlinno on last call to updscr */
static int savepr; /* prflags on last call */
updscr() {
int count;
int i;
if (checkin())
return;
if ((prflags & HELPMSG) == 0
&& (dlinno != savelinno || savepr != prflags)
&& quitflg == 0) {
if (dlinno != savelinno)
prflags &=~ NOPRT;
count = ARTWLEN;
if (prflags & NOPRT)
count = 0;
if ((prflags & HDRONLY) && count > hdrend)
count = hdrend - dlinno;
#ifdef DIGPAGE
if (endsuba > 0 && count > endsuba - dlinno)
count = endsuba - dlinno;
#endif
if ((prflags & NEWART) == 0)
ushift(ARTWIN, ARTWIN+ARTWLEN-1, dlinno - savelinno);
if (count > lastlin - dlinno)
count = lastlin - dlinno;
for (i = ARTWIN ; i < ARTWIN + ARTWLEN ; i++)
clrline(i);
for (i = 0 ; i < count ; i++) {
tfget(linebuf, dlinno + i);
mvaddstr(ARTWIN + i, 0, linebuf);
}
prflags &=~ NEWART;
savepr = prflags;
savelinno = dlinno;
}
clrline(SPLINE), clrline(PRLINE);
#ifdef STATTOP
mvaddstr(PRLINE, 0, prompt);
#else
if (strlen(secpr) <= COLS)
mvaddstr(PRLINE, 0, prompt);
#endif
mvaddstr(PRLINE, 48, timestr);
mvaddstr(PRLINE, 20, groupdir);
addch(' '); addnum(bit); addch('/'); addnum((int)pngsize); addch(' ');
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');
}
/*** 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, *localtime();
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;
beep();
} 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 */
beep();
}
} else {
statb.st_size = 0L;
}
oldmsize = statb.st_size;
#endif
if (uflag && !xflag && --rccount < 0) {
writeoutrc();
if (secpr[0] == '\0')
strcpy(secpr, ".newsrc updated");
rccount = 10;
}
}
char *
getmailname() {
static char mailname[32];
register char *p;
if( (p = getenv("MAIL")) != NULL)
return p;
if (username[0] == '\0' || strlen(username) > 15)
return NULL;
#ifdef BSD
sprintf(mailname, "/usr/spool/mail/%s", username);
#else
sprintf(mailname, "/usr/mail/%s", username);
#endif
return mailname;
}
/*** 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 */
#ifdef USG
int oflags; /* fcntl flags (for nodelay read) */
#endif
/*
* Input a character
*/
vgetc() {
register c;
#ifdef BSD4_2
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;
#ifdef USG
if (oflags & O_NDELAY) {
oflags &=~ O_NDELAY;
fcntl(0, F_SETFL, oflags);
}
#endif
#ifdef BSD4_2
/* use a read because it can be interrupted */
readfds = 1; exceptfds = 1;
select(1,&readfds,0,&exceptfds,0);
if (readfds & 1) { /* got a key, go ahead and get it */
innleft = read(0,inbuf,INBUFSIZ);
#else
if ((innleft = read(0, inbuf, INBUFSIZ)) > 0) {
#endif
#ifdef BSD
if (intflag) {
intflag--;
inbuf[0] = cintr;
clearin(); /* flush input queue */
return cintr;
}
#endif
break;
}
if (innleft == 0) {
quitflg++;
return cintr;
}
if (errno != EINTR)
abort(); /* "Can't happen" */
if (intflag) {
intflag--;
return cintr;
}
}
innext = inbuf + 1;
innleft--;
c = inbuf[0];
}
#ifdef V7
c &= 0177;
if (c == '\034') /* FS character */
onquit();
#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() {
#ifdef BSD
long count;
#endif
#ifdef STATTOP
if (innleft > 0)
#else
if (innleft > 0 || alflag)
#endif
return 1;
#if !0 && !defined(V7)
if (ospeed == B9600)
return 0;
vflush();
if (ospeed <= B300)
ttyowait();
#ifdef USG
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() {
#ifdef USG
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;
for (p = outbuf ; p < outnext ; p += i) {
if ((i = write(1, p, outnext - p)) < 0) {
if (errno != EINTR)
abort(); /* "Can't happen" */
i = 0;
}
}
outnleft = BUFSIZ;
outnext = outbuf;
}
/*** terminal modes ***/
#ifdef USG
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];
cintr = oldtty.c_cc[VINTR]; /* (WLS) */
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;
#ifdef TIOCGETC
static struct tchars tchars;
#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.
*/
short tpgrp, getpgrp();
retry:
#ifdef BSD4_2
sigblock(BIT(SIGTSTP)|BIT(SIGTTIN)|BIT(SIGTTOU));
#else
signal(SIGTSTP, SIG_HOLD);
signal(SIGTTIN, SIG_HOLD);
signal(SIGTTOU, SIG_HOLD);
#endif
if (ioctl(2, TIOCGPGRP, &tpgrp) != 0)
goto nottty;
if (tpgrp != getpgrp(0)) { /* not in foreground */
signal(SIGTTOU, SIG_DFL);
#ifdef BSD4_2
sigsetmask(sigblock(0) & ~BIT(SIGTTOU));
#endif
kill(0, SIGTTOU);
/* job stops here waiting for SIGCONT */
goto retry;
}
signal(SIGTTIN, onstop);
signal(SIGTTOU, onstop);
signal(SIGTSTP, onstop);
#ifdef BSD4_2
sigsetmask(sigblock(0) & ~(BIT(SIGTSTP)|BIT(SIGTTIN)|BIT(SIGTTOU)));
#endif BSD4_2
#endif SIGTSTP
if (gtty(1, &oldtty) < 0)
nottty: xerror("Can't get tty modes");
newtty = oldtty;
newtty.sg_flags &=~ (CRMOD|ECHO|XTABS);
#ifdef BSD
newtty.sg_flags |= CBREAK;
#else
newtty.sg_flags |= RAW;
#endif
#ifdef TIOCGETC
if (ioctl(1,TIOCGETC,&tchars)<0)
xerror("Can't get special tty characters");
cintr = tchars.t_intrc;
#endif
cerase = oldtty.sg_erase;
ckill = oldtty.sg_kill;
ospeed = oldtty.sg_ospeed;
initterm();
}
/*
* Set tty modes for visual processing
*/
ttyraw() {
while (stty(1, &newtty) < 0 && errno == EINTR);
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);
}
#endif
/*** signal handlers ***/
onint() {
if (!news) {
ttycooked();
xxit(1);
}
signal(SIGINT, onint);
clearin(); /* flush input queue */
intflag++;
#ifdef BSD
ioctl(0,TIOCSTI,"\0");
#endif
}
onquit() {
botscreen();
vflush();
ttycooked();
#ifdef COREDUMP
abort();
#else
exit(0);
#endif
}
#ifdef SIGTSTP
onstop(signo)
int signo;
{
/* restore old terminal state */
botscreen();
vflush();
ttycooked();
signal(signo, SIG_DFL);
#ifdef BSD4_2
/* clear SIGSTP mask bit */
sigsetmask(sigblock(0) & ~BIT(signo));
#endif
kill(getpid(), signo); /* stop here until continued */
fprintf(stderr,"Vnews restarted.");
signal(signo, onstop);
/* restore our special terminal state */
ttyraw();
clearok(curscr, 1);
}
#endif
/*** stolen from rfuncs2.c and modified ***/
vsave(to, flags)
register char *to;
{
register FILE *ufp;
int isprogram = 0;
int isnew = 1;
long saveoff;
char temp[20];
char *fname;
char prog[BUFLEN + 24];
int (*svpipe)();
#define hh h
#define hfp fp
saveoff = ftell(fp);
fseek(fp, artbody, 0);
fname = to;
if (*to == PIPECHAR) {
if (strlen(to) > BUFLEN) {
msg("Command name too long");
goto out;
}
flags |= OVWRITE;
strcpy(temp, "/tmp/vnXXXXXX");
mktemp(temp);
fname = temp;
_amove(ROWS - 1, 0);
vflush();
}
if ((flags & OVWRITE) == 0) {
ufp = fopen(fname, "r");
if (ufp != NULL) {
fclose(ufp);
isnew = 0;
}
}
umask(savmask);
if (*to == PIPECHAR)
isprogram++;
if ((ufp = fopen(fname, (flags & OVWRITE) == 0? "a" : "w")) == NULL) {
msg("Cannot open %s", fname);
goto out;
}
/*
* V7MAIL code is here to conform to V7 mail format.
* If you need a different format to be able to
* use your local mail command (such as four ^A's
* on the end of articles) substitute it here.
*/
if (flags & SVHEAD) {
#ifdef V7MAIL
hh.subtime = cgtdate(hh.subdate);
fprintf(ufp, "From %s %s",
#ifdef INTERNET
hh.from,
#else
hh.path,
#endif
ctime(&hh.subtime));
#endif
hprint(&hh, ufp, 2);
#ifdef V7MAIL
tprint(hfp, ufp, TRUE);
putc('\n', ufp); /* force blank line at end (ugh) */
#else
tprint(hfp, ufp, FALSE);
#endif
} else {
tprint(hfp, ufp, FALSE);
}
fclose(ufp);
if (isprogram) {
sprintf(prog, "(%s)<%s", to + 1, fname);
shcmd(prog, CWAIT);
prflags |= NOPRT;
} else {
if ((flags & OVWRITE) == 0)
msg("file: %s %s", to, isnew ? "created" : "appended");
else
msg("file: %s written", to);
}
out:
if (isprogram) {
unlink(fname);
}
umask(N_UMASK);
fseek(fp, saveoff, 0);
}
/*** stolen from rfuncs.c ***/
/*
* Return TRUE if the user has not ruled out this article.
*/
vselect(hp, insist)
register struct hbuf *hp;
int insist;
{
if (insist)
return TRUE;
if (tflag && !titmat(hp, header.title))
return FALSE;
if (aflag && cgtdate(hp->recdate) < atime)
return FALSE;
if (index(hp->nbuf, ',') && !rightgroup(hp))
return FALSE;
if (fflag && isfol(hp))
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(hp)
struct hbuf *hp;
{
char ng[BUFLEN];
char temp[BUFLEN]; /* genrad!john (WLS) */
register char *p, *g;
int i, flag;
strcpy(ng, hp->nbuf);
ngcat(ng);
g = ng;
flag = 1;
while ((p = index(g, ',')) != NULL) {
*p++ = '\0';
while (*p == ' ')
p++;
if (strcmp(g, groupdir) == 0) {
return flag;
}
/* this hack is required because ngmatch expects trailing ','*/
strcpy(temp, g); /* genrad!john (WLS) */
strcat(temp, ","); /* genrad!john (WLS) */
if (ngmatch(temp, header.nbuf) /* genrad!john (WLS) */
&& ((i = findrcline(g)) < 0 || index(rcline[i], '!') == NULL)) {
flag = 0;
}
g = p;
}
/* we must be in "junk" or "control" */
return 1;
}
--
>From the closet of anxieties of: Chuq Von Rospach
{amd70,fortune,hplabs,ihnp4}!nsc!chuqui (408) 733-2600 x242
I'm sure I have my death ray in here somewhere...
More information about the Comp.sources.unix
mailing list