home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / relay / hdrmunge.c < prev    next >
C/C++ Source or Header  |  1993-03-13  |  9KB  |  335 lines

  1. /*
  2.  * Usenet header modification & generation
  3.  *
  4.  * Ideally, headers should never be modified; message text, including
  5.  * headers, should be passed untouched.  Path: and Xref: demand that this
  6.  * rule be violated, and we delete huge obsolete headers to save space.
  7.  *
  8.  * Delete obsolete & large headers and Xref (can't be right),
  9.  * as headers are read.
  10.  * Recognise Newsgroups: and if more than one group, generate Xref: &
  11.  * leave holes for the article numbers - fileart will fill them in.
  12.  * (Make rn look in history instead?)
  13.  *
  14.  * Pile up headers into a static buffer until end of buffer (i.e. next
  15.  * line might not fit) [checked in hdrsave()], end of headers, end of
  16.  * file, or byte count is exhausted [checked in cparttofp].  Then write
  17.  * them to disk.  Prepend hostname! to Path: value, during output.
  18.  */
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <sys/types.h>
  24. #include "libc.h"
  25. #include "news.h"
  26. #include "config.h"
  27. #include "case.h"
  28. #include "headers.h"
  29. #include "relay.h"
  30. #include "hdrint.h"
  31. #include "msgs.h"
  32.  
  33. /*
  34.  * HDRMEMSIZ is the length of a header-stashing buffer, which is used
  35.  * only during article-header copying.
  36.  * HDRMEMSIZ can be too small if memory is tight & will only hurt performance.
  37.  * Derivation: 630 bytes is a large header (after discarding *-Version:, etc.).
  38.  */
  39. #ifndef HDRMEMSIZ
  40. #ifdef SMALLMEM
  41. #define HDRMEMSIZ 630
  42. #else
  43. #define HDRMEMSIZ 8192            /* # bytes for saving headers in core */
  44. #endif                    /* SMALLMEM */
  45. #endif                    /* HDRMEMSIZ */
  46.  
  47. /* private */
  48. static char **hptrs = NULL;    /* saved-headers-ptrs array; allocated once */
  49. static FILE *hdrfp;        /* accumulated header stream for readers */
  50. static char nmhdrstrm[] = "headers";    /* name of same */
  51.  
  52. /*
  53.  * write hdr to the accumulated header stream
  54.  * (for the benefit of threaded newsreaders).
  55.  */
  56. wrhdrstrm(art, hdr, hdrlen)
  57. register struct article *art;
  58. char *hdr;
  59. register int hdrlen;
  60. {
  61.     if (hdrfp == NULL)
  62.         hdrfp = fopenclex(ctlfile(nmhdrstrm), "a");
  63.     if (hdrfp != NULL) {
  64.         if (fwrite(hdr, hdrlen, 1, hdrfp) != 1)
  65.             fulldisk(art, ctlfile(nmhdrstrm));
  66.     }
  67. }
  68.  
  69. /*
  70.  * write hdr to article and to the accumulated header stream
  71.  * (for the benefit of threaded newsreaders).
  72.  * adjust art->a_charswritten to match.
  73.  */
  74. STATIC void
  75. writehdr(art, hdr, hdrlen)
  76. register struct article *art;
  77. char *hdr;
  78. register int hdrlen;
  79. {
  80.     if (fwrite(hdr, hdrlen, 1, art->a_artf) != 1)
  81.         fulldisk(art, spoolnm(art));
  82.     else
  83.         art->a_charswritten += hdrlen;
  84.     wrhdrstrm(art, hdr, hdrlen);
  85. }
  86.  
  87. flshdrstrm(art)
  88. register struct article *art;
  89. {
  90.     if (hdrfp != NULL) {
  91.         (void) putc('\n', hdrfp); /* blank line to separate articles */
  92.         if (fflush(hdrfp) == EOF)
  93.             fulldisk(art, ctlfile(nmhdrstrm));
  94.     }
  95. }
  96.  
  97. statust
  98. clshdrstrm()
  99. {
  100.     statust status = ST_OKAY;
  101.  
  102.     if (hdrfp != NULL && fclose(hdrfp) == EOF) {
  103.         persistent(NOART, 'f', "error writing %s", ctlfile(nmhdrstrm));
  104.         status |= ST_DROPPED|ST_NEEDATTN;
  105.     }
  106.     hdrfp = NULL;
  107.     return status;
  108. }
  109.  
  110. /*
  111.  * Generate an Xref: header from art->a_files.
  112.  * Turn slashes in art->a_files into colons in Xref:.
  113.  */
  114. void
  115. emitxref(art)
  116. register struct article *art;
  117. {
  118.     register char *slashp, *xrefs, *nhdr, *s1, *s2;
  119.  
  120.     if (!art->a_xref) {
  121.         art->a_xref = YES;
  122.         xrefs = strsave(art->a_files);
  123.         for (slashp=xrefs; (slashp = strchr(slashp, FNDELIM)) != NULL; )
  124.             *slashp++ = ':';
  125.  
  126.         s1 = str3save(xrefhdr.hdrnm, " ", hostname());
  127.         s2 = str3save(s1, " ", xrefs);
  128.         free(xrefs);
  129.         free(s1);
  130.         nhdr = str3save(s2, "\n", "");
  131.         free(s2);
  132.         writehdr(art, nhdr, strlen(nhdr));
  133.         free(nhdr);
  134.     }
  135. }
  136.  
  137. /*
  138.  * --- header copying starts here ---
  139.  */
  140.  
  141. /*
  142.  * Change Path: while writing it out, just dump other headers (hdr) verbatim.
  143.  * (Don't change Path: if we are replicating news.)
  144.  */
  145. STATIC void
  146. emithdr(art, hdr, hdrlen)
  147. register struct article *art;
  148. register char *hdr;
  149. int hdrlen;
  150. {
  151.     if (!opts.blvxref &&
  152.         CISTREQN(hdr, pathhdr.hdrnm, (int)pathhdr.hdrlen)) {
  153.         register char *s1, *nhdr;
  154.  
  155.         s1 = str3save(pathhdr.hdrnm, " ", hostname());
  156.         nhdr = str3save(s1, "!", skipsp(&hdr[pathhdr.hdrlen]));
  157.         free(s1);
  158.         writehdr(art, nhdr, strlen(nhdr));
  159.         free(nhdr);
  160.     } else
  161.         writehdr(art, hdr, hdrlen);
  162. }
  163.  
  164. /*
  165.  * If headers already dumped, just write to art->a_artf.
  166.  * Else if there is room, stash "hdr" away until end of headers is seen
  167.  * (could just wait until Newsgroups: and Control: are seen, if seen)
  168.  * or there is no room left in the header buffer, then open the first
  169.  * article link (on art->a_artf) and dump the saved headers and the current
  170.  * header to it.
  171.  *
  172.  * Copy into art->a_haccum (in future, could read in directly,
  173.  * iff copying is high on the profile).
  174.  *
  175.  * hdrstore is static because it is used repeatedly, it only makes sense
  176.  * to have one active at a time, and there is no memory saving in allocating
  177.  * and deallocating it, particularly since copyart's (header) buffer must
  178.  * coexist with hdrstore.
  179.  */
  180. STATIC void
  181. hdrsave(art, hdr, hdrlen)
  182. register struct article *art;
  183. char *hdr;
  184. register int hdrlen;            /* optimisation only */
  185. {
  186.     if (art->a_artf != NULL) {
  187.         emithdr(art, hdr, hdrlen);
  188.         return;
  189.     }
  190.     if (art->a_haccum == NULL) {
  191.         static char hdrstore[HDRMEMSIZ];
  192.  
  193.         art->a_haccum = hdrstore;
  194.         art->a_haccum[0] = '\0';
  195.         art->a_hnext = art->a_haccum;
  196.         art->a_hbytesleft = HDRMEMSIZ;
  197.     }
  198.     if (art->a_hbytesleft <= hdrlen) {
  199.         filetmp(art);
  200.         hdrdump(art);
  201.         if (art->a_artf != NULL)
  202.             emithdr(art, hdr, hdrlen);
  203.     } else {
  204.         /* add new ptr.-to-this-header to tail of saved-hdr-ptr.-list */
  205.         if (art->a_hptrs == NULL) {
  206.             art->a_hpused = 0;
  207.             art->a_hpalloced = MINSHPTRS;
  208.             if (hptrs == NULL)    /* once only */
  209.                 hptrs = (char **) nemalloc((unsigned)
  210.                     (art->a_hpalloced * sizeof(char *)));
  211.             art->a_hptrs = hptrs;
  212.         }
  213.         while (art->a_hpused >= art->a_hpalloced) {
  214.             art->a_hpalloced += MINSHPTRS;
  215.             art->a_hptrs = hptrs = (char **)
  216.                 realloc((char *)art->a_hptrs, (unsigned)
  217.                 (art->a_hpalloced * sizeof(char *)));
  218.             if (art->a_hptrs == NULL)
  219.                 errunlock("out of memory (for art->a_hptrs)", "");
  220.         }
  221.         art->a_hptrs[art->a_hpused++] = art->a_hnext;
  222.  
  223.         /* (void) strcat(art->a_haccum, hdr); */
  224.         (void) strcpy(art->a_hnext, hdr);
  225.         art->a_hnext += hdrlen;        /* points at NUL byte */
  226.         art->a_hbytesleft -= hdrlen;
  227.     }
  228. }
  229.  
  230. /*
  231.  * Copy headers and delete or modify a few.  Assumes hdrparse has been called.
  232.  * Delete obsolete & large headers and Xref.
  233.  * Pile up other headers for later output (Path: is changed during output).
  234.  *
  235.  * art->a_artf may be NULL, and may get set by hdrsave.
  236.  */
  237. STATIC void
  238. hdrmunge(art, buffer, hdrlen, hdrlst)
  239. register struct article *art;
  240. register char *buffer;
  241. int hdrlen;            /* optimisation only */
  242. hdrlist hdrlst;            /* headers of negative utility: snuff 'em */
  243. {
  244.     register struct hdrdef **vhp;
  245.  
  246.     if (headdebug)
  247.         (void) fputs(buffer, stderr);
  248.     for (vhp = hdrlst; *vhp != NULL; vhp++) {
  249.         register char *hdrnm = (*vhp)->hdrnm;
  250.  
  251.         if (CISTREQN(buffer, hdrnm, (int)(*vhp)->hdrlen))
  252.             return;            /* don't save this header */
  253.     }
  254.     hdrsave(art, buffer, hdrlen);
  255. }
  256.  
  257. /*
  258.  * Write out saved headers after opening on art->a_artf either a temporary
  259.  * file (using mktemp(3)) or the first article link, based on art->h.h_ngs &
  260.  * nxtartnum(); set a_tmpf to which ever name is opened.
  261.  * Modify Path: value on the way.
  262.  *
  263.  * If all headers were seen, then assume 1st exists,
  264.  * and generate Xref:, else open a temporary name and write the article
  265.  * there (it will get filed later by hdrdump(...,ALLHDRS) or in insart()).
  266.  */
  267. void
  268. hdrdump(art)
  269. register struct article *art;
  270. {
  271.     if (art->a_artf != NULL &&
  272.         art->a_haccum != NULL && art->a_haccum[0] != '\0') {
  273.         register int i;
  274.         register char **pp;
  275.         register char *nxtln;
  276.         register int saved;
  277.  
  278.         for (i = 0, pp = art->a_hptrs; i < art->a_hpused; ++i, ++pp) {
  279.             /* last in-core hdr? */
  280.             nxtln = (i >= art->a_hpused-1? art->a_hnext: pp[1]);
  281.  
  282.             saved = *nxtln;
  283.             *nxtln = '\0';
  284.             emithdr(art, *pp, nxtln - *pp);
  285.                  *nxtln = saved;            /* restore */
  286.         }
  287.         /* art->a_haccum could be freed and zeroed here, if malloced */
  288.         art->a_haccum[0] = '\0';    /* paranoia */
  289.         art->a_hnext = art->a_haccum;    /* for next article */
  290.         art->a_hpused = 0;        /* trash saved-header-ptr-list */
  291.         /* reduce saved-header-ptr-list to original size */
  292.         if (art->a_hpalloced > MINSHPTRS) {
  293.             art->a_hpalloced = MINSHPTRS;
  294.             art->a_hptrs = hptrs = (char **)
  295.                 realloc((char *)art->a_hptrs, (unsigned)
  296.                 (art->a_hpalloced * sizeof(char *)));
  297.             if (hptrs == NULL)
  298.                 errunlock("can't free a_hptrs memory", "");
  299.         }
  300.     }
  301. }
  302.  
  303. /*
  304.  * hdrparse remembers this header if it's interesting.
  305.  * hdrmunge needs art->h.h_ngs to be set, so it is called second.
  306.  * hdrmunge saves or writes this header, unless it's deemed a waste of bytes.
  307.  * hdrmunge may call hdrdump(art, NOTALLHDRS).
  308.  * hdrdump counts art->a_charswritten.
  309.  */
  310. void
  311. hdrdigest(art, line, hdrlen)
  312. register struct article *art;
  313. register char *line;
  314. int hdrlen;
  315. {
  316.     register int match;
  317.  
  318.     match = hdrparse(&art->h, line, reqdhdrs);
  319.     if (!match)
  320.         match = hdrparse(&art->h, line, opthdrs);
  321.  
  322.     /* duplicate required header and no previous refusal? */
  323.     if (match == YES+1 && !(art->a_status&ST_REFUSED)) {
  324.         register char *hdrnonl = strsave(line);
  325.  
  326.         trim(hdrnonl);
  327.         decline(art);
  328.         prefuse(art);
  329.         (void) printf("duplicate required header `%s'\n", hdrnonl);
  330.         transient(art, '\0', "dup req hdr", "");
  331.         free(hdrnonl);
  332.     }
  333.     hdrmunge(art, line, hdrlen, hdrvilest);
  334. }
  335.