Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 2 Mar 2002 01:04:02 +0000
From:      "J. Mallett" <jmallett@freebsd.org>
To:        freebsd-standards@freebsd.org
Subject:   base64 support for uuencode/uudecode
Message-ID:  <20020302010401.A18553@FreeBSD.ORG>

next in thread | raw e-mail | index | archive | help
Hello,

Below is a patch that adds most notably base64 encoding and decoding to 
uuencode and uudecode respectively.  uuencode(1) recieves two new options 
here, one of which is -m (for MIME) which will cause the output to be 
encoded in base64 instead of the normal uuencode format, the other is -o, 
which while not in SUSv3 I believe is probably logical as that behaviour 
is seen in uudecode and thus may be expected by the user of uuencode, but 
that is of course something I'm willing to hear arguments for or against.

The other notable part of adding base64 support to uuencode is of course 
the addition of uudecode support for the same encoding format.  This is 
done based on what SUSv3 expects, the "begin-base64" replacement of 
"begin", and "====" instead of the terminal string in uuencode format.

To use the b64_{pton,ntop} functions in libc, I had to include 3 
networking related headers, so I could use <resolv.h>'s prototype and 
wrapper from b64_* to _b64_*.

Aside from that, I can't think of anything much that is worth mentioning, 
except that I cleaned up most of the warnings along the way, and that it 
seems to compile fine with BDECFLAGS, and that I cleaned up the style 
nits that stood out as unfathombly gross.

I look forward to your comments.

	Thanks,
	/j.

Index: uuencode/uuencode.1
===================================================================
RCS file: /home/ncvs/src/usr.bin/uuencode/uuencode.1,v
retrieving revision 1.14
diff -u -r1.14 uuencode.1
--- uuencode/uuencode.1	27 Jan 2002 18:21:23 -0000	1.14
+++ uuencode/uuencode.1	2 Mar 2002 00:30:51 -0000
@@ -41,6 +41,8 @@
 .Nd encode/decode a binary file
 .Sh SYNOPSIS
 .Nm
+.Op Fl m
+.Op Fl o Ar output_file
 .Op Ar file
 .Ar name
 .Nm uudecode
@@ -63,7 +65,9 @@
 reads
 .Ar file
 (or by default the standard input) and writes an encoded version
-to the standard output.
+to the standard output, or
+.Ar output_file
+if one has been specified.
 The encoding uses only printing
 .Tn ASCII
 characters and includes the
@@ -86,7 +90,20 @@
 .Nm Uudecode
 ignores any leading and trailing lines.
 .Pp
-The following options are available for
+The following options are available:
+.Pp
+.Nm uuencode :
+.Bl -tag -width ident
+.It Fl m
+Use the Base64 method of encoding, rather than the traditional
+.Nm
+algorithm.
+.It Fl o Ar output_file
+Output to
+.Ar output_file
+instead of standard output.
+.El
+.Pp
 .Nm uudecode :
 .Bl -tag -width ident
 .It Fl c
Index: uuencode/uuencode.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/uuencode/uuencode.c,v
retrieving revision 1.7
diff -u -r1.7 uuencode.c
--- uuencode/uuencode.c	9 Oct 2001 11:05:27 -0000	1.7
+++ uuencode/uuencode.c	2 Mar 2002 00:30:51 -0000
@@ -50,27 +50,53 @@
  *
  * Encode a file so it can be mailed to a remote system.
  */
-#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 
+#include <netinet/in.h>
+
 #include <err.h>
+#include <resolv.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 void encode __P((void));
+void base64_encode __P((void));
 static void usage __P((void));
 
