1: /* 2: * This software is Copyright (c) 1986 by Rick Adams. 3: * 4: * Permission is hereby granted to copy, reproduce, redistribute or 5: * otherwise use this software as long as: there is no monetary 6: * profit gained specifically from the use or reproduction or this 7: * software, it is not sold, rented, traded or otherwise marketed, and 8: * this copyright notice is included prominently in any copy 9: * made. 10: * 11: * The author make no claims as to the fitness or correctness of 12: * this software for any use whatsoever, and it is provided as is. 13: * Any use of this software is at the user's own risk. 14: * 15: * readr - /bin/mail and msgs interface and associated functions. 16: */ 17: 18: #ifdef SCCSID 19: static char *SccsId = "@(#)readr.c 2.55 1/17/86"; 20: #endif /* SCCSID */ 21: 22: #include "rparams.h" 23: #if defined(BSD4_2) || defined(BSD4_1C) 24: #include <sys/dir.h> 25: #else 26: #include "ndir.h" 27: #endif /* !BSD4_2 && !BSD4_1C */ 28: #include <setjmp.h> 29: #include <errno.h> 30: 31: extern int errno; 32: 33: char *Progname = "readnews"; /* used by xerror to identify failing program */ 34: 35: static char lbuf[BUFLEN*2]; 36: long atol(); 37: 38: #define saveart oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hptr = h;h = hold;hold = hptr;ongsize = pngsize 39: #define NLINES(h, fp) (h->numlines[0] ? h->intnumlines : (h->intnumlines=linecnt(fp),sprintf(h->numlines, "%d", h->intnumlines), h->intnumlines)) 40: 41: char *tft = "/tmp/folXXXXXX"; 42: 43: /* 44: * These were made static for u370 with its buggy cc. 45: * I judged it better to have one copy with no ifdefs than 46: * to conditionally compile them as automatic variables 47: * in readr (which they originally were). Performance 48: * considerations might warrant moving some of the simple 49: * things into register variables, but I don't know what 50: * breaks the u370 cc. 51: */ 52: static char goodone[BUFLEN]; /* last decent article */ 53: static char ogroupdir[BUFLEN]; /* last groupdir */ 54: static char address[PATHLEN]; /* for reply copy */ 55: static char edcmdbuf[128]; 56: static int rfq = 0; /* for last article */ 57: static long ongsize; /* Previous ngsize */ 58: static long pngsize; /* Printing ngsize */ 59: static char *bptr; /* temp pointer. */ 60: static struct srec srec; /* srec for sys file entries */ 61: static char *tfilename; /* temporary file name */ 62: static char ofilename1[BUFLEN]; /* previous file name */ 63: static struct hbuf hbuf1, hbuf2, /* for minusing */ 64: *h = &hbuf1, /* current header */ 65: *hold = &hbuf2, /* previous header */ 66: *hptr; /* temporary */ 67: static char *ptr1, *ptr2, *ptr3; /* for reply manipulation */ 68: static int abs = FALSE; /* TRUE if we asked absolutely */ 69: static char tf[100]; 70: static long oobit; /* last bit, really */ 71: static int dgest = 0; 72: static FILE *ofp; /* Current output file to terminal*/ 73: static FILE *fp; /* current article to be printed*/ 74: static int holdup; /* 1 iff should stop before hdr */ 75: static int ignorenews; /* 1 iff readnews -p > /dev/null*/ 76: static time_t timelastsaved; /* time newsrc last written out */ 77: static jmp_buf sigjmpbuf; /* for signal processing */ 78: static int canlongjmp; /* TRUE if setjmp on sigjmp valid */ 79: 80: int catchcont(); 81: readr() 82: { 83: register char *m = getenv("MORE"); 84: register char *m2, cc; 85: 86: /* 87: * Turn of more's 'l' option, so \f kludge will work. 88: * This is really revolting! 89: */ 90: if (m2 = m) { 91: while (cc = *m++) 92: if (cc != 'l') 93: *m2++ = cc; 94: *m2 = '\0'; 95: } 96: 97: #ifdef DEBUG 98: fprintf(stderr, "readr()\n"); 99: #endif 100: if (aflag) { 101: if (*datebuf) { 102: if ((atime = cgtdate(datebuf)) == -1) 103: xerror("Cannot parse date string"); 104: } else 105: atime = 0; 106: } 107: 108: if (pflag && ignoring()) 109: ignorenews = TRUE; 110: 111: if (xflag) 112: uflag = 0; 113: if (uflag) 114: (void) time(&timelastsaved); 115: 116: ofp = stdout; 117: if (cflag && coptbuf[0] != '\0') { 118: (void) umask(022); 119: (void) mktemp(outfile); /* get "unique" file name */ 120: (void) close(creat(outfile,0666)); 121: ofp = xfopen(outfile, "w"); 122: (void) umask(N_UMASK); 123: cflag = FALSE; 124: pflag = TRUE; 125: } 126: 127: /* loop reading articles. */ 128: fp = NULL; 129: obit = -1; 130: nextng(); 131: for ( ;; ) { 132: if (getnextart(FALSE)) 133: break; 134: #ifdef DEBUG 135: fprintf(stderr,"after getnextart, fp %x, pos %ld, bit %ld, group '%s', filename '%s'\n", 136: fp, ftell(fp), bit, groupdir, filename); 137: #endif 138: (void) strcpy(goodone, filename); 139: if (pflag || lflag || eflag) { 140: /* This code should be gotten rid of */ 141: if (SigTrap) { 142: qfflush(ofp); 143: fprintf(ofp, "\n"); 144: cdump(ofp); 145: xxit(0); /* kludge! drop when qfflush works */ 146: return; 147: } 148: clear(bit); 149: nextbit(); 150: FCLOSE(fp); 151: continue; 152: } 153: for ( ;; ) { 154: char *pp; 155: int nlines; 156: int (*ointr)(); 157: #ifdef SIGCONT 158: int (*ocont)(); 159: #endif 160: (void) setjmp(sigjmpbuf); 161: canlongjmp = TRUE; 162: 163: SigTrap = FALSE; 164: if (!cflag) { 165: if (rfq) 166: (void) sprintf(bfr, "Last article. [qfr] "); 167: else { 168: nlines = NLINES(h, fp); 169: if (nlines <= 0) { 170: (void) sprintf(bfr, "(0 lines) Next? [nqfr] "); 171: FCLOSE(fp); 172: } else { 173: (void) sprintf(bfr, "(%d lines) More? [ynq] ", nlines); 174: } 175: } 176: } else 177: (void) sprintf(bfr, "? "); 178: fprintf(ofp, "%s", bfr); 179: (void) fflush(ofp); 180: bptr = lbuf; 181: ointr = signal(SIGINT, catchcont); 182: #ifdef SIGCONT 183: ocont = signal(SIGCONT, catchcont); 184: #endif 185: pp = fgets(bptr, BUFLEN, stdin); 186: canlongjmp = FALSE; 187: (void) signal(SIGINT, ointr); 188: #ifdef SIGCONT 189: (void) signal(SIGCONT, ocont); 190: #endif 191: if (pp != NULL) 192: break; 193: if (!SigTrap) 194: return; 195: #ifdef SIGCONT 196: if (SigTrap != SIGCONT) 197: #endif 198: fprintf(ofp, "\n"); 199: } 200: (void) nstrip(bptr); 201: while (*bptr == ' ' || *bptr == '\t') 202: bptr++; 203: if (command()) 204: break; 205: } 206: 207: if (!pflag && !news) { 208: if (!checkngs(header.nbuf, actfp)) 209: fprintf(stderr, "No news.\n"); 210: } 211: cout(ofp); 212: } 213: 214: #define EOL() if (*bptr != '\0') { fprintf(ofp, "? for commands.\n"); return FALSE; } 215: /* 216: * Process one command, which has already been typed in. 217: */ 218: command() 219: { 220: char *findhist(); 221: long i; 222: 223: switch (*bptr++) { 224: 225: /* No. Go on to next article. */ 226: case 'n': 227: EOL(); 228: readmode = NEXT; 229: if (!cflag) 230: FCLOSE(fp); 231: fprintf(ofp, "\n"); 232: clear(bit); 233: saveart; 234: nextbit(); 235: break; 236: 237: /* Undigestify the article. */ 238: case 'd': 239: dgest = 1; 240: /* fall through */ 241: 242: /* yes: print this article, go on. */ 243: case 'y': 244: EOL(); 245: /* fall through. */ 246: 247: /* The user hit return. Default is 'y' unless rfq, then it's 'q'. */ 248: case '\0': 249: if (!bptr[-1] && rfq) 250: return TRUE; 251: readmode = NEXT; 252: showtail(fp); 253: clear(bit); 254: saveart; 255: nextbit(); 256: break; 257: 258: /* 259: * Unsubscribe to the newsgroup and go on to next group 260: */ 261: case 'u': 262: fprintf(ofp, "To unsubscribe, use 'U'\n"); 263: break; 264: 265: case 'U': 266: fprintf(ofp, "Unsubscribing to newsgroup: %s\n", groupdir); 267: obit = -1; 268: FCLOSE(fp); 269: if (cflag) 270: clear(bit); 271: else 272: putc('\n', ofp); 273: rfq = 0; 274: zapng = TRUE; 275: saveart; 276: if (nextng()) { 277: if (actdirect == BACKWARD) 278: fprintf(ofp, "Can't back up.\n"); 279: else 280: return TRUE; 281: } 282: break; 283: 284: /* Print the current version of news */ 285: case 'v': 286: fprintf(ofp, "News version: %s\n", news_version); 287: break; 288: 289: /* reprint the article */ 290: case 'p': 291: EOL(); 292: if (!cflag) 293: goto minus; 294: readmode = NEXT; 295: if (!cflag) { 296: FCLOSE(fp); 297: bit = last; 298: putc('\n', ofp); 299: } 300: obit = -1; 301: break; 302: 303: /* decrypt joke */ 304: case 'D': 305: caesar_command(); 306: readmode = NEXT; 307: clear(bit); 308: saveart; 309: nextbit(); 310: break; 311: 312: /* write out the article someplace */ 313: case 's': 314: case 'w': 315: { 316: char *grn = groupdir; 317: tfilename = filename; 318: if (*bptr == '-') { 319: bptr++; 320: grn = ogroupdir; 321: if (*ofilename1) 322: tfilename = ofilename1; 323: } 324: if (*bptr != '\0' && *bptr != ' ') { 325: fprintf(ofp, "Bad file name.\n"); 326: break; 327: } 328: while (*bptr == ' ') 329: bptr++; 330: if (*bptr != '|' && *bptr != '/') { 331: char hetyped[BUFLEN]; 332: char *boxptr; 333: struct stat stbf; 334: (void) strcpy(hetyped, bptr); 335: if (hetyped[0] == '~' && hetyped[1] == '/') { 336: strcpy(hetyped, bptr+2); 337: strcpy(bptr, userhome); 338: } else if (boxptr = getenv("NEWSBOX")) { 339: if (index(boxptr, '%')) { 340: sprintf(bptr, boxptr, grn); 341: if (stat(bptr, &stbf) < 0) { 342: if (mkdir(bptr, 0777) < 0) { 343: fprintf(ofp, "Cannot create directory %s", bptr); 344: break; 345: } 346: } else if ((stbf.st_mode & S_IFMT) != S_IFDIR) { 347: fprintf(ofp, "%s is not a directory", bptr); 348: break; 349: } 350: } else 351: strcpy(bptr, boxptr); 352: } else 353: (void) strcpy(bptr, "."); 354: (void) strcat(bptr, "/"); 355: if (hetyped[0] != '\0') 356: (void) strcat(bptr, hetyped); 357: else 358: (void) strcat(bptr, "Articles"); 359: } 360: fwait(fsubr(save, tfilename, bptr)); 361: } 362: break; 363: 364: /* back up */ 365: case '-': 366: minus: 367: rfq = 0; 368: abs = TRUE; 369: if (!*ofilename1) { 370: fprintf(ofp, "Can't back up.\n"); 371: break; 372: } 373: if (cflag) 374: clear(bit); 375: else { 376: FCLOSE(fp); 377: putc('\n', ofp); 378: } 379: hptr = h; 380: h = hold; 381: hold = hptr; 382: (void) strcpy(bfr, filename); 383: (void) strcpy(filename, ofilename1); 384: (void) strcpy(ofilename1, bfr); 385: obit = bit; 386: if (strcmp(groupdir, ogroupdir)) { 387: (void) strcpy(bfr, groupdir); 388: selectng(ogroupdir, TRUE, FALSE); 389: (void) strcpy(groupdir, ogroupdir); 390: (void) strcpy(ogroupdir, bfr); 391: ngrp = 1; 392: back(); 393: } 394: bit = oobit; 395: oobit = obit; 396: obit = -1; 397: (void) getnextart(TRUE); 398: return FALSE; 399: 400: /* skip forwards */ 401: case '+': 402: caseplus: 403: if (*bptr == '\0') 404: (void) strcat(bptr, "1"); 405: rfq = 0; 406: if (cflag) 407: clear(bit); 408: saveart; 409: last = bit; 410: for (i = 0; i < atol(bptr); i++) { 411: nextbit(); 412: if ((bit > pngsize) || (rflag && bit < 1)) 413: break; 414: } 415: if (!cflag) { 416: putc('\n', ofp); 417: FCLOSE(fp); 418: } 419: obit = -1; 420: break; 421: 422: /* exit - time updated to that of most recently read article */ 423: case 'q': 424: EOL(); 425: return TRUE; 426: 427: /* exit - no time update. */ 428: case 'x': 429: EOL(); 430: xxit(0); 431: 432: /* cancel the article. */ 433: case 'c': 434: (void) cancel_command(); 435: break; 436: 437: /* escape to shell */ 438: case '!': 439: fwait(fsubr(ushell, bptr, (char *)NULL)); 440: fprintf(ofp, "\n"); 441: hdr(); 442: break; 443: 444: /* mail reply */ 445: case 'r': 446: (void) reply_command(); 447: break; 448: 449: /* send to some system */ 450: case 'X': 451: xmit_command(); 452: break; 453: /* mark the rest of the articles in this group as read */ 454: case 'K': 455: saveart; 456: while (bit <= pngsize && bit >= minartno) { 457: clear(bit); 458: nextbit(); 459: } 460: FCLOSE(fp); 461: break; 462: 463: /* next newsgroup */ 464: case 'P': 465: *bptr = '-'; 466: case 'N': 467: FCLOSE(fp); 468: if (next_ng_command()) 469: return TRUE; 470: break; 471: 472: case 'b': /* back up 1 article */ 473: i = bit - 1; 474: goto tryartnum; 475: case '0': /* specific no. */ 476: case '1': 477: case '2': 478: case '3': 479: case '4': 480: case '5': 481: case '6': 482: case '7': 483: case '8': 484: case '9': 485: (void) sscanf(--bptr, "%ld", &i); 486: if (i == 0) { 487: fprintf(ofp, "Bad article no.\n"); 488: break; 489: } 490: if (i > pngsize) { 491: fprintf(ofp, "Not that many articles.\n"); 492: break; 493: } 494: tryartnum: 495: readmode = SPEC; 496: abs = TRUE; 497: bit = i; 498: obit = -1; 499: if (!cflag) { 500: putc('\n', ofp); 501: FCLOSE(fp); 502: } 503: rfq = 0; 504: break; 505: 506: /* specific message ID. */ 507: case '<': 508: ptr1 = findhist(--bptr); 509: if (ptr1 == NULL) { 510: fprintf(ofp, "No such article: %s.\n", bptr); 511: break; 512: } 513: ptr2 = index(ptr1, '\t'); 514: ptr3 = index(++ptr2, '\t'); 515: ptr2 = index(++ptr3, ' '); 516: if (ptr2) 517: *ptr2 = '\0'; 518: ptr2 = index(ptr3, '/'); 519: if (!ptr2) { 520: *ptr3 = '\0'; 521: if (strcmp(++ptr3, "cancelled") == 0) { 522: fprintf(ofp, "Article %s has been cancelled.\n", 523: bptr); 524: break; 525: } 526: fprintf(ofp, "Article %s (dated %s) has expired.\n", 527: bptr, index(ptr1, '\t')+1); 528: break; 529: } 530: *ptr2++ = '\0'; 531: abs = TRUE; 532: if (cflag) 533: clear(bit); 534: else { 535: FCLOSE(fp); 536: putc('\n', ofp); 537: } 538: saveart; 539: (void) strcpy(ogroupdir, ptr3); 540: if (strcmp(groupdir, ogroupdir)) { 541: (void) strcpy(bfr, groupdir); 542: selectng(ogroupdir, TRUE, PERHAPS); 543: (void) strcpy(groupdir, ogroupdir); 544: (void) strcpy(ogroupdir, bfr); 545: ngrp = 1; 546: back(); 547: } 548: (void) sscanf(ptr2, "%ld", &bit); 549: oobit = obit; 550: obit = -1; 551: i = bit; 552: (void) getnextart(TRUE); 553: if (bit != i || strcmp(groupdir, ptr3) != 0) { 554: (void) fprintf(ofp, "Can't read %s/%ld.\n", ptr3, i); 555: goto minus; 556: } 557: rfq = 0; 558: break; 559: 560: /* follow-up article */ 561: case 'f': 562: if (strcmp(h->followto, "poster") == 0) { 563: (void) reply_command(); 564: break; 565: } 566: 567: if (*bptr == '-') 568: tfilename = ofilename1; 569: else 570: tfilename = filename; 571: (void) sprintf(bfr,"%s/%s %s", BIN, "postnews", tfilename); 572: (void) system(bfr); 573: break; 574: 575: /* erase - pretend we haven't seen this article. */ 576: case 'e': 577: if (rfq || *bptr == '-') { 578: if (strcmp(groupdir, ogroupdir)) { 579: i = bit; 580: (void) strcpy(bfr, groupdir); 581: selectng(ogroupdir, FALSE, PERHAPS); 582: set(oobit); 583: fprintf(ofp,"Holding article %ld newsgroup %s\n", oobit, ogroupdir), 584: (void) strcpy(groupdir, ogroupdir); 585: selectng(bfr, FALSE, FALSE); 586: bit = i; 587: } else { 588: fprintf(ofp,"Holding article %ld\n", oobit); 589: set(oobit); 590: } 591: } else { 592: fprintf(ofp,"Holding article %ld\n", bit); 593: set(bit); 594: goto caseplus; /* skip this article for now */ 595: } 596: break; 597: 598: case 'H': 599: case 'h': 600: if (!hflag) 601: dash(8, ofp); 602: if (*bptr == '-') { 603: if (oobit > 0) 604: fprintf(ofp, "Article %ld:\n", oobit); 605: hprint(hold, ofp, 1 + (bptr[-1]=='H')); 606: } else { 607: fprintf(ofp, "Article %ld of %ld: %s\n", 608: rfq ? oobit : bit, pngsize, h->ident); 609: hprint(h, ofp, 1 + (bptr[-1]=='H')); 610: } 611: if (!hflag) 612: dash(8, ofp); 613: break; 614: 615: case '#': 616: fprintf(ofp, "Article %ld of %ld: newsgroup %s\n", 617: rfq ? oobit : bit, pngsize, rfq ? ogroupdir : groupdir); 618: break; 619: 620: /* error */ 621: case '?': 622: help(ofp); 623: break; 624: default: 625: fprintf(ofp, "? for commands.\n"); 626: break; 627: } 628: 629: return FALSE; 630: } 631: 632: cancel_command() 633: { 634: int notauthor; 635: tfilename = filename; 636: hptr = h; 637: if (*bptr == '-') { 638: if (*ofilename1) { 639: tfilename = ofilename1; 640: hptr = hold; 641: } 642: bptr++; 643: } 644: EOL(); 645: readmode = SPEC; 646: (void) strcpy(rcbuf, hptr->path); 647: ptr1 = index(rcbuf, ' '); 648: if (ptr1) 649: *ptr1 = 0; 650: notauthor = strcmp(username, rcbuf); 651: if (uid != ROOTID && uid && notauthor) { 652: fprintf(ofp, "Can't cancel what you didn't write.\n"); 653: return FALSE; 654: } 655: if (!cancel(ofp, hptr, notauthor) && hptr == h) { 656: clear(bit); 657: saveart; 658: nextbit(); 659: obit = -1; 660: if (!cflag) 661: putc('\n', ofp); 662: FCLOSE(fp); 663: } 664: return TRUE; 665: } 666: 667: reply_command() 668: { 669: register char *pathptr; 670: int edit = 1; 671: char *ed, *fbp; 672: int idlen; 673: FILE *tfp; 674: char *replyname(); 675: char subj[BUFLEN]; 676: char folbuf[BUFLEN]; 677: struct stat statb; 678: long creatm; 679: 680: hptr = h; 681: while (*bptr && index("d-", *bptr)) { 682: switch (*bptr) { 683: /* Followup the previous article. */ 684: case '-': 685: hptr = hold; 686: break; 687: 688: /* Don't edit the headers */ 689: case 'd': 690: edit = 0; 691: break; 692: } 693: bptr++; 694: } 695: EOL(); 696: ptr1 = index(MAILPARSER, ' '); 697: if (ptr1) 698: *ptr1 = '\0'; 699: if (edit && access(MAILPARSER, 1)) { 700: #ifdef IHCC 701: fprintf(stderr, "Can't edit headers, 'recmail' missing.\n"); 702: #else 703: fprintf(stderr, "Can't edit headers without %s\n", MAILPARSER); 704: #endif 705: edit = 0; 706: } 707: if (ptr1) 708: *ptr1 = ' '; 709: 710: *rcbuf = '\0'; 711: pathptr = replyname(hptr);; 712: for (ptr1 = address, ptr2 = pathptr; *ptr2; ptr1++, ptr2++) { 713: if (index("\"\\$", *ptr2)) 714: *ptr1++ = '\\'; 715: *ptr1 = *ptr2; 716: } 717: *ptr1 = '\0'; 718: 719: folbuf[0] = '\0'; /* References */ 720: if (hptr->followid[0]) { 721: fbp = hptr->followid; 722: idlen = strlen(hptr->ident); 723: 724: /* 725: * If the references line is too long, truncate it. 726: * The "3" is for the comma, the space, and the '\0' at 727: * the end of the string. 728: */ 729: while (fbp && strlen(fbp) + idlen > BUFLEN - 3) 730: fbp = index(fbp + 1, '<'); 731: if (fbp != NULL) { 732: (void) strcpy(folbuf, fbp); 733: (void) strcat(folbuf, ", "); 734: } 735: } 736: (void) strcat(folbuf, hptr->ident); 737: 738: (void) strcpy(subj, hptr->title); /* Subject */ 739: while (isspace(*bptr)) 740: bptr++; 741: if (*bptr != '\0') 742: (void) strcpy(subj, bptr); 743: if (!prefix(subj, "Re:")){ 744: (void) strcpy(bfr, subj); 745: (void) sprintf(subj, "Re: %s", bfr); 746: } 747: if (!edit) { 748: fprintf(ofp, "To: %s\n", pathptr); 749: ed = index(MAILER, '%'); 750: if (ed && ed[1] == 's') 751: fprintf(ofp, "Subject: %s\n", subj); 752: (void) fflush(ofp); 753: } 754: 755: /* Put the user in the editor to create the body of the followup. */ 756: if (edit) { 757: int oumask; 758: 759: (void) strcpy(tf, tft); 760: (void) mktemp(tf); 761: 762: ed = getenv("EDITOR"); 763: if (ed == NULL) 764: ed = DFTEDITOR; 765: 766: oumask = umask(077); 767: if ((tfp = fopen(tf, "w")) == NULL) { 768: perror(tf); 769: creatm = 0L; 770: } else { 771: fprintf(tfp, "To: %s\n", pathptr); 772: fprintf(tfp, "Subject: %s\n", subj); 773: #ifdef INTERNET 774: fprintf(tfp, "News-Path: %s\n", hptr->path); 775: #endif /* INTERNET */ 776: fprintf(tfp, "References: %s\n\n", folbuf); 777: fstat(fileno(tfp), &statb); 778: creatm = statb.st_mtime; 779: (void) fclose(tfp); 780: } 781: (void) umask(oumask); 782: 783: (void) sprintf(edcmdbuf, "%s %s", ed, tf); 784: (void) system(edcmdbuf); 785: (void) strcpy(rcbuf, MAILPARSER); 786: (void) strcat(rcbuf, " -t"); 787: (void) strcat(rcbuf, " < "); 788: (void) strcat(rcbuf, tf); 789: if (access(tf, 4) || stat(tf, &statb)) { 790: fprintf(stderr, "Reply not sent: no input file.\n"); 791: return FALSE; 792: } 793: if (statb.st_mtime == creatm) { 794: fprintf(stderr, "Reply not sent: cancelled.\n"); 795: (void) unlink(tf); 796: return FALSE; 797: } 798: fprintf(ofp,"Sending reply.\n"); 799: (void) fflush(stdout); 800: if (fork() == 0) { 801: (void) system(rcbuf); 802: (void) unlink(tf); 803: _exit(0); 804: } 805: } else { 806: (void) sprintf(rcbuf, MAILER, hptr->title); 807: (void) sprintf(bfr, "%s %s", rcbuf, address); 808: (void) system(bfr); 809: } 810: hdr(); 811: return TRUE; 812: } 813: 814: xmit_command() 815: { 816: tfilename = filename; 817: if (*bptr == '-') { 818: if (*ofilename1) 819: tfilename = ofilename1; 820: bptr++; 821: } 822: if (*bptr != '\0' && *bptr != ' ') { 823: fprintf(ofp, "Bad system name.\n"); 824: return; 825: } 826: while (*bptr == ' ') 827: bptr++; 828: if (*bptr == '\0') { 829: fprintf(ofp, "Missing system name.\n"); 830: return; 831: } 832: if (s_find(&srec, bptr) == NULL) { 833: fprintf(ofp, "%s not in SYSFILE\n", bptr); 834: return; 835: } 836: (void) transmit(&srec, tfilename); 837: } 838: 839: next_ng_command() 840: { 841: obit = -1; 842: if (!*bptr || *bptr == '-') { 843: if (cflag) 844: clear(bit); 845: else 846: putc('\n', ofp); 847: if (*bptr) 848: actdirect = BACKWARD; 849: rfq = 0; 850: saveart; 851: if (nextng()) { 852: if (actdirect == BACKWARD) 853: fprintf(ofp, "Can't back up.\n"); 854: else 855: return TRUE; 856: } 857: return FALSE; 858: } 859: while (isspace(*bptr)) 860: bptr++; 861: if (!validng(bptr)) { 862: fprintf(ofp, "No such group.\n"); 863: return FALSE; 864: } 865: if (cflag) 866: clear(bit); 867: else 868: putc('\n', ofp); 869: readmode = SPEC; 870: rfq = 0; 871: saveart; 872: back(); 873: selectng(bptr, TRUE, TRUE); 874: return FALSE; 875: } 876: 877: caesar_command() 878: { 879: char temp[BUFLEN]; 880: FILE *pfp, *popen(); 881: 882: fprintf(stderr, "Caesar decoding:\n"); 883: (void) sprintf(temp, "%s/%s", LIB, "caesar"); 884: if (*bptr) { 885: (void) strcat(temp, " "); 886: (void) strcat(temp, bptr); 887: } 888: if (NLINES(h, fp) > LNCNT && *PAGER) { 889: (void) strcat(temp, " | "); 890: (void) strcat(temp, PAGER); 891: } 892: pfp = popen(temp, "w"); 893: tprint(fp, pfp, FALSE); 894: FCLOSE(fp); 895: (void) pclose(pfp); 896: } 897: 898: /* 899: * Show the user the tail, if any, of the message on file 900: * descriptor fd, and close fd. The digester is considered, 901: * and the pager is used if appropriate. 902: */ 903: showtail(fd) 904: FILE *fd; 905: { 906: if (fd == NULL) 907: return; 908: 909: if (dgest) { 910: digest(fd, ofp, h); 911: } else if (!lflag && !pflag && !eflag) { 912: pprint(fd); 913: } 914: (void) fclose(fd); 915: } 916: 917: /* 918: * Print out the rest of the article through the pager. 919: */ 920: pprint(fd) 921: FILE *fd; 922: { 923: #ifdef PAGE 924: /* Filter the tail of long messages through PAGER. */ 925: if (NLINES(h, fd) > LNCNT && *PAGER) { 926: if (!index(PAGER, FMETA)) { 927: FILE *pfp, *popen(); 928: 929: pfp = popen(PAGER, "w"); 930: if (pfp == NULL) 931: pfp = ofp; 932: /* 933: * What follows is an attempt to prevent the 934: * next message from scrolling part of this 935: * message off the top of the screen before 936: * the poor luser can read it. 937: */ 938: tprint(fd, pfp, FALSE); 939: putc('\f', pfp); 940: putc('\n', pfp); 941: putc(' ', pfp); 942: (void) pclose(pfp); 943: } 944: else 945: pout(ofp); 946: holdup = TRUE; 947: } 948: else 949: #endif 950: tprint(fd, ofp, FALSE); 951: } 952: 953: /* 954: * Find the next article we want to consider, if we're done with 955: * the last one, and show the header. 956: */ 957: getnextart(minus) 958: int minus; 959: { 960: int noaccess; 961: register DIR *dirp; 962: register struct direct *dir; 963: long nextnum, tnum; 964: 965: noaccess = 0; 966: 967: if (minus) 968: goto nextart2; /* Kludge for "-" command. */ 969: 970: if (bit == obit) /* Return if still on same article as last time */ 971: return 0; 972: 973: SigTrap = FALSE; 974: 975: nextart: 976: #ifdef DEBUG 977: fprintf(stderr,"nextart:\n"); 978: #endif /* DEBUG */ 979: dgest = 0; 980: 981: if (bit < minartno && !rflag) 982: bit = minartno; 983: 984: /* If done with this newsgroup, find the next one. */ 985: while (ngsize <= 0 || (!rflag && ((long) bit > ngsize)) || (rflag && bit < minartno)) { 986: if (nextng()) { 987: if (actdirect == BACKWARD) { 988: fprintf(ofp, "Can't back up.\n"); 989: actdirect = FORWARD; 990: continue; 991: } else 992: if (rfq++ || pflag || cflag) 993: return 1; 994: break; 995: } 996: if (rflag) 997: bit = ngsize + 1; 998: else 999: bit = minartno - 1; 1000: if (uflag && !xflag) { 1001: time_t now; 1002: (void) time(&now); 1003: if (now - timelastsaved > 5*60 /* 5 minutes */) { 1004: if (!xflag) 1005: fprintf(stderr,"[Saving .newsrc]\n"); 1006: writeoutrc(); 1007: timelastsaved = now; 1008: } 1009: } 1010: noaccess = 0; 1011: } 1012: 1013: nextart2: 1014: #ifdef DEBUG 1015: fprintf(stderr, "article: %s/%ld\n", groupdir, bit); 1016: #endif 1017: if (rcreadok) 1018: rcreadok = 2; /* have seen >= 1 article */ 1019: (void) sprintf(filename, "%s/%ld", dirname(groupdir), bit); 1020: if (rfq && goodone[0]) 1021: strcpy(filename, goodone); 1022: if (SigTrap) { 1023: if (SigTrap == SIGHUP) 1024: return 1; 1025: if (!rcreadok) 1026: xxit(0); 1027: fprintf(ofp, "Abort (n)? "); 1028: (void) fflush(ofp); 1029: (void) gets(bfr); 1030: if (*bfr == 'y' || *bfr == 'Y') 1031: xxit(0); 1032: SigTrap = FALSE; 1033: } 1034: #ifdef DEBUG 1035: fprintf(stderr, "filename = '%s'\n", filename); 1036: #endif 1037: /* Decide if we want to show this article. */ 1038: if (bit <= 0 || (fp = fopen(filename, "r")) == NULL) { 1039: /* don't show the header if the article was specifically 1040: * requested and it isn't there 1041: */ 1042: if (lbuf[0] == '<') { 1043: lbuf[0] = '\0'; 1044: bit = -1; 1045: return 1; 1046: } 1047: /* since there can be holes in legal article numbers, */ 1048: /* we wait till we hit 5 consecutive bad articles */ 1049: /* before we haul off and scan the directory */ 1050: if (++noaccess < 5) 1051: goto badart; 1052: noaccess = 0; 1053: dirp = opendir(dirname(groupdir)); 1054: if (dirp == NULL) { 1055: if (errno != EACCES) 1056: fprintf(stderr,"Can't open %s\n", dirname(groupdir)); 1057: goto badart; 1058: } 1059: nextnum = rflag ? minartno - 1 : ngsize + 1; 1060: while ((dir = readdir(dirp)) != NULL) { 1061: tnum = atol(dir->d_name); 1062: if (tnum <= 0) 1063: continue; 1064: if (rflag ? (tnum > nextnum && tnum < bit) 1065: : (tnum < nextnum && tnum > bit)) 1066: nextnum = tnum; 1067: } 1068: closedir(dirp); 1069: if (rflag ? (nextnum >= bit) : (nextnum <= bit)) 1070: goto badart; 1071: #ifdef DEBUG 1072: fprintf(stderr,"nextnum = %ld\n",nextnum); 1073: #endif /* DEBUG */ 1074: do { 1075: clear(bit); 1076: nextbit(); 1077: } while (rflag ? (nextnum < bit) : (nextnum > bit)); 1078: obit = -1; 1079: abs = FALSE; 1080: goto nextart; 1081: } else 1082: noaccess = 0; 1083: 1084: if (ignorenews || hread(h, fp, TRUE) == NULL 1085: || (!rfq && !aselect(h, abs))) { 1086: if (ignorenews) 1087: news = TRUE; 1088: badart: 1089: #ifdef DEBUG 1090: fprintf(stderr, "Bad article '%s'\n", filename); 1091: #endif 1092: FCLOSE(fp); 1093: clear(bit); 1094: obit = -1; 1095: nextbit(); 1096: abs = FALSE; 1097: goto nextart; 1098: } 1099: abs = FALSE; 1100: actdirect = FORWARD; 1101: news = TRUE; 1102: hdr(); 1103: if (pflag) 1104: tprint(fp, ofp, FALSE); 1105: else if (cflag && !lflag && !eflag) { 1106: (void) fflush(ofp); 1107: pprint(fp); 1108: } 1109: if (cflag || lflag || eflag || pflag) { 1110: SigTrap = FALSE; 1111: FCLOSE(fp); 1112: } 1113: obit = bit; 1114: return 0; 1115: } 1116: 1117: /* 1118: * Print out whatever the appropriate header is 1119: */ 1120: hdr() 1121: { 1122: char *briefdate(); 1123: 1124: if (rfq) 1125: return; 1126: 1127: if (lflag || eflag) { 1128: hprint(h, ofp, 0); 1129: return; 1130: } 1131: 1132: /* Print out a header */ 1133: if (ngrp) { 1134: pngsize = ngsize; 1135: ngrp--; 1136: nghprint(groupdir); 1137: } 1138: if (!hflag) 1139: fprintf(ofp, "Article %ld of %ld, %s.\n", 1140: bit, pngsize, briefdate(h->subdate)); 1141: hprint(h, ofp, pflag ? 1 : 0); 1142: } 1143: 1144: nghprint(title) 1145: char *title; 1146: { 1147: char *tstr = "Newsgroup "; 1148: int l = strlen(title) + strlen(tstr); 1149: 1150: fprintf(ofp, "\n"); 1151: if (!hflag) { 1152: dash(l, ofp); 1153: fprintf(ofp, "%s%s\n", tstr, title); 1154: dash(l, ofp); 1155: } else { 1156: fprintf(ofp, "%s%s, ", tstr, title); 1157: if (bit == pngsize) 1158: fprintf(ofp, "%ld\n", pngsize); 1159: else 1160: fprintf(ofp, "%ld-%ld\n", bit, pngsize); 1161: } 1162: fprintf(ofp, "\n"); 1163: } 1164: 1165: /* 1166: * Routine to catch a continue signal. 1167: */ 1168: catchcont(sig) 1169: int sig; 1170: { 1171: (void) signal(sig, catchcont); 1172: SigTrap = sig; 1173: (void) fflush(ofp); 1174: #ifdef SIGCONT 1175: if (fp && sig == SIGCONT) 1176: hdr(); 1177: if (sig != SIGCONT) 1178: #endif /* SIGCONT */ 1179: putc('\n', ofp); 1180: if (canlongjmp) 1181: longjmp(sigjmpbuf,1); 1182: } 1183: 1184: xxit(status) 1185: int status; 1186: { 1187: (void) unlink(infile); 1188: (void) unlink(outfile); 1189: #ifdef SORTACTIVE 1190: if (strncmp(ACTIVE,"/tmp/", 5) == 0) 1191: (void) unlink(ACTIVE); 1192: #endif /* SORTACTIVE */ 1193: exit(status); 1194: }