|
|
1.1 ! root 1: /* ! 2: * visual - visual news interface. ! 3: * Kenneth Almquist ! 4: */ ! 5: ! 6: #ifdef SCCSID ! 7: static char *SccsId = "@(#)visual.c 1.28 3/19/86"; ! 8: #endif /* SCCSID */ ! 9: ! 10: #include "rparams.h" ! 11: #ifdef USG ! 12: #include <sys/ioctl.h> ! 13: #include <termio.h> ! 14: #include <fcntl.h> ! 15: #else /* !USG */ ! 16: #include <sgtty.h> ! 17: #endif /* !USG */ ! 18: ! 19: #include <errno.h> ! 20: #if defined(BSD4_2) || defined(BSD4_1C) ! 21: #include <sys/dir.h> ! 22: #else ! 23: #include "ndir.h" ! 24: #endif ! 25: #ifdef BSD4_2 ! 26: #ifndef sigmask ! 27: #define sigmask(m) (1<<((m)-1)) ! 28: #endif /* !sigmask */ ! 29: #endif /* BSD4_2 */ ! 30: #ifdef MYDB ! 31: #include "db.h" ! 32: #endif /* MYDB */ ! 33: ! 34: extern int errno; ! 35: ! 36: #ifdef SIGTSTP ! 37: #include <setjmp.h> ! 38: #endif /* SIGTSTP */ ! 39: ! 40: #define ARTWLEN (ROWS-2)/* number of lines used to display article */ ! 41: #define even(cols) ((cols&1) ? cols + 1 : cols) ! 42: #ifdef STATTOP ! 43: #define PRLINE 0 /* prompter line */ ! 44: #define SPLINE 1 /* secondary prompt line */ ! 45: #define ARTWIN 2 /* first line of article window */ ! 46: #define SECPRLEN 81 /* length of secondary prompter */ ! 47: #else ! 48: #define PRLINE (ROWS-1)/* prompter line */ ! 49: #define SPLINE (ROWS-2)/* secondary prompt line */ ! 50: #define ARTWIN 0 /* first line of article window */ ! 51: #define SECPRLEN 100 /* length of secondary prompter */ ! 52: #endif ! 53: ! 54: #define PIPECHAR '|' /* indicate save command should pipe to program */ ! 55: #define META 0200 /* meta character bit (as in emacs) */ ! 56: /* print (display) flags */ ! 57: #define HDRONLY 0001 /* print header only */ ! 58: #define NOPRT 0002 /* don't print at all */ ! 59: #define NEWART 0004 /* force article display to be regenerated */ ! 60: #define HELPMSG 0010 /* display currently contains help message */ ! 61: /* prun flags */ ! 62: #define CWAIT 0001 /* type "continue?" and wait for return */ ! 63: #define BKGRND 0002 /* run process in the background */ ! 64: /* values of curflag */ ! 65: #define CURP1 1 /* cursor after prompt */ ! 66: #define CURP2 2 /* cursor after secondary prompt */ ! 67: #define CURHOME 3 /* cursor at home position */ ! 68: /* flags for vsave routine */ ! 69: #define SVHEAD 01 /* write out article header */ ! 70: #define OVWRITE 02 /* overwrite the file if it already exists */ ! 71: /* other files */ ! 72: ! 73: #define saveart oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hptr = h;h = hold;hold = hptr;ongsize = pngsize ! 74: #define NLINES(h, fp) (h->numlines[0] ? h->intnumlines : (h->intnumlines=linecnt(fp),sprintf(h->numlines, "%d", h->intnumlines), h->intnumlines)) ! 75: ! 76: /* terminal handler stuff */ ! 77: extern int _junked; ! 78: #define clearok(xxx, flag) _junked = flag ! 79: extern int COLS; ! 80: extern int ROWS; ! 81: extern int hasscroll; ! 82: ! 83: FILE *tmpfile(); ! 84: char *getmailname(); ! 85: #ifdef MYDB ! 86: char *findparent(); ! 87: #endif /* MYDB */ ! 88: int onint(); ! 89: int onstop(); ! 90: int xxit(); ! 91: ! 92: char *Progname = "vnews"; /* for xerror */ ! 93: ! 94: /* variables shared between vnews routines */ ! 95: static char linebuf[LBUFLEN]; /* temporary workspace */ ! 96: static FILE *tfp; /* temporary file */ ! 97: static char tfname[] = "/tmp/vnXXXXXX"; /* name of temp file */ ! 98: static long artbody; /* offset of body into article */ ! 99: static int quitflg; /* if set, then quit */ ! 100: static int erased; /* current article has been erased */ ! 101: static int artlines; /* # lines in article body */ ! 102: static int artread; /* entire article has been read */ ! 103: static int hdrstart; /* beginning of header */ ! 104: static int hdrend; /* end of header */ ! 105: static int lastlin; /* number of lines in tempfile */ ! 106: static int tflinno = 0; /* next line in tempfile */ ! 107: static int maxlinno; /* number of lines in file + folded */ ! 108: static char secpr[SECPRLEN]; /* secondary prompt */ ! 109: static char prompt[30]; /* prompter */ ! 110: static short prflags; /* print flags (controls updscr) */ ! 111: static short curflag; /* where to locate cursor */ ! 112: static int dlinno; /* top line on screen */ ! 113: static char timestr[20]; /* current time */ ! 114: static int ismail; /* true if user has mail */ ! 115: static char *mailf; /* user's mail file */ ! 116: static int alflag; /* set if unprocessed alarm signal */ ! 117: static int atend; /* set if at end of article */ ! 118: static char cerase; /* erase character */ ! 119: static char ckill; /* kill character */ ! 120: static char cintr; /* interrupt character */ ! 121: #ifdef TIOCGLTC ! 122: static char cwerase; /* word erase character */ ! 123: #endif /* TIOCGLTC */ ! 124: short ospeed; /* terminal speed NOT STATIC */ ! 125: static int intflag; /* set if interrupt received */ ! 126: ! 127: #ifdef SIGTSTP ! 128: static int reading; /* to keep stupid BSD from restarting reads */ ! 129: jmp_buf intjmp, alrmjmp; ! 130: #endif /* SIGTSTP */ ! 131: ! 132: #ifdef MYDB ! 133: static int hasdb; /* true if article data base exists */ ! 134: #endif /* MYDB */ ! 135: ! 136: #ifdef DIGPAGE ! 137: static int endsuba; /* end of sub-article in digest */ ! 138: #endif ! 139: ! 140: #ifdef MYDEBUG ! 141: FILE *debugf; /* file to write debugging info on */ ! 142: #endif ! 143: ! 144: char *tft = "/tmp/folXXXXXX"; ! 145: ! 146: /* ! 147: * These were made static for u370 with its buggy cc. ! 148: * I judged it better to have one copy with no ifdefs than ! 149: * to conditionally compile them as automatic variables ! 150: * in readr (which they originally were). Performance ! 151: * considerations might warrant moving some of the simple ! 152: * things into register variables, but I don't know what ! 153: * breaks the u370 cc. ! 154: */ ! 155: static char goodone[BUFLEN]; /* last decent article */ ! 156: static char ogroupdir[BUFLEN]; /* last groupdir */ ! 157: static char edcmdbuf[128]; ! 158: static int rfq = 0; /* for last article */ ! 159: static long ongsize; /* Previous ngsize */ ! 160: static long pngsize; /* Printing ngsize */ ! 161: static char *bptr; /* temp pointer. */ ! 162: static char *tfilename; /* temporary file name */ ! 163: static char ofilename1[BUFLEN]; /* previous file name */ ! 164: static struct hbuf hbuf1, hbuf2; /* for minusing */ ! 165: static struct hbuf *h = &hbuf1, /* current header */ ! 166: *hold = &hbuf2, /* previous header */ ! 167: *hptr; /* temporary */ ! 168: static char *ptr1, *ptr2, *ptr3; /* for reply manipulation */ ! 169: static int aabs = FALSE; /* TRUE if we asked absolutely */ ! 170: static char *ed, tf[100]; ! 171: static long oobit; /* last bit, really */ ! 172: static int dgest = 0; ! 173: static FILE *fp; /* current article to be printed*/ ! 174: ! 175: readr() ! 176: { ! 177: ! 178: #ifdef MYDEBUG ! 179: debugf = fopen("DEBUG", "w"); ! 180: setbuf(debugf, (char *)NULL); ! 181: #endif ! 182: if (aflag) { ! 183: if (*datebuf) { ! 184: if ((atime = cgtdate(datebuf)) == -1) ! 185: xerror("Cannot parse date string"); ! 186: } else ! 187: atime = 0; ! 188: } ! 189: ! 190: if (SigTrap) ! 191: xxit(1); ! 192: (void) mktemp(tfname); ! 193: (void) close(creat(tfname,0666)); ! 194: if ((tfp = fopen(tfname, "w+")) == NULL) ! 195: xerror("Can't create temp file"); ! 196: (void) unlink(tfname); ! 197: mailf = getmailname(); ! 198: #ifdef MYDB ! 199: if (opendb() >= 0) { ! 200: hasdb = 1; ! 201: fputs("Using article data base\n", stderr); /*DEBUG*/ ! 202: getng(); ! 203: } ! 204: #endif ! 205: ttysave(); ! 206: (void) signal(SIGINT, onint); ! 207: (void) signal(SIGQUIT, xxit); ! 208: if (SigTrap) ! 209: xxit(1); ! 210: ttyraw(); ! 211: timer(); ! 212: ! 213: /* loop reading articles. */ ! 214: fp = NULL; ! 215: obit = -1; ! 216: nextng(); ! 217: quitflg = 0; ! 218: while (quitflg == 0) { ! 219: if (getnextart(FALSE)) ! 220: break; ! 221: (void) strcpy(goodone, filename); ! 222: if (SigTrap) ! 223: return; ! 224: vcmd(); ! 225: } ! 226: ! 227: if (!news) { ! 228: if (!checkngs(header.nbuf, actfp)) ! 229: fprintf(stderr, "No news.\n"); ! 230: } ! 231: } ! 232: ! 233: /* ! 234: * Read and execute a command. ! 235: */ ! 236: vcmd() { ! 237: register c; ! 238: char *p; ! 239: long count; ! 240: int countset; ! 241: ! 242: appfile(fp, dlinno + ARTWLEN + 1); ! 243: #ifdef DIGPAGE ! 244: endsuba = findend(dlinno); ! 245: if (artlines > dlinno + ARTWLEN ! 246: || endsuba > 0 && endsuba < artlines ! 247: #else ! 248: if (artlines > dlinno + ARTWLEN ! 249: #endif ! 250: || (prflags & HDRONLY) && artlines > hdrend) { ! 251: atend = 0; ! 252: if (prflags&HDRONLY || maxlinno == 0) ! 253: (void) strcpy(prompt, "more? "); ! 254: else ! 255: #ifdef DIGPAGE ! 256: (void) sprintf(prompt, "more(%d%%)? ", ! 257: ((((endsuba > 0) ? ! 258: endsuba : (dlinno + ARTWLEN)) - ! 259: hdrend) * 100) / maxlinno); ! 260: #else /* !DIGPAGE */ ! 261: (void) sprintf(prompt, "more(%d%%)? ", ! 262: ((dlinno + ARTWLEN - hdrend) * 100) / maxlinno); ! 263: #endif /* !DIGPAGE */ ! 264: } else { ! 265: atend = 1; ! 266: (void) strcpy(prompt, "next? "); ! 267: if (!erased) ! 268: clear(bit); /* article read */ ! 269: } ! 270: curflag = CURP1; ! 271: p = prompt + strlen(prompt); ! 272: countset = 0; ! 273: count = 0; ! 274: /* ! 275: * Loop while accumulating a count, until an action character ! 276: * is entered. Also handle "meta" here. ! 277: * ! 278: * Count is the current count. Countset=0 means no count ! 279: * currently exists. Countset=1, count=0 is valid and means ! 280: * a count of 0 has been entered ! 281: */ ! 282: for (;;) { ! 283: c = vgetc(); ! 284: if (c == cerase || c == '\b' || c == '\177') { ! 285: if (countset == 0) ! 286: break; /* Use as action char */ ! 287: if (count < 10) ! 288: countset = 0; /* Erase only char of count */ ! 289: else ! 290: count /= 10L; /* Erase 1 char of count */ ! 291: } else { ! 292: #ifdef TIOCGLTC ! 293: if (c == ckill || c == cwerase) { ! 294: #else ! 295: if (c == ckill) { ! 296: #endif ! 297: if (countset == 0) ! 298: break; ! 299: countset = 0; ! 300: } else if (c < '0' || c > '9') ! 301: break; ! 302: else { ! 303: countset = 1; ! 304: count = (count * 10) + (c - '0'); ! 305: } ! 306: } ! 307: if (countset) { ! 308: (void) sprintf(p, "%ld", count); ! 309: } else { ! 310: *p = '\0'; ! 311: count = 0; ! 312: } ! 313: } ! 314: ! 315: if (c == '\033') { /* escape */ ! 316: (void) strcat(prompt, "M-"); ! 317: c = vgetc(); ! 318: if (c != cintr) ! 319: c |= META; ! 320: } ! 321: secpr[0] = '\0'; ! 322: if (countset == 0) ! 323: count = 1; ! 324: docmd(c, count); ! 325: if (c != '?' && c != 'H') /* UGGH */ ! 326: prflags &=~ HELPMSG; ! 327: if (dlinno > hdrstart) ! 328: prflags &=~ HDRONLY; ! 329: } ! 330: ! 331: ! 332: /* ! 333: * Process one command, which has already been typed in. ! 334: */ ! 335: docmd(c, count) ! 336: int c; ! 337: long count; ! 338: { ! 339: int i; ! 340: long nart, Hoffset; ! 341: char *findhist(); ! 342: ! 343: switch (c) { ! 344: ! 345: /* Show more of current article, or advance to next article */ ! 346: case '\n': ! 347: case ' ': ! 348: #ifdef DIGPAGE ! 349: case 'm': ! 350: #endif /* DIGPAGE */ ! 351: case '\06': /* Control-F for vi compat */ ! 352: prflags &=~ NOPRT; ! 353: if (atend) ! 354: goto next; ! 355: else if (prflags & HDRONLY) { ! 356: prflags &=~ HDRONLY; ! 357: if (hasscroll) ! 358: dlinno = hdrstart;} ! 359: #ifdef DIGPAGE ! 360: else if (endsuba > 0) ! 361: dlinno = endsuba; ! 362: else if (c == 'm') { ! 363: do { ! 364: if (lastlin >= maxlinno) ! 365: goto next; ! 366: else ! 367: appfile(fp, lastlin + 1); ! 368: } while(strncmp(linebuf, "------------------------", 24) ! 369: != 0); ! 370: dlinno = endsuba = lastlin; ! 371: } ! 372: #endif ! 373: else if ((appfile(fp, dlinno + 2 * ARTWLEN), artread) ! 374: && hasscroll && artlines - dlinno <= ARTWLEN + 2) ! 375: dlinno = artlines - ARTWLEN; ! 376: else ! 377: dlinno += ARTWLEN * count; ! 378: break; ! 379: ! 380: /* No. Go on to next article. */ ! 381: case '.': /* useful if you have a keypad */ ! 382: next: case 'n': ! 383: readmode = NEXT; ! 384: FCLOSE(fp); ! 385: clear(bit); ! 386: saveart; ! 387: nextbit(); ! 388: break; ! 389: ! 390: ! 391: /* Back up count pages */ ! 392: case '\b': ! 393: case '\177': ! 394: if (dlinno == 0) ! 395: goto backupone; ! 396: /* NO BREAK */ ! 397: case META|'v': ! 398: case '\002': /* Control-B */ ! 399: dlinno -= ARTWLEN * count; ! 400: if (dlinno < 0) ! 401: dlinno = 0; ! 402: break; ! 403: ! 404: /* forward half a page */ ! 405: case '\004': /* Control-D, as in vi */ ! 406: if (!atend) ! 407: dlinno += ARTWLEN/2 * count; ! 408: break; ! 409: ! 410: /* backward half a page */ ! 411: case '\025': /* Control-U */ ! 412: dlinno -= ARTWLEN/2 * count; ! 413: if (dlinno < 0) ! 414: dlinno = 0; ! 415: break; ! 416: ! 417: /* forward count lines */ ! 418: case '\016': /* Control-N */ ! 419: case '\005': /* Control-E */ ! 420: dlinno += count; ! 421: break; ! 422: ! 423: /* backwards count lines */ ! 424: case '\020': /* Control-P */ ! 425: case '\031': /* Control-Y */ ! 426: dlinno -= count; ! 427: if (dlinno < 0) ! 428: dlinno = 0; ! 429: break; ! 430: ! 431: /* Turn displaying of article back on */ ! 432: case 'l': ! 433: case 'd': ! 434: prflags &=~ NOPRT; ! 435: break; ! 436: ! 437: /* display header */ ! 438: case 'h': ! 439: dlinno = hdrstart; ! 440: prflags |= HDRONLY; ! 441: prflags &=~ NOPRT; ! 442: break; ! 443: ! 444: /* ! 445: * Unsubscribe to the newsgroup and go on to next group ! 446: */ ! 447: ! 448: case 'U': ! 449: case 'u': ! 450: strcat(prompt, "u"); ! 451: c = vgetc(); ! 452: if (c == 'g') { ! 453: obit = -1; ! 454: FCLOSE(fp); ! 455: zapng = TRUE; ! 456: saveart; ! 457: if (nextng()) { ! 458: if (actdirect == BACKWARD) ! 459: msg("Can't back up."); ! 460: else ! 461: quitflg = 1; /* probably unnecessary */ ! 462: } ! 463: } else { ! 464: if (c != cintr && c != ckill) ! 465: msg("Illegal command"); ! 466: } ! 467: break; ! 468: ! 469: /* Print the current version of news */ ! 470: case 'v': ! 471: msg("News version: %s", news_version); ! 472: break; ! 473: ! 474: ! 475: /* Decrypt joke. Always does rot 13 */ ! 476: case 'D': ! 477: appfile(fp, 32767); ! 478: for (i = hdrend ; i < artlines ; i++) { ! 479: register char ch, *p; ! 480: tfget(linebuf, i); ! 481: for (p = linebuf ; (ch = *p) != '\0' ; p++) { ! 482: if (ch >= 'a' && ch <= 'z') ! 483: *p = (ch - 'a' + 13) % 26 + 'a'; ! 484: else if (ch >= 'A' && ch <= 'Z') ! 485: *p = (ch - 'A' + 13) % 26 + 'A'; ! 486: } ! 487: tfput(linebuf, i); ! 488: } ! 489: prflags |= NEWART; ! 490: prflags &=~ (HDRONLY|NOPRT); ! 491: break; ! 492: ! 493: /* write out the article someplace */ ! 494: /* w writes out without the header */ ! 495: case 's': ! 496: case 'w': { ! 497: char *grn = groupdir; ! 498: int wflags; ! 499: ! 500: msg("file: "); ! 501: curflag = CURP2; ! 502: while ((wflags = vgetc()) == ' '); ! 503: if (wflags == cintr) { ! 504: secpr[0] = '\0'; ! 505: break; ! 506: } ! 507: if (wflags == '|') { ! 508: linebuf[0] = '|'; ! 509: if (prget("| ", linebuf+1)) ! 510: break; ! 511: } else { ! 512: pushback(wflags); ! 513: if (prget("file: ", linebuf)) ! 514: break; ! 515: } ! 516: wflags = 0; ! 517: if (c == 's') ! 518: wflags |= SVHEAD; ! 519: if (count != 1) ! 520: wflags |= OVWRITE; ! 521: bptr = linebuf; ! 522: while( *bptr == ' ') ! 523: bptr++; /* strip leading spaces */ ! 524: ! 525: if (*bptr != PIPECHAR && *bptr != '/') { ! 526: char hetyped[BUFLEN]; ! 527: char *boxptr; ! 528: (void) strcpy(hetyped, bptr); ! 529: if (hetyped[0] == '~' && hetyped[1] == '/') { ! 530: strcpy(hetyped, bptr+2); ! 531: strcpy(bptr, userhome); ! 532: } else if (boxptr = getenv("NEWSBOX")) { ! 533: if (index(boxptr, '%')) { ! 534: struct stat stbf; ! 535: sprintf(bptr, boxptr, grn); ! 536: if (stat(bptr,&stbf) < 0) { ! 537: if (mkdir(bptr, 0777) < 0) { ! 538: msg("Cannot create directory %s", bptr); ! 539: break; ! 540: } ! 541: } else if ((stbf.st_mode&S_IFMT) != S_IFDIR) { ! 542: msg("%s not a directory", bptr); ! 543: break; ! 544: } ! 545: } else ! 546: strcpy(bptr, boxptr); ! 547: } else ! 548: bptr[0] = '\0'; ! 549: ! 550: if (bptr[0]) ! 551: (void) strcat(bptr, "/"); ! 552: if (hetyped[0] != '\0') ! 553: (void) strcat(bptr, hetyped); ! 554: else ! 555: (void) strcat(bptr, "Articles"); ! 556: } ! 557: vsave(bptr, wflags); ! 558: break; ! 559: } ! 560: ! 561: /* back up */ ! 562: case '-': ! 563: caseminus: ! 564: aabs = TRUE; ! 565: if (!*ofilename1) { ! 566: msg("Can't back up."); ! 567: break; ! 568: } ! 569: FCLOSE(fp); ! 570: hptr = h; ! 571: h = hold; ! 572: hold = hptr; ! 573: (void) strcpy(bfr, filename); ! 574: (void) strcpy(filename, ofilename1); ! 575: (void) strcpy(ofilename1, bfr); ! 576: obit = bit; ! 577: if (strcmp(groupdir, ogroupdir)) { ! 578: (void) strcpy(bfr, groupdir); ! 579: selectng(ogroupdir, FALSE, FALSE); ! 580: (void) strcpy(groupdir, ogroupdir); ! 581: (void) strcpy(ogroupdir, bfr); ! 582: ngrp = 1; ! 583: back(); ! 584: } ! 585: bit = oobit; ! 586: oobit = obit; ! 587: obit = -1; ! 588: getnextart(TRUE); ! 589: break; ! 590: ! 591: /* skip forwards */ ! 592: case '+': ! 593: case '=': ! 594: caseplus: if (count == 0) ! 595: break; ! 596: saveart; ! 597: last = bit; ! 598: for (i = 0; i < count; i++) { ! 599: nextbit(); ! 600: if ((bit > pngsize) || (rflag && bit < 1)) ! 601: break; ! 602: } ! 603: FCLOSE(fp); ! 604: obit = -1; ! 605: break; ! 606: ! 607: /* exit - time updated to that of most recently read article */ ! 608: case 'q': ! 609: quitflg = 1; ! 610: break; ! 611: ! 612: case 'x': ! 613: xxit(0); ! 614: break; ! 615: ! 616: /* cancel the article. */ ! 617: case 'c': ! 618: strcpy(prompt, "cancel [n]? "); ! 619: if (vgetc() != 'y') { ! 620: msg("Article not cancelled"); ! 621: break; ! 622: } ! 623: cancel_command(); ! 624: break; ! 625: ! 626: /* escape to shell */ ! 627: case '!': { ! 628: register char *p; ! 629: int flags; ! 630: ! 631: p = linebuf; ! 632: if (prget("!", p)) ! 633: break; ! 634: flags = CWAIT; ! 635: if (*p == '\0') { ! 636: (void) strcpy(linebuf, SHELL); ! 637: flags = 0; ! 638: } ! 639: while (*p) p++; ! 640: while (p > linebuf && p[-1] == ' ') ! 641: p--; ! 642: if (*--p == '&') { ! 643: *p = '\0'; ! 644: flags = BKGRND; ! 645: } else if (*p == '|') { ! 646: *p = '\0'; ! 647: (void) sprintf(bfr, "(%s)|mail '%s'", linebuf, username); ! 648: (void) strcpy(linebuf, bfr); ! 649: flags |= BKGRND; ! 650: } else { ! 651: prflags |= NOPRT; ! 652: } ! 653: shcmd(linebuf, flags); ! 654: break; ! 655: } ! 656: ! 657: /* mail reply */ ! 658: case 'r': ! 659: reply(FALSE); ! 660: break; ! 661: ! 662: case 'R': ! 663: reply(TRUE); ! 664: break; ! 665: ! 666: case META|'r': ! 667: direct_reply(); ! 668: break; ! 669: ! 670: /* next newsgroup */ ! 671: case 'N': ! 672: FCLOSE(fp); ! 673: if (next_ng_command()) ! 674: quitflg = 1; ! 675: break; ! 676: ! 677: /* mark the rest of the articles in this group as read */ ! 678: case 'K': ! 679: saveart; ! 680: while (bit <= ngsize && bit >= minartno) { ! 681: clear(bit); ! 682: nextbit(); ! 683: } ! 684: FCLOSE(fp); ! 685: break; ! 686: ! 687: /* Print the full header */ ! 688: case 'H': ! 689: if (fp == NULL) { ! 690: msg("No current article"); ! 691: break; ! 692: } ! 693: move(ARTWIN, 0); ! 694: Hoffset = ftell(fp); ! 695: (void) fseek(fp, 0L, 0); ! 696: for (i = 0; i < ARTWLEN; i++) { ! 697: if (fgets(linebuf, COLS, fp) == NULL) ! 698: break; ! 699: if (linebuf[0] == '\n') ! 700: break; ! 701: linebuf[COLS] = '\0'; ! 702: addstr(linebuf); ! 703: } ! 704: (void) fseek(fp, Hoffset, 0); ! 705: for(; i < ARTWLEN; i++) ! 706: addstr(linebuf); ! 707: prflags |= HELPMSG|NEWART; ! 708: break; ! 709: case 'b': /* backup 1 article */ ! 710: backupone: ! 711: count = bit - 1; ! 712: /* NO BREAK */ ! 713: ! 714: case 'A': /* specific number */ ! 715: if (count > pngsize) { ! 716: msg("not that many articles"); ! 717: break; ! 718: } ! 719: readmode = SPEC; ! 720: aabs = TRUE; ! 721: bit = count; ! 722: obit = -1; ! 723: FCLOSE(fp); ! 724: break; ! 725: ! 726: /* display parent article */ ! 727: case 'p': ! 728: #ifdef MYDB ! 729: if (hasdb && (ptr3 = findparent(h->ident, &nart)) != NULL) { ! 730: msg("parent: %s/%ld", ptr3, nart); /*DEBUG*/ ! 731: updscr(); /*DEBUG*/ ! 732: goto selectart; ! 733: } ! 734: #endif ! 735: if (h->followid[0] == '\0') { ! 736: msg("no references line"); ! 737: break; ! 738: } ! 739: ptr1 = h->followid + strlen(h->followid); ! 740: do { ! 741: ptr2 = ptr1; ! 742: if (*ptr2 == '\0') ! 743: ptr1 = rindex(h->followid, ' '); ! 744: else { ! 745: *ptr2 = '\0'; ! 746: ptr1 = rindex(h->followid, ' '); ! 747: *ptr2 = ' '; ! 748: } ! 749: } while (ptr1 != NULL && --count > 0); ! 750: if (ptr1 == NULL) ! 751: ptr1 = h->followid; ! 752: else ++ptr1; ! 753: (void) strncpy(linebuf, ptr1, ptr2 - ptr1); ! 754: linebuf[ptr2 - ptr1] = '\0'; ! 755: msg("%s", linebuf); ! 756: curflag = CURP2; ! 757: updscr(); /* may take this out later */ ! 758: goto searchid; ! 759: /* specific message ID. */ ! 760: case '<': ! 761: /* could improve this */ ! 762: linebuf[0] = '<'; ! 763: if (prget("<", linebuf+1)) ! 764: break; ! 765: searchid: secpr[0] = '\0'; ! 766: if (index(linebuf, '@') == NULL && index(linebuf, '>') == NULL) { ! 767: ptr1 = linebuf; ! 768: if (*ptr1 == '<') ! 769: ptr1++; ! 770: ptr2 = index(ptr1, '.'); ! 771: if (ptr2 != NULL) { ! 772: *ptr2++ = '\0'; ! 773: (void) sprintf(bfr, "<%s@%s.UUCP>", ptr2, ptr1); ! 774: (void) strcpy(linebuf, bfr); ! 775: } ! 776: } ! 777: if (index(linebuf, '>') == NULL) ! 778: (void) strcat(linebuf, ">"); ! 779: ! 780: ptr1 = findhist(linebuf); ! 781: if (ptr1 == NULL) { ! 782: msg("%s not found", linebuf); ! 783: break; ! 784: } ! 785: ptr2 = index(ptr1, '\t'); ! 786: ptr3 = index(++ptr2, '\t'); ! 787: ptr2 = index(++ptr3, ' '); ! 788: if (ptr2) ! 789: *ptr2 = '\0'; ! 790: ptr2 = index(ptr3, '/'); ! 791: if (!ptr2) { ! 792: if (strcmp(++ptr3, "cancelled") == 0) ! 793: msg("%s has been cancelled", linebuf); ! 794: else ! 795: msg("%s has expired", linebuf); ! 796: break; ! 797: } ! 798: *ptr2++ = '\0'; ! 799: (void) sscanf(ptr2, "%ld", &nart); ! 800: ! 801: /* ! 802: * Go to a given article. Ptr3 specifies the newsgroup ! 803: * and nart specifies the article number. ! 804: */ ! 805: #ifdef MYDB ! 806: selectart: ! 807: #endif /* MYDB */ ! 808: aabs = TRUE; ! 809: FCLOSE(fp); ! 810: saveart; ! 811: (void) strcpy(ogroupdir, ptr3); ! 812: if (strcmp(groupdir, ogroupdir)) { ! 813: (void) strcpy(bfr, groupdir); ! 814: selectng(ogroupdir, TRUE, PERHAPS); ! 815: (void) strcpy(groupdir, ogroupdir); ! 816: (void) strcpy(ogroupdir, bfr); ! 817: ngrp = 1; ! 818: back(); ! 819: } ! 820: bit = nart; ! 821: oobit = obit; ! 822: obit = -1; ! 823: getnextart(TRUE); ! 824: if (bit != nart || strcmp(groupdir, ptr3) != 0) { ! 825: msg("can't read %s/%ld", ptr3, nart); ! 826: goto caseminus; ! 827: } ! 828: rfq = 0; ! 829: break; ! 830: ! 831: /* follow-up article */ ! 832: case 'f': ! 833: if (strcmp(h->followto, "poster") == 0) { ! 834: reply(FALSE); ! 835: break; ! 836: } ! 837: (void) sprintf(bfr, "%s/%s %s", BIN, "postnews", goodone); ! 838: shcmd(bfr, CWAIT); ! 839: break; ! 840: ! 841: /* erase - pretend we haven't seen this article. */ ! 842: case 'e': ! 843: erased = 1; ! 844: set(bit); ! 845: goto caseplus; /* skip this article for now */ ! 846: ! 847: case '#': ! 848: msg("Article %ld of %ld", rfq ? oobit : bit, pngsize); ! 849: break; ! 850: ! 851: /* error */ ! 852: case '?': ! 853: { ! 854: FILE *helpf; ! 855: (void) sprintf(linebuf, "%s/vnews.help", LIB); ! 856: if ((helpf = fopen(linebuf, "r")) == NULL) { ! 857: msg("Can't open help file"); ! 858: break; ! 859: } ! 860: move(ARTWIN, 0); ! 861: while (fgets(linebuf, LBUFLEN, helpf) != NULL) ! 862: addstr(linebuf); ! 863: (void) fclose(helpf); ! 864: prflags |= HELPMSG|NEWART; ! 865: } ! 866: break; ! 867: ! 868: default: ! 869: if (c != ckill && c != cintr && c != cerase) ! 870: #ifdef TIOCGLTC ! 871: if (c != cwerase) ! 872: #endif ! 873: msg("Illegal command"); ! 874: break; ! 875: } ! 876: ! 877: return FALSE; ! 878: } ! 879: ! 880: cancel_command() ! 881: { ! 882: int notauthor; ! 883: ! 884: tfilename = filename; ! 885: (void) strcpy(rcbuf, h->path); ! 886: ptr1 = index(rcbuf, ' '); ! 887: if (ptr1) ! 888: *ptr1 = 0; ! 889: notauthor = strcmp(username, rcbuf); ! 890: if (uid != ROOTID && uid && notauthor) { ! 891: msg("Can't cancel what you didn't write."); ! 892: return; ! 893: } ! 894: if (!cancel(stderr, h, notauthor)) { ! 895: clear(bit); ! 896: saveart; ! 897: nextbit(); ! 898: obit = -1; ! 899: fp = NULL; ! 900: } ! 901: FCLOSE(fp); ! 902: } ! 903: /* ! 904: * Generate replies ! 905: */ ! 906: ! 907: reply(include) ! 908: int include; ! 909: { ! 910: char *arg[4]; ! 911: register FILE *rfp; ! 912: char subj[132]; ! 913: register char *p; ! 914: char *replyname(); ! 915: struct stat statb; ! 916: time_t creatm; ! 917: ! 918: /* Put the user in the editor to create the body of the reply. */ ! 919: ed = getenv("EDITOR"); ! 920: if (ed == NULL || *ed == '\0') ! 921: ed = DFTEDITOR; ! 922: if (ed == NULL) { ! 923: msg("You don't have an editor"); ! 924: return; ! 925: } ! 926: ! 927: arg[0] = "/bin/sh"; ! 928: arg[1] = "-c"; ! 929: ! 930: (void) strcpy(tf, tft); ! 931: (void) mktemp(tf); ! 932: (void) close(creat(tf,0600)); ! 933: if ((rfp = fopen(tf, "w")) == NULL) { ! 934: msg("Can't create %s", tf) ; ! 935: return; ! 936: } ! 937: (void) strcpy(subj, h->title); ! 938: if (!prefix(subj, "Re:")){ ! 939: (void) strcpy(bfr, subj); ! 940: (void) sprintf(subj, "Re: %s", bfr); ! 941: } ! 942: ! 943: p = replyname(h); ! 944: fprintf(rfp, "To: %s\n", p); ! 945: fprintf(rfp, "Subject: %s\n", subj); ! 946: fprintf(rfp, "In-reply-to: your article %s\n", h->ident); ! 947: #ifdef INTERNET ! 948: fprintf(rfp, "News-Path: %s\n", h->path); ! 949: #endif /* INTERNET */ ! 950: (void) sprintf(rcbuf, "%s -t < %s; rm -f %s", MAILPARSER, tf, tf); ! 951: putc('\n', rfp); ! 952: if (include) { ! 953: FILE *of; ! 954: char buf[BUFSIZ]; ! 955: ! 956: of = xfopen(goodone, "r"); ! 957: while (fgets(buf, sizeof buf, of) != NULL) ! 958: if (buf[0] == '\n') ! 959: break; ! 960: while (fgets(buf, sizeof buf, of) != NULL) ! 961: fprintf(rfp, "> %s", buf); ! 962: fclose(of); ! 963: putc('\n', rfp); ! 964: } ! 965: fflush(rfp); ! 966: (void) fstat(fileno(rfp), &statb); ! 967: creatm = statb.st_mtime; ! 968: (void) fclose(rfp); ! 969: ! 970: (void) sprintf(edcmdbuf, "exec %s %s", ed, tf); ! 971: arg[2] = edcmdbuf; ! 972: arg[3] = NULL; ! 973: if (prun(arg, 0) != 0) { ! 974: msg("Couldn't run editor"); ! 975: (void) unlink(tf); ! 976: return; ! 977: } ! 978: ! 979: if (access(tf, 4) || stat(tf, &statb)) { ! 980: msg("No input file - mail not sent"); ! 981: (void) unlink(tf); ! 982: return; ! 983: } ! 984: if (statb.st_mtime == creatm || statb.st_size < 5) { ! 985: msg("File unchanged - no message posted"); ! 986: (void) unlink(tf); ! 987: return; ! 988: } ! 989: ! 990: arg[2] = rcbuf; ! 991: arg[3] = NULL; ! 992: prun(arg, BKGRND); ! 993: prflags |= NOPRT; ! 994: } ! 995: ! 996: direct_reply() ! 997: { ! 998: register char *p; ! 999: register char *q; ! 1000: char *arg[4]; ! 1001: char address[PATHLEN]; ! 1002: extern char *replyname(); ! 1003: extern char *getenv(); ! 1004: ! 1005: arg[0] = "/bin/sh"; ! 1006: arg[1] = "-c"; ! 1007: p = replyname(h); ! 1008: q = address; ! 1009: while (*p != '\0') { ! 1010: if (index("\"\\$", *p) != 0) ! 1011: *q++ = '\\'; ! 1012: *q++ = *p++; ! 1013: } ! 1014: *q++ = '\0'; ! 1015: if ((MAILER = getenv("MAILER")) == NULL) ! 1016: MAILER = "mail"; ! 1017: sprintf(rcbuf, MAILER, hptr->title); ! 1018: sprintf(bfr, "%s %s", rcbuf, address); ! 1019: arg[2] = bfr; ! 1020: arg[3] = NULL; ! 1021: if (prun(arg, 0) != 0) { ! 1022: msg("Couldn't run mailer"); ! 1023: return; ! 1024: } ! 1025: prflags |= NOPRT; ! 1026: } ! 1027: ! 1028: next_ng_command() ! 1029: { ! 1030: obit = -1; ! 1031: if (prget("group? ", linebuf)) ! 1032: return FALSE; ! 1033: bptr = linebuf; ! 1034: if (!*bptr || *bptr == '-') { ! 1035: if (*bptr) ! 1036: actdirect = BACKWARD; ! 1037: saveart; ! 1038: if (nextng()) { ! 1039: if (actdirect == BACKWARD) ! 1040: msg("Can't back up."); ! 1041: else ! 1042: return TRUE; ! 1043: } ! 1044: return FALSE; ! 1045: } ! 1046: while (isspace(*bptr)) ! 1047: bptr++; ! 1048: if (!validng(bptr)) { ! 1049: msg("No such group."); ! 1050: return FALSE; ! 1051: } ! 1052: saveart; ! 1053: back(); ! 1054: selectng(bptr, TRUE, TRUE); ! 1055: return FALSE; ! 1056: } ! 1057: ! 1058: /* ! 1059: * Find the next article we want to consider, if we're done with ! 1060: * the last one, and show the header. ! 1061: */ ! 1062: getnextart(minus) ! 1063: int minus; ! 1064: { ! 1065: int noaccess; ! 1066: register DIR *dirp; ! 1067: register struct direct *dir; ! 1068: long nextnum, tnum; ! 1069: long atol(); ! 1070: ! 1071: noaccess = 0; ! 1072: if (minus) ! 1073: goto nextart2; /* Kludge for "-" command. */ ! 1074: ! 1075: if (bit == obit) /* Return if still on same article as last time */ ! 1076: return 0; ! 1077: ! 1078: nextart: ! 1079: if (news) { ! 1080: curflag = CURHOME; ! 1081: _amove(0, 0); ! 1082: vflush(); ! 1083: } ! 1084: dgest = 0; ! 1085: ! 1086: /* If done with this newsgroup, find the next one. */ ! 1087: while (ngsize <= 0 || (!rflag && ((long) bit > ngsize)) || (rflag && bit < minartno)) { ! 1088: if (nextng()) { ! 1089: if (actdirect == BACKWARD) { ! 1090: msg("Can't back up."); ! 1091: actdirect = FORWARD; ! 1092: continue; ! 1093: } ! 1094: else /* if (rfq++ || pflag || cflag) */ ! 1095: return 1; ! 1096: } ! 1097: if (rflag) ! 1098: bit = ngsize + 1; ! 1099: else ! 1100: bit = -1; ! 1101: noaccess = 2; ! 1102: } ! 1103: ! 1104: /* speed things up by not searching for article -1 */ ! 1105: if (bit < 0) { ! 1106: bit = minartno - 1; ! 1107: nextbit(); ! 1108: aabs = FALSE; ! 1109: goto nextart; ! 1110: } ! 1111: ! 1112: nextart2: ! 1113: if (rcreadok) ! 1114: rcreadok = 2; /* have seen >= 1 article */ ! 1115: (void) sprintf(filename, "%s/%ld", dirname(groupdir), bit); ! 1116: if (rfq && goodone[0]) /* ??? */ ! 1117: strcpy(filename, goodone); ! 1118: if (SigTrap == SIGHUP) ! 1119: return 1; ! 1120: /* Decide if we want to show this article. */ ! 1121: if ((fp = fopen(filename, "r")) == NULL) { ! 1122: /* since there can be holes in legal article numbers, */ ! 1123: /* we wait till we hit 5 consecutive bad articles */ ! 1124: /* before we haul off and scan the directory */ ! 1125: if (++noaccess < 5) ! 1126: goto badart; ! 1127: noaccess = 0; ! 1128: dirp = opendir(dirname(groupdir)); ! 1129: if (dirp == NULL) { ! 1130: if (errno != EACCES) ! 1131: msg("Can't open %s", dirname(groupdir)); ! 1132: goto nextart; ! 1133: } ! 1134: nextnum = rflag ? minartno - 1 : ngsize + 1; ! 1135: while ((dir = readdir(dirp)) != NULL) { ! 1136: if (!dir->d_ino) ! 1137: continue; ! 1138: tnum = atol(dir->d_name); ! 1139: if (tnum <= 0) ! 1140: continue; ! 1141: if (rflag ? (tnum > nextnum && tnum < bit) ! 1142: : (tnum < nextnum && tnum > bit)) ! 1143: nextnum = tnum; ! 1144: } ! 1145: closedir(dirp); ! 1146: if (rflag ? (nextnum >= bit) : (nextnum <= bit)) ! 1147: goto badart; ! 1148: do { ! 1149: clear(bit); ! 1150: nextbit(); ! 1151: } while (rflag ? (nextnum < bit) : (nextnum > bit)); ! 1152: obit = -1; ! 1153: aabs = FALSE; ! 1154: goto nextart; ! 1155: } else ! 1156: noaccess = 0; ! 1157: ! 1158: if (hread(h, fp, TRUE) == NULL || (!rfq && !aselect(h, aabs))) { ! 1159: badart: ! 1160: FCLOSE(fp); ! 1161: clear(bit); ! 1162: obit = -1; ! 1163: nextbit(); ! 1164: aabs = FALSE; ! 1165: goto nextart; ! 1166: } ! 1167: aabs = FALSE; ! 1168: actdirect = FORWARD; ! 1169: news = TRUE; ! 1170: artbody = ftell(fp); ! 1171: fmthdr(); ! 1172: artlines = lastlin; ! 1173: artread = 0; ! 1174: prflags |= NEWART; ! 1175: prflags &=~ NOPRT; ! 1176: if (! cflag && hdrend < ARTWLEN && !cflag) ! 1177: prflags |= HDRONLY; ! 1178: dlinno = 0; ! 1179: maxlinno = NLINES(h, fp); ! 1180: erased = 0; ! 1181: ! 1182: obit = bit; ! 1183: return 0; ! 1184: } ! 1185: ! 1186: /* ! 1187: * Print out whatever the appropriate header is ! 1188: */ ! 1189: fmthdr() { ! 1190: char *briefdate(); ! 1191: static FILE *ngfd = NULL; ! 1192: static int triedopen = 0; ! 1193: char pbuf[BUFLEN], *printbuffer = groupdir; ! 1194: ! 1195: lastlin = 0; ! 1196: if (ngrp) { ! 1197: pngsize = ngsize; ! 1198: ngrp--; ! 1199: if (!hflag) { ! 1200: if (!triedopen) { ! 1201: (void) sprintf(pbuf,"%s/newsgroups", LIB); ! 1202: ngfd = fopen(pbuf, "r"); ! 1203: triedopen++; ! 1204: } ! 1205: if (ngfd != NULL) { ! 1206: register char *p; ! 1207: char ibuf[BUFLEN]; ! 1208: rewind(ngfd); ! 1209: while (fgets(ibuf, BUFLEN, ngfd) != NULL) { ! 1210: p = index(ibuf, '\t'); ! 1211: if (p) ! 1212: *p++ = '\0'; ! 1213: if (strcmp(ibuf, groupdir) == 0) { ! 1214: register char *q; ! 1215: q = rindex(p, '\t'); ! 1216: if (q) { ! 1217: p = q; ! 1218: *p++ = '\0'; ! 1219: } ! 1220: if (p) { ! 1221: q = index(p, '\n'); ! 1222: if (q) ! 1223: *q = '\0'; ! 1224: if (*--q == '.') ! 1225: *q = '\0'; ! 1226: (void) sprintf(pbuf,"%s (%s)", ! 1227: groupdir, p); ! 1228: printbuffer = pbuf; ! 1229: } ! 1230: break; ! 1231: } ! 1232: } ! 1233: } ! 1234: (void) sprintf(linebuf, "Newsgroup %s", printbuffer); ! 1235: tfappend(linebuf); ! 1236: } ! 1237: } ! 1238: hdrstart = lastlin; ! 1239: if (!hflag) { ! 1240: (void) sprintf(linebuf, "Article %s %s", ! 1241: h->ident, briefdate(h->subdate)); ! 1242: tfappend(linebuf); ! 1243: } ! 1244: xtabs(h); ! 1245: vhprint(h, pflag ? 1 : 0); ! 1246: (void) sprintf(linebuf, "(%d lines)", NLINES(h, fp)); tfappend(linebuf); ! 1247: tfappend(""); ! 1248: hdrend = lastlin; ! 1249: } ! 1250: ! 1251: /* ! 1252: * Grow tabs into spaces in header fields, 'cause the rest of this ! 1253: * lax program drops turds all over tabs (so it does with \b's, but ..) ! 1254: */ ! 1255: xtabs(p) ! 1256: register struct hbuf *p; ! 1257: { ! 1258: xtabf(p->from, sizeof p->from); ! 1259: xtabf(p->path, sizeof p->path); ! 1260: xtabf(p->nbuf, sizeof p->nbuf); ! 1261: xtabf(p->title, sizeof p->title); ! 1262: xtabf(p->ident, sizeof p->ident); ! 1263: xtabf(p->replyto, sizeof p->replyto); ! 1264: xtabf(p->followid, sizeof p->followid); ! 1265: xtabf(p->subdate, sizeof p->subdate); ! 1266: xtabf(p->expdate, sizeof p->expdate); ! 1267: xtabf(p->ctlmsg, sizeof p->ctlmsg); ! 1268: xtabf(p->sender, sizeof p->sender); ! 1269: xtabf(p->followto, sizeof p->followto); ! 1270: xtabf(p->distribution, sizeof p->distribution); ! 1271: xtabf(p->organization, sizeof p->organization); ! 1272: xtabf(p->numlines, sizeof p->numlines); ! 1273: xtabf(p->keywords, sizeof p->keywords); ! 1274: xtabf(p->summary, sizeof p->summary); ! 1275: xtabf(p->approved, sizeof p->approved); ! 1276: xtabf(p->nf_id, sizeof p->nf_id); ! 1277: xtabf(p->nf_from, sizeof p->nf_from); ! 1278: #ifdef DOXREFS ! 1279: xtabf(p->xref, sizeof p->xref); ! 1280: #endif /* DOXREFS */ ! 1281: } ! 1282: ! 1283: xtabf(s, size) ! 1284: char *s; ! 1285: int size; ! 1286: { ! 1287: register char *p, *str; ! 1288: register c, i; ! 1289: char buf[LBUFLEN]; ! 1290: ! 1291: str = s; ! 1292: if (index(str, '\t') == NULL) ! 1293: return; ! 1294: i = 0; ! 1295: for (p = buf; c = *str++; i++) { ! 1296: if (c == '\t') { ! 1297: *p++ = ' '; ! 1298: if ((i & 7) != 7) ! 1299: str--; ! 1300: } else if (c == '\n') { ! 1301: i = -1; ! 1302: *p++ = c; ! 1303: } else ! 1304: *p++ = c; ! 1305: } ! 1306: *p = '\0'; ! 1307: strncpy(s, buf, size - 1); ! 1308: } ! 1309: ! 1310: /* ! 1311: * Print the file header to the temp file. ! 1312: */ ! 1313: vhprint(hp, verbose) ! 1314: register struct hbuf *hp; ! 1315: int verbose; ! 1316: { ! 1317: register char *p1, *p2; ! 1318: char fname[BUFLEN]; ! 1319: char *tailpath(); ! 1320: ! 1321: fname[0] = '\0'; /* init name holder */ ! 1322: ! 1323: p1 = index(hp->from, '('); /* Find the sender's full name. */ ! 1324: if (p1 == NULL && hp->path[0]) ! 1325: p1 = index(hp->path, '('); ! 1326: if (p1 != NULL) { ! 1327: (void) strcpy(fname, p1+1); ! 1328: p2 = index(fname, ')'); ! 1329: if (p2 != NULL) ! 1330: *p2 = '\0'; ! 1331: } ! 1332: ! 1333: (void) sprintf(linebuf, "Subject: %s", hp->title); ! 1334: tfappend(linebuf); ! 1335: if (!hflag && hp->summary[0]) ! 1336: (void) sprintf(linebuf, "Summary: %s", hp->summary), tfappend(linebuf); ! 1337: if (!hflag && hp->keywords[0]) ! 1338: (void) sprintf(linebuf, "Keywords: %s", hp->keywords), tfappend(linebuf); ! 1339: if (verbose) { ! 1340: (void) sprintf(linebuf, "From: %s", hp->from); tfappend(linebuf); ! 1341: (void) sprintf(linebuf, "Path: %s", hp->path); tfappend(linebuf); ! 1342: if (hp->organization[0]) { ! 1343: (void) sprintf(linebuf, "Organization: %s", hp->organization); ! 1344: tfappend(linebuf); ! 1345: } ! 1346: } ! 1347: else { ! 1348: if (p1 != NULL) ! 1349: *--p1 = '\0'; /* bump over the '(' */ ! 1350: #ifdef INTERNET ! 1351: /* ! 1352: * Prefer Path line if it's in internet format, or if we don't ! 1353: * understand internet format here, or if there is no reply-to. ! 1354: */ ! 1355: (void) sprintf(linebuf, "From: %s", hp->from); ! 1356: #else ! 1357: (void) sprintf(linebuf, "Path: %s", tailpath(hp)); ! 1358: #endif ! 1359: if (fname[0] || hp->organization[0]) { ! 1360: (void) strcat(linebuf, " ("); ! 1361: if (fname[0] == '\0') { ! 1362: (void) strcpy(fname,hp->from); ! 1363: p2 = index(fname,'@'); ! 1364: if (p2) ! 1365: *p2 = '\0'; ! 1366: } ! 1367: (void) strcat(linebuf, fname); ! 1368: if (hp->organization[0] && !hflag) { ! 1369: (void) strcat(linebuf, " @ "); ! 1370: (void) strcat(linebuf, hp->organization); ! 1371: } ! 1372: (void) strcat(linebuf, ")"); ! 1373: } ! 1374: tfappend(linebuf); ! 1375: if (p1 != NULL) ! 1376: *p1 = ' '; ! 1377: if (hp->ctlmsg[0]) { ! 1378: (void) sprintf(linebuf, "Control: %s", hp->ctlmsg); ! 1379: tfappend(linebuf); ! 1380: } ! 1381: } ! 1382: ! 1383: if (verbose) { ! 1384: (void) sprintf(linebuf, "Newsgroups: %s", hp->nbuf); tfappend(linebuf); ! 1385: (void) sprintf(linebuf, "Date: %s", hp->subdate); tfappend(linebuf); ! 1386: if (hp->sender[0]) { ! 1387: (void) sprintf(linebuf, "Sender: %s", hp->sender); ! 1388: tfappend(linebuf); ! 1389: } ! 1390: if (hp->replyto[0]) { ! 1391: (void) sprintf(linebuf, "Reply-To: %s", hp->replyto); ! 1392: tfappend(linebuf); ! 1393: } ! 1394: if (hp->followto[0]) { ! 1395: (void) sprintf(linebuf, "Followup-To: %s", hp->followto); ! 1396: tfappend(linebuf); ! 1397: } ! 1398: } ! 1399: else if (strcmp(hp->nbuf, groupdir) != 0) { ! 1400: (void) sprintf(linebuf, "Newsgroups: %s", hp->nbuf); ! 1401: tfappend(linebuf); ! 1402: timer(); ! 1403: } ! 1404: } ! 1405: ! 1406: #ifdef MYDB ! 1407: ! 1408: char * ! 1409: findparent(id, num) ! 1410: char *id; ! 1411: long *num; ! 1412: { ! 1413: struct artrec a; ! 1414: char idbuf[BUFSIZE]; ! 1415: char *ngname(); ! 1416: ! 1417: strcpy(idbuf, id); ! 1418: lcase(idbuf); ! 1419: ! 1420: if (lookart(id, &a) == DNULL) ! 1421: return NULL; ! 1422: if (a.parent == DNULL) ! 1423: return NULL; ! 1424: readrec(a.parent, &a); ! 1425: *num = a.groups[0].artno; ! 1426: return ngname(a.groups[0].newsgroup); ! 1427: } ! 1428: ! 1429: #endif ! 1430: ! 1431: ! 1432: /* ! 1433: * Append file to temp file, handling control characters, folding lines, etc. ! 1434: * We don't grow the temp file to more than nlines so that a user won't have ! 1435: * to wait for 20 seconds to read in a monster file from net.sources. ! 1436: * What we really want is coroutines--any year now. ! 1437: */ ! 1438: ! 1439: #define ULINE 0200 ! 1440: static char *maxcol; ! 1441: ! 1442: appfile(iop, nlines) ! 1443: register FILE *iop; ! 1444: { ! 1445: register int c; ! 1446: register char *icol; /* &linebuf[0] <= icol <= maxcol */ ! 1447: ! 1448: if (artread || artlines >= nlines || iop == NULL) ! 1449: return; ! 1450: maxcol = linebuf; ! 1451: icol = linebuf; ! 1452: while ((c = getc(iop)) != EOF) { ! 1453: switch (c) { ! 1454: case ' ': ! 1455: if (icol == maxcol && icol < linebuf + LBUFLEN - 1) { ! 1456: *icol++ = ' '; ! 1457: maxcol = icol; ! 1458: } else { ! 1459: if (*icol == '_') ! 1460: *icol++ = ULINE | ' '; ! 1461: else ! 1462: icol++; ! 1463: } ! 1464: break; ! 1465: case '\t': ! 1466: icol = (icol - linebuf &~ 07) + 8 + linebuf; ! 1467: growline(icol); ! 1468: break; ! 1469: case '\b': ! 1470: if (icol > linebuf) --icol; ! 1471: break; ! 1472: case '\n': ! 1473: outline(); ! 1474: if (artlines >= nlines) ! 1475: return; ! 1476: icol = linebuf; ! 1477: break; ! 1478: case '\r': ! 1479: icol = linebuf; ! 1480: break; ! 1481: case '\f': ! 1482: outline(); outline(); outline(); ! 1483: if (artlines >= nlines) ! 1484: return; ! 1485: icol = linebuf; ! 1486: break; ! 1487: default: ! 1488: if (c < ' ' || c > '~') ! 1489: break; ! 1490: else if (icol >= linebuf + LBUFLEN - 1) ! 1491: icol++; ! 1492: else if (icol == maxcol) { ! 1493: *icol++ = c; ! 1494: maxcol = icol; } ! 1495: else if (c == '_') ! 1496: *icol++ |= ULINE; ! 1497: else if (*icol == '_') ! 1498: *icol++ = (c | ULINE); ! 1499: else *icol++ = c; ! 1500: break; ! 1501: } ! 1502: } ! 1503: if (maxcol != linebuf) /* file not terminated with newline */ ! 1504: outline(); ! 1505: artread++; ! 1506: } ! 1507: ! 1508: growline(col) ! 1509: char *col; ! 1510: { ! 1511: while (maxcol < col && maxcol < linebuf + LBUFLEN - 1) ! 1512: *maxcol++ = ' '; ! 1513: } ! 1514: ! 1515: outline() ! 1516: { ! 1517: *maxcol = '\0'; ! 1518: if (strncmp(linebuf, ">From ", 6) == 0) { ! 1519: register char *p; ! 1520: for (p = linebuf ; (*p = p[1]) != '\0' ; p++); ! 1521: } ! 1522: tfappend(linebuf); ! 1523: if (maxcol > linebuf) ! 1524: artlines = lastlin; ! 1525: maxcol = linebuf; ! 1526: } ! 1527: ! 1528: prget(prompter, buf) ! 1529: char *prompter, *buf; ! 1530: { ! 1531: char *p, *q, *r; ! 1532: int c, lastc; ! 1533: ! 1534: curflag = CURP2; ! 1535: r = buf; ! 1536: lastc = '\0'; ! 1537: for (;;) { ! 1538: *r = '\0'; ! 1539: p = secpr; ! 1540: for (q = prompter ; *q ; q++) ! 1541: *p++ = *q; ! 1542: for (q = buf ; *q ; q++) { ! 1543: if (p < &secpr[SECPRLEN-1] && *q >= ' ' && *p <= '~') ! 1544: *p++ = *q; ! 1545: } ! 1546: *p = '\0'; ! 1547: c = vgetc(); ! 1548: if (c == '\n' || c == cintr) { ! 1549: break; ! 1550: } ! 1551: if (c == cerase || c == '\b' || c == '\177') { ! 1552: if (lastc == '\\') ! 1553: r[-1] = c; ! 1554: else if (r > buf) ! 1555: r--; ! 1556: } else if (c == ckill) { ! 1557: if (lastc == '\\') ! 1558: r[-1] = c; ! 1559: else ! 1560: r = buf; ! 1561: #ifdef TIOCGLTC ! 1562: } else if (c == cwerase) { ! 1563: if (lastc == '\\') ! 1564: r[-1] = c; ! 1565: else { ! 1566: while (r > buf && (r[-1] == ' ' || r[-1] == '\t')) ! 1567: r--; ! 1568: while (r > buf && r[-1] != ' ' && r[-1] != '\t') ! 1569: r--; ! 1570: } ! 1571: #endif ! 1572: } else { ! 1573: *r++ = c; ! 1574: } ! 1575: lastc = c; ! 1576: } ! 1577: curflag = CURHOME; ! 1578: secpr[0] = '\0'; ! 1579: return (c == cintr); ! 1580: } ! 1581: ! 1582: ! 1583: ! 1584: /* ! 1585: * Execute a shell command. ! 1586: */ ! 1587: ! 1588: shcmd(cmd, flags) ! 1589: char *cmd; ! 1590: { ! 1591: char *arg[4]; ! 1592: ! 1593: arg[0] = SHELL, arg[1] = "-c", arg[2] = cmd, arg[3] = NULL; ! 1594: return prun(arg, flags); ! 1595: } ! 1596: ! 1597: ! 1598: prun(args, flags) ! 1599: char **args; ! 1600: { ! 1601: int pid; ! 1602: int i; ! 1603: int (*savequit)(); ! 1604: char *env[100], **envp; ! 1605: char a[BUFLEN + 2]; ! 1606: extern char **environ; ! 1607: int pstatus, retval; ! 1608: ! 1609: if (!(flags & BKGRND)) { ! 1610: botscreen(); ! 1611: ttycooked(); ! 1612: #ifdef SIGTSTP ! 1613: (void) signal(SIGTSTP, SIG_DFL); ! 1614: (void) signal(SIGTTIN, SIG_DFL); ! 1615: (void) signal(SIGTTOU, SIG_DFL); ! 1616: #endif ! 1617: } ! 1618: while ((pid = fork()) == -1) ! 1619: sleep(1); /* must not clear alarm */ ! 1620: if (pid == 0) { ! 1621: for (i = 3 ; i < 20 ; i++) ! 1622: close(i); ! 1623: if (flags & BKGRND) { ! 1624: (void) signal(SIGINT, SIG_IGN); ! 1625: (void) signal(SIGQUIT, SIG_IGN); ! 1626: #ifdef SIGTSTP ! 1627: (void) signal(SIGTSTP, SIG_IGN); ! 1628: (void) signal(SIGTTIN, SIG_IGN); ! 1629: (void) signal(SIGTTOU, SIG_IGN); ! 1630: #endif ! 1631: (void) close(0); ! 1632: (void) close(1); ! 1633: (void) open("/dev/null", 2); ! 1634: (void) dup(0); ! 1635: } ! 1636: /* set $A */ ! 1637: (void) sprintf(a, "A=%s", filename); ! 1638: env[0] = a; ! 1639: for (envp = env + 1 ; *environ != NULL && envp < env + 98 ; environ++) ! 1640: if ((*environ)[0] != 'A' || (*environ)[1] != '=') ! 1641: *envp++ = *environ; ! 1642: *envp = NULL; ! 1643: ! 1644: (void) umask(savmask); ! 1645: execve(args[0], args, env); ! 1646: fprintf(stderr, "%s: not found\n", args[0]); ! 1647: exit(20); ! 1648: } ! 1649: if (!(flags & BKGRND)) { ! 1650: savequit = signal(SIGQUIT, SIG_IGN); ! 1651: while ((i = wait(&pstatus)) != pid && (i != -1 || errno == EINTR)) ! 1652: ; ! 1653: if (i == -1) ! 1654: retval = 1; ! 1655: else ! 1656: retval = pstatus; ! 1657: if (flags & CWAIT) { ! 1658: fprintf(stderr, "[Hit return to continue]"); ! 1659: while ((errno = 0, i = getchar()) != '\n' ! 1660: && (i != EOF || errno == EINTR)); ! 1661: } ! 1662: (void) signal(SIGQUIT, savequit); ! 1663: ttyraw(); ! 1664: clearok(curscr, 1); ! 1665: #ifdef SIGTSTP ! 1666: (void) signal(SIGTSTP, onstop); ! 1667: (void) signal(SIGTTIN, onstop); ! 1668: (void) signal(SIGTTOU, onstop); ! 1669: #endif ! 1670: return retval; ! 1671: } else ! 1672: return 0; ! 1673: } ! 1674: ! 1675: #ifdef DIGPAGE ! 1676: ! 1677: ! 1678: /* ! 1679: * Find end of current subarticle in digest. ! 1680: */ ! 1681: ! 1682: findend(l) ! 1683: { ! 1684: register int i, n; ! 1685: register char *p; ! 1686: ! 1687: for (i = l ; i < l + ARTWLEN && i < lastlin ; i++) { ! 1688: tfget(linebuf, i); ! 1689: for (p = linebuf ; *p == '-' ; p++) ! 1690: ; ! 1691: n = (int)p - (int)linebuf; ! 1692: if ( (n > 23 && n < 33) || (n > 65 && n < 79)) { ! 1693: tfget(linebuf, ++i); ! 1694: if (linebuf[0] == '\0') ! 1695: return i + 1; ! 1696: } ! 1697: } ! 1698: return 0; ! 1699: } ! 1700: ! 1701: #endif ! 1702: ! 1703: ! 1704: /*** Routines for handling temporary file ***/ ! 1705: ! 1706: /* ! 1707: * Append to temp file. ! 1708: * Long lines are folded. ! 1709: */ ! 1710: ! 1711: tfappend(tline) ! 1712: register char *tline; ! 1713: { ! 1714: register char *nxtlin; ! 1715: ! 1716: do { ! 1717: nxtlin = index(tline, '\n'); ! 1718: if (nxtlin) ! 1719: *nxtlin++ = '\0'; ! 1720: ! 1721: while (strlen(tline) > COLS) { ! 1722: tfput(tline, lastlin++); ! 1723: tline += COLS; ! 1724: maxlinno++; ! 1725: } ! 1726: tfput(tline, lastlin++); ! 1727: } while ((tline = nxtlin) != NULL); ! 1728: } ! 1729: ! 1730: ! 1731: tfput(tline, linno) ! 1732: char *tline; ! 1733: { ! 1734: register char *p; ! 1735: register FILE *rtfp; /* try to make it a little faster */ ! 1736: register int i; ! 1737: ! 1738: p = tline, i = even(COLS); ! 1739: tfseek(linno, 1); ! 1740: rtfp = tfp; ! 1741: while (--i >= 0) { ! 1742: if (*p) ! 1743: putc(*p++, rtfp); ! 1744: else ! 1745: putc('\0', rtfp); ! 1746: } ! 1747: tflinno++; ! 1748: } ! 1749: ! 1750: ! 1751: tfget(tline, linno) ! 1752: char *tline; ! 1753: { ! 1754: tfseek(linno, 0); ! 1755: fread(tline, even(COLS), 1, tfp); ! 1756: tline[COLS] = '\0'; ! 1757: tflinno++; ! 1758: } ! 1759: ! 1760: ! 1761: tfseek(linno, wrflag) ! 1762: { ! 1763: static int lastwrflag = 1; ! 1764: ! 1765: if (linno != tflinno || wrflag != lastwrflag) { ! 1766: (void) fseek(tfp, (long)linno * even(COLS), 0); ! 1767: tflinno = linno; ! 1768: lastwrflag = wrflag; ! 1769: } ! 1770: } ! 1771: ! 1772: /* VARARGS1 */ ! 1773: msg(s, a1, a2, a3, a4) ! 1774: char *s; ! 1775: { ! 1776: (void) sprintf(secpr, s, a1, a2, a3, a4); ! 1777: } ! 1778: ! 1779: ! 1780: /* ! 1781: * Update the display. ! 1782: * The display is entirely controlled by this routine, ! 1783: * which means that this routine may get pretty snarled. ! 1784: */ ! 1785: ! 1786: static int savelinno = -1; /* dlinno on last call to updscr */ ! 1787: static int savepr; /* prflags on last call */ ! 1788: #ifdef TIOCGWINSZ ! 1789: static int UPDATING = 0, WINCH = 0; ! 1790: ! 1791: /* ! 1792: * called by winch() from virtterm.c -- resets state information back ! 1793: * to start-up state and forces a full redraw of the screen. The ! 1794: * current article is rewound to the beginning because it's would ! 1795: * be very difficult to get the screen to return to the exact point ! 1796: * in the file that the user left off (I know, I tried). ! 1797: */ ! 1798: winch_upd() ! 1799: { ! 1800: if(UPDATING) /* concurrency. wow! */ ! 1801: WINCH++; ! 1802: else if((WINCH == 0) && (savelinno >= 0)) { ! 1803: int saveline = dlinno, saveflag = curflag; ! 1804: ! 1805: /* reread the article */ ! 1806: FCLOSE(fp); ! 1807: obit = -1; ! 1808: getnextart(FALSE); ! 1809: appfile(fp, dlinno + ARTWLEN + 1); ! 1810: ! 1811: /* fix up the screen */ ! 1812: curflag = saveflag; ! 1813: strcpy(prompt,"more? "); ! 1814: clearok(curscr, 1); ! 1815: updscr(); ! 1816: } ! 1817: } ! 1818: #endif /* TIOCGWINSZ */ ! 1819: ! 1820: ! 1821: updscr() ! 1822: { ! 1823: int count; ! 1824: int i; ! 1825: ! 1826: #ifdef TIOCGWINSZ ! 1827: UPDATING++; ! 1828: #endif /* TIOCGWINSZ */ ! 1829: if (checkin()) ! 1830: return; ! 1831: if ((prflags & HELPMSG) == 0 ! 1832: && (dlinno != savelinno || savepr != prflags) ! 1833: && quitflg == 0) { ! 1834: if (dlinno != savelinno) ! 1835: prflags &=~ NOPRT; ! 1836: count = ARTWLEN; ! 1837: if (prflags & NOPRT) ! 1838: count = 0; ! 1839: if ((prflags & HDRONLY) && count > hdrend) ! 1840: count = hdrend - dlinno; ! 1841: #ifdef DIGPAGE ! 1842: if (endsuba > 0 && count > endsuba - dlinno) ! 1843: count = endsuba - dlinno; ! 1844: #endif ! 1845: if ((prflags & NEWART) == 0) ! 1846: ushift(ARTWIN, ARTWIN+ARTWLEN-1, dlinno - savelinno); ! 1847: if (count > lastlin - dlinno) ! 1848: count = lastlin - dlinno; ! 1849: for (i = ARTWIN ; i < ARTWIN + ARTWLEN ; i++) ! 1850: clrline(i); ! 1851: for (i = 0 ; i < count ; i++) { ! 1852: tfget(linebuf, dlinno + i); ! 1853: mvaddstr(ARTWIN + i, 0, linebuf); ! 1854: } ! 1855: prflags &=~ NEWART; ! 1856: savepr = prflags; ! 1857: savelinno = dlinno; ! 1858: } ! 1859: clrline(SPLINE), clrline(PRLINE); ! 1860: #ifdef STATTOP ! 1861: mvaddstr(PRLINE, 0, prompt); ! 1862: #else ! 1863: if (strlen(secpr) <= COLS) ! 1864: mvaddstr(PRLINE, 0, prompt); ! 1865: #endif ! 1866: mvaddstr(PRLINE, 59, timestr); ! 1867: mvaddstr(PRLINE, 15, groupdir); ! 1868: addch(' '); addnum(bit); addch('/'); addnum(pngsize); addch(' '); ! 1869: if (ismail) ! 1870: mvaddstr(PRLINE, 75, ismail > 1? "MAIL" : "mail"); ! 1871: mvaddstr(SPLINE, 0, secpr); ! 1872: if (curflag == CURP1) ! 1873: move(PRLINE, strlen(prompt)); ! 1874: else if (curflag == CURHOME) ! 1875: move(0, 0); ! 1876: refresh(); ! 1877: #ifdef TIOCGWINSZ ! 1878: UPDATING=0; ! 1879: if (WINCH) { /* window changed while updating screen */ ! 1880: WINCH = 0; ! 1881: winch_upd(); ! 1882: } ! 1883: #endif /* TIOCGWINSZ */ ! 1884: } ! 1885: ! 1886: addnum(n) ! 1887: register long n; ! 1888: { ! 1889: if (n >= 10) ! 1890: addnum(n / 10); ! 1891: addch((char)(n % 10 + '0')); ! 1892: } ! 1893: ! 1894: /* ! 1895: * Called on alarm signal. ! 1896: * Simply sets flag, signal processed later. ! 1897: */ ! 1898: ! 1899: onalarm() ! 1900: { ! 1901: #ifdef SIGTSTP ! 1902: int dojump = reading; ! 1903: ! 1904: reading = FALSE; ! 1905: alflag++; ! 1906: if (dojump) ! 1907: longjmp(alrmjmp, 1); ! 1908: #else /* !SIGTSTP */ ! 1909: alflag++; ! 1910: #endif ! 1911: } ! 1912: ! 1913: /* ! 1914: * Process alarm signal (or start clock) ! 1915: */ ! 1916: timer() ! 1917: { ! 1918: time_t tod; ! 1919: int hour; ! 1920: int i; ! 1921: struct tm *t; ! 1922: struct stat statb; ! 1923: struct tm *localtime(); ! 1924: static char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; ! 1925: static long oldmsize = 1000000L; ! 1926: static int rccount = 10; ! 1927: static time_t lastismail = 0; ! 1928: ! 1929: alflag = 0; ! 1930: (void) signal(SIGALRM, onalarm); ! 1931: (void) time(&tod); ! 1932: t = localtime(&tod); ! 1933: i = 60 - t->tm_sec; ! 1934: (void) alarm(i > 30? 30 : i); /* reset alarm */ ! 1935: hour = t->tm_hour % 12; ! 1936: if (hour == 0) hour = 12; ! 1937: (void) sprintf(timestr, "%.3s %d %d:%02d", ! 1938: months + 3 * t->tm_mon, t->tm_mday, hour, t->tm_min); ! 1939: if (mailf == NULL || stat(mailf, &statb) < 0) { ! 1940: statb.st_size = 0; ! 1941: } ! 1942: if (statb.st_size > oldmsize) { ! 1943: ismail = 2; ! 1944: beep(); ! 1945: } else { ! 1946: if (statb.st_size == 0) ! 1947: ismail = 0; ! 1948: /* force MAIL for at least 30 seconds */ ! 1949: else if (ismail > 1 && (lastismail+30) < tod) ! 1950: ismail = 1; ! 1951: } ! 1952: oldmsize = statb.st_size; ! 1953: lastismail = tod; ! 1954: if (uflag && !xflag && --rccount < 0) { ! 1955: writeoutrc(); ! 1956: if (secpr[0] == '\0') ! 1957: (void) strcpy(secpr, ".newsrc updated"); ! 1958: rccount = 10; ! 1959: } ! 1960: } ! 1961: ! 1962: char * ! 1963: getmailname() ! 1964: { ! 1965: static char mailname[32]; ! 1966: register char *p; ! 1967: ! 1968: if( (p = getenv("MAIL")) != NULL) ! 1969: return p; ! 1970: #ifndef MMDF ! 1971: if (username[0] == '\0' || strlen(username) > 15) ! 1972: return NULL; ! 1973: #ifdef USG ! 1974: (void) sprintf(mailname, "/usr/mail/%s", username); ! 1975: #else /* !USG */ ! 1976: (void) sprintf(mailname, "/usr/spool/mail/%s", username); ! 1977: #endif /* !USG */ ! 1978: #else /* MMDF */ ! 1979: (void) sprintf(mailname, "%s/mailbox", userhome); ! 1980: #endif /* MMDF */ ! 1981: return mailname; ! 1982: } ! 1983: ! 1984: ! 1985: ! 1986: /*** Terminal I/O ***/ ! 1987: ! 1988: #define INBUFSIZ 8 ! 1989: ! 1990: char inbuf[INBUFSIZ]; /* input buffer */ ! 1991: char outbuf[BUFSIZ]; /* output buffer */ ! 1992: int innleft = 0; /* # of chars in input buffer */ ! 1993: int outnleft = BUFSIZ; /* room left in output buffer */ ! 1994: char *innext; /* next input character */ ! 1995: char *outnext = outbuf; /* next space in output buffer */ ! 1996: #ifdef USG ! 1997: int oflags; /* fcntl flags (for nodelay read) */ ! 1998: #endif ! 1999: ! 2000: /* ! 2001: * Input a character ! 2002: */ ! 2003: ! 2004: vgetc() ! 2005: { ! 2006: register c; ! 2007: #if defined(BSD4_2) || defined(BSD4_1C) ! 2008: int readfds, exceptfds; ! 2009: #endif ! 2010: ! 2011: recurse: ! 2012: if (--innleft >= 0) { ! 2013: c = *innext++; ! 2014: } else { ! 2015: if (alflag) ! 2016: timer(); ! 2017: updscr(); /* update the display */ ! 2018: for (;;) { ! 2019: if (innleft > 0 || alflag) ! 2020: goto recurse; ! 2021: intflag = 0; ! 2022: #ifdef USG ! 2023: if (oflags & O_NDELAY) { ! 2024: oflags &=~ O_NDELAY; ! 2025: fcntl(0, F_SETFL, oflags); ! 2026: } ! 2027: #endif ! 2028: #ifdef SIGTSTP ! 2029: if (setjmp(alrmjmp)) ! 2030: continue; ! 2031: if (setjmp(intjmp)) ! 2032: return cintr; ! 2033: reading = TRUE; ! 2034: #endif /* SIGTSTP */ ! 2035: #if defined(BSD4_2) || defined(BSD4_1C) ! 2036: /* Use a select because it can be interrupted. */ ! 2037: readfds = 1; exceptfds = 1; ! 2038: select(1, &readfds, (int *)0, &exceptfds, (int *)0); ! 2039: if (!(readfds & 1)) ! 2040: break; ! 2041: #endif ! 2042: innleft = read(0, inbuf, INBUFSIZ); ! 2043: #ifdef SIGTSTP ! 2044: reading = FALSE; ! 2045: #endif /* SIGTSTP */ ! 2046: if (innleft > 0) ! 2047: break; ! 2048: if (innleft == 0) { ! 2049: quitflg++; ! 2050: return cintr; ! 2051: } ! 2052: if (errno != EINTR) ! 2053: abort(); /* "Can't happen" */ ! 2054: if (intflag) { ! 2055: intflag--; ! 2056: return cintr; ! 2057: } ! 2058: } ! 2059: innext = inbuf + 1; ! 2060: innleft--; ! 2061: c = inbuf[0]; ! 2062: } ! 2063: #ifndef USG ! 2064: #ifndef CBREAK ! 2065: c &= 0177; ! 2066: if (c == '\034') /* FS character */ ! 2067: xxit(0); ! 2068: #endif ! 2069: #endif ! 2070: if (c == '\f') { ! 2071: clearok(curscr, 1); ! 2072: goto recurse; ! 2073: } ! 2074: if (c == '\r') ! 2075: c = '\n'; ! 2076: return c; ! 2077: } ! 2078: ! 2079: ! 2080: /* ! 2081: * Push a character back onto the input stream. ! 2082: */ ! 2083: ! 2084: pushback(c) ! 2085: { ! 2086: if (innext <= inbuf) ! 2087: abort(); ! 2088: *--innext = c; ! 2089: innleft++; ! 2090: } ! 2091: ! 2092: /* ! 2093: * Check for terminal input ! 2094: */ ! 2095: ! 2096: checkin() ! 2097: { ! 2098: #ifdef FIONREAD ! 2099: int count; ! 2100: #endif ! 2101: #ifdef STATTOP ! 2102: if (innleft > 0) ! 2103: #else ! 2104: if (innleft > 0 || alflag) ! 2105: #endif ! 2106: return 1; ! 2107: #if defined(USG) || defined(FIONREAD) ! 2108: if (ospeed >= B9600) ! 2109: return 0; ! 2110: vflush(); ! 2111: if (ospeed <= B300) ! 2112: ttyowait(); ! 2113: #ifdef USG ! 2114: if ((oflags & O_NDELAY) == 0) { ! 2115: oflags |= O_NDELAY; ! 2116: (void) fcntl(0, F_SETFL, oflags); ! 2117: } ! 2118: if ((innleft = read(0, inbuf, INBUFSIZ)) > 0) { ! 2119: innext = inbuf; ! 2120: return 1; ! 2121: } ! 2122: #endif ! 2123: #ifdef FIONREAD ! 2124: count = 0; /* in case FIONREAD fails */ ! 2125: (void) ioctl(0, FIONREAD, (char *)&count); ! 2126: if (count) ! 2127: return 1; ! 2128: #endif ! 2129: #endif ! 2130: return 0; ! 2131: } ! 2132: ! 2133: ! 2134: ! 2135: /* ! 2136: * flush terminal input queue. ! 2137: */ ! 2138: ! 2139: clearin() ! 2140: { ! 2141: #ifdef USG ! 2142: (void) ioctl(0, TCFLSH, (char *)0); ! 2143: #else ! 2144: #ifdef TIOCFLUSH ! 2145: (void) ioctl(0, TIOCFLUSH, (char *)0); ! 2146: #else ! 2147: struct sgttyb tty; ! 2148: (void) ioctl(0, TIOCGETP, &tty); ! 2149: (void) ioctl(0, TIOCSETP, &tty); ! 2150: #endif ! 2151: #endif ! 2152: innleft = 0; ! 2153: } ! 2154: ! 2155: vputc(c) ! 2156: { ! 2157: if (--outnleft < 0) { ! 2158: vflush(); ! 2159: outnleft--; ! 2160: } ! 2161: *outnext++ = c; ! 2162: } ! 2163: ! 2164: /* ! 2165: * Flush the output buffer ! 2166: */ ! 2167: ! 2168: vflush() ! 2169: { ! 2170: register char *p; ! 2171: register int i; ! 2172: #ifdef BSD4_2 ! 2173: int mask; ! 2174: #else ! 2175: unsigned oalarm; ! 2176: #endif ! 2177: ! 2178: #ifdef BSD4_2 ! 2179: mask = sigblock(1 << (SIGALRM-1)); ! 2180: #else ! 2181: oalarm = alarm(0); ! 2182: #endif ! 2183: for (p = outbuf ; p < outnext ; p += i) { ! 2184: if ((i = write(1, p, outnext - p)) < 0) { ! 2185: if (errno != EINTR) ! 2186: abort(); /* "Can't happen" */ ! 2187: i = 0; ! 2188: } ! 2189: } ! 2190: outnleft = BUFSIZ; ! 2191: outnext = outbuf; ! 2192: #ifdef BSD4_2 ! 2193: sigsetmask(mask); ! 2194: #else ! 2195: (void) alarm(oalarm); ! 2196: #endif ! 2197: } ! 2198: ! 2199: /*** terminal modes ***/ ! 2200: ! 2201: #ifdef USG ! 2202: static struct termio oldtty, newtty; ! 2203: ! 2204: /* ! 2205: * Save tty modes ! 2206: */ ! 2207: ! 2208: ttysave() ! 2209: { ! 2210: if (ioctl(1, TCGETA, &oldtty) < 0) ! 2211: xerror("Can't get tty modes"); ! 2212: newtty = oldtty; ! 2213: newtty.c_iflag &=~ (INLCR|IGNCR|ICRNL); ! 2214: newtty.c_oflag &=~ (OPOST); ! 2215: newtty.c_lflag &=~ (ICANON|ECHO|ECHOE|ECHOK|ECHONL); ! 2216: newtty.c_lflag |= (NOFLSH); ! 2217: newtty.c_cc[VMIN] = 1; ! 2218: newtty.c_cc[VTIME] = 0; ! 2219: cerase = oldtty.c_cc[VERASE]; ! 2220: ckill = oldtty.c_cc[VKILL]; ! 2221: cintr = oldtty.c_cc[VINTR]; ! 2222: ospeed = oldtty.c_cflag & CBAUD; ! 2223: initterm(); ! 2224: } ! 2225: ! 2226: ! 2227: /* ! 2228: * Set tty modes for visual processing ! 2229: */ ! 2230: ! 2231: ttyraw() ! 2232: { ! 2233: while (ioctl(1, TCSETAF, &newtty) < 0 && errno == EINTR) ! 2234: ; ! 2235: rawterm(); ! 2236: } ! 2237: ! 2238: ttyowait() ! 2239: { /* wait for output queue to drain */ ! 2240: while (ioctl(1, TCSETAW, &newtty) < 0 && errno == EINTR) ! 2241: ; ! 2242: } ! 2243: ! 2244: /* ! 2245: * Restore tty modes ! 2246: */ ! 2247: ! 2248: ttycooked() ! 2249: { ! 2250: cookedterm(); ! 2251: vflush(); ! 2252: while (ioctl(1, TCSETAF, &oldtty) < 0 && errno == EINTR) ! 2253: ; ! 2254: oflags &=~ O_NDELAY; ! 2255: (void) fcntl(0, F_SETFL, oflags) ; ! 2256: } ! 2257: ! 2258: #else ! 2259: ! 2260: static struct sgttyb oldtty, newtty; ! 2261: #ifdef TIOCGLTC ! 2262: static struct ltchars oldltchars, newltchars; ! 2263: #endif ! 2264: ! 2265: /* ! 2266: * Save tty modes ! 2267: */ ! 2268: ! 2269: ttysave() ! 2270: { ! 2271: #ifdef CBREAK ! 2272: struct tchars tchars; /* special characters, including interrupt */ ! 2273: #endif ! 2274: #ifdef SIGTSTP ! 2275: int getpgrp(); ! 2276: #if defined(BSD4_2) || defined(BSD4_1C) ! 2277: int tpgrp; ! 2278: #else /* BSD4_1 */ ! 2279: short tpgrp; ! 2280: #endif /* BSD4_1 */ ! 2281: ! 2282: retry: ! 2283: #ifdef BSD4_2 ! 2284: (void) sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU)); ! 2285: #else /* !BSD4_2 */ ! 2286: (void) signal(SIGTSTP, SIG_HOLD); ! 2287: (void) signal(SIGTTIN, SIG_HOLD); ! 2288: (void) signal(SIGTTOU, SIG_HOLD); ! 2289: #endif /* !BSD4_2 */ ! 2290: if (ioctl(2, TIOCGPGRP, (char *)&tpgrp) < 0) ! 2291: goto nottty; ! 2292: if (tpgrp != getpgrp(0)) { /* not in foreground */ ! 2293: (void) signal(SIGTTOU, SIG_DFL); ! 2294: #ifdef BSD4_2 ! 2295: (void) sigsetmask(sigblock(0) & ~sigmask(SIGTTOU)); ! 2296: #endif /* BSD4_2 */ ! 2297: (void) kill(0, SIGTTOU); ! 2298: /* job stops here waiting for SIGCONT */ ! 2299: goto retry; ! 2300: } ! 2301: (void) signal(SIGTTIN, onstop); ! 2302: (void) signal(SIGTTOU, onstop); ! 2303: (void) signal(SIGTSTP, onstop); ! 2304: #ifdef BSD4_2 ! 2305: (void) sigsetmask(sigblock(0) & ~(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU))); ! 2306: #endif /* BSD4_2 */ ! 2307: #endif /* SIGTSTP */ ! 2308: if (ioctl(1, TIOCGETP, (char *)&oldtty) < 0) ! 2309: nottty: xerror("Can't get tty modes"); ! 2310: newtty = oldtty; ! 2311: newtty.sg_flags &=~ (CRMOD|ECHO|XTABS); ! 2312: #ifdef CBREAK ! 2313: newtty.sg_flags |= CBREAK; ! 2314: ioctl(1, TIOCGETC, (char *)&tchars); ! 2315: cintr = tchars.t_intrc; ! 2316: #else /* !CBREAK */ ! 2317: newtty.sg_flags |= RAW; ! 2318: cintr = '\0177'; /* forcibly this on V6 systems */ ! 2319: #endif /* !CBREAK */ ! 2320: cerase = oldtty.sg_erase; ! 2321: ckill = oldtty.sg_kill; ! 2322: ospeed = oldtty.sg_ospeed; ! 2323: #ifdef TIOCGLTC ! 2324: if (ioctl(1, TIOCGLTC, (char *)&oldltchars) >= 0) { ! 2325: newltchars = oldltchars; ! 2326: newltchars.t_dsuspc = -1; ! 2327: cwerase = oldltchars.t_werasc; ! 2328: } ! 2329: #endif ! 2330: initterm(); ! 2331: } ! 2332: ! 2333: ! 2334: /* ! 2335: * Set tty modes for visual processing ! 2336: */ ! 2337: ! 2338: ttyraw() ! 2339: { ! 2340: while (ioctl(1, TIOCSETN, (char *)&newtty) < 0 && errno == EINTR) ! 2341: ; ! 2342: #ifdef TIOCGLTC ! 2343: if (newltchars.t_dsuspc == '\377') ! 2344: while (ioctl(1, TIOCSLTC, (char *)&newltchars) < 0 && errno == EINTR) ! 2345: ; ! 2346: #endif ! 2347: rawterm(); ! 2348: } ! 2349: ! 2350: ttyowait() ! 2351: { /* wait for output queue to drain */ ! 2352: #ifdef TIOCDRAIN /* This ioctl is a local mod on linus */ ! 2353: (void) ioctl(1, TIOCDRAIN, (char *)0); ! 2354: #endif ! 2355: } ! 2356: ! 2357: ! 2358: /* ! 2359: * Restore tty modes ! 2360: */ ! 2361: ! 2362: ttycooked() ! 2363: { ! 2364: cookedterm(); ! 2365: vflush(); ! 2366: while (ioctl(1, TIOCSETN, (char *)&oldtty) < 0 && errno == EINTR) ! 2367: ; ! 2368: #ifdef TIOCGLTC ! 2369: if (newltchars.t_dsuspc == '\377') ! 2370: while (ioctl(1, TIOCSLTC, (char *)&oldltchars) < 0 && errno == EINTR) ! 2371: ; ! 2372: #endif ! 2373: } ! 2374: ! 2375: #endif ! 2376: ! 2377: ! 2378: ! 2379: /*** signal handlers ***/ ! 2380: ! 2381: onint() { ! 2382: #ifdef SIGTSTP ! 2383: int dojump = reading; ! 2384: ! 2385: reading = FALSE; ! 2386: #endif /* SIGTSTP */ ! 2387: if (!news) { ! 2388: ttycooked(); ! 2389: xxit(1); ! 2390: } ! 2391: (void) signal(SIGINT, onint); ! 2392: clearin(); /* flush input queue */ ! 2393: #ifdef SIGTSTP ! 2394: if (dojump) ! 2395: longjmp(intjmp, 1); ! 2396: #endif /* SIGTSTP */ ! 2397: intflag++; ! 2398: } ! 2399: ! 2400: #ifdef SIGTSTP ! 2401: onstop(signo) ! 2402: int signo; ! 2403: { ! 2404: /* restore old terminal state */ ! 2405: botscreen(); ! 2406: vflush(); ! 2407: ttycooked(); ! 2408: (void) signal(signo, SIG_DFL); ! 2409: #ifdef BSD4_2 ! 2410: (void) sigblock(sigmask(SIGALRM)|sigmask(SIGINT)); ! 2411: (void) sigsetmask(sigblock(0) & ~sigmask(signo)); ! 2412: #else /* BSD4_1 */ ! 2413: (void) alarm(0); ! 2414: #endif /* BSD4_1 */ ! 2415: (void) kill(0, signo); /* stop here until continued */ ! 2416: ! 2417: (void) signal(signo, onstop); ! 2418: /* restore our special terminal state */ ! 2419: ttyraw(); ! 2420: #ifdef TIOCGWINSZ ! 2421: winch(); /* get current window size and redraw screen */ ! 2422: #endif /* TIOCGWINSZ */ ! 2423: clearok(curscr, 1); ! 2424: updscr(); ! 2425: #ifdef BSD4_2 ! 2426: (void) sigsetmask(sigblock(0) & ~(sigmask(SIGALRM)|sigmask(SIGINT))); ! 2427: #else /* BSD4_1 */ ! 2428: timer(); ! 2429: #endif /* BSD4_1 */ ! 2430: } ! 2431: #endif ! 2432: ! 2433: /*** stolen from rfuncs2.c and modified ***/ ! 2434: ! 2435: vsave(to, flags) ! 2436: register char *to; ! 2437: { ! 2438: register FILE *ufp; ! 2439: int isprogram = 0; ! 2440: int isnew = 1; ! 2441: long saveoff; ! 2442: char temp[20]; ! 2443: char *fname; ! 2444: char prog[BUFLEN + 24]; ! 2445: ! 2446: saveoff = ftell(fp); ! 2447: (void) fseek(fp, artbody, 0); ! 2448: fname = to; ! 2449: if (*to == PIPECHAR) { ! 2450: if (strlen(to) > BUFLEN) { ! 2451: msg("Command name too long"); ! 2452: goto out; ! 2453: } ! 2454: flags |= OVWRITE; ! 2455: (void) strcpy(temp, "/tmp/vnXXXXXX"); ! 2456: (void) mktemp(temp); ! 2457: fname = temp; ! 2458: _amove(ROWS - 1, 0); ! 2459: vflush(); ! 2460: } ! 2461: if ((flags & OVWRITE) == 0) { ! 2462: ufp = fopen(fname, "r"); ! 2463: if (ufp != NULL) { ! 2464: (void) fclose(ufp); ! 2465: isnew = 0; ! 2466: } ! 2467: } ! 2468: (void) umask(savmask); ! 2469: ! 2470: if (*to == PIPECHAR) ! 2471: isprogram++; ! 2472: if ((ufp = fopen(fname, (flags & OVWRITE) == 0? "a" : "w")) == NULL) { ! 2473: msg("Cannot open %s", fname); ! 2474: goto out; ! 2475: } ! 2476: /* ! 2477: * V7MAIL code is here to conform to V7 mail format. ! 2478: * If you need a different format to be able to ! 2479: * use your local mail command (such as four ^A's ! 2480: * on the end of articles) substitute it here. ! 2481: */ ! 2482: if (flags & SVHEAD) { ! 2483: #ifdef MMDF ! 2484: if (!isprogram) ! 2485: fprintf(ufp, "\001\001\001\001\n"); ! 2486: #endif /* MMDF */ ! 2487: #ifdef V7MAIL ! 2488: h->subtime = cgtdate(h->subdate); ! 2489: fprintf(ufp, "From %s %s", ! 2490: #ifdef INTERNET ! 2491: h->from, ! 2492: #else ! 2493: h->path, ! 2494: #endif ! 2495: ctime(&h->subtime)); ! 2496: #endif ! 2497: hprint(h, ufp, 2); ! 2498: #ifdef V7MAIL ! 2499: tprint(fp, ufp, TRUE); ! 2500: putc('\n', ufp); /* force blank line at end (ugh) */ ! 2501: #else ! 2502: tprint(fp, ufp, FALSE); ! 2503: #endif ! 2504: } else { ! 2505: tprint(fp, ufp, FALSE); ! 2506: } ! 2507: ! 2508: fclose(ufp); ! 2509: if (isprogram) { ! 2510: (void) sprintf(prog, "(%s)<%s", to + 1, fname); ! 2511: shcmd(prog, CWAIT); ! 2512: prflags |= NOPRT; ! 2513: } else { ! 2514: if ((flags & OVWRITE) == 0) ! 2515: msg("file: %s %s", to, isnew ? "created" : "appended"); ! 2516: else ! 2517: msg("file: %s written", to); ! 2518: } ! 2519: ! 2520: out: ! 2521: if (isprogram) { ! 2522: (void) unlink(fname); ! 2523: } ! 2524: (void) umask(N_UMASK); ! 2525: (void) fseek(fp, saveoff, 0); ! 2526: } ! 2527: ! 2528: xxit(status) ! 2529: int status; ! 2530: { ! 2531: (void) unlink(infile); ! 2532: (void) unlink(outfile); ! 2533: #ifdef SORTACTIVE ! 2534: if (strncmp(ACTIVE,"/tmp/", 5) == 0) ! 2535: (void) unlink(ACTIVE); ! 2536: #endif /* SORTACTIVE */ ! 2537: if (ospeed) { /* is == 0, we haven't been in raw mode yet */ ! 2538: botscreen(); ! 2539: vflush(); ! 2540: ttycooked(); ! 2541: } ! 2542: exit(status); ! 2543: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.