home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 1 / GoldFishApril1994_CD2.img / d4xx / d473 / cnewssrc / cnews_src.lzh / relay / transmit.c < prev    next >
C/C++ Source or Header  |  1991-01-07  |  8KB  |  301 lines

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