+FILE *output = stdout;
+int mode;
+char **av;
+
 int
 main(argc, argv)
 	int argc;
 	char *argv[];
 {
 	struct stat sb;
-	int mode;
-
-	while (getopt(argc, argv, "") != -1)
-		usage();
+	int base64;
+	char ch;
+	char *outfile;
+
+	base64 = 0;
+	outfile = NULL;
+
+	while ((ch = getopt(argc, argv, "mo:")) != -1) {
+		switch (ch) {
+		case 'm':
+			base64 = 1;
+			break;
+		case 'o':
+			outfile = optarg;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	}
 	argv += optind;
 	argc -= optind;
 
@@ -91,9 +117,18 @@
 		usage();
 	}
 
-	(void)printf("begin %o %s\n", mode, *argv);
-	encode();
-	(void)printf("end\n");
+	av = argv;
+
+	if (outfile != NULL) {
+		output = fopen(outfile, "w+");
+		if (output == NULL)
+			err(1, "Unable to open %s for output!\n", outfile);
+		chmod(outfile, 0644);
+	}
+	if (base64)
+		base64_encode();
+	else
+		encode();
 	if (ferror(stdout))
 		errx(1, "write error");
 	exit(0);
@@ -103,6 +138,34 @@
 #define	ENC(c) ((c) ? ((c) & 077) + ' ': '`')
 
 /*
+ * copy from in to out, encoding in base64 as you go along.
+ */
+void
+base64_encode(void)
+{
+#define	GROUPS	8 /* Group output chunks */
+	unsigned char buf[6];
+	char buf2[16];
+	size_t n;
+	int rv, sequence;
+
+	sequence = 0;
+
+	fprintf(output, "begin-base64 %o %s\n", mode, *av);
+	while ((n = fread(buf, sizeof(buf[0]),
+	    (sizeof(buf) / sizeof(buf[0])), stdin))) {
+		++sequence;
+		rv = b64_ntop(buf, n, buf2, (sizeof(buf2) / sizeof(buf2[0])));
+		if (rv == -1)
+			errx(1, "b64_ntop: error encoding base64");
+		fprintf(output, "%s%s", buf2, (sequence % GROUPS) ? "" : "\n");
+	}
+	if (sequence % GROUPS)
+		fprintf(output, "\n");
+	fprintf(output, "====\n");
+}
+
+/*
  * copy from in to out, encoding as you go along.
  */
 void
@@ -112,9 +175,10 @@
 	register char *p;
 	char buf[80];
 
+	(void)fprintf(output, "begin %o %s\n", mode, *av);
 	while ((n = fread(buf, 1, 45, stdin))) {
 		ch = ENC(n);
-		if (putchar(ch) == EOF)
+		if (fputc(ch, output) == EOF)
 			break;
 		for (p = buf; n > 0; n -= 3, p += 3) {
 			/* Pad with nulls if not a multiple of 3. */
@@ -125,34 +189,32 @@
 			}
 			ch = *p >> 2;
 			ch = ENC(ch);
-			if (putchar(ch) == EOF)
+			if (fputc(ch, output) == EOF)
 				break;
 			ch = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
 			ch = ENC(ch);
-			if (putchar(ch) == EOF)
+			if (fputc(ch, output) == EOF)
 				break;
 			ch = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
 			ch = ENC(ch);
-			if (putchar(ch) == EOF)
+			if (fputc(ch, output) == EOF)
 				break;
 			ch = p[2] & 077;
 			ch = ENC(ch);
-			if (putchar(ch) == EOF)
+			if (fputc(ch, output) == EOF)
 				break;
 		}
-		if (putchar('\n') == EOF)
+		if (fputc('\n', output) == EOF)
 			break;
 	}
 	if (ferror(stdin))
 		errx(1, "read error");
-	ch = ENC('\0');
-	(void)putchar(ch);
-	(void)putchar('\n');
+	(void)fprintf(output, "%c\nend\n", ENC('\0'));
 }
 
 static void
 usage()
 {
-	(void)fprintf(stderr,"usage: uuencode [infile] remotefile\n");
+	(void)fprintf(stderr,"usage: uuencode [-m] [-o outfile] [infile] remotefile\n");
 	exit(1);
 }
Index: uudecode/uudecode.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/uudecode/uudecode.c,v
retrieving revision 1.17
diff -u -r1.17 uudecode.c
--- uudecode/uudecode.c	27 Jan 2002 18:21:23 -0000	1.17
+++ uudecode/uudecode.c	2 Mar 2002 00:30:51 -0000
@@ -52,11 +52,14 @@
  * used with uuencode.
  */
 #include <sys/param.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 
+#include <netinet/in.h>
+
 #include <err.h>
-#include <fnmatch.h>
 #include <pwd.h>
+#include <resolv.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -69,6 +72,7 @@
 static void usage __P((void));
 int	decode __P((void));
 int	decode2 __P((int));
+void	base64_decode __P((const char *));
 
 int
 main(argc, argv)
@@ -109,8 +113,8 @@
 			usage();
 		}
 	}
-        argc -= optind;
-        argv += optind;
+	argc -= optind;
+	argv += optind;
 
 			
 	if (*argv) {
@@ -131,22 +135,22 @@
 }
 
 int
-decode ()
+decode(void)
 {
 	int flag;
 
 	/* decode only one file per input stream */
 	if (!cflag) 
-		return(decode2(0));
+		return (decode2(0));
 
 	/* multiple uudecode'd files */
 	for (flag = 0; ; flag++)
 		if (decode2(flag))
-			return(1);
+			return (1);
 		else if (feof(stdin))
 			break;
 
-	return(0);
+	return (0);
 }
 
 int
@@ -156,31 +160,40 @@
 	struct passwd *pw;
 	register int n;
 	register char ch, *p;
