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