home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / UUPC11XT.ZIP / RN / RCSTUFF.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-21  |  29.5 KB  |  1,283 lines

  1. /* $Header: E:\SRC\UUPC\RN\RCS/RCSTUFF.C 1.1 1992/11/21 06:14:58 ahd Exp $
  2.  *
  3.  * $Log: RCSTUFF.C $
  4.  * Revision 1.1  1992/11/21  06:14:58  ahd
  5.  * Initial
  6.  *
  7.  *
  8.  *    Rev 1.0   18 Nov 1990  0:22:00
  9.  * Initial revision.
  10.  * Revision 4.3.2.5  90/05/04  00:44:07  sob
  11.  * Fixes to add_newsgroup() from lar@usl.edu.
  12.  *
  13.  * Revision 4.3.2.4  90/04/23  00:25:45  sob
  14.  * Changed atoi to atol.
  15.  *
  16.  * Revision 4.3.2.3  89/12/20  23:25:04  sob
  17.  * Changed the maximum lenght of a newsgroup name from 20 to 40 characters.
  18.  *
  19.  * Revision 4.3.2.2  89/11/26  18:22:26  sob
  20.  * Added changes to addnewgroup() to cause rn to ask once and only once
  21.  * to add a new group to .newsrc.
  22.  * Fix provided by Fletcher Mattox <fletcher@cs.utexas.edu>
  23.  *
  24.  * Revision 4.3.2.1  89/11/06  00:58:29  sob
  25.  * Added RRN support from NNTP 1.5
  26.  *
  27.  * Revision 4.3.1.5  86/07/24  14:09:10  lwall
  28.  * Removed check for spool directory existence in get_ng.
  29.  *
  30.  * Revision 4.3.1.4  85/09/10  11:04:44  lwall
  31.  * Improved %m in in_char().
  32.  *
  33.  * Revision 4.3.1.3  85/05/29  09:13:25  lwall
  34.  * %d that should be %ld.
  35.  *
  36.  * Revision 4.3.1.2  85/05/17  11:40:08  lwall
  37.  * Sped up "rn -c" by not mallocing unnecessarily.
  38.  *
  39.  * Revision 4.3.1.1  85/05/10  11:37:18  lwall
  40.  * Branch for patches.
  41.  *
  42.  * Revision 4.3  85/05/01  11:45:56  lwall
  43.  * Baseline for release with 4.3bsd.
  44.  *
  45.  */
  46.  
  47. #include <time.h>
  48.  
  49. #include "ssleep.h"
  50.  
  51. #include "EXTERN.h"
  52. #include "common.h"
  53. #include "util.h"
  54. #include "ngdata.h"
  55. #include "term.h"
  56. #include "final.h"
  57. #include "rn.h"
  58. #include "intrp.h"
  59. #include "only.h"
  60. #include "rcln.h"
  61.  
  62. #ifdef SERVER
  63. #include "server.h"
  64. #endif
  65.  
  66. #include "INTERN.h"
  67. #include "rcstuff.h"
  68.  
  69. char *rcname INIT(Nullch);   /* path name of .newsrc
  70.                               * file */
  71. char *rctname INIT(Nullch);  /* path name of temp
  72.                               * .newsrc file */
  73. char *rcbname INIT(Nullch);  /* path name of backup
  74.                               * .newsrc file */
  75. char *softname INIT(Nullch); /* path name of .rnsoft
  76.                               * file */
  77. FILE *rcfp INIT(Nullfp);     /* .newsrc file pointer */
  78.  
  79. #ifdef HASHNG
  80. short hashtbl[HASHSIZ];
  81.  
  82. #endif
  83.  
  84. bool
  85. rcstuff_init()
  86. {
  87.    register NG_NUM newng;
  88.    register char *s;
  89.    register int i;
  90.    register bool foundany = FALSE;
  91.    char *some_buf;
  92.    long length;
  93.  
  94. #ifdef SERVER
  95.    char *cp;
  96.  
  97. #endif                       /* SERVER */
  98.  
  99. #ifdef HASHNG
  100.    for (i = 0; i < HASHSIZ; i++)
  101.       hashtbl[i] = -1;
  102. #endif
  103.  
  104.    /* make filenames */
  105.  
  106. #ifdef SERVER
  107.    if (cp = getenv("NEWSRC"))
  108.       rcname = savestr(filexp(cp));
  109.    else
  110.       rcname = savestr(filexp(RCNAME));
  111.  
  112. #else                        /* not SERVER */
  113.  
  114.    rcname = savestr(filexp(RCNAME));
  115. #endif                       /* SERVER */
  116.  
  117.    rctname = savestr(filexp(RCTNAME));
  118.    rcbname = savestr(filexp(RCBNAME));
  119.    softname = savestr(filexp(SOFTNAME));
  120.  
  121.    /* make sure the .newsrc file exists */
  122.  
  123.    newsrc_check();
  124.  
  125.    /* open .rnsoft file containing soft ptrs to active file */
  126.  
  127.    tmpfp = fopen(softname, "r");
  128.    if (tmpfp == Nullfp)
  129.       writesoft = TRUE;
  130.  
  131.    /* read in the .newsrc file */
  132.  
  133.    for (nextrcline = 0;
  134.          (some_buf = get_a_line(buf, LBUFLEN, rcfp)) != Nullch;
  135.          nextrcline++)
  136.    {
  137.       /* for each line in .newsrc */
  138.       char tmpbuf[10];
  139.  
  140.       newng = nextrcline;    /* get it into a
  141.                               * register */
  142.       length = len_last_line_got;       /* side effect of
  143.                                          * get_a_line */
  144.       if (length <= 1)
  145.       {                      /* only a newline??? */
  146.          nextrcline--;       /* compensate for loop
  147.                               * increment */
  148.          continue;
  149.       }
  150.       if (newng >= MAXRCLINE)
  151.       {                      /* check for overflow */
  152.          fputs("Too many lines in .newsrc\n", stdout) FLUSH;
  153.          finalize(1);
  154.       }
  155.       if (tmpfp != Nullfp && fgets(tmpbuf, 10, tmpfp) != Nullch)
  156.          softptr[newng] = atol(tmpbuf);
  157.       else
  158.          softptr[newng] = 0;
  159.       some_buf[--length] = '\0';        /* wipe out newline */
  160.       if (checkflag)         /* no extra mallocs for
  161.                               * -c */
  162.          rcline[newng] = some_buf;
  163.       else if (some_buf == buf)
  164.       {
  165.          rcline[newng] = savestr(some_buf);
  166.          /* make a semipermanent copy */
  167.       }
  168.       else
  169.       {
  170.          /* NOSTRICT */
  171.  
  172. #ifndef lint
  173.          some_buf = saferealloc(some_buf, (MEM_SIZE) (length + 1));
  174. #endif                       /* lint */
  175.  
  176.          rcline[newng] = some_buf;
  177.       }
  178.  
  179. #ifdef NOTDEF
  180.       if (strnEQ(some_buf, "to.", 3))
  181.       {                      /* is this a
  182.                               * non-newsgroup? */
  183.          nextrcline--;       /* destroy this line */
  184.          continue;
  185.       }
  186. #endif
  187.  
  188.       if (*some_buf == ' ' ||
  189.             *some_buf == '\t' ||
  190.             strnEQ(some_buf, "options", 7))
  191.       {                      /* non-useful line? */
  192.          toread[newng] = TR_JUNK;
  193.          rcchar[newng] = ' ';
  194.          rcnums[newng] = 0;
  195.          continue;
  196.       }
  197.       for (s = rcline[newng]; *s && *s != ':' && *s != NEGCHAR; s++);
  198.       if (!*s && !checkflag)
  199.       {
  200.  
  201. #ifndef lint
  202.          rcline[newng] = saferealloc(rcline[newng], (MEM_SIZE) length + 2);
  203. #endif                       /* lint */
  204.  
  205.          s = rcline[newng] + length;
  206.          *s = ':';
  207.          *(s + 1) = '\0';
  208.       }
  209.       rcchar[newng] = *s;    /* salt away the : or ! */
  210.       rcnums[newng] = (char) (s - rcline[newng]);
  211.       rcnums[newng]++;       /* remember where it was */
  212.       *s = '\0';             /* null terminate
  213.                               * newsgroup name */
  214.  
  215. #ifdef HASHNG
  216.       if (!checkflag)
  217.          sethash(newng);
  218. #endif
  219.  
  220.       if (rcchar[newng] == NEGCHAR)
  221.       {
  222.          toread[newng] = TR_UNSUB;
  223.          continue;
  224.       }
  225.  
  226.       /* now find out how much there is to read */
  227.  
  228.       if (!inlist(buf) || (suppress_cn && foundany && !paranoid))
  229.          toread[newng] = TR_NONE;       /* no need to calculate
  230.                                          * now */
  231.       else
  232.          set_toread(newng);
  233.  
  234. #ifdef VERBOSE
  235.       if (!checkflag && softmisses == 1)
  236.       {
  237.          softmisses++;       /* lie a little */
  238.          fputs("(Revising soft pointers--be patient.)\n", stdout) FLUSH;
  239.       }
  240. #endif
  241.  
  242.       if (toread[newng] > TR_NONE)
  243.       {                      /* anything unread? */
  244.          if (!foundany)
  245.          {
  246.             starthere = newng;
  247.             foundany = TRUE; /* remember that fact */
  248.          }
  249.          if (suppress_cn)
  250.          {                   /* if no listing desired */
  251.             if (checkflag)
  252.             {                /* if that is all they
  253.                               * wanted */
  254.                finalize(1);  /* then bomb out */
  255.             }
  256.          }
  257.          else
  258.          {
  259.  
  260. #ifdef VERBOSE
  261.             IF(verbose)
  262.                printf("Unread news in %-40s %5ld article%s\n",
  263.                       rcline[newng], (long) toread[newng],
  264.                       toread[newng] == TR_ONE ? nullstr : "s") FLUSH;
  265.             ELSE
  266. #endif
  267.  
  268. #ifdef TERSE
  269.                printf("%s: %ld article%s\n",
  270.                       rcline[newng], (long) toread[newng],
  271.                       toread[newng] == TR_ONE ? nullstr : "s") FLUSH;
  272. #endif
  273.  
  274.             if (int_count)
  275.             {
  276.                countdown = 1;
  277.                int_count = 0;
  278.             }
  279.             if (countdown)
  280.             {
  281.                if (!--countdown)
  282.                {
  283.                   fputs("etc.\n", stdout) FLUSH;
  284.                   if (checkflag)
  285.                      finalize(1);
  286.                   suppress_cn = TRUE;
  287.                }
  288.             }
  289.          }
  290.       }
  291.    }
  292.    fclose(rcfp);             /* close .newsrc */
  293.    if (tmpfp != Nullfp)
  294.       fclose(tmpfp);         /* close .rnsoft */
  295.    if (checkflag)
  296.    {                         /* were we just
  297.                               * checking? */
  298.       finalize(foundany);    /* tell them what we
  299.                               * found */
  300.    }
  301.    if (paranoid)
  302.       cleanup_rc();
  303.  
  304. #ifdef DEBUGGING
  305.    if (debug & DEB_HASH)
  306.    {
  307.       page_init();
  308.       for (i = 0; i < HASHSIZ; i++)
  309.       {
  310.          sprintf(buf, "%d       %d", i, hashtbl[i]);
  311.          print_lines(buf, NOMARKING);
  312.       }
  313.    }
  314. #endif
  315.  
  316.    return foundany;
  317. }
  318.  
  319. /* try to find or add an explicitly specified newsgroup */
  320. /* returns TRUE if found or added, FALSE if not. */
  321. /* assumes that we are chdir'ed to SPOOL */
  322.  
  323. #ifdef SERVER
  324. static int addnewbydefault = 0;
  325.  
  326. #endif                       /* SERVER */
  327.  
  328. bool
  329. get_ng(what, do_reloc)
  330.    char *what;
  331.    bool do_reloc;
  332. {
  333.    char *ntoforget;
  334.    char promptbuf[128];
  335.  
  336. #ifdef SERVER
  337.    char ser_line[256];
  338.  
  339. #endif                       /* SERVER */
  340.  
  341. #ifdef VERBOSE
  342.    IF(verbose)
  343.       ntoforget = "Type n to forget about this newsgroup.\n";
  344.    ELSE
  345. #endif
  346.  
  347. #ifdef TERSE
  348.       ntoforget = "n to forget it.\n";
  349. #endif
  350.  
  351.    if (index(what, '/'))
  352.    {
  353.       dingaling();
  354.       printf("\nBad newsgroup name.\n") FLUSH;
  355.       return FALSE;
  356.    }
  357.    set_ngname(what);
  358.    ng = find_ng(ngname);
  359.    if (ng == nextrcline)
  360.    {                         /* not in .newsrc? */
  361.  
  362. #ifdef SERVER
  363.       sprintf(ser_line, "GROUP %s", ngname);
  364.       put_server(ser_line);
  365.       if (get_server(ser_line, sizeof (ser_line)) < 0)
  366.       {
  367.          fprintf(stderr, "rrn: Unexpected close of server socket.\n");
  368.          finalize(1);
  369.       }
  370.       if (*ser_line != CHAR_OK)
  371.       {
  372.          if (atoi(ser_line) != ERR_NOGROUP)
  373.          {
  374.             fprintf(stderr, "Server response to GROUP %s:\n%s\n",
  375.                     ngname, ser_line);
  376.          }
  377. #else                        /* not SERVER */
  378.  
  379.       if ((softptr[ng] = findact(buf, ngname, strlen(ngname), 0L)) < 0)
  380.       {
  381. #endif                       /* SERVER */
  382.  
  383.          dingaling();
  384.  
  385. #ifdef VERBOSE
  386.          IF(verbose)
  387.             printf("\nNewsgroup %s does not exist!\n", ngname) FLUSH;
  388.          ELSE
  389. #endif
  390.  
  391. #ifdef TERSE
  392.             printf("\nNo %s!\n", ngname) FLUSH;
  393. #endif
  394.  
  395.          ssleep(2);
  396.          return FALSE;
  397.       }
  398.  
  399. #ifdef SERVER
  400.       if (addnewbydefault)
  401.       {
  402.          printf("(Adding %s to end of your .newsrc)\n", ngname);
  403.          ng = add_newsgroup(ngname, ':');
  404.          do_reloc = FALSE;
  405.       }
  406.       else
  407.       {
  408. #endif                       /* SERVER */
  409.  
  410. #ifdef VERBOSE
  411.          IF(verbose)
  412.             sprintf(promptbuf, "\nNewsgroup %s not in .newsrc--add? [yn] ", ngname);
  413.          ELSE
  414. #endif
  415.  
  416. #ifdef TERSE
  417.             sprintf(promptbuf, "\nAdd %s? [yn] ", ngname);
  418. #endif
  419.  
  420.    reask_add:
  421.          in_char(promptbuf, 'A');
  422.          putchar('\n') FLUSH;
  423.          setdef(buf, "y");
  424.  
  425. #ifdef VERIFY
  426.          printcmd();
  427. #endif
  428.  
  429.          if (*buf == 'h')
  430.          {
  431.  
  432. #ifdef VERBOSE
  433.             IF(verbose)
  434.                printf("Type y or SP to add %s to your .newsrc.\n", ngname)
  435.                FLUSH;
  436.             ELSE
  437. #endif
  438.  
  439. #ifdef TERSE
  440.                fputs("y or SP to add\n", stdout) FLUSH;
  441. #endif
  442.  
  443.             fputs(ntoforget, stdout) FLUSH;
  444.             goto reask_add;
  445.          }
  446.          else if (*buf == 'n' || *buf == 'q')
  447.          {
  448.             ng = add_newsgroup(ngname, '!');
  449.             return FALSE;
  450.          }
  451.          else if (*buf == 'y')
  452.          {
  453.             ng = add_newsgroup(ngname, ':');
  454.             do_reloc = FALSE;
  455.          }
  456.  
  457. #ifdef SERVER
  458.          else if (*buf == 'Y')
  459.          {
  460.             fputs(
  461.                   "(I'll add all new newsgroups to the end of your .newsrc.)\n", stdout);
  462.             addnewbydefault = 1;
  463.             printf("(Adding %s to end of your .newsrc)\n", ngname);
  464.             ng = add_newsgroup(ngname, ':');
  465.             do_reloc = FALSE;
  466.          }
  467. #endif                       /* SERVER */
  468.  
  469.          else
  470.          {
  471.             fputs(hforhelp, stdout) FLUSH;
  472.             settle_down();
  473.             goto reask_add;
  474.          }
  475.  
  476. #ifdef SERVER
  477.       }
  478. #endif                       /* SERVER */
  479.    }
  480.    else if (rcchar[ng] == NEGCHAR)
  481.    {                         /* unsubscribed? */
  482.  
  483. #ifdef VERBOSE
  484.       IF(verbose)
  485.          sprintf(promptbuf,
  486.                  "\nNewsgroup %s is currently unsubscribed to--resubscribe? [yn] ", ngname)
  487.          FLUSH;
  488.       ELSE
  489. #endif
  490.  
  491. #ifdef TERSE
  492.          sprintf(promptbuf, "\n%s unsubscribed--resubscribe? [yn] ", ngname)
  493.          FLUSH;
  494. #endif
  495.  
  496. reask_unsub:
  497.       in_char(promptbuf, 'R');
  498.       putchar('\n') FLUSH;
  499.       setdef(buf, "y");
  500.  
  501. #ifdef VERIFY
  502.       printcmd();
  503. #endif
  504.  
  505.       if (*buf == 'h')
  506.       {
  507.  
  508. #ifdef VERBOSE
  509.          IF(verbose)
  510.             printf("Type y or SP to resubscribe to %s.\n", ngname) FLUSH;
  511.          ELSE
  512. #endif
  513.  
  514. #ifdef TERSE
  515.             fputs("y or SP to resubscribe.\n", stdout) FLUSH;
  516. #endif
  517.  
  518.          fputs(ntoforget, stdout) FLUSH;
  519.          goto reask_unsub;
  520.       }
  521.       else if (*buf == 'n' || *buf == 'q')
  522.       {
  523.          return FALSE;
  524.       }
  525.       else if (*buf == 'y')
  526.       {
  527.          rcchar[ng] = ':';
  528.       }
  529.       else
  530.       {
  531.          fputs(hforhelp, stdout) FLUSH;
  532.          settle_down();
  533.          goto reask_unsub;
  534.       }
  535.    }
  536.  
  537.    /* now calculate how many unread articles in newsgroup */
  538.  
  539.    set_toread(ng);
  540.  
  541. #ifdef RELOCATE
  542.    if (do_reloc)
  543.       ng = relocate_newsgroup(ng, -1);
  544. #endif
  545.  
  546.    return toread[ng] >= TR_NONE;
  547. }
  548.  
  549. /* add a newsgroup to the .newsrc file (eventually) */
  550.  
  551. NG_NUM
  552. add_newsgroup(ngn, c)
  553.    char *ngn, c;
  554. {
  555.    register NG_NUM newng = nextrcline++;
  556.  
  557.    /* increment max rcline index */
  558.  
  559.    rcnums[newng] = strlen(ngn) + 1;
  560.    rcline[newng] = safemalloc((MEM_SIZE) (rcnums[newng] + 1));
  561.    strcpy(rcline[newng], ngn);  /* and copy over the
  562.                                  * name */
  563.    *(rcline[newng] + rcnums[newng]) = '\0';
  564.    rcchar[newng] = c;        /* subscribe or
  565.                               * unsubscribe */
  566.    toread[newng] = TR_NONE;  /* just for prettiness */
  567.  
  568. #ifdef HASHNG
  569.    sethash(newng);           /* so we can find it
  570.                               * again */
  571. #endif
  572.  
  573. #ifdef RELOCATE
  574.    return c == '!' ? newng : relocate_newsgroup(newng, -1);
  575. #else
  576.    return newng;
  577. #endif
  578. }
  579.  
  580. #ifdef RELOCATE
  581. NG_NUM
  582. relocate_newsgroup(ngx, newng)
  583.    NG_NUM ngx;
  584.    NG_NUM newng;
  585. {
  586.    char *dflt = (ngx != current_ng ? "$^.L" : "$^L");
  587.    char *tmprcline;
  588.    ART_UNREAD tmptoread;
  589.    char tmprcchar;
  590.    char tmprcnums;
  591.    ACT_POS tmpsoftptr;
  592.    register NG_NUM i;
  593.  
  594. #ifdef DEBUGGING
  595.    ART_NUM tmpngmax;
  596.  
  597. #endif
  598.  
  599. #ifdef CACHEFIRST
  600.    ART_NUM tmpabs1st;
  601.  
  602. #endif
  603.  
  604.    starthere = 0;            /* Disable this
  605.                               * optimization */
  606.    writesoft = TRUE;         /* Update soft pointer
  607.                               * file */
  608.    if (ngx < nextrcline - 1)
  609.    {
  610.  
  611. #ifdef HASHNG
  612.       for (i = 0; i < HASHSIZ; i++)
  613.       {
  614.          if (hashtbl[i] > ngx)
  615.             --hashtbl[i];
  616.          else if (hashtbl[i] == ngx)
  617.             hashtbl[i] = nextrcline - 1;
  618.       }
  619. #endif
  620.  
  621.       tmprcline = rcline[ngx];
  622.       tmptoread = toread[ngx];
  623.       tmprcchar = rcchar[ngx];
  624.       tmprcnums = rcnums[ngx];
  625.       tmpsoftptr = softptr[ngx];
  626.  
  627. #ifdef DEBUGGING
  628.       tmpngmax = ngmax[ngx];
  629. #endif
  630.  
  631. #ifdef CACHEFIRST
  632.       tmpabs1st = abs1st[ngx];
  633. #endif
  634.  
  635.       for (i = ngx + 1; i < nextrcline; i++)
  636.       {
  637.          rcline[i - 1] = rcline[i];
  638.          toread[i - 1] = toread[i];
  639.          rcchar[i - 1] = rcchar[i];
  640.          rcnums[i - 1] = rcnums[i];
  641.          softptr[i - 1] = softptr[i];
  642.  
  643. #ifdef DEBUGGING
  644.          ngmax[i - 1] = ngmax[i];
  645. #endif
  646.  
  647. #ifdef CACHEFIRST
  648.          abs1st[i - 1] = abs1st[i];
  649. #endif
  650.       }
  651.       rcline[nextrcline - 1] = tmprcline;
  652.       toread[nextrcline - 1] = tmptoread;
  653.       rcchar[nextrcline - 1] = tmprcchar;
  654.       rcnums[nextrcline - 1] = tmprcnums;
  655.       softptr[nextrcline - 1] = tmpsoftptr;
  656.  
  657. #ifdef DEBUGGING
  658.       ngmax[nextrcline - 1] = tmpngmax;
  659. #endif
  660.  
  661. #ifdef CACHEFIRST
  662.       abs1st[nextrcline - 1] = tmpabs1st;
  663. #endif
  664.    }
  665.    if (current_ng > ngx)
  666.       current_ng--;
  667.    if (newng < 0)
  668.    {
  669. reask_reloc:
  670.       unflush_output();      /* disable any ^O in
  671.                               * effect */
  672.  
  673. #ifdef SERVER
  674.       if (addnewbydefault)
  675.       {
  676.          buf[0] = '$';
  677.          buf[1] = '\0';
  678.       }
  679.       else
  680.       {
  681. #endif                       /* SERVER */
  682.  
  683. #ifdef VERBOSE
  684.          IF(verbose)
  685.             printf("\nPut newsgroup where? [%s] ", dflt);
  686.          ELSE
  687. #endif
  688.  
  689. #ifdef TERSE
  690.             printf("\nPut where? [%s] ", dflt);
  691. #endif
  692.  
  693.          fflush(stdout);
  694.    reinp_reloc:
  695.          eat_typeahead();
  696.          getcmd(buf);
  697.  
  698. #ifdef SERVER
  699.       }
  700. #endif                       /* SERVER */
  701.  
  702.       if (errno || *buf == '\f')
  703.       {
  704.          /* if return from stop signal */
  705.          goto reask_reloc;   /* give them a prompt
  706.                               * again */
  707.       }
  708.       setdef(buf, dflt);
  709.  
  710. #ifdef VERIFY
  711.       printcmd();
  712. #endif
  713.  
  714.       if (*buf == 'h')
  715.       {
  716.  
  717. #ifdef VERBOSE
  718.          IF(verbose)
  719.          {
  720.             printf("\n\n\
  721. Type ^ to put the newsgroup first (position 0).\n\
  722. Type $ to put the newsgroup last (position %d).\n", nextrcline - 1);
  723.             printf("\
  724. Type . to put it before the current newsgroup (position %d).\n", current_ng);
  725.             printf("\
  726. Type -newsgroup name to put it before that newsgroup.\n\
  727. Type +newsgroup name to put it after that newsgroup.\n\
  728. Type a number between 0 and %d to put it at that position.\n", nextrcline - 1);
  729.             printf("\
  730. Type L for a listing of newsgroups and their positions.\n") FLUSH;
  731.          }
  732.          ELSE
  733. #endif
  734.  
  735. #ifdef TERSE
  736.          {
  737.             printf("\n\n\
  738. ^ to put newsgroup first (pos 0).\n\
  739. $ to put last (pos %d).\n", nextrcline - 1);
  740.             printf("\
  741. . to put before current newsgroup (pos %d).\n", current_ng);
  742.             printf("\
  743. -newsgroup to put before newsgroup.\n\
  744. +newsgroup to put after.\n\
  745. number in 0-%d to put at that pos.\n", nextrcline - 1);
  746.             printf("\
  747. L for list of .newsrc.\n") FLUSH;
  748.          }
  749. #endif
  750.  
  751.          goto reask_reloc;
  752.       }
  753.       else if (*buf == 'L')
  754.       {
  755.          putchar('\n') FLUSH;
  756.          list_newsgroups();
  757.          goto reask_reloc;
  758.       }
  759.       else if (isdigit(*buf))
  760.       {
  761.          if (!finish_command(TRUE))     /* get rest of command */
  762.             goto reinp_reloc;
  763.          newng = atol(buf);
  764.          if (newng < 0)
  765.             newng = 0;
  766.          if (newng >= nextrcline)
  767.             return nextrcline - 1;
  768.       }
  769.       else if (*buf == '^')
  770.       {
  771.          putchar('\n') FLUSH;
  772.          newng = 0;
  773.       }
  774.       else if (*buf == '$')
  775.       {
  776.          putchar('\n') FLUSH;
  777.          return nextrcline - 1;
  778.       }
  779.       else if (*buf == '.')
  780.       {
  781.          putchar('\n') FLUSH;
  782.          newng = current_ng;
  783.       }
  784.       else if (*buf == '-' || *buf == '+')
  785.       {
  786.          if (!finish_command(TRUE))     /* get rest of command */
  787.             goto reinp_reloc;
  788.          newng = find_ng(buf + 1);
  789.          if (newng == nextrcline)
  790.          {
  791.             fputs("Not found.", stdout) FLUSH;
  792.             goto reask_reloc;
  793.          }
  794.          if (*buf == '+')
  795.             newng++;
  796.       }
  797.       else
  798.       {
  799.          printf("\n%s", hforhelp) FLUSH;
  800.          settle_down();
  801.          goto reask_reloc;
  802.       }
  803.    }
  804.    if (newng < nextrcline - 1)
  805.    {
  806.  
  807. #ifdef HASHNG
  808.       for (i = 0; i < HASHSIZ; i++)
  809.       {
  810.          if (hashtbl[i] == nextrcline - 1)
  811.             hashtbl[i] = newng;
  812.          else if (hashtbl[i] >= newng)
  813.             ++hashtbl[i];
  814.       }
  815. #endif
  816.  
  817.       tmprcline = rcline[nextrcline - 1];
  818.       tmptoread = toread[nextrcline - 1];
  819.       tmprcchar = rcchar[nextrcline - 1];
  820.       tmprcnums = rcnums[nextrcline - 1];
  821.       tmpsoftptr = softptr[nextrcline - 1];
  822.  
  823. #ifdef DEBUGGING
  824.       tmpngmax = ngmax[nextrcline - 1];
  825. #endif
  826.  
  827. #ifdef CACHEFIRST
  828.       tmpabs1st = abs1st[nextrcline - 1];
  829. #endif
  830.  
  831.       for (i = nextrcline - 2; i >= newng; i--)
  832.       {
  833.          rcline[i + 1] = rcline[i];
  834.          toread[i + 1] = toread[i];
  835.          rcchar[i + 1] = rcchar[i];
  836.          rcnums[i + 1] = rcnums[i];
  837.          softptr[i + 1] = softptr[i];
  838.  
  839. #ifdef DEBUGGING
  840.          ngmax[i + 1] = ngmax[i];
  841. #endif
  842.  
  843. #ifdef CACHEFIRST
  844.          abs1st[i + 1] = abs1st[i];
  845. #endif
  846.       }
  847.       rcline[newng] = tmprcline;
  848.       toread[newng] = tmptoread;
  849.       rcchar[newng] = tmprcchar;
  850.       rcnums[newng] = tmprcnums;
  851.       softptr[newng] = tmpsoftptr;
  852.  
  853. #ifdef DEBUGGING
  854.       ngmax[newng] = tmpngmax;
  855. #endif
  856.  
  857. #ifdef CACHEFIRST
  858.       abs1st[newng] = tmpabs1st;
  859. #endif
  860.    }
  861.    if (current_ng >= newng)
  862.       current_ng++;
  863.    return newng;
  864. }
  865.  
  866. #endif
  867.  
  868. /* List out the newsrc with annotations */
  869.  
  870. void
  871.   list_newsgroups()
  872. {
  873.    register NG_NUM i;
  874.    char tmpbuf[2048];
  875.    static char *status[] = {"(READ)", "(UNSUB)", "(BOGUS)", "(JUNK)"};
  876.    int cmd;
  877.  
  878.    page_init();
  879.    print_lines("\
  880.   #  Status  Newsgroup\n\
  881. ", STANDOUT);
  882.    for (i = 0; i < nextrcline && !int_count; i++)
  883.    {
  884.       if (toread[i] >= 0)
  885.          set_toread(i);
  886.       *(rcline[i] + rcnums[i] - 1) = rcchar[i];
  887.       if (toread[i] > 0)
  888.          sprintf(tmpbuf, "%3d %6ld   ", i, (long) toread[i]);
  889.       else
  890.          sprintf(tmpbuf, "%3d %7s  ", i, status[-toread[i]]);
  891.       safecpy(tmpbuf + 13, rcline[i], 2034);
  892.       *(rcline[i] + rcnums[i] - 1) = '\0';
  893.       if ((cmd = print_lines(tmpbuf, NOMARKING)) != 0)
  894.       {
  895.          if (cmd > 0)
  896.             pushchar(cmd);
  897.          break;
  898.       }
  899.    }
  900.    int_count = 0;
  901. }
  902.  
  903. /* find a newsgroup in .newsrc */
  904.  
  905. NG_NUM
  906. find_ng(ngnam)
  907.    char *ngnam;
  908. {
  909.    register NG_NUM ngnum;
  910.  
  911. #ifdef HASHNG
  912.    register int hashix = hash(ngnam);
  913.    register int incr = 1;
  914.  
  915.    while ((ngnum = hashtbl[hashix]) >= 0)
  916.    {
  917.       if (strEQ(rcline[ngnum], ngnam) && toread[ngnum] >= TR_UNSUB)
  918.          return ngnum;
  919.       hashix = (hashix + incr) % HASHSIZ;
  920.       incr += 2;             /* offsets from original
  921.                               * are in n*2 */
  922.    }
  923.    return nextrcline;        /* = notfound */
  924.  
  925. #else                        /* just do linear search */
  926.  
  927.    for (ngnum = 0; ngnum < nextrcline; ngnum++)
  928.    {
  929.       if (strEQ(rcline[ngnum], ngnam))
  930.          break;
  931.    }
  932.    return ngnum;
  933. #endif
  934. }
  935.  
  936. void
  937.   cleanup_rc()
  938. {
  939.    register NG_NUM ngx;
  940.    register NG_NUM bogosity = 0;
  941.  
  942. #ifdef VERBOSE
  943.    IF(verbose)
  944.       fputs("Checking out your .newsrc--hang on a second...\n", stdout)
  945.       FLUSH;
  946.    ELSE
  947. #endif
  948.  
  949. #ifdef TERSE
  950.       fputs("Checking .newsrc--hang on...\n", stdout) FLUSH;
  951. #endif
  952.  
  953.    for (ngx = 0; ngx < nextrcline; ngx++)
  954.    {
  955.       if (toread[ngx] >= TR_UNSUB)
  956.       {
  957.          set_toread(ngx);    /* this may reset
  958.                               * newsgroup */
  959.          /* or declare it bogus */
  960.       }
  961.       if (toread[ngx] == TR_BOGUS)
  962.          bogosity++;
  963.    }
  964.    for (ngx = nextrcline - 1; ngx >= 0 && toread[ngx] == TR_BOGUS; ngx--)
  965.       bogosity--;            /* discount already
  966.                               * moved ones */
  967.    if (nextrcline > 5 && bogosity > nextrcline / 2)
  968.    {
  969.       fputs(
  970.             "It looks like the active file is messed up.  Contact your news administrator,\n\
  971. ", stdout);
  972.       fputs(
  973.             "leave the \"bogus\" groups alone, and they may come back to normal.  Maybe.\n\
  974. ", stdout) FLUSH;
  975.    }
  976.  
  977. #ifdef RELOCATE
  978.    else if (bogosity)
  979.    {
  980.  
  981. #ifdef VERBOSE
  982.       IF(verbose)
  983.          fputs("Moving bogus newsgroups to the end of your .newsrc.\n",
  984.                stdout) FLUSH;
  985.       ELSE
  986. #endif
  987.  
  988. #ifdef TERSE
  989.          fputs("Moving boguses to the end.\n", stdout) FLUSH;
  990. #endif
  991.  
  992.       for (; ngx >= 0; ngx--)
  993.       {
  994.          if (toread[ngx] == TR_BOGUS)
  995.             relocate_newsgroup(ngx, nextrcline - 1);
  996.       }
  997.  
  998. #ifdef DELBOGUS
  999. reask_bogus:
  1000.       in_char("Delete bogus newsgroups? [ny] ", 'D');
  1001.       putchar('\n') FLUSH;
  1002.       setdef(buf, "n");
  1003.  
  1004. #ifdef VERIFY
  1005.       printcmd();
  1006. #endif
  1007.  
  1008.       if (*buf == 'h')
  1009.       {
  1010.  
  1011. #ifdef VERBOSE
  1012.          IF(verbose)
  1013.             fputs("\
  1014. Type y to delete bogus newsgroups.\n\
  1015. Type n or SP to leave them at the end in case they return.\n\
  1016. ", stdout) FLUSH;
  1017.          ELSE
  1018. #endif
  1019.  
  1020. #ifdef TERSE
  1021.             fputs("y to delete, n to keep\n", stdout) FLUSH;
  1022. #endif
  1023.  
  1024.          goto reask_bogus;
  1025.       }
  1026.       else if (*buf == 'n' || *buf == 'q')
  1027.          ;
  1028.       else if (*buf == 'y')
  1029.       {
  1030.          while (toread[nextrcline - 1] == TR_BOGUS && nextrcline > 0)
  1031.             --nextrcline;    /* real tough, huh? */
  1032.       }
  1033.       else
  1034.       {
  1035.          fputs(hforhelp, stdout) FLUSH;
  1036.          settle_down();
  1037.          goto reask_bogus;
  1038.       }
  1039. #endif
  1040.    }
  1041. #else
  1042.  
  1043. #ifdef VERBOSE
  1044.    IF(verbose)
  1045.       fputs("You should edit bogus newsgroups out of your .newsrc.\n",
  1046.             stdout) FLUSH;
  1047.    ELSE
  1048. #endif
  1049.  
  1050. #ifdef TERSE
  1051.       fputs("Edit boguses from .newsrc.\n", stdout) FLUSH;
  1052. #endif
  1053.  
  1054. #endif
  1055.  
  1056.    paranoid = FALSE;
  1057. }
  1058.  
  1059. #ifdef HASHNG
  1060. /* make an entry in the hash table for the current newsgroup */
  1061.  
  1062. void
  1063.   sethash(thisng)
  1064.    NG_NUM thisng;
  1065. {
  1066.    register int hashix = hash(rcline[thisng]);
  1067.    register int incr = 1;
  1068.  
  1069. #ifdef DEBUGGING
  1070.    static int hashhits = 0, hashtries = 0;
  1071.  
  1072. #endif
  1073.  
  1074. #ifdef DEBUGGING
  1075.    hashtries++;
  1076. #endif
  1077.  
  1078.    while (hashtbl[hashix] >= 0)
  1079.    {
  1080.  
  1081. #ifdef DEBUGGING
  1082.       hashhits++;
  1083.       if (debug & DEB_HASH)
  1084.       {
  1085.          printf("  Hash hits: %d / %d\n", hashhits, hashtries) FLUSH;
  1086.       }
  1087.       hashtries++;
  1088. #endif
  1089.  
  1090.       hashix = (hashix + incr) % HASHSIZ;
  1091.       incr += 2;             /* offsets from original
  1092.                               * are in n*2 */
  1093.    }
  1094.    hashtbl[hashix] = thisng;
  1095. }
  1096.  
  1097. short prime[] = {1, 2, -3, -5, 7, 11, -13, -17, 19, 23, -29, -31, 37, 41, -43, -47, 53, 57, -59,
  1098. -61, 67, 71, -73, -79, 83, 89, -97, -101, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
  1099.  
  1100. int
  1101.   hash(ngnam)
  1102.    register char *ngnam;
  1103. {
  1104.    register int i = 0;
  1105.    register int ch;
  1106.    register int sum = 0;
  1107.  
  1108. #ifdef DEBUGGING
  1109.    char *ngn = ngnam;
  1110.  
  1111. #endif
  1112.  
  1113.    while ((ch = *ngnam++) != 0)
  1114.    {
  1115.       sum += (ch + i) * prime[i];       /* gives ~ 10% hits at
  1116.                                          * 25% full */
  1117.       i++;
  1118.    }
  1119.  
  1120. #ifdef DEBUGGING
  1121.    if (debug & DEB_HASH)
  1122.       printf("hash(%s) => %d => %d\n", ngn, sum, (sum < 0 ? -sum : sum) % HASHSIZ)
  1123.          FLUSH;
  1124. #endif
  1125.  
  1126.    if (sum < 0)
  1127.       sum = -sum;
  1128.    return sum % HASHSIZ;
  1129. }
  1130.  
  1131. #endif
  1132.  
  1133. void
  1134.   newsrc_check()
  1135. {
  1136.    rcfp = fopen(rcname, "r");/* open it */
  1137.    if (rcfp == Nullfp)
  1138.    {                         /* not there? */
  1139.  
  1140. #ifdef VERBOSE
  1141.       IF(verbose)
  1142.          fputs("\
  1143. Trying to set up a .newsrc file--running newsetup...\n\n\
  1144. ", stdout) FLUSH;
  1145.       ELSE
  1146. #endif
  1147.  
  1148. #ifdef TERSE
  1149.          fputs("Setting up .newsrc...\n", stdout) FLUSH;
  1150. #endif
  1151.  
  1152.       if (doshell(sh, filexp(NEWSETUP)) ||
  1153.             (rcfp = fopen(rcname, "r")) == Nullfp)
  1154.       {
  1155.  
  1156. #ifdef VERBOSE
  1157.          IF(verbose)
  1158.             fputs("\
  1159. Can't create a .newsrc--you must do it yourself.\n\
  1160. ", stdout) FLUSH;
  1161.          ELSE
  1162. #endif
  1163.  
  1164. #ifdef TERSE
  1165.             fputs("(Fatal)\n", stdout) FLUSH;
  1166. #endif
  1167.  
  1168.          finalize(1);
  1169.       }
  1170.    }
  1171.    else
  1172.    {
  1173.  
  1174. #if     unix
  1175.       UNLINK(rcbname);       /* unlink backup file
  1176.                               * name */
  1177.       link(rcname, rcbname); /* and backup current
  1178.                               * name */
  1179. #endif                       /* unix */
  1180.  
  1181. #ifdef msdos
  1182.       UNLINK(rcbname);       /* Get rid of old backup
  1183.                               * file */
  1184.       {
  1185.          FILE *fn;
  1186.          FILE *fo;
  1187.          int i;
  1188.          char buf[128];
  1189.  
  1190.          fo = fopen(rcname, "r");
  1191.          fn = fopen(rcbname, "w");
  1192.          while ((i = fread(buf, sizeof (char), 128, fo)) != 0)
  1193.          {
  1194.             fwrite(buf, sizeof (char), i, fn);
  1195.          }
  1196.          fclose(fo);
  1197.          fclose(fn);
  1198.       }
  1199. #endif
  1200.    }
  1201. }
  1202.  
  1203. /* write out the (presumably) revised .newsrc */
  1204.  
  1205. void
  1206.   write_rc()
  1207. {
  1208.    register NG_NUM tmpng;
  1209.    register char *delim;
  1210.  
  1211.    rcfp = fopen(rctname, "w");  /* open .newsrc */
  1212.    if (rcfp == Nullfp)
  1213.    {
  1214.       printf("Can't recreate .newsrc\n") FLUSH;
  1215.       finalize(1);
  1216.    }
  1217.  
  1218.    /* write out each line */
  1219.  
  1220.    for (tmpng = 0; tmpng < nextrcline; tmpng++)
  1221.    {
  1222.       if (rcnums[tmpng])
  1223.       {
  1224.          delim = rcline[tmpng] + rcnums[tmpng] - 1;
  1225.          *delim = rcchar[tmpng];
  1226.       }
  1227.       else
  1228.          delim = Nullch;
  1229.  
  1230. #ifdef DEBUGGING
  1231.       if (debug & DEB_NEWSRC_LINE)
  1232.          printf("%s\n", rcline[tmpng]) FLUSH;
  1233. #endif
  1234.  
  1235.       fprintf(rcfp, "%s\n", rcline[tmpng]);
  1236.       if (delim)
  1237.          *delim = '\0';      /* might still need this
  1238.                               * line */
  1239.    }
  1240.  
  1241.    fclose(rcfp);             /* close .newsrc */
  1242.    UNLINK(rcname);
  1243.    rename(rctname, rcname);
  1244.  
  1245.    if (writesoft)
  1246.    {
  1247.       tmpfp = fopen(softname, "w");     /* open .rnsoft */
  1248.       if (tmpfp == Nullfp)
  1249.       {
  1250.          printf(cantcreate, softname) FLUSH;
  1251.          return;
  1252.       }
  1253.       for (tmpng = 0; tmpng < nextrcline; tmpng++)
  1254.       {
  1255.          fprintf(tmpfp, "%ld\n", (long) softptr[tmpng]);
  1256.       }
  1257.       fclose(tmpfp);
  1258.    }
  1259. }
  1260.  
  1261. void
  1262.   get_old_rc()
  1263. {
  1264.    UNLINK(rctname);
  1265.    rename(rcname, rctname);
  1266.    rename(rcbname, rcname);
  1267. }
  1268.  
  1269. #ifdef  unix
  1270. rename(old, new)
  1271.    char *old;
  1272.    char *new;
  1273. {
  1274.    register int err;
  1275.  
  1276.    err = link(old, new);
  1277.    if (!err)
  1278.       err = UNLINK(old);
  1279.    return err;
  1280. }
  1281.  
  1282. #endif                       /* unix */
  1283.