home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2678 < prev    next >
Internet Message Format  |  1991-02-06  |  6KB

  1. From: em@dce.ie (Eamonn McManus)
  2. Newsgroups: news.software.b,alt.sources
  3. Subject: Re: unbatcher out of sync?
  4. Message-ID: <scratchmatch@dce.ie>
  5. Date: 15 Jan 91 23:34:28 GMT
  6.  
  7. henry@zoo.toronto.edu (Henry Spencer) writes:
  8. >It means "something's wrong with your batch":  relaynews did not find a
  9. >"#! rnews nnnnn" line where one should have been.  Typically this means
  10. >garbling during preparation or transmission.  One notorious trouble spot
  11. >is that the batch format cannot tolerate transformations of newlines to
  12. >CR-LF pairs; the byte counts in the "#! rnews" lines must be spot-on.
  13.  
  14. We had `unbatcher out of sync' problems at a site I was involved in, which
  15. was fed its news by mail from a VMS site (ugh).  The VMS mailer (PMDF) got
  16. confused when lines exceeded 256 characters, as References lines often do,
  17. and would make a total hash of the header when this happened.  As a result,
  18. the "#! rnews" count would always be off by a small amount for the affected
  19. article.  C News resyncs at the next "#! rnews" line, but if the count is
  20. too long for the actual article contents it will have missed the start of
  21. the article following the garbled one.
  22.  
  23. To kludge around this problem I wrote a program `patchbatch' which zips
  24. through a news batch looking for "#! rnews" lines with incorrect counts.
  25. If it finds one, it hunts back and forth a small amount for the next "#!
  26. rnews" line and adjusts the incorrect one to point to it.  This was
  27. surprisingly effective: while it was running I believe it never failed to
  28. correct a munged batch.
  29.  
  30. I'm including the source of patchbatch in case it is of use to the original
  31. poster, or anyone else.
  32.  
  33. ,
  34. Eamonn
  35.  
  36. /* patchbatch.c - patch a news batch. */
  37.  
  38. /* By Eamonn McManus <emcmanus@cs.tcd.ie>, February 1990.
  39.  * This program is not copyrighted.
  40.  *
  41.  * Blast through a news batch checking the offsets after `#! rnews'.
  42.  * If we find that the offset does not lead to another `#! rnews' line
  43.  * or EOF, we search around for the line somewhere in the vicinity.  If
  44.  * it is found, we go back and patch the original offset to point to the
  45.  * correct place.  This is useful for example on systems where long lines
  46.  * get truncated or split in transmission, since in this case the stated
  47.  * offset will be wrong.
  48.  *
  49.  * This is the hackiest program I have written in a long time.
  50.  */
  51.  
  52. #include <stdio.h>
  53. #include <string.h>
  54. #include <sys/fcntl.h>    /* For O_RDWR. */
  55. #include <sys/types.h>
  56. #include <sys/stat.h>
  57.  
  58. extern long strtol();
  59.  
  60. char verbose;
  61. extern int optind;
  62.  
  63.  
  64. main(argc, argv)
  65. char **argv;
  66. {
  67.     int i, status;
  68.     while ((i = getopt(argc, argv, "v")) != -1)
  69.         switch (i) {
  70.         case 'v':
  71.             verbose = 1; break;
  72.         default:
  73.             goto usage;
  74.         }
  75.     if (optind == argc) {
  76. usage:
  77.         fprintf(stderr, "Usage: patchbatch file [...]\n");
  78.         exit(2);
  79.     }
  80.     status = 0;
  81.     for (i = optind; i < argc; i++)
  82.         if (patchbatch(argv[i]) < 0)
  83.             status = 1;
  84.     exit(status);
  85. }
  86.  
  87.  
  88. static char lead[] = "#! rnews ";
  89. #define LEADLEN (sizeof lead - 1)
  90. #define FUDGE (2 * sizeof lead)
  91.  
  92. int patchbatch(name)
  93. char *name;
  94. {
  95.     int fd, i;
  96.     long here, offset;
  97.     char buf[64];
  98.     struct stat st;
  99.     if ((fd = open(name, O_RDWR)) < 0) {
  100.         perror(name);
  101.         return -1;
  102.     }
  103.     if (fstat(fd, &st) < 0) {
  104.         perror(name);
  105.         return -1;
  106.     }
  107.     if ((i = read(fd, buf, sizeof buf - 1)) != sizeof buf - 1) {
  108.         if (i < 0)
  109.             perror(name);
  110.         else    fprintf(stderr, "%s: too short for a news batch\n");
  111.         close(fd); return -1;
  112.     }
  113.     buf[sizeof buf - 1] = '\0';
  114.     if (strncmp(buf, lead, LEADLEN) != 0) {
  115.         fprintf(stderr, "%s: not a news batch (should start with %s)\n",
  116.             name, lead);
  117.         close(fd);
  118.         return -1;
  119.     }
  120.     here = 0; i = 0;
  121.     while (1) {
  122.         char *p;
  123.         int numsize;
  124.         long artstart, newpos;
  125.         offset = strtol(buf + LEADLEN, &p, 10);
  126.         if (offset == 0) {
  127.             fprintf(stderr,
  128.                 "%s: bad value after %s, file offset %ld\n",
  129.                 name, lead, here);
  130.             close(fd);
  131.             return -1;
  132.         }
  133.         numsize = p - (buf + LEADLEN);
  134.         artstart = here + LEADLEN + numsize + 1/*\n*/;
  135.         newpos = artstart + offset;
  136.         if (newpos == st.st_size)
  137.             return 0;
  138.         else if (newpos > st.st_size) {
  139.             char offstr[16];
  140. lastart:
  141.             offset = st.st_size - artstart;
  142. changeoffset:
  143.             sprintf(offstr + 1, "%ld", offset);
  144.             switch (strlen(offstr + 1) - numsize) {
  145.             case 0:        /* Same size, just overwrite. */
  146.                 p = offstr + 1;
  147.                 break;
  148.             case -1:    /* Shorter, use leading 0. */
  149.                 p = offstr; *p = '0';
  150.                 break;
  151.             case 1:        /* Longer, oops. */
  152.                 fprintf(stderr, "%s: no room to change article \
  153. length to %ld, file offset %ld\n", name, offset, here);
  154.                 goto setnewpos;
  155.             }
  156.             lseek(fd, here + LEADLEN, 0);
  157.             if (write(fd, p, numsize) < 0) {
  158.                 perror(name); return -1;
  159.             }
  160.             if (verbose)
  161.                 fprintf(stderr, "%s: changed article length to \
  162. %ld, file offset %ld\n", name, offset, here);
  163. setnewpos:
  164.             newpos = artstart + offset;
  165.             if (newpos >= st.st_size)
  166.                 return 0;
  167.         } else {    /* newpos < st.st_size */
  168.             lseek(fd, newpos - FUDGE, 0);
  169.             if (read(fd, buf, sizeof buf - 1) < sizeof buf - 1)
  170.                 goto lastart;
  171.             if (strncmp(buf + FUDGE, lead, LEADLEN) == 0) {
  172.                 strcpy(buf, buf + FUDGE);    /* Hmmm... */
  173.                 here = newpos;
  174.                 continue;
  175.             }
  176.             for (p = buf; (p = strchr(p, lead[0])) != NULL; p++)
  177.                 if (strncmp(p, lead, LEADLEN) == 0)
  178.                     break;
  179.             if (p == NULL) {
  180.                 fprintf(stderr, "%s: can't find next article \
  181. with offset %ld from file pos %ld\n", name, offset, here);
  182.                 close(fd); return -1;
  183.             }
  184.             offset = (newpos - FUDGE) + (p - buf) - artstart;
  185.             goto changeoffset;
  186.         }
  187.         lseek(fd, newpos, 0);
  188.         if (read(fd, buf, sizeof buf - 1) < sizeof buf - 1) {
  189.             fprintf(stderr, "%s: last article too short\n", name);
  190.             close(fd); return -1;
  191.         }
  192.         here = newpos;
  193.     }
  194. }
  195.