home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / trn / part09 / rcstuff.c < prev   
Encoding:
C/C++ Source or Header  |  1991-12-02  |  27.0 KB  |  1,185 lines

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