rick@seismo.UUCP (Rick Adams) (09/10/84)
if test ! -d src then mkdir src echo mkdir src fi echo x - src/rfuncs.c sed 's/^X//' >src/rfuncs.c <<'*-*-END-of-src/rfuncs.c-*-*' X/* X * rfuncs - functions for readnews. X */ X X#ifndef lint Xstatic char *SccsId = "@(#)rfuncs.c 2.20 9/3/84"; X#endif !lint X X#include "rparams.h" X Xlong nngsize; /* The next upcoming value of ngsize. */ Xlong nminartno; /* Smallest article number in this group */ X Xnextng() X{ X long curpos; X#ifdef DEBUG X fprintf(stderr, "nextng()\n"); X#endif X curpos = ftell(actfp); X Xnext: X#ifdef DEBUG X fprintf(stderr, "next:\n"); X#endif X if (actdirect == BACKWARD) { X if (back()) { X fseek(actfp, curpos, 0); X return 1; X } X if (back()) { X fseek(actfp, curpos, 0); X return 1; X } X } X if (fgets(afline, BUFLEN, actfp) == NULL) X return 1; X if (sscanf(afline, "%s %ld %ld", bfr, &nngsize, &nminartno) < 3) { X bfr[0] = '\0'; X nngsize = 0; X nminartno = 0; X } X#ifdef DEBUG X fprintf(stderr, "bfr = '%s'\n", bfr); X#endif X X ngcat(bfr); X if (!ngmatch(bfr, header.nbuf)) X goto next; X ngdel(bfr); X if (xflag) X readmode = SPEC; X else X readmode = NEXT; X if (selectng(bfr, TRUE)) X goto next; X return 0; X} X X Xselectng(name, fastcheck) Xchar *name; X{ X register char *ptr, punct = ','; X register int i; X register char *p; X register long cur; X long next = 0; X FILE *af; X long s, sm; X char buf[100], n[100]; X X if (*groupdir) X updaterc(); X last = 1; X if (strcmp(name, bfr)) { X af = xfopen(ACTIVE, "r"); X while (fgets(buf, sizeof buf, af) != NULL) { X if (sscanf(buf, "%s %ld %ld", n, &s, &sm) == 3 && X strcmp(n, name) == 0) { X ngsize = s; X minartno = sm; X break; X } X } X fclose(af); X } else { X ngsize = nngsize; X minartno = nminartno; X } X#ifdef DEBUG X fprintf(stderr, "selectng(%s) sets ngsize to %ld, minartno to %ld\n", X name, ngsize, minartno); X#endif X strcpy(groupdir, name); X if (!xflag) { X i = findrcline(name); X if (i >= 0) { X if (index(rcline[i], '!')) { X groupdir[0] = 0; X return 1; X } X sprintf(rcbuf, "%s,%ld", rcline[i], ngsize+1); X } X else X sprintf(rcbuf, "ng: %ld", ngsize+1); X } else X sprintf(rcbuf, "ng: %ld", ngsize+1); X#ifdef DEBUG X fprintf(stderr, "rcbuf set to %s\n", rcbuf); X#endif DEBUG X X /* X * Fast check for common case: 1-### X */ X if (fastcheck) { X p = rcbuf; X while (*p != ' ') X p++; X while (*p == ' ') X p++; X if (*p++ == '1' && *p++ == '-') { X i = 0; X while (isdigit(*p)) X i = 10 * i + *p++ - '0'; X if (*p == ',' && i >= ngsize) { X groupdir[0] = 0; X return 1; X } X } X } X X/* X * The key to understanding this piece of code is that a bit is set iff X * that article has NOT been read. Thus, we fill in the holes when X * commas are found (e.g. 1-20,30-35 will result in filling in the 21-29 X * holes), and so we assume the newsrc file is properly ordered, the way X * we write it out. X */ X if ((ngsize-minartno) > BITMAPSIZE) { X sprintf(buf," Bitmap not large enough for newsgroup %s", groupdir); X xerror(buf); X } X X cur = 0; X /* Zero out the bitmap */ X p = &bitmap[(ngsize-minartno)/8+1]; X for (ptr = bitmap; ptr <= p;) X *ptr++ = 0; X X /* Decode the .newsrc line indicating what we have read. */ X for (ptr = rcbuf; *ptr && *ptr != ':'; ptr++) X ; X while (*ptr) { X while (!isdigit(*ptr) && *ptr) X ptr++; X if (!*ptr) X break; X sscanf(ptr, "%ld", &next); X if (punct == ',') { X while (++cur < next) { X set(cur); X } X } X cur = next; X while (!ispunct(*ptr) && *ptr) X ptr++; X punct = *ptr; X } X if (rflag) X bit = ngsize+1; X else X bit = minartno -1; X nextbit(); X ngrp = 1; X return 0; X} X X#ifdef TMAIL Xcatchterm() X{ X unlink(infile); X unlink(outfile); X xxit(0); X} X X X/* X * The -M (Mail) interface. This code is a reasonably simple model for X * writing other interfaces. We write out all relavent articles to X * a temp file, then invoke Mail with an option to have it tell us which X * articles it read. Finally we count those articles as really read. X */ XMail() X{ X register FILE *fp = NULL, *ofp; X struct hbuf h; X register char *ptr, *fname; X int news = 0; X register int i; X X for(i=0;i<NUNREC;i++) X h.unrec[i] = NULL; X X ofp = xfopen(mktemp(outfile), "w"); X if (aflag && *datebuf) X if ((atime = cgtdate(datebuf)) == -1) X xerror("Cannot parse date string"); X while (!nextng()) X while (bit <= ngsize) { X sprintf(filename, "%s/%ld", dirname(groupdir), bit); X if (access(filename, 4) X || ((fp = fopen(filename, "r")) == NULL) X || (hread(&h, fp, TRUE) == NULL) X || !aselect(&h, FALSE)) { X#ifdef DEBUG X fprintf(stderr, "Bad article '%s'\n", filename); X#endif X if (fp != NULL) { X fclose(fp); X fp = NULL; X } X clear(bit); X nextbit(); X continue; X } X fname = ptr = index(h.from, '('); X if (fname) { X while (ptr && ptr[-1] == ' ') X ptr--; X if (ptr) X *ptr = 0; X fname++; X ptr = fname + strlen(fname) - 1; X if (*ptr == ')') X *ptr = 0; X } X h.subtime = cgtdate(h.subdate); X fprintf(ofp, "From %s %s", X#ifdef INTERNET X h.from[0] ? h.from : X#endif X h.path, ctime(&h.subtime)); X if (fname) X fprintf(ofp, "Full-Name: %s\n", fname); X fprintf(ofp, "Newsgroups: %s\n", h.nbuf); X fprintf(ofp, "Subject: %s\n", h.title); X fprintf(ofp, "Article-ID: %s/%ld\n\n", groupdir, bit); X tprint(fp, ofp, TRUE); X putc('\n', ofp); X news = TRUE; X fclose(fp); X fp = NULL; X nextbit(); X } X updaterc(); X fclose(ofp); X if (!news) { X fprintf(stderr, "No news.\n"); X unlink(outfile); X return; X } X signal(SIGHUP, catchterm); X signal(SIGTERM, catchterm); X sprintf(bfr, "%s -f %s -T %s", TMAIL, outfile, mktemp(infile)); X fwait(fsubr(ushell, bfr, (char *)NULL)); X ofp = xfopen(infile, "r"); X fseek(actfp, 0L, 0); X while (fgets(afline, BUFLEN, actfp) != NULL) { X last = 0; X if (sscanf(afline, "%s %ld", bfr, &nngsize) < 2) { X bfr[0] = '\0'; X nngsize = 0; X } X ngcat(bfr); X if (!ngmatch(bfr, header.nbuf)) X continue; X ngdel(bfr); X *groupdir = 0; X if (selectng(bfr, TRUE)) X continue; X fseek(ofp, 0L, 0); X while (fgets(groupdir, BUFLEN, ofp) != NULL) { X nstrip(groupdir); X ptr = index(groupdir, '/'); X *ptr = 0; X if (strcmp(bfr, groupdir)) X continue; X sscanf(++ptr, "%ld", &last); X clear(last); X } X if (last) { X strcpy(groupdir, bfr); X updaterc(); X } X } X unlink(infile); X unlink(outfile); X} X#endif X Xupdaterc() X{ X register long cur = 1, next = 1; X register int i; X register char *ptr; X char oldptr; X X sprintf(rcbuf, "%s%c ", groupdir, zapng ? '!' : ':'); X X zapng = FALSE; Xagain: X ptr = &rcbuf[strlen(rcbuf)]; X while (get(next) && next <= ngsize) X next++; X cur = next; X while (!(get(next)) && next <= ngsize) X next++; X if (cur == next) { X next = ngsize + 1; X goto skip; X } X if (cur + 1 == next) X sprintf(ptr, "%ld,", cur); X else X sprintf(ptr, "%ld-%ld,", cur, next - 1); Xskip: X if ((long) next > ngsize) { X if (index(rcbuf, ',') != NULL) X ngdel(rcbuf); X else if (index(rcbuf, '!') == NULL) X return; X ptr = index(rcbuf, ' '); X ptr--; X oldptr = *ptr; X ptr[0] = ':'; X ptr[1] = '\0'; X i = findrcline(groupdir); X if (i >= 0) { X ptr[0] = oldptr; X ptr[1] = ' '; X rcline[i] = realloc(rcline[i], (unsigned)(strlen(rcbuf) + 1)); X if (rcline[i] == NULL) X xerror("Cannot realloc"); X strcpy(rcline[i], rcbuf); X return; X } X if (++line > LINES) X xerror("Too many newsgroups"); X ptr[0] = oldptr; X ptr[1] = ' '; X if ((rcline[line] = malloc((unsigned)(strlen(rcbuf) + 1))) == NULL) X xerror("Not enough memory"); X strcpy(rcline[line], rcbuf); X return; X } X cur = next; X goto again; X} X Xnewrc(rcname) Xchar *rcname; X{ X register FILE *fp; X X if (close(creat(rcname, 0666))) { X sprintf(bfr, "Cannot create %s", newsrc); X xerror(bfr); X } X X sprintf(bfr, "%s/users", LIB); X if ((fp = fopen(bfr, "a")) != NULL) { X fprintf(fp, "%s\n", username); X fclose(fp); X chmod(bfr, 0666); X } X} X Xnextbit() X{ X#ifdef DEBUG X fprintf(stderr,"nextbit() bit = %ld\n", bit); X#endif DEBUG X last = bit; X if (readmode == SPEC || xflag) { X if (rflag) X bit--; X else X bit++; X return; X } X if (rflag) X while (--bit, !get(bit) && bit > minartno) X ; X else X while (++bit, !get(bit) && bit <= ngsize) X ; X#ifdef DEBUG X fprintf(stderr,"nextng leaves bit as %ld\n", bit); X#endif DEBUG X} X Xxxit(status) Xint status; X{ X unlink(infile); X unlink(outfile); X#ifdef SORTACTIVE X if (strncmp(ACTIVE,"/tmp/",4) == 0) /* Paranoia */ X unlink(ACTIVE); X#endif SORTACTIVE X exit(status); X} X X/* X * Return TRUE if the user has not ruled out this article. X */ Xaselect(hp, insist) Xregister struct hbuf *hp; Xint insist; X{ X if (insist) X return TRUE; X if (tflag && !titmat(hp, header.title)) X return FALSE; X if (aflag && cgtdate(hp->recdate) < atime) X return FALSE; X if (index(hp->nbuf, ',') && !rightgroup(hp)) X return FALSE; X if (fflag && isfol(hp)) X return FALSE; X return TRUE; X} X X/* X * Code to avoid showing multiple articles for news. X * Works even if you exit news. X * Returns nonzero if we should show this article. X */ Xrightgroup(hp) Xstruct hbuf *hp; X{ X char ng[BUFLEN]; X register char *p, *g; X int i, flag; X X strcpy(ng, hp->nbuf); X ngcat(ng); X g = ng; X flag = 1; X while ((p = index(g, ',')) != NULL) { X *p++ = '\0'; X while (*p == ' ') X p++; X if (strcmp(g, groupdir) == 0) X return flag; X if (ngmatch(g, header.nbuf) X && ((i = findrcline(g)) >= 0 X && index(rcline[i], '!') == NULL)) X flag = 0; X g = p; X } X /* we must be in "junk" or "control" */ X return TRUE; X} X X/* X * Return TRUE if this article is a followup to something. X */ Xisfol(hp) Xregister struct hbuf *hp; X{ X if (hp->followid[0]) X return TRUE; X if (strncmp(hp->title, "Re:", 3) == 0) X return TRUE; X return FALSE; X} X Xback() X{ X while (fseek(actfp, -2L, 1) != -1 && ftell(actfp) > 0L) { X if (getc(actfp) == '\n') X return 0; X } X if (ftell(actfp) == 0L) X return 0; X return 1; X} X X/* X * Trap interrupts. X */ Xonsig(n) Xint n; X{ X signal(n, onsig); X sigtrap = n; X if (rcreadok < 2) { X fprintf(stderr, "Aborted early\n"); X xxit(0); X } X} X X/* X * finds the line in your .newsrc file (actually the in-core "rcline" X * copy of it) and returns the index into the array where it was found. X * -1 means it didn't find it. X * X * We play clever games here to make this faster. It's inherently X * quadratic - we spend lots of CPU time here because we search through X * the whole .newsrc for each line. The "prev" variable remembers where X * the last match was found; we start the search there and loop around X * to the beginning, in the hopes that the calls will be roughly in order. X */ Xint Xfindrcline(name) Xchar *name; X{ X register char *p, *ptr; X register int cur; X register int i; X register int top; X static int prev = 0; X X top = line; i = prev; Xloop: X for (; i <= top; i++) { X for (p = name, ptr = rcline[i]; (cur = *p++); ) { X if (cur != *ptr++) X goto contin2; X } X if (*ptr != ':' && *ptr != '!') X continue; X prev = i; X return i; Xcontin2: X ; X } X if (i > line && line > prev-1) { X i = 0; X top = prev-1; X goto loop; X } X return -1; X} X X#ifdef SORTACTIVE X/* X * sortactive - make a local copy of the active file, sorted according X * to the user's preferences, according to his .newsrc file. X * Marvin Solomon, University of Wisconsin, 1/2/84 X */ X Xstruct table_elt { X long actpos, rcpos; X}; X Xstatic int Xrcsort(a,b) Xstruct table_elt *a, *b; X{ X return(a->rcpos - b->rcpos); X} X Xsortactive() X{ X char newactivename[BUFLEN], aline[BUFLEN], *strcpy(), *p; X register FILE *nfp, *afp; X struct table_elt table[LINES]; X int nlines = 0, i; X long actpos; X X /* make a new sorted copy of ACTIVE in the user's home directory */ X strcpy(newactivename, mktemp("/tmp/newsaXXXXXX")); X nfp = fopen(newactivename, "w"); X if (nfp == NULL) { X perror(newactivename); X return; X } X X /* look up all the lines in ACTIVE, finding their positions in .newsrc */ X afp = xfopen(ACTIVE, "r"); X actpos = ftell(afp); X while (fgets(aline, sizeof aline, afp) != NULL) { X if (p = index(aline, ' ')) X *p = '\0'; X table[nlines].rcpos = findrcline(aline); X table[nlines].actpos = actpos; X nlines++; X actpos = ftell(afp); X } X X /* sort by position in user's .newsrc file (new groups come up first) */ X qsort((char *)table, nlines, sizeof table[0], rcsort); X X /* copy active to newactive, in the new order */ X for (i=0; i<nlines; i++) { X (void) fseek(afp, table[i].actpos, 0); X (void) fgets(aline, sizeof aline, afp); X (void) fprintf(nfp, "%s", aline); X } X (void) fclose(afp); X (void) fclose(nfp); X X /* make the rest of readnews think the local active file is the real one */ X free(ACTIVE); X ACTIVE = AllocCpy(newactivename); X} X#endif SORTACTIVE *-*-END-of-src/rfuncs.c-*-* echo x - src/rfuncs2.c sed 's/^X//' >src/rfuncs2.c <<'*-*-END-of-src/rfuncs2.c-*-*' X/* X * rfuncs2 - more routines needed by readr. X */ X X#ifndef lint Xstatic char *SccsId = "@(#)rfuncs2.c 1.17 9/3/84"; X#endif !lint X X#include "rparams.h" X Xstatic char lbuf[BUFLEN*2]; X XFILE *popen(); X X/* X * Match title. X */ Xtitmat(h, titlist) Xregister struct hbuf *h; Xregister char *titlist; X{ X register char *p; X X while (*titlist != '\0') { X X for (p = h->title; *p != '\0'; p++) X if (prefix(p, titlist)) { X return(TRUE); X } X while (*titlist++ != '\0') X ; X } X return(FALSE); X} X X X/* X * Save the news item in the user's file. X * Fri Mar 12 20:04:43 EST 1982: (ittvax!swatt) X * Allow files with first character as '|' to write article X * to program across a pipe. X */ X X#define PIPECHAR '|' X Xsave(file, to) Xregister char *file, *to; X{ X register FILE *ufp, *hfp; X struct hbuf hh; X int isprogram = 0; X int isnew = 1; X register int i; X X for(i=0;i<NUNREC;i++) X hh.unrec[i] = NULL; X X if ((hfp = fopen(file, "r")) == NULL) { X fprintf(stderr, "Can't get article.\n"); X return; X } X if (hread(&hh, hfp, TRUE) == NULL) { X fprintf(stderr, "Article is garbled.\n"); X return; X } X ufp = fopen(to, "r"); X if (ufp != NULL) { X fclose(ufp); X isnew = 0; X } X setgid(gid); X setuid(uid); X umask(savmask); X X if (*to == PIPECHAR) { X if ((ufp = popen (&to[1], "w")) == NULL) { X fprintf(stderr,"Cannot execute %s\n", &to[1]); X return; X } X isprogram++; X } else if ((ufp = fopen(to, "a")) == NULL) { X fprintf(stderr,"Cannot append to %s.\n", to); X return; X } X /* X * V7MAIL code is here to conform to V7 mail format. X * If you need a different format to be able to X * use your local mail command (such as four ^A's X * on the end of articles) substitute it here. X */ X#ifdef V7MAIL X hh.subtime = cgtdate(hh.subdate); X fprintf(ufp, "From %s %s", X#ifdef INTERNET X hh.from, X#else X hh.path, X#endif X ctime(&hh.subtime)); X#endif X hprint(&hh, ufp, 2); X#ifdef V7MAIL X tprint(hfp, ufp, TRUE); X putc('\n', ufp); /* force blank line at end (ugh) */ X#else X tprint(hfp, ufp, FALSE); X#endif X fclose(hfp); X if (isprogram) X pclose (ufp); X else X fclose(ufp); X if (!isprogram) X printf("%s: %s\n", to, isnew ? "New file" : "Appended"); X} X X X/* X * Print out the rest of the article. X */ Xtprint(ifp, ofp, checkfrom) Xregister FILE *ifp, *ofp; Xint checkfrom; X{ X while ((fgets(bfr, sizeof bfr, ifp)) != NULL && !sigtrap) { X if (checkfrom && strncmp(bfr, "From ", 5) == 0) X putc('>', ofp); X fputs(bfr, ofp); X } X if (sigtrap) X qfflush(ofp); X fflush(ofp); X fprintf(ofp, (sigtrap ? "\n\n" : "\n")); X sigtrap = FALSE; X} X X X/* X * Print the file header. X */ Xhprint(hp, ofp, verbose) Xregister struct hbuf *hp; Xint verbose; Xregister FILE *ofp; X{ X register char *p1, *p2; X char fname[BUFLEN]; X char *tailpath(); X X fname[0] = '\0'; /* init name holder */ X X if (verbose == 2) { X lhwrite(hp, ofp); X return; X } X X if (lflag || eflag) { X char buf1[80], buf2[200]; X char *cp; X X strcpy(bfr, groupdir); X for (cp=bfr; *cp; cp++) X if (*cp == '/') X *cp = '.'; X sprintf(buf1, "%s/%ld", bfr, bit); X sprintf(buf2, "%-20s %s", buf1, hp->title); X fprintf(ofp, "%.76s\n", buf2); X return; X } X X p1 = index(hp->from, '('); /* Find the sender's full name. */ X if (p1 == NULL && hp->path[0]) X p1 = index(hp->path, '('); X if (p1 != NULL) { X strcpy(fname, p1+1); X p2 = index(fname, ')'); X if (p2 != NULL) X *p2 = '\0'; X } X X fprintf(ofp, "Subject: %s\n", hp->title); X if (!hflag && hp->keywords[0]) X fprintf(ofp, "Keywords: %s\n", hp->keywords); X if (verbose) { X fprintf(ofp, "From: %s\n", hp->from); X fprintf(ofp, "Path: %s\n", hp->path); X if (hp->organization[0]) X fprintf(ofp, "Organization: %s\n", hp->organization); X } X else { X if (p1 != NULL) X *--p1 = '\0'; /* bump over the '(' */ X#ifdef INTERNET X /* X * Prefer Path line if it's in internet format, or if we don't X * understand internet format here, or if there is no reply-to. X */ X fprintf(ofp, "From: %s", hp->from); X#else X fprintf(ofp, "Path: %s", tailpath(hp)); X#endif X if (fname[0] || hp->organization[0]) { X if (fname[0] == '\0') { X strcpy(fname,hp->from); X p2 = index(fname,'@'); X if (p2) X *p2 = '\0'; X } X fprintf(ofp, " (%s", fname); X if (hp->organization[0] && !hflag) X fprintf(ofp, " @ %s", hp->organization); X fprintf(ofp, ")"); X } X fprintf(ofp, "\n"); X if (p1 != NULL) X *p1 = ' '; X } X X ngdel(strcpy(bfr, hp->nbuf)); X if (verbose) { X fprintf(ofp, "Newsgroups: %s\n", bfr); X fprintf(ofp, "Date: %s\n", hp->subdate); X if (hp->sender[0]) X fprintf(ofp, "Sender: %s\n", hp->sender); X if (hp->replyto[0]) X fprintf(ofp, "Reply-To: %s\n", hp->replyto); X if (hp->followto[0]) X fprintf(ofp, "Followup-To: %s\n", hp->followto); X } X else if (index(bfr, ',') || strcmp(groupdir, "junk") == 0) X fprintf(ofp, "Newsgroups: %s\n", bfr); X X if (pflag || ofp != stdout) X putc('\n', ofp); X} X X X/* X * If ofp != stdout, close it and run the script in coptbuf. X */ Xcout(ofp) XFILE *ofp; X{ X register char *p, *q, *r; X X if (ofp == stdout) X return; X fclose(ofp); X p = coptbuf; X q = lbuf; X while ((*q = *p++) != '\0') X if (*q++ == FMETA) { X q--; X r = outfile; X while ((*q++ = *r++) != '\0') X ; X q--; X } X fwait(fsubr(ushell, lbuf, (char *)NULL)); X unlink(outfile); X} X X Xcdump(ofp) Xregister FILE *ofp; X{ X if (ofp == stdout) X return; X fclose(ofp); X unlink(outfile); X} X X X/* X * Quiet 'flush'. X * Empty (without fflush()) the buffer for stream fp. X */ X/* ARGSUSED */ Xqfflush(fp) XFILE *fp; X{ X /* Alas, stdio does not permit this */ X} X X X/* X * Count the number of remaining lines in file fp. X * Do not move the file pointer. X */ Xlinecnt(fp) XFILE *fp; X{ X long curpos; X register int nlines = 0; X register int c; X X if (fp == NULL) X return 0; X curpos = ftell(fp); X while ((c = getc(fp)) != EOF) X if (c == '\n') X nlines++; X fseek(fp, curpos, 0); X return nlines; X} X X X/* X * Transmit file to system. X */ Xtransmit(sp, file) Xregister struct srec *sp; Xchar *file; X{ X register FILE *ifp, *ofp; X register int c; X struct hbuf hh; X char TRANS[BUFLEN]; X X#ifdef DEBUG X fprintf(stderr, "xmit %s to %s using %s\n", file, sp->s_name, sp->s_xmit); X#endif X ifp = xfopen(file, "r"); X for(c=0;c<NUNREC;c++) X hh.unrec[c] = NULL; X if (hread(&hh, ifp, TRUE) == NULL) X return; X strcpy(TRANS, "/tmp/trXXXXXX"); X ofp = xfopen(mktemp(TRANS), "w"); X if (index(sp->s_flags, 'A') == NULL) X hwrite(&hh, ofp); X else X ohwrite(&hh, ofp); X while ((c = getc(ifp)) != EOF) X putc(c, ofp); X fclose(ifp); X fclose(ofp); X if (*sp->s_xmit == '\0' || index(sp->s_flags, 'F') || index(sp->s_flags, 'U')) X sprintf(bfr, DFTXMIT, sp->s_name, TRANS); X else X sprintf(bfr, "(%s) < %s", sp->s_xmit, TRANS); X#ifdef DEBUG X fprintf(stderr, "%s\n", bfr); X#endif X fwait(fsubr(pshell, bfr, (char *)NULL)); X unlink(TRANS); X} X X X/* X * Cancel the article whose header is in hp, by posting a control message X * to cancel it. The scope of the control message depends on who would X * really be willing to cancel it. It is sent as far as it will do any good. X * notauthor is true iff the person posting this article is not the X * real author of the article being cancelled. X */ Xcancel(ofp, hp, notauthor) XFILE *ofp; Xstruct hbuf *hp; Xint notauthor; X{ X int pid; X X fflush(ofp); X pid = fork(); X if (pid < 0) { X perror("readnews: cancel"); X return 0; X } X if (pid > 0) X return 0; X if (notauthor) X sprintf(bfr, "%s/%s -t 'cmsg cancel %s' -n %s -d local < /dev/null", X LIB, "inews", hp->ident, hp->nbuf); X else { X if (hp->distribution[0] == '\0') X sprintf(bfr, "%s/%s -t 'cmsg cancel %s' -n %s < /dev/null", X LIB, "inews", hp->ident, hp->nbuf); X else X sprintf(bfr, "%s/%s -t 'cmsg cancel %s' -n %s -d %s < /dev/null", X LIB, "inews", hp->ident, hp->nbuf, hp->distribution); X } X execl("/bin/sh", "sh", "-c", bfr, (char *) 0); X perror(bfr); X exit(1); X#ifdef lint X return 0; X#endif lint X} X X Xdash(num, ofp) Xregister int num; Xregister FILE *ofp; X{ X register int i; X X for (i = 0; i < num; i++) X putc('-', ofp); X putc('\n', ofp); X} X X Xhelp(ofp) Xregister FILE *ofp; X{ X register FILE *fp; X register int c; X char temp[BUFLEN]; X X if (cflag) { Xoneline: X fprintf(ofp, "(n)ext re(p)rint (w)rite (q)uit (r)eply\ X (c)ancel -[n] +[n] (f)ollowup (N)ext (U)nsubscribe (v)ersion\n"); X return; X } X sprintf(temp, "%s/%s", LIB, "help"); X if ((fp = fopen(temp, "r")) == NULL) { X fprintf(ofp, "No help file.\n"); X goto oneline; X } X while ((c = getc(fp)) != EOF && !sigtrap) X putc(c, ofp); X fclose(fp); X} X X Xpout(ofp) XFILE *ofp; X{ X register char *p, *q, *r; X X p = PAGER; X q = lbuf; X while ((*q = *p++) != '\0') X if (*q++ == FMETA) { X q--; X r = filename; X while ((*q++ = *r++) != '\0') X ; X q--; X } X fwait(fsubr(ushell, lbuf, (char *)NULL)); X fprintf(ofp, "\n"); X} X X/* X * Print a very brief version of the date in question. X */ Xchar * Xbriefdate(datestr) Xchar *datestr; X{ X time_t dt, now; X char *tmstr; X char *wkday, *monthdate, *timeofday; X static char rbuf[20]; X X dt = cgtdate(datestr); X tmstr = ctime(&dt); X X wkday = tmstr; tmstr[3] = '\0'; X monthdate = tmstr+4; tmstr[10] = '\0'; X timeofday = tmstr+11; tmstr[16] = '\0'; X X (void) time(&now); X if (now - dt < 7 * DAYS) X strcpy(rbuf, wkday); X else X strcpy(rbuf, monthdate); X strcat(rbuf, " "); X strcat(rbuf, timeofday); X return rbuf; X} X X/* X * Return TRUE iff stdout is /dev/null. X */ Xignoring() X{ X struct stat ss, ns; X X fstat(1, &ss); X stat("/dev/null", &ns); X if (ss.st_dev == ns.st_dev && ss.st_rdev == ns.st_rdev) X return TRUE; X return FALSE; X} *-*-END-of-src/rfuncs2.c-*-* echo x - src/rmgroup.sh sed 's/^X//' >src/rmgroup.sh <<'*-*-END-of-src/rmgroup.sh-*-*' X: '@(#)rmgroup.sh 1.3 8/21/84' Xfor group Xdo X echo "Removing newsgroup $group" X qgrp="`echo $group | sed 's/\./\\\./g'`" X if X grep -s "^$qgrp " LIBDIR/active X then X ed - LIBDIR/active << E_O_F X/^$qgrp /d Xw Xq XE_O_F X dir=SPOOLDIR/"`echo $group | sed 's/\./\//g'`" X if X [ -d "$dir" ] X then X rm -r "$dir" X else X echo "$0: $dir: no spool directory" 2>&1 X fi X else X echo "$0: $group: no such newsgroup" 2>&1 X fi Xdone Xexit 0 *-*-END-of-src/rmgroup.sh-*-* echo x - src/rparams.h sed 's/^X//' >src/rparams.h <<'*-*-END-of-src/rparams.h-*-*' X/* X * rparams.h - parameters for readnews, rfuncs, and readr. X */ X X/* @(#)rparams.h 2.14 8/28/84 */ X X#include "params.h" X X/* flags for readnews */ X#define pflag options[0].flag X#define tflag options[1].flag X#define aflag options[2].flag X#define nflag options[3].flag X#define cflag options[4].flag X#define lflag options[5].flag X#define rflag options[6].flag X#define sflag options[7].flag X#define xflag options[8].flag X#define hflag options[9].flag X#define Mflag options[10].flag X#define fflag options[11].flag X#define uflag options[12].flag X#define eflag options[13].flag X X#define NEXT 0 X#define SPEC 1 X X#define FORWARD 0 X#define BACKWARD 1 X X#define UNKNOWN 0001 /* possible modes for news program */ X#define MAIL 0004 X#define ANY 0007 X X#define BITMAPSIZE 2048 /* Must be a power of 2 */ X Xstruct optable { /* options table. */ X char optlet; /* option character. */ X char filchar; /* if to pickup string, fill character. */ X int flag; /* TRUE if have seen this opt. */ X int newstate; /* STRING if takes arg, else OPTION */ X int oldmode; /* OR of legal input modes. */ X int newmode; /* output mode. */ X char *buf; /* string buffer */ X}; X X/* external declarations specific to readnews */ Xextern char *infile, *outfile, PAGER[]; Xextern char bitmap[], *temprc, *MAILER; X X#ifndef ROOTID Xextern int ROOTID; X#endif X X#ifdef NOTIFY Xextern char *TELLME; X#endif X Xextern char filename[],coptbuf[],datebuf[],titlebuf[],afline[]; Xextern char newsrc[],groupdir[],rcbuf[],*rcline[],*argvrc[]; Xextern int mode, ngrp, line, newrc(), readmode; Xextern long bit, obit, last, ngsize, minartno; Xextern FILE *rcfp,*actfp; Xextern time_t atime; Xextern struct stat statbuf; Xextern struct optable *optpt, options[]; Xextern int actdirect, rcreadok, zapng; X X#ifndef lint X/* lint gets very mad about i-minartno, this is one way of shutting it up */ X/* macros */ X#define get(i) ((i<minartno)? 0 : (bitmap[(i-minartno) >> 3] & (1 << (i-minartno) % 8))) X#define set(i) if (i>=minartno) bitmap[(i-minartno) >> 3] |= (1 << (i-minartno) % 8);else X#define clear(i) if (i>=minartno) bitmap[(i-minartno) >> 3] &= ~(1 << (i-minartno) % 8);else X#endif !lint X X#define FCLOSE(fp) {if (fp != NULL) {fclose(fp);fp = NULL;}} *-*-END-of-src/rparams.h-*-* echo x - src/sendbatch.sh sed 's/^X//' >src/sendbatch.sh <<'*-*-END-of-src/sendbatch.sh-*-*' X: '@(#)sendbatch.sh 1.3 8/21/84' Xfor rmt in $* Xdo X while test $? -eq 0 -a \( -s BATCHDIR/$rmt -o -s BATCHDIR/$rmt.work \) X do X LIBDIR/batch BATCHDIR/$rmt 50000 | \ X if test -s BATCHDIR/$rmt.cmd X then X BATCHDIR/$rmt.cmd X else X uux - UUXFLAGS $rmt!rnews X fi X done Xdone *-*-END-of-src/sendbatch.sh-*-* echo x - src/sendnews.c sed 's/^X//' >src/sendnews.c <<'*-*-END-of-src/sendnews.c-*-*' X/* X * sendnews - send news article by mail. X */ X X#ifndef lint Xstatic char *SccsId = "@(#)sendnews.c 2.8 8/14/84"; X#endif !lint X X#include <stdio.h> X#include <ctype.h> X#ifndef USG Xstruct utsname { X char Sysname[9]; X char nodename[33]; X char release[9]; X char version[9]; X}; X#else X#include <sys/utsname.h> X#endif X X#define eq(a,b) (strcmp(a,b) == 0) X#define LNLEN 7 /* strlen("ucbvax!") */ X Xchar *index(); Xchar buffer[BUFSIZ]; Xint linecount, oflag = 0, aflag = 0, bflag = 0, toflag = 0; X XFILE *popen(); Xmain(argc, argv) Xchar **argv; X{ X FILE *out; X char newsgroup[100]; X char sysn[20]; X struct utsname ubuf; X#ifdef lint X argc = argc; X#endif lint X X while (**(++argv) == '-') { X if (*++*argv == 'o') X oflag++; X else if (**argv == 'a') X aflag++; X else if (**argv == 'b') X bflag++; X else if (**argv == 'n') X strcpy(newsgroup, *(++argv)); X } X if (aflag && bflag) { X fprintf(stderr, "'-a' and '-b' options mutually exclusive.\n"); X exit(1); X } X X#ifdef debug X printf("mail %s\n", *argv); X sprintf(buffer, "cat"); X#else X sprintf(buffer, "mail %s", *argv); X#endif X out = popen(buffer, "w"); X uname(&ubuf); X strcpy(sysn, ubuf.nodename); X strcat(sysn, "!"); X X /* Standard mail prelude to make the formatters happy */ X fprintf(out, "To: %s\n", *argv); X fprintf(out, "Subject: network news article\n"); X fprintf(out, "\n"); X X while (fgets(buffer, sizeof buffer, stdin)) { X if (*newsgroup && ngline()) { X if (oflag) X sprintf(buffer, "%s\n", newsgroup); X else X sprintf(buffer, "Newsgroups: %s\n", newsgroup); X } X putc('N', out); X fputs(buffer, out); X } X pclose(out); X exit(0); X} X Xngline() X{ X if (oflag) X return linecount == 2; X if (!toflag && (!strncmp("Newsgroups: ", buffer, 12) || X !strncmp("To: ",buffer, 4))) X return ++toflag; X return 0; X} X X/* X * Return the ptr in sp at which the character c appears; X * NULL if not found X */ X Xchar * Xindex(sp, c) Xregister char *sp, c; X{ X do { X if (*sp == c) X return(sp); X } while (*sp++); X return(NULL); X} *-*-END-of-src/sendnews.c-*-* echo x - src/uname.c sed 's/^X//' >src/uname.c <<'*-*-END-of-src/uname.c-*-*' X/* X * This routine is compatible with the Unix T/S system call uname, X * which figures out the name of the local system. X * However, we do it by reading the file /usr/include/whoami.h. X * This avoids having to recompile uucp for each site and hence X * avoids having to distribute the source to uucp to people who X * have only binary licenses. X */ X X#ifndef lint Xstatic char *SccsId = "@(#)uname.c 2.6 8/13/84"; X#endif !lint X X#include "params.h" X X#ifdef UNAME X# define DONE X#endif X X#ifdef GHNAME Xuname(uptr) Xstruct utsname *uptr; X{ X gethostname(uptr->nodename, sizeof (uptr->nodename)); X} X# define DONE X#endif X X#ifndef DONE X#define HDRFILE "/usr/include/whoami.h" X Xuname(uptr) Xstruct utsname *uptr; X{ X char buf[BUFSIZ]; X FILE *fd; X X fd = fopen(HDRFILE, "r"); X if (fd == NULL) { X fprintf(stderr, "Cannot open %s\n", HDRFILE); X exit(1); X } X X for (;;) { /* each line in the file */ X if (fgets(buf, sizeof buf, fd) == NULL) { X fprintf(stderr, "no sysname in %s\n", HDRFILE); X fclose(fd); X exit(2); X } X if (sscanf(buf, "#define sysname \"%[^\"]\"", uptr->nodename) == 1) { X fclose(fd); X return; X } X } X} X#endif *-*-END-of-src/uname.c-*-* echo x - src/unbatch.c sed 's/^X//' >src/unbatch.c <<'*-*-END-of-src/unbatch.c-*-*' X/* X * unbatchnews: extract news in batched format and process it one article X * at a time. The format looks like X * #! rnews 1234 X * article containing 1234 characters X * #! rnews 4321 X * article containing 4321 characters X */ X X#ifndef lint Xstatic char *SccsId = "@(#)unbatch.c 1.8 9/3/84"; X#endif !lint X X# include <stdio.h> X Xchar buf[512]; X Xmain() X{ X register int c; X register FILE *pfn; X register long size; X char *filename; X int pid, wpid, exstat; X char *mktemp(), *gets(); X long atol(); X X filename = mktemp("/tmp/unbnewsXXXXXX"); X while(gets(buf) != NULL) { X while (strncmp(buf, "#! rnews ", 9)) { X fprintf(stderr, "out of sync, skipping %s\n", buf); X if (gets(buf) == NULL) X exit(0); X } X size = atol(buf+9); X if(size <= 0) X break; X pfn = fopen(filename, "w"); X while(--size >= 0 && (c = getc(stdin)) != EOF) X putc(c, pfn); X fclose(pfn); X X /* X * If we got a truncated batch, don't process the X * last article; it will probably be received again. X */ X if (size > 0) X break; X X /* X * rnews < filename X */ X while ((pid = fork()) == -1) { X fprintf(stderr, "fork failed, waiting...\r\n"); X sleep(60); X } X if (pid == 0) { X close(0); X open(filename, 0); X#ifdef IHCC X sprintf(buf, "%s/%s/rnews", logdir(HOME), LIBDIR); X execlp(buf, "rnews", (char *)0); X#else X execlp("rnews", "rnews", (char *)0); X#endif X perror("rnews"); X exit(1); X } X while ((wpid = wait(&exstat)) >= 0 && wpid != pid) X ; X } X unlink(filename); X} *-*-END-of-src/unbatch.c-*-* echo x - src/uurec.c sed 's/^X//' >src/uurec.c <<'*-*-END-of-src/uurec.c-*-*' X/* X * uurec - receive articles via /bin/mail. X */ X X#ifndef lint Xstatic char *SccsId = "@(#)uurec.c 2.7 9/3/84"; X#endif !lint X X#include "defs.h" X X#include <stdio.h> X#include <ctype.h> X X/* X * Process a news article which has been shipped via /bin/mail. X */ X X#define FROM 01 X#define NLIN 02 X#define BLANK 03 X#define OTHER 04 X X#define SKIPPING 010 X#define READING 020 X X#define BFSZ 250 X X#define EOT '\004' X X#define A 01 X#define B 02 X X#ifdef debug X# define RNEWS "cat" X#endif Xextern char *strcat(), *strcpy(); Xextern char *frombreak(); Xextern FILE *popen(); X X/* ARGSUSED */ Xmain(argc, argv) Xint argc; Xchar **argv; X{ X char buf[BFSZ], fbuf[BFSZ]; X char bfr[BFSZ], *pbfr = bfr; X register char *p = NULL; X register FILE *pipe = stdout; X register int mode, frmflg, pathcnt, format; X char *index(); X X mode = SKIPPING; X frmflg = FALSE; X while (fgets(buf, BFSZ, stdin) != NULL) { X#ifdef debug X printf("%o\t%s", mode|type(buf), buf); X#endif X switch (mode | type(buf)) { X X case FROM | SKIPPING: X if (frmflg) X p = frombreak(p, buf); X else X p = fbuf; X frmflg = TRUE; X break; X X case FROM | READING: X if (!frmflg) { X frmflg = TRUE; X p = fbuf; X pclose(pipe); X } X p = frombreak(p, buf); X break; X X case NLIN | SKIPPING: X if ((isupper(buf[1]) && index(buf, ':')) || !strncmp(buf, "From ", 5)) X format = B; X else X format = A; X#ifdef debug X printf("format = %d\n", format); X#endif X mode = READING; X X case NLIN | READING: X if (frmflg) { X frmflg = FALSE; X --p; X while (p >= fbuf && *--p != '!') X ; X *++p = '\0'; X pathcnt = 0; X#ifdef IHCC X sprintf(pbfr, "%s/%s/%s", logdir(HOME), X LIBDIR, "rnews"); X#else X pbfr = RNEWS; X#endif X if ((pipe = popen(pbfr, "w")) == NULL) { X perror("uurec: popen failed"); X exit(1); X } X } X if (format == A) { X if (++pathcnt == 3) X fputs(fbuf, pipe); X fputs(buf+1, pipe); X } else { X if (!pathcnt && (!strncmp(buf+1, "From: ", 6) || !strncmp(buf+1, "From ", 5))) { X pathcnt++; X fprintf(pipe, "From: %s", fbuf); X sscanf(buf, "%s %s[^\n]", fbuf, fbuf); X fprintf(pipe, "%s\n", fbuf); X } else X fputs(buf+1, pipe); X } X break; X X case OTHER | SKIPPING: X break; X X case OTHER | READING: X pclose(pipe); X mode = SKIPPING; X } X } X if (pipe) X pclose(pipe); X exit(0); X} X Xtype(p) Xregister char *p; X{ X while (*p == ' ' || *p == '?') X ++p; X X if (*p == 'N') X return (NLIN); X X if (strncmp(p, ">From ", 6) == 0) X return (FROM); X X if (strncmp(p, "From ", 5) == 0) X return (FROM); X X return(OTHER); X} X X/* X * Get the system name out of a from line. X */ Xchar * Xfrombreak(buf, fbuf) Xregister char *buf, *fbuf; X{ X register char *p; X X /* break the line into tokens. */ X p = fbuf; X while (*++p != '\0') X switch (*p) { X case '\n': X case '\t': X case ' ': X *p = '\0'; X break; X case EOT: X goto garbled; X default:; X } X *++p = EOT; X *++p = '\0'; X X for (p=fbuf; *p != EOT || p[1] != '\0'; p += strlen(p)+1) { X if (strcmp(p, "forwarded") == 0) X return(buf); X if (strcmp(p, "remote") == 0) { X p += strlen(p)+1; X if (strcmp(p, "from") == 0) { X p += strlen(p)+1; X strcpy(buf, p); X strcat(buf, "!"); X return(buf+strlen(buf)); X } X } X } X garbled: X strcat(buf, "???!"); X return(buf+4); X} *-*-END-of-src/uurec.c-*-* echo x - src/virtterm.c sed 's/^X//' >src/virtterm.c <<'*-*-END-of-src/virtterm.c-*-*' X/* X * Virtual terminal handler for the HP-2621 terminal. X * Written by Kenneth Almquist, AGS Computers (HO 4C601, X7105). X * Modified by Stephen Hemminger, to use TERMCAP (without curses) X */ Xstatic char *SccsId = "@(#)virtterm.c 1.4 7/17/84"; X X#include <stdio.h> X#include <ctype.h> X X#define MAXPLEN 24 X#define MAXLLEN 80 X#define BOTLINE (ROWS - 1) X#define DIRTY 01 X X/* terminal escape sequences from termcap */ X#define HO _tstr[0] /* home */ X#define CL _tstr[1] /* clear screen */ X#define CD _tstr[2] /* clear to end of screen */ X#define CE _tstr[3] /* clear to end of line */ X#define xUP _tstr[4] /* up one line */ X#define DO _tstr[5] /* down one line */ X#define US _tstr[6] /* underline */ X#define UE _tstr[7] /* underline end */ X#define BT _tstr[8] /* backtab */ X#define xBC _tstr[9] /* backspace */ X#define AL _tstr[10] /* insert line */ X#define DL _tstr[11] /* delete line */ X#define CM _tstr[12] /* cursor move */ X#define CH _tstr[13] /* cursor horizontal move */ X#define CV _tstr[14] /* cursor vertical move */ X#define CS _tstr[15] /* scrolling region */ X#define SF _tstr[16] /* scroll forwards */ X#define SR _tstr[17] /* scroll backwards */ X#define TI _tstr[18] /* start cursor mode */ X#define TE _tstr[19] /* end cursor mode */ X#define TA _tstr[20] /* tab char (if not \t) */ X#define CR _tstr[21] /* carriage return (if not \r) */ X#define xPC _tstr[22] /* for reading pad character */ Xchar PC; /* pad character */ Xchar *BC, *UP; /* external variables for tgoto */ X Xstatic char sname[] = "hoclcdceupdousuebtbcaldlcmchcvcssfsrtitetacrpc"; Xchar *_tstr[23]; Xint HOlen; /* length of HO string */ X X X/* terminal flags */ X#define BS _tflg[0] /* can backspace */ X#define AM _tflg[1] /* has auto margins */ X#define XN _tflg[2] /* no newline after wrap */ X#define RET !_tflg[3] /* has carriage return */ X#define NS _tflg[4] /* has SF (scroll forward) */ X#define PT _tflg[5] /* has tabs */ X#define XT _tflg[6] /* tabs are destructive */ Xint GT = 1; /* tab stops on terminal are set */ X Xstatic char bname[] = "bsamxnncnsptxt"; Xchar _tflg[7]; X X Xextern char *tgoto(), *tgetstr(); Xextern char *getenv(), *strcpy(); X X#define ULINE 0200 X#define CURSEEN 1 X X/* Constants accessable by user */ Xint hasscroll; /* scrolling type, 0 == no scrolling */ Xint ROWS; /* number of lines on screen */ Xint COLS; /* width of screen */ X Xstruct line { X char len; X char flags; X char l[MAXLLEN]; X}; X Xint _row, _col; Xint _srow, _scol; Xstruct line _virt[MAXPLEN], _actual[MAXPLEN]; Xint _uline = 0; Xint _junked = 1; Xint _curjunked; Xint _dir = 1; Xint _shifttop, _shiftbot; Xint _shift; Xint _scratched; Xint vputc(); X X X X/* X * Tell refresh to shift lines in region upwards count lines. Count X * may be negative. The virtual image is not shifted; this may change X * later. The variable _scratched is set to supress all attempts to X * shift. X */ X Xushift(top, bot, count) { X if (_scratched) X return; X if (_shift != 0 && (_shifttop != top || _shiftbot != bot)) { X _scratched++; X return; X } X _shifttop = top; X _shiftbot = bot; X _shift += count; X} X X X X/* X * generate a beep on the terminal X */ X Xbeep() { X vputc('\7'); X} X X/* X * Move to one line below the bottom of the screen. X */ X Xbotscreen() { X _amove(BOTLINE, 0); X vputc('\n'); X vflush(); X} X X X Xmove(row, col) { X if (row < 0 || row >= ROWS || col < 0 || col >= COLS) X return; X _row = row; X _col = col; X} X X X X/* X * Output string at specified location. X */ X Xmvaddstr(row, col, str) X char *str; X { X move(row, col); X addstr(str); X} X X Xaddstr(s) Xchar *s; X{ X register char *p; X register struct line *lp; X register int col = _col; X X lp = &_virt[_row]; X if (lp->len < col) { X p = &lp->l[lp->len]; X while (lp->len < col) { X *p++ = ' '; X lp->len++; X } X } X for (p = s; *p != '\0'; p++) { X if (*p == '\n') { X lp->len = col; X lp->flags |= DIRTY; X col = 0; X if (++_row >= ROWS) X _row = 0; X lp = &_virt[_row]; X } X else { X lp->l[col] = *p; X lp->flags |= DIRTY; X if (++col >= COLS) { X lp->len = COLS; X col = 0; X if (++_row >= ROWS) X _row = 0; X lp = &_virt[_row]; X } X } X } X if (lp->len <= col) X lp->len = col; X _col = col; X} X X X Xaddch (c) { X register struct line *lp; X register char *p; X X lp = &_virt[_row]; X if (lp->len < _col) { X p = &lp->l[lp->len]; X while (lp->len < _col) { X *p++ = ' '; X lp->len++; X } X } X lp->l[_col] = c; X if (lp->len == _col) X lp->len++; X if (++_col >= COLS) { X _col = 0; X if (++_row >= ROWS) X _row = 0; X } X lp->flags |= DIRTY; X} X X X Xclrtoeol() { X register struct line *lp; X X lp = &_virt[_row]; X if (lp->len > _col) { X lp->len = _col; X lp->flags |= DIRTY; X } X} X X X/* X * Clear an entire line. X */ X Xclrline(row) { X register struct line *lp; X X lp = &_virt[row]; X if (lp->len > 0) { X lp->len = 0; X lp->flags |= DIRTY; X } X} X X X Xclear() { X erase(); X _junked++; X} X X X Xerase() { X register i; X X for (i = 0; i < ROWS; i++) { X _virt[i].len = 0; X _virt[i].flags |= DIRTY; X } X} X X X Xrefresh() { X register i; X int j, len; X register char *p, *q; X X if (checkin()) X return; X i = 1; X if (_junked) { X _sclear(); X _junked = 0; X } else if (! _scratched) { X if (_shift > 0) { X _ushift(_shifttop, _shiftbot, _shift); X } else if (_shift < 0) { X i = _dshift(_shifttop, _shiftbot, -_shift); X } else { X i = _dir; X } X } X _dir = i; X _shift = 0; X if (checkin()) X return; X _fixlines(); X for (i = _dir > 0 ? 0 : BOTLINE; i >= 0 && i < ROWS; i += _dir) { X if ((_virt[i].flags & DIRTY) == 0) X continue; X _ckclrlin(i); /* decide whether to do a clear line */ X /* probably should consider cd as well */ X len = _virt[i].len; X if (_actual[i].len < len) X len = _actual[i].len; X p = _virt[i].l; X q = _actual[i].l; X for (j = 0; j < len; j++) { X if (*p != *q) { X _amove(i, j); X _aputc(*p); X *q = *p; X } X p++, q++; X } X len = _virt[i].len; X if (_actual[i].len > len) { X _clrtoeol(i, len); X } X else { X for (; j < len; j++) { X if (*p != ' ') { X _amove(i, j); X _aputc(*p); X } X *q++ = *p++; X } X _actual[i].len = len; X } X if (checkin()) X return; X } X _dir = 1; X if (CURSEEN) X _amove(_row, _col); X vflush(); /* flush output buffer */ X _scratched = 0; X} X X X_dshift(top, bot, count) { X register i; X X if (count >= bot - top || hasscroll < 4) { /* must have CS or AL/DL */ X _scratched++; X return 1; X } X for (i = bot - count; _actual[i].len == 0; i--) X if (i == top) X return 1; X for (i = top; i <= bot; i++) X _virt[i].flags |= DIRTY; X for (i = bot; i >= top + count; i--) X _actual[i] = _actual[i - count]; X for (; i >= top; i--) X _actual[i].len = 0; X X if (hasscroll != 5) { /* can we define scrolling region, and scroll back */ X tputs(tgoto(CS, bot, top), 1, vputc);/* define scroll region */ X _curjunked = 1; X _amove(top, 0); X for (i = count; --i >= 0;) X tputs(SR, 1, vputc);/* scroll back */ X tputs(tgoto(CS, BOTLINE, 0), 1, vputc); X _curjunked = 1; X } else { X _amove(bot - count + 1, 0); X if (CD && bot == BOTLINE) X tputs(CD, 1, vputc); X else { X for (i = count; --i >= 0;) X tputs(DL, ROWS - _srow, vputc); X } X _amove(top, 0); X for (i = count; --i >= 0;) X tputs(AL, ROWS - _srow, vputc); X } X return -1; X} X X X_ushift(top, bot, count) { X register i; X X if (count >= bot - top || hasscroll == 0) { X _scratched++; X return; X } X for (i = top + count; _actual[i].len == 0; i++) X if (i == bot) X return; X if (hasscroll == 1 || hasscroll == 3) { X /* we cheat and shift the entire screen */ X /* be sure we are shifting more lines into than out of position */ X if ((bot - top + 1) - count <= ROWS - (bot - top + 1)) X return; X top = 0, bot = BOTLINE; X } X for (i = top; i <= bot; i++) X _virt[i].flags |= DIRTY; X for (i = top; i <= bot - count; i++) X _actual[i] = _actual[i + count]; X for (; i <= bot; i++) X _actual[i].len = 0; X X if (hasscroll != 5) { X if (top != 0 || bot != BOTLINE) { X tputs(tgoto(CS, bot, top), 0, vputc); X _curjunked = 1; X } X _amove(bot, 0); /* move to bottom */ X for (i = 0; i < count; i++) { X if (SF) /* scroll forward */ X tputs(SF, 1, vputc); X else X vputc('\n'); X } X if (top != 0 || bot != BOTLINE) { X tputs(tgoto(CS, BOTLINE, 0), 0, vputc); X _curjunked = 1; X } X } else { X _amove(top, 0); X for (i = count; --i >= 0;) X tputs(DL, ROWS - _srow, vputc); X if (bot < BOTLINE) { X _amove(bot - count + 1, 0); X for (i = count; --i >= 0;) X tputs(AL, ROWS - _srow, vputc); X } X } X} X X X_sclear() { X register struct line *lp; X X tputs(CL, 0, vputc); X _srow = _scol = 0; X for (lp = _actual; lp < &_actual[ROWS]; lp++) { X lp->len = 0; X } X for (lp = _virt; lp < &_virt[ROWS]; lp++) { X if (lp->len != 0) X lp->flags |= DIRTY; X } X} X X X_clrtoeol(row, col) { X register struct line *lp = &_actual[row]; X register i; X X if (CE && lp->len > col + 1) { X _amove(row, col); X tputs(CE, 1, vputc); X } else { X for (i = col ; i < lp->len ; i++) { X if (lp->l[i] != ' ') { X _amove(row, i); X _aputc(' '); X } X } X } X lp->len = col; X} X X X_fixlines() { X register struct line *lp; X register char *p; X register int i; X X for (i = 0; i < ROWS; i++) { X lp = &_virt[i]; X if (lp->flags & DIRTY) { X lp = &_virt[i]; X for (p = &lp->l[lp->len]; --p >= lp->l && *p == ' ';); X lp->len = p + 1 - lp->l; X if (lp->len == _actual[i].len && strncmp(lp->l, _actual[i].l, lp->len) == 0) X lp->flags &= ~DIRTY; X } X } X} X X X/* X * Consider clearing the line before overwriting it. X * We always clear a line if it has underlined characters in it X * because these can cause problems. Otherwise decide whether X * that will decrease the number of characters to change. This X * routine could probably be simplified with no great loss. X */ X X_ckclrlin(i) { X int eval; X int len; X int first; X register struct line *vp, *ap; X register int j; X X if (!CE) X return; X ap = &_actual[i]; X vp = &_virt[i]; X len = ap->len; X eval = -strlen(CE); X if (len > vp->len) { X len = vp->len; X eval = 0; X } X for (j = 0; j < len && vp->l[j] == ap->l[j]; j++); X if (j == len) X return; X first = j; X while (j < len) { X if (vp->l[j] == ' ') { X if (ap->l[j] != ' ') { X while (++j < len && vp->l[j] == ' ' && ap->l[j] != ' ') { X eval++; X } X if (j == len) X eval++; X continue; X } X } X else { X if (vp->l[j] == ap->l[j]) { X while (++j < len && vp->l[j] == ap->l[j]) { X eval--; X } X continue; X } X } X j++; X } X if (US) { X for (j = 0 ; j < ap->len ; j++) { X if (ap->l[j] & ULINE) { X eval = 999; X if (first > j) X first = j; X break; X } X } X } X for (j = first; --j >= 0;) X if (vp->l[j] != ' ') X break; X if (j < 0) X first = 0; X if (eval > 0) { X _amove(i, first); X tputs(CE, 0, vputc); X _actual[i].len = first; X } X} X X X X/* X * Move routine X * first compute direct cursor address string and cost X * then relative motion string and cost, X * then home then relative and cost X * choose smallest and do it. X * X * The plod stuff is to build the strings (with padding) then decide X */ Xstatic char *plodstr; /* current location in relmove string */ X Xplodput(c) { *plodstr++ = c; } X X_amove(row, col) { X char direct[20]; X char rel[MAXPLEN*10 + MAXLLEN*10]; /* longest move is full screen */ X char ho[MAXPLEN*10 + MAXLLEN*10]; X int cost, newcost; X register char *movstr; X X if (row == _srow && col == _scol && _curjunked == 0) X return; X _setul(0); X X cost = 999; X if (CM) { X plodstr = direct; X tputs(tgoto(CM, col, row), 0, plodput); X *plodstr = '\0'; X cost = plodstr - direct; X movstr = direct; X } X if (_curjunked == 0) { X plodstr = rel; X if (_vmove(_srow, row) >= 0 X && _hmove(_scol, col, row) >= 0 X && (newcost = plodstr - rel) < cost) { X *plodstr = '\0'; X cost = newcost; X movstr = rel; X } X } X if (cost > HOlen) { /* is it worth calculating */ X plodstr = ho; X tputs(HO, 0, plodput); X if (_vmove(0, row) >= 0 X && _hmove(0, col, row) >= 0 X && (newcost = plodstr - ho) < cost) { X *plodstr = '\0'; X cost = newcost; X movstr = ho; X } X } X X while (--cost >= 0) { X vputc(*movstr++); X } X _srow = row, _scol = col; X _curjunked = 0; X} X X X_vmove(orow, nrow) { X char direct[128]; X char *saveplod = plodstr; X X if (CV) { X plodstr = direct; X tputs(tgoto(CV, nrow, nrow), 0, plodput); X *plodstr = '\0'; X plodstr = saveplod; X } X if (orow > nrow) { /* cursor up */ X if (! UP) X return -1; X while (orow > nrow) { X tputs(UP, 1, plodput); X orow--; X } X } X while (orow < nrow) { /* cursor down */ X if (DO) X tputs(DO, 1, plodput); X else X *plodstr++ = '\n'; X orow++; X } X if (CV && plodstr - saveplod >= strlen(direct)) { X register char *p; X plodstr = saveplod; X for (p = direct ; *plodstr = *p++ ; plodstr++); X } X return 0; X} X X X_hmove(ocol, ncol, row) { X char direct[128]; X char ret[MAXLLEN*10]; X char *saveplod = plodstr; X char *movstr; X int cost, newcost; X X cost = 999; X if (CH) { X plodstr = direct; X tputs(tgoto(CH, ncol, ncol), 0, plodput); X cost = plodstr - direct; X movstr = direct; X plodstr = saveplod; X } X if (RET && ocol > ncol) { /* consider doing carriage return */ X plodstr = ret; X if (CR) X tputs(CR, 1, plodput); X else X *plodstr++ = '\r'; X if (_relhmove(0, ncol, row) >= 0 X && (newcost = plodstr - ret) < cost) { X cost = newcost; X movstr = ret; X } X plodstr = saveplod; X } X if (_relhmove(ocol, ncol, row) < 0) { X if (cost == 999) X return -1; X goto copy; X } X if (plodstr - saveplod > cost) { Xcopy: plodstr = saveplod; X while (--cost >= 0) X *plodstr++ = *movstr++; X } X return 0; X} X X X X_relhmove(ocol, ncol, row) { X int tab; X X if (ocol < ncol && PT && GT) { /* tab (nondestructive) */ X while ((tab = (ocol + 8) & ~07) <= ncol) { X if (TA) X tputs(TA, 1, plodput); X else X *plodstr++ = '\t'; X ocol = tab; X } X if (tab < COLS && tab - ncol < ncol - ocol) { X if (TA) X tputs(TA, 1, plodput); X else X *plodstr++ = '\t'; X ocol = tab; X } X } else if (BT && GT && ocol > ncol) { /* backwards tab */ X while ((tab = (ocol - 1) &~ 07) >= ncol) { X if (BS && tab == ocol - 1) { X if (BC) X tputs(BC, 1, plodput); X else X *plodstr++ = '\b'; X } else X tputs(BT, 1, plodput); X ocol = tab; X } X if (ncol - tab + 1 < ocol - ncol) { X tputs(BT, 1, plodput); X ocol = tab; X } X } X if (ocol > ncol) { /* cursor left */ X if (! BS) X return -1; X while (ocol > ncol) { X if (BC != NULL) X tputs(BC, 1, plodput); X else X *plodstr++ = '\b'; X ocol--; X } X } X if (ocol < ncol) { /* cursor right */ X register struct line *lp = &_actual[row]; X /* X * This code doesn't move over underlined characters properly, X * but in practice this doesn't seem to matter. X */ X while (ocol < ncol) { X if (ocol < lp->len) X *plodstr++ = lp->l[ocol]; X else X *plodstr++ = ' '; X ocol++; X } X } X return 0; X} X X X X_aputc(c) { X if (AM && _scol == COLS - 1 && _srow == ROWS - 1) X return; X _setul(c & ULINE); X vputc(c & ~ULINE); X if (++_scol >= COLS) { X if (! AM) { X _scol--; X } else if (XN) { X _curjunked++; X } else { X _scol = 0; X ++_srow; X } X } X} X X X_setul(on) { X if (on) { X if (_uline == 0 && US != NULL) { X tputs(US, 1, vputc); X _uline = 1; X } X } X else { X if (_uline != 0 && UE != NULL) { X tputs(UE, 1, vputc); X _uline = 0; X } X } X} X X X/* X * Initialize termcap strings for later use. X */ Xinitterm() { X static char tcbuf[1024]; /* termcap buffer */ X register char *cp; X X if ((cp = getenv("TERM")) == NULL) X xerror("TERM not set in environment"); X X switch (tgetent(tcbuf, cp)) { X case 0: X xerror("Terminal not found in TERMCAP"); X case -1: X xerror("Can't open /etc/termcap"); X case 1: X break; X } X X if ((ROWS = tgetnum("li")) == -1 X || (COLS = tgetnum("co")) == -1) X xerror("Can't get screen size"); X _zap(); X X if (CL == NULL) X xerror ("No clear screen defined"); X X if (HO == NULL && CM == NULL) X xerror("No home or cursor addressing"); X if (HO) X HOlen = strlen(HO); X else X HOlen = 999; X X PC = xPC ? xPC[0] : 0; X BC = xBC; X UP = xUP; X X if (tgetnum("ug") > 0) X US = UE = NULL; X X if (XT) /* Destructive tab code not included */ X PT = 0; /* to keep things simple */ X X if (ROWS > MAXPLEN) X ROWS = MAXPLEN; X if (COLS > MAXLLEN) { X COLS = MAXLLEN; X AM = XN = 1; X } X X /* Select article scrolling algorithm. We prefer scrolling region X over insert/delete line because it's faster on the HP */ X hasscroll = 0; X if (!NS) { X hasscroll = 1; X if (SR) X hasscroll = 3; X if (CS) X hasscroll++; X } X if (AL && DL && hasscroll != 4) X hasscroll = 5; X} X X Xrawterm() { X if (TI != NULL) X tputs(TI, 0, vputc); X} X X Xcookedterm() { X if (TE != NULL) X tputs(TE, 0, vputc); X} X X X/* get strings from termcap */ X_zap() { X static char tstrbuf[1024]; X static char *tp; X register char *namp, **sp, *bp; X X tp = tstrbuf; X sp = _tstr; X for (namp = sname; *namp; namp += 2) { X *sp++ = tgetstr(namp, &tp); X } X bp = _tflg; X for (namp = bname; *namp; namp += 2) { X *bp++ = tgetflag(namp, &tp); X } X} *-*-END-of-src/virtterm.c-*-* exit