-	int ignore, mode, n1;
+	int base64, ignore, mode, n1;
 	char buf[MAXPATHLEN];
 	char buffn[MAXPATHLEN]; /* file name buffer */
 
-	ignore = 0;
+	base64 = ignore = 0;
 	/* search for header line */
 	do {
 		if (!fgets(buf, sizeof(buf), stdin)) {
 			if (flag) /* no error */
-				return(0);
+				return (0);
 
 			warnx("%s: no \"begin\" line", filename);
-			return(1);
+			return (1);
 		}
-	} while (strncmp(buf, "begin ", 6) || 
-		 fnmatch("begin [0-7]* *", buf, 0));
+	} while (strncmp(buf, "begin", 5) != 0);
+
+	if (strncmp(buf, "begin-base64", 12) == 0)
+		base64 = 1;
 
 	if (oflag) {
-		(void)sscanf(buf, "begin %o ", &mode);
+		if (base64)
+			(void)sscanf(buf, "begin-base64 %o ", &mode);
+		else
+			(void)sscanf(buf, "begin %o ", &mode);
 		if (strlcpy(buf, outfile, sizeof(buf)) >= sizeof(buf)) {
 			warnx("%s: filename too long", outfile);
 			return (1);
 		}
-	} else
-		(void)sscanf(buf, "begin %o %[^\n\r]", &mode, buf);
+	} else {
+		if (base64)
+			(void)sscanf(buf, "begin-base64 %o %[^\n\r]", &mode, buf);
+		else
+			(void)sscanf(buf, "begin %o %[^\n\r]", &mode, buf);
+	}
 
 	if (!sflag && !pflag) {
 		strncpy(buffn, buf, sizeof(buffn)); 
@@ -188,7 +201,7 @@
 			strncpy(buf, strrchr(buffn, '/') + 1, sizeof(buf));
 		if (buf[0] == '\0') {
 			warnx("%s: illegal filename", buffn);
-			return(1);
+			return (1);
 		}
 	}
 
@@ -196,18 +209,18 @@
 	if (buf[0] == '~') {
 		if (!(p = index(buf, '/'))) {
 			warnx("%s: illegal ~user", filename);
-			return(1);
+			return (1);
 		}
 		*p++ = '\0';
 		if (!(pw = getpwnam(buf + 1))) {
 			warnx("%s: no user %s", filename, buf);
-			return(1);
+			return (1);
 		}
 		n = strlen(pw->pw_dir);
 		n1 = strlen(p);
 		if (n + n1 + 2 > MAXPATHLEN) {
 			warnx("%s: path too long", filename);
-			return(1);
+			return (1);
 		}
 		bcopy(p, buf + n + 1, n1 + 1);
 		bcopy(pw->pw_dir, buf, n);
@@ -225,16 +238,23 @@
 		} else if (!freopen(buf, "w", stdout) ||
 		    fchmod(fileno(stdout), mode&0666)) {
 			warn("%s: %s", buf, filename);
-			return(1);
+			return (1);
 		}
 	}
 	strcpy(buffn, buf); /* store file name from header line */
 
 	/* for each input line */
+next:
 	for (;;) {
 		if (!fgets(p = buf, sizeof(buf), stdin)) {
 			warnx("%s: short file", filename);
-			return(1);
+			return (1);
+		}
+		if (base64) {
+			if (strncmp(buf, "====", 4) == 0)
+				return (0);
+			base64_decode(buf);
+			goto next;
 		}
 #define	DEC(c)	(((c) - ' ') & 077)		/* single character decode */
 #define IS_DEC(c) ( (((c) - ' ') >= 0) &&  (((c) - ' ') <= 077 + 1) )
@@ -245,7 +265,7 @@
     warnx( \
 "\n\tinput file: %s\n\tencoded file: %s\n\tcharacter out of range: [%d-%d]", \
  	filename, buffn, 1 + ' ', 077 + ' ' + 1); \
-        return(1); \
+        return (1); \
 }
 #define PUTCHAR(c) \
 if (!ignore) \
@@ -300,9 +320,22 @@
 	    (strcmp(buf, "end") && strcmp(buf, "end\n") &&
 	     strcmp(buf, "end\r\n"))) {
 		warnx("%s: no \"end\" line", filename);
-		return(1);
+		return (1);
 	}
-	return(0);
+
+	return (0);
+}
+
+void
+base64_decode(const char *stream)
+{
+	unsigned char out[MAXPATHLEN * 4];
+	int rv;
+
+	rv = b64_pton(stream, out, (sizeof(out) / sizeof(out[0])));
+	if (rv == -1)
+		errx(1, "b64_pton: error decoding base64 input stream");
+	printf("%s", out);
 }
 
 static void


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-standards" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020302010401.A18553>