home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
300-399
/
ff319.lzh
/
CNewsSrc
/
cnews.orig.lzh
/
relay
/
transmit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-06-27
|
8KB
|
277 lines
/*
* transmit - transmit incoming articles to neighbouring machines
*/
#include <stdio.h>
#include <sys/types.h>
#include "libc.h"
#include "news.h"
#include "config.h"
#include "headers.h"
#include "active.h"
#include "article.h"
#include "msgs.h"
#include "system.h"
#include "trbatch.h"
#include "transmit.h"
/* forwards */
FORWARD boolean oktransmit();
FORWARD void ejaculate(), trappend();
/* private */
static boolean debug = NO;
void
transdebug(state)
boolean state;
{
debug = state;
}
/*
* 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=%s sy_distr=%s\n",
sys->sy_name, sys->sy_ngs, sys->sy_distr);
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");
}
/*
* 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 =
canonpath(art->h.h_path, art->h.h_approved, art->h.h_sender);
register int result;
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) ||
!ngmatch(sys->sy_ngs, art->h.h_ngs) ||
!ngmatch(sys->sy_distr, 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 = YES; /* too silly */
else
result = (flags&FLG_MOD? moderated(art->h.h_ngs):
!moderated(art->h.h_ngs));
} else
result = YES;
free(path);
return result;
}
/*
* 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, and
* translate it to a full path name to avoid ambiguity.
*
* 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; /* sometimes is a message-id */
if (debug)
(void) fprintf(stderr, "transmitting %s to %s\n",
art->h.h_msgid, sys->sy_name);
(void) printf(" %s", sys->sy_name); /* logging */
if (sys->sy_flags&FLG_IHAVE)
fullname = art->h.h_msgid;
else {
register char *filename = first(art->a_files);
mkfilenm(filename);
fullname = fullartfile(filename);
free(filename);
}
#ifdef PARANOID
fullname = strsave(fullname);
#endif
if (sys->sy_flags&FLG_BATCH)
trbatch(art, sys, fullname, bsysno);
else
trcmd(art, sys, fullname);
#ifdef PARANOID
free(fullname);
#endif
}
/*
* 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.
*
* We use strcat instead of sprintf if syscmd contains no %.
* this avoids the 128-byte restriction on printf output
* (see printf(3) BUGS, at least in V7).
*/
void
trcmd(art, sys, filename)
struct article *art;
struct system *sys;
char *filename;
{
register char *cmd;
int exitstat;
char *syscmd = sys->sy_cmd, *percent;
static char *ctlcmd = NULL, *bincmd = NULL;
if (ctlcmd == NULL)
ctlcmd = strsave(ctlfile("bin"));
if (bincmd == NULL)
bincmd = strsave(binfile("relay"));
cmd = nemalloc((unsigned)(STRLEN("PATH=") + strlen(ctlcmd) +
STRLEN(":") + strlen(bincmd) + STRLEN(":") + strlen(newspath()) +
STRLEN(" <") + strlen(filename) + STRLEN(" ") +
strlen(syscmd) + strlen(filename) + 1));
(void) strcpy(cmd, "PATH=");
(void) strcat(cmd, ctlcmd);
(void) strcat(cmd, ":");
(void) strcat(cmd, bincmd);
(void) strcat(cmd, ":");
(void) strcat(cmd, newspath());
(void) strcat(cmd, " <");
(void) strcat(cmd, filename);
(void) strcat(cmd, " ");
percent = index(syscmd, '%');
if (percent == NULL)
(void) strcat(cmd, syscmd);
else {
char *pcent2;
++percent;
pcent2 = index(percent, '%');
if (pcent2 != NULL) {
art->a_status |= ST_DROPPED;
(void) fprintf(stderr, "%s: `%s' contains two %%'s\n",
progname, cmd);
} else if (*percent != 's' && *percent != '%') {
art->a_status |= ST_DROPPED;
(void) fprintf(stderr, "%s: `%s' contains %%%c, not %%s\n",
progname, cmd, *percent);
} else
(void) sprintf(cmd+strlen(cmd), syscmd, filename);
}
exitstat = system(cmd);
if (exitstat != 0) {
art->a_status |= ST_DROPPED;
(void) fprintf(stderr, "%s: `%s' returned exit status 0%o\n",
progname, cmd, exitstat);
}
free(cmd);
}
/*
* 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)
art->a_status |= ST_DROPPED;
else {
trappend(art, sys, bf, filename);
art->a_status |= bffkclose(bsysno);
}
}
/*
* write filename, message-id or size on batch file "bf".
* under the 'f' flag (FLG_SZBATCH), include the size in bytes of the article
* after "name" to assist the C news batcher. under the 'n' flag (FLG_NBATCH),
* write the article's message-id. afterward, flush "bf" in case
* the machine crashes before the stream is closed.
*/
STATIC void
trappend(art, sys, bf, name)
register struct article *art;
register struct system *sys;
register struct batchfile *bf;
char *name;
{
if (fputs(name, bf->bf_str) == EOF)
fulldisk(art, bf->bf_name);
if (sys->sy_flags&FLG_SZBATCH &&
fprintf(bf->bf_str, " %ld", art->a_charswritten) == EOF)
fulldisk(art, bf->bf_name);
if (sys->sy_flags&FLG_NBATCH &&
fprintf(bf->bf_str, " %s", art->h.h_msgid) == EOF)
fulldisk(art, bf->bf_name);
/* don't check putc return value for portability; use ferror */
(void) putc('\n', bf->bf_str);
if (ferror(bf->bf_str) || bfflush(bf) == EOF)
fulldisk(art, bf->bf_name);
}
/*
* really close all the open batch files
*/
statust
trclose()
{
return bfrealclose();
}