home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1462 < prev    next >
Internet Message Format  |  1990-12-28  |  63KB

  1. From: sob@lib.tmc.edu (Stan Barber)
  2. Newsgroups: alt.sources
  3. Subject: rn/rrn combo kit part 5 of 9
  4. Message-ID: <431@lib.tmc.edu>
  5. Date: 14 Jun 90 03:28:04 GMT
  6.  
  7. #! /bin/sh
  8.  
  9. # Make a new directory for the rn sources, cd to it, and run kits 1 thru 9 
  10. # through sh.  When all 9 kits have been run, read README.
  11.  
  12. echo "This is rn kit 5 (of 9).  If kit 5 is complete, the line"
  13. echo '"'"End of kit 5 (of 9)"'" will echo at the end.'
  14. echo ""
  15. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  16. echo Extracting art.c
  17. cat >art.c <<'!STUFFY!FUNK!'
  18. /* $Header: art.c,v 4.3.2.3 90/04/21 14:43:27 sob Exp $
  19.  *
  20.  * $Log:    art.c,v $
  21.  * Revision 4.3.2.3  90/04/21  14:43:27  sob
  22.  * Revised previous patch insure that it does not decrement below zero.
  23.  * 
  24.  * Revision 4.3.2.2  90/03/22  23:03:25  sob
  25.  * Fixes provided by Wayne Davison <drivax!davison>
  26.  * 
  27.  * Revision 4.3.2.1  89/11/07  23:20:57  sob
  28.  * Bug fixes for NNTP
  29.  * 
  30.  * Revision 4.3.1.5  85/09/10  11:07:18  lwall
  31.  * %m not restored on some returns.
  32.  * 
  33.  * Revision 4.3.1.4  85/05/23  12:13:31  lwall
  34.  * shouldn't display article that's really a subdirectory.
  35.  * 
  36.  * Revision 4.3.1.3  85/05/13  09:29:55  lwall
  37.  * Added CUSTOMLINES option.
  38.  * 
  39.  * Revision 4.3.1.2  85/05/10  13:46:07  lwall
  40.  * Fixed header reparse bug on backpage.
  41.  * 
  42.  * Revision 4.3.1.1  85/05/10  11:30:56  lwall
  43.  * Branch for patches.
  44.  * 
  45.  * Revision 4.3  85/05/01  11:34:51  lwall
  46.  * Baseline for release with 4.3bsd.
  47.  * 
  48.  */
  49.  
  50. #include "EXTERN.h"
  51. #include "common.h"
  52. #include "rn.h"
  53. #include "ngstuff.h"
  54. #include "ngdata.h"
  55. #include "head.h"
  56. #include "cheat.h"
  57. #include "help.h"
  58. #include "search.h"
  59. #include "artio.h"
  60. #include "ng.h"
  61. #include "bits.h"
  62. #include "final.h"
  63. #include "artstate.h"
  64. #include "rcstuff.h"
  65. #include "term.h"
  66. #include "sw.h"
  67. #include "util.h"
  68. #include "backpage.h"
  69. #include "intrp.h"
  70. #include "INTERN.h"
  71. #include "art.h"
  72.  
  73. /* page_switch() return values */
  74.  
  75. #define PS_NORM 0
  76. #define PS_ASK 1
  77. #define PS_RAISE 2
  78. #define PS_TOEND 3
  79.  
  80. bool special = FALSE;        /* is next page special length? */
  81. int slines = 0;            /* how long to make page when special */
  82. ART_LINE highlight = -1;    /* next line to be highlighted */
  83. char *restart = Nullch;        /* if nonzero, the place where last */
  84.                 /* line left off on line split */
  85. char *blinebeg;            /* where in buffer current line began */
  86. ART_POS alinebeg;        /* where in file current line began */
  87.  
  88. #ifdef INNERSEARCH
  89. ART_POS innersearch = 0;    /* artpos of end of line we found */
  90.                 /* for 'g' command */
  91. ART_LINE isrchline = 0;            /* last line to display */
  92. bool hide_everything = FALSE;
  93.                 /* if set, do not write page now, */
  94.                 /* but refresh when done with page */
  95. COMPEX gcompex;                /* in article search pattern */
  96. #endif
  97.  
  98. bool firstpage;            /* is this the 1st page of article? */
  99.  
  100. char art_buf[LBUFLEN];        /* place for article lines */
  101.  
  102. void
  103. art_init()
  104. {
  105.     ;
  106. }
  107.  
  108. int
  109. do_article()
  110. {
  111.     register char *s;
  112.     ART_POS artsize;            /* size in bytes of article */
  113.     bool hide_this_line = FALSE;    /* hidden header line? */
  114.     ART_LINE linenum;    /* line # on page, 1 origin */
  115. #ifdef ULSMARTS
  116.     bool under_lining = FALSE;
  117.                 /* are we underlining a word? */
  118. #endif
  119.     register char *bufptr = art_buf;
  120.                 /* pointer to input buffer */
  121.     register int outpos;    /* column position of output */
  122.     static char prompt_buf[64];        /* place to hold prompt */
  123.     bool notesfiles = FALSE;        /* might there be notesfiles junk? */
  124.     char oldmode = mode;
  125.  
  126. #ifdef INNERSEARCH
  127.     register int outputok;
  128. #endif
  129.  
  130.     if (fstat(artfp->_file,&filestat))
  131.                 /* get article file stats */
  132.     return DA_CLEAN;
  133.     if ((filestat.st_mode & S_IFMT) != S_IFREG)
  134.     return DA_NORM;
  135.     artsize = filestat.st_size;
  136.                 /* from that get article size */
  137.     sprintf(prompt_buf,
  138.     "%%sEnd of article %ld (of %ld)--what next? [%%s]",
  139.     (long)art,(long)lastart);    /* format prompt string */
  140.     prompt = prompt_buf;
  141.     int_count = 0;        /* interrupt count is 0 */
  142.     firstpage = (topline < 0);
  143.     for (;;) {            /* for each page */
  144.     assert(art == openart);
  145.     if (do_fseek) {
  146. #ifdef ASYNC_PARSE
  147.         parse_maybe(art);        /* make sure header is ours */
  148. #endif
  149.         artpos = vrdary(artline);
  150.         if (artpos < 0)
  151.         artpos = -artpos;    /* labs(), anyone? */
  152.         if (firstpage)
  153.         artpos = (ART_POS)0;
  154.         fseek(artfp,artpos,0);
  155.         if (artpos < htype[PAST_HEADER].ht_minpos)
  156.         in_header = SOME_LINE;
  157.         do_fseek = FALSE;
  158.         restart = Nullch;
  159.     }
  160.     if (firstpage) {
  161.         if (firstline) {
  162.         interp(art_buf, (sizeof art_buf), firstline);
  163. #ifdef CLEAREOL
  164.         maybe_eol();    
  165. #endif CLEAREOL
  166.         fputs(art_buf,stdout) FLUSH;
  167.         artopen(art);        /* rewind article in case interp */
  168.                     /* forced a header parse */
  169.         }
  170.         else {
  171.         ART_NUM i;
  172.  
  173. #ifdef CLEAREOL
  174.         maybe_eol();    
  175. #endif CLEAREOL
  176.         printf("Article %ld",(long)art);
  177.         i = (((ART_NUM)toread[ng]) - 1 + was_read(art));
  178. #ifdef DELAYMARK
  179.         if (i || dmcount) {
  180.             printf(" (%ld more",(long)i);
  181.             if (dmcount)
  182.             printf(" + %ld Marked to return)",(long)dmcount);
  183.             putchar(')');
  184.         }
  185. #else
  186.         if (i)
  187.             printf(" (%ld more)",(long)i);
  188. #endif
  189.         if (htype[NGS_LINE].ht_flags & HT_HIDE)
  190.             printf(" in %s", ngname);
  191.         fputs(moderated,stdout);
  192.         fputs(":\n",stdout) FLUSH;
  193.         }
  194.         start_header(art);
  195.         forcelast = FALSE;        /* we will have our day in court */
  196.         restart = Nullch;
  197.         artline = 0;        /* start counting lines */
  198.         artpos = 0;
  199.         vwtary(artline,artpos);    /* remember pos in file */
  200.     }
  201.     for (linenum=(firstpage?2:1);
  202.       in_header || (
  203. #ifdef INNERSEARCH
  204.       innersearch ? innermore() :
  205. #endif
  206.       linenum<(firstpage?initlines:(special?slines:LINES)) );
  207.       linenum++) {        /* for each line on page */
  208.         if (int_count) {    /* exit via interrupt? */
  209.         putchar('\n') FLUSH;    /* get to left margin */
  210.         int_count = 0;    /* reset interrupt count */
  211.         mode = oldmode;
  212.         return DA_NORM;    /* skip out of loops */
  213.         }
  214.         if (restart) {        /* did not finish last line? */
  215.         bufptr = restart;    /* then start again here */
  216.         restart = Nullch;    /* and reset the flag */
  217.         }
  218.         else {            /* not a restart */
  219.         if (fgets(art_buf,LBUFLEN,artfp)==Nullch) {
  220.                     /* if all done */
  221.             mode = oldmode;
  222.             return DA_NORM;    /* skip out of loops */
  223.         }
  224.         bufptr = art_buf;    /* so start at beginning */
  225.         art_buf[LBUFLEN-1] = '\0';
  226.                     /* make sure string ends */
  227.         }
  228.         blinebeg = bufptr;    /* remember where we began */
  229.         alinebeg = artpos;    /* both in buffer and file */
  230.         if (in_header && bufptr == art_buf)
  231.         hide_this_line =
  232.             parseline(art_buf,do_hiding,hide_this_line);
  233.         else if (notesfiles && do_hiding &&
  234.           bufptr == art_buf && *art_buf == '#' &&
  235.           isupper(art_buf[1]) && art_buf[2] == ':' ) {
  236.         fgets(art_buf,sizeof(art_buf),artfp);
  237.         if (index(art_buf,'!') != Nullch)
  238.             fgets(art_buf,sizeof(art_buf),artfp);
  239.         htype[PAST_HEADER].ht_minpos = ftell(artfp);
  240.                     /* exclude notesfiles droppings */
  241.         hide_this_line = TRUE;    /* and do not print either */
  242.         notesfiles = FALSE;
  243.         }
  244. #ifdef CUSTOMLINES
  245.         if (hideline && bufptr == art_buf &&
  246.           execute(&hide_compex,art_buf) )
  247.         hide_this_line = TRUE;
  248. #endif
  249.         if (in_header && htype[in_header].ht_flags & HT_MAGIC) {
  250.         if (in_header == NGS_LINE) {
  251.             hide_this_line = (index(art_buf,',') == Nullch);
  252.         }
  253.         else if (in_header == EXPIR_LINE) {
  254.             if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE))
  255.             hide_this_line = (strlen(art_buf) < 10);
  256.         }
  257.         }
  258.         if (in_header == SUBJ_LINE &&
  259.         htype[SUBJ_LINE].ht_flags & HT_MAGIC) {
  260.                 /* is this the subject? */
  261.         int length;
  262.  
  263.         length = strlen(art_buf)-1;
  264.         artline++;
  265.         art_buf[length] = '\0';        /* wipe out newline */
  266. #ifdef NOFIREWORKS
  267.         no_ulfire();
  268. #endif
  269.         notesfiles =
  270.             (instr(&art_buf[length-10]," - (nf") != Nullch);
  271.         if (oldsubject) {
  272.             length += 7;
  273.             fputs("(SAME) ",stdout);
  274.             oldsubject = FALSE;
  275.         }
  276.         if (length+UG > COLS) {        /* rarely true */
  277.             linenum++;
  278.             vwtary(artline,vrdary(artline-1)+COLS);
  279.             artline++;
  280.         }
  281.         s = art_buf + 8;
  282.         *s++ = '\0';    /* make into 2 strings */
  283. #ifdef CLEAREOL
  284.         maybe_eol();    
  285. #endif CLEAREOL
  286.         fputs(art_buf,stdout) FLUSH;
  287.                 /* print up through : */
  288.         if (!UG)
  289.             putchar(' ');
  290.         underprint(s);    /* print subject underlined */
  291.         putchar('\n') FLUSH;    /* and finish the line */
  292.         }
  293.         else if (hide_this_line && do_hiding) {
  294.                     /* do not print line? */
  295.         linenum--;        /* compensate for linenum++ */
  296.         if (!in_header)
  297.             hide_this_line = FALSE;
  298.         }
  299.         else {            /* just a normal line */
  300.         if (highlight==artline) {    /* this line to be highlit? */
  301.             if (marking == STANDOUT) {
  302. #ifdef NOFIREWORKS
  303.             if (erase_screen)
  304.                 no_sofire();
  305. #endif
  306.             standout();
  307.             }
  308.             else {
  309. #ifdef NOFIREWORKS
  310.             if (erase_screen)
  311.                 no_ulfire();
  312. #endif
  313.             underline();
  314.             }
  315.             if (*bufptr == '\n')
  316.             putchar(' ');
  317.         }
  318. #ifdef INNERSEARCH
  319.         outputok = !hide_everything;
  320.                     /* get it into register, hopefully */
  321. #endif
  322. #ifdef CLEAREOL
  323. #ifdef INNERSEARCH
  324.         if (outputok)
  325. #endif
  326.         maybe_eol();    
  327. #endif CLEAREOL
  328. #ifdef CUSTOMLINES
  329.         if (pagestop && bufptr == art_buf && 
  330.           execute(&page_compex,art_buf) )
  331.             linenum = 32700;
  332. #endif
  333.         for (outpos = 0; outpos < COLS; ) {
  334.                     /* while line has room */
  335.             if (*bufptr >= ' ') {    /* normal char? */
  336. #ifdef ULSMARTS
  337.             if (*bufptr == '_') {
  338.                 if (bufptr[1] == '\b') {
  339.                 if (!under_lining && highlight!=artline
  340. #ifdef INNERSEARCH
  341.                     && outputok
  342. #endif
  343.                     ) {
  344.                     under_lining++;
  345.                     if (UG) {
  346.                     if (bufptr != buf &&
  347.                       bufptr[-1] == ' ') {
  348.                         outpos--;
  349.                         backspace();
  350.                     }
  351.                     }
  352.                     underline();
  353.                 }
  354.                 bufptr += 2;
  355.                 }
  356.             }
  357.             else {
  358.                 if (under_lining) {
  359.                 under_lining = 0;
  360.                 un_underline();
  361.                 if (UG) {
  362.                     if (*bufptr == ' ')
  363.                     goto skip_put;
  364.                     outpos++;
  365.                 }
  366.                 }
  367.             }
  368. #endif
  369. #ifdef INNERSEARCH
  370.             if (outputok)
  371. #endif
  372.             {
  373. #ifdef ROTATION
  374.                 if (rotate && !in_header
  375.                   && isalpha(*bufptr)) {
  376.                 if ((*bufptr & 31) <= 13)
  377.                     putchar(*bufptr+13);
  378.                 else
  379.                     putchar(*bufptr-13);
  380.                 }
  381.                 else
  382. #endif
  383.                 putchar(*bufptr);
  384.             }
  385.             if (*UC && ((highlight==artline && marking == 1)
  386. #ifdef ULSMARTS
  387.                 || under_lining
  388. #endif
  389.                 )) {
  390.                 backspace();
  391.                 underchar();
  392.             }
  393.             skip_put:
  394.             bufptr++;
  395.             outpos++;
  396.             }
  397.             else if (*bufptr == '\n' || !*bufptr) {
  398.                             /* newline? */
  399. #ifdef ULSMARTS
  400.             if (under_lining) {
  401.                 under_lining = 0;
  402.                 un_underline();
  403.             }
  404. #endif
  405. #ifdef DEBUGGING
  406.             if (debug & DEB_INNERSRCH && outpos < COLS - 6) {
  407.                 standout();
  408.                 printf("%4d",artline); 
  409.                 un_standout();
  410.             }
  411. #endif
  412. #ifdef INNERSEARCH
  413.             if (outputok)
  414. #endif
  415.                 putchar('\n') FLUSH;
  416.             restart = 0;
  417.             outpos = 1000;    /* signal normal \n */
  418.             }
  419.             else if (*bufptr == '\t') {    /* tab? */
  420. #ifdef INNERSEARCH
  421.             if (outputok)
  422. #endif
  423.                 putchar(*bufptr);
  424.             bufptr++;
  425.             outpos += 8 - outpos % 8;
  426.             }
  427.             else if (*bufptr == '\f') {    /* form feed? */
  428. #ifdef INNERSEARCH
  429.             if (outputok)
  430. #endif
  431.                 fputs("^L",stdout);
  432.             if (bufptr == blinebeg && highlight != artline)
  433.                 linenum = 32700;
  434.                 /* how is that for a magic number? */
  435.             bufptr++;
  436.             outpos += 2;
  437.             }
  438.             else {        /* other control char */
  439. #ifdef INNERSEARCH
  440.             if (outputok)
  441. #endif
  442.             {
  443.                 putchar('^');
  444.                 if (highlight == artline && *UC && marking == 1) {
  445.                 backspace();
  446.                 underchar();
  447.                 putchar(*bufptr+64);
  448.                 backspace();
  449.                 underchar();
  450.                 }
  451.                 else
  452.                 putchar(*bufptr+64);
  453.             }
  454.             bufptr++;
  455.             outpos += 2;
  456.             }
  457.             
  458.         } /* end of column loop */
  459.  
  460.         if (outpos < 1000) {/* did line overflow? */
  461.             restart = bufptr;
  462.                     /* restart here next time */
  463.             if (AM) {    /* automatic margins on tty? */
  464.             if (!XN && *bufptr == '\n')
  465.                     /* need we simulate XN? */
  466.                 restart = 0;
  467.                     /* skip the newline */
  468.             }
  469.             else {        /* cursor just hangs there */
  470. #ifdef INNERSEARCH
  471.             if (outputok)
  472. #endif
  473.                 putchar('\n') FLUSH;
  474.                     /* so move it down ourselves */
  475.             if (*bufptr == '\n')
  476.                 restart = 0;
  477.                     /* simulate XN if need be */
  478.             }
  479. #ifdef CLEAREOL
  480. /* #ifdef INNERSEARCH
  481.             if (outputok)
  482. #endif
  483.             maybe_eol(); */    /* comment this out for now
  484.                             until I am sure it is
  485.                             needed*/
  486.  
  487. #endif CLEAREOL
  488.         }
  489.  
  490.         /* handle normal end of output line formalities */
  491.  
  492.         if (highlight == artline) {
  493.                     /* were we highlighting line? */
  494.             if (marking == STANDOUT)
  495.             un_standout();
  496.             else
  497.             un_underline();
  498.             highlight = -1;    /* no more we are */
  499.         }
  500.         artline++;    /* count the line just printed */
  501.         if (artline - LINES + 1 > topline)
  502.                 /* did we just scroll top line off? */
  503.             topline = artline - LINES + 1;
  504.                 /* then recompute top line # */
  505.         }
  506.  
  507.         /* determine actual position in file */
  508.  
  509.         if (restart)    /* stranded somewhere in the buffer? */
  510.         artpos += restart - blinebeg;
  511.                 /* just calculate position */
  512.         else        /* no, ftell will do */
  513.         artpos = ftell(artfp);
  514.                 /* so do ftell */
  515.         vwtary(artline,artpos);    /* remember pos in file */
  516.     } /* end of line loop */
  517.  
  518. #ifdef INNERSEARCH
  519.     innersearch = 0;
  520.     if (hide_everything) {
  521.         hide_everything = FALSE;
  522.         *buf = Ctl('l');
  523.         goto fake_command;
  524.     }
  525. #endif
  526.     if (linenum >= 32700)/* did last line have formfeed? */
  527.         vwtary(artline-1,-vrdary(artline-1));
  528.                 /* remember by negating pos in file */
  529.  
  530.     special = FALSE;    /* end of page, so reset page length */
  531.     firstpage = FALSE;    /* and say it is not 1st time thru */
  532.  
  533.     /* extra loop bombout */
  534.  
  535.     if (artpos == artsize) {/* did we just now reach EOF? */
  536.         mode = oldmode;
  537.         return DA_NORM;    /* avoid --MORE--(100%) */
  538.     }
  539.  
  540. /* not done with this article, so pretend we are a pager */
  541.  
  542. reask_pager:            
  543.     unflush_output();    /* disable any ^O in effect */
  544.     standout();        /* enter standout mode */
  545.     printf("--MORE--(%ld%%)",(long)(artpos*100/artsize));
  546.     un_standout();    /* leave standout mode */
  547.     fflush(stdout);
  548. /* reinp_pager:                 /* unused, commented for lint */
  549.     eat_typeahead();
  550. #ifdef DEBUGGING
  551.     if (debug & DEB_CHECKPOINTING) {
  552.         printf("(%d %d %d)",checkcount,linenum,artline);
  553.         fflush(stdout);
  554.     }
  555. #endif
  556.     if (checkcount >= docheckwhen &&
  557.       linenum == LINES &&
  558.       (artline > 40 || checkcount >= docheckwhen+10) ) {
  559.                 /* while he is reading a whole page */
  560.                 /* in an article he is interested in */
  561.         checkcount = 0;
  562.         checkpoint_rc();    /* update .newsrc */
  563.     }
  564.     collect_subjects();        /* loads subject cache until */
  565.                     /* input is pending */
  566.     mode = 'p';
  567.     getcmd(buf);
  568.     if (errno) {
  569.         if (LINES < 100 && !int_count)
  570.         *buf = '\f';/* on CONT fake up refresh */
  571.         else {
  572.         *buf = 'q';    /* on INTR or paper just quit */
  573.         }
  574.     }
  575.     carriage_return();
  576. #ifndef CLEAREOL
  577.     erase_eol();    /* and erase the prompt */
  578. #else
  579.     if (erase_screen && can_home_clear)    
  580.         clear_rest();
  581.     else
  582.         erase_eol();    /* and erase the prompt */
  583. #endif CLEAREOL
  584.      carriage_return(); /* Resets kernels tab coloumn counter to 0 */    fflush(stdout);
  585.  
  586.     fake_command:        /* used by innersearch */
  587.  
  588.     /* parse and process pager command */
  589.  
  590.     switch (page_switch()) {
  591.     case PS_ASK:    /* reprompt "--MORE--..." */
  592.         goto reask_pager;
  593.     case PS_RAISE:    /* reparse on article level */
  594.         mode = oldmode;
  595.         return DA_RAISE;
  596.     case PS_TOEND:    /* fast pager loop exit */
  597.         mode = oldmode;
  598.         return DA_TOEND;
  599.     case PS_NORM:    /* display more article */
  600.         break;
  601.     }
  602.     } /* end of page loop */
  603. }
  604.  
  605. /* process pager commands */
  606.  
  607. int
  608. page_switch()
  609. {
  610.     register char *s;
  611.     
  612.     switch (*buf) {
  613.     case 'd':
  614.     case Ctl('d'):    /* half page */
  615.     special = TRUE;
  616.     slines = LINES / 2 + 1;
  617.     if (marking && *blinebeg != '\f'
  618. #ifdef CUSTOMLINES
  619.       && (!pagestop || blinebeg != art_buf ||
  620.           !execute(&page_compex,blinebeg))
  621. #endif
  622.       ) {
  623.         up_line();
  624.         highlight = --artline;
  625.         restart = blinebeg;
  626.         artpos = alinebeg;
  627.     }
  628.     return PS_NORM;
  629.     case '!':            /* shell escape */
  630.     escapade();
  631.     return PS_ASK;
  632. #ifdef INNERSEARCH
  633.     case Ctl('i'):
  634.     gline = 3;
  635.     sprintf(cmd_buf,"^[^%c]",*blinebeg);
  636.     compile(&gcompex,cmd_buf,TRUE,TRUE);
  637.     goto caseG;
  638.     case Ctl('g'):
  639.     gline = 3;
  640.     compile(&gcompex,"^Subject:",TRUE,TRUE);
  641.     goto caseG;
  642.     case 'g':        /* in-article search */
  643.     if (!finish_command(FALSE))/* get rest of command */
  644.         return PS_ASK;
  645.     s = buf+1;
  646.     if (isspace(*s))
  647.         s++;
  648.     if ((s = compile(&gcompex,s,TRUE,TRUE)) != Nullch) {
  649.                 /* compile regular expression */
  650.         printf("\n%s\n",s) FLUSH;
  651.         return PS_ASK;
  652.     }
  653.     carriage_return();
  654.     erase_eol();    /* erase the prompt */
  655.      carriage_return(); /* Resets kernels tab coloumn counter to 0 */
  656.     /* FALL THROUGH */
  657.     caseG:
  658.     case 'G': {
  659.     /* ART_LINE lines_to_skip = 0; */
  660.     ART_POS start_where;
  661.  
  662.     if (gline < 0 || gline > LINES-2)
  663.         gline = LINES-2;
  664. #ifdef DEBUGGING
  665.     if (debug & DEB_INNERSRCH)
  666.         printf("Start here? %d  >=? %d\n",topline + gline + 1,artline)
  667.           FLUSH;
  668. #endif
  669.     if (*buf == Ctl('i') || topline+gline+1 >= artline)
  670.         start_where = artpos;
  671.             /* in case we had a line wrap */
  672.     else {
  673.         start_where = vrdary(topline+gline+1);
  674.         if (start_where < 0)
  675.         start_where = -start_where;
  676.     }
  677.     if (start_where < htype[PAST_HEADER].ht_minpos)
  678.         start_where = htype[PAST_HEADER].ht_minpos;
  679.     fseek(artfp,(long)start_where,0);
  680.     innersearch = 0; /* assume not found */
  681.     while (fgets(buf, sizeof buf, artfp) != Nullch) {
  682.         /* lines_to_skip++;         NOT USED NOW */
  683. #ifdef DEBUGGING
  684.         if (debug & DEB_INNERSRCH)
  685.         printf("Test %s",buf) FLUSH;
  686. #endif
  687.         if (execute(&gcompex,buf) != Nullch) {
  688.         innersearch = ftell(artfp);
  689.         break;
  690.         }
  691.     }
  692.     if (!innersearch) {
  693.         fseek(artfp,artpos,0);
  694.         fputs("(Not found)",stdout) FLUSH;
  695.         return PS_ASK;
  696.     }
  697. #ifdef DEBUGGING
  698.     if (debug & DEB_INNERSRCH)
  699.         printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos)
  700.           FLUSH;
  701. #endif
  702.     if (innersearch <= artpos) {    /* already on page? */
  703.         if (innersearch < artpos) {
  704.         artline = topline+1;
  705.         while (vrdary(artline) < innersearch)
  706.             artline++;
  707.         }
  708.         highlight = artline - 1;
  709. #ifdef DEBUGGING
  710.         if (debug & DEB_INNERSRCH)
  711.         printf("@ %d\n",highlight) FLUSH;
  712. #endif
  713.         topline = highlight - gline;
  714.         if (topline < -1)
  715.         topline = -1;
  716.         *buf = '\f';        /* fake up a refresh */
  717.         innersearch = 0;
  718.         return page_switch();
  719.     }
  720.     else {                /* who knows how many lines it is? */
  721.         do_fseek = TRUE;
  722.         hide_everything = TRUE;
  723.     }
  724.     return PS_NORM;
  725.     }
  726. #else
  727.     case 'g': case 'G': case Ctl('g'):
  728.     notincl("g");
  729.     return PS_ASK;
  730. #endif
  731.     case '\n':        /* one line */
  732.     special = TRUE;
  733.     slines = 2;
  734.     return PS_NORM;
  735. #ifdef ROTATION
  736.     case 'X':
  737.     rotate = !rotate;
  738.     /* FALL THROUGH */
  739. #endif
  740.     case 'l':
  741.     case '\f':        /* refresh screen */
  742. #ifdef DEBUGGING
  743.     if (debug & DEB_INNERSRCH) {
  744.         printf("Topline = %d",topline) FLUSH;
  745.         gets(buf);
  746.     }
  747. #endif
  748.     clear();
  749.      carriage_return(); /* Resets kernels tab coloumn counter to 0 */
  750.     do_fseek = TRUE;
  751.     artline = topline;
  752.     if (artline < 0)
  753.         artline = 0;
  754.     firstpage = (topline < 0);
  755.     return PS_NORM;
  756.     case 'b':
  757.     case '\b':
  758.     case Ctl('b'): {    /* back up a page */
  759.     ART_LINE target;
  760.  
  761. #ifndef CLEAREOL
  762.     clear();
  763. #else
  764.     if (can_home_clear)    /* if we can home do it */
  765.         home_cursor();
  766.     else
  767.         clear();
  768.  
  769. #endif CLEAREOL
  770.      carriage_return(); /* Resets kernels tab coloumn counter to 0 */
  771.     do_fseek = TRUE;    /* reposition article file */
  772.     target = topline - (LINES - 2);
  773.     artline = topline;
  774.     if (artline > 0) do {
  775.         artline--;
  776.     } while (artline >= 0 && artline > target &&
  777.         vrdary(artline-1) >= 0);
  778.     topline = artline;
  779.             /* remember top line of screen */
  780.             /*  (line # within article file) */
  781.     if (artline < 0)
  782.         artline = 0;
  783.     firstpage = (topline < 0);
  784.     return PS_NORM;
  785.     }
  786.     case 'h': {        /* help */
  787.     int cmd;
  788.  
  789.     if ((cmd = help_page()) > 0)
  790.         pushchar(cmd);
  791.     return PS_ASK;
  792.     }
  793.     case '\177':
  794.     case '\0':        /* treat del,break as 'n' */
  795.     *buf = 'n';
  796.     /* FALL THROUGH */
  797.     case 'k':    case 'K':
  798.     case 'n':    case 'N':    case Ctl('n'):
  799.     case 's':    case 'S':
  800.     case 'u':
  801.     case 'w':    case 'W':
  802.     case '|':
  803.     mark_as_read(art);    /* mark article as read */
  804.     /* FALL THROUGH */
  805.     case '#':
  806.     case '$':
  807.     case '&':
  808.     case '-':
  809.     case '.':
  810.     case '/':
  811.     case '1': case '2': case '3': case '4': case '5':
  812.     case '6': case '7': case '8': case '9':
  813.     case '=':
  814.     case '?':
  815.     case 'c':    case 'C':    
  816.     case 'f':    case 'F':    
  817.     case 'j':
  818.                 case Ctl('k'):
  819.     case 'm':    case 'M':    
  820.     case 'p':    case 'P':    case Ctl('p'):    
  821.         case 'Q':
  822.     case 'r':    case 'R':    case Ctl('r'):
  823.     case 'v':
  824.         case 'Y':
  825. #ifndef ROTATION
  826.     case 'x':    case 'X':
  827. #endif
  828.     case Ctl('x'):
  829.     case '^':
  830.  
  831. #ifdef ROTATION
  832.     rotate = FALSE;
  833. #endif
  834.     reread = FALSE;
  835.     do_hiding = TRUE;
  836.     if (index("nNpP",*buf) == Nullch &&
  837.       index("wWsS!&|/?123456789.",*buf) != Nullch) {
  838.         setdfltcmd();
  839.         standout();        /* enter standout mode */
  840.         printf(prompt,mailcall,dfltcmd);
  841.                 /* print prompt, whatever it is */
  842.         un_standout();    /* leave standout mode */
  843.         putchar(' ');
  844.         fflush(stdout);
  845.     }
  846.     return PS_RAISE;    /* and pretend we were at end */
  847. #ifdef ROTATION
  848.     case 'x':
  849.     rotate = TRUE;
  850.     /* FALL THROUGH */
  851. #endif
  852.     case 'y':
  853.     case Ctl('v'):
  854.                     /* Leaving it undocumented in case */
  855.                     /* I want to steal the key--LAW */
  856.     case ' ':    /* continue current article */
  857.     if (erase_screen) {    /* -e? */
  858. #ifndef CLEAREOL
  859.         clear();        /* clear screen */
  860. #else
  861.         if (can_home_clear)    /* if we can home do it */
  862.         home_cursor();
  863.         else
  864.         clear();    /* else clear screen */
  865.  
  866. #endif CLEAREOL
  867.         if (*blinebeg != '\f'
  868. #ifdef CUSTOMLINES
  869.           && (!pagestop || blinebeg != art_buf ||
  870.               !execute(&page_compex,blinebeg))
  871. #endif
  872.           ) {
  873.         restart = blinebeg;
  874.         artline--;     /* restart this line */
  875.         artpos = alinebeg;
  876.         if (marking)    /* and mark repeated line */
  877.             highlight = artline;
  878.         }
  879.         topline = artline;
  880.             /* and remember top line of screen */
  881.             /*  (line # within article file) */
  882.     }
  883.     else if (marking && *blinebeg != '\f'
  884. #ifdef CUSTOMLINES
  885.       && (!pagestop || blinebeg != art_buf ||
  886.           !execute(&page_compex,blinebeg))
  887. #endif
  888.       ) {
  889.                 /* are we marking repeats? */
  890.         up_line();        /* go up one line */
  891.         highlight = --artline;/* and get ready to highlight */
  892.         restart = blinebeg;    /*   the old line */
  893.         artpos = alinebeg;
  894.     }
  895.     return PS_NORM;
  896.     case 'q':    /* quit this article? */
  897.     do_hiding = TRUE;
  898.     return PS_TOEND;
  899.     default:
  900.     fputs(hforhelp,stdout) FLUSH;
  901.     settle_down();
  902.     return PS_ASK;
  903.     }
  904. }
  905.  
  906. #ifdef INNERSEARCH
  907. bool
  908. innermore()
  909. {
  910.     if (artpos < innersearch) {        /* not even on page yet? */
  911. #ifdef DEBUGGING
  912.     if (debug & DEB_INNERSRCH)
  913.         printf("Not on page %ld < %ld\n",(long)artpos,(long)innersearch)
  914.           FLUSH;
  915. #endif
  916.     return TRUE;
  917.     }
  918.     if (artpos == innersearch) {    /* just got onto page? */
  919.     isrchline = artline;        /* remember first line after */
  920.     highlight = artline - 1;
  921. #ifdef DEBUGGING
  922.     if (debug & DEB_INNERSRCH)
  923.         printf("There it is %ld = %ld, %d @ %d\n",(long)artpos,
  924.         (long)innersearch,hide_everything,highlight) FLUSH;
  925. #endif
  926.     if (hide_everything) {        /* forced refresh? */
  927.         topline = highlight - gline;
  928.         if (topline < -1)
  929.         topline = -1;
  930.         return FALSE;        /* let refresh do it all */
  931.     }
  932.     }
  933. #ifdef DEBUGGING
  934.     if (debug & DEB_INNERSRCH)
  935.     printf("Not far enough? %d <? %d + %d\n",artline,isrchline,gline)
  936.       FLUSH;
  937. #endif
  938.     if (artline < isrchline + gline) {
  939.     return TRUE;
  940.     }
  941.     return FALSE;
  942. }
  943. #endif
  944. !STUFFY!FUNK!
  945. echo Extracting rcstuff.c
  946. cat >rcstuff.c <<'!STUFFY!FUNK!'
  947. /* $Header: rcstuff.c,v 4.3.2.5 90/05/04 00:44:07 sob Exp $
  948.  *
  949.  * $Log:    rcstuff.c,v $
  950.  * Revision 4.3.2.5  90/05/04  00:44:07  sob
  951.  * Fixes to add_newsgroup() from lar@usl.edu.
  952.  * 
  953.  * Revision 4.3.2.4  90/04/23  00:25:45  sob
  954.  * Changed atoi to atol.
  955.  * 
  956.  * Revision 4.3.2.3  89/12/20  23:25:04  sob
  957.  * Changed the maximum lenght of a newsgroup name from 20 to 40 characters.
  958.  * 
  959.  * Revision 4.3.2.2  89/11/26  18:22:26  sob
  960.  * Added changes to addnewgroup() to cause rn to ask once and only once
  961.  * to add a new group to .newsrc. 
  962.  * Fix provided by Fletcher Mattox <fletcher@cs.utexas.edu>
  963.  * 
  964.  * Revision 4.3.2.1  89/11/06  00:58:29  sob
  965.  * Added RRN support from NNTP 1.5
  966.  * 
  967.  * Revision 4.3.1.5  86/07/24  14:09:10  lwall
  968.  * Removed check for spool directory existence in get_ng.
  969.  * 
  970.  * Revision 4.3.1.4  85/09/10  11:04:44  lwall
  971.  * Improved %m in in_char().
  972.  * 
  973.  * Revision 4.3.1.3  85/05/29  09:13:25  lwall
  974.  * %d that should be %ld.
  975.  * 
  976.  * Revision 4.3.1.2  85/05/17  11:40:08  lwall
  977.  * Sped up "rn -c" by not mallocing unnecessarily.
  978.  * 
  979.  * Revision 4.3.1.1  85/05/10  11:37:18  lwall
  980.  * Branch for patches.
  981.  * 
  982.  * Revision 4.3  85/05/01  11:45:56  lwall
  983.  * Baseline for release with 4.3bsd.
  984.  * 
  985.  */
  986.  
  987. #include "EXTERN.h"
  988. #include "common.h"
  989. #include "util.h"
  990. #include "ngdata.h"
  991. #include "term.h"
  992. #include "final.h"
  993. #include "rn.h"
  994. #include "intrp.h"
  995. #include "only.h"
  996. #include "rcln.h"
  997. #ifdef SERVER
  998. #include "server.h"
  999. #endif
  1000. #include "INTERN.h"
  1001. #include "rcstuff.h"
  1002.  
  1003. char *rcname INIT(Nullch);        /* path name of .newsrc file */
  1004. char *rctname INIT(Nullch);        /* path name of temp .newsrc file */
  1005. char *rcbname INIT(Nullch);        /* path name of backup .newsrc file */
  1006. char *softname INIT(Nullch);        /* path name of .rnsoft file */
  1007. FILE *rcfp INIT(Nullfp);            /* .newsrc file pointer */
  1008.  
  1009. #ifdef HASHNG
  1010.     short hashtbl[HASHSIZ];
  1011. #endif
  1012.  
  1013. bool
  1014. rcstuff_init()
  1015. {
  1016.     register NG_NUM newng;
  1017.     register char *s;
  1018.     register int i;
  1019.     register bool foundany = FALSE;
  1020.     char *some_buf;
  1021.     long length;
  1022. #ifdef SERVER
  1023.     char *cp;
  1024. #endif SERVER
  1025.  
  1026. #ifdef HASHNG
  1027.     for (i=0; i<HASHSIZ; i++)
  1028.     hashtbl[i] = -1;
  1029. #endif
  1030.  
  1031.     /* make filenames */
  1032.  
  1033. #ifdef SERVER
  1034.  
  1035.     if (cp = getenv("NEWSRC"))
  1036.     rcname = savestr(filexp(cp));
  1037.     else
  1038.     rcname = savestr(filexp(RCNAME));
  1039.  
  1040. #else not SERVER
  1041.  
  1042.     rcname = savestr(filexp(RCNAME));
  1043.  
  1044. #endif SERVER
  1045.  
  1046.     rctname = savestr(filexp(RCTNAME));
  1047.     rcbname = savestr(filexp(RCBNAME));
  1048.     softname = savestr(filexp(SOFTNAME));
  1049.     
  1050.     /* make sure the .newsrc file exists */
  1051.  
  1052.     newsrc_check();
  1053.  
  1054.     /* open .rnsoft file containing soft ptrs to active file */
  1055.  
  1056.     tmpfp = fopen(softname,"r");
  1057.     if (tmpfp == Nullfp)
  1058.     writesoft = TRUE;
  1059.  
  1060.     /* read in the .newsrc file */
  1061.  
  1062.     for (nextrcline = 0;
  1063.     (some_buf = get_a_line(buf,LBUFLEN,rcfp)) != Nullch;
  1064.     nextrcline++) {
  1065.                     /* for each line in .newsrc */
  1066.     char tmpbuf[10];
  1067.  
  1068.     newng = nextrcline;        /* get it into a register */
  1069.     length = len_last_line_got;    /* side effect of get_a_line */
  1070.     if (length <= 1) {        /* only a newline??? */
  1071.         nextrcline--;        /* compensate for loop increment */
  1072.         continue;
  1073.     }
  1074.     if (newng >= MAXRCLINE) {    /* check for overflow */
  1075.         fputs("Too many lines in .newsrc\n",stdout) FLUSH;
  1076.         finalize(1);
  1077.     }
  1078.     if (tmpfp != Nullfp && fgets(tmpbuf,10,tmpfp) != Nullch)
  1079.         softptr[newng] = atol(tmpbuf);
  1080.     else
  1081.         softptr[newng] = 0;
  1082.     some_buf[--length] = '\0';    /* wipe out newline */
  1083.     if (checkflag)            /* no extra mallocs for -c */
  1084.         rcline[newng] = some_buf;
  1085.     else if (some_buf == buf) {
  1086.         rcline[newng] = savestr(some_buf);
  1087.                     /* make a semipermanent copy */
  1088.     }
  1089.     else {
  1090.         /*NOSTRICT*/
  1091. #ifndef lint
  1092.         some_buf = saferealloc(some_buf,(MEM_SIZE)(length+1));
  1093. #endif lint
  1094.         rcline[newng] = some_buf;
  1095.     }
  1096. #ifdef NOTDEF
  1097.     if (strnEQ(some_buf,"to.",3)) {    /* is this a non-newsgroup? */
  1098.         nextrcline--;        /* destroy this line */
  1099.         continue;
  1100.     }
  1101. #endif
  1102.     if (*some_buf == ' ' ||
  1103.       *some_buf == '\t' ||
  1104.       strnEQ(some_buf,"options",7)) {        /* non-useful line? */
  1105.         toread[newng] = TR_JUNK;
  1106.         rcchar[newng] = ' ';
  1107.         rcnums[newng] = 0;
  1108.         continue;
  1109.     }
  1110.     for (s = rcline[newng]; *s && *s != ':' && *s != NEGCHAR; s++) ;
  1111.     if (!*s && !checkflag) {
  1112. #ifndef lint
  1113.         rcline[newng] = saferealloc(rcline[newng],(MEM_SIZE)length+2);
  1114. #endif lint
  1115.         s = rcline[newng] + length;
  1116.         *s = ':';
  1117.         *(s+1) = '\0';
  1118.     }
  1119.     rcchar[newng] = *s;        /* salt away the : or ! */
  1120.     rcnums[newng] = (char)(s - rcline[newng]); 
  1121.     rcnums[newng]++;        /* remember where it was */
  1122.     *s = '\0';            /* null terminate newsgroup name */
  1123. #ifdef HASHNG
  1124.     if (!checkflag)
  1125.         sethash(newng);
  1126. #endif
  1127.     if (rcchar[newng] == NEGCHAR) {
  1128.         toread[newng] = TR_UNSUB;
  1129.         continue;
  1130.     }
  1131.  
  1132.     /* now find out how much there is to read */
  1133.  
  1134.     if (!inlist(buf) || (suppress_cn && foundany && !paranoid))
  1135.         toread[newng] = TR_NONE;    /* no need to calculate now */
  1136.     else
  1137.         set_toread(newng);
  1138. #ifdef VERBOSE
  1139.     if (!checkflag && softmisses == 1) {
  1140.         softmisses++;        /* lie a little */
  1141.         fputs("(Revising soft pointers--be patient.)\n",stdout) FLUSH;
  1142.     }
  1143. #endif
  1144.     if (toread[newng] > TR_NONE) {    /* anything unread? */
  1145.         if (!foundany) {
  1146.         starthere = newng;
  1147.         foundany = TRUE;    /* remember that fact*/
  1148.         }
  1149.         if (suppress_cn) {        /* if no listing desired */
  1150.         if (checkflag) {    /* if that is all they wanted */
  1151.             finalize(1);    /* then bomb out */
  1152.         }
  1153.         }
  1154.         else {
  1155. #ifdef VERBOSE
  1156.         IF(verbose)
  1157.             printf("Unread news in %-40s %5ld article%s\n",
  1158.             rcline[newng],(long)toread[newng],
  1159.             toread[newng]==TR_ONE ? nullstr : "s") FLUSH;
  1160.         ELSE
  1161. #endif
  1162. #ifdef TERSE
  1163.             printf("%s: %ld article%s\n",
  1164.             rcline[newng],(long)toread[newng],
  1165.             toread[newng]==TR_ONE ? nullstr : "s") FLUSH;
  1166. #endif
  1167.         if (int_count) {
  1168.             countdown = 1;
  1169.             int_count = 0;
  1170.         }
  1171.         if (countdown) {
  1172.             if (! --countdown) {
  1173.             fputs("etc.\n",stdout) FLUSH;
  1174.             if (checkflag)
  1175.                 finalize(1);
  1176.             suppress_cn = TRUE;
  1177.             }
  1178.         }
  1179.         }
  1180.     }
  1181.     }
  1182.     fclose(rcfp);            /* close .newsrc */
  1183.     if (tmpfp != Nullfp)
  1184.     fclose(tmpfp);            /* close .rnsoft */
  1185.     if (checkflag) {            /* were we just checking? */
  1186.     finalize(foundany);        /* tell them what we found */
  1187.     }
  1188.     if (paranoid)
  1189.     cleanup_rc();
  1190.  
  1191. #ifdef DEBUGGING
  1192.     if (debug & DEB_HASH) {
  1193.     page_init();
  1194.     for (i=0; i<HASHSIZ; i++) {
  1195.         sprintf(buf,"%d    %d",i,hashtbl[i]);
  1196.         print_lines(buf,NOMARKING);
  1197.     }
  1198.     }
  1199. #endif
  1200.  
  1201.     return foundany;
  1202. }
  1203.  
  1204. /* try to find or add an explicitly specified newsgroup */
  1205. /* returns TRUE if found or added, FALSE if not. */
  1206. /* assumes that we are chdir'ed to SPOOL */
  1207.  
  1208. #ifdef SERVER
  1209. static int addnewbydefault = 0;
  1210. #endif SERVER
  1211.  
  1212. bool
  1213. get_ng(what,do_reloc)
  1214. char *what;
  1215. bool do_reloc;
  1216. {
  1217.     char *ntoforget;
  1218.     char promptbuf[128];
  1219. #ifdef SERVER
  1220.     char ser_line[256];
  1221. #endif SERVER
  1222.  
  1223. #ifdef VERBOSE
  1224.     IF(verbose)
  1225.     ntoforget = "Type n to forget about this newsgroup.\n";
  1226.     ELSE
  1227. #endif
  1228. #ifdef TERSE
  1229.     ntoforget = "n to forget it.\n";
  1230. #endif
  1231.     if (index(what,'/')) {
  1232.     dingaling();
  1233.     printf("\nBad newsgroup name.\n") FLUSH;
  1234.     return FALSE;
  1235.     }
  1236.     set_ngname(what);
  1237.     ng = find_ng(ngname);
  1238.     if (ng == nextrcline) {        /* not in .newsrc? */
  1239.  
  1240. #ifdef SERVER
  1241.     sprintf(ser_line, "GROUP %s", ngname);
  1242.     put_server(ser_line);
  1243.     if (get_server(ser_line, sizeof(ser_line)) < 0) {
  1244.         fprintf(stderr, "rrn: Unexpected close of server socket.\n");
  1245.         finalize(1);
  1246.     }
  1247.     if (*ser_line != CHAR_OK) {
  1248.         if (atoi(ser_line) != ERR_NOGROUP) {
  1249.         fprintf(stderr, "Server response to GROUP %s:\n%s\n",
  1250.             ngname, ser_line);
  1251.         }
  1252. #else not SERVER
  1253.  
  1254.     if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0 ) {
  1255.  
  1256. #endif SERVER
  1257.  
  1258.         dingaling();
  1259. #ifdef VERBOSE
  1260.         IF(verbose)
  1261.         printf("\nNewsgroup %s does not exist!\n",ngname) FLUSH;
  1262.         ELSE
  1263. #endif
  1264. #ifdef TERSE
  1265.         printf("\nNo %s!\n",ngname) FLUSH;
  1266. #endif
  1267.         sleep(2);
  1268.         return FALSE;
  1269.     }
  1270. #ifdef SERVER
  1271.     if (addnewbydefault) {
  1272.         printf("(Adding %s to end of your .newsrc)\n", ngname);
  1273.             ng = add_newsgroup(ngname, ':');
  1274.             do_reloc = FALSE;
  1275.     } else {
  1276. #endif SERVER
  1277. #ifdef VERBOSE
  1278.     IF(verbose)
  1279.         sprintf(promptbuf,"\nNewsgroup %s not in .newsrc--add? [yn] ",ngname);
  1280.     ELSE
  1281. #endif
  1282. #ifdef TERSE
  1283.         sprintf(promptbuf,"\nAdd %s? [yn] ",ngname);
  1284. #endif
  1285. reask_add:
  1286.     in_char(promptbuf,'A');
  1287.     putchar('\n') FLUSH;
  1288.     setdef(buf,"y");
  1289. #ifdef VERIFY
  1290.     printcmd();
  1291. #endif
  1292.     if (*buf == 'h') {
  1293. #ifdef VERBOSE
  1294.         IF(verbose)
  1295.         printf("Type y or SP to add %s to your .newsrc.\n", ngname)
  1296.           FLUSH;
  1297.         ELSE
  1298. #endif
  1299. #ifdef TERSE
  1300.         fputs("y or SP to add\n",stdout) FLUSH;
  1301. #endif
  1302.         fputs(ntoforget,stdout) FLUSH;
  1303.         goto reask_add;
  1304.     }
  1305.     else if (*buf == 'n' || *buf == 'q') {
  1306.         ng = add_newsgroup(ngname, '!');
  1307.         return FALSE;
  1308.     }
  1309.     else if (*buf == 'y') {
  1310.         ng = add_newsgroup(ngname, ':');
  1311.         do_reloc = FALSE;
  1312.     }
  1313. #ifdef SERVER
  1314.     else if (*buf == 'Y') {
  1315.         fputs(
  1316.     "(I'll add all new newsgroups to the end of your .newsrc.)\n", stdout);
  1317.         addnewbydefault = 1;
  1318.         printf("(Adding %s to end of your .newsrc)\n", ngname);
  1319.         ng = add_newsgroup(ngname, ':');
  1320.         do_reloc = FALSE;
  1321.     }
  1322. #endif SERVER
  1323.     else {
  1324.         fputs(hforhelp,stdout) FLUSH;
  1325.         settle_down();
  1326.         goto reask_add;
  1327.     }
  1328. #ifdef SERVER
  1329.       }
  1330. #endif SERVER
  1331.     }
  1332.     else if (rcchar[ng] == NEGCHAR) {    /* unsubscribed? */
  1333. #ifdef VERBOSE
  1334.     IF(verbose)
  1335.         sprintf(promptbuf,
  1336. "\nNewsgroup %s is currently unsubscribed to--resubscribe? [yn] ",ngname)
  1337.   FLUSH;
  1338.     ELSE
  1339. #endif
  1340. #ifdef TERSE
  1341.         sprintf(promptbuf,"\n%s unsubscribed--resubscribe? [yn] ",ngname)
  1342.           FLUSH;
  1343. #endif
  1344. reask_unsub:
  1345.     in_char(promptbuf,'R');
  1346.     putchar('\n') FLUSH;
  1347.     setdef(buf,"y");
  1348. #ifdef VERIFY
  1349.     printcmd();
  1350. #endif
  1351.     if (*buf == 'h') {
  1352. #ifdef VERBOSE
  1353.         IF(verbose)
  1354.         printf("Type y or SP to resubscribe to %s.\n", ngname) FLUSH;
  1355.         ELSE
  1356. #endif
  1357. #ifdef TERSE
  1358.         fputs("y or SP to resubscribe.\n",stdout) FLUSH;
  1359. #endif
  1360.         fputs(ntoforget,stdout) FLUSH;
  1361.         goto reask_unsub;
  1362.     }
  1363.     else if (*buf == 'n' || *buf == 'q') {
  1364.         return FALSE;
  1365.     }
  1366.     else if (*buf == 'y') {
  1367.         rcchar[ng] = ':';
  1368.     }
  1369.     else {
  1370.         fputs(hforhelp,stdout) FLUSH;
  1371.         settle_down();
  1372.         goto reask_unsub;
  1373.     }
  1374.     }
  1375.  
  1376.     /* now calculate how many unread articles in newsgroup */
  1377.  
  1378.     set_toread(ng);
  1379. #ifdef RELOCATE
  1380.     if (do_reloc)
  1381.     ng = relocate_newsgroup(ng,-1);
  1382. #endif
  1383.     return toread[ng] >= TR_NONE;
  1384. }
  1385.  
  1386. /* add a newsgroup to the .newsrc file (eventually) */
  1387.  
  1388. NG_NUM
  1389. add_newsgroup(ngn, c)
  1390. char *ngn, c;
  1391. {
  1392.     register NG_NUM newng = nextrcline++;
  1393.                     /* increment max rcline index */
  1394.     
  1395.     rcnums[newng] = strlen(ngn) + 1;
  1396.     rcline[newng] = safemalloc((MEM_SIZE)(rcnums[newng] + 1));
  1397.     strcpy(rcline[newng],ngn);        /* and copy over the name */
  1398.     *(rcline[newng] + rcnums[newng]) = '\0';
  1399.     rcchar[newng] = c;            /* subscribe or unsubscribe */
  1400.     toread[newng] = TR_NONE;    /* just for prettiness */
  1401. #ifdef HASHNG
  1402.     sethash(newng);            /* so we can find it again */
  1403. #endif
  1404. #ifdef RELOCATE
  1405.     return c=='!' ? newng : relocate_newsgroup(newng,-1);
  1406. #else
  1407.     return newng;
  1408. #endif
  1409. }
  1410.  
  1411. #ifdef RELOCATE
  1412. NG_NUM
  1413. relocate_newsgroup(ngx,newng)
  1414. NG_NUM ngx;
  1415. NG_NUM newng;
  1416. {
  1417.     char *dflt = (ngx!=current_ng ? "$^.L" : "$^L");
  1418.     char *tmprcline;
  1419.     ART_UNREAD tmptoread;
  1420.     char tmprcchar;
  1421.     char tmprcnums;
  1422.     ACT_POS tmpsoftptr;
  1423.     register NG_NUM i;
  1424. #ifdef DEBUGGING
  1425.     ART_NUM tmpngmax;
  1426. #endif
  1427. #ifdef CACHEFIRST
  1428.     ART_NUM tmpabs1st;
  1429. #endif
  1430.     
  1431.     starthere = 0;                      /* Disable this optimization */
  1432.     writesoft = TRUE;            /* Update soft pointer file */
  1433.     if (ngx < nextrcline-1) {
  1434. #ifdef HASHNG
  1435.     for (i=0; i<HASHSIZ; i++) {
  1436.         if (hashtbl[i] > ngx)
  1437.         --hashtbl[i];
  1438.         else if (hashtbl[i] == ngx)
  1439.         hashtbl[i] = nextrcline-1;
  1440.     }
  1441. #endif
  1442.     tmprcline = rcline[ngx];
  1443.     tmptoread = toread[ngx];
  1444.     tmprcchar = rcchar[ngx];
  1445.     tmprcnums = rcnums[ngx];
  1446.     tmpsoftptr = softptr[ngx];
  1447. #ifdef DEBUGGING
  1448.     tmpngmax = ngmax[ngx];
  1449. #endif
  1450. #ifdef CACHEFIRST
  1451.     tmpabs1st = abs1st[ngx];
  1452. #endif
  1453.     for (i=ngx+1; i<nextrcline; i++) {
  1454.         rcline[i-1] = rcline[i];
  1455.         toread[i-1] = toread[i];
  1456.         rcchar[i-1] = rcchar[i];
  1457.         rcnums[i-1] = rcnums[i];
  1458.         softptr[i-1] = softptr[i];
  1459. #ifdef DEBUGGING
  1460.         ngmax[i-1] = ngmax[i];
  1461. #endif
  1462. #ifdef CACHEFIRST
  1463.         abs1st[i-1] = abs1st[i];
  1464. #endif
  1465.     }
  1466.     rcline[nextrcline-1] = tmprcline;
  1467.     toread[nextrcline-1] = tmptoread;
  1468.     rcchar[nextrcline-1] = tmprcchar;
  1469.     rcnums[nextrcline-1] = tmprcnums;
  1470.     softptr[nextrcline-1] = tmpsoftptr;
  1471. #ifdef DEBUGGING
  1472.     ngmax[nextrcline-1] = tmpngmax;
  1473. #endif
  1474. #ifdef CACHEFIRST
  1475.     abs1st[nextrcline-1] = tmpabs1st;
  1476. #endif
  1477.     }
  1478.     if (current_ng > ngx)
  1479.     current_ng--;
  1480.     if (newng < 0) {
  1481.       reask_reloc:
  1482.     unflush_output();        /* disable any ^O in effect */
  1483. #ifdef SERVER
  1484.     if (addnewbydefault) {
  1485.         buf[0] = '$';
  1486.         buf[1] = '\0';
  1487.     } else {
  1488. #endif SERVER
  1489. #ifdef VERBOSE
  1490.     IF(verbose)
  1491.         printf("\nPut newsgroup where? [%s] ", dflt);
  1492.     ELSE
  1493. #endif
  1494. #ifdef TERSE
  1495.         printf("\nPut where? [%s] ", dflt);
  1496. #endif
  1497.     fflush(stdout);
  1498.       reinp_reloc:
  1499.     eat_typeahead();
  1500.     getcmd(buf);
  1501. #ifdef SERVER
  1502.     }
  1503. #endif SERVER
  1504.     if (errno || *buf == '\f') {
  1505.                 /* if return from stop signal */
  1506.         goto reask_reloc;    /* give them a prompt again */
  1507.     }
  1508.     setdef(buf,dflt);
  1509. #ifdef VERIFY
  1510.     printcmd();
  1511. #endif
  1512.     if (*buf == 'h') {
  1513. #ifdef VERBOSE
  1514.         IF(verbose) {
  1515.         printf("\n\n\
  1516. Type ^ to put the newsgroup first (position 0).\n\
  1517. Type $ to put the newsgroup last (position %d).\n", nextrcline-1);
  1518.         printf("\
  1519. Type . to put it before the current newsgroup (position %d).\n", current_ng);
  1520.         printf("\
  1521. Type -newsgroup name to put it before that newsgroup.\n\
  1522. Type +newsgroup name to put it after that newsgroup.\n\
  1523. Type a number between 0 and %d to put it at that position.\n", nextrcline-1);
  1524.         printf("\
  1525. Type L for a listing of newsgroups and their positions.\n") FLUSH;
  1526.         }
  1527.         ELSE
  1528. #endif
  1529. #ifdef TERSE
  1530.         {
  1531.         printf("\n\n\
  1532. ^ to put newsgroup first (pos 0).\n\
  1533. $ to put last (pos %d).\n", nextrcline-1);
  1534.         printf("\
  1535. . to put before current newsgroup (pos %d).\n", current_ng);
  1536.         printf("\
  1537. -newsgroup to put before newsgroup.\n\
  1538. +newsgroup to put after.\n\
  1539. number in 0-%d to put at that pos.\n", nextrcline-1);
  1540.         printf("\
  1541. L for list of .newsrc.\n") FLUSH;
  1542.         }
  1543. #endif
  1544.         goto reask_reloc;
  1545.     }
  1546.     else if (*buf == 'L') {
  1547.         putchar('\n') FLUSH;
  1548.         list_newsgroups();
  1549.         goto reask_reloc;
  1550.     }
  1551.     else if (isdigit(*buf)) {
  1552.         if (!finish_command(TRUE))    /* get rest of command */
  1553.         goto reinp_reloc;
  1554.         newng = atol(buf);
  1555.         if (newng < 0)
  1556.         newng = 0;
  1557.         if (newng >= nextrcline)
  1558.         return nextrcline-1;
  1559.     }
  1560.     else if (*buf == '^') {
  1561.         putchar('\n') FLUSH;
  1562.         newng = 0;
  1563.     }
  1564.     else if (*buf == '$') {
  1565.         putchar('\n') FLUSH;
  1566.         return nextrcline-1;
  1567.     }
  1568.     else if (*buf == '.') {
  1569.         putchar('\n') FLUSH;
  1570.         newng = current_ng;
  1571.     }
  1572.     else if (*buf == '-' || *buf == '+') {
  1573.         if (!finish_command(TRUE))    /* get rest of command */
  1574.         goto reinp_reloc;
  1575.         newng = find_ng(buf+1);
  1576.         if (newng == nextrcline) {
  1577.         fputs("Not found.",stdout) FLUSH;
  1578.         goto reask_reloc;
  1579.         }
  1580.         if (*buf == '+')
  1581.         newng++;
  1582.     }
  1583.     else {
  1584.         printf("\n%s",hforhelp) FLUSH;
  1585.         settle_down();
  1586.         goto reask_reloc;
  1587.     }
  1588.     }
  1589.     if (newng < nextrcline-1) {
  1590. #ifdef HASHNG
  1591.     for (i=0; i<HASHSIZ; i++) {
  1592.         if (hashtbl[i] == nextrcline-1)
  1593.         hashtbl[i] = newng;
  1594.         else if (hashtbl[i] >= newng)
  1595.         ++hashtbl[i];
  1596.     }
  1597. #endif
  1598.     tmprcline = rcline[nextrcline-1];
  1599.     tmptoread = toread[nextrcline-1];
  1600.     tmprcchar = rcchar[nextrcline-1];
  1601.     tmprcnums = rcnums[nextrcline-1];
  1602.     tmpsoftptr = softptr[nextrcline-1];
  1603. #ifdef DEBUGGING
  1604.     tmpngmax = ngmax[nextrcline-1];
  1605. #endif
  1606. #ifdef CACHEFIRST
  1607.     tmpabs1st = abs1st[nextrcline-1];
  1608. #endif
  1609.     for (i=nextrcline-2; i>=newng; i--) {
  1610.         rcline[i+1] = rcline[i];
  1611.         toread[i+1] = toread[i];
  1612.         rcchar[i+1] = rcchar[i];
  1613.         rcnums[i+1] = rcnums[i];
  1614.         softptr[i+1] = softptr[i];
  1615. #ifdef DEBUGGING
  1616.         ngmax[i+1] = ngmax[i];
  1617. #endif
  1618. #ifdef CACHEFIRST
  1619.         abs1st[i+1] = abs1st[i];
  1620. #endif
  1621.     }
  1622.     rcline[newng] = tmprcline;
  1623.     toread[newng] = tmptoread;
  1624.     rcchar[newng] = tmprcchar;
  1625.     rcnums[newng] = tmprcnums;
  1626.     softptr[newng] = tmpsoftptr;
  1627. #ifdef DEBUGGING
  1628.     ngmax[newng] = tmpngmax;
  1629. #endif
  1630. #ifdef CACHEFIRST
  1631.     abs1st[newng] = tmpabs1st;
  1632. #endif
  1633.     }
  1634.     if (current_ng >= newng)
  1635.     current_ng++;
  1636.     return newng;
  1637. }
  1638. #endif
  1639.  
  1640. /* List out the newsrc with annotations */
  1641.  
  1642. void
  1643. list_newsgroups()
  1644. {
  1645.     register NG_NUM i;
  1646.     char tmpbuf[2048];
  1647.     static char *status[] = {"(READ)","(UNSUB)","(BOGUS)","(JUNK)"};
  1648.     int cmd;
  1649.  
  1650.     page_init();
  1651.     print_lines("\
  1652.   #  Status  Newsgroup\n\
  1653. ",STANDOUT);
  1654.     for (i=0; i<nextrcline && !int_count; i++) {
  1655.     if (toread[i] >= 0)
  1656.         set_toread(i);
  1657.     *(rcline[i] + rcnums[i] - 1) = rcchar[i];
  1658.     if (toread[i] > 0)
  1659.         sprintf(tmpbuf,"%3d %6ld   ",i,(long)toread[i]);
  1660.     else
  1661.         sprintf(tmpbuf,"%3d %7s  ",i,status[-toread[i]]);
  1662.     safecpy(tmpbuf+13,rcline[i],2034);
  1663.     *(rcline[i] + rcnums[i] - 1) = '\0';
  1664.     if (cmd = print_lines(tmpbuf,NOMARKING)) {
  1665.         if (cmd > 0)
  1666.         pushchar(cmd);
  1667.         break;
  1668.     }
  1669.     }
  1670.     int_count = 0;
  1671. }
  1672.  
  1673. /* find a newsgroup in .newsrc */
  1674.  
  1675. NG_NUM
  1676. find_ng(ngnam)
  1677. char *ngnam;
  1678. {
  1679.     register NG_NUM ngnum;
  1680. #ifdef HASHNG
  1681.     register int hashix = hash(ngnam);
  1682.     register int incr = 1;
  1683.  
  1684.     while ((ngnum = hashtbl[hashix]) >= 0) {
  1685.     if (strEQ(rcline[ngnum], ngnam) && toread[ngnum] >= TR_UNSUB)
  1686.         return ngnum;
  1687.     hashix = (hashix + incr) % HASHSIZ;
  1688.     incr += 2;            /* offsets from original are in n*2 */
  1689.     }
  1690.     return nextrcline;            /* = notfound */
  1691.  
  1692. #else /* just do linear search */
  1693.  
  1694.     for (ngnum = 0; ngnum < nextrcline; ngnum++) {
  1695.     if (strEQ(rcline[ngnum],ngnam))
  1696.         break;
  1697.     }
  1698.     return ngnum;
  1699. #endif
  1700. }
  1701.  
  1702. void
  1703. cleanup_rc()
  1704. {
  1705.     register NG_NUM ngx;
  1706.     register NG_NUM bogosity = 0;
  1707.  
  1708. #ifdef VERBOSE
  1709.     IF(verbose)
  1710.     fputs("Checking out your .newsrc--hang on a second...\n",stdout)
  1711.       FLUSH;
  1712.     ELSE
  1713. #endif
  1714. #ifdef TERSE
  1715.     fputs("Checking .newsrc--hang on...\n",stdout) FLUSH;
  1716. #endif
  1717.     for (ngx = 0; ngx < nextrcline; ngx++) {
  1718.     if (toread[ngx] >= TR_UNSUB) {
  1719.         set_toread(ngx);        /* this may reset newsgroup */
  1720.                     /* or declare it bogus */
  1721.     }
  1722.     if (toread[ngx] == TR_BOGUS)
  1723.         bogosity++;
  1724.     }
  1725.     for (ngx = nextrcline-1; ngx >= 0 && toread[ngx] == TR_BOGUS; ngx--)
  1726.     bogosity--;            /* discount already moved ones */
  1727.     if (nextrcline > 5 && bogosity > nextrcline / 2) {
  1728.     fputs(
  1729. "It looks like the active file is messed up.  Contact your news administrator,\n\
  1730. ",stdout);
  1731.     fputs(
  1732. "leave the \"bogus\" groups alone, and they may come back to normal.  Maybe.\n\
  1733. ",stdout) FLUSH;
  1734.     }
  1735. #ifdef RELOCATE
  1736.     else if (bogosity) {
  1737. #ifdef VERBOSE
  1738.     IF(verbose)
  1739.         fputs("Moving bogus newsgroups to the end of your .newsrc.\n",
  1740.         stdout) FLUSH;
  1741.     ELSE
  1742. #endif
  1743. #ifdef TERSE
  1744.         fputs("Moving boguses to the end.\n",stdout) FLUSH;
  1745. #endif
  1746.     for (; ngx >= 0; ngx--) {
  1747.         if (toread[ngx] == TR_BOGUS)
  1748.         relocate_newsgroup(ngx,nextrcline-1);
  1749.     }
  1750. #ifdef DELBOGUS
  1751. reask_bogus:
  1752.     in_char("Delete bogus newsgroups? [ny] ", 'D');
  1753.     putchar('\n') FLUSH;
  1754.     setdef(buf,"n");
  1755. #ifdef VERIFY
  1756.     printcmd();
  1757. #endif
  1758.     if (*buf == 'h') {
  1759. #ifdef VERBOSE
  1760.         IF(verbose)
  1761.         fputs("\
  1762. Type y to delete bogus newsgroups.\n\
  1763. Type n or SP to leave them at the end in case they return.\n\
  1764. ",stdout) FLUSH;
  1765.         ELSE
  1766. #endif
  1767. #ifdef TERSE
  1768.         fputs("y to delete, n to keep\n",stdout) FLUSH;
  1769. #endif
  1770.         goto reask_bogus;
  1771.     }
  1772.     else if (*buf == 'n' || *buf == 'q')
  1773.         ;
  1774.     else if (*buf == 'y') {
  1775.         while (toread[nextrcline-1] == TR_BOGUS && nextrcline > 0)
  1776.         --nextrcline;        /* real tough, huh? */
  1777.     }
  1778.     else {
  1779.         fputs(hforhelp,stdout) FLUSH;
  1780.         settle_down();
  1781.         goto reask_bogus;
  1782.     }
  1783. #endif
  1784.     }
  1785. #else
  1786. #ifdef VERBOSE
  1787.     IF(verbose)
  1788.     fputs("You should edit bogus newsgroups out of your .newsrc.\n",
  1789.         stdout) FLUSH;
  1790.     ELSE
  1791. #endif
  1792. #ifdef TERSE
  1793.     fputs("Edit boguses from .newsrc.\n",stdout) FLUSH;
  1794. #endif
  1795. #endif
  1796.     paranoid = FALSE;
  1797. }
  1798.  
  1799. #ifdef HASHNG
  1800. /* make an entry in the hash table for the current newsgroup */
  1801.  
  1802. void
  1803. sethash(thisng)
  1804. NG_NUM thisng;
  1805. {
  1806.     register int hashix = hash(rcline[thisng]);
  1807.     register int incr = 1;
  1808. #ifdef DEBUGGING
  1809.     static int hashhits = 0, hashtries = 0;
  1810. #endif
  1811.  
  1812. #ifdef DEBUGGING
  1813.     hashtries++;
  1814. #endif
  1815.     while (hashtbl[hashix] >= 0) {
  1816. #ifdef DEBUGGING
  1817.     hashhits++;
  1818.     if (debug & DEB_HASH) {
  1819.         printf("  Hash hits: %d / %d\n",hashhits, hashtries) FLUSH;
  1820.     }
  1821.     hashtries++;
  1822. #endif
  1823.     hashix = (hashix + incr) % HASHSIZ;
  1824.     incr += 2;            /* offsets from original are in n*2 */
  1825.     }
  1826.     hashtbl[hashix] = thisng;
  1827. }
  1828.  
  1829. short prime[] = {1,2,-3,-5,7,11,-13,-17,19,23,-29,-31,37,41,-43,-47,53,57,-59,
  1830.     -61,67,71,-73,-79,83,89,-97,-101,1,1,1,1,1,1,1,1,1,1,1,1};
  1831.  
  1832. int
  1833. hash(ngnam)
  1834. register char *ngnam;
  1835. {
  1836.     register int i = 0;
  1837.     register int ch;
  1838.     register int sum = 0;
  1839. #ifdef DEBUGGING
  1840.     char *ngn = ngnam;
  1841. #endif
  1842.  
  1843.     while (ch = *ngnam++) {
  1844.     sum += (ch + i) * prime[i];   /* gives ~ 10% hits at 25% full */
  1845.     i++;
  1846.     }
  1847. #ifdef DEBUGGING
  1848.     if (debug & DEB_HASH)
  1849.     printf("hash(%s) => %d => %d\n",ngn, sum, (sum<0?-sum:sum)%HASHSIZ)
  1850.       FLUSH;
  1851. #endif
  1852.     if (sum < 0)
  1853.     sum = -sum;
  1854.     return sum % HASHSIZ;
  1855. }
  1856.  
  1857. #endif
  1858.  
  1859. void
  1860. newsrc_check()
  1861. {
  1862.     rcfp = fopen(rcname,"r");        /* open it */
  1863.     if (rcfp == Nullfp) {            /* not there? */
  1864. #ifdef VERBOSE
  1865.     IF(verbose)
  1866.         fputs("\
  1867. Trying to set up a .newsrc file--running newsetup...\n\n\
  1868. ",stdout) FLUSH;
  1869.     ELSE
  1870. #endif
  1871. #ifdef TERSE
  1872.         fputs("Setting up .newsrc...\n",stdout) FLUSH;
  1873. #endif
  1874.     if (doshell(sh,filexp(NEWSETUP)) ||
  1875.         (rcfp = fopen(rcname,"r")) == Nullfp) {
  1876. #ifdef VERBOSE
  1877.         IF(verbose)
  1878.         fputs("\
  1879. Can't create a .newsrc--you must do it yourself.\n\
  1880. ",stdout) FLUSH;
  1881.         ELSE
  1882. #endif
  1883. #ifdef TERSE
  1884.         fputs("(Fatal)\n",stdout) FLUSH;
  1885. #endif
  1886.         finalize(1);
  1887.     }
  1888.     }
  1889.     else {
  1890.     UNLINK(rcbname);        /* unlink backup file name */
  1891.     link(rcname,rcbname);        /* and backup current name */
  1892.     }
  1893. }
  1894.  
  1895. /* write out the (presumably) revised .newsrc */
  1896.  
  1897. void
  1898. write_rc()
  1899. {
  1900.     register NG_NUM tmpng;
  1901.     register char *delim;
  1902.  
  1903.     rcfp = fopen(rctname, "w");        /* open .newsrc */
  1904.     if (rcfp == Nullfp) {
  1905.     printf("Can't recreate .newsrc\n") FLUSH;
  1906.     finalize(1);
  1907.     }
  1908.  
  1909.     /* write out each line*/
  1910.  
  1911.     for (tmpng = 0; tmpng < nextrcline; tmpng++) {
  1912.     if (rcnums[tmpng]) {
  1913.         delim = rcline[tmpng] + rcnums[tmpng] - 1;
  1914.         *delim = rcchar[tmpng];
  1915.     }
  1916.     else
  1917.         delim = Nullch;
  1918. #ifdef DEBUGGING
  1919.     if (debug & DEB_NEWSRC_LINE)
  1920.         printf("%s\n",rcline[tmpng]) FLUSH;
  1921. #endif
  1922.     fprintf(rcfp,"%s\n",rcline[tmpng]);
  1923.     if (delim)
  1924.         *delim = '\0';        /* might still need this line */
  1925.     }
  1926.  
  1927.     fclose(rcfp);            /* close .newsrc */
  1928.     UNLINK(rcname);
  1929.     link(rctname,rcname);
  1930.     UNLINK(rctname);
  1931.  
  1932.     if (writesoft) {
  1933.     tmpfp = fopen(filexp(softname), "w");    /* open .rnsoft */
  1934.     if (tmpfp == Nullfp) {
  1935.         printf(cantcreate,filexp(softname)) FLUSH;
  1936.         return;
  1937.     }
  1938.     for (tmpng = 0; tmpng < nextrcline; tmpng++) {
  1939.         fprintf(tmpfp,"%ld\n",(long)softptr[tmpng]);
  1940.     }
  1941.     fclose(tmpfp);
  1942.     }
  1943. }
  1944.  
  1945. void
  1946. get_old_rc()
  1947. {
  1948.     UNLINK(rctname);
  1949.     link(rcname,rctname);
  1950.     UNLINK(rcname);
  1951.     link(rcbname,rcname);
  1952.     UNLINK(rcbname);
  1953. }
  1954. !STUFFY!FUNK!
  1955. echo Extracting bits.c
  1956. cat >bits.c <<'!STUFFY!FUNK!'
  1957. /* $Header: bits.c,v 4.3.2.3 89/11/28 01:52:02 sob Locked $
  1958.  *
  1959.  * $Log:    bits.c,v $
  1960.  * Revision 4.3.2.3  89/11/28  01:52:02  sob
  1961.  * Removed some lint.
  1962.  * 
  1963.  * Revision 4.3.2.2  89/11/27  01:30:04  sob
  1964.  * Altered NNTP code per ideas suggested by Bela Lubkin
  1965.  * <filbo@gorn.santa-cruz.ca.us>
  1966.  * 
  1967.  * Revision 4.3.1.4  86/10/31  15:23:53  lwall
  1968.  * Separated firstart into two variables so KILL on new articles won't
  1969.  * accidentally mark articles read.
  1970.  * 
  1971.  * Revision 4.3.1.3  86/09/09  16:01:43  lwall
  1972.  * Fixed 'n more articles' bug.
  1973.  * 
  1974.  * Revision 4.3.1.2  86/07/24  14:40:23  lwall
  1975.  * Gets host name from path instead of relay-version for news 2.10.3.
  1976.  *
  1977.  * Revision 4.3.1.1  85/05/10  11:31:41  lwall
  1978.  * Branch for patches.
  1979.  *
  1980.  * Revision 4.3  85/05/01  11:36:15  lwall
  1981.  * Baseline for release with 4.3bsd.
  1982.  * 
  1983.  */
  1984.  
  1985. #include "EXTERN.h"
  1986. #include "common.h"
  1987. #include "rcstuff.h"
  1988. #include "head.h"
  1989. #include "util.h"
  1990. #include "final.h"
  1991. #include "rn.h"
  1992. #include "cheat.h"
  1993. #include "ng.h"
  1994. #include "artio.h"
  1995. #include "intrp.h"
  1996. #include "ngdata.h"
  1997. #include "rcln.h"
  1998. #include "kfile.h"
  1999. #include "INTERN.h"
  2000. #include "bits.h"
  2001.  
  2002. #ifdef DBM
  2003. #    ifdef NULL
  2004. #    undef NULL
  2005. #    endif NULL
  2006. #    include <dbm.h>
  2007. #endif DBM
  2008. MEM_SIZE ctlsize;            /* size of bitmap in bytes */
  2009.  
  2010. void
  2011. bits_init()
  2012. {
  2013. #ifdef DELAYMARK
  2014.     dmname = savestr(filexp(RNDELNAME));
  2015. #else
  2016.     ;
  2017. #endif
  2018. }
  2019.  
  2020. /* checkpoint the .newsrc */
  2021.  
  2022. void
  2023. checkpoint_rc()
  2024. {
  2025. #ifdef DEBUGGING
  2026.     if (debug & DEB_CHECKPOINTING) {
  2027.     fputs("(ckpt)",stdout);
  2028.     fflush(stdout);
  2029.     }
  2030. #endif
  2031.     if (doing_ng)
  2032.     restore_ng();            /* do not restore M articles */
  2033.     if (rc_changed)
  2034.     write_rc();
  2035. #ifdef DEBUGGING
  2036.     if (debug & DEB_CHECKPOINTING) {
  2037.     fputs("(done)",stdout);
  2038.     fflush(stdout);
  2039.     }
  2040. #endif
  2041. }
  2042.  
  2043. /* reconstruct the .newsrc line in a human readable form */
  2044.  
  2045. void
  2046. restore_ng()
  2047. {
  2048.     register char *s, *mybuf = buf;
  2049.     register ART_NUM i;
  2050.     ART_NUM count=0;
  2051.     int safelen = LBUFLEN - 16;
  2052.  
  2053.     strcpy(buf,rcline[ng]);        /* start with the newsgroup name */
  2054.     s = buf + rcnums[ng] - 1;        /* use s for buffer pointer */
  2055.     *s++ = rcchar[ng];            /* put the requisite : or !*/
  2056.     *s++ = ' ';                /* put the not-so-requisite space */
  2057.     for (i=1; i<=lastart; i++) {    /* for each article in newsgroup */
  2058.     if (s-mybuf > safelen) {    /* running out of room? */
  2059.         safelen *= 2;
  2060.         if (mybuf == buf) {        /* currently static? */
  2061.         *s = '\0';
  2062.         mybuf = safemalloc((MEM_SIZE)safelen + 16);
  2063.         strcpy(mybuf,buf);    /* so we must copy it */
  2064.         s = mybuf + (s-buf);
  2065.                     /* fix the pointer, too */
  2066.         }
  2067.         else {            /* just grow in place, if possible */
  2068.         char *newbuf;
  2069.  
  2070.         newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16);
  2071.         s = newbuf + (s-mybuf);
  2072.         mybuf = newbuf;
  2073.         }
  2074.     }
  2075.     if (!was_read(i))        /* still unread? */
  2076.         count++;            /* then count it */
  2077.     else {                /* article was read */
  2078.         ART_NUM oldi;
  2079.  
  2080.         sprintf(s,"%ld",(long)i);    /* put out the min of the range */
  2081.         s += strlen(s);        /* keeping house */
  2082.         oldi = i;            /* remember this spot */
  2083.         do i++; while (i <= lastart && was_read(i));
  2084.                     /* find 1st unread article or end */
  2085.         i--;            /* backup to last read article */
  2086.         if (i > oldi) {        /* range of more than 1? */
  2087.         sprintf(s,"-%ld,",(long)i);
  2088.                     /* then it out as a range */
  2089.         s += strlen(s);        /* and housekeep */
  2090.         }
  2091.         else
  2092.         *s++ = ',';        /* otherwise, just a comma will do */
  2093.     }
  2094.     }
  2095.     if (*(s-1) == ',')            /* is there a final ','? */
  2096.     s--;                /* take it back */
  2097.     *s++ = '\0';            /* and terminate string */
  2098. #ifdef DEBUGGING
  2099.     if (debug & DEB_NEWSRC_LINE && !panic) {
  2100.     printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]) FLUSH;
  2101.     printf("%s\n",mybuf) FLUSH;
  2102.     }
  2103. #endif
  2104.     free(rcline[ng]);            /* return old rc line */
  2105.     if (mybuf == buf) {
  2106.     rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1);
  2107.                     /* grab a new rc line */
  2108.     strcpy(rcline[ng], buf);    /* and load it */
  2109.     }
  2110.     else {
  2111.     mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1);
  2112.                     /* be nice to the heap */
  2113.     rcline[ng] = mybuf;
  2114.     }
  2115.     *(rcline[ng] + rcnums[ng] - 1) = '\0';
  2116.     if (rcchar[ng] == NEGCHAR) {    /* did they unsubscribe? */
  2117.     printf(unsubto,ngname) FLUSH;
  2118.     toread[ng] = TR_UNSUB;        /* make line invisible */
  2119.     }
  2120.     else
  2121.     /*NOSTRICT*/
  2122.     toread[ng] = (ART_UNREAD)count;        /* remember how many unread there are */
  2123. }
  2124.  
  2125. /* mark an article unread, keeping track of toread[] */
  2126.  
  2127. void
  2128. onemore(artnum)
  2129. ART_NUM artnum;
  2130. {
  2131. #ifdef DEBUGGING
  2132.     if (debug && artnum < firstbit) {
  2133.     printf("onemore: %d < %d\n",artnum,firstbit) FLUSH;
  2134.     return;
  2135.     }
  2136. #endif
  2137.     if (ctl_read(artnum)) {
  2138.     ctl_clear(artnum);
  2139.     ++toread[ng];
  2140.     }
  2141. }
  2142.  
  2143. /* mark an article read, keeping track of toread[] */
  2144.  
  2145. void
  2146. oneless(artnum)
  2147. ART_NUM artnum;
  2148. {
  2149. #ifdef DEBUGGING
  2150.     if (debug && artnum < firstbit) {
  2151.     printf("oneless: %d < %d\n",artnum,firstbit) FLUSH;
  2152.     return;
  2153.     }
  2154. #endif
  2155.     if (!ctl_read(artnum)) {
  2156.     ctl_set(artnum);
  2157.     if (toread[ng] > TR_NONE)
  2158.         --toread[ng];
  2159.     }
  2160. }
  2161.  
  2162. /* mark an article as unread, making sure that firstbit is properly handled */
  2163. /* cross-references are left as read in the other newsgroups */
  2164.  
  2165. void
  2166. unmark_as_read(artnum)
  2167. ART_NUM artnum;
  2168. {
  2169.     check_first(artnum);
  2170.     onemore(artnum);
  2171. #ifdef MCHASE
  2172.     if (!parse_maybe(artnum))
  2173.     chase_xrefs(artnum,FALSE);
  2174. #endif
  2175. }
  2176.  
  2177. #ifdef DELAYMARK
  2178. /* temporarily mark article as read.  When newsgroup is exited, articles */
  2179. /* will be marked as unread.  Called via M command */
  2180.  
  2181. void
  2182. delay_unmark(artnum)
  2183. ART_NUM artnum;
  2184. {
  2185.     if (dmfp == Nullfp) {
  2186.     dmfp = fopen(dmname,"w");
  2187.     if (dmfp == Nullfp) {
  2188.         printf(cantcreate,dmname) FLUSH;
  2189.         sig_catcher(0);
  2190.     }
  2191.     }
  2192.     oneless(artnum);            /* set the correct bit */
  2193.     dmcount++;
  2194.     fprintf(dmfp,"%ld\n",(long)artnum);
  2195. }
  2196. #endif
  2197.  
  2198. /* mark article as read.  If article is cross referenced to other */
  2199. /* newsgroups, mark them read there also. */
  2200.  
  2201. void
  2202. mark_as_read(artnum)
  2203. ART_NUM artnum;
  2204. {
  2205.     oneless(artnum);            /* set the correct bit */
  2206.     checkcount++;            /* get more worried about crashes */
  2207.     chase_xrefs(artnum,TRUE);
  2208. }
  2209.  
  2210. /* make sure we have bits set correctly down to firstbit */
  2211.  
  2212. void
  2213. check_first(min)
  2214. ART_NUM min;
  2215. {
  2216.     register ART_NUM i = firstbit;
  2217.  
  2218.     if (min < absfirst)
  2219.     min = absfirst;
  2220.     if (min < i) {
  2221.     for (i--; i>=min; i--)
  2222.         ctl_set(i);        /* mark as read */
  2223.     firstart = firstbit = min;
  2224.     }
  2225. }
  2226.  
  2227. /* bring back articles marked with M */
  2228.  
  2229. #ifdef DELAYMARK
  2230. void
  2231. yankback()
  2232. {
  2233.     register ART_NUM anum;
  2234.  
  2235.     if (dmfp) {            /* delayed unmarks pending? */
  2236. #ifdef VERBOSE
  2237.     printf("\nReturning %ld Marked article%s...\n",(long)dmcount,
  2238.         dmcount == 1 ? nullstr : "s") FLUSH;
  2239. #endif
  2240.     fclose(dmfp);
  2241.     if (dmfp = fopen(dmname,"r")) {
  2242.         while (fgets(buf,sizeof buf,dmfp) != Nullch) {
  2243.         anum = (ART_NUM)atol(buf);
  2244.         /*NOSTRICT*/
  2245.         onemore(anum);             /* then unmark them */
  2246. #ifdef MCHASE
  2247.         chase_xrefs(anum,FALSE);
  2248. #endif
  2249.         }
  2250.         fclose(dmfp);
  2251.         dmfp = Nullfp;
  2252.         UNLINK(dmname);        /* and be tidy */
  2253.     }
  2254.     else {
  2255.         printf(cantopen,dmname) FLUSH;
  2256.         sig_catcher(0);
  2257.     }
  2258.     }
  2259.     dmcount = 0;
  2260. }
  2261. #endif
  2262.     
  2263. /* run down xref list and mark as read or unread */
  2264.  
  2265. int
  2266. chase_xrefs(artnum,markread)
  2267. ART_NUM artnum;
  2268. int markread;
  2269. {
  2270. #ifdef ASYNC_PARSE
  2271.     if (parse_maybe(artnum))        /* make sure we have right header */
  2272.     return -1;
  2273. #endif
  2274. #ifdef DBM
  2275.     {
  2276.     datum lhs, rhs;
  2277.     datum fetch();
  2278.     register char *idp;
  2279.     char *ident_buf;
  2280.     static FILE * hist_file = Nullfp;
  2281. #else
  2282.     if (
  2283. #ifdef DEBUGGING
  2284.     debug & DEB_FEED_XREF ||
  2285. #endif
  2286.     htype[XREF_LINE].ht_minpos >= 0) {
  2287.                     /* are there article# xrefs? */
  2288. #endif DBM
  2289.     char *xref_buf, *curxref;
  2290.     register char *xartnum;
  2291.     char *rver_buf = Nullch;
  2292.     static char *inews_site = Nullch;
  2293.     register ART_NUM x;
  2294.     char tmpbuf[128];
  2295.  
  2296. #ifdef DBM
  2297.     rver_buf = fetchlines(artnum,NGS_LINE);
  2298.                     /* get Newsgroups */
  2299.     if (!index(rver_buf,','))    /* if no comma, no Xref! */
  2300.         return 0;
  2301.     if (hist_file == Nullfp) {    /* Init. file accesses */
  2302. #ifdef DEBUGGING
  2303.         if (debug)
  2304.         printf ("chase_xref: opening files\n");
  2305. #endif
  2306.         dbminit(filexp(ARTFILE));
  2307.         if ((hist_file = fopen (filexp(ARTFILE), "r")) == Nullfp)
  2308.         return 0;
  2309.     }
  2310.     xref_buf = safemalloc((MEM_SIZE)BUFSIZ);
  2311.     ident_buf = fetchlines(artnum,MESSID_LINE);
  2312.                     /* get Message-ID */
  2313. #ifdef DEBUGGING
  2314.     if (debug)
  2315.         printf ("chase_xref: Message-ID: %s\n", ident_buf);
  2316. #endif
  2317.     idp = ident_buf;
  2318.     while (*++idp)            /* make message-id case insensitive */
  2319.         if (isupper(*idp))
  2320.             *idp = tolower (*idp);
  2321.     lhs.dptr = ident_buf;        /* look up article by id */
  2322.     lhs.dsize = strlen(lhs.dptr) + 1;
  2323.     rhs = fetch(lhs);        /* fetch the record */
  2324.     if (rhs.dptr == NULL)        /* if null, nothing there */
  2325.         goto wild_goose;
  2326.     fseek (hist_file, *((long *)rhs.dptr), 0);
  2327.                     /* datum returned is position in hist file */
  2328.     fgets (xref_buf, BUFSIZ, hist_file);
  2329. #ifdef DEBUGGING
  2330.     if (debug)
  2331.         printf ("Xref from history: %s\n", xref_buf);
  2332. #endif
  2333.     curxref = cpytill(tmpbuf, xref_buf, '\t') + 1;
  2334.     curxref = cpytill(tmpbuf, curxref, '\t') + 1;
  2335. #ifdef DEBUGGING
  2336.     if (debug)
  2337.         printf ("chase_xref: curxref: %s\n", curxref);
  2338. #endif
  2339. #else !DBM
  2340. #ifdef DEBUGGING
  2341.     if (htype[XREF_LINE].ht_minpos >= 0)
  2342. #endif
  2343.         xref_buf = fetchlines(artnum,XREF_LINE);
  2344.                     /* get xrefs list */
  2345. #ifdef DEBUGGING
  2346.     else {
  2347.         xref_buf = safemalloc((MEM_SIZE)100);
  2348.         printf("Give Xref: ") FLUSH;
  2349.         gets(xref_buf);
  2350.     }
  2351. #endif
  2352. #ifdef DEBUGGING
  2353.     if (debug & DEB_XREF_MARKER)
  2354.         printf("Xref: %s\n",xref_buf) FLUSH;
  2355. #endif
  2356.     curxref = cpytill(tmpbuf,xref_buf,' ') + 1;
  2357.  
  2358.     /* Make sure site name on Xref matches what inews thinks site is.
  2359.      * Check first against last inews_site.  If it matches, fine.
  2360.      * If not, fetch inews_site from current Relay-Version line and
  2361.      * check again.  This is so that if the new administrator decides
  2362.      * to change the system name as known to inews, rn will still do
  2363.      * Xrefs correctly--each article need only match itself to be valid.
  2364.      */ 
  2365.     if (inews_site == Nullch || strNE(tmpbuf,inews_site)) {
  2366. #ifndef NORELAY
  2367.         char *t;
  2368. #endif
  2369.         if (inews_site != Nullch)
  2370.         free(inews_site);
  2371. #ifndef NORELAY
  2372.         rver_buf = fetchlines(artnum,RVER_LINE);
  2373.         if ((t = instr(rver_buf,"; site ")) == Nullch)
  2374. #else NORELAY
  2375.           /* In version 2.10.3 of news or afterwards, the Relay-Version
  2376.            * and Posting-Version header lines have been removed.  For
  2377.            * the code below to work as intended, I have modified it to
  2378.            * extract the first component of the Path header line.  This
  2379.            * should give the same effect as did the old code with respect
  2380.            * to the use of the Relay-Version site name.
  2381.            */
  2382.           rver_buf = fetchlines(artnum,PATH_LINE);
  2383.           if (instr(rver_buf,"!") == Nullch)
  2384. #endif NORELAY
  2385.         inews_site = savestr(nullstr);
  2386.         else {
  2387.         char new_site[128];
  2388.  
  2389. #ifndef NORELAY
  2390.         cpytill(new_site,t + 7,'.');
  2391. #else NORELAY
  2392.               cpytill(new_site,rver_buf,'!');
  2393. #endif NORELAY
  2394.         inews_site = savestr(new_site);
  2395.         }
  2396.         if (strNE(tmpbuf,inews_site)) {
  2397. #ifdef DEBUGGING
  2398.         if (debug)
  2399.             printf("Xref not from %s--ignoring\n",inews_site) FLUSH;
  2400. #endif
  2401.         goto wild_goose;
  2402.         }
  2403.     }
  2404. #endif DBM
  2405.     while (*curxref) {
  2406.                     /* for each newsgroup */
  2407.         curxref = cpytill(tmpbuf,curxref,' ');
  2408. #ifdef DBM
  2409.         xartnum = index(tmpbuf,'/');
  2410. #else
  2411.         xartnum = index(tmpbuf,':');
  2412. #endif DBM
  2413.         if (!xartnum)        /* probably an old-style Xref */
  2414.         break;
  2415.         *xartnum++ = '\0';
  2416.         if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */
  2417.         x = atol(xartnum);
  2418.         if (x)
  2419.             if (markread) {
  2420.             if (addartnum(x,tmpbuf))
  2421.                 goto wild_goose;
  2422.             }
  2423. #ifdef MCHASE
  2424.             else
  2425.             subartnum(x,tmpbuf);
  2426. #endif
  2427.         }
  2428.         while (*curxref && isspace(*curxref))
  2429.         curxref++;
  2430.     }
  2431.       wild_goose:
  2432.     free(xref_buf);
  2433. #ifdef DBM
  2434.     free(ident_buf);
  2435. #endif DBM
  2436.     if (rver_buf != Nullch)
  2437.         free(rver_buf);
  2438.     }
  2439.     return 0;
  2440. }
  2441.  
  2442. int
  2443. initctl()
  2444. {
  2445.     char *mybuf = buf;            /* place to decode rc line */
  2446.     register char *s, *c, *h;
  2447.     register long i;
  2448.     register ART_NUM unread;
  2449.     
  2450. #ifdef DELAYMARK
  2451.     dmcount = 0;
  2452. #endif
  2453.     if ((lastart = getngsize(ng)) < 0)    /* this cannot happen (laugh here) */
  2454.     return -1;
  2455.  
  2456.     absfirst = getabsfirst(ng,lastart);    /* remember first existing article */
  2457.     if (!absfirst)            /* no articles at all? */
  2458.     absfirst = 1;            /* pretend there is one */
  2459. #ifndef lint
  2460.     ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20);
  2461. #endif lint
  2462.     ctlarea = safemalloc(ctlsize);    /* allocate control area */
  2463.  
  2464.     /* now modify ctlarea to reflect what has already been read */
  2465.  
  2466.     for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ;
  2467.                     /* find numbers in rc line */
  2468.     i = strlen(s);
  2469. #ifndef lint
  2470.     if (i >= LBUFLEN-2)            /* bigger than buf? */
  2471.     mybuf = safemalloc((MEM_SIZE)(i+2));
  2472. #endif lint
  2473.     strcpy(mybuf,s);            /* make scratch copy of line */
  2474.     mybuf[i++] = ',';            /* put extra comma on the end */
  2475.     mybuf[i] = '\0';
  2476.     s = mybuf;                /* initialize the for loop below */
  2477.     if (strnEQ(s,"1-",2)) {        /* can we save some time here? */
  2478.     firstbit = atol(s+2)+1;        /* ignore first range thusly */
  2479.     s=index(s,',') + 1;
  2480.     }
  2481.     else
  2482.     firstbit = 1;            /* all the bits are valid for now */
  2483.     if (absfirst > firstbit) {        /* do we know already? */
  2484.     firstbit = absfirst;        /* no point calling getngmin again */
  2485.     }
  2486.     else if (artopen(firstbit) == Nullfp) {
  2487.                     /* first unread article missing? */
  2488.     i = getngmin(".",firstbit);    /* see if expire has been busy */
  2489.     if (i) {            /* avoid a bunch of extra opens */
  2490.         firstbit = i;
  2491.     }
  2492.     }
  2493.     firstart = firstbit;        /* firstart > firstbit in KILL */
  2494. #ifdef PENDING
  2495. #   ifdef CACHESUBJ
  2496.     subj_to_get = firstbit;
  2497. #   endif
  2498. #endif
  2499.     unread = lastart - firstbit + 1;    /* assume this range unread */
  2500.     for (i=OFFSET(firstbit)/BITSPERBYTE; i<ctlsize; i++)
  2501.     ctlarea[i] = 0;            /* assume unread */
  2502. #ifdef DEBUGGING
  2503.     if (debug & DEB_CTLAREA_BITMAP) {
  2504.     printf("\n%s\n",mybuf) FLUSH;
  2505.     for (i=1; i <= lastart; i++)
  2506.         if (! was_read(i))
  2507.         printf("%ld ",(long)i) FLUSH;
  2508.     }
  2509. #endif
  2510.     for ( ; (c = index(s,',')) != Nullch; s = ++c) {
  2511.                     /* for each range */
  2512.     ART_NUM min, max;
  2513.  
  2514.     *c = '\0';            /* do not let index see past comma */
  2515.     if ((h = index(s,'-')) != Nullch) {    /* is there a -? */
  2516.         min = atol(s);
  2517.         max = atol(h+1);
  2518.         if (min < firstbit)        /* make sure range is in range */
  2519.         min = firstbit;
  2520.         if (max > lastart)
  2521.         max = lastart;
  2522.         if (min <= max)        /* non-null range? */
  2523.         unread -= max - min + 1;/* adjust unread count */
  2524.         for (i=min; i<=max; i++)    /* for all articles in range */
  2525.         ctl_set(i);        /* mark them read */
  2526.     }
  2527.     else if ((i = atol(s)) >= firstbit && i <= lastart) {
  2528.                     /* is single number reasonable? */
  2529.         ctl_set(i);            /* mark it read */
  2530.         unread--;            /* decrement articles to read */
  2531.     }
  2532. #ifdef DEBUGGING
  2533.     if (debug & DEB_CTLAREA_BITMAP) {
  2534.         printf("\n%s\n",s) FLUSH;
  2535.         for (i=1; i <= lastart; i++)
  2536.         if (! was_read(i))
  2537.             printf("%ld ",(long)i) FLUSH;
  2538.     }
  2539. #endif
  2540.     }
  2541. #ifdef DEBUGGING
  2542.     if (debug & DEB_CTLAREA_BITMAP) {
  2543.     fputs("\n(hit CR)",stdout) FLUSH;
  2544.     gets(cmd_buf);
  2545.     }
  2546. #endif
  2547.     if (mybuf != buf)
  2548.     free(mybuf);
  2549.     toread[ng] = unread;
  2550.     return 0;
  2551. }
  2552.  
  2553. void
  2554. grow_ctl()
  2555. {
  2556.     ART_NUM newlast;
  2557.     ART_NUM tmpfirst;
  2558.     MEM_SIZE newsize;
  2559.     register ART_NUM i;
  2560.  
  2561.     forcegrow = FALSE;
  2562.     newlast = getngsize(ng);
  2563.     if (newlast > lastart) {
  2564.     ART_NUM tmpart = art;
  2565. #ifndef lint
  2566.     newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2);
  2567. #else
  2568.     newsize = Null(MEM_SIZE);
  2569. #endif lint
  2570.     if (newsize > ctlsize) {
  2571.         newsize += 20;
  2572.         ctlarea = saferealloc(ctlarea,newsize);
  2573.         ctlsize = newsize;
  2574.     }
  2575.     toread[ng] += (ART_UNREAD)(newlast-lastart);
  2576.     for (i=lastart+1; i<=newlast; i++)
  2577.         ctl_clear(i);    /* these articles are unread */
  2578. #ifdef CACHESUBJ
  2579.     if (subj_list != Null(char**)) {
  2580. #ifndef lint
  2581.         subj_list = (char**)saferealloc((char*)subj_list,
  2582.           (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) );
  2583. #endif lint
  2584.         for (i=lastart+1; i<=newlast; i++)
  2585.         subj_list[OFFSET(i)] = Nullch;
  2586.     }
  2587. #endif
  2588.     tmpfirst = lastart+1;
  2589.     lastart = newlast;
  2590. #ifdef KILLFILES
  2591. #ifdef VERBOSE
  2592.     IF(verbose)
  2593.         sprintf(buf,
  2594.         "%ld more article%s arrived--looking for more to kill...\n\n",
  2595.         (long)(lastart - tmpfirst + 1),
  2596.         (lastart > tmpfirst ? "s have" : " has" ) );
  2597.     ELSE            /* my, my, how clever we are */
  2598. #endif
  2599. #ifdef TERSE
  2600.         strcpy(buf, "More news--killing...\n\n");
  2601. #endif
  2602.     kill_unwanted(tmpfirst,buf,TRUE);
  2603. #endif
  2604.     art = tmpart;
  2605.     }
  2606. }
  2607.  
  2608. !STUFFY!FUNK!
  2609. echo Extracting INIT
  2610. cat >INIT <<'!STUFFY!FUNK!'
  2611. -ESAMPLE="sample"
  2612. !STUFFY!FUNK!
  2613. echo ""
  2614. echo "End of kit 5 (of 9)"
  2615. cat /dev/null >kit5isdone
  2616. config=true
  2617. for iskit in 1 2 3 4 5 6 7 8 9 ; do
  2618.     if test -f kit${iskit}isdone; then
  2619.     echo "You have run kit ${iskit}."
  2620.     else
  2621.     echo "You still need to run kit ${iskit}."
  2622.     config=false
  2623.     fi
  2624. done
  2625. case $config in
  2626.     true)
  2627.     echo "You have run all your kits.  Please read README and then type Configure."
  2628.     chmod 755 Configure
  2629.     ;;
  2630. esac
  2631. : I do not append .signature, but someone might mail this.
  2632. exit
  2633.