1: /* $Header: ng.c,v 4.3.1.3 85/05/16 16:48:09 lwall Exp $ 2: * 3: * $Log: ng.c,v $ 4: * Revision 4.3.1.3 85/05/16 16:48:09 lwall 5: * Fixed unsubsubscribe. 6: * 7: * Revision 4.3.1.2 85/05/13 09:29:28 lwall 8: * Added CUSTOMLINES option. 9: * 10: * Revision 4.3.1.1 85/05/10 11:36:00 lwall 11: * Branch for patches. 12: * 13: * Revision 4.3 85/05/01 11:43:43 lwall 14: * Baseline for release with 4.3bsd. 15: * 16: */ 17: 18: #include "EXTERN.h" 19: #include "common.h" 20: #include "rn.h" 21: #include "term.h" 22: #include "final.h" 23: #include "util.h" 24: #include "artsrch.h" 25: #include "cheat.h" 26: #include "help.h" 27: #include "kfile.h" 28: #include "rcstuff.h" 29: #include "head.h" 30: #include "artstate.h" 31: #include "bits.h" 32: #include "art.h" 33: #include "artio.h" 34: #include "ngstuff.h" 35: #include "intrp.h" 36: #include "respond.h" 37: #include "ngdata.h" 38: #include "backpage.h" 39: #include "rcln.h" 40: #include "last.h" 41: #include "search.h" 42: #include "server.h" 43: #include "INTERN.h" 44: #include "ng.h" 45: #include "artstate.h" /* somebody has to do it */ 46: 47: /* art_switch() return values */ 48: 49: #define AS_NORM 0 50: #define AS_INP 1 51: #define AS_ASK 2 52: #define AS_CLEAN 3 53: 54: ART_NUM recent_art = 0; /* previous article # for '-' command */ 55: ART_NUM curr_art = 0; /* current article # */ 56: int exit_code = NG_NORM; 57: 58: void 59: ng_init() 60: { 61: 62: #ifdef KILLFILES 63: open_kfile(KF_GLOBAL); 64: #endif 65: #ifdef CUSTOMLINES 66: init_compex(&hide_compex); 67: init_compex(&page_compex); 68: #endif 69: } 70: 71: /* do newsgroup on line ng with name ngname */ 72: 73: /* assumes that we are chdir'ed to SPOOL, and assures that that is 74: * still true upon return, but chdirs to SPOOL/ngname in between 75: * 76: * If you can understand this routine, you understand most of the program. 77: * The basic structure is: 78: * for each desired article 79: * for each desired page 80: * for each line on page 81: * if we need another line from file 82: * get it 83: * if it's a header line 84: * do special things 85: * for each column on page 86: * put out a character 87: * end loop 88: * end loop 89: * end loop 90: * end loop 91: * 92: * (Actually, the pager is in another routine.) 93: * 94: * The chief problem is deciding what is meant by "desired". Most of 95: * the messiness of this routine is due to the fact that people want 96: * to do unstructured things all the time. I have used a few judicious 97: * goto's where I thought it improved readability. The rest of the messiness 98: * arises from trying to be both space and time efficient. Have fun. 99: */ 100: 101: int 102: do_newsgroup(start_command) 103: char *start_command; /* command to fake up first */ 104: { 105: #ifdef SERVER 106: char ser_line[256]; 107: char artname[32]; 108: static long our_pid; 109: #endif 110: char oldmode = mode; 111: register long i; /* scratch */ 112: int skipstate; /* how many unavailable articles */ 113: /* have we skipped already? */ 114: 115: char *whatnext = "%sWhat next? [%s]"; 116: 117: #ifdef SERVER 118: if (our_pid == 0) /* Agreed, this is gross */ 119: our_pid = getpid(); 120: #endif 121: 122: #ifdef ARTSEARCH 123: srchahead = (scanon && ((ART_NUM)toread[ng]) >= scanon ? -1 : 0); 124: /* did they say -S? */ 125: #endif 126: 127: mode = 'a'; 128: recent_art = curr_art = 0; 129: exit_code = NG_NORM; 130: #ifndef SERVER 131: if (eaccess(ngdir,5)) { /* directory read protected? */ 132: if (eaccess(ngdir,0)) { 133: #ifdef VERBOSE 134: IF(verbose) 135: printf("\nNewsgroup %s does not have a spool directory!\n", 136: ngname) FLUSH; 137: ELSE 138: #endif 139: #ifdef TERSE 140: printf("\nNo spool for %s!\n",ngname) FLUSH; 141: #endif 142: #ifdef CATCHUP 143: catch_up(ng); 144: #endif 145: toread[ng] = TR_NONE; 146: } 147: else { 148: #ifdef VERBOSE 149: IF(verbose) 150: printf("\nNewsgroup %s is not currently accessible.\n", 151: ngname) FLUSH; 152: ELSE 153: #endif 154: #ifdef TERSE 155: printf("\n%s not readable.\n",ngname) FLUSH; 156: #endif 157: toread[ng] = TR_NONE; /* make this newsgroup invisible */ 158: /* (temporarily) */ 159: } 160: mode = oldmode; 161: return -1; 162: } 163: 164: /* chdir to newsgroup subdirectory */ 165: 166: if (chdir(ngdir)) { 167: printf(nocd,ngdir) FLUSH; 168: mode = oldmode; 169: return -1; 170: } 171: #else /* SERVER */ 172: sprintf(ser_line, "GROUP %s", ngname); 173: put_server(ser_line); 174: if (get_server(ser_line, sizeof(ser_line)) < 0) { 175: fprintf(stderr, "rrn: Unexpected close of server socket.\n"); 176: finalize(1); 177: } 178: if (*ser_line != CHAR_OK) 179: return (-1); 180: #endif /* SERVER */ 181: 182: #ifdef CACHESUBJ 183: subj_list = Null(char **); /* no subject list till needed */ 184: #endif 185: 186: /* initialize control bitmap */ 187: 188: if (initctl()) { 189: mode = oldmode; 190: return -1; 191: } 192: 193: /* FROM HERE ON, RETURN THRU CLEANUP OR WE ARE SCREWED */ 194: 195: in_ng = TRUE; /* tell the world we are here */ 196: forcelast = TRUE; /* if 0 unread, do not bomb out */ 197: art=firstart; 198: 199: /* remember what newsgroup we were in for sake of posterity */ 200: 201: writelast(); 202: 203: /* see if there are any special searches to do */ 204: 205: #ifdef KILLFILES 206: open_kfile(KF_LOCAL); 207: #ifdef VERBOSE 208: IF(verbose) 209: kill_unwanted(firstart,"Looking for articles to kill...\n\n",TRUE); 210: ELSE 211: #endif 212: #ifdef TERSE 213: kill_unwanted(firstart,"Killing...\n\n",TRUE); 214: #endif 215: #endif 216: 217: /* do they want a special top line? */ 218: 219: firstline = getval("FIRSTLINE",Nullch); 220: 221: /* custom line suppression, custom page ending */ 222: 223: #ifdef CUSTOMLINES 224: if (hideline = getval("HIDELINE",Nullch)) 225: compile(&hide_compex,hideline,TRUE,TRUE); 226: if (pagestop = getval("PAGESTOP",Nullch)) 227: compile(&page_compex,pagestop,TRUE,TRUE); 228: #endif 229: 230: /* now read each unread article */ 231: 232: rc_changed = doing_ng = TRUE; /* enter the twilight zone */ 233: skipstate = 0; /* we have not skipped anything (yet) */ 234: checkcount = 0; /* do not checkpoint for a while */ 235: do_fseek = FALSE; /* start 1st article at top */ 236: if (art > lastart) 237: art=firstart; /* init the for loop below */ 238: for (; art<=lastart+1; ) { /* for each article */ 239: 240: /* do we need to "grow" the newsgroup? */ 241: 242: if (art > lastart || forcegrow) 243: grow_ctl(); 244: check_first(art); /* make sure firstart is still 1st */ 245: if (start_command) { /* fake up an initial command? */ 246: prompt = whatnext; 247: strcpy(buf,start_command); 248: free(start_command); 249: start_command = Nullch; 250: art = lastart+1; 251: goto article_level; 252: } 253: if (art>lastart) { /* are we off the end still? */ 254: ART_NUM ucount = 0; /* count of unread articles left */ 255: 256: for (i=firstart; i<=lastart; i++) 257: if (!(ctl_read(i))) 258: ucount++; /* count the unread articles */ 259: #ifdef DEBUGGING 260: /*NOSTRICT*/ 261: if (debug && ((ART_NUM)toread[ng]) != ucount) 262: printf("(toread=%ld sb %ld)",(long)toread[ng],(long)ucount) 263: FLUSH; 264: #endif 265: /*NOSTRICT*/ 266: toread[ng] = (ART_UNREAD)ucount; /* this is perhaps pointless */ 267: art = lastart + 1; /* keep bitmap references sane */ 268: if (art != curr_art) { 269: recent_art = curr_art; 270: /* remember last article # (for '-') */ 271: curr_art = art; /* remember this article # */ 272: } 273: if (erase_screen) 274: clear(); /* clear the screen */ 275: else 276: fputs("\n\n",stdout) FLUSH; 277: #ifdef VERBOSE 278: IF(verbose) 279: printf("End of newsgroup %s.",ngname); 280: /* print pseudo-article */ 281: ELSE 282: #endif 283: #ifdef TERSE 284: printf("End of %s",ngname); 285: #endif 286: if (ucount) { 287: printf(" (%ld article%s still unread)", 288: (long)ucount,ucount==1?nullstr:"s"); 289: } 290: else { 291: if (!forcelast) 292: goto cleanup; /* actually exit newsgroup */ 293: } 294: prompt = whatnext; 295: #ifdef ARTSEARCH 296: srchahead = 0; /* no more subject search mode */ 297: #endif 298: fputs("\n\n",stdout) FLUSH; 299: skipstate = 0; /* back to none skipped */ 300: } 301: else if (!reread && was_read(art)) { 302: /* has this article been read? */ 303: art++; /* then skip it */ 304: continue; 305: } 306: else if 307: (!reread && !was_read(art) 308: && artopen(art) == Nullfp) { /* never read it, & cannot find it? */ 309: if (errno != ENOENT) { /* has it not been deleted? */ 310: #ifdef VERBOSE 311: IF(verbose) 312: printf("\n(Article %ld exists but is unreadable.)\n", 313: (long)art) FLUSH; 314: ELSE 315: #endif 316: #ifdef TERSE 317: printf("\n(%ld unreadable.)\n",(long)art) FLUSH; 318: #endif 319: skipstate = 0; 320: sleep(2); 321: } 322: switch(skipstate++) { 323: case 0: 324: clear(); 325: #ifdef VERBOSE 326: IF(verbose) 327: fputs("Skipping unavailable article",stdout); 328: ELSE 329: #endif 330: #ifdef TERSE 331: fputs("Skipping",stdout); 332: #endif 333: for (i = just_a_sec/3; i; --i) 334: putchar(PC); 335: fflush(stdout); 336: sleep(1); 337: break; 338: case 1: 339: fputs("..",stdout); 340: fflush(stdout); 341: break; 342: default: 343: putchar('.'); 344: fflush(stdout); 345: #ifndef SERVER 346: #define READDIR 347: #ifdef READDIR 348: { /* fast skip patch */ 349: ART_NUM newart; 350: 351: if (! (newart=getngmin(".",art))) 352: newart = lastart+1; 353: for (i=art; i<newart; i++) 354: oneless(i); 355: art = newart - 1; 356: } 357: #endif 358: #endif 359: break; 360: } 361: oneless(art); /* mark deleted as read */ 362: art++; /* try next article */ 363: continue; 364: } 365: else { /* we have a real live article */ 366: skipstate = 0; /* back to none skipped */ 367: if (art != curr_art) { 368: recent_art = curr_art; 369: /* remember last article # (for '-') */ 370: curr_art = art; /* remember this article # */ 371: } 372: if (!do_fseek) { /* starting at top of article? */ 373: artline = 0; /* start at the beginning */ 374: topline = -1; /* and remember top line of screen */ 375: /* (line # within article file) */ 376: } 377: clear(); /* clear screen */ 378: artopen(art); /* make sure article file is open */ 379: if (artfp == Nullfp) { /* could not find article? */ 380: printf("Article %ld of %s is not available.\n\n", 381: (long)art,ngname) FLUSH; 382: prompt = whatnext; 383: #ifdef ARTSEARCH 384: srchahead = 0; 385: #endif 386: } 387: else { /* found it, so print it */ 388: switch (do_article()) { 389: case DA_CLEAN: /* quit newsgroup */ 390: goto cleanup; 391: case DA_TOEND: /* do not mark as read */ 392: goto reask_article; 393: case DA_RAISE: /* reparse command at end of art */ 394: goto article_level; 395: case DA_NORM: /* normal end of article */ 396: break; 397: } 398: } 399: mark_as_read(art); /* mark current article as read */ 400: reread = FALSE; 401: do_hiding = TRUE; 402: #ifdef ROTATION 403: rotate = FALSE; 404: #endif 405: } 406: 407: /* if these gotos bother you, think of this as a little state machine */ 408: 409: reask_article: 410: #ifdef MAILCALL 411: setmail(); 412: #endif 413: setdfltcmd(); 414: #ifdef CLEAREOL 415: if (erase_screen && can_home_clear) /* PWP was here */ 416: clear_rest(); 417: #endif CLEAREOL 418: unflush_output(); /* disable any ^O in effect */ 419: standout(); /* enter standout mode */ 420: printf(prompt,mailcall,dfltcmd);/* print prompt, whatever it is */ 421: un_standout(); /* leave standout mode */ 422: putchar(' '); 423: fflush(stdout); 424: reinp_article: 425: eat_typeahead(); 426: #ifdef PENDING 427: look_ahead(); /* see what we can do in advance */ 428: if (!input_pending()) 429: collect_subjects(); /* loads subject cache until */ 430: /* input is pending */ 431: #endif 432: getcmd(buf); 433: if (errno || *buf == '\f') { 434: if (LINES < 100 && !int_count) 435: *buf = '\f'; /* on CONT fake up refresh */ 436: else { 437: putchar('\n') FLUSH; /* but only on a crt */ 438: goto reask_article; 439: } 440: } 441: article_level: 442: 443: /* parse and process article level command */ 444: 445: switch (art_switch()) { 446: case AS_INP: /* multichar command rubbed out */ 447: goto reinp_article; 448: case AS_ASK: /* reprompt "End of article..." */ 449: goto reask_article; 450: case AS_CLEAN: /* exit newsgroup */ 451: goto cleanup; 452: case AS_NORM: /* display article art */ 453: break; 454: } 455: } /* end of article selection loop */ 456: 457: /* shut down newsgroup */ 458: 459: cleanup: 460: #ifdef KILLFILES 461: kill_unwanted(firstart,"\nCleaning up...\n\n",FALSE); 462: /* do cleanup from KILL file, if any */ 463: #endif 464: in_ng = FALSE; /* leave newsgroup state */ 465: if (artfp != Nullfp) { /* article still open? */ 466: fclose(artfp); /* close it */ 467: artfp = Nullfp; /* and tell the world */ 468: #ifdef SERVER 469: sprintf(artname, "/tmp/rrn%ld.%ld", (long) openart, our_pid); 470: UNLINK(artname); 471: #endif 472: openart = 0; 473: } 474: putchar('\n') FLUSH; 475: yankback(); /* do a Y command */ 476: restore_ng(); /* reconstitute .newsrc line */ 477: doing_ng = FALSE; /* tell sig_catcher to cool it */ 478: free(ctlarea); /* return the control area */ 479: #ifdef CACHESUBJ 480: if (subj_list) { 481: for (i=OFFSET(lastart); i>=0; --i) 482: if (subj_list[i]) 483: free(subj_list[i]); 484: #ifndef lint 485: free((char*)subj_list); 486: #endif lint 487: } 488: #endif 489: write_rc(); /* and update .newsrc */ 490: rc_changed = FALSE; /* tell sig_catcher it is ok */ 491: if (chdir(spool)) { 492: printf(nocd,spool) FLUSH; 493: sig_catcher(0); 494: } 495: #ifdef KILLFILES 496: if (localkfp) { 497: fclose(localkfp); 498: localkfp = Nullfp; 499: } 500: #endif 501: mode = oldmode; 502: return exit_code; 503: } /* Whew! */ 504: 505: /* decide what to do at the end of an article */ 506: 507: int 508: art_switch() 509: { 510: register ART_NUM i; 511: 512: setdef(buf,dfltcmd); 513: #ifdef VERIFY 514: printcmd(); 515: #endif 516: switch (*buf) { 517: case 'p': /* find previous unread article */ 518: do { 519: if (art <= firstart) 520: break; 521: art--; 522: } while (was_read(art) || artopen(art) == Nullfp); 523: #ifdef ARTSEARCH 524: srchahead = 0; 525: #endif 526: return AS_NORM; 527: case 'P': /* goto previous article */ 528: if (art > absfirst) 529: art--; 530: else { 531: #ifdef VERBOSE 532: IF(verbose) 533: fputs("\n\ 534: There are no articles prior to this one.\n\ 535: ",stdout) FLUSH; 536: ELSE 537: #endif 538: #ifdef TERSE 539: fputs("\nNo previous articles\n",stdout) FLUSH; 540: #endif 541: return AS_ASK; 542: } 543: reread = TRUE; 544: #ifdef ARTSEARCH 545: srchahead = 0; 546: #endif 547: return AS_NORM; 548: case '-': 549: if (recent_art) { 550: art = recent_art; 551: reread = TRUE; 552: #ifdef ARTSEARCH 553: srchahead = -(srchahead != 0); 554: #endif 555: return AS_NORM; 556: } 557: else { 558: exit_code = NG_MINUS; 559: return AS_CLEAN; 560: } 561: case 'n': /* find next unread article? */ 562: if (art > lastart) { 563: if (toread[ng]) 564: art = firstart; 565: else 566: return AS_CLEAN; 567: } 568: #ifdef ARTSEARCH 569: else if (scanon && srchahead) { 570: *buf = Ctl('n'); 571: goto normal_search; 572: } 573: #endif 574: else 575: art++; 576: #ifdef ARTSEARCH 577: srchahead = 0; 578: #endif 579: return AS_NORM; 580: case 'N': /* goto next article */ 581: if (art > lastart) 582: art = absfirst; 583: else 584: art++; 585: if (art <= lastart) 586: reread = TRUE; 587: #ifdef ARTSEARCH 588: srchahead = 0; 589: #endif 590: return AS_NORM; 591: case '$': 592: art = lastart+1; 593: forcelast = TRUE; 594: #ifdef ARTSEARCH 595: srchahead = 0; 596: #endif 597: return AS_NORM; 598: case '1': case '2': case '3': /* goto specified article */ 599: case '4': case '5': case '6': /* or do something with a range */ 600: case '7': case '8': case '9': case '.': 601: forcelast = TRUE; 602: switch (numnum()) { 603: case NN_INP: 604: return AS_INP; 605: case NN_ASK: 606: return AS_ASK; 607: case NN_REREAD: 608: reread = TRUE; 609: #ifdef ARTSEARCH 610: if (srchahead) 611: srchahead = -1; 612: #endif 613: break; 614: case NN_NORM: 615: if (was_read(art)) { 616: art = firstart; 617: pad(just_a_sec/3); 618: } 619: else 620: return AS_ASK; 621: break; 622: } 623: return AS_NORM; 624: case Ctl('k'): 625: edit_kfile(); 626: return AS_ASK; 627: case 'K': 628: case 'k': 629: case Ctl('n'): case Ctl('p'): 630: case '/': case '?': 631: #ifdef ARTSEARCH 632: normal_search: 633: { /* search for article by pattern */ 634: char cmd = *buf; 635: 636: reread = TRUE; /* assume this */ 637: switch (art_search(buf, (sizeof buf), TRUE)) { 638: case SRCH_ERROR: 639: return AS_ASK; 640: case SRCH_ABORT: 641: return AS_INP; 642: case SRCH_INTR: 643: #ifdef VERBOSE 644: IF(verbose) 645: printf("\n(Interrupted at article %ld)\n",(long)art) FLUSH; 646: ELSE 647: #endif 648: #ifdef TERSE 649: printf("\n(Intr at %ld)\n",(long)art) FLUSH; 650: #endif 651: art = curr_art; 652: /* restore to current article */ 653: return AS_ASK; 654: case SRCH_DONE: 655: fputs("done\n",stdout) FLUSH; 656: pad(just_a_sec/3); /* 1/3 second */ 657: if (srchahead) 658: art = firstart; 659: else 660: art = curr_art; 661: reread = FALSE; 662: return AS_NORM; 663: case SRCH_SUBJDONE: 664: #ifdef UNDEF 665: fputs("\n\n\n\nSubject not found.\n",stdout) FLUSH; 666: pad(just_a_sec/3); /* 1/3 second */ 667: #endif 668: art = firstart; 669: reread = FALSE; 670: return AS_NORM; 671: case SRCH_NOTFOUND: 672: fputs("\n\n\n\nNot found.\n",stdout) FLUSH; 673: art = curr_art; /* restore to current article */ 674: return AS_ASK; 675: case SRCH_FOUND: 676: if (cmd == Ctl('n') || cmd == Ctl('p')) 677: oldsubject = TRUE; 678: break; 679: } 680: return AS_NORM; 681: } 682: #else 683: buf[1] = '\0'; 684: notincl(buf); 685: return AS_ASK; 686: #endif 687: case 'u': /* unsubscribe from this newsgroup? */ 688: rcchar[ng] = NEGCHAR; 689: return AS_CLEAN; 690: case 'M': 691: #ifdef DELAYMARK 692: if (art <= lastart) { 693: delay_unmark(art); 694: printf("\nArticle %ld will return.\n",(long)art) FLUSH; 695: } 696: #else 697: notincl("M"); 698: #endif 699: return AS_ASK; 700: case 'm': 701: if (art <= lastart) { 702: unmark_as_read(art); 703: printf("\nArticle %ld marked as still unread.\n",(long)art) FLUSH; 704: } 705: return AS_ASK; 706: case 'c': /* catch up */ 707: reask_catchup: 708: #ifdef VERBOSE 709: IF(verbose) 710: in_char("\nDo you really want to mark everything as read? [yn] "); 711: ELSE 712: #endif 713: #ifdef TERSE 714: in_char("\nReally? [ynh] "); 715: #endif 716: putchar('\n') FLUSH; 717: setdef(buf,"y"); 718: #ifdef VERIFY 719: printcmd(); 720: #endif 721: if (*buf == 'h') { 722: #ifdef VERBOSE 723: IF(verbose) 724: fputs("\ 725: Type y or SP to mark all articles as read.\n\ 726: Type n to leave articles marked as they are.\n\ 727: Type u to mark everything read and unsubscribe.\n\ 728: ",stdout) FLUSH; 729: ELSE 730: #endif 731: #ifdef TERSE 732: fputs("\ 733: y or SP to mark all read.\n\ 734: n to forget it.\n\ 735: u to mark all and unsubscribe.\n\ 736: ",stdout) FLUSH; 737: #endif 738: goto reask_catchup; 739: } 740: else if (*buf == 'n' || *buf == 'q') { 741: return AS_ASK; 742: } 743: else if (*buf != 'y' && *buf != 'u') { 744: fputs(hforhelp,stdout) FLUSH; 745: settle_down(); 746: goto reask_catchup; 747: } 748: for (i = firstart; i <= lastart; i++) { 749: ctl_set(i); /* mark as read */ 750: } 751: #ifdef DELAYMARK 752: if (dmfp) 753: yankback(); 754: #endif 755: if (*buf == 'u') { 756: rcchar[ng] = NEGCHAR; 757: return AS_CLEAN; 758: } 759: art = lastart+1; 760: forcelast = FALSE; 761: return AS_NORM; 762: case 'Q': 763: exit_code = NG_ASK; 764: /* FALL THROUGH */ 765: case 'q': /* go back up to newsgroup level? */ 766: return AS_CLEAN; 767: case 'j': 768: putchar('\n') FLUSH; 769: if (art <= lastart) 770: mark_as_read(art); 771: return AS_ASK; 772: case 'h': { /* help? */ 773: int cmd; 774: 775: if ((cmd = help_art()) > 0) 776: pushchar(cmd); 777: return AS_ASK; 778: } 779: case '&': 780: if (switcheroo()) /* get rest of command */ 781: return AS_INP; /* if rubbed out, try something else */ 782: return AS_ASK; 783: case '#': 784: #ifdef VERBOSE 785: IF(verbose) 786: printf("\nThe last article is %ld.\n",(long)lastart) FLUSH; 787: ELSE 788: #endif 789: #ifdef TERSE 790: printf("\n%ld\n",(long)lastart) FLUSH; 791: #endif 792: return AS_ASK; 793: case '=': { 794: char tmpbuf[256]; 795: ART_NUM oldart = art; 796: int cmd; 797: char *subjline = getval("SUBJLINE",Nullch); 798: #ifndef CACHESUBJ 799: char *s; 800: #endif 801: 802: page_init(); 803: #ifdef CACHESUBJ 804: if (!subj_list) 805: fetchsubj(art,TRUE,FALSE); 806: #endif 807: for (i=firstart; i<=lastart && !int_count; i++) { 808: #ifdef CACHESUBJ 809: if (!was_read(i) && 810: (subj_list[OFFSET(i)] != Nullch || fetchsubj(i,FALSE,FALSE)) && 811: *subj_list[OFFSET(i)] ) { 812: sprintf(tmpbuf,"%5ld ", i); 813: if (subjline) { 814: art = i; 815: interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline); 816: } 817: else 818: safecpy(tmpbuf + 6, subj_list[OFFSET(i)], 819: (sizeof tmpbuf) - 6); 820: if (cmd = print_lines(tmpbuf,NOMARKING)) { 821: if (cmd > 0) 822: pushchar(cmd); 823: break; 824: } 825: } 826: #else 827: if (!was_read(i) && (s = fetchsubj(i,FALSE,FALSE)) && *s) { 828: sprintf(tmpbuf,"%5ld ", i); 829: if (subjline) { /* probably fetches it again! */ 830: art = i; 831: interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline); 832: } 833: else 834: safecpy(tmpbuf + 6, s, (sizeof tmpbuf) - 6); 835: if (cmd = print_lines(tmpbuf,NOMARKING)) { 836: if (cmd > 0) 837: pushchar(cmd); 838: break; 839: } 840: } 841: #endif 842: } 843: int_count = 0; 844: art = oldart; 845: return AS_ASK; 846: } 847: case '^': 848: art = firstart; 849: #ifdef ARTSEARCH 850: srchahead = 0; 851: #endif 852: return AS_NORM; 853: #if defined(CACHESUBJ) && defined(DEBUGGING) 854: case 'D': 855: printf("\nFirst article: %ld\n",(long)firstart) FLUSH; 856: if (!subj_list) 857: fetchsubj(art,TRUE,FALSE); 858: if (subj_list != Null(char **)) { 859: for (i=1; i<=lastart && !int_count; i++) { 860: if (subj_list[OFFSET(i)]) 861: printf("%5ld %c %s\n", 862: i, (was_read(i)?'y':'n'), subj_list[OFFSET(i)]) FLUSH; 863: } 864: } 865: int_count = 0; 866: return AS_ASK; 867: #endif 868: case 'v': 869: if (art <= lastart) { 870: reread = TRUE; 871: do_hiding = FALSE; 872: } 873: return AS_NORM; 874: #ifdef ROTATION 875: case Ctl('x'): 876: #endif 877: case Ctl('r'): 878: #ifdef ROTATION 879: rotate = (*buf==Ctl('x')); 880: #endif 881: if (art <= lastart) 882: reread = TRUE; 883: return AS_NORM; 884: #ifdef ROTATION 885: case 'X': 886: rotate = !rotate; 887: /* FALL THROUGH */ 888: #else 889: case Ctl('x'): 890: case 'x': 891: case 'X': 892: notincl("x"); 893: return AS_ASK; 894: #endif 895: case 'l': case Ctl('l'): /* refresh screen */ 896: if (art <= lastart) { 897: reread = TRUE; 898: clear(); 899: do_fseek = TRUE; 900: artline = topline; 901: if (artline < 0) 902: artline = 0; 903: } 904: return AS_NORM; 905: case 'b': case Ctl('b'): /* back up a page */ 906: if (art <= lastart) { 907: ART_LINE target; 908: 909: reread = TRUE; 910: clear(); 911: do_fseek = TRUE; 912: target = topline - (LINES - 2); 913: artline = topline; 914: do { 915: artline--; 916: } while (artline >= 0 && artline > target && 917: vrdary(artline-1) >= 0); 918: topline = artline; 919: if (artline < 0) 920: artline = 0; 921: } 922: return AS_NORM; 923: case '!': /* shell escape */ 924: if (escapade()) 925: return AS_INP; 926: return AS_ASK; 927: case 'C': { 928: cancel_article(); 929: return AS_ASK; 930: } 931: case 'R': 932: case 'r': { /* reply? */ 933: reply(); 934: return AS_ASK; 935: } 936: case 'F': 937: case 'f': { /* followup command */ 938: followup(); 939: forcegrow = TRUE; /* recalculate lastart */ 940: return AS_ASK; 941: } 942: case '|': 943: case 'w': case 'W': 944: case 's': case 'S': /* save command */ 945: if (save_article() == SAVE_ABORT) 946: return AS_INP; 947: return AS_ASK; 948: #ifdef DELAYMARK 949: case 'Y': /* yank back M articles */ 950: yankback(); 951: art = firstart; /* from the beginning */ 952: return AS_NORM; /* pretend nothing happened */ 953: #endif 954: #ifdef STRICTCR 955: case '\n': 956: fputs(badcr,stdout) FLUSH; 957: return AS_ASK; 958: #endif 959: default: 960: printf("\n%s",hforhelp) FLUSH; 961: settle_down(); 962: return AS_ASK; 963: } 964: } 965: 966: #ifdef MAILCALL 967: /* see if there is any mail */ 968: 969: void 970: setmail() 971: { 972: if (! (mailcount++)) { 973: char *mailfile = filexp(getval("MAILFILE",MAILFILE)); 974: 975: if (stat(mailfile,&filestat) < 0 || !filestat.st_size 976: || filestat.st_atime > filestat.st_mtime) 977: mailcall = nullstr; 978: else 979: mailcall = "(Mail) "; 980: } 981: mailcount %= 10; /* check every 10 articles */ 982: } 983: #endif 984: 985: void 986: setdfltcmd() 987: { 988: if (toread[ng]) { 989: #ifdef ARTSEARCH 990: if (srchahead) 991: dfltcmd = "^Nnpq"; 992: else 993: #endif 994: dfltcmd = "npq"; 995: } 996: else { 997: if (art > lastart) 998: dfltcmd = "qnp"; 999: else 1000: dfltcmd = "npq"; 1001: } 1002: }