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 / procart.c < prev    next >
C/C++ Source or Header  |  1989-06-27  |  12KB  |  407 lines

  1. /*
  2.  * process a single incoming article
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <sys/types.h>
  7. #include "libc.h"
  8. #include "news.h"
  9. #include "active.h"
  10. #include "control.h"
  11. #include "headers.h"
  12. #include "article.h"
  13. #include "history.h"
  14. #include "io.h"
  15. #include "msgs.h"
  16. #include "system.h"
  17. #include "transmit.h"
  18.  
  19. /*
  20.  * COPYSIZE is the length of a bulk-copying buffer: the bigger the better,
  21.  * though fewer than 3% of articles exceed 8192 bytes (may 1988).
  22.  * It holds header lines first, and later holds bytes of the body.
  23.  * This buffer is allocated once at the start and never deallocated.
  24.  */
  25. #ifndef COPYSIZE
  26. #ifdef SMALLMEM
  27. #define COPYSIZE BUFSIZ        /* conserve memory at the expense of speed */
  28. #else
  29. #define COPYSIZE 8192        /* big enough even for worst-case 4.2bsd blocks */
  30. #endif                /* SMALLMEM */
  31. #endif                /* COPYSIZE */
  32.  
  33. extern char *exclude;        /* for erik */
  34. extern boolean okrefusal;    /* flag from command line */
  35.  
  36. /* forwards */
  37. extern void tossorfile(), surveydamage(), reject(), prefuse(), uninsart();
  38. extern char *hdrcopy();
  39. FORWARD void copyart(), cpybody(), insart();
  40. FORWARD statust snuffmayreturn();
  41.  
  42. /*
  43.  * Copy the article on "in" to a temporary name in the news spool directory,
  44.  * unlink temp name; *or* copy into the final names, if known early enough.
  45.  * (Sets a_tmpf in or near hdrmunge() or hdrdump().)
  46.  * If the spool file opened, install the article it contains.
  47.  */
  48. statust
  49. cpinsart(in, inname, maxima, blvmax)
  50. FILE *in;
  51. register char *inname;
  52. long maxima;
  53. boolean blvmax;                /* believe maxima? */
  54. {
  55.     register struct article *artp;
  56.     register statust status;
  57.     struct article art;
  58.  
  59.     artp = &art;
  60.     artinit(artp);
  61.     artp->a_blvmax = blvmax;
  62.     artp->a_unread = maxima;
  63.  
  64.     /*
  65.      * copyart() may reject() the article, and may fill the disk.
  66.      * it calls fileart and logs rejected articles.
  67.      */
  68.     copyart(artp, in, inname);
  69.  
  70.     if (artp->a_status&ST_REFUSED) {
  71.         /* no good ngs (in fileart) or reject()ed; not serious */
  72.         artp->a_status &= ~ST_REFUSED;
  73.         /* paranoia; shouldn't happen */
  74.         nnfclose(artp, &artp->a_artf, inname);
  75.     } else if (artp->a_artf == NULL) {
  76.         warning("can't open spool file `%s'", artp->a_tmpf);
  77.         artp->a_status |= ST_DROPPED;
  78.     } else {
  79.         nnfclose(artp, &artp->a_artf, inname);
  80.         insart(artp);    /* logs accepted art.s during transmission */
  81.         if (artp->a_status&ST_JUNKED) {    /* yer welcome, henry */
  82.             artp->a_status &= ~ST_JUNKED;
  83.             timestamp(stdout, (time_t *)NULL);
  84.             (void) printf(" %s j %s junked due to groups `%s'\n",
  85.                 sendersite(nullify(artp->h.h_path)),
  86.                 artp->h.h_msgid, artp->h.h_ngs);
  87.         }
  88.     }
  89.     status = artp->a_status;
  90.     artfree(artp);
  91.     return status;
  92. }
  93.  
  94. /*
  95.  * Copy the next charcnt bytes of "in" (may be not a disk file)
  96.  * to a permanent file under a (possibly) temporary name.
  97.  * After the headers are seen, accept or reject the article.
  98.  * If rejected and the headers fit in core, no files will be opened.
  99.  * Must munge certain headers on the way & remember certain values.
  100.  * hdrmunge() or hdrdump() sets art->a_tmpf & art->a_artf.
  101.  * Unlink art->a_tmpf, if a temporary link.
  102.  */
  103. /* ARGSUSED inname */
  104. STATIC void
  105. copyart(art, in, inname)
  106. register struct article *art;
  107. register FILE *in;
  108. char *inname;
  109. {
  110.     boolean installed = YES;
  111.     char *body;
  112.  
  113.     body = hdrcopy(art, in);
  114.     hdrdeflt(&art->h);
  115.     tossorfile(art, &installed);
  116.     /* assertion: header values (art->h) can be forgotten here */
  117.     cpybody(art, in, body);
  118.     surveydamage(art, &installed);
  119. }
  120.  
  121. /*
  122.  * The loop copies header lines from input to output or a
  123.  * header output cache.  On exit, hdr will contain the first
  124.  * non-header line, if any, left over from the end of header copying.
  125.  *
  126.  * Some people think the loop is ugly; I'm not sure why.
  127.  * If the byte count is positive, read a line; if it doesn't return
  128.  * EOF and is a header, then adjust byte count, stash and munge headers.
  129.  * strlen(line) must be computed before hdrstash is called,
  130.  * as hdrstash (and thus hdrdigest) removes newlines.
  131.  */
  132. char *                        /* first body line, from gethdr */
  133. hdrcopy(art, in)
  134. register struct article *art;
  135. FILE *in;
  136. {
  137.     register char *hdr = NULL;
  138.     long limit;
  139.     int is_hdr = NO;
  140.  
  141.     hdrwretch();                /* reset the header parser */
  142.     limit = (art->a_blvmax? art->a_unread+1: art->a_unread); /* 1 for NUL */
  143.     /* 1 is again for NUL */
  144.     while (limit > 1 && (hdr = gethdr(in, &limit, &is_hdr)) != NULL && is_hdr) {
  145.             hdrdigest(art, hdr, strlen(hdr));
  146.         hdr = NULL;            /* freed inside gethdr */
  147.     }
  148.     /* If we read a body line, gethdr has adjusted limit appropriately. */
  149.     art->a_unread = limit - 1;        /* limit updated by gethdr */
  150.     if (is_hdr)                /* no body: header fills limit */
  151.         hdr = NULL;
  152.     return hdr;
  153. }
  154.  
  155. /*
  156.  * Either reject the article described by art, or accept it and file it.
  157.  * If rejecting it, remove any links and give back assigned #'s
  158.  * (art->a_artf may still be open; arguably uninsart should close it).
  159.  * If accepting it, dump any saved headers and file the article.
  160.  * Unlink art->a_tmpf if it's a temporary link.
  161.  */
  162. void
  163. tossorfile(art, installedp)
  164. register struct article *art;
  165. boolean *installedp;
  166. {
  167.     reject(art);                /* duplicate, etc.? */
  168.     if (art->a_status&(ST_DROPPED|ST_REFUSED)) {
  169.         uninsart(art);
  170.         *installedp = NO;
  171.     } else
  172.         hdrdump(art, ALLHDRS);        /* ALLHDRS triggers fileart */
  173.  
  174.     if (art->a_unlink) {
  175.         /* a_tmpf has had links made to it, so it can be removed. */
  176.         if (unlink(art->a_tmpf) < 0) {
  177.             warning("copyart can't unlink `%s'", art->a_tmpf);
  178.             art->a_status |= ST_ACCESS;
  179.         }
  180.         art->a_unlink = NO;        /* caution */
  181.     }
  182. }
  183.  
  184. /*
  185.  * Copy article body.
  186.  * body will contain the first  non-header line, if any,
  187.  * left over from the end of header copying.  Write it.
  188.  * Copy at most COPYSIZE bytes of body at a time and exactly art->a_unread
  189.  * bytes in total, barring EOF or a full disk. Then "block" is no longer needed
  190.  
  191.  * Force the article to disk, mostly for the benefit of control message
  192.  * processing.
  193.  *
  194.  * The copying buffer, block, is static because it is used repeatedly
  195.  * and persists through most of execution, so dynamic allocation
  196.  * and deallocation seems wasteful, but also for the benefit
  197.  * of compilers for odd machines (e.g. PE, 370s) which make
  198.  * implementing "large" automatic arrays difficult.
  199.  */
  200. STATIC void
  201. cpybody(art, in, body)
  202. register struct article *art;
  203. FILE *in;
  204. register char *body;
  205. {
  206.     register int readcnt;
  207.     static char block[COPYSIZE];
  208.  
  209.     if (body != NULL) {            /* read too far? */
  210.         register int bodylen = strlen(body);
  211.  
  212.         if (art->a_artf != NULL &&
  213.             fwrite(body, 1, bodylen, art->a_artf) != bodylen)
  214.             fulldisk(art, spoolnm(art));
  215.         art->a_charswritten += bodylen;
  216.     }
  217.     for (; art->a_unread > 0 && !(art->a_status&ST_DISKFULL) &&
  218.         (readcnt=fread(block, 1, (int)min(art->a_unread, COPYSIZE), in)) > 0;
  219.         art->a_unread -= readcnt, art->a_charswritten += readcnt)
  220.         if (art->a_artf != NULL &&
  221.             fwrite(block, 1, readcnt, art->a_artf) != readcnt)
  222.             fulldisk(art, spoolnm(art));
  223.     if (art->a_artf != NULL && fflush(art->a_artf) == EOF)
  224.         fulldisk(art, spoolnm(art));
  225. }
  226.  
  227. /*
  228.  * If not yet uninstalled, and the disk filled, uninstall this article
  229.  * to remove any zero-length links and decrement the active article number.
  230.  * The ST_DISKFULL status will prevent a history entry from being generated.
  231.  */
  232. void
  233. surveydamage(art, installedp)
  234. register struct article *art;
  235. register boolean *installedp;
  236. {
  237.     if (art->a_unread > 0 && art->a_blvmax) {
  238.         (void) fprintf(stderr, "%s: article %s short by %ld bytes\n",
  239.             progname, (art->h.h_msgid != NULL? art->h.h_msgid: ""),
  240.             (long)art->a_unread);
  241.         art->a_status |= ST_SHORT;    /* NB.: don't uninstall this art. */
  242.     }
  243.     if (*installedp && art->a_status&ST_DISKFULL) {
  244.         uninsart(art);
  245.         *installedp = NO;
  246.     }
  247. #ifdef WATCHCORE
  248.     {
  249.         char stbot;
  250.         extern char *sbrk();
  251.  
  252.         printf("debugging memory use: top of data=%u", (unsigned)sbrk(0));
  253.         printf(", bottom of stack=%u\n", (unsigned)&stbot);
  254.     }
  255. #endif
  256. }
  257.  
  258. /*
  259.  * Install the article on art->a_tmpf or art->a_files:
  260.  * The article should have been accepted and filed in copyart().
  261.  * Add history entries for the article.  Log arrival.
  262.  * Transmit the article to our neighbours.
  263.  * Process control mess(age)es.  ctlmsg can call transmit(fakeart,x)
  264.  * and generate log lines for cancels and ihave/sendme.
  265.  */
  266. STATIC void
  267. insart(art)
  268. register struct article *art;
  269. {
  270.     if (!(art->a_status&(ST_DROPPED|ST_REFUSED|ST_DISKFULL))) {
  271.         if (!art->a_filed)            /* paranoia */
  272.             (void) fprintf(stderr, "%s: %s not filed by copyart!\n",
  273.                 progname, art->h.h_msgid);
  274.         history(art, STARTLOG);
  275.         transmit(art, exclude);        /* writes systems on stdout */
  276.         (void) putchar('\n');        /* ends the log line */
  277.         if (art->h.h_ctlcmd != NULL)
  278.             ctlmsg(art);
  279. #ifdef notdef                    /* it's only a log file! */
  280.         (void) fflush(stdout);        /* crash-proofness */
  281. #endif
  282.     }
  283.     art->a_status &= ~ST_REFUSED;    /* refusal is quite casual & common */
  284. }
  285.  
  286. /*
  287.  * Reject articles.  This can be arbitrarily picky.
  288.  * Only the headers are used to decide, so this can be called before
  289.  * the article is filed.
  290.  * Be sure to put the fastest tests first, especially if they often result
  291.  * in rejections.
  292.  */
  293. void
  294. reject(art)
  295. register struct article *art;
  296. {
  297.     if (art->h.h_path == NULL) {
  298.         prefuse(art);
  299.         (void) printf("no Path: header\n");
  300.     } else if (alreadyseen(art->h.h_msgid)) {
  301.         prefuse(art);
  302.         (void) printf("duplicate\n");
  303.     } else if (art->h.h_path != NULL && hopcount(art->h.h_path) > 0 &&
  304.         !ngmatch(oursys()->sy_ngs, art->h.h_ngs)) {
  305.         extern boolean histreject;
  306.  
  307.         /*
  308.          * non-local article, with all bad groups.
  309.          * (local articles with bad groups will be bounced
  310.          * by fileart when the groups aren't in active.)
  311.          */
  312.         if (histreject)
  313.             history(art, NOLOG);
  314.         prefuse(art);
  315.         (void) printf("no subscribed groups in `%s'\n", art->h.h_ngs);
  316.     } else if (art->h.h_approved == NULL && moderated(art->h.h_ngs)) {
  317.         prefuse(art);
  318.         (void) printf("unapproved article in moderated group(s) `%s'\n",
  319.             art->h.h_ngs);
  320.     } else
  321.         return;            /* art was accepted */
  322.     art->a_status |= ST_REFUSED;
  323.     if (!okrefusal)
  324.         art->a_status |= ST_DROPPED;
  325. }
  326.  
  327. /*
  328.  * print the leader of a refusal message about the article in "art".
  329.  */
  330. void
  331. prefuse(art)
  332. register struct article *art;
  333. {
  334.     timestamp(stdout, (time_t *)NULL);
  335.     (void) printf(" %s - %s ", sendersite(nullify(art->h.h_path)),
  336.         art->h.h_msgid);
  337. }
  338.  
  339. /*
  340.  * "Uninstall" an article: remove art->a_files (permanent names) and
  341.  * a_tmpf (temporary name if a_unlink set), and return assigned article #'s.
  342.  * If a_unlink isn't set, a_tmpf is a copy of the first link in art->a_files.
  343.  * Must be called before history() is called, else there will be a
  344.  * history entry for the article, but no spool files.
  345.  */
  346. void
  347. uninsart(art)
  348. register struct article *art;
  349. {
  350.     if (art->a_unlink && art->a_tmpf != NULL) {
  351.         (void) unlink(art->a_tmpf);    /* I don't wanna know... */
  352.         art->a_unlink = NO;
  353.     }
  354.     /* return article numbers (YES) & ignore unlink errors */
  355.     (void) snuffmayreturn(art->a_files, YES);
  356. }
  357.  
  358. statust
  359. snufffiles(filelist)        /* just unlink all files in filelist */
  360. char *filelist;
  361. {
  362.     /* don't return article numbers (NO) & return unlink errors */
  363.     return snuffmayreturn(filelist, NO);
  364. }
  365.  
  366. /*
  367.  * Unlink all files in filelist, and optionally return article numbers.
  368.  * When removing a link, note any failure, but don't issue an error message.
  369.  * For one thing, cancel controls fail routinely because the article has been
  370.  * removed manually or never existed (a previous cancel arrived before its
  371.  * subject and generated a fake history entry).
  372.  */
  373. STATIC statust
  374. snuffmayreturn(filelist, artret)
  375. char *filelist;
  376. boolean artret;        /* return article numbers & note unlink errors? */
  377. {
  378.     register statust status = ST_OKAY;
  379.     register char *arts, *spacep, *slashp, *artnm;
  380.  
  381.     /* this is a deadly tedious job and I really should automate it */
  382.     for (arts = filelist; arts != NULL && arts[0] != '\0';
  383.          arts = (spacep == NULL? NULL: spacep+1)) {
  384.         spacep = index(arts, ' ');
  385.         if (spacep != NULL)
  386.             spacep[0] = '\0';    /* will be restored below */
  387.         artnm = strsave(arts);
  388.         if (spacep != NULL)
  389.             spacep[0] = ' ';    /* restore space */
  390.  
  391.         slashp = index(artnm, FNDELIM);
  392.         if (slashp != NULL)
  393.             slashp[0] = '\0';    /* will be restored below */
  394.         if (artret)
  395.             /* prevartnum will complain on i/o error to active */
  396.             (void) prevartnum(artnm); /* return assigned # */
  397.         if (slashp != NULL)
  398.             slashp[0] = FNDELIM;    /* restore slash */
  399.  
  400.         mkfilenm(artnm);
  401.         if (unlink(artnm) < 0)
  402.             status |= ST_ACCESS;
  403.         free(artnm);
  404.     }
  405.     return status;
  406. }
  407.