home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Unix System Administration Handbook 1997 October
/
usah_oct97.iso
/
news
/
cnews.tar
/
relay
/
transmit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-13
|
7KB
|
287 lines
/*
* transmit - transmit incoming articles to neighbouring machines
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "fixerrno.h"
#include <sys/types.h>
#include "libc.h"
#include "news.h"
#include "config.h"
#include "headers.h"
#include "active.h"
#include "relay.h"
#include "msgs.h"
#include "ngmatch.h"
#include "system.h"
#include "trbatch.h"
/* private */
static boolean debug = NO;
void
transdebug(state)
boolean state;
{
debug = state;
}
/*
* Is it okay to send the article corresponding to "art" to site "sys",
* excluding site "exclude"?
*
* If L(n) flag is on, must have been posted within n hops of here.
* Never send to this site, nor the "exclude" site, nor any site with a host
* in sys->sy_excl named in Path:, nor any site named in Path:.
*
* Newsgroups: must match sys's subscription list.
* Distribution: must match sys's distribution list. (RFC 850 is wrong:
* Distribution:s are *not* patterns, they are lists. See RFC 1036.)
*
* If m flag is on, group(s) must be moderated; if u flag is on,
* must be unmoderated. (If both are on, act as if neither is on.)
*/
STATIC boolean
oktransmit(art, sys, exclude)
register struct article *art;
register struct system *sys;
char *exclude; /* no copy to him */
{
register int flags = sys->sy_flags;
register char *site = sys->sy_name;
register char *path;
register int result = YES;
static char *canpath;
static long lastid = -1;
if (art->a_id != lastid) { /* new article? */
lastid = art->a_id;
nnfree(&canpath);
canpath = canonpath(art->h.h_path, art->h.h_approved, art->h.h_sender);
}
path = canpath;
if (flags&FLG_LOCAL && hopcount(path) > sys->sy_lochops ||
STREQ(hostname(), site) ||
exclude != NULL && STREQ(exclude, site) || hostin(site, path) ||
sys->sy_excl != NULL && anyhostin(sys->sy_excl, path) ||
!ngpatmat(sys->sy_trngs, art->h.h_ngs) ||
!ngpatmat(sys->sy_trdistr, art->h.h_distr))
result = NO;
else if (flags&(FLG_MOD|FLG_UNMOD)) { /* u, m flag selection */
if ((flags&(FLG_MOD|FLG_UNMOD)) != (FLG_MOD|FLG_UNMOD))
result = (flags&FLG_MOD? moderated(art->h.h_ngs):
!moderated(art->h.h_ngs));
}
return result;
}
/*
* We avoid sprintf if syscmd contains no %, thus avoiding the 128-byte
* restriction on printf output (see printf(3) BUGS, at least in V7).
*/
STATIC char * /* malloced storage */
pctsubst(cmd, file) /* copy cmd, replace %s in it with file, return copy */
char *cmd, *file;
{
register char *copy = NULL, *percent, *pcent2 = NULL;
register int format;
percent = strchr(cmd, '%');
if (percent == NULL)
copy = strsave(cmd);
else {
++percent;
format = *percent;
if (format != '\0')
percent++;
errno = 0;
pcent2 = strchr(percent, '%');
if (pcent2 != NULL)
persistent(NOART, 'f',
"sys file command `%s' contains two %%'s",
cmd);
else if (format != 's' && format != '%')
persistent(NOART, 'f',
"sys file command `%s' contains format specifier other than %%s", cmd);
else {
copy = nemalloc((unsigned)
(strlen(cmd) + strlen(file) + SIZENUL));
(void) sprintf(copy, cmd, file);
}
}
return copy;
}
/*
* Execute sys->sy_cmd with the current article as stdin
* and filename substituted for %s in sys->sy_cmd (if any).
*
* Search path includes $NEWSCTL/bin and $NEWSBIN/relay.
* redirect stdin to prevent consuming my stdin & so cmd's stdin
* is filename by default.
*/
void
trcmd(art, sys, filename)
struct article *art;
struct system *sys;
char *filename;
{
register char *cmd, *substcmd;
int exitstat;
char *s1, *s2, *s3, *pfx;
static char *ctlcmd = NULL, *bincmd = NULL;
if (ctlcmd == NULL)
ctlcmd = strsave(ctlfile("bin"));
if (bincmd == NULL)
bincmd = strsave(binfile("relay"));
s1 = str3save("PATH=", ctlcmd, ":");
s2 = str3save(bincmd, ":", newspath());
s3 = str3save("; <", filename, " (");
pfx = str3save(s1, s2, s3);
free(s1);
free(s2);
free(s3);
errno = 0;
substcmd = pctsubst(sys->sy_cmd, filename);
if (substcmd == NULL)
persistent(art, '\0', "malloc failed", "");
else {
cmd = str3save(pfx, substcmd, ")");
free(substcmd);
exitstat = system(cmd);
if (exitstat != 0)
persistent(art, 's', "sys file command `%s' failed",
cmd);
free(cmd);
}
free(pfx);
}
/*
* package up article filename, message-id, size, batch file name
* and formatting flags for batch file "bf".
*/
STATIC void
trappend(art, sys, bf, artname)
register struct article *art;
register struct system *sys;
struct batchfile *bf;
char *artname;
{
int flag = (sys->sy_flags&FLG_IHAVE? 'I':
(sys->sy_flags&FLG_NBATCH? 'n':
(sys->sy_flags&FLG_SZBATCH? 'f': 'F')));
if (!bfappend(bf, flag, sys->sy_cmd,
artname, art->h.h_msgid, art->a_charswritten))
fulldisk(art, bf->bf_name);
}
/*
* Append "filename" to sys->sy_cmd. bsysno is the ordinal # of this batch
* sys line. If bsysno is low enough, use the batchfile cache of batch file
* descriptors.
*/
void
trbatch(art, sys, filename, bsysno)
register struct article *art;
struct system *sys;
char *filename;
register int bsysno;
{
register struct batchfile *bf = bfopen(sys->sy_cmd, bsysno);
if (bf == NULL || bf->bf_str == NULL)
persistent(art, '\0', "can't open batch file %s", sys->sy_cmd);
else {
trappend(art, sys, bf, filename);
art->a_status |= bffkclose(bsysno);
}
}
/*
* Send the article denoted by art to the system denoted by sys.
*
* When a filename is needed, we use the first one in art->a_files
* rather than art->a_tmpf because we want a permanent name.
*
* Side-effect: prints the system name on stdout for logging.
*/
STATIC void
ejaculate(art, sys, bsysno)
register struct article *art;
register struct system *sys;
int bsysno;
{
register char *fullname;
register char *filename = first(art->a_files);
if (debug)
(void) fprintf(stderr, "transmitting %s to %s\n",
art->h.h_msgid, sys->sy_name);
(void) printf(" %s", sys->sy_name); /* logging */
mkfilenm(filename);
fullname = strsave(artfile(filename)); /* N.B.: relative path */
free(filename);
if (sys->sy_flags&FLG_BATCH)
trbatch(art, sys, fullname, bsysno);
else
trcmd(art, sys, fullname);
free(fullname);
}
/*
* For each system in "sys" other than this one,
* transmit this article when its ng pattern matches
* art->h.h_distr (which may be just a copy of art->h.h_ngs).
*/
void
transmit(art, exclude)
register struct article *art;
char *exclude; /* no copy to this site */
{
register struct system *sys;
register int bsysno = 0; /* ordinal # of batch sys entry */
rewndsys();
if (debug)
(void) fprintf(stderr, "just rewound sys file\n");
while ((sys = nextsys()) != NULL) {
if (debug) {
(void) fprintf(stderr, "sy_name=%s sy_ngs=",
sys->sy_name);
ngprint(sys->sy_trngs, stderr);
(void) fprintf(stderr, " sy_distr=");
ngprint(sys->sy_trdistr, stderr);
(void) fprintf(stderr, "\n");
}
if (oktransmit(art, sys, exclude))
ejaculate(art, sys, bsysno);
if (sys->sy_flags&FLG_BATCH)
++bsysno;
}
if (debug)
(void) fprintf(stderr, "just finished reading sys file\n");
}
/*
* really close all the open batch files
*/
statust
trclose()
{
extern statust trrealclose();
return trrealclose();
}