home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / relay / transmit.c < prev    next >
C/C++ Source or Header  |  1993-03-13  |  7KB  |  287 lines

  1. /*
  2.  * transmit - transmit incoming articles to neighbouring machines
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <errno.h>
  9. #include "fixerrno.h"
  10. #include <sys/types.h>
  11.  
  12. #include "libc.h"
  13. #include "news.h"
  14. #include "config.h"
  15. #include "headers.h"
  16. #include "active.h"
  17. #include "relay.h"
  18. #include "msgs.h"
  19. #include "ngmatch.h"
  20. #include "system.h"
  21. #include "trbatch.h"
  22.  
  23. /* private */
  24. static boolean debug = NO;
  25.  
  26. void
  27. transdebug(state)
  28. boolean state;
  29. {
  30.     debug = state;
  31. }
  32.  
  33. /*
  34.  * Is it okay to send the article corresponding to "art" to site "sys",
  35.  * excluding site "exclude"?
  36.  *
  37.  * If L(n) flag is on, must have been posted within n hops of here.
  38.  * Never send to this site, nor the "exclude" site, nor any site with a host
  39.  * in sys->sy_excl named in Path:, nor any site named in Path:.
  40.  *
  41.  * Newsgroups: must match sys's subscription list.
  42.  * Distribution: must match sys's distribution list.  (RFC 850 is wrong:
  43.  * Distribution:s are *not* patterns, they are lists.  See RFC 1036.)
  44.  *
  45.  * If m flag is on, group(s) must be moderated; if u flag is on,
  46.  * must be unmoderated.  (If both are on, act as if neither is on.)
  47.  */
  48. STATIC boolean
  49. oktransmit(art, sys, exclude)
  50. register struct article *art;
  51. register struct system *sys;
  52. char *exclude;                /* no copy to him */
  53. {
  54.     register int flags = sys->sy_flags;
  55.     register char *site = sys->sy_name;
  56.     register char *path;
  57.     register int result = YES;
  58.     static char *canpath;
  59.     static long lastid = -1;
  60.  
  61.     if (art->a_id != lastid) {    /* new article? */
  62.         lastid = art->a_id;
  63.         nnfree(&canpath);
  64.         canpath = canonpath(art->h.h_path, art->h.h_approved, art->h.h_sender);
  65.     }
  66.     path = canpath;
  67.     if (flags&FLG_LOCAL && hopcount(path) > sys->sy_lochops ||
  68.         STREQ(hostname(), site) ||
  69.         exclude != NULL && STREQ(exclude, site) || hostin(site, path) ||
  70.         sys->sy_excl != NULL && anyhostin(sys->sy_excl, path) ||
  71.         !ngpatmat(sys->sy_trngs, art->h.h_ngs) ||
  72.         !ngpatmat(sys->sy_trdistr, art->h.h_distr))
  73.         result = NO;
  74.     else if (flags&(FLG_MOD|FLG_UNMOD)) {    /* u, m flag selection */
  75.         if ((flags&(FLG_MOD|FLG_UNMOD)) != (FLG_MOD|FLG_UNMOD))
  76.             result = (flags&FLG_MOD? moderated(art->h.h_ngs):
  77.                         !moderated(art->h.h_ngs));
  78.     }
  79.     return result;
  80. }
  81.  
  82. /*
  83.  * We avoid sprintf if syscmd contains no %, thus avoiding the 128-byte
  84.  * restriction on printf output (see printf(3) BUGS, at least in V7).
  85.  */
  86. STATIC char *                    /* malloced storage */
  87. pctsubst(cmd, file)    /* copy cmd, replace %s in it with file, return copy */
  88. char *cmd, *file;
  89. {
  90.     register char *copy = NULL, *percent, *pcent2 = NULL;
  91.     register int format;
  92.  
  93.     percent = strchr(cmd, '%');
  94.     if (percent == NULL)
  95.         copy = strsave(cmd);
  96.     else {
  97.         ++percent;
  98.         format = *percent;
  99.         if (format != '\0')
  100.             percent++;
  101.         errno = 0;
  102.         pcent2 = strchr(percent, '%');
  103.         if (pcent2 != NULL)
  104.             persistent(NOART, 'f',
  105.                    "sys file command `%s' contains two %%'s",
  106.                    cmd);
  107.         else if (format != 's' && format != '%')
  108.             persistent(NOART, 'f',
  109.     "sys file command `%s' contains format specifier other than %%s", cmd);
  110.         else {
  111.             copy = nemalloc((unsigned)
  112.                 (strlen(cmd) + strlen(file) + SIZENUL));
  113.             (void) sprintf(copy, cmd, file);
  114.         }
  115.     }
  116.     return copy;
  117. }
  118.  
  119. /*
  120.  * Execute sys->sy_cmd with the current article as stdin
  121.  * and filename substituted for %s in sys->sy_cmd (if any).
  122.  *
  123.  * Search path includes $NEWSCTL/bin and $NEWSBIN/relay.
  124.  * redirect stdin to prevent consuming my stdin & so cmd's stdin
  125.  * is filename by default.
  126.  */
  127. void
  128. trcmd(art, sys, filename)
  129. struct article *art;
  130. struct system *sys;
  131. char *filename;
  132. {
  133.     register char *cmd, *substcmd;
  134.     int exitstat;
  135.     char *s1, *s2, *s3, *pfx;
  136.     static char *ctlcmd = NULL, *bincmd = NULL;
  137.  
  138.     if (ctlcmd == NULL)
  139.         ctlcmd = strsave(ctlfile("bin"));
  140.     if (bincmd == NULL)
  141.         bincmd = strsave(binfile("relay"));
  142.  
  143.     s1 = str3save("PATH=", ctlcmd, ":");
  144.     s2 = str3save(bincmd, ":", newspath());
  145.     s3 = str3save("; <", filename, " (");
  146.     pfx = str3save(s1, s2, s3);
  147.     free(s1);
  148.     free(s2);
  149.     free(s3);
  150.  
  151.     errno = 0;
  152.     substcmd = pctsubst(sys->sy_cmd, filename);
  153.     if (substcmd == NULL)
  154.         persistent(art, '\0', "malloc failed", "");
  155.     else {
  156.         cmd = str3save(pfx, substcmd, ")");
  157.         free(substcmd);
  158.     
  159.         exitstat = system(cmd);
  160.         if (exitstat != 0)
  161.             persistent(art, 's', "sys file command `%s' failed",
  162.                 cmd);
  163.         free(cmd);
  164.     }
  165.     free(pfx);
  166. }
  167.  
  168. /*
  169.  * package up article filename, message-id, size, batch file name
  170.  * and formatting flags for batch file "bf".
  171.  */
  172. STATIC void
  173. trappend(art, sys, bf, artname)
  174. register struct article *art;
  175. register struct system *sys;
  176. struct batchfile *bf;
  177. char *artname;
  178. {
  179.     int flag = (sys->sy_flags&FLG_IHAVE? 'I':
  180.            (sys->sy_flags&FLG_NBATCH? 'n':
  181.            (sys->sy_flags&FLG_SZBATCH? 'f': 'F')));
  182.  
  183.     if (!bfappend(bf, flag, sys->sy_cmd,
  184.         artname, art->h.h_msgid, art->a_charswritten))
  185.         fulldisk(art, bf->bf_name);
  186. }
  187.  
  188. /*
  189.  * Append "filename" to sys->sy_cmd.  bsysno is the ordinal # of this batch
  190.  * sys line.  If bsysno is low enough, use the batchfile cache of batch file
  191.  * descriptors.
  192.  */
  193. void
  194. trbatch(art, sys, filename, bsysno)
  195. register struct article *art;
  196. struct system *sys;
  197. char *filename;
  198. register int bsysno;
  199. {
  200.     register struct batchfile *bf = bfopen(sys->sy_cmd, bsysno);
  201.  
  202.     if (bf == NULL || bf->bf_str == NULL)
  203.         persistent(art, '\0', "can't open batch file %s", sys->sy_cmd);
  204.     else {
  205.         trappend(art, sys, bf, filename);
  206.         art->a_status |= bffkclose(bsysno);
  207.     }
  208. }
  209.  
  210. /*
  211.  * Send the article denoted by art to the system denoted by sys.
  212.  *
  213.  * When a filename is needed, we use the first one in art->a_files
  214.  * rather than art->a_tmpf because we want a permanent name.
  215.  *
  216.  * Side-effect: prints the system name on stdout for logging.
  217.  */
  218. STATIC void
  219. ejaculate(art, sys, bsysno)
  220. register struct article *art;
  221. register struct system *sys;
  222. int bsysno;
  223. {
  224.     register char *fullname;
  225.     register char *filename = first(art->a_files);
  226.  
  227.     if (debug)
  228.         (void) fprintf(stderr, "transmitting %s to %s\n",
  229.                    art->h.h_msgid, sys->sy_name);
  230.         (void) printf(" %s", sys->sy_name);    /* logging */
  231.  
  232.     mkfilenm(filename);
  233.     fullname = strsave(artfile(filename));    /* N.B.: relative path */
  234.     free(filename);
  235.  
  236.     if (sys->sy_flags&FLG_BATCH)
  237.             trbatch(art, sys, fullname, bsysno);
  238.     else
  239.         trcmd(art, sys, fullname);
  240.     free(fullname);
  241. }
  242.  
  243. /*
  244.  * For each system in "sys" other than this one,
  245.  * transmit this article when its ng pattern matches
  246.  * art->h.h_distr (which may be just a copy of art->h.h_ngs).
  247.  */
  248. void
  249. transmit(art, exclude)
  250. register struct article *art;
  251. char *exclude;                    /* no copy to this site */
  252. {
  253.     register struct system *sys;
  254.     register int bsysno = 0;    /* ordinal # of batch sys entry */
  255.  
  256.     rewndsys();
  257.     if (debug)
  258.         (void) fprintf(stderr, "just rewound sys file\n");
  259.     while ((sys = nextsys()) != NULL) {
  260.         if (debug) {
  261.             (void) fprintf(stderr, "sy_name=%s sy_ngs=",
  262.                 sys->sy_name);
  263.             ngprint(sys->sy_trngs, stderr);
  264.             (void) fprintf(stderr, " sy_distr=");
  265.             ngprint(sys->sy_trdistr, stderr);
  266.             (void) fprintf(stderr, "\n");
  267.         }
  268.         if (oktransmit(art, sys, exclude))
  269.             ejaculate(art, sys, bsysno);
  270.         if (sys->sy_flags&FLG_BATCH)
  271.             ++bsysno;
  272.     }
  273.     if (debug)
  274.         (void) fprintf(stderr, "just finished reading sys file\n");
  275. }
  276.  
  277. /*
  278.  * really close all the open batch files
  279.  */
  280. statust
  281. trclose()
  282. {
  283.     extern statust trrealclose();
  284.  
  285.     return trrealclose();
  286. }
  287.