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 / fileart.c < prev    next >
C/C++ Source or Header  |  1989-06-27  |  10KB  |  353 lines

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