home *** CD-ROM | disk | FTP | other *** search
- /*
- * newsrc file handling
- */
-
- #include "defs.h"
-
- static char nrcname[] = NEWSRC;
-
- static char *rcname; /* full pathname of .newsrc */
- newsrc *rc; /* internal .newsrc */
- char *rcgrps; /* subscription from .newsrc */
- static newsrc *lastrc; /* last newsrc struct in list */
- static int rclineno; /* current lineno in .newsrc */
- static bool sortrc; /* if we should sort on output */
-
- static newsrc *findnewsrc();
-
- readnewsrc()
- {
- register FILE *f;
- static char option[] = "options";
- char word[BUFSIZ], rest[BUFSIZ]; /* getline knows sizes */
- extern char *getenv();
-
- if ((rcname = getenv("HOME")) == NULL)
- error("No $HOME in environment.");
- rcname = newstr3(rcname, "/", nrcname);
- if ((f = fopen(rcname, "r")) == NULL)
- return;
-
- rclineno = 0;
- while (getline(f, word, rest))
- if (CMP(word, option) == 0)
- dooptions(rest);
- else
- dorcline(word, rest);
- (void) fclose(f);
- }
-
- /*
- * Read a line from f, put first word into w and the rest into r.
- * Discard trailing newline instead of storing it.
- * This is a poor design, as w & r are unchecked for overrun.
- */
- static
- getline(f, w, r)
- register FILE *f;
- char *w, *r;
- {
- register int c;
- register char *s;
- register int n;
-
- rclineno++;
- s = w;
- n = BUFSIZ-1;
- while ((c = getc(f)) != EOF && c != ' ' && c != '\t')
- if (n > 0) {
- *s++ = c; /* stash first word */
- n--;
- }
- *s = '\0';
- if (n <= 0)
- error("%s line %d too long", rcname, rclineno);
-
- if (c != EOF) {
- s = r;
- n = BUFSIZ-1;
- while ((c = getc(f)) != EOF && c != '\n')
- if (n > 0) {
- *s++ = c; /* stash the rest */
- n--;
- }
- *s = '\0';
- if (n <= 0)
- error("%s line %d too long", rcname, rclineno);
- }
-
- if (c != '\n' && c != EOF)
- error("Bad format: %s line %d: %s", rcname, rclineno, w);
-
- return c != EOF;
- }
-
- /*
- * Parse s into words and simulate command line arguments with them.
- */
- static
- dooptions(s)
- char *s;
- {
- register char *cp;
- register int argc;
- register char **argv;
-
- cp = s;
- while (isspace(*cp))
- cp++;
- if (!*cp)
- return;
-
- argc = 1;
- argv = (char **) myalloc(sizeof(char *));
- argv[argc - 1] = cp;
- while (*cp && (cp = strpbrk(cp, " \t")) != NULL) {
- while (*cp == ' ' || *cp == '\t')
- *cp++ = '\0';
- if (*cp) {
- argc++;
- argv = (char **) myrealloc((char *) argv,
- argc * (int)sizeof(char *));
- argv[argc - 1] = cp;
- }
- }
- if (options(argc, argv, false))
- error("Bad options: %s line %d: %s", rcname, rclineno, s);
- free((char *) argv);
- }
-
- /*
- * Parse w & r together as a .newsrc newsgroup line.
- */
- static
- dorcline(w, r)
- char *w, *r;
- {
- register char lastw;
- register int len;
- register newsrc *np;
-
- len = strlen(w);
- lastw = w[len - 1]; /* save presumed colon or bang */
- w[len - 1] = '\0'; /* nuke presumed colon */
- while (*r == ' ' || *r == '\t')
- r++; /* skip extra whitespace */
-
- /* kludges, hacks, etc. for compatibility with other readers */
- if (strncmp(r, "1-", sizeof "1-"-1) == 0)
- r += sizeof "1-"-1; /* skip usual `1-' */
- if (*r == '\0') /* rn's: `news.trash: ' */
- r = "0"; /* fake a zero */
-
- if (lastw != ':' && lastw != NEGCHAR || !isdigit(*r))
- error("Bad line: %s line %d: %s", rcname, rclineno, w);
-
- np = NEW(newsrc);
- np->n_subscribe = (bool) (lastw == ':'); /* colon or bang? */
- np->n_next = NIL(newsrc);
- np->n_last = atoi(r); /* stash first number only */
- np->n_name = newstr(w); /* stash n.g. name */
-
- if (rc == 0)
- rc = np;
- else
- lastrc->n_next = np;
- lastrc = np;
- }
-
- /*
- * for every group in active list, which belongs to the specified subscription
- * list, and has messages to be read, call func
- * if no mention in newsrc file, make new entry
- */
- apply(alist, group, func, dolast)
- active *alist;
- char *group;
- applycom (*func)();
- bool dolast;
- {
- register active *ap;
- register newsrc *np;
- register applycom act;
- register bool donesome;
-
- donesome = false;
- do {
- act = stop;
- for (ap = alist; ap; ap = ap->a_next) {
- if (ap->a_seq == 0 || ap->a_low > ap->a_seq)
- continue; /* empty group */
- if (!ngmatch(ap->a_name, group))
- continue;
- if ((np = findnewsrc(ap->a_name)) == NULL) {
- np = NEW(newsrc);
- np->n_name = newstr(ap->a_name);
- np->n_next = NULL;
- np->n_last = 0;
- np->n_subscribe = true;
- if (!rc)
- rc = np;
- else
- lastrc->n_next = np;
- lastrc = np;
- }
- if (!np->n_subscribe)
- continue;
- /*
- * if we haven't read any news for a while (or at all),
- * or somehow seq got smaller (active corrupted?),
- * set last read to oldest available article
- */
- if (ap->a_low - 1 > np->n_last || ap->a_seq < np->n_last)
- np->n_last = ap->a_low - 1;
- while (np->n_last < ap->a_seq) {
- donesome = true;
- switch (act = (*func)(ap, np, false, false)) {
- case stop:
- return;
- case next:
- continue;
- case nextgroup:
- break;
- case searchgroup:
- break;
- }
- break;
- } /* while */
- if (act == searchgroup)
- break;
- } /* for */
- if (act != searchgroup && dolast && donesome)
- act = (*func)(NIL(active), NIL(newsrc), true, false);
- } while (act == searchgroup);
- }
-
- /*
- * find if a newsrc entry exists,
- * taking advantange of the fact that requests should be
- * in the same order
- *
- * detect when the newsrc gets out of order
- * so it can be sorted at the end of the session
- */
- static newsrc *
- findnewsrc(name)
- register char *name;
- {
- register newsrc *np, *start;
- register bool found;
- static newsrc *nextp;
-
- if (!rc)
- return NULL;
-
- found = false;
- np = nextp ? nextp : rc;
- nextp = start = np;
- do {
- if (CMP(np->n_name, name) == 0) {
- found = true;
- break;
- }
- np = np->n_next;
- if (!np)
- np = rc;
- } while (np != nextp);
-
- if (!found)
- return NIL(newsrc);
- nextp = np->n_next;
- if (np != start)
- sortrc = true;
- return np;
- }
-
- /*
- * rewrite the newsrc file
- */
- writenewsrc(alist)
- active *alist;
- {
- register FILE *f;
- register active *ap;
- register newsrc *np;
- register int i;
- extern int usize;
-
- if (!rc && (!rcgrps || !*rcgrps))
- return;
-
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
-
- f = fopenf(rcname, "w");
- if (rcgrps && *rcgrps)
- (void) fprintf(f, "options -n %s\n", rcgrps);
- if (sortrc) {
- /*
- * sort newsrc so next time we use it,
- * history/newsrc comparisons will be faster
- */
- for (ap = alist; ap; ap = ap->a_next)
- if (np = findnewsrc(ap->a_name))
- writengline(f, np);
- } else
- for (np = rc; np; np = np->n_next)
- writengline(f, np);
- (void) fclose(f);
- }
-
- static
- writengline(f, np) /* write .newsrc n.g. line in normal form on f */
- FILE *f;
- register newsrc *np;
- {
- (void) fprintf(f, "%s%c 1-%d\n", np->n_name,
- (np->n_subscribe? ':': NEGCHAR), np->n_last);
- }
-