home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 1
/
GoldFishApril1994_CD2.img
/
d4xx
/
d473
/
cnewssrc
/
cnews_src.lzh
/
relay
/
fileart.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-01
|
11KB
|
377 lines
/* :ts=4
* fileart - file an article, given its temporary file name and its headers
*
* It may be desirable to, some day, prevent cross-postings across
* "universes", where a universe might be "alt" or "comp,news".
*
* There are three classes of newsgroup for the purposes of filing:
* "wanted" (in the active file and missing the "x" flag);
* "not wanted" ("x"ed in active, or not in active and not matched by sys
* file's subscription list for this machine), so ignore it; or
* "don't know it" (not in active and matched by subscription list,
* so file the article in junk once, iff there are no good groups).
* junk *must* be in the active file or it's an error (ST_DROPPED),
* but junk may have an "x" flag to prevent filing.
*
* Use the active file 'x' flag to snuff groups quietly, even when your
* subscription list permits them, without filing in junk.
*
* $Log$
*/
#include "fixerrno.h"
#include <stdio.h>
#include <errno.h>
#ifdef unix
# include <sys/types.h>
#endif /* unix */
#include "libc.h"
#include "news.h"
#include "config.h"
#include "control.h"
#include "active.h"
#include "fileart.h"
#include "mkdirs.h"
#include "headers.h"
#include "article.h"
#include "history.h"
#include "system.h"
static long artnum; /* asgnartnum sets artnum */
static int goodngs; /* asgnartnum reads goodngs */
static boolean debug = NO;
/* imports from news */
extern void prefuse();
/* forwards */
FORWARD void asgnartnum(), gotgoodng(), mkjunklink(), mklinks();
FORWARD boolean openorlink(), mkonelink(), tryartnum();
void
filedebug(state) /* set debugging state */
boolean state;
{
debug = state;
}
/*
* File in the spool directory the article in art & fill in art->a_files.
* Generate Xref: header if needed (successfully cross-posted).
*
* If a_unlink is true, there is a temp file, so openfirst should
* be false, and vice versa.
*
* If openfirst (!art->a_unlink) is true, fill in a_tmpf with the name of
* the first link, fopen it (into art->a_artf), and make any remaining links.
* If openfirst is false, just make links to a_tmpf, which is already
* open as art->a_artf. openfirst means "Newsgroups:" was seen in time.
*/
void
fileart(art)
register struct article *art;
{
register boolean openfirst = !art->a_unlink;
int junkgroups = 0; /* count "junked" groups */
char artnumstr[MAXCOMP]; /* article number in ascii */
if (art->a_filed)
return; /* don't file twice */
artnum = 0;
goodngs = 0;
#ifdef AMIGA
{
extern size_t input_lines;
if (input_lines) {
fprintf(art->a_artf, "Lines: %ld\n", input_lines);
input_lines = 0;
}
}
#endif /* AMIGA */
mklinks(art, openfirst, artnumstr, &junkgroups);
mkjunklink(art, openfirst, artnumstr, &junkgroups);
if (goodngs > 1 && art->a_artf != NULL) /* cross-posted? */
emitxref(art);
}
/*
* Store in spooldir. Link temp file to spooldir/ng/article-number
* for each ng. Control messages go in CONTROL, never in all.all.ctl.
*/
STATIC void
mklinks(art, openfirst, artnumstr, junkgroupsp)
register struct article *art;
boolean openfirst;
char *artnumstr;
int *junkgroupsp;
{
register char *ngs, *ng;
register char *comma;
ngs = (art->h.h_ctlcmd != NULL? CONTROL: art->h.h_ngs); /* NCMP */
if (art->a_status&ST_REFUSED)
(void) fprintf(stderr,
"%s: mklinks called with ST_REFUSED set (can't happen)\n", progname);
for (; ngs != NULL; ngs = comma) {
comma = strchr(ngs, NGSEP);
if (comma != NULL)
*comma = '\0'; /* will be restored below */
ng = realngname(ngs);
if (ng == NULL)
ng = strsave(ngs);
asgnartnum(art, openfirst, ng, artnumstr);
/*
* If no such group in active or link failed, and the group
* wasn't 'x'ed in active, but our subscription list permits
* this group, then set flag to file it under "junk" later.
*/
if ((artnum < 1 || art->a_status != ST_OKAY) &&
art->a_status != ST_REFUSED &&
ngmatch(oursys()->sy_ngs, ng))
++*junkgroupsp;
/*
* If article # was assigned & link succeeded,
* update art->a_files list for history.
*/
if (artnum >= 1 && art->a_status == ST_OKAY)
gotgoodng(art, ng, artnumstr);
free(ng);
if (comma != NULL)
*comma++ = NGSEP; /* step past comma */
/* asgnartnum refused just this ng */
art->a_status &= ~ST_REFUSED;
}
}
/*
* File once in "junk" iff no ngs were filed due to absence from
* active, but some were permitted by sys. This will make one junk
* link, no matter how many bad groups, and only if all are bad
* (e.g. rec.drugs,talk.chew-the-fat).
*/
STATIC void
mkjunklink(art, openfirst, artnumstr, junkgroupsp)
register struct article *art;
boolean openfirst;
char *artnumstr;
int *junkgroupsp;
{
if (*junkgroupsp > 0 && goodngs == 0) { /* all groups were "junked"? */
asgnartnum(art, openfirst, JUNK, artnumstr);
if (artnum >= 1 && art->a_status == ST_OKAY) {
gotgoodng(art, JUNK, artnumstr);
art->a_status |= ST_JUNKED;
} else {
/*
* couldn't file article in junk.
* was JUNK not 'x'ed (i.e. doesn't exist)?
*/
if (art->a_status != ST_REFUSED) {
static boolean warned = NO;
art->a_status |= ST_REFUSED|ST_DROPPED;
if (!warned) {
warned = YES;
(void) fprintf(stderr, "%s: no %s group\n",
progname, JUNK);
}
}
prefuse(art);
(void) printf("no known groups in `%s' and no %s group\n",
art->h.h_ngs, JUNK);
}
} else if (goodngs == 0) {
extern boolean histreject;
/*
* Groups were permitted by subscription list, but all
* were 'x'ed in active, or otherwise refused.
*/
if (histreject)
history(art, NOLOG);
prefuse(art);
(void) printf("all groups `%s' excluded in active\n", art->h.h_ngs);
art->a_status |= ST_REFUSED;
}
}
/*
* Append ng/artnumstr to art's list of files, and bump goodngs.
*/
STATIC void
gotgoodng(art, ng, artnumstr)
struct article *art;
char *ng, *artnumstr;
{
++goodngs;
histupdfiles(art, ng, artnumstr);
}
/*
* Assign a permanent name and article number to the temporary name
* art->a_tmpf in newsgroup "ng" & store the ascii form of the article
* number into "artnumstr", returning the article number in "artnum".
*
* If openfirst is true and goodngs is zero, set inname to artname,
* fopen artname and store the result in art->a_artf.
*/
STATIC void
asgnartnum(art, openfirst, ng, artnumstr)
struct article *art;
boolean openfirst; /* open first link? */
register char *ng; /* read-only */
char *artnumstr;
{
register char *slashng; /* a group, slashed */
/* field active 'x' flag: don't file this group, quietly */
if (unwanted(ng)) {
artnum = -1;
art->a_status |= ST_REFUSED;
return;
}
slashng = strsave(ng);
mkfilenm(slashng); /* relative to spooldir */
while ((artnum = nxtartnum(ng)) >= 1)
if (tryartnum(art, openfirst, slashng, artnumstr))
break;
free(slashng);
}
/*
* Construct a link name (slashng/artnum) for this article,
* and try to link art to it.
*
* We changed directory to spooldir in main(), so the generated name
* is relative to spooldir, therefore artname can be used as is.
*
* Return value is identical to mkonelink's.
*/
STATIC boolean
tryartnum(art, openfirst, slashng, artnumstr)
register struct article *art;
boolean openfirst;
register char *slashng;
char *artnumstr; /* side-effect returned here */
{
register char *artname; /* article file name */
register boolean ret;
(void) sprintf(artnumstr, "%ld", artnum);
artname = nemalloc((unsigned) (strlen(slashng) +
STRLEN(SFNDELIM) + strlen(artnumstr) + SIZENUL));
(void) strcpy(artname, slashng);
(void) strcat(artname, SFNDELIM);
(void) strcat(artname, artnumstr);
#ifdef notdef
char *tartname = strsave(artfile(artname));
free(artname);
artname = tartname;
#endif
ret = mkonelink(art, artname, openfirst);
free(artname);
return ret;
}
/*
* Try to link art to artname.
* If the attempt fails, maybe some intermediate directories are missing,
* so create any missing directories and try again. If the second attempt
* also fails, look at errno; if it is EEXIST, artname already exists
* (presumably because the active file is out of date, or the existing
* file is a directory such as net/micro/432), so indicate that higher
* levels should keep trying, otherwise we are unable to create the
* necessary directories, so complain and set bad status in art.
*
* Returns YES iff there is no point in trying to file this article again,
* usually because it has been successfully filed, but sometimes because
* the necessary directories cannot be made.
*/
STATIC boolean
mkonelink(art, artname, openfirst)
register struct article *art;
register char *artname;
boolean openfirst;
{
if (openorlink(artname, art, openfirst, goodngs))
return YES;
else {
(void) mkdirs(artname, getuid(), getgid());
if (openorlink(artname, art, openfirst, goodngs))
return YES;
else if (errno != EEXIST) {
warning("can't link to `%s'", artname);
art->a_status |= ST_DROPPED;
return YES; /* hopeless - give up */
} else
return NO;
}
}
/*
* Try to make a link of art (actually art->a_tmpf) to artname.
* If no links have been made yet, record and open artname iff no
* link yet exists to that name (by any file, to avoid overwriting
* existing articles, e.g. due to an out-of-date active file).
* If links already exist, try to make artname a link to the first link
* (art->a_tmpf).
*
* Liberally sprinkled with debugging output, as this is the heart
* of article filing.
*/
#ifdef AMIGA
extern FILE **Link_a; /* A *REAL* kludge to make link() work correctly */
#endif
STATIC boolean
openorlink(artname, art, openfirst, goodngcnt)
register char *artname;
register struct article *art;
boolean openfirst; /* open art's first link? */
int goodngcnt; /* count of good news groups */
{
register boolean worked; /* open or link worked? */
if (openfirst && goodngcnt == 0) {
if (debug)
(void) fprintf(stderr, "opening `%s'... ", artname);
nnfree(&art->a_tmpf);
art->a_tmpf = strsave(artname);
art->a_artf = fopenexcl(art->a_tmpf);
worked = art->a_artf != NULL;
} else {
if (debug)
(void) fprintf(stderr, "linking `%s' to `%s'... ",
art->a_tmpf, artname);
#ifndef AMIGA
worked = link(art->a_tmpf, artname) == 0;
#else
Link_a = &art->a_artf;
worked = link(art->a_tmpf, artname) == 0;
Link_a = NULL;
#endif /* AMIGA */
if (!worked)
/*
* If art->a_tmpf really *is* a temporary name (because
* the whole header didn't fit in core), then this will
* produce a symbolic link to a non-existent name when
* art->a_tmpf is unlinked, which will be soon.
* Moral: don't run Eunice on your PDP-11.
*/
worked = symlink(fullartfile(art->a_tmpf), artname) == 0;
}
if (debug)
if (worked)
(void) fprintf(stderr, "success.\n");
else
warning("failed.", "");
return worked;
}