home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / readnews / newsrc.c < prev    next >
C/C++ Source or Header  |  1995-04-27  |  7KB  |  314 lines

  1. /*
  2.  * newsrc file handling
  3.  */
  4.  
  5. #include "defs.h"
  6.  
  7. static char nrcname[]     = NEWSRC;
  8.  
  9. static char *rcname;        /* full pathname of .newsrc */
  10. newsrc *rc;            /* internal .newsrc */
  11. char *rcgrps;            /* subscription from .newsrc */
  12. static newsrc *lastrc;        /* last newsrc struct in list */
  13. static int rclineno;        /* current lineno in .newsrc */
  14. static bool sortrc;        /* if we should sort on output */
  15.  
  16. static newsrc *findnewsrc();
  17. static int getline();
  18. static int dooptions();
  19. static int dorcline();
  20. static int writengline();
  21.  
  22. readnewsrc()
  23. {
  24.     register FILE *f;
  25.     static char option[] = "options";
  26.     char word[BUFSIZ], rest[BUFSIZ];    /* getline knows sizes */
  27.     extern char *getenv();
  28.  
  29.     if ((rcname = getenv("HOME")) == NULL)
  30.         error("No $HOME in environment.");
  31.     rcname = newstr3(rcname, "/", nrcname);
  32.     if ((f = fopen(rcname, "r")) == NULL)
  33.         return;
  34.  
  35.     rclineno = 0;
  36.     while (getline(f, word, rest))
  37.         if (CMP(word, option) == 0)
  38.             dooptions(rest);
  39.         else
  40.             dorcline(word, rest);
  41.     (void) fclose(f);
  42. }
  43.  
  44. /*
  45.  * Read a line from f, put first word into w and the rest into r.
  46.  * Discard trailing newline instead of storing it.
  47.  * This is a poor design, as w & r are unchecked for overrun.
  48.  */
  49. static int
  50. getline(f, w, r)
  51. register FILE *f;
  52. char *w, *r;
  53. {
  54.     register int c;
  55.     register char *s;
  56.     register int n;
  57.  
  58.     rclineno++;
  59.     s = w;
  60.     n = BUFSIZ-1;
  61.     while ((c = getc(f)) != EOF && c != ' ' && c != '\t')
  62.         if (n > 0) {
  63.             *s++ = c;            /* stash first word */
  64.             n--;
  65.         }
  66.     *s = '\0';
  67.     if (n <= 0)
  68.         error("%s line %d too long", rcname, rclineno);
  69.  
  70.     if (c != EOF) {
  71.         s = r;
  72.         n = BUFSIZ-1;
  73.         while ((c = getc(f)) != EOF && c != '\n')
  74.             if (n > 0) {
  75.                 *s++ = c;        /* stash the rest */
  76.                 n--;
  77.             }
  78.         *s = '\0';
  79.         if (n <= 0)
  80.             error("%s line %d too long", rcname, rclineno);
  81.     }
  82.  
  83.     if (c != '\n' && c != EOF)
  84.         error("Bad format: %s line %d: %s", rcname, rclineno, w);
  85.  
  86.     return c != EOF;
  87. }
  88.  
  89. /*
  90.  * Parse s into words and simulate command line arguments with them.
  91.  */
  92. static int
  93. dooptions(s)
  94. char *s;
  95. {
  96.     register char *cp;
  97.     register int argc;
  98.     register char **argv;
  99.  
  100.     cp = s;
  101.     while (isspace(*cp))
  102.         cp++;
  103.     if (!*cp)
  104.         return;
  105.  
  106.     argc = 2;
  107.     argv = (char **) myalloc(2 * sizeof(char *));
  108.     argv[0] = "options";
  109.     argv[argc - 1] = cp;
  110.     while (*cp && (cp = strpbrk(cp, " \t")) != NULL) {
  111.         while (*cp == ' ' || *cp == '\t')
  112.             *cp++ = '\0';
  113.         if (*cp) {
  114.             argc++;
  115.             argv = (char **) myrealloc((char *) argv,
  116.                 argc * (int)sizeof(char *));
  117.             argv[argc - 1] = cp;
  118.         }
  119.     }
  120.     if (options(argc, argv, false) < 0)
  121.         error("Bad options: %s line %d: %s", rcname, rclineno, s);
  122.     free((char *) argv);
  123. }
  124.  
  125. /*
  126.  * Parse w & r together as a .newsrc newsgroup line.
  127.  */
  128. static int
  129. dorcline(w, r)
  130. char *w, *r;
  131. {
  132.     register char lastw;
  133.     register int len;
  134.     register newsrc    *np;
  135.  
  136.     len = strlen(w);
  137.     lastw = w[len - 1];            /* save presumed colon or bang */
  138.     w[len - 1] = '\0';            /* nuke presumed colon */
  139.     while (*r == ' ' || *r == '\t')
  140.         r++;                /* skip extra whitespace */
  141.  
  142.     /* kludges, hacks, etc. for compatibility with other readers */
  143.     if (strncmp(r, "1-", sizeof "1-"-1) == 0)
  144.         r += sizeof "1-"-1;        /* skip usual `1-' */
  145.     if (*r == '\0')                /* rn's: `news.trash: ' */
  146.         r = "0";            /* fake a zero */
  147.  
  148.     if (lastw != ':' && lastw != NEGCHAR || !isdigit(*r))
  149.         error("Bad line: %s line %d: %s", rcname, rclineno, w);
  150.  
  151.     np = NEW(newsrc);
  152.     np->n_subscribe = (bool) (lastw == ':');    /* colon or bang? */
  153.     np->n_next = NIL(newsrc);
  154.     np->n_last = atoi(r);            /* stash first number only */
  155.     np->n_name = newstr(w);            /* stash n.g. name */
  156.  
  157.     if (rc == 0)
  158.         rc = np;
  159.     else
  160.         lastrc->n_next = np;
  161.     lastrc = np;
  162. }
  163.  
  164. /*
  165.  * for every group in active list, which belongs to the specified subscription
  166.  * list, and has messages to be read, call func
  167.  * if no mention in newsrc file, make new entry
  168.  */
  169. apply(alist, group, func, dolast)
  170. active *alist;
  171. char *group;
  172. applycom (*func)();
  173. bool dolast;
  174. {
  175.     register active *ap;
  176.     register newsrc *np;
  177.     register applycom act;
  178.     register bool donesome;
  179.  
  180.     donesome = false;
  181.     do {
  182.         act = stop;
  183.         for (ap = alist; ap; ap = ap->a_next) {
  184.             if (ap->a_seq == 0 || ap->a_low > ap->a_seq)
  185.                 continue;    /* empty group */
  186.             if (!ngmatch(ap->a_name, group))
  187.                 continue;
  188.             if ((np = findnewsrc(ap->a_name)) == NULL) {
  189.                 np = NEW(newsrc);
  190.                 np->n_name = newstr(ap->a_name);
  191.                 np->n_next = NULL;
  192.                 np->n_last = 0;
  193.                 np->n_subscribe = true;
  194.                 if (!rc)
  195.                     rc = np;
  196.                 else
  197.                     lastrc->n_next = np;
  198.                 lastrc = np;
  199.             }
  200.             if (!np->n_subscribe)
  201.                 continue;
  202.             /*
  203.              * if we haven't read any news for a while (or at all),
  204.              * or somehow seq got smaller (active corrupted?),
  205.              * set last read to oldest available article
  206.              */
  207.             if (ap->a_low - 1 > np->n_last || ap->a_seq < np->n_last)
  208.                 np->n_last = ap->a_low - 1;
  209.             while (np->n_last < ap->a_seq) {
  210.                 donesome = true;
  211.                 switch (act = (*func)(ap, np, false, false)) {
  212.                 case stop:        
  213.                     return;
  214.                 case next:        
  215.                     continue;
  216.                 case nextgroup:        
  217.                     break;
  218.                 case searchgroup:    
  219.                     break;
  220.                 }
  221.                 break;
  222.             }                /* while */
  223.             if (act == searchgroup)
  224.                 break;
  225.         }                    /* for */
  226.         if (act != searchgroup && dolast && donesome)
  227.             act = (*func)(NIL(active), NIL(newsrc), true, false);
  228.     } while (act == searchgroup);
  229. }
  230.  
  231. /*
  232.  * find if a newsrc entry exists,
  233.  * taking advantange of the fact that requests should be
  234.  * in the same order
  235.  *
  236.  * detect when the newsrc gets out of order
  237.  * so it can be sorted at the end of the session
  238.  */
  239. static newsrc *
  240. findnewsrc(name)
  241. register char *name;
  242. {
  243.     register newsrc *np, *start;
  244.     register bool found;
  245.     static newsrc *nextp;
  246.  
  247.     if (!rc)
  248.         return NULL;
  249.  
  250.     found = false;
  251.     np = nextp ? nextp : rc;
  252.     nextp = start = np;
  253.     do {
  254.         if (CMP(np->n_name, name) == 0) {
  255.             found = true;
  256.             break;
  257.         }
  258.         np = np->n_next;
  259.         if (!np)
  260.             np = rc;
  261.     } while (np != nextp);
  262.  
  263.     if (!found)
  264.         return NIL(newsrc);
  265.     nextp = np->n_next;
  266.     if (np != start)
  267.         sortrc = true;
  268.     return np;
  269. }
  270.  
  271. /*
  272.  * rewrite the newsrc file
  273.  */
  274. writenewsrc(alist)
  275. active *alist;
  276. {
  277.     register FILE *f;
  278.     register active    *ap;
  279.     register newsrc    *np;
  280.     register int i;
  281.     extern int usize;
  282.  
  283.     if (!rc && (!rcgrps || !*rcgrps))
  284.         return;
  285.  
  286.     signal(SIGINT, SIG_IGN);
  287.     signal(SIGQUIT, SIG_IGN);
  288.  
  289.     f = fopenf(rcname, "w");
  290.     if (rcgrps && *rcgrps)
  291.         (void) fprintf(f, "options -n %s\n", rcgrps);
  292.     if (sortrc) {
  293.         /*
  294.          * sort newsrc so next time we use it,
  295.          * history/newsrc comparisons will be faster
  296.          */
  297.         for (ap = alist; ap; ap = ap->a_next)
  298.             if (np = findnewsrc(ap->a_name))
  299.                 writengline(f, np);
  300.     } else
  301.         for (np = rc; np; np = np->n_next)
  302.             writengline(f, np);
  303.     (void) fclose(f);
  304. }
  305.  
  306. static int
  307. writengline(f, np)        /* write .newsrc n.g. line in normal form on f */
  308. FILE *f;
  309. register newsrc *np;
  310. {
  311.     (void) fprintf(f, "%s%c 1-%d\n", np->n_name,
  312.         (np->n_subscribe? ':': NEGCHAR), np->n_last);
  313. }
  314.