home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / relay / sys.c < prev    next >
C/C++ Source or Header  |  1993-02-16  |  9KB  |  349 lines

  1. /*
  2.  * news sys file reading functions
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <ctype.h>
  8. #include <string.h>
  9. #include <errno.h>
  10. #include "fixerrno.h"
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13.  
  14. #include "libc.h"
  15. #include "fgetmfs.h"
  16. #include "news.h"
  17. #include "config.h"
  18. #include "batchnames.h"
  19. #include "ngmatch.h"
  20. #include "system.h"
  21.  
  22. #ifndef CMDPFX
  23. #define CMDPFX "uux - -r -z "    /* prefix of default command */
  24. #endif
  25. #define CMDSFX "!rnews"        /* suffix of same */
  26.  
  27. /* imports */
  28. extern boolean donesys();
  29. extern struct system *mysysincache();
  30. extern void rewsys(), remmysys(), advcurrsys(), setupsys();
  31.  
  32. /* exports */
  33. struct system *firstsys = NULL;    /* cache: 1st sys of in-core sys file */
  34. struct system *currsys = NULL;    /* current system */
  35.  
  36. /* private */
  37. static FILE *fp = NULL;            /* stream for ctlfile(filerelname) */
  38. static char filerelname[] = "sys";    /* filename relative to $NEWSCTL */
  39. static struct parsing {            /* parsing state */
  40.     char *next;
  41. } parsing;
  42.  
  43. struct system *
  44. oursys()            /* return our sys entry */
  45. {
  46.     register struct system *sys = mysysincache();
  47.     static struct system fakesys;
  48.  
  49.     if (sys == NULL) {
  50.         register char *host = hostname();
  51.  
  52.         rewsys(fp);
  53.         while ((sys = nextsys()) != NULL && !STREQ(sys->sy_name, host))
  54.             ;
  55.         if (sys == NULL) {
  56.             /* no entry: cook one up; no need to malloc members */
  57.             sys = &fakesys;
  58.             sys->sy_name = host;
  59.             sys->sy_excl = NULL;
  60.             sys->sy_ngs = "all";
  61.             sys->sy_distr = sys->sy_ngs;
  62.             sys->sy_flags = 0;
  63.             sys->sy_lochops = 0;
  64.             sys->sy_cmd = "";
  65.             sys->sy_trngs = ngparse(strsave(sys->sy_ngs));
  66.             sys->sy_trdistr = sys->sy_trngs;
  67.             sys->sy_next = NULL;
  68.         }
  69.         remmysys(sys);            /* for future reference */
  70.     }
  71.     return sys;
  72. }
  73.  
  74. /*
  75.  * replace "delim" in "field" with a NUL and return the address of the byte
  76.  * after the NUL (the address of the second subfield), or NULL if no
  77.  * "delim" was present.
  78.  */
  79. STATIC char *
  80. reparse(field, delim)
  81. char *field;
  82. register int delim;
  83. {
  84.     register char *delimp;
  85.  
  86.     STRCHR(field, delim, delimp);
  87.     if (delimp != NULL)
  88.         *delimp++ = '\0';
  89.     return delimp;
  90. }
  91.  
  92. /*
  93.  * parse up to a colon, NUL it out and
  94.  * return NULL or ptr. to byte after colon.
  95.  */
  96. STATIC char *
  97. parsecolon(line)
  98. char *line;
  99. {
  100.     return reparse(line, ':');
  101. }
  102.  
  103. /*
  104.  * Parse "next" to colon into malloced storage, return its ptr
  105.  * (freed iff on a small system, in readsys(), see freecursys()).
  106.  */
  107. STATIC char *
  108. parse()
  109. {
  110.     register char *curr = parsing.next;
  111.  
  112.     if (curr != NULL)
  113.         parsing.next = parsecolon(curr);
  114.     return strsave(curr == NULL? "": curr);
  115. }
  116.  
  117. /*
  118.  * Parse sys file flags into sysp.
  119.  */
  120. STATIC void
  121. parseflags(flags, sysp)
  122. register char *flags;
  123. register struct system *sysp;
  124. {
  125.     sysp->sy_flags = 0;
  126.     sysp->sy_lochops = 0;        /* default L value */
  127.     errno = 0;
  128.     for (; *flags != '\0'; flags++)
  129.         switch (*flags) {
  130.         case 'A':
  131.             errunlock("A news format not supported", "");
  132.             /* NOTREACHED */
  133.         case 'B':        /* mostly harmless */
  134.             break;
  135.         case 'f':
  136.             sysp->sy_flags |= FLG_BATCH|FLG_SZBATCH;
  137.             break;
  138.         case 'F':
  139.             sysp->sy_flags |= FLG_BATCH;
  140.             break;
  141.         case 'I':        /* NNTP hook: write msgids, !files */
  142.             sysp->sy_flags |= FLG_BATCH|FLG_IHAVE;
  143.             break;
  144.         case 'L':        /* Ln */
  145.             sysp->sy_flags |= FLG_LOCAL;
  146.             sysp->sy_lochops = 0;
  147.             while (isascii(flags[1]) && isdigit(flags[1])) {
  148.                 sysp->sy_lochops *= 10;
  149.                 sysp->sy_lochops += *++flags - '0';
  150.             }
  151.             break;
  152.         case 'm':        /* send only moderated groups */
  153.             sysp->sy_flags |= FLG_MOD;
  154.             break;
  155.         case 'N':
  156.             errunlock(
  157.     "The N flag is a wasteful old kludge; see the I flag instead.", "");
  158.             /* NOTREACHED */
  159.         case 'n':        /* NNTP hook: write files+msgids */
  160.             sysp->sy_flags |= FLG_BATCH|FLG_NBATCH;
  161.             break;
  162.         case 'u':        /* send only unmoderated groups */
  163.             sysp->sy_flags |= FLG_UNMOD;
  164.             break;
  165.         case 'U':        /* mostly harmless */
  166.             break;
  167.         case 'H':        /* write history entry? sorry */
  168.         case 'S':    /* duplicate the work of the shell.  bzzt */
  169.         case 'M':        /* multicast: obs., see batcher */
  170.         case 'O':        /* multicast: obs., see batcher */
  171.         default:
  172.             errunlock("unknown sys flag `%s' given", flags);
  173.             /* NOTREACHED */
  174.         }
  175. }
  176.  
  177. /* if s contains whitespace, complain and exit */
  178. badspace(s, part, sysp)
  179. char *s, *part;
  180. struct system *sysp;
  181. {
  182.     if (spacein(s)) {
  183.         char *err = str3save("whitespace in ", part,
  184.             " of sys entry for system name `%s'");
  185.  
  186.         errunlock(err, sysp->sy_name);
  187.         /* NOTREACHED */
  188.     }
  189. }
  190.  
  191. /*
  192.  * Parse (and modify) sysline into *currsys, which is malloced here
  193.  * and freed iff on a small system, in readsys(), see freecursys().
  194.  *
  195.  * Side-effect: sysline has a trailing newline removed.
  196.  */
  197. STATIC void
  198. parsesysln(sysline)
  199. register char *sysline;
  200. {
  201.     register struct system *sysp =(struct system *)nemalloc(sizeof *sysp);
  202.     char *flagstring;
  203.  
  204.     trim(sysline);
  205.     parsing.next = sysline;
  206.     sysp->sy_name = parse();
  207.     sysp->sy_ngs = parse();
  208.     flagstring = parse();
  209.     sysp->sy_cmd = parse();
  210.     errno = 0;
  211.     badspace(sysp->sy_name, "system name (or exclusions)", sysp);
  212.     badspace(sysp->sy_ngs, "newsgroups (or distributions)", sysp);
  213.     badspace(flagstring, "flags", sysp);
  214.     /* could check for extra fields here */
  215.  
  216.     parseflags(flagstring, sysp);
  217.     free(flagstring);        /* malloced by parse */
  218.     sysp->sy_next = NULL;
  219.  
  220.     /* reparse for embedded slashes */
  221.     sysp->sy_excl = reparse(sysp->sy_name, '/');
  222.     sysp->sy_distr = reparse(sysp->sy_ngs, '/');
  223.     /*
  224.      * N.B.: ngparse will chew up sy_ngs.  not copying sy_ngs saves
  225.      * a lot of memory when you have a big sys file.
  226.      */
  227.     sysp->sy_trngs = ngparse(sysp->sy_ngs);
  228.     if (sysp->sy_distr == NULL) {    /* default distr is ngs... */
  229.         sysp->sy_distr =   sysp->sy_ngs;
  230.         sysp->sy_trdistr = sysp->sy_trngs;
  231.     } else {
  232.         if (strchr(sysp->sy_distr, '/') != NULL)
  233.             errunlock(
  234.     "slash in distribution subfield of sys entry for system name `%s'",
  235.                 sysp->sy_name);
  236.         /* N.B.: ngparse will chew up sy_distr. */
  237.         sysp->sy_trdistr = ngparse(sysp->sy_distr);
  238.     }
  239.  
  240.     sysdeflt(sysp);            /* fill in any defaults */
  241.  
  242.     /* stash *sysp away on the tail of the current list of systems */
  243.     *(firstsys == NULL? &firstsys: &currsys->sy_next) = sysp;
  244.     currsys = sysp;
  245. }
  246.  
  247. /*
  248.  * On small systems, read one entry; else read whole sys file (done once only).
  249.  * Ignores '#' comments and blank lines; uses cfgetms to read possibly-
  250.  * continued lines of arbitrary length.
  251.  */
  252. STATIC void
  253. readsys()
  254. {
  255.     register char *sysline, *nonblank;
  256.  
  257.     setupsys(fp);        /* reuse currsys or rewind sys file */
  258.     while ((sysline = cfgetms(fp)) != NULL) {
  259.         nonblank = skipsp(sysline);
  260.         if (nonblank[0] != '#' && nonblank[0] != '\n')
  261.             parsesysln(nonblank);
  262.         free(sysline);
  263.         if (donesys())        /* early exit if on disk (small) */
  264.             return;
  265.     }
  266.     (void) nfclose(fp);
  267.     fp = NULL;
  268.     rewsys(fp);
  269. }
  270.  
  271. /*
  272.  * Return the next sys entry, which may span multiple lines.
  273.  * Returned pointer points at a struct whose lifetime (and that of its
  274.  * members) is not promised to last beyond the next call to nextsys();
  275.  * copy it and its pointed-to strings if you need them for longer.
  276.  *
  277.  * Note that readsys() reads one entry on small systems, but the entire
  278.  * sys file on big systems, so the common code in this file is subtle.
  279.  */
  280. struct system *
  281. nextsys()
  282. {
  283.     struct system *retsys;
  284.  
  285.     if (firstsys == NULL && fp == NULL)
  286.         if ((fp = fopenwclex(ctlfile(filerelname), "r")) == NULL)
  287.             return NULL;
  288.     if (fp != NULL && firstsys == NULL)
  289.         readsys();
  290.     retsys = currsys;
  291.     advcurrsys();
  292.     return retsys;
  293. }
  294.  
  295. STATIC void
  296. newartfile(sysp, file)        /* replace sysp->sy_cmd with artfile(file) */
  297. register struct system *sysp;
  298. register char *file;
  299. {
  300.     free(sysp->sy_cmd);        /* malloced by parse */
  301. #ifdef BATCHSPOOL                /* UUNET special */
  302.     sysp->sy_cmd = str3save(BATCHSPOOL, SFNDELIM, file);
  303. #else
  304.     sysp->sy_cmd = strsave(artfile(file));
  305. #endif
  306.     free(file);
  307. }
  308.  
  309. /*
  310.  * fill in defaults in sysp.
  311.  *
  312.  * expand a name of "ME" to hostname().
  313.  * If an empty batch file name was given, supply a default
  314.  * ($NEWSARTS/BTCHPFX system BTCHSFX).
  315.  * Prepend $NEWSARTS/BTCHDIR to relative file names.
  316.  * If an empty command was given, supply a default (uux - -r -z system!rnews).
  317.  * (This *is* yucky and uucp-version-dependent.)
  318.  */
  319. void
  320. sysdeflt(sysp)
  321. register struct system *sysp;
  322. {
  323.     if (STREQ(sysp->sy_name, "ME")) {
  324.         free(sysp->sy_name);    /* malloced by parse */
  325.         sysp->sy_name = strsave(hostname());
  326.     }
  327.     if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] == '\0') {
  328.         register char *deffile =
  329.             str3save(BTCHPFX, sysp->sy_name, BTCHSFX);
  330.  
  331.         /* frees old sysp->sy_cmd, deffile */
  332.         newartfile(sysp, deffile);
  333.     } else if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] != FNDELIM) {
  334.         register char *absfile = str3save(BTCHDIR, sysp->sy_cmd, "");
  335.  
  336.         /* frees old sysp->sy_cmd, absfile */
  337.         newartfile(sysp, absfile);
  338.     } else if (!(sysp->sy_flags&FLG_BATCH) && sysp->sy_cmd[0] == '\0') {
  339.         free(sysp->sy_cmd);    /* malloced by parse */
  340.         sysp->sy_cmd = str3save(CMDPFX, sysp->sy_name, CMDSFX);
  341.     }
  342. }
  343.  
  344. void
  345. rewndsys()
  346. {
  347.     rewsys(fp);
  348. }
  349.