Add base64 support to uuencode(1) and uudecode(1), as specified by SUSv3.

Add `-o' option to uuencode(1) to pipe the uuencoded output to an
arbitrary file, instead of just stdout.

Reviewed by:	-standards, mike
Approved by:	mike
This commit is contained in:
Juli Mallett 2002-03-05 03:27:47 +00:00
parent 996abba928
commit 0e01f18b86
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=91661
3 changed files with 139 additions and 29 deletions

View File

@ -52,11 +52,14 @@ static const char rcsid[] =
* 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 @@ int cflag, iflag, oflag, pflag, sflag;
static void usage __P((void));
int decode __P((void));
int decode2 __P((int));
void base64_decode __P((const char *));
int
main(argc, argv)
@ -155,11 +159,11 @@ decode2(flag)
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)) {
@ -169,17 +173,26 @@ decode2(flag)
warnx("%s: no \"begin\" line", filename);
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));
@ -230,11 +243,18 @@ decode2(flag)
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);
}
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) )
/* #define IS_DEC(c) (1) */
@ -304,6 +324,19 @@ if (!ignore) \
return(0);
}
void
base64_decode(stream)
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
usage()
{

View File

@ -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 @@ data.
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 @@ and execute bits are not retained.
.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

View File

@ -50,27 +50,53 @@ static const char rcsid[] =
*
* 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;
int base64;
char ch;
char *outfile;
while (getopt(argc, argv, "") != -1)
usage();
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,10 +117,18 @@ main(argc, argv)
usage();
}
(void)printf("begin %o %s\n", mode, *argv);
encode();
(void)printf("end\n");
if (ferror(stdout))
av = argv;
if (outfile != NULL) {
output = fopen(outfile, "w+");
if (output == NULL)
err(1, "unable to open %s for output", outfile);
}
if (base64)
base64_encode();
else
encode();
if (ferror(output))
errx(1, "write error");
exit(0);
}
@ -103,7 +137,34 @@ main(argc, argv)
#define ENC(c) ((c) ? ((c) & 077) + ' ': '`')
/*
* copy from in to out, encoding as you go along.
* Copy from in to out, encoding in base64 as you go along.
*/
void
base64_encode()
{
#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, 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");
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
encode()
@ -112,9 +173,10 @@ encode()
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 +187,32 @@ encode()
}
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);
}