/* * news sys file reading functions */ #include #include #include #include #include #include "fixerrno.h" #include #include #include "libc.h" #include "fgetmfs.h" #include "news.h" #include "config.h" #include "batchnames.h" #include "ngmatch.h" #include "system.h" #ifndef CMDPFX #define CMDPFX "uux - -r -z " /* prefix of default command */ #endif #define CMDSFX "!rnews" /* suffix of same */ /* private */ static FILE *fp = NULL; /* stream for ctlfile(filerelname) */ static char filerelname[] = "sys"; /* filename relative to $NEWSCTL */ /* forward decls */ FORWARD char *parsecolon(), *reparse(); FORWARD void readsys(), parsesysln(), parse(), parseflags(), newartfile(); FORWARD int spacein(); /* exports */ struct system *firstsys = NULL; /* cache: 1st sys of in-core sys file */ struct system *currsys = NULL; /* current system */ /* imports */ extern boolean donesys(); extern struct system *mysysincache(); extern void rewsys(), remmysys(), advcurrsys(), setupsys(); struct system * oursys() /* return our sys entry */ { register struct system *sys = mysysincache(); static struct system fakesys; if (sys == NULL) { register char *host = hostname(); rewsys(fp); while ((sys = nextsys()) != NULL && !STREQ(sys->sy_name, host)) ; if (sys == NULL) { /* no entry: cook one up; no need to malloc members */ sys = &fakesys; sys->sy_name = host; sys->sy_excl = NULL; sys->sy_ngs = "all"; sys->sy_distr = sys->sy_ngs; sys->sy_flags = 0; sys->sy_lochops = 0; sys->sy_cmd = ""; sys->sy_trngs = ngparse(strsave(sys->sy_ngs)); sys->sy_trdistr = sys->sy_trngs; sys->sy_next = NULL; } remmysys(sys); /* for future reference */ } return sys; } /* * Return the next sys entry, which may span multiple lines. * Returned pointer points at a struct whose lifetime (and that of its * members) is not promised to last beyond the next call to nextsys(); * copy it and its pointed-to strings if you need them for longer. * * Note that readsys() reads one entry on small systems, but the entire * sys file on big systems, so the common code in this file is subtle. */ struct system * nextsys() { struct system *retsys; if (firstsys == NULL && fp == NULL) if ((fp = fopenwclex(ctlfile(filerelname), "r")) == NULL) return NULL; if (fp != NULL && firstsys == NULL) readsys(); retsys = currsys; advcurrsys(); return retsys; } /* * On small systems, read one entry; else read whole sys file (done once only). * Ignores '#' comments and blank lines; uses cfgetms to read possibly- * continued lines of arbitrary length. */ STATIC void readsys() { register char *sysline; setupsys(fp); /* reuse currsys or rewind sys file */ while ((sysline = cfgetms(fp)) != NULL) { if (sysline[0] != '#' && sysline[0] != '\n') parsesysln(sysline); free(sysline); if (donesys()) /* early exit if on disk (small) */ return; } (void) nfclose(fp); fp = NULL; rewsys(fp); } static char *curr, *next; /* parsing state */ /* * Parse (and modify) sysline into *currsys, which is malloced here * and freed iff on a small system, in readsys(), see freecursys(). * * Side-effect: sysline has a trailing newline removed. */ STATIC void parsesysln(sysline) register char *sysline; { register struct system *sysp =(struct system *)nemalloc(sizeof *sysp); char *flagstring; trim(sysline); next = sysline; parse(&sysp->sy_name); parse(&sysp->sy_ngs); parse(&flagstring); parse(&sysp->sy_cmd); errno = 0; if (spacein(sysp->sy_name)) errunlock( "whitespace in system name (or exclusions) of sys entry for `%s'", sysp->sy_name); if (spacein(sysp->sy_ngs)) errunlock( "whitespace in newsgroups (or distributions) of sys entry for `%s'", sysp->sy_name); if (spacein(flagstring)) errunlock("whitespace in flags of sys entry for `%s'", sysp->sy_name); /* could check for extra fields here */ parseflags(flagstring, sysp); free(flagstring); /* malloced by parse */ sysp->sy_next = NULL; /* reparse for embedded slashes */ sysp->sy_excl = reparse(sysp->sy_name, '/'); sysp->sy_distr = reparse(sysp->sy_ngs, '/'); /* * N.B.: ngparse will chew up sy_ngs. not copying sy_ngs saves * a lot of memory when you have a big sys file. */ sysp->sy_trngs = ngparse(sysp->sy_ngs); if (sysp->sy_distr == NULL) { /* default distr is ngs... */ sysp->sy_distr = sysp->sy_ngs; sysp->sy_trdistr = sysp->sy_trngs; } else { if (strchr(sysp->sy_distr, '/') != NULL) errunlock( "slash in distribution subfield of sys entry for `%s'", sysp->sy_name); /* N.B.: ngparse will chew up sy_distr. */ sysp->sy_trdistr = ngparse(sysp->sy_distr); } sysdeflt(sysp); /* fill in any defaults */ /* stash *sysp away on the tail of the current list of systems */ *(firstsys == NULL? &firstsys: &currsys->sy_next) = sysp; currsys = sysp; } STATIC int spacein(s) register char *s; { return strchr(s, ' ') != NULL || strchr(s, '\t') != NULL; } /* * fill in defaults in sysp. * * expand a name of "ME" to hostname(). * If an empty batch file name was given, supply a default * ($NEWSARTS/BTCHPFX system BTCHSFX). * Prepend $NEWSARTS/BTCHDIR to relative file names. * If an empty command was given, supply a default (uux - -r -z system!rnews). * (This *is* yucky and uucp-version-dependent.) */ void sysdeflt(sysp) register struct system *sysp; { if (STREQ(sysp->sy_name, "ME")) { free(sysp->sy_name); /* malloced by parse */ sysp->sy_name = strsave(hostname()); } if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] == '\0') { register char *deffile = str3save(BTCHPFX, sysp->sy_name, BTCHSFX); /* frees old sysp->sy_cmd, deffile */ newartfile(sysp, deffile); } else if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] != FNDELIM) { register char *absfile = str3save(BTCHDIR, sysp->sy_cmd, ""); /* frees old sysp->sy_cmd, absfile */ newartfile(sysp, absfile); } else if (!(sysp->sy_flags&FLG_BATCH) && sysp->sy_cmd[0] == '\0') { free(sysp->sy_cmd); /* malloced by parse */ sysp->sy_cmd = str3save(CMDPFX, sysp->sy_name, CMDSFX); } } STATIC void newartfile(sysp, file) /* replace sysp->sy_cmd with artfile(file) */ register struct system *sysp; register char *file; { free(sysp->sy_cmd); /* malloced by parse */ #ifdef BATCHSPOOL /* UUNET special */ sysp->sy_cmd = str3save(BATCHSPOOL, SFNDELIM, file); #else sysp->sy_cmd = strsave(artfile(file)); #endif free(file); } /* * Parse "next" to colon into malloced storage, return its ptr via "into". * *into is freed iff on a small system, in readsys(), see freecursys(). */ STATIC void parse(into) register char **into; { curr = next; if (curr == NULL) *into = strsave(""); else { next = parsecolon(curr); *into = strsave(curr); } } STATIC char * parsecolon(line) /* return NULL or ptr. to byte after colon */ char *line; { register char *colon; STRCHR(line, ':', colon); if (colon != NULL) *colon++ = '\0'; return colon; } /* * replace "delim" in "field" with a NUL and return the address of the byte * after the NUL (the address of the second subfield), or NULL if no * "delim" was present. */ STATIC char * reparse(field, delim) char *field; int delim; { register char *delimp = strchr(field, delim); if (delimp != NULL) *delimp++ = '\0'; return delimp; } /* * Parse sys file flags into sysp. */ STATIC void parseflags(flags, sysp) register char *flags; register struct system *sysp; { sysp->sy_flags = 0; sysp->sy_lochops = 0; /* default L value */ errno = 0; for (; *flags != '\0'; flags++) switch (*flags) { case 'A': errunlock("A news format not supported", ""); /* NOTREACHED */ case 'B': /* mostly harmless */ break; case 'f': sysp->sy_flags |= FLG_BATCH|FLG_SZBATCH; break; case 'F': sysp->sy_flags |= FLG_BATCH; break; case 'I': /* NNTP hook: write msgids, !files */ sysp->sy_flags |= FLG_BATCH|FLG_IHAVE; break; case 'L': /* Ln */ sysp->sy_flags |= FLG_LOCAL; sysp->sy_lochops = 0; while (isascii(flags[1]) && isdigit(flags[1])) { sysp->sy_lochops *= 10; sysp->sy_lochops += *++flags - '0'; } break; case 'm': /* send only moderated groups */ sysp->sy_flags |= FLG_MOD; break; case 'N': errunlock( "The N flag is a wasteful old kludge; see the I flag instead.", ""); /* NOTREACHED */ case 'n': /* NNTP hook: write files+msgids */ sysp->sy_flags |= FLG_BATCH|FLG_NBATCH; break; case 'u': /* send only unmoderated groups */ sysp->sy_flags |= FLG_UNMOD; break; case 'U': /* mostly harmless */ break; case 'H': /* write history entry? sorry */ case 'S': /* duplicate the work of the shell. bzzt */ case 'M': /* multicast: obs., see batcher */ case 'O': /* multicast: obs., see batcher */ default: errunlock("unknown sys flag `%s' given", flags); /* NOTREACHED */ } } void rewndsys() { rewsys(fp); }