home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / trn_12.zip / src / rcstuff.c < prev    next >
C/C++ Source or Header  |  1993-12-04  |  29KB  |  1,197 lines

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