1 /*
2  *	(c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
3  *      Copyright (c) 1996-2005 Michael T Pins.  All rights reserved.
4  *
5  *	Article browser.
6  */
7 
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include "config.h"
12 #include "global.h"
13 #include "articles.h"
14 #include "answer.h"
15 #include "db.h"
16 #include "execute.h"
17 #include "folder.h"
18 #include "group.h"
19 #include "init.h"
20 #include "keymap.h"
21 #include "kill.h"
22 #include "macro.h"
23 #include "match.h"
24 #include "menu.h"
25 #include "news.h"
26 #include "regexp.h"
27 #include "save.h"
28 #include "nn_term.h"
29 
30 /* more.c */
31 
32 static void     more_auto_select(void);
33 static char    *a_st_flags(flag_type flag);
34 static void     brief_header_line(register article_header * ah, int lno);
35 
36 int             monitor_mode = 0;
37 int             compress_mode = 0;
38 int             show_article_date = 1;
39 int             first_page_lines = 0;
40 int             overlap = 2;
41 int             mark_overlap = 0;
42 
43 #ifdef GNKSA
44 char           *header_lines = "=F_S_D_n_W_R";
45 #else
46 char           *header_lines = NULL;
47 #endif
48 
49 int             min_pv_window = 7;
50 int             wrap_headers = 6;
51 int             data_bits = 7;
52 int             scroll_clear_page = 1;
53 int             expired_msg_delay = 1;
54 char           *trusted_escapes = NULL;
55 int             new_read_prompt = 1;
56 int             re_layout_more = -1;
57 int             scroll_last_lines = 0;
58 int             ignore_formfeed = 0;
59 
60 extern int      preview_window;
61 extern int      novice;
62 extern int      slow_mode;
63 extern int      auto_preview_mode;
64 extern int      flush_typeahead;
65 extern int      case_fold_search;
66 extern int      echo_prefix_key;
67 extern int      re_layout;
68 extern char    *folder_save_file, *default_save_file;
69 extern int      show_art_next_invalid;
70 extern int      mouse_y;
71 extern int      mouse_state;
72 extern int      STANDOUT;
73 extern int      alt_cmd_key, in_menu_mode, any_message;
74 extern long     n_selected;
75 
76 extern char     delayed_msg[];
77 
78 static int      rot13_must_init = 1;
79 static char     rot13_table[128];
80 int             rot13_active = 0;
81 #define ROT13_DECODE(c) 	((c & 0x80) ? c : rot13_table[c])
82 
83 static int      compress_space;
84 
85 static regexp  *regular_expr = NULL;
86 
87 #define LINEMAX	100		/* most articles are less than 100 lines */
88 
89 int             mark_overlap_shading = 0;
90 
91 static struct header_def {
92     char            field;
93     char           *text;
94     char          **news;
95     char          **digest;
96 }               header_defs[] = {
97 
98     'A', "Approved", &news.ng_appr, 0,
99     'B', "Distribution", &news.ng_dist, 0,
100     'c', "Comment-To", &news.ng_comment, 0,
101     'C', "Control", &news.ng_control, 0,
102     'D', "Date", &news.ng_date, &digest.dg_date,
103     'F', "From", &news.ng_from, &digest.dg_from,
104     'f', "Sender", &news.ng_sender, 0,
105     'I', "Message-Id", &news.ng_ident, 0,
106     'J', "Originator", &news.ng_origr, 0,
107     'K', "Keywords", &news.ng_keyw, 0,
108     'L', "Lines", &news.ng_xlines, 0,
109     'N', "Newsgroups", &news.ng_groups, 0,
110     'O', "Organization", &news.ng_org, 0,
111     'P', "Path", &news.ng_path, 0,
112     'R', "Reply-To", &news.ng_reply, 0,
113     'S', "Subject", &news.ng_subj, &digest.dg_subj,
114     'W', "Followup-To", &news.ng_follow, 0,
115     'X', "References", &news.ng_ref, 0,
116     'Y', "Summary", &news.ng_summ, 0,
117     'd', "Date-Received", &news.ng_rdate, 0,
118     'g', "Newsgroup", &news.ng_groups, 0,
119     'G', "Newsgroup", &news.ng_groups, 0,
120     'n', "Newsgroups", &news.ng_groups, 0,
121     'x', "Back-Ref", &news.ng_bref, 0,
122     'v', "Save-File", NULL, 0,
123     'a', "Spool-File", NULL, 0,
124     'i', "DB-Info", NULL, 0,
125     0
126 };
127 
128 static int
get_header_field(char code,char ** namep,char ** valp,register article_header * ah)129 get_header_field(char code, char **namep, char **valp, register article_header * ah)
130 {
131     static char     special[FILENAME];
132     register struct header_def *hdef;
133     char           *lp;
134 
135     lp = NULL;
136     for (hdef = header_defs; hdef->field; hdef++) {
137 	if (hdef->field != code)
138 	    continue;
139 
140 	if ((ah->flag & A_DIGEST) && hdef->digest)
141 	    lp = *(hdef->digest);
142 	if (lp == NULL && hdef->news)
143 	    lp = *(hdef->news);
144 	break;
145     }
146 
147     switch (code) {
148 	case 'n':
149 	case 'g':
150 	    if (lp == NULL)
151 		break;
152 	    if (!(current_group->group_flag & G_MERGED) && strchr(lp, ',') == NULL)
153 		return 0;
154 	    if (code == 'n')
155 		break;
156 	    /* FALLTHROUGH */
157 	case 'G':
158 	    if (ah->a_number > 0) {
159 		sprintf(special, "%s/%ld",
160 			current_group->group_name, (long) ah->a_number);
161 		lp = special;
162 	    } else
163 		lp = current_group->group_name;
164 	    break;
165 
166 	case 'a':
167 	    if (current_group->group_flag & G_FOLDER)
168 		lp = current_group->archive_file;
169 	    else if (group_file_name && *group_file_name)
170 		lp = group_path_name;
171 	    break;
172 
173 	case 'v':
174 	    if ((lp = current_group->save_file) == NULL)
175 		lp = (current_group->group_flag & G_FOLDER) ?
176 		    folder_save_file : default_save_file;
177 	    if (lp == NULL)
178 		return 0;
179 	    if (expand_file_name(special, lp, 2))
180 		lp = special;
181 	    break;
182 
183 	case 'i':
184 	    sprintf(special, "#%ld fl=%ld re=%d li=%d hp=%ld fp=%ld lp=%ld ts=%ld",
185 		    (long) ah->a_number, (long) ah->flag, (int) ah->replies,
186 		    ah->lines, ah->hpos, ah->fpos, (long) ah->lpos,
187 		    (long) ah->t_stamp);
188 	    lp = special;
189 	    break;
190     }
191     if (lp == NULL)
192 	return 0;
193 
194     *namep = hdef->text;
195     *valp = lp;
196     return 1;
197 }
198 
199 static char    *scan_codes;
200 static article_header *scan_arthdr;
201 
202 void
scan_header_fields(char * fields,article_header * ah)203 scan_header_fields(char *fields, article_header * ah)
204 {
205     scan_codes = fields;
206     scan_arthdr = ah;
207 }
208 
209 int
next_header_field(char ** namep,char ** valp,fct_type * attrp)210 next_header_field(char **namep, char **valp, fct_type * attrp)
211 {
212     fct_type        attr;
213 
214     while (*scan_codes) {
215 	attr = NULL_FCT;
216 	*namep = NULL;
217 
218 	switch (*scan_codes) {
219 	    case '*':
220 		scan_codes++;
221 		return 1;	/* name == NULL */
222 
223 	    case '=':
224 		attr = highlight;
225 		scan_codes++;
226 		break;
227 
228 	    case '_':
229 		attr = underline;
230 		scan_codes++;
231 		break;
232 
233 	    case '+':
234 		attr = shadeline;
235 		scan_codes++;
236 		break;
237 	}
238 
239 	if (*scan_codes == NUL)
240 	    break;
241 
242 	if (attrp)
243 	    *attrp = attr;
244 	if (get_header_field(*scan_codes++, namep, valp, scan_arthdr))
245 	    return 1;
246     }
247     return 0;
248 }
249 
250 static void
more_auto_select(void)251 more_auto_select(void)
252 {
253     register article_header *ah;
254     register int32  n;
255     int             count = 0;
256 
257     for (n = 0; n < n_articles; n++) {
258 	ah = articles[n];
259 	if (ah->attr == A_READ)
260 	    continue;
261 	if (ah->attr & A_SELECT)
262 	    continue;
263 
264 	if (auto_select_article(ah, 2)) {
265 	    ah->attr = A_AUTO_SELECT;
266 	    show_art_next_invalid = 1;
267 	    count++;
268 	}
269     }
270 
271     if (count)
272 	msg("Selected %d articles", count);
273 }
274 
275 static char    *
a_st_flags(flag_type flag)276 a_st_flags(flag_type flag)
277 {
278     static char     buf[40];
279     register char  *cp;
280     static flag_type prevflag = 0;
281 
282     flag &= A_ST_FILED | A_ST_REPLY | A_ST_FOLLOW;
283     if (flag == 0) {
284 	prevflag = 0;
285 	return "";
286     }
287     if (flag == prevflag)
288 	return buf;
289     prevflag = flag;
290 
291     cp = buf;
292     *cp++ = '(';
293     if (flag & A_ST_FILED) {
294 	*cp++ = 'F';
295 	*cp++ = 'i';
296 	*cp++ = 'l';
297 	*cp++ = 'e';
298 	*cp++ = 'd';
299     }
300     if (flag & A_ST_REPLY) {
301 	if (cp[-1] != '(')
302 	    *cp++ = SP;
303 	*cp++ = 'R';
304 	*cp++ = 'e';
305     }
306     if (flag & A_ST_FOLLOW) {
307 	if (cp[-1] != '(')
308 	    *cp++ = SP;
309 	*cp++ = 'F';
310 	*cp++ = 'o';
311 	*cp++ = 'l';
312     }
313     strcpy(cp, new_read_prompt ? ")--" : ")------");
314     return buf;
315 }
316 
317 static void
brief_header_line(register article_header * ah,int lno)318 brief_header_line(register article_header * ah, int lno)
319 {
320     int             o_re_layout;
321 
322     so_gotoxy(0, lno, 0);
323     so_printf("%s: ", ah->sender);
324     o_re_layout = re_layout;
325     if (re_layout_more >= 0)
326 	re_layout = re_layout_more;
327     prt_replies(ah->replies);
328     re_layout = o_re_layout;
329     so_printf("%s", ah->subject);
330     so_end();
331 }
332 
333 #ifdef NOV
334 /* fill in ah->?pos from the article itself */
335 /* This should really go into more itself */
336 void
setpos(register article_header * ah,register FILE * art)337 setpos(register article_header * ah, register FILE * art)
338 {
339     /* XXX: set to zero here? Digests? */
340     register long   startpos = ftell(art);
341     char            line[1024];
342 
343     ah->fpos = 0;		/* initialize in case not found */
344 
345     /* header position == beginning of file */
346     ah->hpos = 0;
347 
348     /* find the length */
349     fseek(art, 0L, 2);
350     ah->lpos = ftell(art);
351 
352     /* always start from the beginning */
353     fseek(art, 0L, 0);
354     while (fgets(line, sizeof(line), art) != NULL)
355 	if (*line == '\n') {	/* end of header? */
356 	    ah->fpos = ftell(art);	/* start of article */
357 	    break;
358 	}
359     fseek(art, startpos, 0);
360 }
361 
362 #endif				/* NOV */
363 
364 
365 int
more(article_header * ah,int mode,int screen_offset)366 more(article_header * ah, int mode, int screen_offset)
367 {
368     register char  *lp;
369     register int    c, col, lno = 0;
370     register FILE  *art;
371     int             more_cmd, eof, skip_spaces, has_space, window_lines;
372     int             form_feed, last_ff_line, ignore_nl = 0;
373     long            lineposbuf[LINEMAX];
374     long           *linepos = lineposbuf;
375     int             linemax = LINEMAX;
376     char            linebuf[200], skip_char;
377     int             skip_wrap;
378     news_header_buffer ngheader, dgheader;
379     struct news_header news_save;
380     struct digest_header digest_save;
381     int             linenum, maxline, topline, print_lines, lno1;
382     int             scroll_lines, scroll_from;
383     off_t           scroll_offset;
384     int             underline_line, fake_underline;
385     int             match_lines, match_redraw, match_topline = 0, match_botline;
386     int             goto_line, prev_goto, stop_line, extra_lines;
387     flag_type       in_digest = ah->flag & A_DIGEST;
388     article_header  digestah;
389     char           *fname, *hdrline;
390     char            pr_fmt[200], send_date[40];
391     int             match_expr, shade_overlap, shade_line;
392     int            *key_map;
393     key_type        cur_key;
394     fct_type        hdrattr;
395     char           *match_start, *match_end = NULL;
396     int             open_modes, o_mode;
397 
398 #ifdef RESIZING
399     int             entry_col = Columns;
400 #endif
401 
402 #define more_return(cmd) \
403     { more_cmd = cmd; goto more_exit; }
404 
405     if (ah->a_group != NULL)
406 	init_group(ah->a_group);
407 
408     open_modes = SKIP_HEADER;
409     if (show_article_date || header_lines) {
410 	open_modes |= FILL_NEWS_HEADER;
411 	if (header_lines == NULL)
412 	    open_modes |= GET_DATE_ONLY;
413 	else
414 	    open_modes |= GET_ALL_FIELDS;
415 	if (in_digest)
416 	    open_modes |= FILL_DIGEST_HEADER;
417     }
418     art = open_news_article(ah, open_modes, ngheader, dgheader);
419 
420     if (art == NULL) {
421 	if (expired_msg_delay >= 0) {
422 	    msg("Canceled or expired: \"%s: %-.35s\"", ah->sender, ah->subject);
423 	    if ((mode & MM_PREVIEW) == 0 && expired_msg_delay > 0)
424 		user_delay(expired_msg_delay);
425 	}
426 	return MC_NEXT;
427     }
428     o_mode = in_menu_mode;
429     in_menu_mode = 0;
430 
431     if (screen_offset) {
432 	if (preview_window < 1 && Lines - screen_offset < min_pv_window)
433 	    screen_offset = 0;
434 	else {
435 	    brief_header_line(ah, screen_offset++);
436 	    if (!STANDOUT)
437 		screen_offset++;
438 	    clrline();
439 	}
440     }
441     if (show_article_date) {
442 	if (in_digest && digest.dg_date)
443 	    strncpy(send_date, digest.dg_date, 40);
444 	else if (news.ng_date) {
445 	    strncpy(send_date, news.ng_date, 40);
446 	} else
447 	    send_date[0] = NUL;
448 	send_date[39] = NUL;
449 	if ((lp = strrchr(send_date, ':')))
450 	    *lp = NUL;
451     }
452     linepos[0] = ah->hpos;
453     linepos[1] = ah->fpos;
454     maxline = 1;
455     topline = 1;
456     hdrline = screen_offset == 0 ? header_lines : "";
457 
458     rot13_active = 0;
459     compress_space = compress_mode;
460     last_ff_line = goto_line = -1, prev_goto = 1;
461     skip_char = NUL;
462     skip_wrap = 0;
463     match_lines = match_redraw = match_expr = 0;
464     underline_line = -1;
465     fake_underline = 0;
466     shade_overlap = 0;
467 
468     /*
469      * initialization added by Peter Wemm..  These vars may be used before
470      * set, what should they *really* be set to to be safe? XXXX
471      */
472     window_lines = 0;
473     form_feed = 0;
474     lno1 = 0;
475     match_botline = 0;
476     extra_lines = 0;
477     cur_key = 0;
478     /* end */
479 
480     scroll_lines = scroll_from = 0;
481     scroll_offset = 0;
482     if (scroll_last_lines < 0)
483 	scroll_from = -1;
484     else if (scroll_last_lines > 0) {
485 	if (ah->lines > 0)
486 	    scroll_from = ah->lines - scroll_last_lines;
487 	else
488 	    scroll_offset = ah->lpos - (scroll_last_lines * 64);
489     }
490     stop_line = first_page_lines ? first_page_lines : -1;
491 
492     if (new_read_prompt) {
493 	char           *xp, *group_name = current_group->group_name;
494 	int             len, maxl;
495 
496 	maxl = novice ? 18 : 25;
497 
498 	if ((len = strlen(group_name)) > maxl) {
499 	    for (xp = group_name + len - maxl; *xp; xp++) {
500 		if (*xp == '.')
501 		    break;
502 		if (*xp == '/') {
503 		    xp++;
504 		    break;
505 		}
506 	    }
507 	    if (*xp)
508 		group_name = xp;
509 	    else
510 		group_name += len - maxl;
511 	}
512 	if (mode & (MM_PREVIEW | MM_DIGEST) || n_selected == 0)
513 	    sprintf(pr_fmt,
514 		    "\1\2--%s-- %s%s %s--%%s--%%s\1",
515 		    group_name,
516 		    (mode & MM_DIGEST) ? "DIGEST" :
517 		    (mode & MM_PREVIEW) ? "PREVIEW" : "LAST",
518 		    (ah->flag & A_NEXT_SAME) ? "+next" : "",
519 		    novice ? "--help:?" : "");
520 	else
521 	    sprintf(pr_fmt,
522 		    "\1\2--%s-- %ld MORE%s %s--%%s--%%s\1",
523 		    group_name,
524 		    n_selected,
525 		    (ah->flag & A_NEXT_SAME) ? "+next" : "",
526 		    novice ? "--help:?" : "");
527     } else
528 	sprintf(pr_fmt,
529 		"\1\2-- %s%s %s-----%%s%s-----%%s\1",
530 		(mode & MM_PREVIEW) ? "PREVIEW " : "",
531 		(mode & MM_DIGEST) ? "FULL DIGEST" :
532 		(mode & MM_LAST_SELECTED) ? "LAST ARTICLE" : "ARTICLE",
533 		novice ? "-- help:? " : "",
534 		(ah->flag & A_NEXT_SAME) ? " (+next)" : "");
535 
536     if (screen_offset)
537 	goto safe_redraw;
538 
539 redraw:			/* redraw that will destroy whole screen */
540     screen_offset = 0;
541 
542 safe_redraw:			/* redraw of "more window" only */
543     linenum = topline;
544 
545 next_page:
546     no_raw();
547 
548     s_keyboard = 0;
549 
550     if (stop_line) {
551 	lno = screen_offset;
552 	if (scroll_clear_page || linenum <= 1) {
553 	    if (lno) {
554 		gotoxy(0, lno);
555 		clrpage();
556 	    } else
557 		clrdisp();
558 	}
559 	if (linenum == 1) {
560 	    hdrline = screen_offset == 0 ? header_lines : "";
561 	    if (hdrline && hdrline[0] == '@') {
562 		linenum = 0;
563 		fseek(art, linepos[0], 0);
564 		hdrline = NULL;
565 	    }
566 	}
567 print_header:
568 	if (hdrline == NULL || *hdrline == '*') {
569 	    if (hdrline && *++hdrline == NUL)
570 		hdrline = NULL;
571 
572 	    if (linenum <= 1) {
573 		if (linenum == 0 || (mode & MM_DIGEST)) {
574 		    if (screen_offset) {
575 			lno--;
576 			if (!STANDOUT)
577 			    lno--;
578 			gotoxy(0, lno);
579 		    }
580 		    so_printxy(0, lno,
581 			       "Newsgroup: %s, article: %ld%s",
582 			       current_group->group_name,
583 			       (long) (ah->a_number),
584 			       ((mode & MM_DIGEST) || in_digest)
585 			       ? "  *DIGEST*" : "");
586 /*		    fseek(art, linepos[0], 0); */
587 
588 		    lno++;
589 		    if (!STANDOUT)
590 			lno++;
591 		} else {
592 		    if (screen_offset == 0 && linenum == 1) {
593 			if (show_article_date)
594 			    so_printxy(-1, 0, send_date);
595 
596 			brief_header_line(ah, lno++);
597 			if (!STANDOUT)
598 			    lno++;
599 		    }
600 		}
601 	    }
602 	}
603 	if (hdrline && screen_offset == 0) {
604 
605 	    scan_header_fields(hdrline, ah);
606 	    while (next_header_field(&fname, &hdrline, &hdrattr)) {
607 
608 		if (fname == NULL) {
609 		    hdrline = --scan_codes;	/* this is a hack! */
610 		    goto print_header;
611 		}
612 		lp = hdrline;
613 
614 		gotoxy(0, lno++);
615 		tprintf("%s: ", fname);
616 		c = col = strlen(fname) + 2;
617 
618 	split_header_line:
619 		if (hdrattr)
620 		    CALL(hdrattr) (1);
621 
622 		while (*lp && c < Columns) {
623 		    if (isspace(*lp)) {
624 			while (lp[1] && isspace(lp[1]))
625 			    lp++;
626 			if (wrap_headers > 0 &&
627 			    (c + wrap_headers) >= Columns &&
628 			    (int) strlen(lp) >= wrap_headers) {
629 			    lp++;
630 			    break;
631 			}
632 			*lp = SP;
633 		    }
634 		    tputc(*lp++);
635 		    c++;
636 		}
637 		if (hdrattr)
638 		    CALL(hdrattr) (0);
639 		if (*lp && wrap_headers >= 0) {
640 		    gotoxy(col, lno++);
641 		    c = col;
642 		    goto split_header_line;
643 		}
644 	    }
645 
646 	    hdrline = NULL;
647 	    tputc(NL);
648 	    lno++;
649 	}
650 	lno1 = lno;
651 	topline = linenum;
652 
653 	window_lines = Lines - lno - 2;
654 	print_lines = window_lines;
655 
656 	ignore_nl = 1;		/* ignore blank lines at top op screen */
657     } else {
658 	tputc(CR);
659 	clrline();
660 	print_lines = extra_lines;	/* LINT complaints here -- ignore */
661     }
662 
663     if (stop_line > 0) {
664 	if (print_lines > stop_line) {
665 	    extra_lines = print_lines - stop_line;
666 	    print_lines = stop_line;
667 	    underline_line = -1;
668 	    shade_overlap = 0;
669 	}
670 	stop_line = 0;
671     } else
672 	stop_line = -1;
673 
674 next_line:
675 
676     if (linenum == linemax) {
677 	linemax += 500;
678 	if (linepos == lineposbuf) {
679 	    linepos = newobj(long, linemax);
680 	    for (linenum = 0; linenum < LINEMAX; linenum++)
681 		linepos[linenum] = lineposbuf[linenum];
682 	} else
683 	    linepos = resizeobj(linepos, long, linemax);
684     }
685     if (goto_line == linenum) {
686 	goto_line = -1;
687 	goto next_page;
688     }
689     eof = 0;
690 
691     if (linenum > maxline)
692 	linepos[++maxline] = ftell(art);
693     else if (linenum > 0)
694 	fseek(art, linepos[linenum], 0);
695 
696 
697     if (linepos[linenum] >= ah->lpos) {
698 	if (match_expr) {
699 	    match_expr = 0;
700 	    topline = match_topline;	/* LINT complaints here -- ignore */
701 	    linenum = match_botline;	/* LINT complaints here -- ignore */
702 	    fseek(art, linepos[linenum], 0);
703 	    msg("Not found");
704 	    goto Prompt;
705 	}
706 	eof++;
707 	if (goto_line > 0) {
708 	    goto_line = -1;
709 	    linenum -= window_lines / 2;
710 	    goto next_page;
711 	}
712 	goto Prompt;
713     }
714     if (linenum == 0) {
715 	if (ftell(art) >= linepos[1]) {
716 	    linenum = 2;	/* current line is 1st line ! */
717 	    lno1 = lno;
718 	}
719     } else {
720 	if (match_expr && linenum == match_botline)
721 	    msg("Searching...");
722 	linenum++;
723     }
724 
725     lp = linebuf;
726     col = 0;
727     form_feed = 0;
728 
729 next_char:
730 
731     c = getc(art);
732     if (c == EOF) {
733 	eof++;
734 	if (lp == linebuf)
735 	    goto Prompt;
736 	goto end_line;
737     }
738     if (c & 0200) {
739 	if (monitor_mode || data_bits != 8) {
740 	    col += 4;
741 	    if (col > Columns) {/* then there is no room for M-^X */
742 		ungetc(c, art);
743 		goto long_line;
744 	    }
745 	    c &= 0177;
746 	    *lp++ = 'M';
747 	    *lp++ = '-';
748 	    if (c < SP) {
749 		*lp++ = '^';
750 		c += '@';
751 	    } else
752 		col--;
753 	}
754     } else if (c < SP) {
755 	if (monitor_mode) {
756 	    if (c == NL) {
757 		*lp++ = '$';
758 		goto end_line;
759 	    }
760 	    if (col + 2 > Columns) {
761 		*lp++ = '\\';
762 		ungetc(c, art);
763 		goto end_line;
764 	    }
765 	    *lp++ = '^';
766 	    c += '@';
767 	    col++;
768 	} else
769 	    switch (c) {
770 
771 		case '\f':
772 		    if (ignore_formfeed == 1)
773 			goto default_control;
774 		    last_ff_line = linenum;
775 		    if (lp == linebuf) {
776 			if (goto_line > 0 || skip_char || match_expr || lno == lno1)
777 			    goto next_line;
778 			form_feed = 1;
779 			goto Prompt;
780 		    }
781 		    form_feed = 1;
782 		    goto end_line;
783 
784 		case CR:
785 		    if (lp == linebuf || ignore_nl)
786 			goto next_char;
787 		    ignore_nl = 1;
788 		    goto end_line;
789 
790 		case NL:
791 		    if (ignore_nl) {
792 			ignore_nl = 0;
793 			if (lp == linebuf) {
794 			    if (lno == lno1) {
795 				ignore_nl = 1;
796 				goto next_line;
797 			    }
798 			    goto next_char;
799 			}
800 		    }
801 		    goto end_line;
802 
803 		case BS:
804 		    if (col) {
805 			lp--;
806 			col--;
807 		    }
808 		    goto next_char;
809 
810 		case TAB:
811 		    if (col + 8 - (col & 07) >= Columns)
812 			goto long_line;
813 
814 		    do {
815 			*lp++ = SP;
816 			col++;
817 		    } while (col & 07);
818 		    goto next_char;
819 
820 		case 033:	/* ESC may be a start/end of kanji or similar */
821 		    if (trusted_escapes != NULL) {
822 			if (col + 3 > Columns) {
823 			    ungetc(c, art);
824 			    goto long_line;
825 			}
826 			if (strcmp(trusted_escapes, "all") == 0)
827 			    break;
828 			c = getc(art);
829 			if (c == EOF)
830 			    goto next_char;
831 			ungetc(c, art);
832 			for (fname = trusted_escapes; *fname; fname++)
833 			    if (c == *fname)
834 				break;
835 			c = 033;
836 			if (*fname != NUL)
837 			    break;
838 		    }
839 		    /* FALLTHROUGH */
840 
841 	    default_control:
842 		default:
843 		    if (col + 2 > Columns) {
844 			ungetc(c, art);
845 			goto long_line;
846 		    }
847 		    *lp++ = '^';
848 		    c += '@';
849 		    col++;
850 		    break;
851 	    }
852     } else if (rot13_active && linenum > 0)
853 	c = ROT13_DECODE(c);
854 
855     *lp++ = c;
856     col++;
857     ignore_nl = 0;
858 
859     if (col < Columns)
860 	goto next_char;
861 
862 long_line:
863     ignore_nl = 1;
864 
865 end_line:
866     /* if we are seaching for a specific line, repeat until it is found */
867     if (skip_wrap) {
868 	skip_wrap = ignore_nl;
869 	goto next_line;
870     }
871     if (goto_line >= linenum)
872 	goto next_line;
873     if (skip_char) {
874 	if (lp == linebuf || linebuf[0] == skip_char) {
875 	    skip_wrap = ignore_nl;
876 	    goto next_line;
877 	}
878 	skip_char = NUL;
879 	if (overlap > 0) {
880 	    underline_line = linenum - 1;
881 	    linenum -= overlap + 1;
882 	    shade_overlap = mark_overlap_shading;
883 	    goto next_page;
884 	}
885     }
886     *lp++ = NUL;
887 
888     if (match_expr) {
889 	if (!regexec_cf(regular_expr, linebuf))
890 	    goto next_line;
891 	match_expr = 0;
892 	match_lines = 1;
893 	if (linenum > match_botline) {
894 	    match_redraw = 0;
895 	    if (last_ff_line > linenum)
896 		last_ff_line = -1;
897 	    linenum -= 5;
898 	    if (linenum < last_ff_line)
899 		linenum = last_ff_line;
900 	    goto next_page;
901 	}
902 	match_redraw = (stop_line < 0);
903 	stop_line = -1;
904 	lno = lno1 + linenum - topline - 1;
905 	print_lines = window_lines - lno + lno1;
906     }
907     /* now print the line */
908 
909     shade_line = 0;
910     if ((shade_overlap > 0 && linenum <= underline_line) ||
911 	(shade_overlap < 0 && linenum > underline_line)) {
912 	if (match_redraw)
913 	    goto no_print;
914 	match_start = NULL;
915 	shade_line = 1;
916     } else if (match_lines && underline_line != linenum &&
917 	       regexec_cf(regular_expr, linebuf)) {
918 	match_start = regular_expr->startp[0];
919 	match_end = regular_expr->endp[0];
920 	if (match_start == match_end) {
921 	    match_start = NULL;	/* null string */
922 	    if (match_redraw)
923 		goto no_print;
924 	}
925     } else {
926 	if (match_redraw)
927 	    goto no_print;
928 	match_start = NULL;
929     }
930 
931     gotoxy(0, lno);
932     if (!scroll_clear_page)
933 	clrline();
934 
935     if (shade_line)
936 	shadeline(1);
937     else if (mark_overlap && underline_line == linenum)
938 	if (!underline(1))
939 	    fake_underline = 1;
940     skip_spaces = has_space = 0;
941 
942     for (lp = linebuf; ((c = *lp)); lp++) {
943 
944 	if (match_start) {
945 	    if (lp == match_start)
946 		highlight(1);
947 	    if (lp == match_end) {
948 		highlight(0);
949 		match_start = NULL;
950 		if (regexec_cf(regular_expr, lp)) {
951 		    match_start = regular_expr->startp[0];
952 		    match_end = regular_expr->endp[0];
953 		    lp--;
954 		    continue;
955 		}
956 		if (match_redraw)
957 		    goto no_print;
958 	    }
959 	}
960 	if (c == SP) {
961 	    if (skip_spaces) {
962 		if (has_space)
963 		    continue;
964 		has_space++;
965 	    }
966 	    if (fake_underline)
967 		c = '_';
968 	} else {
969 	    if (compress_space && c != ' ') {
970 		skip_spaces = 1;
971 		has_space = 0;
972 	    }
973 	}
974 
975 	tputc(c);
976     }
977 
978     if (match_start)
979 	highlight(0);
980 
981     if (shade_line) {
982 	shadeline(0);
983 	if (shade_overlap > 0 && underline_line == linenum) {
984 	    underline_line = -1;
985 	    shade_overlap = 0;
986 	}
987     } else if (mark_overlap && underline_line == linenum) {
988 	while (lp - linebuf < 10) {
989 	    tputc(fake_underline ? '_' : ' ');
990 	    lp++;
991 	}
992 	underline(0);
993 	underline_line = -1;
994 	fake_underline = 0;
995     }
996 no_print:
997 
998     ++lno;
999     if (--print_lines > 0 && s_keyboard == 0 && form_feed == 0)
1000 	goto next_line;
1001 
1002     if (shade_overlap) {
1003 	underline_line = -1;
1004 	shade_overlap = 0;
1005     }
1006     if (!eof && linenum >= maxline) {
1007 	if (ignore_nl) {
1008 	    c = getc(art);
1009 	    if (c == EOF)
1010 		eof++;
1011 	    else if (c != NL)
1012 		ungetc(c, art);
1013 	    else
1014 		ignore_nl = 0;
1015 	}
1016 	if (!eof && ftell(art) >= ah->lpos)
1017 	    eof++;
1018     }
1019     match_redraw = 0;
1020 
1021 Prompt:
1022 
1023     if (eof && lno == screen_offset)
1024 	more_return(MC_NEXT);
1025 
1026     if (scroll_lines > 0) {
1027 	if (eof)
1028 	    scroll_lines = 0;
1029 	else {
1030 	    print_lines = 1;
1031 	    scroll_lines--;
1032 	    prompt_line = lno;
1033 	    goto scroll_next;
1034 	}
1035     }
1036     nn_raw();
1037 
1038     prompt_line = lno;
1039 
1040     if (!scroll_clear_page)
1041 	clrpage();
1042 
1043 dflt_prompt:
1044 
1045     prompt(pr_fmt,
1046 	   pct(ah->fpos, (long) (ah->lpos),
1047 	       linepos[topline], ftell(art)),
1048 	   a_st_flags(ah->flag));
1049 
1050     if (delayed_msg[0] != NUL) {
1051 	msg(delayed_msg);
1052 	delayed_msg[0] = NUL;
1053     }
1054 same_prompt:
1055 
1056     if (flush_typeahead)
1057 	flush_input();
1058 
1059     key_map = more_key_map;
1060 
1061 prefix_key:
1062     if ((c = get_c()) & GETC_COMMAND)
1063 	c &= ~GETC_COMMAND;
1064     else
1065 	c = key_map[cur_key = c];
1066 
1067     if (s_hangup)
1068 	c = K_QUIT;
1069 
1070     if (c & K_PREFIX_KEY) {
1071 	key_map = keymaps[c & ~K_PREFIX_KEY].km_map;
1072 	if (echo_prefix_key)
1073 	    msg("%s", key_name(cur_key));
1074 	goto prefix_key;
1075     }
1076     if (any_message && c != K_LAST_MESSAGE)
1077 	clrmsg(0);
1078 
1079     if (c & K_MACRO) {
1080 	m_invoke(c & ~K_MACRO);
1081 	goto same_prompt;
1082     }
1083 #define STATE(new_state)  c = new_state; goto alt_key;
1084 
1085 alt_key:
1086 
1087     switch (c) {
1088 	case K_UNBOUND:
1089 	    ding();
1090 	    /* FALLTHROUGH */
1091 	case K_INVALID:
1092 	    goto same_prompt;
1093 
1094 	case K_REDRAW:
1095 
1096 #ifdef RESIZING
1097 	    if (Columns != entry_col) {
1098 		entry_col = Columns;
1099 		maxline = topline = 1;
1100 	    }
1101 #endif
1102 
1103 	    goto redraw;
1104 
1105 	case K_M_CONTINUE:
1106 	    if (mouse_y >= 0) {
1107 		if (mouse_y >= prompt_line) {
1108 		    STATE(K_NEXT_ARTICLE);
1109 		} else if (mouse_y == 0) {
1110 		    if (topline == 1) {
1111 			STATE(K_PREVIOUS);
1112 		    } else {
1113 			STATE(K_PREV_PAGE);
1114 		    }
1115 		} else {
1116 		    STATE(K_CONTINUE);
1117 		}
1118 	    }
1119 	    /* fall through??? */
1120 
1121 	case K_NEXT_PAGE:
1122 	    if (eof) {
1123 		ding();
1124 		goto same_prompt;
1125 	    }
1126 	    /* FALLTHROUGH */
1127 	case K_CONTINUE:
1128 	    if (eof)
1129 		break;
1130 	    if (screen_offset == 0 && form_feed == 0 && stop_line) {
1131 		if ((scroll_from && linenum > scroll_from) ||
1132 		    (scroll_offset && ftell(art) > scroll_offset)) {
1133 		    scroll_lines = Lines - 2 - overlap;
1134 		    print_lines = 1;
1135 		    goto scroll;
1136 		}
1137 		if (linenum > overlap) {
1138 		    underline_line = linenum;
1139 		    linenum -= overlap;
1140 		    shade_overlap = mark_overlap_shading;
1141 		}
1142 	    }
1143 	    goto next_page;
1144 
1145 	case K_LAST_MESSAGE:
1146 	    msg((char *) NULL);
1147 	    goto dflt_prompt;
1148 
1149 	case K_HELP:
1150 	    display_help("more");
1151 	    goto redraw;
1152 
1153 	case K_SHELL:
1154 	    tputc(CR);
1155 	    if (shell_escape())
1156 		goto redraw;
1157 	    goto dflt_prompt;
1158 
1159 	case K_VERSION:
1160 	    prompt(P_VERSION);
1161 	    goto same_prompt;
1162 
1163 	case K_M_TOGGLE:
1164 	    if (mouse_state) {
1165 		xterm_mouse_off();
1166 		mouse_state = 0;
1167 	    } else {
1168 		xterm_mouse_on();
1169 		mouse_state = 1;
1170 	    }
1171 	    goto dflt_prompt;
1172 
1173 	case K_EXTENDED_CMD:
1174 	    news_save = news;
1175 	    digest_save = digest;
1176 	    more_cmd = alt_command();
1177 	    news = news_save;
1178 	    digest = digest_save;
1179 
1180 	    switch (more_cmd) {
1181 
1182 		case AC_UNCHANGED:
1183 		    goto same_prompt;
1184 
1185 		case AC_QUIT:
1186 		    more_return(MC_QUIT);
1187 		    break;	/* for lint */
1188 
1189 		case AC_PROMPT:
1190 		    goto dflt_prompt;
1191 
1192 		case AC_REENTER_GROUP:
1193 		    more_return(MC_REENTER_GROUP);
1194 		    break;	/* for lint */
1195 
1196 		case AC_REORDER:
1197 		    more_return(MC_MENU);
1198 		    break;	/* for lint */
1199 
1200 		case AC_REDRAW:
1201 		    goto redraw;
1202 
1203 		case AC_KEYCMD:
1204 		    c = alt_cmd_key;
1205 		    goto alt_key;
1206 	    }
1207 	    /* XXX: fall-thru? */
1208 	case K_QUIT:
1209 	    ah->attr = A_LEAVE_NEXT;
1210 	    more_return(MC_QUIT);
1211 	    break;		/* for lint */
1212 
1213 	case K_SAVE_NO_HEADER:
1214 	case K_SAVE_SHORT_HEADER:
1215 	case K_SAVE_FULL_HEADER:
1216 	case K_SAVE_HEADER_ONLY:
1217 	case K_PRINT:
1218 	case K_UNSHAR:
1219 	case K_PATCH:
1220 	case K_UUDECODE:
1221 	    news_save = news;
1222 	    digest_save = digest;
1223 
1224 	    tputc(CR);
1225 	    if (init_save(c, (char **) NULL) != NULL) {
1226 		if (c == K_UNSHAR)
1227 		    prompt_line = Lines - 2;
1228 
1229 		save(ah);
1230 		end_save();
1231 	    }
1232 	    news = news_save;
1233 	    digest = digest_save;
1234 	    if (!slow_mode && (c == K_UNSHAR || c == K_PATCH)) {
1235 		tprintf("\r\n\n");
1236 		any_key(0);
1237 		goto redraw;
1238 	    }
1239 	    goto Prompt;
1240 
1241 	case K_FOLLOW_UP:
1242 	case K_REPLY:
1243 	case K_MAIL_OR_FORWARD:
1244 	    news_save = news;
1245 	    digest_save = digest;
1246 	    more_cmd = answer(ah, c, -1);
1247 	    news = news_save;
1248 	    digest = digest_save;
1249 	    if (more_cmd) {
1250 		if (slow_mode)
1251 		    clrdisp();
1252 		else
1253 		    goto redraw;
1254 	    }
1255 	    goto Prompt;
1256 
1257 	case K_POST:
1258 	    if (post_menu()) {
1259 		if (slow_mode)
1260 		    clrdisp();
1261 		else
1262 		    goto redraw;
1263 	    }
1264 	    goto Prompt;
1265 
1266 	case K_CANCEL:
1267 	    if (current_group->group_flag & G_FOLDER) {
1268 		prompt("%s this folder entry",
1269 		       (ah->attr == A_CANCEL) ? "UNcancel" : "Cancel");
1270 		if (yes(0))
1271 		    fcancel(ah);
1272 		goto Prompt;
1273 	    }
1274 	    if (cancel(ah) > 0)
1275 		goto Prompt;
1276 	    more_return(MC_NEXT);
1277 	    break;		/* for lint */
1278 
1279 	case K_UNSUBSCRIBE:
1280 	    if (!unsubscribe(current_group))
1281 		goto Prompt;
1282 	    if ((current_group->group_flag & G_UNSUBSCRIBED) == 0)
1283 		goto Prompt;
1284 	    more_return(MC_NEXTGROUP);
1285 	    break;		/* for lint */
1286 
1287 	case K_GROUP_OVERVIEW:
1288 	    group_overview(-1);
1289 	    goto redraw;
1290 
1291 	case K_KILL_HANDLING:
1292 	    switch (kill_menu(ah)) {
1293 		case 0:
1294 		    more_auto_select();
1295 		    ah->attr = 0;
1296 		    break;
1297 		case 1:
1298 		    more_return(MC_DO_KILL);
1299 		default:
1300 		    break;
1301 	    }
1302 	    goto Prompt;
1303 
1304 	case K_READ_GROUP_UPDATE:
1305 	    if (mode & MM_PREVIEW)
1306 		more_return(MC_MENU);
1307 	    prompt("Mark rest of current group as read?");
1308 	    if (yes(1) <= 0)
1309 		goto Prompt;
1310 	    more_return(MC_READGROUP);
1311 	    break;		/* for lint */
1312 
1313 	case K_NEXT_GROUP_NO_UPDATE:
1314 	    if (mode & MM_PREVIEW)
1315 		more_return(MC_MENU);
1316 	    more_return(MC_NEXTGROUP);
1317 	    break;		/* for lint */
1318 
1319 	case K_BACK_TO_MENU:
1320 	    more_return(MC_MENU);
1321 	    break;		/* for lint */
1322 
1323 	case K_PREVIOUS:
1324 	    if ((mode & MM_PREVIOUS) == 0) {
1325 		msg("No previous article");
1326 		goto dflt_prompt;
1327 	    }
1328 	    more_return(MC_PREV);
1329 
1330 	    /* FALLTHROUGH */
1331 	case K_ADVANCE_GROUP:
1332 	case K_BACK_GROUP:
1333 	case K_GOTO_GROUP:
1334 	    news_save = news;
1335 	    digest_save = digest;
1336 	    more_cmd = goto_group(c, ah, (flag_type) 0);
1337 	    news = news_save;
1338 	    digest = digest_save;
1339 
1340 	    switch (more_cmd) {
1341 		case ME_NO_REDRAW:
1342 		    goto Prompt;
1343 
1344 		case ME_QUIT:
1345 		    more_return(ME_QUIT);
1346 
1347 		default:
1348 		    goto redraw;
1349 	    }
1350 
1351 	case K_NEXT_LINE:
1352 	    if (eof)
1353 		break;
1354 	    if (screen_offset)
1355 		goto same_prompt;
1356 
1357 	    print_lines = 1;
1358 	    goto scroll;
1359 
1360 	case K_NEXT_HALF_PAGE:
1361 	    if (eof)
1362 		break;
1363 	    if (screen_offset)
1364 		goto same_prompt;
1365 
1366 	    print_lines = window_lines / 2;
1367 
1368     scroll:
1369 	    gotoxy(0, prompt_line);
1370 	    clrpage();
1371 	    no_raw();
1372 
1373 	    if (print_lines + lno < (Lines - 1))
1374 		goto next_page;
1375 
1376 	    stop_line = -1;
1377 
1378     scroll_next:
1379 	    gotoxy(0, Lines - 1);
1380 	    c = print_lines + lno - Lines + 2;
1381 	    while (--c >= 0) {
1382 		tputc(NL);
1383 		if (--lno1 < 0)
1384 		    topline++;
1385 		prompt_line--;
1386 	    }
1387 	    if (lno1 < 0)
1388 		lno1 = 0;
1389 	    if (prompt_line < 0)
1390 		prompt_line = 0;
1391 	    lno = prompt_line;
1392 	    goto next_line;
1393 
1394 	case K_PREV_HALF_PAGE:
1395 	    /* XXX: Bug: will not back over headers */
1396 	    if (topline <= 1)
1397 		goto Prompt;
1398 	    linenum = topline - window_lines / 2;
1399 	    if (linenum < 1)
1400 		linenum = 1;
1401 	    goto next_page;
1402 
1403 	case K_PREV_PAGE:
1404 	    /* XXX: Bug: will not back over headers */
1405 	    if (topline <= 1)
1406 		goto Prompt;
1407 	    linenum = topline - window_lines + overlap;	/* not perfect after FF */
1408 	    underline_line = topline;
1409 	    shade_overlap = -mark_overlap_shading;
1410 	    if (linenum < 1)
1411 		linenum = 1;
1412 	    goto next_page;
1413 
1414 	case K_SKIP_LINES:
1415 	    skip_char = linebuf[0];
1416 	    goto next_page;
1417 
1418 	case K_GOTO_LINE:
1419 	    prompt("\1Go to line:\1 ");
1420 	    if ((fname = get_s(NONE, NONE, "$^", NULL_FCT)) == NULL)
1421 		goto Prompt;
1422 
1423 	    if (*fname == NUL) {
1424 		if (prev_goto < 0)
1425 		    goto Prompt;
1426 		goto_line = prev_goto;
1427 
1428 	    } else if (*fname == '$')
1429 		goto_line = 30000;
1430 	    else if (*fname == '^')
1431 		goto_line = 1;
1432 	    else {
1433 		goto_line = atoi(fname);
1434 		if (goto_line <= 0) {
1435 		    goto_line = -1;
1436 		    goto Prompt;
1437 		}
1438 	    }
1439 
1440     goto_page:
1441 	    prev_goto = topline;
1442 
1443 	    if (goto_line <= maxline) {
1444 		linenum = goto_line;
1445 		goto_line = -1;
1446 	    }
1447 	    goto next_page;
1448 
1449 	case K_SELECT_SUBJECT:
1450 	    more_return(MC_ALLSUBJ);
1451 	    break;		/* for lint */
1452 
1453 	case K_HEADER_PAGE:
1454 	    fseek(art, linepos[0], 0);
1455 	    goto_line = 0;
1456 	    goto goto_page;
1457 
1458 	case K_FIRST_PAGE:
1459 	    goto_line = 1;
1460 	    goto goto_page;
1461 
1462 	case K_LAST_PAGE:
1463 	    goto_line = 30000;
1464 	    goto goto_page;
1465 
1466 	case K_GOTO_MATCH:
1467 	    prompt("\1/\1");
1468 	    if ((fname = get_s(NONE, NONE, "/", NULL_FCT)) == NULL)
1469 		goto Prompt;
1470 
1471 	    if (*fname && *fname != '/') {
1472 		if (regular_expr)
1473 		    freeobj(regular_expr);
1474 		if (case_fold_search)
1475 		    fold_string(fname);
1476 		regular_expr = regcomp(fname);
1477 		match_lines = 0;
1478 	    }
1479 	    /* XXX: fall here? */
1480 	case K_NEXT_MATCH:
1481 	    if (regular_expr == NULL) {
1482 		msg("No previous expression");
1483 		goto Prompt;
1484 	    }
1485 	    match_expr = 1;
1486 	    if (match_topline != topline)
1487 		prev_goto = topline;
1488 	    match_topline = topline;
1489 	    match_botline = linenum;
1490 	    if (match_lines == 0 && topline <= 1)
1491 		linenum = topline;
1492 	    match_lines = 0;
1493 	    goto next_line;	/* don't clear the screen if no match */
1494 
1495 	case K_FULL_DIGEST:
1496 	    if (mode & MM_DIGEST)
1497 		more_return(MC_NO_REDRAW);
1498 
1499 	    if (!in_digest)
1500 		goto same_prompt;
1501 
1502 	    /* could do something more clever here later */
1503 	    digestah = *ah;
1504 	    digestah.flag &= ~A_DIGEST;
1505 	    digestah.hpos = digestah.fpos = 0;
1506 	    fseek(art, 0L, 2);
1507 	    digestah.lpos = ftell(art);
1508 
1509 	    switch (more(&digestah, mode | MM_DIGEST, screen_offset)) {
1510 
1511 		case MC_REDRAW:
1512 		    goto redraw;
1513 
1514 		case MC_NO_REDRAW:
1515 		    goto safe_redraw;
1516 
1517 		case MC_QUIT:
1518 		    more_return(MC_QUIT);
1519 		    break;	/* for lint */
1520 
1521 		case MC_REENTER_GROUP:
1522 		    more_return(MC_REENTER_GROUP);
1523 
1524 		default:
1525 		    goto safe_redraw;
1526 	    }
1527 
1528 	case K_LEAVE_NEXT:
1529 	    ah->attr = A_LEAVE_NEXT;
1530 	    more_return(MC_PREVIEW_NEXT);
1531 	    break;		/* for lint */
1532 
1533 	case K_LEAVE_ARTICLE:
1534 	    ah->attr = (mode & MM_PREVIEW) ? A_SELECT : A_LEAVE;
1535 
1536 	    /* FALLTHROUGH */
1537 	case K_NEXT_ARTICLE:
1538 	    if ((mode & MM_PREVIEW) == 0)
1539 		break;
1540 	    more_return(MC_PREVIEW_NEXT);
1541 	    break;		/* for lint */
1542 
1543 	case K_BACK_ARTICLE:
1544 	    if (mode & MM_FIRST_ARTICLE) {
1545 		msg("First article is displayed");
1546 		goto same_prompt;
1547 	    }
1548 	    more_return(MC_BACK_ART);
1549 	    break;		/* for lint */
1550 
1551 	case K_FORW_ARTICLE:
1552 	    if (mode & MM_LAST_ARTICLE) {
1553 		msg("Last article is displayed");
1554 		goto same_prompt;
1555 	    }
1556 	    more_return(MC_FORW_ART);
1557 	    break;		/* for lint */
1558 
1559 	case K_NEXT_SUBJECT:
1560 	    more_return(MC_NEXTSUBJ);
1561 	    break;		/* for lint */
1562 
1563 	case K_ROT13:
1564 	    if (rot13_must_init) {
1565 		register int    i;
1566 		for (i = 0; i <= 127; i++) {
1567 		    c = i;
1568 		    if (c >= 'a' && c <= 'm')
1569 			c += 13;
1570 		    else if (c >= 'n' && c <= 'z')
1571 			c -= 13;
1572 		    else if (c >= 'A' && c <= 'M')
1573 			c += 13;
1574 		    else if (c >= 'N' && c <= 'Z')
1575 			c -= 13;
1576 		    rot13_table[i] = c;
1577 		}
1578 		rot13_must_init = 0;
1579 	    }
1580 	    rot13_active = !rot13_active;
1581 	    goto safe_redraw;
1582 
1583 	case K_COMPRESS:
1584 	    compress_space = !compress_space;
1585 	    goto safe_redraw;
1586 
1587 	case K_PREVIEW:
1588 	    if (mode & MM_PREVIEW)
1589 		more_return(MC_PREVIEW_OTHER);
1590 
1591 	    /* fall thru to "default" */
1592 
1593 	default:
1594 	    msg("Command %d not supported", c);
1595 	    goto dflt_prompt;
1596     }
1597 
1598     more_return(MC_NEXT);
1599 
1600 more_exit:
1601     in_menu_mode = o_mode;
1602     rot13_active = 0;
1603 
1604     if (linepos != lineposbuf)
1605 	freeobj(linepos);
1606 
1607     no_raw();
1608     fclose(art);
1609 
1610     if (mode & MM_PREVIEW)
1611 	if (more_cmd != MC_QUIT && more_cmd != MC_REENTER_GROUP) {
1612 	    gotoxy(0, screen_offset);
1613 	    clrpage();
1614 	    if (auto_preview_mode && ah->attr == 0)
1615 		ah->attr = A_READ;
1616 	    if (screen_offset == 0)
1617 		prompt_line = -1;
1618 	}
1619     return more_cmd;
1620 }
1621 
1622 
1623 void
rot13_line(register char * cp)1624 rot13_line(register char *cp)
1625 {
1626     register int    c;
1627 
1628     while ((c = *cp))
1629 	*cp++ = ROT13_DECODE(c);
1630 }
1631