home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / trn-3.3 / part09 / art.c next >
C/C++ Source or Header  |  1993-11-27  |  26KB  |  1,070 lines

  1. /* $Id: art.c,v 3.0 1992/02/01 03:09:32 davison Trn $
  2.  */
  3. /* This software is Copyright 1991 by Stan Barber. 
  4.  *
  5.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  6.  * use this software as long as: there is no monetary profit gained
  7.  * specifically from the use or reproduction of this software, it is not
  8.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  9.  * included prominently in any copy made. 
  10.  *
  11.  * The authors make no claims as to the fitness or correctness of this software
  12.  * for any use whatsoever, and it is provided as is. Any use of this software
  13.  * is at the user's own risk. 
  14.  */
  15.  
  16. #include "EXTERN.h"
  17. #include "common.h"
  18. #include "trn.h"
  19. #include "ngstuff.h"
  20. #include "ngdata.h"
  21. #include "cache.h"
  22. #include "bits.h"
  23. #include "head.h"
  24. #include "help.h"
  25. #include "search.h"
  26. #include "artio.h"
  27. #include "ng.h"
  28. #include "final.h"
  29. #include "artstate.h"
  30. #include "rcstuff.h"
  31. #include "term.h"
  32. #include "sw.h"
  33. #include "util.h"
  34. #include "backpage.h"
  35. #include "intrp.h"
  36. #include "rthread.h"
  37. #include "rt-select.h"
  38. #include "rt-util.h"
  39. #include "rt-wumpus.h"
  40. #include "INTERN.h"
  41. #include "art.h"
  42.  
  43. /* page_switch() return values */
  44.  
  45. #define PS_NORM 0
  46. #define PS_ASK 1
  47. #define PS_RAISE 2
  48. #define PS_TOEND 3
  49.  
  50. bool special = FALSE;        /* is next page special length? */
  51. int slines = 0;            /* how long to make page when special */
  52. ART_LINE highlight = -1;    /* next line to be highlighted */
  53. char *restart = Nullch;        /* if nonzero, the place where last */
  54.                 /* line left off on line split */
  55. char *blinebeg;            /* where in buffer current line began */
  56. ART_POS alinebeg;        /* where in file current line began */
  57.  
  58. #ifdef INNERSEARCH
  59. ART_POS innersearch = 0;    /* artpos of end of line we found */
  60.                 /* for 'g' command */
  61. ART_LINE isrchline = 0;            /* last line to display */
  62. bool hide_everything = FALSE;
  63.                 /* if set, do not write page now, */
  64.                 /* but refresh when done with page */
  65. COMPEX gcompex;                /* in article search pattern */
  66. #endif
  67.  
  68. bool firstpage;            /* is this the 1st page of article? */
  69.  
  70. char art_buf[LBUFLEN];        /* place for article lines */
  71.  
  72. void
  73. art_init()
  74. {
  75. #ifdef INNERSEARCH
  76.     init_compex(&gcompex)
  77. #endif
  78.     ;
  79. }
  80.  
  81. #ifdef MIME_SUPPORT
  82. #define VERY_LONG_STRING        200
  83. int
  84. display_mime()
  85. {
  86.     int code = 1;
  87.  
  88.     if (!getenv("NOMIME")) {
  89.     char oldmode = mode;
  90.  
  91.     interp(cmd_buf,(sizeof cmd_buf),getval("MIMESHOW",MIMESHOW));
  92.     fputs("Process MIME article? [yn]",stdout);
  93.     fflush(stdout);
  94.     eat_typeahead();
  95. #ifdef PENDING
  96.     cache_until_key();
  97. #endif
  98.     mode = 'p';
  99.     getcmd(buf);
  100.     mode = oldmode;
  101.     setdef(buf,"y");
  102. #ifdef VERIFY
  103.     printcmd();
  104. #endif
  105.     carriage_return();
  106.     erase_eol();    /* erase the prompt */
  107.     carriage_return();    /* Resets kernel's tab column counter to 0 */
  108.     if (*buf == 'y') {
  109.         putchar('\n');
  110.         fflush(stdout);
  111.         termlib_reset();
  112.         resetty();
  113.         code = doshell(SH,cmd_buf);
  114.         noecho();
  115.         crmode();
  116.         termlib_init();
  117.     }
  118.     }
  119.     return code;
  120. }
  121. #endif
  122.  
  123.  
  124. int
  125. do_article()
  126. {
  127.     register char *s;
  128.     ART_POS artsize;            /* size in bytes of article */
  129.     bool hide_this_line = FALSE;    /* hidden header line? */
  130.     ART_LINE linenum;    /* line # on page, 1 origin */
  131. #ifdef ULSMARTS
  132.     bool under_lining = FALSE;        /* are we underlining a word? */
  133. #endif
  134.     register char *bufptr = art_buf;    /* pointer to input buffer */
  135.     register int outpos;        /* column position of output */
  136.     static char prompt_buf[64];        /* place to hold prompt */
  137.     bool notesfiles = FALSE;        /* might there be notesfiles junk? */
  138.     char oldmode = mode;
  139.     char *ctime();
  140. #ifdef MIME_SUPPORT
  141.     bool tried_display_mime = FALSE;
  142. #endif
  143. #ifdef INNERSEARCH
  144.     register int outputok;
  145. #endif
  146.  
  147. #ifdef MIME_SUPPORT
  148.     mime_article = FALSE;
  149. #endif
  150.  
  151.     if (fstat(fileno(artfp),&filestat)) /* get article file stats */
  152.     return DA_CLEAN;
  153.     if ((filestat.st_mode & S_IFMT) != S_IFREG)
  154.     return DA_NORM;
  155.     artsize = filestat.st_size;        /* from that get article size */
  156.     sprintf(prompt_buf,
  157.     "%%sEnd of article %ld (of %ld) -- what next? [%%s]",
  158.     (long)art,(long)lastart);    /* format prompt string */
  159.     prompt = prompt_buf;
  160.     int_count = 0;        /* interrupt count is 0 */
  161.     if ((firstpage = (topline < 0)) != 0) {
  162.     parseheader(art);
  163.     fseek(artfp,htype[PAST_HEADER].ht_minpos,0);
  164.     }
  165.     for (;;) {            /* for each page */
  166.     if (ThreadedGroup && max_tree_lines)
  167.         init_tree();    /* init tree display */
  168.     assert(art == openart);
  169.     if (do_fseek) {
  170.         parseheader(art);        /* make sure header is ours */
  171.         artpos = vrdary(artline);
  172.         if (artpos < 0)
  173.         artpos = -artpos;    /* labs(), anyone? */
  174.         if (firstpage)
  175.         artpos = (ART_POS)0;
  176.         if (artpos < htype[PAST_HEADER].ht_minpos) {
  177.         in_header = SOME_LINE;
  178.         fseek(artfp,htype[PAST_HEADER].ht_minpos,0);
  179.         } else
  180.         fseek(artfp,artpos,0);
  181.         do_fseek = FALSE;
  182.         restart = Nullch;
  183.     }
  184.     linenum = 1;
  185.     if (firstpage) {
  186.         if (firstline) {
  187.         interp(art_buf, (sizeof art_buf), firstline);
  188.         linenum += tree_puts(art_buf,linenum+topline,0);
  189.         } else 
  190.             {
  191.         ART_NUM i;
  192.         int selected, unseen;
  193.  
  194.         selected = (curr_artp->flags & AF_SEL);
  195.         unseen = !was_read(art);
  196.         sprintf(art_buf,"%s%s #%ld",ngname,moderated,(long)art);
  197.         if (selected_only) {
  198.             i = selected_count - (unseen && selected);
  199.             sprintf(art_buf+strlen(art_buf)," (%ld + %ld more)",
  200.                 (long)i,(long)toread[ng] - selected_count
  201.                     - (!selected && unseen));
  202.         }
  203.         else if ((i = (ART_NUM)(toread[ng] - unseen)) != 0
  204.                || (!ThreadedGroup && dmcount))
  205.             sprintf(art_buf+strlen(art_buf)," (%ld more)",(long)i);
  206.         if (!ThreadedGroup && dmcount)
  207.             sprintf(art_buf+strlen(art_buf)-1," + %ld Marked to return)",
  208.                 (long)dmcount);
  209.         linenum += tree_puts(art_buf,linenum+topline,0);
  210.         }
  211.         start_header(art);
  212.         forcelast = FALSE;        /* we will have our day in court */
  213.         restart = Nullch;
  214.         artline = 0;        /* start counting lines */
  215.         artpos = 0;
  216.         vwtary(artline,artpos);    /* remember pos in file */
  217.     }
  218.     for (;                /* linenum already set */
  219.       in_header || (
  220. #ifdef INNERSEARCH
  221.       innersearch ? innermore() :
  222. #endif
  223.       linenum<(firstpage?initlines:(special?slines:LINES)) );
  224.       linenum++) {        /* for each line on page */
  225.         if (int_count) {    /* exit via interrupt? */
  226.         putchar('\n') FLUSH;    /* get to left margin */
  227.         int_count = 0;    /* reset interrupt count */
  228.         mode = oldmode;
  229.         special = FALSE;
  230.         return DA_NORM;    /* skip out of loops */
  231.         }
  232.         if (restart) {        /* did not finish last line? */
  233.         bufptr = restart;    /* then start again here */
  234.         restart = Nullch;    /* and reset the flag */
  235.         }
  236.         else if (in_header && headbuf[artpos] != '\0') {
  237.         bufptr = index(headbuf+artpos,'\n') + 1;
  238.         bcopy(headbuf+artpos,art_buf,bufptr-headbuf-artpos);
  239.         art_buf[bufptr-headbuf-artpos] = '\0';
  240.         bufptr = art_buf;
  241.         } else {
  242.         if (fgets(art_buf,LBUFLEN,artfp)==Nullch) {
  243.                     /* if all done */
  244.             mode = oldmode;
  245.             special = FALSE;
  246.             return DA_NORM;    /* skip out of loops */
  247.         }
  248.         bufptr = art_buf;    /* so start at beginning */
  249.         art_buf[LBUFLEN-1] = '\0';
  250.                     /* make sure string ends */
  251.         }
  252.         blinebeg = bufptr;    /* remember where we began */
  253.         alinebeg = artpos;    /* both in buffer and file */
  254.         if (in_header && bufptr == art_buf) {
  255.         hide_this_line =
  256.             parseline(art_buf,do_hiding,hide_this_line);
  257.         if (!in_header) {
  258.             linenum += finish_tree(linenum+topline);
  259.             end_header();
  260.         }
  261.         } else if (notesfiles && do_hiding &&
  262.           bufptr == art_buf && *art_buf == '#' &&
  263.           isupper(art_buf[1]) && art_buf[2] == ':' ) {
  264.         fgets(art_buf,sizeof(art_buf),artfp);
  265.         if (index(art_buf,'!') != Nullch)
  266.             fgets(art_buf,sizeof(art_buf),artfp);
  267.         htype[PAST_HEADER].ht_minpos = ftell(artfp);
  268.                     /* exclude notesfiles droppings */
  269.         hide_this_line = TRUE;    /* and do not print either */
  270.         notesfiles = FALSE;
  271.         }
  272. #ifdef CUSTOMLINES
  273.         if (hideline && bufptr == art_buf &&
  274.           execute(&hide_compex,art_buf) )
  275.         hide_this_line = TRUE;
  276. #endif
  277.         if (in_header && htype[in_header].ht_flags & HT_MAGIC) {
  278.         if (in_header == NGS_LINE) {
  279.             if ((s = index(art_buf,'\n')) != Nullch)
  280.             *s = '\0';
  281.             hide_this_line = (index(art_buf,',') == Nullch)
  282.             && strEQ(art_buf+12, ngname);
  283.             if (s != Nullch)
  284.             *s = '\n';
  285.         }
  286.         else if (in_header == EXPIR_LINE) {
  287.             if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE))
  288.             hide_this_line = (strlen(art_buf) < 10);
  289.         }
  290.         else if (in_header == FROM_LINE) {
  291.             if (do_hiding && (s = extract_name(art_buf+6)) != Nullch)
  292.             strcpy(art_buf+6,s);
  293.         }
  294. #ifdef HAS_STRFTIME
  295.         else if (in_header == DATE_LINE) {
  296.             if (do_hiding && curr_artp->date != -1)
  297.             strftime(art_buf+6, sizeof(art_buf)-6,
  298.                  getval("LOCALTIMEFMT", LOCALTIMEFMT),
  299.                  localtime(&curr_artp->date));
  300.         }
  301. #endif
  302. #ifdef MIME_SUPPORT
  303.         else if (in_header == CONTENT_LINE && !isspace(*art_buf)) {
  304.             mime_article = nontext(art_buf+14);
  305.         }
  306. #endif
  307.         }
  308.         if (in_header == SUBJ_LINE &&
  309.         htype[SUBJ_LINE].ht_flags & HT_MAGIC) {
  310.                 /* is this the subject? */
  311.         int length;
  312.  
  313.         length = strlen(art_buf)-1;
  314.         artline++;
  315.         art_buf[length] = '\0';        /* wipe out newline */
  316. #ifdef NOFIREWORKS
  317.         no_ulfire();
  318. #endif
  319.         notesfiles =
  320.             (instr(&art_buf[length-10]," - (nf", TRUE) != Nullch);
  321.         /* tree_puts(, ,1) underlines subject */
  322.         linenum += tree_puts(art_buf,linenum+topline,1)-1;
  323.         }
  324.         else if (hide_this_line && do_hiding) {
  325.                     /* do not print line? */
  326.         linenum--;        /* compensate for linenum++ */
  327.         if (!in_header)
  328.             hide_this_line = FALSE;
  329.         }
  330.         else if (in_header) {
  331.         artline++;
  332.         linenum += tree_puts(art_buf,linenum+topline,0)-1;
  333.         }
  334.         else {            /* just a normal line */
  335. #ifdef MIME_SUPPORT
  336.         if (mime_article && do_hiding && !tried_display_mime) {
  337.             if (display_mime() == 0)
  338.             return DA_NORM;
  339.             else
  340.             tried_display_mime = TRUE;
  341.         }
  342. #endif
  343.         if (highlight==artline) {    /* this line to be highlit? */
  344.             if (marking == STANDOUT) {
  345. #ifdef NOFIREWORKS
  346.             if (erase_screen)
  347.                 no_sofire();
  348. #endif
  349.             standout();
  350.             }
  351.             else {
  352. #ifdef NOFIREWORKS
  353.             if (erase_screen)
  354.                 no_ulfire();
  355. #endif
  356.             underline();
  357.             }
  358.             if (*bufptr == '\n')
  359.             putchar(' ');
  360.         }
  361. #ifdef INNERSEARCH
  362.         outputok = !hide_everything;
  363.                     /* get it into register, hopefully */
  364. #endif
  365. #ifdef CLEAREOL
  366. #ifdef INNERSEARCH
  367.         if (outputok)
  368. #endif
  369.         maybe_eol();    
  370. #endif /* CLEAREOL */
  371. #ifdef CUSTOMLINES
  372.         if (pagestop && bufptr == art_buf && 
  373.           execute(&page_compex,art_buf) )
  374.             linenum = 32700;
  375. #endif
  376.         for (outpos = 0; outpos < COLS; ) {
  377.                     /* while line has room */
  378.             if (*(unsigned char *)bufptr >= ' ') { /* normal char? */
  379. #ifdef ULSMARTS
  380.             if (*bufptr == '_') {
  381.                 if (bufptr[1] == '\b') {
  382.                 if (!under_lining && highlight!=artline
  383. #ifdef INNERSEARCH
  384.                     && outputok
  385. #endif
  386.                     ) {
  387.                     under_lining++;
  388.                     if (UG) {
  389.                     if (bufptr != buf &&
  390.                       bufptr[-1] == ' ') {
  391.                         outpos--;
  392.                         backspace();
  393.                     }
  394.                     }
  395.                     underline();
  396.                 }
  397.                 bufptr += 2;
  398.                 }
  399.             }
  400.             else {
  401.                 if (under_lining) {
  402.                 under_lining = 0;
  403.                 un_underline();
  404.                 if (UG) {
  405.                     if (*bufptr == ' ')
  406.                     goto skip_put;
  407.                     outpos++;
  408.                 }
  409.                 }
  410.             }
  411. #endif
  412. #ifdef INNERSEARCH
  413.             if (outputok)
  414. #endif
  415.             {
  416. #ifdef ROTATION
  417.                 if (rotate && !in_header
  418.                   && isalpha(*bufptr)) {
  419.                 if ((*bufptr & 31) <= 13)
  420.                     putchar(*bufptr+13);
  421.                 else
  422.                     putchar(*bufptr-13);
  423.                 }
  424.                 else
  425. #endif
  426.                 putchar(*bufptr);
  427.             }
  428.             if (*UC && ((highlight==artline && marking == 1)
  429. #ifdef ULSMARTS
  430.                 || under_lining
  431. #endif
  432.                 )) {
  433.                 backspace();
  434.                 underchar();
  435.             }
  436.             skip_put:
  437.             bufptr++;
  438.             outpos++;
  439.             }
  440.             else if (*bufptr == '\n' || !*bufptr) {
  441.                             /* newline? */
  442. #ifdef ULSMARTS
  443.             if (under_lining) {
  444.                 under_lining = 0;
  445.                 un_underline();
  446.             }
  447. #endif
  448. #ifdef DEBUG
  449.             if (debug & DEB_INNERSRCH && outpos < COLS - 6) {
  450.                 standout();
  451.                 printf("%4d",artline); 
  452.                 un_standout();
  453.             }
  454. #endif
  455. #ifdef INNERSEARCH
  456.             if (outputok)
  457. #endif
  458.                 putchar('\n') FLUSH;
  459.             restart = 0;
  460.             outpos = 1000;    /* signal normal \n */
  461.             }
  462.             else if (*bufptr == '\t') {    /* tab? */
  463.             int incpos =  8 - outpos % 8;
  464. #ifdef INNERSEARCH
  465.             if (outputok)
  466. #endif
  467.                 if (GT)
  468.                 putchar(*bufptr);
  469.                 else
  470.                 while (incpos--) putchar(' ');
  471.             bufptr++;
  472.             outpos += 8 - outpos % 8;
  473.             }
  474.             else if (*bufptr == '\f') {    /* form feed? */
  475. #ifdef INNERSEARCH
  476.             if (outputok)
  477. #endif
  478.                 fputs("^L",stdout);
  479.             if (bufptr == blinebeg && highlight != artline)
  480.                 linenum = 32700;
  481.                 /* how is that for a magic number? */
  482.             bufptr++;
  483.             outpos += 2;
  484.             }
  485.             else {        /* other control char */
  486. #ifdef INNERSEARCH
  487.             if (outputok)
  488. #endif
  489.             {
  490.                 if (dont_filter_control)
  491.                 putchar(*bufptr);
  492.                 else {
  493.                 putchar('^');
  494.                 if (highlight == artline && *UC && marking == 1) {
  495.                     backspace();
  496.                     underchar();
  497.                     putchar(*bufptr+64);
  498.                     backspace();
  499.                     underchar();
  500.                 }
  501.                 else
  502.                     putchar(*bufptr+64);
  503.                 }
  504.             }
  505.             bufptr++;
  506.             outpos += 2;
  507.             }
  508.             
  509.         } /* end of column loop */
  510.  
  511.         if (outpos < 1000) {/* did line overflow? */
  512.             restart = bufptr;
  513.                     /* restart here next time */
  514.             if (!AM || XN) {/* no automatic margins on tty? */
  515. #ifdef INNERSEARCH            /* then move it down ourselves */
  516.             if (outputok)
  517. #endif
  518.                 putchar('\n') FLUSH;
  519.             }
  520.             if (*bufptr == '\n')    /* skip the newline */
  521.             restart = 0;
  522.         }
  523.  
  524.         /* handle normal end of output line formalities */
  525.  
  526.         if (highlight == artline) {
  527.                     /* were we highlighting line? */
  528.             if (marking == STANDOUT)
  529.             un_standout();
  530.             else
  531.             un_underline();
  532.             highlight = -1;    /* no more we are */
  533.         }
  534.         artline++;    /* count the line just printed */
  535.         if (artline - LINES + 1 > topline)
  536.                 /* did we just scroll top line off? */
  537.             topline = artline - LINES + 1;
  538.                 /* then recompute top line # */
  539.         }
  540.  
  541.         /* determine actual position in file */
  542.  
  543.         if (restart)    /* stranded somewhere in the buffer? */
  544.         artpos += restart - blinebeg;
  545.                 /* just calculate position */
  546.         else if (in_header)
  547.         artpos = index(headbuf+artpos, '\n') - headbuf + 1;
  548.         else        /* no, ftell will do */
  549.         artpos = ftell(artfp);
  550.         vwtary(artline,artpos);    /* remember pos in file */
  551.     } /* end of line loop */
  552.  
  553. #ifdef INNERSEARCH
  554.     innersearch = 0;
  555.     if (hide_everything) {
  556.         hide_everything = FALSE;
  557.         *buf = Ctl('l');
  558.         goto fake_command;
  559.     }
  560. #endif
  561.     if (linenum >= 32700)/* did last line have formfeed? */
  562.         vwtary(artline-1,-vrdary(artline-1));
  563.                 /* remember by negating pos in file */
  564.  
  565.     special = FALSE;    /* end of page, so reset page length */
  566.     firstpage = FALSE;    /* and say it is not 1st time thru */
  567.  
  568.     /* extra loop bombout */
  569.  
  570.     if (artpos == artsize) {/* did we just now reach EOF? */
  571.         mode = oldmode;
  572.         return DA_NORM;    /* avoid --MORE--(100%) */
  573.     }
  574.  
  575. /* not done with this article, so pretend we are a pager */
  576.  
  577. reask_pager:            
  578.     unflush_output();    /* disable any ^O in effect */
  579.     standout();        /* enter standout mode */
  580.     printf("--MORE--(%ld%%)",(long)(artpos*100/artsize));
  581.     un_standout();    /* leave standout mode */
  582. #ifdef CLEAREOL
  583.      maybe_eol();
  584. #endif
  585.     fflush(stdout);
  586.     eat_typeahead();
  587. #ifdef DEBUG
  588.     if (debug & DEB_CHECKPOINTING) {
  589.         printf("(%d %d %d)",checkcount,linenum,artline);
  590.         fflush(stdout);
  591.     }
  592. #endif
  593.     if (checkcount >= docheckwhen &&
  594.       linenum == LINES &&
  595.       (artline > 40 || checkcount >= docheckwhen+10) ) {
  596.                 /* while he is reading a whole page */
  597.                 /* in an article he is interested in */
  598.         checkcount = 0;
  599.         checkpoint_rc();    /* update .newsrc */
  600.     }
  601.     cache_until_key();
  602.     mode = 'p';
  603.     getcmd(buf);
  604.     if (errno) {
  605.         if (LINES < 100 && !int_count)
  606.         *buf = '\f';/* on CONT fake up refresh */
  607.         else {
  608.         *buf = 'q';    /* on INTR or paper just quit */
  609.         }
  610.     }
  611.     carriage_return();
  612. #ifndef CLEAREOL
  613.     erase_eol();    /* and erase the prompt */
  614. #else
  615.     if (erase_screen && can_home_clear)    
  616.         clear_rest();
  617.     else
  618.         erase_eol();    /* and erase the prompt */
  619. #endif /* CLEAREOL */
  620.     carriage_return();    /* Resets kernel's tab column counter to 0 */
  621.     fflush(stdout);
  622.  
  623.     fake_command:        /* used by innersearch */
  624.     output_chase_phrase = TRUE;
  625.  
  626.     /* parse and process pager command */
  627.  
  628.     switch (page_switch()) {
  629.     case PS_ASK:    /* reprompt "--MORE--..." */
  630.         goto reask_pager;
  631.     case PS_RAISE:    /* reparse on article level */
  632.         mode = oldmode;
  633.         return DA_RAISE;
  634.     case PS_TOEND:    /* fast pager loop exit */
  635.         mode = oldmode;
  636.         return DA_TOEND;
  637.     case PS_NORM:    /* display more article */
  638.         break;
  639.     }
  640.     } /* end of page loop */
  641. }
  642.  
  643. /* process pager commands */
  644.  
  645. int
  646. page_switch()
  647. {
  648.     register char *s;
  649.     
  650.     switch (*buf) {
  651.     case 'd':
  652.     case Ctl('d'):    /* half page */
  653.     special = TRUE;
  654.     slines = LINES / 2 + 1;
  655.     if (marking && *blinebeg != '\f'
  656. #ifdef CUSTOMLINES
  657.       && (!pagestop || blinebeg != art_buf ||
  658.           !execute(&page_compex,blinebeg))
  659. #endif
  660.       ) {
  661.         up_line();
  662.         highlight = --artline;
  663.         restart = blinebeg;
  664.         artpos = alinebeg;
  665.     }
  666.     return PS_NORM;
  667.     case '!':            /* shell escape */
  668.     escapade();
  669.     return PS_ASK;
  670. #ifdef INNERSEARCH
  671.     case Ctl('i'):
  672.     gline = 3;
  673.     sprintf(cmd_buf,"^[^%c]",*blinebeg);
  674.     compile(&gcompex,cmd_buf,TRUE,TRUE);
  675.     goto caseG;
  676.     case Ctl('g'):
  677.     gline = 3;
  678.     compile(&gcompex,"^Subject:",TRUE,TRUE);
  679.     goto caseG;
  680.     case 'g':        /* in-article search */
  681.     if (!finish_command(FALSE))/* get rest of command */
  682.         return PS_ASK;
  683.     s = buf+1;
  684.     if (isspace(*s))
  685.         s++;
  686.     if ((s = compile(&gcompex,s,TRUE,TRUE)) != Nullch) {
  687.                 /* compile regular expression */
  688.         printf("\n%s\n",s) FLUSH;
  689.         return PS_ASK;
  690.     }
  691.     carriage_return();
  692.     erase_eol();    /* erase the prompt */
  693.     carriage_return();    /* Resets kernel's tab column counter to 0 */
  694.     /* FALL THROUGH */
  695.     caseG:
  696.     case 'G': {
  697.     /* ART_LINE lines_to_skip = 0; */
  698.     ART_POS start_where;
  699.  
  700.     if (gline < 0 || gline > LINES-2)
  701.         gline = LINES-2;
  702. #ifdef DEBUG
  703.     if (debug & DEB_INNERSRCH)
  704.         printf("Start here? %d  >=? %d\n",topline + gline + 1,artline)
  705.           FLUSH;
  706. #endif
  707.     if (*buf == Ctl('i') || topline+gline+1 >= artline)
  708.         start_where = artpos;
  709.             /* in case we had a line wrap */
  710.     else {
  711.         start_where = vrdary(topline+gline+1);
  712.         if (start_where < 0)
  713.         start_where = -start_where;
  714.     }
  715.     if (start_where < htype[PAST_HEADER].ht_minpos)
  716.         start_where = htype[PAST_HEADER].ht_minpos;
  717.     fseek(artfp,(long)start_where,0);
  718.     innersearch = 0; /* assume not found */
  719.     while (fgets(buf, sizeof buf, artfp) != Nullch) {
  720.         /* lines_to_skip++;         NOT USED NOW */
  721. #ifdef DEBUG
  722.         if (debug & DEB_INNERSRCH)
  723.         printf("Test %s",buf) FLUSH;
  724. #endif
  725.         if (execute(&gcompex,buf) != Nullch) {
  726.         innersearch = ftell(artfp);
  727.         break;
  728.         }
  729.     }
  730.     if (!innersearch) {
  731.         fseek(artfp,artpos,0);
  732.         fputs("(Not found)",stdout) FLUSH;
  733.         return PS_ASK;
  734.     }
  735. #ifdef DEBUG
  736.     if (debug & DEB_INNERSRCH)
  737.         printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos)
  738.           FLUSH;
  739. #endif
  740.     if (innersearch <= artpos) {    /* already on page? */
  741.         if (innersearch < artpos) {
  742.         artline = topline+1;
  743.         while (vrdary(artline) < innersearch)
  744.             artline++;
  745.         }
  746.         highlight = artline - 1;
  747. #ifdef DEBUG
  748.         if (debug & DEB_INNERSRCH)
  749.         printf("@ %d\n",highlight) FLUSH;
  750. #endif
  751.         topline = highlight - gline;
  752.         if (topline < -1)
  753.         topline = -1;
  754.         *buf = '\f';        /* fake up a refresh */
  755.         innersearch = 0;
  756.         return page_switch();
  757.     }
  758.     else {                /* who knows how many lines it is? */
  759.         do_fseek = TRUE;
  760.         hide_everything = TRUE;
  761.     }
  762.     return PS_NORM;
  763.     }
  764. #else
  765.     case 'g': case 'G': case Ctl('g'):
  766.     notincl("g");
  767.     return PS_ASK;
  768. #endif
  769.     case '\n':        /* one line */
  770.     special = TRUE;
  771.     slines = 2;
  772.     return PS_NORM;
  773. #ifdef ROTATION
  774.     case 'X':
  775.     rotate = !rotate;
  776.     /* FALL THROUGH */
  777. #endif
  778.     case 'l':
  779.     case '\f':        /* refresh screen */
  780. #ifdef DEBUG
  781.     if (debug & DEB_INNERSRCH) {
  782.         printf("Topline = %d",topline) FLUSH;
  783.         gets(buf);
  784.     }
  785. #endif
  786.     clear();
  787.     carriage_return();    /* Resets kernel's tab column counter to 0 */
  788.     do_fseek = TRUE;
  789.     artline = topline;
  790.     if (artline < 0)
  791.         artline = 0;
  792.     firstpage = (topline < 0);
  793.     return PS_NORM;
  794.     case 'b':
  795.     case '\b':
  796.     case Ctl('b'): {    /* back up a page */
  797.     ART_LINE target;
  798.  
  799. #ifndef CLEAREOL
  800.     clear();
  801. #else
  802.     if (can_home_clear)    /* if we can home do it */
  803.         home_cursor();
  804.     else
  805.         clear();
  806.  
  807. #endif /* CLEAREOL */
  808.     carriage_return();    /* Resets kernel's tab column counter to 0 */
  809.     do_fseek = TRUE;    /* reposition article file */
  810.     target = topline - (LINES - 2);
  811.     artline = topline;
  812.     if (artline >= 0) do {
  813.         artline--;
  814.     } while(artline >= 0 && artline > target && vrdary(artline-1) >= 0);
  815.     topline = artline;
  816.             /* remember top line of screen */
  817.             /*  (line # within article file) */
  818.     if (artline < 0)
  819.         artline = 0;
  820.     firstpage = (topline < 0);
  821.     return PS_NORM;
  822.     }
  823.     case 'h': {        /* help */
  824.     int cmd;
  825.  
  826.     if ((cmd = help_page()) > 0)
  827.         pushchar(cmd);
  828.     return PS_ASK;
  829.     }
  830.     case 't':        /* output thread data */
  831.     page_line = 1;
  832.     entire_tree(curr_artp);
  833.     return PS_ASK;
  834.     case '_':
  835.     if (!finish_dblchar())
  836.         return PS_ASK;
  837.     switch (buf[1] & 0177) {
  838.     default:
  839.         goto leave_pager;
  840.     }
  841.     break;
  842.     case '\177':
  843.     case '\0':        /* treat del,break as 'n' */
  844.     *buf = 'n';
  845.     /* FALL THROUGH */
  846.     case 'k':    case 'K':    case 'J':
  847.     case 'n':    case 'N':    case Ctl('n'):
  848.     case 's':    case 'S':
  849.     case 'e':
  850.     case 'u':
  851.     case 'w':    case 'W':
  852.     case '|':
  853.     mark_as_read();        /* mark article as read */
  854.     /* FALL THROUGH */
  855.     case 'U':    case ',':
  856.     case '<':    case '>':
  857.     case '[':    case ']':
  858.     case '{':    case '}':
  859.     case '(':   case ')':
  860.     case '+':   case ':':
  861.     case '#':
  862.     case '$':
  863.     case '&':
  864.     case '-':
  865.     case '.':
  866.     case '/':
  867.     case '1': case '2': case '3': case '4': case '5':
  868.     case '6': case '7': case '8': case '9':
  869.     case '=':
  870.     case '?':
  871.     case 'A':    case 'T':
  872.     case 'c':    case 'C':    
  873. #ifdef DEBUG
  874.     case 'D':
  875. #endif
  876.     case 'E':
  877.     case 'f':    case 'F':    case Ctl('f'):
  878.     case 'j':
  879.                 case Ctl('k'):
  880.     case 'm':    case 'M':    
  881.     case 'p':    case 'P':    case Ctl('p'):    
  882.         case 'Q':
  883.     case 'r':    case 'R':    case Ctl('r'):
  884.     case 'v':
  885.         case 'Y':
  886. #ifndef ROTATION
  887.     case 'x':    case 'X':
  888. #endif
  889.     case Ctl('x'):
  890.     case 'z':    case 'Z':
  891.     case '^':
  892. leave_pager:
  893. #ifdef ROTATION
  894.     rotate = FALSE;
  895. #endif
  896.     reread = FALSE;
  897.     do_hiding = TRUE;
  898.     if (index("nNpP\016\020",*buf) == Nullch &&
  899.       index("wWsSe:!&|/?123456789.",*buf) != Nullch) {
  900.         setdfltcmd();
  901.         standout();        /* enter standout mode */
  902.         printf(prompt,mailcall,dfltcmd);
  903.                 /* print prompt, whatever it is */
  904.         un_standout();    /* leave standout mode */
  905.         putchar(' ');
  906.         fflush(stdout);
  907.     }
  908.     return PS_RAISE;    /* and pretend we were at end */
  909. #ifdef ROTATION
  910.     case 'x':
  911.     rotate = TRUE;
  912.     /* FALL THROUGH */
  913. #endif
  914.     case 'y':
  915.     case Ctl('v'):
  916.                     /* Leaving it undocumented in case */
  917.                     /* I want to steal the key--LAW */
  918.     case ' ':    /* continue current article */
  919.     if (erase_screen) {    /* -e? */
  920. #ifndef CLEAREOL
  921.         clear();        /* clear screen */
  922. #else
  923.         if (can_home_clear)    /* if we can home do it */
  924.         home_cursor();
  925.         else
  926.         clear();    /* else clear screen */
  927.  
  928. #endif /* CLEAREOL */
  929.         carriage_return();    /* Resets kernel's tab column counter to 0 */
  930.         fflush(stdout);
  931.  
  932.         if (*blinebeg != '\f'
  933. #ifdef CUSTOMLINES
  934.           && (!pagestop || blinebeg != art_buf ||
  935.               !execute(&page_compex,blinebeg))
  936. #endif
  937.           ) {
  938.         restart = blinebeg;
  939.         artline--;     /* restart this line */
  940.         artpos = alinebeg;
  941.         if (marking)    /* and mark repeated line */
  942.             highlight = artline;
  943.         }
  944.         topline = artline;
  945.             /* and remember top line of screen */
  946.             /*  (line # within article file) */
  947.     }
  948.     else if (marking && *blinebeg != '\f'
  949. #ifdef CUSTOMLINES
  950.       && (!pagestop || blinebeg != art_buf ||
  951.           !execute(&page_compex,blinebeg))
  952. #endif
  953.       ) {
  954.                 /* are we marking repeats? */
  955.         up_line();        /* go up one line */
  956.         highlight = --artline;/* and get ready to highlight */
  957.         restart = blinebeg;    /*   the old line */
  958.         artpos = alinebeg;
  959.     }
  960.     return PS_NORM;
  961.     case 'q':    /* quit this article? */
  962.     do_hiding = TRUE;
  963.     return PS_TOEND;
  964.     default:
  965.     fputs(hforhelp,stdout) FLUSH;
  966.     settle_down();
  967.     return PS_ASK;
  968.     }
  969. }
  970.  
  971. #ifdef INNERSEARCH
  972. bool
  973. innermore()
  974. {
  975.     if (artpos < innersearch) {        /* not even on page yet? */
  976. #ifdef DEBUG
  977.     if (debug & DEB_INNERSRCH)
  978.         printf("Not on page %ld < %ld\n",(long)artpos,(long)innersearch)
  979.           FLUSH;
  980. #endif
  981.     return TRUE;
  982.     }
  983.     if (artpos == innersearch) {    /* just got onto page? */
  984.     isrchline = artline;        /* remember first line after */
  985.     highlight = artline - 1;
  986. #ifdef DEBUG
  987.     if (debug & DEB_INNERSRCH)
  988.         printf("There it is %ld = %ld, %d @ %d\n",(long)artpos,
  989.         (long)innersearch,hide_everything,highlight) FLUSH;
  990. #endif
  991.     if (hide_everything) {        /* forced refresh? */
  992.         topline = highlight - gline;
  993.         if (topline < -1)
  994.         topline = -1;
  995.         return FALSE;        /* let refresh do it all */
  996.     }
  997.     }
  998. #ifdef DEBUG
  999.     if (debug & DEB_INNERSRCH)
  1000.     printf("Not far enough? %d <? %d + %d\n",artline,isrchline,gline)
  1001.       FLUSH;
  1002. #endif
  1003.     if (artline < isrchline + gline) {
  1004.     return TRUE;
  1005.     }
  1006.     return FALSE;
  1007. }
  1008. #endif
  1009.  
  1010. #ifdef MIME_SUPPORT
  1011. int
  1012. nontext(content_type)
  1013. char *content_type;
  1014. {
  1015.     char *t;
  1016.  
  1017.     if (content_type[0] == '\n')
  1018.     return 0;
  1019.     while (content_type && isspace(*content_type))
  1020.     content_type++;
  1021.     t = index(content_type, ';');
  1022.     if (!t)
  1023.     t = index(content_type, '\n');
  1024.     if (t)
  1025.     *t-- = '\0';
  1026.     while (t && *t && t > content_type && isspace(*t))
  1027.     *t-- = '\0';
  1028.     if (notplain(content_type))
  1029.     return 1;
  1030.     return 0;
  1031. }
  1032.  
  1033. int
  1034. notplain(s)
  1035. char *s;
  1036. {
  1037.     char *t;
  1038.     if (!s)
  1039.     return 1;
  1040.     while (*s && isspace(*s))
  1041.     s++;
  1042.     for (t=s; *t; ++t) {
  1043.     if (isupper(*t))
  1044.         *t = tolower(*t);
  1045.     }
  1046.     while (t > s && isspace(*--t)) ;
  1047.     if (((t-s) == 3) && !strncmp(s, "text", 4))
  1048.     return 0;
  1049.     if (strncmp(s, "text/plain", 10))
  1050.     return 1;
  1051.     t = index(s, ';');
  1052.     while (t) {
  1053.     t++;
  1054.     while (*t && isspace(*t)) t++;
  1055.     if (!strncmp(t, "charset", 7)) {
  1056.         s = index(t, '=');
  1057.         if (s) {
  1058.         s++;
  1059.         while (*s && isspace(*s)) s++;
  1060.         if (!strncmp(s, "us-ascii", 8))
  1061.             return 0;
  1062.         }
  1063.         return(1);
  1064.     }
  1065.     t = index(t, ';');
  1066.     }
  1067.     return 0;    /* no charset, was text/plain */
  1068. }
  1069. #endif
  1070.