home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / trn-3.3 / part08 / rcstuff.c < prev    next >
C/C++ Source or Header  |  1993-11-27  |  26KB  |  1,074 lines

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