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