From 3b4778f8b295e3d89ddd940162ab14b485e58071 Mon Sep 17 00:00:00 2001 From: elad Date: Sun, 24 Sep 2006 15:32:48 +0000 Subject: [PATCH] PR/33319: Seebs: base64 is annoying Thanks to Matt Fleming for implementing a -m switch (base64 mode) for both uuencode(1) and uudecode(1)! Man-pages updated as well. --- usr.bin/uudecode/uudecode.c | 148 +++++++++++++++++++++++++----------- usr.bin/uuencode/uuencode.1 | 11 ++- usr.bin/uuencode/uuencode.c | 64 +++++++++++++--- 3 files changed, 168 insertions(+), 55 deletions(-) diff --git a/usr.bin/uudecode/uudecode.c b/usr.bin/uudecode/uudecode.c index 014dbef3d672..ff74e5f852b3 100644 --- a/usr.bin/uudecode/uudecode.c +++ b/usr.bin/uudecode/uudecode.c @@ -1,4 +1,4 @@ -/* $NetBSD: uudecode.c,v 1.20 2005/06/29 20:35:32 wiz Exp $ */ +/* $NetBSD: uudecode.c,v 1.21 2006/09/24 15:32:48 elad Exp $ */ /*- * Copyright (c) 1983, 1993 @@ -40,7 +40,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\ #if 0 static char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94"; #endif -__RCSID("$NetBSD: uudecode.c,v 1.20 2005/06/29 20:35:32 wiz Exp $"); +__RCSID("$NetBSD: uudecode.c,v 1.21 2006/09/24 15:32:48 elad Exp $"); #endif /* not lint */ /* @@ -51,11 +51,13 @@ __RCSID("$NetBSD: uudecode.c,v 1.20 2005/06/29 20:35:32 wiz Exp $"); */ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -64,9 +66,11 @@ __RCSID("$NetBSD: uudecode.c,v 1.20 2005/06/29 20:35:32 wiz Exp $"); static int decode(void); static void usage(void); +static int checkend(const char *, const char *, const char *); +static int base64_decode(void); int main(int, char *[]); -int pflag; +int base64, pflag; char *filename; int @@ -78,8 +82,11 @@ main(int argc, char *argv[]) setprogname(argv[0]); pflag = 0; - while ((ch = getopt(argc, argv, "p")) != -1) + while ((ch = getopt(argc, argv, "mp")) != -1) switch (ch) { + case 'm': + base64 = 1; + break; case 'p': pflag = 1; break; @@ -118,23 +125,37 @@ decode(void) char buf[MAXPATHLEN]; /* search for header line */ - do { + for (;;) { if (!fgets(buf, sizeof(buf), stdin)) { - warnx("%s: no \"begin\" line", filename); + warnx("%s: no \"%s\" line", filename, base64 ? + "begin-base64" : "begin"); return(1); } - } while (strncmp(buf, "begin ", 6)); + p = buf; + if (strncmp(p, "begin-base64", 12) == 0) { + base64 = 1; + p += 13; + break; + } else if (strncmp(p, "begin", 5) == 0) { + p += 6; + break; + } else + continue; + } + /* must be followed by an octal mode and a space */ - mode = strtol(buf + 6, &fn, 8); - if (fn == (buf+6) || !isspace((unsigned char)*fn) || mode==LONG_MIN || mode==LONG_MAX) + mode = strtol(p, &fn, 8); + if (fn == (p) || !isspace((unsigned char)*fn) || mode==LONG_MIN || mode==LONG_MAX) { - warnx("%s: invalid mode on \"begin\" line", filename); + warnx("%s: invalid mode on \"%s\" line", filename, + base64 ? "begin-base64" : "begin"); return(1); } /* skip whitespace for file name */ while (*fn && isspace((unsigned char)*fn)) fn++; if (*fn == 0) { - warnx("%s: no filename on \"begin\" line", filename); + warnx("%s: no filename on \"%s\" line", filename, + base64 ? "begin-base64" : "begin"); return(1); } /* zap newline */ @@ -173,54 +194,93 @@ decode(void) return(1); } - /* for each input line */ - for (;;) { - if (!fgets(p = buf, sizeof(buf), stdin)) { - warnx("%s: short file.", filename); - return(1); - } -#define DEC(c) (((c) - ' ') & 077) /* single character decode */ - /* - * `n' is used to avoid writing out all the characters - * at the end of the file. - */ - if ((n = DEC(*p)) <= 0) - break; - for (++p; n > 0; p += 4, n -= 3) - if (n >= 3) { - ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; - putchar(ch); - ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; - putchar(ch); - ch = DEC(p[2]) << 6 | DEC(p[3]); - putchar(ch); + if (base64) + return base64_decode(); + else { + /* for each input line */ + for (;;) { + if (!fgets(p = buf, sizeof(buf), stdin)) { + warnx("%s: short file.", filename); + return(1); } - else { - if (n >= 1) { +#define DEC(c) (((c) - ' ') & 077) /* single character decode */ + /* + * `n' is used to avoid writing out all the characters + * at the end of the file. + */ + if ((n = DEC(*p)) <= 0) + break; + for (++p; n > 0; p += 4, n -= 3) + if (n >= 3) { ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; putchar(ch); - } - if (n >= 2) { ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; putchar(ch); - } - if (n >= 3) { ch = DEC(p[2]) << 6 | DEC(p[3]); putchar(ch); } - } + else { + if (n >= 1) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + putchar(ch); + } + if (n >= 2) { + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + putchar(ch); + } + if (n >= 3) { + ch = DEC(p[2]) << 6 | DEC(p[3]); + putchar(ch); + } + } + } + if (!fgets(buf, sizeof(buf), stdin) || strcmp(buf, "end\n")) { + warnx("%s: no \"end\" line.", filename); + return(1); + } + return(0); } - if (!fgets(buf, sizeof(buf), stdin) || strcmp(buf, "end\n")) { - warnx("%s: no \"end\" line.", filename); - return(1); +} + +static int +checkend(const char *ptr, const char *end, const char *msg) +{ + size_t n; + + n = strlen(end); + if (strncmp(ptr, end, n) != 0 || + strspn(ptr + n, "\t\r\n") != strlen(ptr + n)) { + warnx("%s", msg); + return (1); } - return(0); + return (0); +} + +static int +base64_decode(void) +{ + int n; + char inbuf[MAXPATHLEN]; + unsigned char outbuf[MAXPATHLEN * 4]; + + for (;;) { + if (!fgets(inbuf, sizeof(inbuf), stdin)) { + warnx("%s: short file.", filename); + return (1); + } + n = b64_pton(inbuf, outbuf, sizeof(outbuf)); + if (n < 0) + break; + fwrite(outbuf, 1, n, stdout); + } + return (checkend(inbuf, "====", + "error decoding base64 input stream")); } static void usage() { - (void)fprintf(stderr, "usage: %s [-p] [file ...]\n", + (void)fprintf(stderr, "usage: %s [-m | -p] [file ...]\n", getprogname()); exit(1); } diff --git a/usr.bin/uuencode/uuencode.1 b/usr.bin/uuencode/uuencode.1 index 0eeb1d071d5f..d7f0f2415d42 100644 --- a/usr.bin/uuencode/uuencode.1 +++ b/usr.bin/uuencode/uuencode.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: uuencode.1,v 1.14 2003/08/07 11:16:58 agc Exp $ +.\" $NetBSD: uuencode.1,v 1.15 2006/09/24 15:32:48 elad Exp $ .\" .\" Copyright (c) 1980, 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" @(#)uuencode.1 8.1 (Berkeley) 6/6/93 .\" -.Dd March 19, 1999 +.Dd September 24, 2006 .Dt UUENCODE 1 .Os .Sh NAME @@ -38,6 +38,7 @@ .Nd encode/decode a binary file .Sh SYNOPSIS .Nm +.Op Fl m .Op Ar file .Ar name .Nm uudecode @@ -52,6 +53,12 @@ that do not support other than simple .Tn ASCII data. .Pp +The following options are available: +.Bl -tag +.It Fl m +Use base64 encoding. +.El +.Pp .Nm reads .Ar file diff --git a/usr.bin/uuencode/uuencode.c b/usr.bin/uuencode/uuencode.c index 2d75aea6ceaf..67d6ffd98213 100644 --- a/usr.bin/uuencode/uuencode.c +++ b/usr.bin/uuencode/uuencode.c @@ -1,4 +1,4 @@ -/* $NetBSD: uuencode.c,v 1.11 2005/06/29 20:35:48 wiz Exp $ */ +/* $NetBSD: uuencode.c,v 1.12 2006/09/24 15:32:48 elad Exp $ */ /*- * Copyright (c) 1983, 1993 @@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\ #if 0 static char sccsid[] = "@(#)uuencode.c 8.2 (Berkeley) 4/2/94"; #else -__RCSID("$NetBSD: uuencode.c,v 1.11 2005/06/29 20:35:48 wiz Exp $"); +__RCSID("$NetBSD: uuencode.c,v 1.12 2006/09/24 15:32:48 elad Exp $"); #endif #endif /* not lint */ @@ -50,9 +50,11 @@ __RCSID("$NetBSD: uuencode.c,v 1.11 2005/06/29 20:35:48 wiz Exp $"); */ #include #include +#include #include #include #include +#include #include #include #include @@ -60,20 +62,29 @@ __RCSID("$NetBSD: uuencode.c,v 1.11 2005/06/29 20:35:48 wiz Exp $"); int main(int, char *[]); static void encode(void); +static void base64_encode(void); static void usage(void); int main(int argc, char *argv[]) { struct stat sb; - int mode; + int base64, ch, mode; mode = 0; + base64 = 0; setlocale(LC_ALL, ""); setprogname(argv[0]); - while (getopt(argc, argv, "") != -1) - usage(); + while ((ch = getopt(argc, argv, "m")) != -1) { + switch(ch) { + case 'm': + base64 = 1; + break; + default: + usage(); + } + } argv += optind; argc -= optind; @@ -94,9 +105,16 @@ main(int argc, char *argv[]) usage(); } - (void)printf("begin %o %s\n", mode, *argv); - encode(); - (void)printf("end\n"); + if (base64) { + (void)printf("begin-base64 %o %s\n", mode, *argv); + base64_encode(); + (void)printf("====\n"); + } else { + (void)printf("begin %o %s\n", mode, *argv); + encode(); + (void)printf("end\n"); + } + if (ferror(stdout)) err(1, "write error"); exit(0); @@ -105,6 +123,34 @@ main(int argc, char *argv[]) /* ENC is the basic 1 character encoding function to make a char printing */ #define ENC(c) ((c) ? ((c) & 077) + ' ': '`') +/* + * copy from in to out, encoding in base64 as you go along. + */ +static void +base64_encode(void) +{ + /* + * Output must fit into 80 columns, chunks come in 4, leave 1. + */ +#define GROUPS ((70 / 4) - 1) + unsigned char buf[3]; + char buf2[sizeof(buf) * 2 + 1]; + size_t n; + int rv, sequence; + + sequence = 0; + + while ((n = fread(buf, 1, sizeof(buf), stdin))) { + ++sequence; + rv = b64_ntop(buf, n, buf2, (sizeof(buf2) / sizeof(buf2[0]))); + if (rv == -1) + errx(1, "b64_ntop: error encoding base64"); + printf("%s%s", buf2, (sequence % GROUPS) ? "" : "\n"); + } + if (sequence % GROUPS) + printf("\n"); +} + /* * copy from in to out, encoding as you go along. */ @@ -150,7 +196,7 @@ encode(void) static void usage(void) { - (void)fprintf(stderr, "usage: %s [infile] remotefile\n", + (void)fprintf(stderr, "usage: %s [-m] [infile] remotefile\n", getprogname()); exit(1); }