From owner-freebsd-standards Fri Mar 1 17:27: 6 2002 Delivered-To: freebsd-standards@freebsd.org Received: from sunny.newgold.net (durham-ar1-174-172.durham.dsl.gtei.net [4.40.174.172]) by hub.freebsd.org (Postfix) with ESMTP id B089137B405 for ; Fri, 1 Mar 2002 17:26:48 -0800 (PST) Received: from sunny.newgold.net (freebsd@localhost [IPv6:::1]) by sunny.newgold.net (8.12.1/8.12.1) with ESMTP id g2215PDF012492 for ; Sat, 2 Mar 2002 01:06:46 GMT Received: (from freebsd@localhost) by sunny.newgold.net (8.12.1/8.12.1/Submit) id g2215ON8021952 for freebsd-standards@freebsd.org; Sat, 2 Mar 2002 01:05:24 GMT Date: Sat, 2 Mar 2002 01:04:02 +0000 From: "J. Mallett" To: freebsd-standards@freebsd.org Subject: base64 support for uuencode/uudecode Message-ID: <20020302010401.A18553@FreeBSD.ORG> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.3.21i Organisation: FreeBSD Sender: owner-freebsd-standards@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG 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 '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 +#include +#include #include +#include + #include +#include #include #include +#include #include 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 +#include #include +#include + #include -#include #include +#include #include #include #include @@ -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