home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume23 / trn / part07 / rcstuff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-22  |  24.4 KB  |  1,055 lines

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