[news.software.b] c7decode for Jon Zeeff's rnews replacement

gemini@geminix.UUCP (Uwe Doering) (01/06/90)

Here is a patch for Jon Zeeff's great rnews replacement. The original
release didn't support c7encoded news batches. This is fixed by this
patch.

C7encode is used by sites that get or deliver their news via uucp f-protocol
or an X.25 link. These protocols are 7-bit only.

If you think you have already seen this patch some weeks ago in this
newsgroup note that this is an updated version of that patch. The old
one had a bug. But because, due to a major news feed reshuffle here in
West Germany, this old patch wasn't distributed worldwide (I think),
I now rather post the complete patch instead of a patch to a patch.
Got it?

    Uwe


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	rnews.diff
# This archive created: Mon Jan  1 21:10:38 1990
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'rnews.diff'" '(7666 characters)'
if test -f 'rnews.diff'
then
	echo shar: "will not over-write existing file 'rnews.diff'"
else
sed 's/^X//' << \SHAR_EOF > 'rnews.diff'
X*** rnews.c.00	Mon Jan  1 21:03:48 1990
X--- rnews.c	Thu Dec 28 20:50:54 1989
X***************
X*** 54,59 ****
X--- 54,61 ----
X  2) don't hold me responsible for any problems.  
X  3) report all bugs and modifications to me via email 
X  
X+ Support for c7decode added by Uwe Doering <gemini@netmbx.UUCP>
X+ I used the original Cnews c7decode.c with slight modifications.
X  */
X  
X  #include <stdio.h>
X***************
X*** 92,102 ****
X  main()
X  {
X  	char buffer[20];
X  
X  	/* get rid of our suid root status completely */
X  	if (setgid(NEWS_GROUP) || setuid(NEWS_UID)) {
X             perror("can't set uid or gid\n");
X!            /* exit(1); /* */
X          }
X  
X  	/* replace environment with a clean one */
X--- 94,106 ----
X  main()
X  {
X  	char buffer[20];
X+ 	int pid,wpid,pfildes[2],exit_stat = 0;
X+ 	FILE *rnews_pipe;
X  
X  	/* get rid of our suid root status completely */
X  	if (setgid(NEWS_GROUP) || setuid(NEWS_UID)) {
X             perror("can't set uid or gid\n");
X!            exit(1); /* */
X          }
X  
X  	/* replace environment with a clean one */
X***************
X*** 139,158 ****
X  	(void) sleep(1);
X  #endif
X  
X! 	if (fread(buffer, 1, 12, stdin) != 12) {
X! 		fprintf(stderr, "could not read in first 12 characters\n");
X  		exit(4);
X  	}
X  
X! 	if (strncmp(buffer, "#! cunbatch\n",12) == 0) 
X  	   uncompress();
X  	else if (buffer[0] == 0x1f) {   /* compressed w/o cunbatch */
X                  rewind(stdin);          /* won't work on a pipe */
X                  uncompress();
X               }
X          else {                                          /* plain text */
X!             if (fwrite(buffer,1,12,relaynews) != 12) {
X! 		fprintf(stderr, "error writing first 12 characters\n");
X  		exit(5);
X  	    }
X  	    copyout();
X--- 143,203 ----
X  	(void) sleep(1);
X  #endif
X  
X! 	if (fread(buffer, 1, 13, stdin) != 13) {
X! 		fprintf(stderr, "could not read in first 13 characters\n");
X  		exit(4);
X  	}
X  
X! 	if (strncmp(buffer, "#! cunbatch\n",12) == 0) {
X! 	   (void) ungetc(buffer[12], stdin);
X  	   uncompress();
X+ 	}
X+ 	else if (strncmp(buffer, "#! c7unbatch\n",13) == 0) {
X+ 		   if (pipe(pfildes) != 0) {
X+ 		      fprintf(stderr, "could not open interprocess pipe\n");
X+ 		      exit(7);
X+ 		   }
X+ 		   if ((pid = fork()) == -1) {
X+ 		      fprintf(stderr, "could not fork\n");
X+ 		      exit(8);
X+ 		   }
X+ 		   if (pid) {
X+ 		      (void) fclose(stdin);
X+ 		      if ((rnews_pipe = fdopen(pfildes[0],"r")) == NULL) {
X+ 			 fprintf(stderr, "could not open rnews_pipe for input\n");
X+ 			 exit(9);
X+ 		      }
X+ 		      (void) close(pfildes[1]);
X+ 		      uncompress();
X+ 		      (void) fclose(rnews_pipe);
X+ 		      (void) close(pfildes[0]);
X+ 		      while ((wpid = wait(&exit_stat)) != pid && wpid != -1)
X+ 			    ;
X+ 		      if (exit_stat)
X+ 			 exit(10);
X+ 		   }
X+ 		   else {
X+ 		      int result;
X+ 
X+ 		      (void) fclose(relaynews);
X+ 		      if ((rnews_pipe = fdopen(pfildes[1],"w")) == NULL) {
X+ 			 fprintf(stderr, "could not open rnews_pipe for output\n");
X+ 			 exit(11);
X+ 		      }
X+ 		      (void) close(pfildes[0]);
X+ 		      result = c7decode();
X+ 		      (void) fclose(rnews_pipe);
X+ 		      (void) close(pfildes[1]);
X+ 		      exit(result);
X+ 		   }
X+ 	     }
X  	else if (buffer[0] == 0x1f) {   /* compressed w/o cunbatch */
X                  rewind(stdin);          /* won't work on a pipe */
X                  uncompress();
X               }
X          else {                                          /* plain text */
X!             if (fwrite(buffer,1,13,relaynews) != 13) {
X! 		fprintf(stderr, "error writing first 13 characters\n");
X  		exit(5);
X  	    }
X  	    copyout();
X***************
X*** 163,169 ****
X             exit(6);
X          }
X  
X!         return 0;
X  }
X  
X  /* Copy stdin to relaynews */
X--- 208,214 ----
X             exit(6);
X          }
X  
X!         exit(0);
X  }
X  
X  /* Copy stdin to relaynews */
X***************
X*** 1338,1340 ****
X--- 1383,1570 ----
X  	(void)fprintf(stream, "%d.%02d%%", q / 100, q % 100);
X  }
X  
X+ /* c7decode */
X+ 
X+ /*
X+  * This program is the inverse of encode
X+  *
X+  * It collects runs of 12 characters, combines pairs of those
X+  * to form 6 13 bit numbers, extracts the top bit of each of
X+  * those to make a 13th 6 bit character, and splits each of
X+  * the remaining 6 12 bit numbers to form 12 6 bit ones.
X+  *
X+  * The strings of 6 bit numbers are collected into groups of
X+  * 4 and converted into 3 8 bit characters.
X+  *
X+  * Now all that would be trivial, if we didn't need to worry
X+  * about ending all this correctly.  About 1/2 of the following
X+  * program wouldn't be here if the ending didn't matter....
X+  */
X+ 
X+ /*
X+  * the following pair of characters can never occur as a pair
X+  * in legal input (since (90 * 91 + 90) > 2^13) - they are
X+  * noticed at the beginning of a 12 char block, and serve to
X+  * indicate that this block is the terminator.  The character
X+  * immediately following is the (expanded) terminator length.
X+  */
X+ #define	ENDMARK1	((90*91 + 90) / 91)
X+ #define	ENDMARK2	((90*91 + 90) % 91)
X+ 
X+ int errcnt = 0;
X+ 
X+ c7decode()
X+ {
X+ 	register c;
X+ 	register char *p;
X+ 	register i;
X+ 	register first = 1;
X+ 	register cnt = 0;
X+ 	char b12[12];
X+ 	char c12[12];
X+ 
X+ 	p = b12;
X+ 	i = 12;
X+ 
X+ 	while ((c = getchar()) != EOF) {
X+ 		if (c < ' ' || c >= (' ' + 91)) {
X+ 			if (errcnt++ == 0)
X+ 				fprintf(stderr, "c7decode: Bad data\n");
X+ 			continue;
X+ 		}
X+ 		if (i == 10 && p[-1] == ENDMARK1 && p[-2] == ENDMARK2) {
X+ 			cnt = c - ' ';
X+ 			i = 12;
X+ 			p -= 2;
X+ 			continue;
X+ 		}
X+ 		*p++ = c - ' ';
X+ 		if (--i == 0) {
X+ 			if (p == &b12[12]) {
X+ 				if (!first)
X+ 					pack12(c12, 12, 0);
X+ 				else
X+ 					first = 0;
X+ 				p = c12;
X+ 			} else {
X+ 				pack12(b12, 12, 0);
X+ 				p = b12;
X+ 			}
X+ 			i = 12;
X+ 		}
X+ 	}
X+ 
X+ 	if (p >= &b12[0] && p < &b12[12]) {
X+ 		if (!first)
X+ 			pack12(c12, 12, i == 12 ? cnt : 0);
X+ 	} else
X+ 		pack12(b12, 12, i == 12 ? cnt : 0);
X+ 
X+ 	if (i != 12) {
X+ 		if (p >= &b12[0] && p < &b12[12])
X+ 			pack12(b12, 12-i, cnt);
X+ 		else
X+ 			pack12(c12, 12-i, cnt);
X+ 	}
X+ 
X+ 	return((errcnt > 0) ? 1 : 0);
X+ }
X+ 
X+ static char b4[4];
X+ static int cnt = 0;
X+ 
X+ pack12(p, n, last)
X+ 	register char *p;
X+ 	register n;
X+ 	int last;
X+ {
X+ 	register i;
X+ 	register char *q;
X+ 	char b13[13];
X+ 
X+ 	{
X+ 		register c;
X+ 		register c13;
X+ 
X+ 		q = b13;
X+ 		c13 = 0;
X+ 
X+ 		for (i = 0; i < n; i += 2) {
X+ 			c = *p++ * 91;
X+ 			c += *p++;
X+ 			c13 <<= 1;
X+ 			if (c & (1 << 12))
X+ 				c13 |= 1;
X+ 			*q++ = (c >> 6) & 0x3f;
X+ 			*q++ = c & 0x3f;
X+ 		}
X+ 		*q++ = c13;
X+ 		if (last)
X+ 			q = &b13[last];
X+ 	}
X+ 
X+ 	p = b13;
X+ 	n = q - p;
X+ 	i = cnt;
X+ 	q = &b4[cnt];
X+ 
X+ 	while (--n > 0) {
X+ 		*q++ = *p++;
X+ 		if (++i == 4) {
X+ 			char b3[3];
X+ 			register char *b = b4;
X+ 
X+ 			/* inline expansion of pack6bit, to save calls ... */
X+ 
X+ 			q = b3;
X+ 			*q++ = (b[0] << 2) | ((b[1] >> 4) & 0x3);
X+ 			*q++ = (b[1] << 4) | ((b[2] >> 2) & 0xf);
X+ 			*q = (b[2] << 6) | (b[3] & 0x3f);
X+ 
X+ 			q = b3;
X+ 			while (--i > 0)
X+ 				putchar(*q++);
X+ 
X+ 			q = b4;
X+ 		}
X+ 	}
X+ 
X+ 	*q++ = *p++;	/* the last octet */
X+ 	++i;
X+ 
X+ 	if (last || i == 4) {
X+ 		pack6bit(b4, i, last);
X+ 		i = 0;
X+ 	}
X+ 
X+ 	cnt = i;
X+ }
X+ 
X+ pack6bit(p, n, last)
X+ 	register char *p;
X+ 	register int n;
X+ 	int last;
X+ {
X+ 	register char *q;
X+ 	register i = 3;
X+ 	char b3[3];
X+ 
X+ 	if (last) {
X+ 		i = p[n-1];
X+ 		if (i >= 3) {
X+ 			fprintf(stderr, "c7decode: Badly encoded file\n");
X+ 			errcnt++;
X+ 			i = 3;		/* do the best we can */
X+ 		}
X+ 	}
X+ 
X+ 	q = b3;
X+ 	*q++ = (p[0] << 2) | ((p[1] >> 4) & 0x3);
X+ 	*q++ = (p[1] << 4) | ((p[2] >> 2) & 0xf);
X+ 	*q = (p[2] << 6) | (p[3] & 0x3f);
X+ 
X+ 	q = b3;
X+ 
X+ 	while (--i >= 0)
X+ 		putchar(*q++);
X+ }
SHAR_EOF
if test 7666 -ne "`wc -c < 'rnews.diff'`"
then
	echo shar: "error transmitting 'rnews.diff'" '(should have been 7666 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
Uwe Doering   |  Domain   : gemini@netmbx.UUCP
Berlin        |---------------------------------------------------------------
West Germany  |  Bangpath : ...!uunet!unido!tmpmbx!netmbx!gemini