home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume22 / nn6.4 / part09 / more.c
Encoding:
C/C++ Source or Header  |  1990-06-07  |  23.6 KB  |  1,180 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Article browser.
  5.  */
  6.  
  7. #include "config.h"
  8. #include "news.h"
  9. #include "term.h"
  10. #include "menu.h"
  11. #include "keymap.h"
  12. #include "regexp.h"
  13.  
  14. export int  monitor_mode = 0;
  15. export int  compress_mode = 0;
  16. export int  show_article_date = 1;
  17. export int  first_page_lines = 0;
  18. export int  overlap = 2;
  19. export int  mark_overlap = 0;
  20. export char *header_lines = NULL;
  21. export int  min_pv_window = 7;
  22. export int  wrap_headers = 6;
  23. export int  data_bits = 7;
  24. export int  scroll_clear_page = 1;
  25. export int  expired_msg_delay = 1;
  26.  
  27. import int  preview_window;
  28. import int  novice;
  29. import int  slow_mode;
  30. import int  auto_preview_mode;
  31. import int  flush_typeahead;
  32. import int  case_fold_search;
  33.  
  34. import char delayed_msg[];
  35.  
  36. extern char *init_save();
  37.  
  38. static int rot13_must_init = 1;
  39. static char rot13_table[128];
  40. export int rot13_active = 0;
  41. #define ROT13_DECODE(c)     ((c & 0x80) ? c : rot13_table[c])
  42.  
  43. static int compress_space;
  44.  
  45. static regexp *regular_expr = NULL;
  46.  
  47. #define LINEMAX    100        /* most articles are less than 100 lines */
  48.  
  49. static struct header_def {
  50.     char field;
  51.     char *text;
  52.     char **news;
  53.     char **digest;
  54. } header_defs[] = {
  55.     'A', "Approved",    &news.ng_appr,        0,
  56.     'B', "Distribution",&news.ng_dist,        0,
  57.     'D', "Date",    &news.ng_date,        &digest.dg_date,
  58.     'F', "From",    &news.ng_from,        &digest.dg_from,
  59.     'I', "Message-Id",    &news.ng_ident,        0,
  60.     'K', "Keywords",    &news.ng_keyw,        0,
  61.     'L', "Lines",    &news.ng_xlines,    0,
  62.     'N', "Newsgroups",    &news.ng_groups,    0,
  63.     'O', "Organization",&news.ng_org,        0,
  64.     'P', "Path",    &news.ng_path,        0,
  65.     'R', "Reply-To",    &news.ng_reply,        0,
  66.     'S', "Subject",    &news.ng_subj,        &digest.dg_subj,
  67.     'W', "Followup-To",    &news.ng_follow,    0,
  68.     'X', "References",    &news.ng_ref,        0,
  69.     'Y', "Summary",    &news.ng_summ,        0,
  70.     'd', "Date-Received", &news.ng_rdate,    0,
  71.     'n', "Newsgroups",    &news.ng_groups,    0,
  72.     'x', "Back-Ref",    &news.ng_bref,        0,
  73.     0
  74. };
  75.  
  76. static char *a_st_flags(flag)
  77. flag_type flag;
  78. {
  79.     static char buf[40];
  80.     register char *cp;
  81.     static flag_type prevflag = 0;
  82.  
  83.     flag &= A_ST_FILED | A_ST_REPLY | A_ST_FOLLOW;
  84.     if (flag == 0) {
  85.     prevflag = 0;
  86.     return "";
  87.     }
  88.  
  89.     if (flag == prevflag) return buf;
  90.     prevflag = flag;
  91.  
  92.     cp = buf;
  93.     *cp++ = '(';
  94.     if (flag & A_ST_FILED) {
  95.     *cp++ = 'F';
  96.     *cp++ = 'i';
  97.     *cp++ = 'l';
  98.     *cp++ = 'e';
  99.     *cp++ = 'd';
  100.     }
  101.  
  102.     if (flag & A_ST_REPLY) {
  103.     if (cp[-1] != '(') *cp++ = SP;
  104.     *cp++ = 'R';
  105.     *cp++ = 'e';
  106.     }
  107.  
  108.     if (flag & A_ST_FOLLOW) {
  109.     if (cp[-1] != '(') *cp++ = SP;
  110.     *cp++ = 'F';
  111.     *cp++ = 'o';
  112.     *cp++ = 'l';
  113.     }
  114.  
  115.     strcpy(cp, ")------");
  116.     return buf;
  117. }
  118.  
  119. more(ah, mode, screen_offset)
  120. article_header *ah;
  121. int mode, screen_offset;
  122. {
  123.     register int c, col, lno;
  124.     register FILE *art;
  125.     int more_cmd, eof, skip_spaces, has_space, window_lines;
  126.     int form_feed, last_ff_line, ignore_nl;
  127.     off_t firstl, lastl;
  128.     off_t lineposbuf[LINEMAX];
  129.     off_t *linepos = lineposbuf;
  130.     int linemax = LINEMAX;
  131.     char linebuf[200], *lp, skip_char;
  132.     int skip_wrap;
  133.     news_header_buffer ngheader, dgheader;
  134.     struct news_header news_save;
  135.     struct digest_header digest_save;
  136.     int linenum, maxline, topline, print_lines, lno1;
  137.     int underline_line, fake_underline;
  138.     int match_lines, match_redraw, match_topline, match_botline;
  139.     int goto_line, prev_goto, stop_line, extra_lines;
  140.     flag_type in_digest = ah->flag & A_DIGEST;
  141.     article_header digestah;
  142.     char *fname, *hdrline;
  143.     extern STANDOUT;
  144.     char pr_fmt[60], send_date[40];
  145.     int match_expr;
  146.     char *match_start, *match_end;
  147.     int open_modes, hdr_mode, o_mode;
  148.     struct header_def *hdef;
  149.     extern int alt_cmd_key, in_menu_mode, any_message;
  150. #ifdef RESIZING
  151.     int entry_col = Columns;
  152. #endif
  153.     extern char *pct();
  154.  
  155. #define more_return(cmd) \
  156.     { more_cmd = cmd; goto more_exit; }
  157.  
  158.     if (ah->a_group != NULL) init_group(ah->a_group);
  159.  
  160.     open_modes = SKIP_HEADER;
  161.     if (show_article_date || header_lines) {
  162.     open_modes |= FILL_NEWS_HEADER;
  163.     if (header_lines == NULL)
  164.         open_modes |= GET_DATE_ONLY;
  165.     else
  166.         open_modes |= GET_ALL_FIELDS;
  167.     if (in_digest) open_modes |= FILL_DIGEST_HEADER;
  168.     }
  169.  
  170.     art = open_news_article(ah, open_modes, ngheader, dgheader);
  171.  
  172.     if (art == NULL) {
  173.     if (expired_msg_delay >= 0) {
  174.         msg("Expired: \"%s: %-.50s\"", ah->sender, ah->subject);
  175.         if ((mode & MM_PREVIEW) == 0 && expired_msg_delay > 0)
  176.         user_delay(expired_msg_delay);
  177.     }
  178.     return MC_NEXT;
  179.     }
  180.  
  181.     o_mode = in_menu_mode;
  182.     in_menu_mode = 0;
  183.  
  184.     if (screen_offset)
  185.     if (preview_window < 1 && Lines - screen_offset < min_pv_window)
  186.         screen_offset = 0;
  187.         else {
  188.         so_printxy(0, screen_offset++, "%s: %s ", ah->sender, ah->subject);
  189.         if (!STANDOUT) screen_offset++;
  190.         clrline();
  191.     }
  192.  
  193.     if (show_article_date) {
  194.     if (in_digest && digest.dg_date)
  195.         strncpy(send_date, digest.dg_date, 40);
  196.     else
  197.         if (news.ng_date) {
  198.         strncpy(send_date, news.ng_date, 40);
  199.         } else
  200.         send_date[0] = NUL;
  201.     send_date[39] = NUL;
  202.     if (lp = strrchr(send_date, ':')) *lp = NUL;
  203.     }
  204.  
  205.     linepos[0] = ah->hpos;
  206.     linepos[1] = firstl = ah->fpos;
  207.     maxline = 1;
  208.     topline = 1;
  209.     hdrline = screen_offset == 0 ? header_lines : "";
  210.  
  211.     lastl = (ah->lpos - firstl + 99)/100;
  212.     if (lastl == 0) lastl = 1;    /* impossible ? */
  213.  
  214.     rot13_active = 0;
  215.     compress_space = compress_mode;
  216.     last_ff_line = goto_line = -1, prev_goto = 1;
  217.     skip_char = NUL; skip_wrap = 0;
  218.     match_lines = match_redraw = match_expr = 0;
  219.     underline_line = -1;
  220.     fake_underline = 0;
  221.  
  222.     stop_line = first_page_lines ? first_page_lines : -1;
  223.  
  224.     sprintf(pr_fmt,
  225.         "\1\2-- %s%s %s-----%%s%s-----%%s\1",
  226.         (mode & MM_PREVIEW) ? "PREVIEW " : "",
  227.         (mode & MM_DIGEST) ? "FULL DIGEST" :
  228.         (mode & MM_LAST_SELECTED) ? "LAST ARTICLE" : "ARTICLE",
  229.         novice ? "-- help:? " : "",
  230.         (ah->flag & A_NEXT_SAME) ? " (+next)" : "");
  231.  
  232.     if (screen_offset) goto safe_redraw;
  233.  
  234.  redraw:        /* redraw that will destroy whole screen */
  235.     screen_offset = 0;
  236.  
  237.  safe_redraw:     /* redraw of "more window" only */
  238.     linenum = topline;
  239.  
  240.  next_page:
  241.     no_raw();
  242.  
  243.     s_keyboard = 0;
  244.  
  245.     if (stop_line) {
  246.     lno = screen_offset;
  247.     if (scroll_clear_page || linenum <= 1) {
  248.         if (lno) {
  249.         gotoxy(0, lno);
  250.         clrpage(lno);
  251.         } else
  252.         clrdisp();
  253.     }
  254.  
  255.     if (linenum == 1)
  256.         hdrline = screen_offset == 0 ? header_lines : "";
  257.  
  258.       print_header:
  259.     if (hdrline == NULL || *hdrline == '*') {
  260.         if (hdrline && *++hdrline == NUL) hdrline = NULL;
  261.  
  262.         if (linenum <= 1) {
  263.         if (linenum == 0 || (mode & MM_DIGEST)) {
  264.             if (screen_offset) {
  265.             lno--;
  266.             if (!STANDOUT) lno--;
  267.             gotoxy(0, lno);
  268.             }
  269.  
  270.             so_printxy(0, lno,
  271.                    "Newsgroup: %s, article: %ld%s",
  272.                    current_group->group_name,
  273.                    (long)(ah->a_number),
  274.                    ((mode & MM_DIGEST) || in_digest)
  275.                    ? "  *DIGEST*" : "");
  276. /*            fseek(art, linepos[0], 0); */
  277.  
  278.             lno++;
  279.             if (!STANDOUT) lno++;
  280.         } else {
  281.             if (screen_offset == 0 && linenum == 1) {
  282.             if (show_article_date) so_printxy(-1, 0, send_date);
  283.  
  284.             /* so_printxy will cut subject */
  285.             so_printxy(0, lno, "%s: %s ", ah->sender, ah->subject);
  286.             lno++;
  287.             if (!STANDOUT) lno++;
  288.             }
  289.         }
  290.         }
  291.     }
  292.  
  293.     if (hdrline && screen_offset == 0) {
  294.  
  295.         hdr_mode = 0;
  296.         while (*hdrline) {
  297.  
  298.         if (*hdrline == '*') goto print_header;
  299.  
  300.         if (*hdrline == '=') {
  301.             hdr_mode = 1;
  302.             hdrline++;
  303.             continue;
  304.         }
  305.         if (*hdrline == '_') {
  306.             hdr_mode = 2;
  307.             hdrline++;
  308.             continue;
  309.         }
  310.         for (hdef = header_defs; hdef->field; hdef++) {
  311.             if (hdef->field != *hdrline) continue;
  312.             if (in_digest) {
  313.             if (hdef->digest == NULL) break;
  314.             if ((lp = *(hdef->digest)) == NULL)
  315.                 break;
  316.             } else
  317.             if ((lp = *(hdef->news)) == NULL)
  318.                 break;
  319.             if (*hdrline == 'n')
  320.             if ((current_group->group_flag & G_MERGED) == 0 &&
  321.                 strchr(lp, ',') == NULL) break;
  322.  
  323.             gotoxy(0, lno++);
  324.             printf("%s: ", hdef->text);
  325.             c = col = strlen(hdef->text) + 2;
  326.          split_header_line:
  327.             switch (hdr_mode) {
  328.              case 0:
  329.             break;
  330.              case 1:
  331.             highlight(1);
  332.             break;
  333.              case 2:
  334.             underline(1);
  335.             break;
  336.             }
  337.             while (*lp && c < Columns) {
  338.             if (isspace(*lp)) {
  339.                 while (lp[1] && isspace(lp[1])) lp++;
  340.                 if (wrap_headers > 0 &&
  341.                 (c + wrap_headers) >= Columns &&
  342.                 strlen(lp) >= wrap_headers) {
  343.                 lp++;
  344.                 break;
  345.                 }
  346.                 *lp = SP;
  347.             }
  348.             putchar(*lp++);
  349.             c++;
  350.             }
  351.             switch (hdr_mode) {
  352.              case 0:
  353.             break;
  354.              case 1:
  355.             highlight(0);
  356.             break;
  357.              case 2:
  358.             underline(0);
  359.             break;
  360.             }
  361.             if (*lp && wrap_headers >= 0) {
  362.             gotoxy(col, lno++);
  363.             c = col;
  364.             goto split_header_line;
  365.             }
  366.             break;
  367.         }
  368.         hdr_mode = 0;
  369.         hdrline++;
  370.         }
  371.  
  372.         hdrline = NULL;
  373.         putchar(NL);
  374.         lno++;
  375.     }
  376.  
  377.     lno1 = lno;
  378.     topline = linenum;
  379.  
  380.     window_lines = Lines - lno - 2;
  381.     print_lines = window_lines;
  382.  
  383.     ignore_nl = 1;    /* ignore blank lines at top op screen */
  384.     } else {
  385.     putchar(CR);
  386.     clrline();
  387.     print_lines = extra_lines;    /* LINT complaints here -- ignore */
  388.     }
  389.  
  390.     if (stop_line > 0) {
  391.     if (print_lines > stop_line) {
  392.         extra_lines = print_lines - stop_line;
  393.         print_lines = stop_line;
  394.         underline_line = -1;
  395.     }
  396.     stop_line = 0;
  397.     } else
  398.     stop_line = -1;
  399.  
  400.  next_line:
  401.  
  402.     if (linenum == linemax) {
  403.     linemax += 500;
  404.     if (linepos == lineposbuf) {
  405.         linepos = newobj(off_t, linemax);
  406.         for (linenum = 0; linenum < LINEMAX; linenum++)
  407.         linepos[linenum] = lineposbuf[linenum];
  408.     } else
  409.         linepos = resizeobj(linepos, off_t, linemax);
  410.     }
  411.  
  412.     if (goto_line == linenum) {
  413.     goto_line = -1;
  414.     goto next_page;
  415.     }
  416.  
  417.     eof = 0;
  418.  
  419.     if (linenum > maxline)
  420.     linepos[++maxline] = ftell(art);
  421.     else
  422.     if (linenum > 0)
  423.     fseek(art, linepos[linenum], 0);
  424.  
  425.  
  426.     if (linepos[linenum] >= ah->lpos) {
  427.     if (match_expr) {
  428.         match_expr = 0;
  429.         topline = match_topline;    /* LINT complaints here -- ignore */
  430.         linenum = match_botline;    /* LINT complaints here -- ignore */
  431.         fseek(art, linepos[linenum], 0);
  432.         msg("Not found");
  433.         goto Prompt;
  434.     }
  435.     eof++;
  436.     if (goto_line > 0) {
  437.         goto_line = -1;
  438.         linenum -= window_lines/2;
  439.         goto next_page;
  440.     }
  441.     goto Prompt;
  442.     }
  443.  
  444.     if (linenum == 0) {
  445.     if (ftell(art) >= linepos[1]) {
  446.         linenum = 2;    /* current line is 1st line ! */
  447.         lno1 = lno;
  448.     }
  449.     } else
  450.     linenum++;
  451.  
  452.     lp = linebuf;
  453.     col = 0;
  454.     form_feed = 0;
  455.  
  456.  next_char:
  457.  
  458.     c = getc(art);
  459.     if (c == EOF) {
  460.     eof++;
  461.     if (lp == linebuf) goto Prompt;
  462.     goto end_line;
  463.     }
  464.  
  465.     if (c & 0200) {
  466.     if (monitor_mode || data_bits != 8) {
  467.         col += 4;
  468.         if (col > Columns) {    /* then there is no room for M-^X */
  469.         ungetc(c, art);
  470.         goto long_line;
  471.         }
  472.         c &= 0177;
  473.         *lp++ = 'M';
  474.         *lp++ = '-';
  475.         if (c < SP) {
  476.         *lp++ = '^';
  477.         c += '@';
  478.         } else
  479.         col--;
  480.     }
  481.     } else
  482.     if (c < SP) {
  483.     if (monitor_mode) {
  484.         if (c == NL) {
  485.         *lp++ = '$';
  486.             goto end_line;
  487.         }
  488.         if (col + 2 > Columns) {
  489.         *lp++ = '\\';
  490.         ungetc(c, art);
  491.         goto end_line;
  492.         }
  493.         *lp++ = '^';
  494.         c += '@';
  495.         col++;
  496.     } else
  497.     switch (c) {
  498.  
  499.      case '\f':
  500.         last_ff_line = linenum;
  501.         if (lp == linebuf) {
  502.         if (goto_line > 0 || skip_char || match_expr || lno == lno1)
  503.             goto next_line;
  504.         form_feed = 1;
  505.         goto Prompt;
  506.         }
  507.         form_feed = 1;
  508.         goto end_line;
  509.  
  510.      case CR:
  511.         if (lp == linebuf || ignore_nl) goto next_char;
  512.         ignore_nl = 1;
  513.         goto end_line;
  514.  
  515.      case NL:
  516.         if (ignore_nl) {
  517.         ignore_nl = 0;
  518.         if (lp == linebuf) {
  519.             if (lno == lno1) {
  520.             ignore_nl = 1;
  521.             goto next_line;
  522.             }
  523.             goto next_char;
  524.         }
  525.         }
  526.         goto end_line;
  527.  
  528.      case BS:
  529.         if (col) {
  530.         lp--;
  531.         col--;
  532.         }
  533.         goto next_char;
  534.  
  535.      case TAB:
  536.         if (col + 8 - (col & 07) >= Columns)
  537.         goto long_line;
  538.  
  539.         do {
  540.         *lp++ = SP;
  541.         col++;
  542.         } while (col & 07);
  543.         goto next_char;
  544.  
  545.      default:
  546.         if (col + 2 > Columns) {
  547.         ungetc(c, art);
  548.         goto long_line;
  549.         }
  550.         *lp++ = '^';
  551.         c += '@';
  552.         col++;
  553.         break;
  554.     }
  555.     }
  556.  
  557.     *lp++ = c;
  558.     col++;
  559.     ignore_nl = 0;
  560.  
  561.     if (col < Columns) goto next_char;
  562.  
  563. long_line:
  564.     ignore_nl = 1;
  565.  
  566.  end_line:
  567.     /* if we are seaching for a specific line, repeat until it is found */
  568.     if (skip_wrap) {
  569.     skip_wrap = ignore_nl;
  570.     goto next_line;
  571.     }
  572.     if (goto_line >= linenum) goto next_line;
  573.     if (skip_char) {
  574.     if (lp == linebuf || linebuf[0] == skip_char) {
  575.         skip_wrap = ignore_nl;
  576.         goto next_line;
  577.     }
  578.     skip_char = NUL;
  579.     if (overlap > 0) {
  580.         underline_line = linenum;
  581.         linenum -= overlap;
  582.         goto next_page;
  583.     }
  584.     }
  585.  
  586.     *lp++ = NUL;
  587.  
  588.     if (match_expr) {
  589.     if (!regexec_cf(regular_expr, linebuf))
  590.         goto next_line;
  591.     match_expr = 0;
  592.     match_lines = 1;
  593.     if (linenum > match_botline) {
  594.         match_redraw = 0;
  595.         if (last_ff_line > linenum) last_ff_line = -1;
  596.         linenum -= 5;
  597.         if (linenum < last_ff_line) linenum = last_ff_line;
  598.         goto next_page;
  599.     }
  600.     match_redraw = (stop_line < 0);
  601.     stop_line = -1;
  602.     lno = lno1 + linenum - topline - 1;
  603.     print_lines = window_lines - lno + lno1;
  604.     }
  605.  
  606.     /* now print the line */
  607.  
  608.     if (match_lines && underline_line != linenum &&
  609.     regexec_cf(regular_expr, linebuf)) {
  610.     match_start = regular_expr->startp[0];
  611.     match_end = regular_expr->endp[0];
  612.     } else {
  613.     if (match_redraw) goto no_print;
  614.     match_start = NULL;
  615.     }
  616.  
  617.     gotoxy(0, lno);
  618.     if (!scroll_clear_page) clrline();
  619.  
  620.     if (mark_overlap && underline_line == linenum)
  621.     if (!underline(1))
  622.         fake_underline = 1;
  623.     skip_spaces = has_space = 0;
  624.  
  625.     for (lp = linebuf; c = *lp; lp++) {
  626.  
  627.     if (match_start) {
  628.         if (lp == match_start) highlight(1);
  629.         if (lp == match_end) {
  630.         highlight(0);
  631.         match_start = NULL;
  632.         if (match_redraw) goto no_print;
  633.         }
  634.     }
  635.  
  636.     if (c == SP) {
  637.         if (skip_spaces) {
  638.         if (has_space) continue;
  639.         has_space++;
  640.         }
  641.         if (fake_underline) c = '_';
  642.     } else {
  643.         if (compress_space && c != ' ') {
  644.         skip_spaces = 1;
  645.         has_space = 0;
  646.         }
  647.         if (rot13_active && linenum > 0)
  648.         c = ROT13_DECODE(c);
  649.     }
  650.  
  651.     putchar(c);
  652.     }
  653.  
  654.     if (match_start) highlight(0);
  655.  
  656.     if (mark_overlap && underline_line == linenum) {
  657.     while (lp - linebuf < 10) {
  658.         putchar(fake_underline ? '_' : ' ');
  659.         lp++;
  660.     }
  661.     underline(0);
  662.     underline_line = -1;
  663.     fake_underline = 0;
  664.     }
  665.  
  666. no_print:
  667.  
  668.     ++lno;
  669.     if (--print_lines > 0 && s_keyboard == 0 && form_feed == 0) goto next_line;
  670.  
  671.     if (!eof && linenum >= maxline) {
  672.     if (ignore_nl) {
  673.         c = getc(art);
  674.         if (c == EOF)
  675.         eof++;
  676.         else if (c != NL)
  677.         ungetc(c, art);
  678.         else
  679.         ignore_nl = 0;
  680.     }
  681.  
  682.     if (!eof && ftell(art) >= ah->lpos) eof++;
  683.     }
  684.  
  685.     match_redraw = 0;
  686.  
  687.  Prompt:
  688.  
  689.     if (eof && lno == screen_offset) more_return(MC_NEXT);
  690.  
  691.     raw();
  692.  
  693.     prompt_line = lno;
  694.  
  695.     if (!scroll_clear_page)
  696.     clrpage(prompt_line);
  697.  
  698.  dflt_prompt:
  699.  
  700.     prompt(pr_fmt,
  701.        pct((long)(ah->fpos), (long)(ah->lpos),
  702.            (long)(linepos[topline]), (long)ftell(art)),
  703.        a_st_flags(ah->flag));
  704.  
  705.     if (delayed_msg[0] != NUL) {
  706.     msg(delayed_msg);
  707.     delayed_msg[0] = NUL;
  708.     }
  709.  
  710.  same_prompt:
  711.  
  712.     if (flush_typeahead) flush_input();
  713.  
  714.     if ((c = get_c()) & GETC_COMMAND)
  715.     c &= ~GETC_COMMAND;
  716.     else
  717.     c = more_key_map[c];
  718.  
  719.     if (s_hangup) c = K_QUIT;
  720.  
  721.     if (any_message) clrmsg(0);
  722.  
  723.     if (c & K_MACRO) {
  724.     m_invoke(c & ~K_MACRO);
  725.     goto same_prompt;
  726.     }
  727.  
  728.  alt_key:
  729.  
  730.     switch (c) {
  731.      case K_UNBOUND:
  732.     ding();
  733.      case K_INVALID:
  734.     goto same_prompt;
  735.  
  736.      case K_REDRAW:
  737. #ifdef RESIZING
  738.     if (Columns != entry_col) {
  739.         entry_col = Columns;
  740.         maxline = topline = 1;
  741.     }
  742. #endif
  743.      goto redraw;
  744.  
  745.      case K_NEXT_PAGE:
  746.     if (eof) {
  747.         ding();
  748.         goto same_prompt;
  749.     }
  750.     /* FALL THRU */
  751.  
  752.      case K_CONTINUE:
  753.     if (eof) break;
  754.     if (screen_offset == 0 && form_feed == 0 && stop_line) {
  755.         if (linenum > overlap) {
  756.         underline_line = linenum;
  757.         linenum -= overlap;
  758.         }
  759.     }
  760.     goto next_page;
  761.  
  762.      case K_LAST_MESSAGE:
  763.     msg((char *)NULL);
  764.     goto dflt_prompt;
  765.  
  766.      case K_HELP:
  767.     display_help("more");
  768.     goto redraw;
  769.  
  770.      case K_SHELL:
  771.     putchar(CR);
  772.     if (shell_escape()) goto redraw;
  773.     goto dflt_prompt;
  774.  
  775.      case K_EXTENDED_CMD:
  776.     news_save = news;
  777.     digest_save = digest;
  778.     more_cmd = alt_command();
  779.     news = news_save;
  780.     digest = digest_save;
  781.  
  782.     switch (more_cmd) {
  783.  
  784.      case AC_UNCHANGED:
  785.         goto same_prompt;
  786.  
  787.      case AC_QUIT:
  788.         more_return( MC_QUIT );
  789.  
  790.      case AC_PROMPT:
  791.         goto dflt_prompt;
  792.  
  793.      case AC_REENTER_GROUP:
  794.         more_return( MC_REENTER_GROUP );
  795.  
  796.      case AC_REORDER:
  797.         more_return( MC_MENU );
  798.  
  799.      case AC_REDRAW:
  800.         goto redraw;
  801.  
  802.      case AC_KEYCMD:
  803.         c = alt_cmd_key;
  804.         goto alt_key;
  805.     }
  806.  
  807.      case K_QUIT:
  808.     ah->attr = A_LEAVE_NEXT;
  809.     more_return( MC_QUIT );
  810.  
  811.      case K_SAVE_NO_HEADER:
  812.      case K_SAVE_SHORT_HEADER:
  813.      case K_SAVE_FULL_HEADER:
  814.      case K_PRINT:
  815.      case K_UNSHAR:
  816.      case K_PATCH:
  817.      case K_UUDECODE:
  818.     news_save = news;
  819.     digest_save = digest;
  820.  
  821.     putchar(CR);
  822.     if (init_save(c, (char **)NULL) != NULL) {
  823.         if (c == K_UNSHAR)
  824.         prompt_line = Lines - 2;
  825.  
  826.         save(ah);
  827.         end_save();
  828.     }
  829.     news = news_save;
  830.     digest = digest_save;
  831.     if (!slow_mode && (c == K_UNSHAR || c == K_PATCH)) {
  832.         printf("\r\n\n");
  833.         any_key(0);
  834.         goto redraw;
  835.     }
  836.     goto Prompt;
  837.  
  838.      case K_FOLLOW_UP:
  839. #ifdef NNTP_POST
  840.      if (use_nntp && nntp_no_post()) goto Prompt;
  841. #endif
  842.      case K_REPLY:
  843.      case K_MAIL_OR_FORWARD:
  844.     news_save = news;
  845.     digest_save = digest;
  846.     more_cmd = answer(ah, c, -1);
  847.     news = news_save;
  848.     digest = digest_save;
  849.     if (more_cmd)
  850.         if (slow_mode) clrdisp(); else goto redraw;
  851.     goto Prompt;
  852.  
  853.      case K_POST:
  854.     if (post_menu())
  855.         if (slow_mode) clrdisp(); else goto redraw;
  856.     goto Prompt;
  857.  
  858.      case K_CANCEL:
  859.     if (current_group->group_flag & G_FOLDER) {
  860.         prompt("%s this folder entry",
  861.            (ah->attr == A_CANCEL) ? "UNcancel" : "Cancel");
  862.         if (yes(0)) fcancel(ah);
  863.         goto Prompt;
  864.     }
  865.  
  866.     if (cancel(ah) > 0) goto Prompt;
  867.     more_return(MC_NEXT);
  868.  
  869.      case K_UNSUBSCRIBE:
  870.     if (!unsubscribe(current_group)) goto Prompt;
  871.     if ((current_group->group_flag & G_UNSUBSCRIBED) == 0) goto Prompt;
  872.     more_return(MC_NEXTGROUP);
  873.  
  874.      case K_GROUP_OVERVIEW:
  875.     group_overview(-1);
  876.     goto redraw;
  877.  
  878.      case K_KILL_HANDLING:
  879.     switch (kill_menu(ah)) {
  880.      case 0:
  881.         more_return(MC_DO_SELECT);
  882.      case 1:
  883.         more_return(MC_DO_KILL);
  884.      default:
  885.         break;
  886.     }
  887.     goto Prompt;
  888.  
  889.      case K_READ_GROUP_UPDATE:
  890.     if (mode & MM_PREVIEW) more_return(MC_MENU);
  891.     prompt("Mark rest of current group as read?");
  892.     if (yes(1) <= 0) goto Prompt;
  893.     more_return(MC_READGROUP);
  894.  
  895.      case K_NEXT_GROUP_NO_UPDATE:
  896.     if (mode & MM_PREVIEW) more_return(MC_MENU);
  897.     more_return(MC_NEXTGROUP);
  898.  
  899.      case K_BACK_TO_MENU:
  900.     more_return(MC_MENU);
  901.  
  902.      case K_PREVIOUS:
  903.     if ((mode & MM_PREVIOUS) == 0) {
  904.         msg("No previous article");
  905.         goto dflt_prompt;
  906.     }
  907.     more_return(MC_PREV);
  908.  
  909.      case K_ADVANCE_GROUP:
  910.      case K_BACK_GROUP:
  911.      case K_GOTO_GROUP:
  912.     news_save = news;
  913.     digest_save = digest;
  914.     more_cmd = goto_group(c, ah, (flag_type)0);
  915.     news = news_save;
  916.     digest = digest_save;
  917.  
  918.     switch (more_cmd) {
  919.      case ME_NO_REDRAW:
  920.         goto Prompt;
  921.  
  922.      case ME_QUIT:
  923.         more_return( ME_QUIT );
  924.  
  925.      default:
  926.         goto redraw;
  927.     }
  928.  
  929.      case K_NEXT_LINE:
  930.     if (eof) break;
  931.     if (screen_offset) goto same_prompt;
  932.  
  933.     print_lines = 1;
  934.     goto scroll;
  935.  
  936.      case K_NEXT_HALF_PAGE:
  937.     if (eof) break;
  938.     if (screen_offset) goto same_prompt;
  939.  
  940.     print_lines = window_lines/2;
  941.  
  942.      scroll:
  943.     gotoxy(0, prompt_line);
  944.     clrpage(prompt_line);
  945.     no_raw();
  946.  
  947.     if (print_lines + lno < (Lines - 1))
  948.         goto next_page;
  949.  
  950.     stop_line = -1;
  951.     gotoxy(0, Lines-1);
  952.     c = print_lines + lno - Lines + 2;
  953.     while (--c >= 0) {
  954.         putchar(NL);
  955.         if (--lno1 < 0) topline++;
  956.         prompt_line--;
  957.     }
  958.     if (lno1 < 0) lno1 = 0;
  959.     if (prompt_line < 0) prompt_line = 0;
  960.     lno = prompt_line;
  961.     goto next_line;
  962.  
  963.      case K_PREV_HALF_PAGE:
  964.     if (topline <= 1) goto Prompt;
  965.     linenum = topline - window_lines/2;
  966.     if (linenum < 1) linenum = 1;
  967.     goto next_page;
  968.  
  969.      case K_PREV_PAGE:
  970.     if (topline <= 1) goto Prompt;
  971.     linenum = topline - window_lines + overlap; /* not perfect after FF */
  972.     underline_line = topline;
  973.     if (linenum < 1) linenum = 1;
  974.     goto next_page;
  975.  
  976.      case K_SKIP_LINES:
  977.     skip_char = linebuf[0];
  978.     goto next_page;
  979.  
  980.      case K_GOTO_LINE:
  981.     prompt("\1Go to line:\1 ");
  982.     if ((fname = get_s(NONE, NONE, "$^", NULL_FCT)) == NULL)
  983.         goto Prompt;
  984.  
  985.     if (*fname == NUL) {
  986.         if (prev_goto < 0) goto Prompt;
  987.         goto_line = prev_goto;
  988.  
  989.     } else
  990.     if (*fname == '$')
  991.         goto_line = 30000;
  992.     else
  993.     if (*fname == '^')
  994.         goto_line = 1;
  995.     else {
  996.         goto_line = atoi(fname);
  997.         if (goto_line <= 0) {
  998.         goto_line = -1;
  999.         goto Prompt;
  1000.         }
  1001.     }
  1002.  
  1003.      goto_page:
  1004.     prev_goto = topline;
  1005.  
  1006.     if (goto_line <= maxline) {
  1007.         linenum = goto_line;
  1008.         goto_line = -1;
  1009.     }
  1010.  
  1011.     goto next_page;
  1012.  
  1013.      case K_SELECT_SUBJECT:
  1014.     more_return(MC_ALLSUBJ);
  1015.  
  1016.      case K_HEADER_PAGE:
  1017.     fseek(art, linepos[0], 0);
  1018.     goto_line = 0;
  1019.     goto goto_page;
  1020.  
  1021.      case K_FIRST_PAGE:
  1022.     goto_line = 1;
  1023.     goto goto_page;
  1024.  
  1025.      case K_LAST_PAGE:
  1026.     goto_line = 30000;
  1027.     goto goto_page;
  1028.  
  1029.      case K_GOTO_MATCH:
  1030.     prompt("\1/\1");
  1031.     if ((fname = get_s(NONE, NONE, "/", NULL_FCT)) == NULL)
  1032.         goto Prompt;
  1033.  
  1034.     if (*fname && *fname != '/') {
  1035.         if (regular_expr) freeobj(regular_expr);
  1036.         if (case_fold_search) fold_string(fname);
  1037.         regular_expr = regcomp(fname);
  1038.     }
  1039.  
  1040.      case K_NEXT_MATCH:
  1041.     if (regular_expr == NULL) {
  1042.         msg("No previous expression");
  1043.         goto Prompt;
  1044.     }
  1045.  
  1046.     match_expr = 1;
  1047.     if (match_topline != topline) prev_goto = topline;
  1048.     match_topline = topline;
  1049.     match_botline = linenum;
  1050.     if (match_lines == 0 && topline <= 1) linenum = topline;
  1051.     match_lines = 0;
  1052.     goto next_line;        /* don't clear the screen if no match */
  1053.  
  1054.      case K_FULL_DIGEST:
  1055.     if (mode & MM_DIGEST)
  1056.         more_return( MC_NO_REDRAW );
  1057.  
  1058.     if (!in_digest)
  1059.         goto same_prompt;
  1060.  
  1061.     /* could do something more clever here later */
  1062.     digestah = *ah;
  1063.     digestah.flag &= ~A_DIGEST;
  1064.     digestah.hpos = digestah.fpos = 0;
  1065.     fseek(art, 0L, 2);
  1066.     digestah.lpos = ftell(art);
  1067.  
  1068.     switch (more(&digestah, mode | MM_DIGEST, screen_offset)) {
  1069.  
  1070.      case MC_REDRAW:
  1071.         goto redraw;
  1072.  
  1073.      case MC_NO_REDRAW:
  1074.         goto safe_redraw;
  1075.  
  1076.      case MC_QUIT:
  1077.         more_return( MC_QUIT );
  1078.  
  1079.      case MC_REENTER_GROUP:
  1080.         more_return( MC_REENTER_GROUP );
  1081.  
  1082.      default:
  1083.         goto safe_redraw;
  1084.     }
  1085.  
  1086.      case K_LEAVE_NEXT:
  1087.     ah->attr = A_LEAVE_NEXT;
  1088.     more_return(MC_PREVIEW_NEXT);
  1089.  
  1090.      case K_LEAVE_ARTICLE:
  1091.     ah->attr = (mode & MM_PREVIEW) ? A_SELECT : A_LEAVE;
  1092.     /* fall thru */
  1093.  
  1094.      case K_NEXT_ARTICLE:
  1095.     if ((mode & MM_PREVIEW) == 0) break;
  1096.     more_return(MC_PREVIEW_NEXT);
  1097.  
  1098.      case K_BACK_ARTICLE:
  1099.     if (mode & MM_FIRST_ARTICLE) {
  1100.         msg("First article is displayed");
  1101.         goto same_prompt;
  1102.     }
  1103.     more_return(MC_BACK_ART);
  1104.  
  1105.      case K_FORW_ARTICLE:
  1106.     if (mode & MM_LAST_ARTICLE) {
  1107.         msg("Last article is displayed");
  1108.         goto same_prompt;
  1109.     }
  1110.     more_return(MC_FORW_ART);
  1111.  
  1112.      case K_NEXT_SUBJECT:
  1113.     more_return(MC_NEXTSUBJ);
  1114.  
  1115.      case K_ROT13:
  1116.     if (rot13_must_init) {
  1117.         register i;
  1118.         for (i=0; i<=127; i++) {
  1119.         c = i;
  1120.         if (c >= 'a' && c <= 'm') c += 13;
  1121.         else if (c >= 'n' && c <= 'z') c -= 13;
  1122.         else if (c >= 'A' && c <= 'M') c += 13;
  1123.         else if (c >= 'N' && c <= 'Z') c -= 13;
  1124.         rot13_table[i] = c;
  1125.         }
  1126.         rot13_must_init = 0;
  1127.     }
  1128.  
  1129.     rot13_active = !rot13_active;
  1130.     goto safe_redraw;
  1131.  
  1132.      case K_COMPRESS:
  1133.     compress_space = !compress_space;
  1134.     goto safe_redraw;
  1135.  
  1136.      case K_PREVIEW:
  1137.     if (mode & MM_PREVIEW)
  1138.         more_return(MC_PREVIEW_OTHER);
  1139.  
  1140.     /* fall thru to "default" */
  1141.  
  1142.      default:
  1143.     msg("Command %d not supported", c);
  1144.     goto dflt_prompt;
  1145.     }
  1146.  
  1147.     more_return(MC_NEXT);
  1148.  
  1149.  more_exit:
  1150.     in_menu_mode = o_mode;
  1151.     rot13_active = 0;
  1152.  
  1153.     if (linepos != lineposbuf) freeobj(linepos);
  1154.  
  1155.     no_raw();
  1156.     fclose(art);
  1157.  
  1158.     if (mode & MM_PREVIEW)
  1159.     if (more_cmd != MC_QUIT && more_cmd != MC_REENTER_GROUP) {
  1160.         gotoxy(0, screen_offset);
  1161.         clrpage(screen_offset);
  1162.         if (auto_preview_mode && ah->attr == 0)
  1163.         ah->attr = A_READ;
  1164.         if (screen_offset == 0) prompt_line = -1;
  1165.     }
  1166.  
  1167.     return more_cmd;
  1168. }
  1169.  
  1170.  
  1171. rot13_line(cp)
  1172. register char *cp;
  1173. {
  1174.     register int c;
  1175.  
  1176.     while (c = *cp)
  1177.     *cp++ = ROT13_DECODE(c);
  1178. }
  1179.  
  1180.