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

  1. /* :ts=4
  2.  * fileart - file an article, given its temporary file name and its headers
  3.  *
  4.  * It may be desirable to, some day, prevent cross-postings across
  5.  * "universes", where a universe might be "alt" or "comp,news".
  6.  *
  7.  * There are three classes of newsgroup for the purposes of filing:
  8.  * "wanted" (in the active file and missing the "x" flag);
  9.  * "not wanted" ("x"ed in active, or not in active and not matched by sys
  10.  *    file's subscription list for this machine), so ignore it; or
  11.  * "don't know it" (not in active and matched by subscription list,
  12.  *    so file the article in junk once, iff there are no good groups).
  13.  * junk *must* be in the active file or it's an error (ST_DROPPED),
  14.  * but junk may have an "x" flag to prevent filing.
  15.  *
  16.  * Use the active file 'x' flag to snuff groups quietly, even when your
  17.  * subscription list permits them, without filing in junk.
  18.  *
  19.  *    $Log$
  20.  */
  21.  
  22. #include "fixerrno.h"
  23. #include <stdio.h>
  24. #include <errno.h>
  25. #ifdef unix
  26. # include <sys/types.h>
  27. #endif /* unix */
  28.  
  29. #include "libc.h"
  30. #include "news.h"
  31. #include "config.h"
  32. #include "control.h"
  33. #include "active.h"
  34. #include "fileart.h"
  35. #include "mkdirs.h"
  36. #include "headers.h"
  37. #include "article.h"
  38. #include "history.h"
  39. #include "system.h"
  40.  
  41. static long artnum;            /* asgnartnum sets artnum */
  42. static int goodngs;            /* asgnartnum reads goodngs */
  43.  
  44. static boolean debug = NO;
  45.  
  46. /* imports from news */
  47. extern void prefuse();
  48.  
  49. /* forwards */
  50. FORWARD void asgnartnum(), gotgoodng(), mkjunklink(), mklinks();
  51. FORWARD boolean openorlink(), mkonelink(), tryartnum();
  52.  
  53. void
  54. filedebug(state)        /* set debugging state */
  55. boolean state;
  56. {
  57.     debug = state;
  58. }
  59.  
  60. /*
  61.  * File in the spool directory the article in art & fill in art->a_files.
  62.  * Generate Xref: header if needed (successfully cross-posted).
  63.  *
  64.  * If a_unlink is true, there is a temp file, so openfirst should
  65.  * be false, and vice versa.
  66.  *
  67.  * If openfirst (!art->a_unlink) is true, fill in a_tmpf with the name of
  68.  * the first link, fopen it (into art->a_artf), and make any remaining links.
  69.  * If openfirst is false, just make links to a_tmpf, which is already
  70.  * open as art->a_artf.  openfirst means "Newsgroups:" was seen in time.
  71.  */
  72. void
  73. fileart(art)
  74. register struct article *art;
  75. {
  76.     register boolean openfirst = !art->a_unlink;
  77.     int junkgroups = 0;        /* count "junked" groups */
  78.     char artnumstr[MAXCOMP];    /* article number in ascii */
  79.  
  80.     if (art->a_filed)
  81.         return;            /* don't file twice */
  82.     artnum = 0;
  83.     goodngs = 0;
  84. #ifdef AMIGA
  85.     {
  86.         extern size_t input_lines;
  87.  
  88.         if (input_lines) {
  89.             fprintf(art->a_artf, "Lines: %ld\n", input_lines);
  90.             input_lines = 0;
  91.         }
  92.     }
  93. #endif /* AMIGA */
  94.     mklinks(art, openfirst, artnumstr, &junkgroups);
  95.     mkjunklink(art, openfirst, artnumstr, &junkgroups);
  96.     if (goodngs > 1 && art->a_artf != NULL)    /* cross-posted? */
  97.         emitxref(art);
  98. }
  99.  
  100. /*
  101.  * Store in spooldir.  Link temp file to spooldir/ng/article-number
  102.  * for each ng.  Control messages go in CONTROL, never in all.all.ctl.
  103.  */
  104. STATIC void
  105. mklinks(art, openfirst, artnumstr, junkgroupsp)
  106. register struct article *art;
  107. boolean openfirst;
  108. char *artnumstr;
  109. int *junkgroupsp;
  110. {
  111.     register char *ngs, *ng;
  112.     register char *comma;
  113.  
  114.     ngs = (art->h.h_ctlcmd != NULL? CONTROL: art->h.h_ngs);    /* NCMP */
  115.     if (art->a_status&ST_REFUSED)
  116.         (void) fprintf(stderr,
  117.             "%s: mklinks called with ST_REFUSED set (can't happen)\n", progname);
  118.     for (; ngs != NULL; ngs = comma) {
  119.         comma = strchr(ngs, NGSEP);
  120.         if (comma != NULL)
  121.             *comma = '\0';        /* will be restored below */
  122.         ng = realngname(ngs);
  123.         if (ng == NULL)
  124.             ng = strsave(ngs);
  125.         asgnartnum(art, openfirst, ng, artnumstr);
  126.         /*
  127.          * If no such group in active or link failed, and the group
  128.          * wasn't 'x'ed in active, but our subscription list permits
  129.          * this group, then set flag to file it under "junk" later.
  130.          */
  131.         if ((artnum < 1 || art->a_status != ST_OKAY) &&
  132.             art->a_status != ST_REFUSED &&
  133.             ngmatch(oursys()->sy_ngs, ng))
  134.                 ++*junkgroupsp;
  135.         /*
  136.          * If article # was assigned & link succeeded,
  137.          * update art->a_files list for history.
  138.          */
  139.         if (artnum >= 1 && art->a_status == ST_OKAY)
  140.             gotgoodng(art, ng, artnumstr);
  141.         free(ng);
  142.  
  143.         if (comma != NULL)
  144.             *comma++ = NGSEP;    /* step past comma */
  145.  
  146.         /* asgnartnum refused just this ng */
  147.         art->a_status &= ~ST_REFUSED;
  148.     }
  149. }
  150.  
  151. /*
  152.  * File once in "junk" iff no ngs were filed due to absence from
  153.  * active, but some were permitted by sys.  This will make one junk
  154.  * link, no matter how many bad groups, and only if all are bad
  155.  * (e.g. rec.drugs,talk.chew-the-fat).
  156.  */
  157. STATIC void
  158. mkjunklink(art, openfirst, artnumstr, junkgroupsp)
  159. register struct article *art;
  160. boolean openfirst;
  161. char *artnumstr;
  162. int *junkgroupsp;
  163. {
  164.     if (*junkgroupsp > 0 && goodngs == 0) {    /* all groups were "junked"? */
  165.         asgnartnum(art, openfirst, JUNK, artnumstr);
  166.         if (artnum >= 1 && art->a_status == ST_OKAY) {
  167.             gotgoodng(art, JUNK, artnumstr);
  168.             art->a_status |= ST_JUNKED;
  169.         } else {
  170.             /*
  171.              * couldn't file article in junk.
  172.              * was JUNK not 'x'ed (i.e. doesn't exist)?
  173.              */
  174.             if (art->a_status != ST_REFUSED) {
  175.                 static boolean warned = NO;
  176.  
  177.                 art->a_status |= ST_REFUSED|ST_DROPPED;
  178.                 if (!warned) {
  179.                     warned = YES;
  180.                     (void) fprintf(stderr, "%s: no %s group\n",
  181.                         progname, JUNK);
  182.                 }
  183.             }
  184.             prefuse(art);
  185.             (void) printf("no known groups in `%s' and no %s group\n",
  186.                 art->h.h_ngs, JUNK);
  187.         }
  188.     } else if (goodngs == 0) {
  189.         extern boolean histreject;
  190.  
  191.         /*
  192.          * Groups were permitted by subscription list, but all
  193.          * were 'x'ed in active, or otherwise refused.
  194.          */
  195.         if (histreject)
  196.             history(art, NOLOG);
  197.         prefuse(art);
  198.         (void) printf("all groups `%s' excluded in active\n", art->h.h_ngs);
  199.         art->a_status |= ST_REFUSED;
  200.     }
  201. }
  202.  
  203. /*
  204.  * Append ng/artnumstr to art's list of files, and bump goodngs.
  205.  */
  206. STATIC void
  207. gotgoodng(art, ng, artnumstr)
  208. struct article *art;
  209. char *ng, *artnumstr;
  210. {
  211.     ++goodngs;
  212.     histupdfiles(art, ng, artnumstr);
  213. }
  214.  
  215. /*
  216.  * Assign a permanent name and article number to the temporary name
  217.  * art->a_tmpf in newsgroup "ng" & store the ascii form of the article
  218.  * number into "artnumstr", returning the article number in "artnum".
  219.  *
  220.  * If openfirst is true and goodngs is zero, set inname to artname,
  221.  * fopen artname and store the result in art->a_artf.
  222.  */
  223. STATIC void
  224. asgnartnum(art, openfirst, ng, artnumstr)
  225. struct article *art;
  226. boolean openfirst;                /* open first link? */
  227. register char *ng;                /* read-only */
  228. char *artnumstr;
  229. {
  230.     register char *slashng;            /* a group, slashed */
  231.  
  232.     /* field active 'x' flag: don't file this group, quietly */
  233.     if (unwanted(ng)) {
  234.         artnum = -1;
  235.         art->a_status |= ST_REFUSED;
  236.         return;
  237.     }
  238.  
  239.     slashng = strsave(ng);
  240.     mkfilenm(slashng);            /* relative to spooldir */
  241.     while ((artnum = nxtartnum(ng)) >= 1)
  242.         if (tryartnum(art, openfirst, slashng, artnumstr))
  243.             break;
  244.     free(slashng);
  245. }
  246.  
  247. /*
  248.  * Construct a link name (slashng/artnum) for this article,
  249.  * and try to link art to it.
  250.  *
  251.  * We changed directory to spooldir in main(), so the generated name
  252.  * is relative to spooldir, therefore artname can be used as is.
  253.  *
  254.  * Return value is identical to mkonelink's.
  255.  */
  256. STATIC boolean
  257. tryartnum(art, openfirst, slashng, artnumstr)
  258. register struct article *art;
  259. boolean openfirst;
  260. register char *slashng;
  261. char *artnumstr;            /* side-effect returned here */
  262. {
  263.     register char *artname;        /* article file name */
  264.     register boolean ret;
  265.  
  266.     (void) sprintf(artnumstr, "%ld", artnum);
  267.     artname = nemalloc((unsigned) (strlen(slashng) +
  268.         STRLEN(SFNDELIM) + strlen(artnumstr) + SIZENUL));
  269.     (void) strcpy(artname, slashng);
  270.     (void) strcat(artname, SFNDELIM);
  271.     (void) strcat(artname, artnumstr);
  272. #ifdef notdef
  273.     char *tartname = strsave(artfile(artname));
  274.     free(artname);
  275.     artname = tartname;
  276. #endif
  277.     ret = mkonelink(art, artname, openfirst);
  278.     free(artname);
  279.     return ret;
  280. }
  281.  
  282. /*
  283.  * Try to link art to artname.
  284.  * If the attempt fails, maybe some intermediate directories are missing,
  285.  * so create any missing directories and try again.  If the second attempt
  286.  * also fails, look at errno; if it is EEXIST, artname already exists
  287.  * (presumably because the active file is out of date, or the existing
  288.  * file is a directory such as net/micro/432), so indicate that higher
  289.  * levels should keep trying, otherwise we are unable to create the
  290.  * necessary directories, so complain and set bad status in art.
  291.  *
  292.  * Returns YES iff there is no point in trying to file this article again,
  293.  * usually because it has been successfully filed, but sometimes because
  294.  * the necessary directories cannot be made.
  295.  */
  296. STATIC boolean
  297. mkonelink(art, artname, openfirst)
  298. register struct article *art;
  299. register char *artname;
  300. boolean openfirst;
  301. {
  302.     if (openorlink(artname, art, openfirst, goodngs))
  303.         return YES;
  304.     else {
  305.         (void) mkdirs(artname, getuid(), getgid());
  306.         if (openorlink(artname, art, openfirst, goodngs))
  307.             return YES;
  308.         else if (errno != EEXIST) {
  309.             warning("can't link to `%s'", artname);
  310.             art->a_status |= ST_DROPPED;
  311.             return YES;        /* hopeless - give up */
  312.         } else
  313.             return NO;
  314.     }
  315. }
  316.  
  317. /*
  318.  * Try to make a link of art (actually art->a_tmpf) to artname.
  319.  * If no links have been made yet, record and open artname iff no
  320.  * link yet exists to that name (by any file, to avoid overwriting
  321.  * existing articles, e.g. due to an out-of-date active file).
  322.  * If links already exist, try to make artname a link to the first link
  323.  * (art->a_tmpf).
  324.  *
  325.  * Liberally sprinkled with debugging output, as this is the heart
  326.  * of article filing.
  327.  */
  328.  
  329. #ifdef AMIGA
  330. extern FILE **Link_a;        /* A *REAL* kludge to make link() work correctly */
  331. #endif
  332.  
  333. STATIC boolean
  334. openorlink(artname, art, openfirst, goodngcnt)
  335. register char *artname;
  336. register struct article *art;
  337. boolean openfirst;            /* open art's first link? */
  338. int goodngcnt;                /* count of good news groups */
  339. {
  340.     register boolean worked;        /* open or link worked? */
  341.  
  342.     if (openfirst && goodngcnt == 0) {
  343.         if (debug)
  344.             (void) fprintf(stderr, "opening `%s'... ", artname);
  345.         nnfree(&art->a_tmpf);
  346.         art->a_tmpf = strsave(artname);
  347.         art->a_artf = fopenexcl(art->a_tmpf);
  348.         worked = art->a_artf != NULL;
  349.     } else {
  350.         if (debug)
  351.             (void) fprintf(stderr, "linking `%s' to `%s'... ",
  352.                 art->a_tmpf, artname);
  353. #ifndef AMIGA
  354.         worked = link(art->a_tmpf, artname) == 0;
  355. #else
  356.         Link_a = &art->a_artf;
  357.         worked = link(art->a_tmpf, artname) == 0;
  358.         Link_a = NULL;
  359. #endif /* AMIGA */
  360.         if (!worked)
  361.             /*
  362.              * If art->a_tmpf really *is* a temporary name (because
  363.              * the whole header didn't fit in core), then this will
  364.              * produce a symbolic link to a non-existent name when
  365.              * art->a_tmpf is unlinked, which will be soon.
  366.              * Moral: don't run Eunice on your PDP-11.
  367.              */
  368.             worked = symlink(fullartfile(art->a_tmpf), artname) == 0;
  369.     }
  370.     if (debug)
  371.         if (worked)
  372.             (void) fprintf(stderr, "success.\n");
  373.         else
  374.             warning("failed.", "");
  375.     return worked;
  376. }
  377.