BSD 4_3 development
[unix-history] / usr / contrib / rn / ng.c
CommitLineData
1cd0e254
C
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
62ART_NUM recent_art = 0; /* previous article # for '-' command */
63ART_NUM curr_art = 0; /* current article # */
64int exit_code = NG_NORM;
65
66void
67ng_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
109int
110do_newsgroup(start_command)
111char *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
394reask_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);
409reinp_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 }
426article_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
444cleanup:
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
488int
489art_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\
515There 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
613normal_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("\
707Type y or SP to mark all articles as read.\n\
708Type n to leave articles marked as they are.\n\
709Type u to mark everything read and unsubscribe.\n\
710",stdout) FLUSH;
711 ELSE
712#endif
713#ifdef TERSE
714 fputs("\
715y or SP to mark all read.\n\
716n to forget it.\n\
717u 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
951void
952setmail()
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
967void
968setdfltcmd()
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}
985