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: }