home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume23 / trn / part02 / bits.c < prev    next >
C/C++ Source or Header  |  1991-08-22  |  18KB  |  724 lines

  1. /* $Header: bits.c,v 4.3.3.2 91/01/16 02:29:48 davison Trn $
  2.  *
  3.  * $Log:    bits.c,v $
  4.  * Revision 4.3.3.2  91/01/16  02:29:48  davison
  5.  * Integrated rn patches 48-54.
  6.  * 
  7.  * Revision 4.3.3.1  90/06/20  22:36:24  davison
  8.  * Initial Trn Release
  9.  * 
  10.  * Revision 4.3.2.5  90/11/22  13:47:16  sob
  11.  * Altered #endifs to make System V compiliers happy.
  12.  * 
  13.  * Revision 4.3.2.4  90/10/06  11:55:33  sob
  14.  * Added fix for DBM support.
  15.  * 
  16.  * Revision 4.3.2.3  89/11/28  01:52:02  sob
  17.  * Removed some lint.
  18.  * 
  19.  * Revision 4.3.2.2  89/11/27  01:30:04  sob
  20.  * Altered NNTP code per ideas suggested by Bela Lubkin
  21.  * <filbo@gorn.santa-cruz.ca.us>
  22.  * 
  23.  * Revision 4.3.1.4  86/10/31  15:23:53  lwall
  24.  * Separated firstart into two variables so KILL on new articles won't
  25.  * accidentally mark articles read.
  26.  * 
  27.  * Revision 4.3.1.3  86/09/09  16:01:43  lwall
  28.  * Fixed 'n more articles' bug.
  29.  * 
  30.  * Revision 4.3.1.2  86/07/24  14:40:23  lwall
  31.  * Gets host name from path instead of relay-version for news 2.10.3.
  32.  *
  33.  * Revision 4.3.1.1  85/05/10  11:31:41  lwall
  34.  * Branch for patches.
  35.  *
  36.  * Revision 4.3  85/05/01  11:36:15  lwall
  37.  * Baseline for release with 4.3bsd.
  38.  * 
  39.  */
  40.  
  41. #include "EXTERN.h"
  42. #include "common.h"
  43. #include "rcstuff.h"
  44. #include "head.h"
  45. #include "util.h"
  46. #include "final.h"
  47. #include "rn.h"
  48. #include "cheat.h"
  49. #include "ng.h"
  50. #include "artio.h"
  51. #include "intrp.h"
  52. #include "ngdata.h"
  53. #include "rcln.h"
  54. #include "kfile.h"
  55. #ifdef USETHREADS
  56. #include "rthreads.h"
  57. #endif
  58. #include "INTERN.h"
  59. #include "bits.h"
  60.  
  61. #ifdef DBM
  62. #    ifdef NULL
  63. #    undef NULL
  64. #    endif
  65. #    include <dbm.h>
  66. #endif
  67. MEM_SIZE ctlsize;            /* size of bitmap in bytes */
  68.  
  69. void
  70. bits_init()
  71. {
  72. #ifdef DELAYMARK
  73.     dmname = savestr(filexp(RNDELNAME));
  74. #else
  75.     ;
  76. #endif
  77. }
  78.  
  79. /* checkpoint the .newsrc */
  80.  
  81. void
  82. checkpoint_rc()
  83. {
  84. #ifdef DEBUGGING
  85.     if (debug & DEB_CHECKPOINTING) {
  86.     fputs("(ckpt)",stdout);
  87.     fflush(stdout);
  88.     }
  89. #endif
  90.     if (doing_ng)
  91.     restore_ng();            /* do not restore M articles */
  92.     if (rc_changed)
  93.     write_rc();
  94. #ifdef DEBUGGING
  95.     if (debug & DEB_CHECKPOINTING) {
  96.     fputs("(done)",stdout);
  97.     fflush(stdout);
  98.     }
  99. #endif
  100. }
  101.  
  102. /* reconstruct the .newsrc line in a human readable form */
  103.  
  104. void
  105. restore_ng()
  106. {
  107.     register char *s, *mybuf = buf;
  108.     register ART_NUM i;
  109.     ART_NUM count=0;
  110.     int safelen = LBUFLEN - 16;
  111.  
  112.     strcpy(buf,rcline[ng]);        /* start with the newsgroup name */
  113.     s = buf + rcnums[ng] - 1;        /* use s for buffer pointer */
  114.     *s++ = rcchar[ng];            /* put the requisite : or !*/
  115.     *s++ = ' ';                /* put the not-so-requisite space */
  116.     for (i=1; i<=lastart; i++) {    /* for each article in newsgroup */
  117.     if (s-mybuf > safelen) {    /* running out of room? */
  118.         safelen *= 2;
  119.         if (mybuf == buf) {        /* currently static? */
  120.         *s = '\0';
  121.         mybuf = safemalloc((MEM_SIZE)safelen + 16);
  122.         strcpy(mybuf,buf);    /* so we must copy it */
  123.         s = mybuf + (s-buf);
  124.                     /* fix the pointer, too */
  125.         }
  126.         else {            /* just grow in place, if possible */
  127.         char *newbuf;
  128.  
  129.         newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16);
  130.         s = newbuf + (s-mybuf);
  131.         mybuf = newbuf;
  132.         }
  133.     }
  134.     if (!was_read(i))        /* still unread? */
  135.         count++;            /* then count it */
  136.     else {                /* article was read */
  137.         ART_NUM oldi;
  138.  
  139.         sprintf(s,"%ld",(long)i);    /* put out the min of the range */
  140.         s += strlen(s);        /* keeping house */
  141.         oldi = i;            /* remember this spot */
  142.         do i++; while (i <= lastart && was_read(i));
  143.                     /* find 1st unread article or end */
  144.         i--;            /* backup to last read article */
  145.         if (i > oldi) {        /* range of more than 1? */
  146.         sprintf(s,"-%ld,",(long)i);
  147.                     /* then it out as a range */
  148.         s += strlen(s);        /* and housekeep */
  149.         }
  150.         else
  151.         *s++ = ',';        /* otherwise, just a comma will do */
  152.     }
  153.     }
  154.     if (*(s-1) == ',')            /* is there a final ','? */
  155.     s--;                /* take it back */
  156.     *s++ = '\0';            /* and terminate string */
  157. #ifdef DEBUGGING
  158.     if (debug & DEB_NEWSRC_LINE && !panic) {
  159.     printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]) FLUSH;
  160.     printf("%s\n",mybuf) FLUSH;
  161.     }
  162. #endif
  163.     free(rcline[ng]);            /* return old rc line */
  164.     if (mybuf == buf) {
  165.     rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1);
  166.                     /* grab a new rc line */
  167.     strcpy(rcline[ng], buf);    /* and load it */
  168.     }
  169.     else {
  170.     mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1);
  171.                     /* be nice to the heap */
  172.     rcline[ng] = mybuf;
  173.     }
  174.     *(rcline[ng] + rcnums[ng] - 1) = '\0';
  175.     if (rcchar[ng] == NEGCHAR) {    /* did they unsubscribe? */
  176.     printf(unsubto,ngname) FLUSH;
  177.     toread[ng] = TR_UNSUB;        /* make line invisible */
  178.     }
  179.     else
  180.     /*NOSTRICT*/
  181.     toread[ng] = (ART_UNREAD)count;        /* remember how many unread there are */
  182. }
  183.  
  184. /* mark an article unread, keeping track of toread[] */
  185.  
  186. void
  187. onemore(artnum)
  188. ART_NUM artnum;
  189. {
  190. #ifdef DEBUGGING
  191.     if (debug && artnum < firstbit) {
  192.     printf("onemore: %d < %d\n",artnum,firstbit) FLUSH;
  193.     return;
  194.     }
  195. #endif
  196.     if (ctl_read(artnum)) {
  197.     ctl_clear(artnum);
  198.     ++toread[ng];
  199.     }
  200. }
  201.  
  202. /* mark an article read, keeping track of toread[] */
  203.  
  204. void
  205. oneless(artnum)
  206. ART_NUM artnum;
  207. {
  208. #ifdef DEBUGGING
  209.     if (debug && artnum < firstbit) {
  210.     printf("oneless: %d < %d\n",artnum,firstbit) FLUSH;
  211.     return;
  212.     }
  213. #endif
  214.     if (!ctl_read(artnum)) {
  215.     ctl_set(artnum);
  216.     if (toread[ng] > TR_NONE)
  217.         --toread[ng];
  218.     }
  219. }
  220.  
  221. /* mark an article as unread, making sure that firstbit is properly handled */
  222. /* cross-references are left as read in the other newsgroups */
  223.  
  224. void
  225. unmark_as_read()
  226. {
  227.     check_first(art);
  228. #ifdef USETHREADS
  229.     /* Keep selected_count accurate */
  230.     if (ctl_read(art)) {
  231.     find_article(art);
  232.     if (p_art) {
  233.         if (selected_roots[p_art->root]) {
  234.         selected_count++;
  235.         }
  236.         root_article_cnts[p_art->root] = 1;
  237.     } else
  238.         unthreaded++;
  239.     }
  240.     scan_all_roots = FALSE;
  241. #endif
  242.     onemore(art);
  243. #ifdef MCHASE
  244.     if (!parse_maybe(art))
  245.     chase_xrefs(art,FALSE);
  246. #endif
  247. }
  248.  
  249. #ifdef USETHREADS
  250. /* mark an article as read in this newsgroup only */
  251.  
  252. void
  253. set_read(artnum,sel)
  254. ART_NUM artnum;
  255. int sel;
  256. {
  257.     if (!ctl_read(artnum)) {
  258.     oneless(artnum);
  259.     if( p_art->subject != -1 )
  260.         selected_count -= sel;
  261.     }
  262. }
  263.  
  264. /* mark an article as unread in this newsgroup only */
  265.  
  266. void
  267. set_unread(artnum,sel)
  268. ART_NUM artnum;
  269. int sel;
  270. {
  271.     if (artnum >= absfirst) {
  272.     check_first(artnum);
  273.     if (ctl_read(artnum)) {
  274.         onemore(artnum);
  275.         selected_count += sel;
  276.         root_article_cnts[p_art->root] = 1;
  277.         scan_all_roots = FALSE;
  278.     }
  279.     }
  280. }
  281. #endif
  282.  
  283. #ifdef DELAYMARK
  284. /* temporarily mark article as read.  When newsgroup is exited, articles */
  285. /* will be marked as unread.  Called via M command */
  286.  
  287. void
  288. delay_unmark(artnum)
  289. ART_NUM artnum;
  290. {
  291.     if (dmfp == Nullfp) {
  292.     dmfp = fopen(dmname,"w+");
  293.     if (dmfp == Nullfp) {
  294.         printf(cantcreate,dmname) FLUSH;
  295.         sig_catcher(0);
  296.     }
  297.     }
  298. #ifdef USETHREADS
  299.     /* Keep selected_count accurate */
  300.     if (!ctl_read(artnum)) {
  301.     find_article(artnum);
  302.     if (p_art) {
  303.         if (selected_roots[p_art->root])
  304.         selected_count--;
  305.     } else
  306.         unthreaded--;
  307.     }
  308. #endif
  309.     oneless(artnum);            /* set the correct bit */
  310.     dmcount++;
  311.     fprintf(dmfp,"%ld\n",(long)artnum);
  312. }
  313. #endif
  314.  
  315. /* mark article as read.  If article is cross referenced to other */
  316. /* newsgroups, mark them read there also. */
  317.  
  318. void
  319. mark_as_read()
  320. {
  321. #ifdef USETHREADS
  322.     /* Keep selected_count accurate */
  323.     if (!ctl_read(art)) {
  324.     find_article(art);
  325.     if (p_art) {
  326.         if (selected_roots[p_art->root])
  327.         selected_count--;
  328.     } else
  329.         unthreaded--;
  330.     }
  331. #endif
  332.     oneless(art);            /* set the correct bit */
  333.     checkcount++;            /* get more worried about crashes */
  334.     chase_xrefs(art,TRUE);
  335. }
  336.  
  337. /* make sure we have bits set correctly down to firstbit */
  338.  
  339. void
  340. check_first(min)
  341. ART_NUM min;
  342. {
  343.     register ART_NUM i = firstbit;
  344.  
  345.     if (min < absfirst)
  346.     min = absfirst;
  347.     if (min < i) {
  348.     for (i--; i>=min; i--)
  349.         ctl_set(i);        /* mark as read */
  350.     firstart = firstbit = min;
  351.     }
  352. }
  353.  
  354. /* bring back articles marked with M */
  355.  
  356. #ifdef DELAYMARK
  357. void
  358. yankback()
  359. {
  360.     if (dmfp) {            /* delayed unmarks pending? */
  361. #ifdef VERBOSE
  362.     printf("\nReturning %ld Marked article%s...\n",(long)dmcount,
  363.         dmcount == 1 ? nullstr : "s") FLUSH;
  364. #endif
  365.     rewind(dmfp);
  366.     while (fgets(buf,sizeof buf,dmfp) != Nullch) {
  367.         art = (ART_NUM)atol(buf);
  368.         unmark_as_read();
  369.     }
  370.     fclose(dmfp);
  371.     dmfp = Nullfp;
  372.     UNLINK(dmname);        /* and be tidy */
  373.     }
  374.     dmcount = 0;
  375. }
  376. #endif
  377.     
  378. /* run down xref list and mark as read or unread */
  379.  
  380. int
  381. chase_xrefs(artnum,markread)
  382. ART_NUM artnum;
  383. int markread;
  384. {
  385. #ifdef ASYNC_PARSE
  386.     if (parse_maybe(artnum))        /* make sure we have right header */
  387.     return -1;
  388. #endif
  389. #ifdef DBM
  390.     {
  391.     datum lhs, rhs;
  392.     datum fetch();
  393.     register char *idp;
  394.     char *ident_buf;
  395.     static FILE * hist_file = Nullfp;
  396. #else
  397.     if (
  398. #ifdef DEBUGGING
  399.     debug & DEB_FEED_XREF ||
  400. #endif
  401.     htype[XREF_LINE].ht_minpos >= 0) {
  402.                     /* are there article# xrefs? */
  403. #endif /* DBM */
  404.     char *xref_buf, *curxref;
  405.     register char *xartnum;
  406.     char *rver_buf = Nullch;
  407.     static char *inews_site = Nullch;
  408.     register ART_NUM x;
  409.     char tmpbuf[128];
  410.     long pos;
  411.  
  412. #ifdef DBM
  413.     rver_buf = fetchlines(artnum,NGS_LINE);
  414.                     /* get Newsgroups */
  415.     if (!index(rver_buf,','))    /* if no comma, no Xref! */
  416.         return 0;
  417.     if (hist_file == Nullfp) {    /* Init. file accesses */
  418. #ifdef DEBUGGING
  419.         if (debug)
  420.         printf ("chase_xref: opening files\n");
  421. #endif
  422.         dbminit(filexp(ARTFILE));
  423.         if ((hist_file = fopen (filexp(ARTFILE), "r")) == Nullfp)
  424.         return 0;
  425.     }
  426.     xref_buf = safemalloc((MEM_SIZE)BUFSIZ);
  427.     ident_buf = fetchlines(artnum,MESSID_LINE);
  428.                     /* get Message-ID */
  429. #ifdef DEBUGGING
  430.     if (debug)
  431.         printf ("chase_xref: Message-ID: %s\n", ident_buf);
  432. #endif
  433.     idp = ident_buf;
  434.     while (*++idp)            /* make message-id case insensitive */
  435.         if (isupper(*idp))
  436.             *idp = tolower (*idp);
  437.     lhs.dptr = ident_buf;        /* look up article by id */
  438.     lhs.dsize = strlen(lhs.dptr) + 1;
  439.     rhs = fetch(lhs);        /* fetch the record */
  440.     if (rhs.dptr == NULL)        /* if null, nothing there */
  441.         goto wild_goose;
  442.     bcopy((void *)rhs.dptr,(void *)&pos, 4);
  443.     fseek (hist_file, pos, 0);
  444.                 /* datum returned is position in hist file */
  445.     fgets (xref_buf, BUFSIZ, hist_file);
  446. #ifdef DEBUGGING
  447.     if (debug)
  448.         printf ("Xref from history: %s\n", xref_buf);
  449. #endif
  450.     curxref = cpytill(tmpbuf, xref_buf, '\t') + 1;
  451.     curxref = cpytill(tmpbuf, curxref, '\t') + 1;
  452. #ifdef DEBUGGING
  453.     if (debug)
  454.         printf ("chase_xref: curxref: %s\n", curxref);
  455. #endif
  456. #else /* !DBM */
  457. #ifdef DEBUGGING
  458.     if (htype[XREF_LINE].ht_minpos >= 0)
  459. #endif
  460.         xref_buf = fetchlines(artnum,XREF_LINE);
  461.                     /* get xrefs list */
  462. #ifdef DEBUGGING
  463.     else {
  464.         xref_buf = safemalloc((MEM_SIZE)100);
  465.         printf("Give Xref: ") FLUSH;
  466.         gets(xref_buf);
  467.     }
  468. #endif
  469. #ifdef DEBUGGING
  470.     if (debug & DEB_XREF_MARKER)
  471.         printf("Xref: %s\n",xref_buf) FLUSH;
  472. #endif
  473.     curxref = cpytill(tmpbuf,xref_buf,' ') + 1;
  474.  
  475.     /* Make sure site name on Xref matches what inews thinks site is.
  476.      * Check first against last inews_site.  If it matches, fine.
  477.      * If not, fetch inews_site from current Relay-Version line and
  478.      * check again.  This is so that if the new administrator decides
  479.      * to change the system name as known to inews, rn will still do
  480.      * Xrefs correctly--each article need only match itself to be valid.
  481.      */ 
  482.     if (inews_site == Nullch || strNE(tmpbuf,inews_site)) {
  483. #ifndef NORELAY
  484.         char *t;
  485. #endif
  486.         if (inews_site != Nullch)
  487.         free(inews_site);
  488. #ifndef NORELAY
  489.         rver_buf = fetchlines(artnum,RVER_LINE);
  490.         if ((t = instr(rver_buf,"; site ")) == Nullch)
  491. #else /* NORELAY */
  492.           /* In version 2.10.3 of news or afterwards, the Relay-Version
  493.            * and Posting-Version header lines have been removed.  For
  494.            * the code below to work as intended, I have modified it to
  495.            * extract the first component of the Path header line.  This
  496.            * should give the same effect as did the old code with respect
  497.            * to the use of the Relay-Version site name.
  498.            */
  499.           rver_buf = fetchlines(artnum,PATH_LINE);
  500.           if (instr(rver_buf,"!") == Nullch)
  501. #endif /* NORELAY */
  502.         inews_site = savestr(nullstr);
  503.         else {
  504.         char new_site[128];
  505.  
  506. #ifndef NORELAY
  507.         cpytill(new_site,t + 7,'.');
  508. #else /* NORELAY */
  509.               cpytill(new_site,rver_buf,'!');
  510. #endif /* NORELAY */
  511.         inews_site = savestr(new_site);
  512.         }
  513.         if (strNE(tmpbuf,inews_site)) {
  514. #ifdef DEBUGGING
  515.         if (debug)
  516.             printf("Xref not from %s--ignoring\n",inews_site) FLUSH;
  517. #endif
  518.         goto wild_goose;
  519.         }
  520.     }
  521. #endif /* DBM */
  522.     while (*curxref) {
  523.                     /* for each newsgroup */
  524.         curxref = cpytill(tmpbuf,curxref,' ');
  525. #ifdef DBM
  526.         xartnum = index(tmpbuf,'/');
  527. #else
  528.         xartnum = index(tmpbuf,':');
  529. #endif /* DBM */
  530.         if (!xartnum)        /* probably an old-style Xref */
  531.         break;
  532.         *xartnum++ = '\0';
  533.         if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */
  534.         x = atol(xartnum);
  535.         if (x)
  536.             if (markread) {
  537.             if (addartnum(x,tmpbuf))
  538.                 goto wild_goose;
  539.             }
  540. #ifdef MCHASE
  541.             else
  542.             subartnum(x,tmpbuf);
  543. #endif
  544.         }
  545.         while (*curxref && isspace(*curxref))
  546.         curxref++;
  547.     }
  548.       wild_goose:
  549.     free(xref_buf);
  550. #ifdef DBM
  551.     free(ident_buf);
  552. #endif /* DBM */
  553.     if (rver_buf != Nullch)
  554.         free(rver_buf);
  555.     }
  556.     return 0;
  557. }
  558.  
  559. int
  560. initctl()
  561. {
  562.     char *mybuf = buf;            /* place to decode rc line */
  563.     register char *s, *c, *h;
  564.     register long i;
  565.     register ART_NUM unread;
  566.     
  567. #ifdef DELAYMARK
  568.     dmcount = 0;
  569. #endif
  570.     if ((lastart = getngsize(ng)) < 0)    /* this cannot happen (laugh here) */
  571.     return -1;
  572.  
  573.     absfirst = getabsfirst(ng,lastart);    /* remember first existing article */
  574.     if (!absfirst)            /* no articles at all? */
  575.     absfirst = 1;            /* pretend there is one */
  576. #ifndef lint
  577.     ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20);
  578. #endif /* lint */
  579.     ctlarea = safemalloc(ctlsize);    /* allocate control area */
  580.  
  581.     /* now modify ctlarea to reflect what has already been read */
  582.  
  583.     for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ;
  584.                     /* find numbers in rc line */
  585.     i = strlen(s);
  586. #ifndef lint
  587.     if (i >= LBUFLEN-2)            /* bigger than buf? */
  588.     mybuf = safemalloc((MEM_SIZE)(i+2));
  589. #endif /* lint */
  590.     strcpy(mybuf,s);            /* make scratch copy of line */
  591.     mybuf[i++] = ',';            /* put extra comma on the end */
  592.     mybuf[i] = '\0';
  593.     s = mybuf;                /* initialize the for loop below */
  594.     if (strnEQ(s,"1-",2)) {        /* can we save some time here? */
  595.     firstbit = atol(s+2)+1;        /* ignore first range thusly */
  596.     s=index(s,',') + 1;
  597.     }
  598.     else
  599.     firstbit = 1;            /* all the bits are valid for now */
  600.     if (absfirst > firstbit) {        /* do we know already? */
  601.     firstbit = absfirst;        /* no point calling getngmin again */
  602.     }
  603.     else if (artopen(firstbit) == Nullfp) {
  604.                     /* first unread article missing? */
  605.     i = getngmin(".",firstbit);    /* see if expire has been busy */
  606.     if (i) {            /* avoid a bunch of extra opens */
  607.         firstbit = i;
  608.     }
  609.     }
  610.     firstart = firstbit;        /* firstart > firstbit in KILL */
  611. #ifdef PENDING
  612. #   ifdef CACHESUBJ
  613.     subj_to_get = firstbit;
  614. #   endif
  615. #endif
  616.     unread = lastart - firstbit + 1;    /* assume this range unread */
  617.     for (i=OFFSET(firstbit)/BITSPERBYTE; i<ctlsize; i++)
  618.     ctlarea[i] = 0;            /* assume unread */
  619. #ifdef DEBUGGING
  620.     if (debug & DEB_CTLAREA_BITMAP) {
  621.     printf("\n%s\n",mybuf) FLUSH;
  622.     for (i=1; i <= lastart; i++)
  623.         if (! was_read(i))
  624.         printf("%ld ",(long)i) FLUSH;
  625.     }
  626. #endif
  627.     for ( ; (c = index(s,',')) != Nullch; s = ++c) {
  628.                     /* for each range */
  629.     ART_NUM min, max;
  630.  
  631.     *c = '\0';            /* do not let index see past comma */
  632.     if ((h = index(s,'-')) != Nullch) {    /* is there a -? */
  633.         min = atol(s);
  634.         max = atol(h+1);
  635.         if (min < firstbit)        /* make sure range is in range */
  636.         min = firstbit;
  637.         if (max > lastart)
  638.         max = lastart;
  639.         if (min <= max)        /* non-null range? */
  640.         unread -= max - min + 1;/* adjust unread count */
  641.         for (i=min; i<=max; i++)    /* for all articles in range */
  642.         ctl_set(i);        /* mark them read */
  643.     }
  644.     else if ((i = atol(s)) >= firstbit && i <= lastart) {
  645.                     /* is single number reasonable? */
  646.         ctl_set(i);            /* mark it read */
  647.         unread--;            /* decrement articles to read */
  648.     }
  649. #ifdef DEBUGGING
  650.     if (debug & DEB_CTLAREA_BITMAP) {
  651.         printf("\n%s\n",s) FLUSH;
  652.         for (i=1; i <= lastart; i++)
  653.         if (! was_read(i))
  654.             printf("%ld ",(long)i) FLUSH;
  655.     }
  656. #endif
  657.     }
  658. #ifdef DEBUGGING
  659.     if (debug & DEB_CTLAREA_BITMAP) {
  660.     fputs("\n(hit CR)",stdout) FLUSH;
  661.     gets(cmd_buf);
  662.     }
  663. #endif
  664.     if (mybuf != buf)
  665.     free(mybuf);
  666.     toread[ng] = unread;
  667.     return 0;
  668. }
  669.  
  670. void
  671. grow_ctl(newlast)
  672. ART_NUM newlast;
  673. {
  674.     ART_NUM tmpfirst;
  675.     MEM_SIZE newsize;
  676.     register ART_NUM i;
  677.  
  678.     forcegrow = FALSE;
  679.     if (newlast > lastart) {
  680.     ART_NUM tmpart = art;
  681. #ifndef lint
  682.     newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2);
  683. #else
  684.     newsize = Null(MEM_SIZE);
  685. #endif /* lint */
  686.     if (newsize > ctlsize) {
  687.         newsize += 20;
  688.         ctlarea = saferealloc(ctlarea,newsize);
  689.         ctlsize = newsize;
  690.     }
  691.     toread[ng] += (ART_UNREAD)(newlast-lastart);
  692.     for (i=lastart+1; i<=newlast; i++)
  693.         ctl_clear(i);    /* these articles are unread */
  694. #ifdef CACHESUBJ
  695.     if (subj_list != Null(char**)) {
  696. #ifndef lint
  697.         subj_list = (char**)saferealloc((char*)subj_list,
  698.           (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) );
  699. #endif /* lint */
  700.         for (i=lastart+1; i<=newlast; i++)
  701.         subj_list[OFFSET(i)] = Nullch;
  702.     }
  703. #endif
  704.     tmpfirst = lastart+1;
  705.     lastart = newlast;
  706. #ifdef KILLFILES
  707. #ifdef VERBOSE
  708.     IF(verbose)
  709.         sprintf(buf,
  710.         "%ld more article%s arrived--looking for more to kill...\n\n",
  711.         (long)(lastart - tmpfirst + 1),
  712.         (lastart > tmpfirst ? "s have" : " has" ) );
  713.     ELSE            /* my, my, how clever we are */
  714. #endif
  715. #ifdef TERSE
  716.         strcpy(buf, "More news--killing...\n\n");
  717. #endif
  718.     kill_unwanted(tmpfirst,buf,TRUE);
  719. #endif
  720.     art = tmpart;
  721.     }
  722. }
  723.  
  724.