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

Defined functions

art_switch defined in line 542; used 2 times
do_newsgroup defined in line 110; used 2 times
ng_init defined in line 67; used 2 times
setdfltcmd defined in line 1021; used 3 times
setmail defined in line 1005; used 2 times

Defined variables

curr_art defined in line 64; used 10 times
exit_code defined in line 65; used 4 times
recent_art defined in line 63; used 5 times

Defined macros

AS_ASK defined in line 60; used 25 times
AS_CLEAN defined in line 61; used 5 times
AS_INP defined in line 59; used 5 times
AS_NORM defined in line 58; used 17 times
READDIR defined in line 362; used 1 times
Last modified: 1987-05-26
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5728
Valid CSS Valid XHTML 1.0 Strict