[net.sources] uuencode/uudecode sources

coulter@hplabsc.UUCP (Michael Coulter) (05/22/86)

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by coulter at hplmac on Thu May 22 12:54:36 1986
#
# This archive contains:
#	README		uudecode.bas	uudecode.c	uuencode.1c	
#	uuencode.c	

echo x - README
cat >README <<'@EOF'

This shar file contains the C source for uuencode and uudecode.  It also
has the MSDOS BASIC code for uudecode.  There is a man page in
uuencode.1c.  P.S. - I didn't write any of it.

-- Michael Coulter ...hplabs!coulter
@EOF
size=`wc -c <README`; if test $size -ne 222 ; then
	echo ERROR: README is $size bytes but should be 222.
fi

chmod 644 README

echo x - uudecode.bas
cat >uudecode.bas <<'@EOF'
# Written  1:32 am  Feb 17, 1986 by rde@ukc.ac.uk in net.sources
# In Real Life: R.D.Eager at U of Kent at Canterbury, Canterbury, UK
# Subject: uudecode in MS-BASIC

[food for line eater]

There  has been some discussion about public domain versions of uudecode
for those souls who didn't get it in a distribution. I  thought  it  was
time  to post the updated version of uudecode in Microsoft BASIC; I have
made a minor change to cater for a variation in  coding  encountered  on
some uuencoded files.

This  program  is  short  enough  that  it  can  be  typed in by hand if
necessary. I hope it is of some  use  to  micro  owners  without  direct
access to other uudecodes.

---------CUT HERE--------CUT HERE----------CUT HERE---------CUT HERE------
1000 DEFINT A-Z
1010 REM Trap filing errors
1020 ON ERROR GOTO 1600
1030 CLS
1040 LOCATE 5,11
1050 PRINT STRING$(40," ")
1060 LOCATE 5,11
1070 INPUT "Enter name of input file: ", INFILE$
1080 OPEN INFILE$ FOR INPUT AS #1
1090 LOCATE 8,10
1100 PRINT STRING$(40," ")
1110 LOCATE 8,10
1120 INPUT "Enter name of output file: ", OUTFILE$
1130 OPEN "R", #2,OUTFILE$, 1
1140 FIELD #2, 1 AS N$
1150 REM Search for header line
1160 LINE INPUT #1,A$
1170 IF LEFT$(A$,5) <>"begin" THEN 1160
1180 LOCATE 11,10
1190 PRINT "Header = ";A$
1200 SP = ASC(" ")
1210 DIM BUF(5000)
1220 P = 0
1230 REM Main loop
1240 LINE INPUT #1, A$
1250 P = 0
1260 COUNT = ASC(LEFT$(A$,1)) - SP
1270 IF COUNT <> 64 THEN 1290
1280 COUNT = 0
1290 IF COUNT = 0 THEN 1560
1300 ADJ = COUNT MOD 4
1310 FOR I = 2 TO LEN(A$) STEP 4
1320    X1 = ASC(MID$(A$,I,I)) - SP
1330    IF X1 <> 64 THEN 1350
1340    X1 = 0
1350    X2 = ASC(MID$(A$,I+1,I+1)) - SP
1360    IF X2 <> 64 THEN 1380
1370    X2 = 0
1380    X3 = ASC(MID$(A$,I+2,I+2)) - SP
1390    IF X3 <> 64 THEN 1410
1400    X3 = 0
1410    X4 = ASC(MID$(A$,I+3,I+3)) - SP
1420    IF X4 <> 64 THEN 1440
1430    X4 = 0
1440    P = P + 1
1450    BUF(P) = (X2\16) + (X1*4)
1460    P = P + 1
1470    BUF(P) = (X3\4) + ((X2 MOD 16) * 16)
1480    P = P + 1
1490    BUF(P) = X4 + ((X3 MOD 4) * 64)
1500 NEXT I
1510 FOR I = 1 TO P
1520   LSET N$ = CHR$(BUF(I))
1530   PUT #2
1540 NEXT I
1550 GOTO 1240
1560 END
1570 REM
1580 REM Error trapping routine for file handling
1590 REM
1600 IF ERL <> 1080 GOTO 1650          ' not input file problem
1610 LOCATE 22,20
1620 PRINT "Can't open input file"
1630 GOSUB 1780
1640 RESUME 1040
1650 IF ERL <> 1130 GOTO 1700          ' not output file problem
1660 LOCATE 22,20
1670 PRINT "Can't open output file"
1680 GOSUB 1780
1690 RESUME 1090
1700 IF ERL <> 1160 THEN 1770
1710 LOCATE 22,20
1720 PRINT "Header line not found"
1730 GOSUB 1780
1740 GOSUB 1780
1750 LOCATE 24,1
1760 END
1770 ERROR ERR
1780 FOR I = 1 TO 5000: NEXT I
1790 LOCATE 22,20
1800 PRINT STRING$(30," ")
1810 RETURN
TE 24,1
1760 END
1770 ERROR ERR
1780 FOR I = 1 TO 5000: NEXT I
1
---------CUT HERE--------CUT HERE----------CUT HERE---------CUT HERE------
-- 
           Bob Eager

           rde@ukc.UUCP
           rde@ukc
           ...!mcvax!ukc!rde

           Phone: +44 227 66822 ext 7589
# End of text from net.sources on hplabsc.UUCP
@EOF
size=`wc -c <uudecode.bas`; if test $size -ne 3106 ; then
	echo ERROR: uudecode.bas is $size bytes but should be 3106.
fi

chmod 644 uudecode.bas

echo x - uudecode.c
cat >uudecode.c <<'@EOF'
#ifndef lint
static char sccsid[] = "@(#)uudecode.c	5.1 (Berkeley) 7/2/83";
#endif

/*
 * uudecode [input]
 *
 * create the specified file, decoding as you go.
 * used with uuencode.
 */
#include <stdio.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>

/* single character decode */
#define DEC(c)	(((c) - ' ') & 077)

main(argc, argv)
char **argv;
{
	FILE *in, *out;
	struct stat sbuf;
	int mode;
	char dest[128];
	char buf[80];

	/* optional input arg */
	if (argc > 1) {
		if ((in = fopen(argv[1], "r")) == NULL) {
			perror(argv[1]);
			exit(1);
		}
		argv++; argc--;
	} else
		in = stdin;

	if (argc != 1) {
		printf("Usage: uudecode [infile]\n");
		exit(2);
	}

	/* search for header line */
	for (;;) {
		if (fgets(buf, sizeof buf, in) == NULL) {
			fprintf(stderr, "No begin line\n");
			exit(3);
		}
		if (strncmp(buf, "begin ", 6) == 0)
			break;
	}
	sscanf(buf, "begin %o %s", &mode, dest);

	/* handle ~user/file format */
	if (dest[0] == '~') {
		char *sl;
		struct passwd *getpwnam();
		char *index();
		struct passwd *user;
		char dnbuf[100];

		sl = index(dest, '/');
		if (sl == NULL) {
			fprintf(stderr, "Illegal ~user\n");
			exit(3);
		}
		*sl++ = 0;
		user = getpwnam(dest+1);
		if (user == NULL) {
			fprintf(stderr, "No such user as %s\n", dest);
			exit(4);
		}
		strcpy(dnbuf, user->pw_dir);
		strcat(dnbuf, "/");
		strcat(dnbuf, sl);
		strcpy(dest, dnbuf);
	}

	/* create output file */
	out = fopen(dest, "w");
	if (out == NULL) {
		perror(dest);
		exit(4);
	}
	chmod(dest, mode);

	decode(in, out);

	if (fgets(buf, sizeof buf, in) == NULL || strcmp(buf, "end\n")) {
		fprintf(stderr, "No end line\n");
		exit(5);
	}
	exit(0);
}

/*
 * copy from in to out, decoding as you go along.
 */
decode(in, out)
FILE *in;
FILE *out;
{
	char buf[80];
	char *bp;
	int n;

	for (;;) {
		/* for each input line */
		if (fgets(buf, sizeof buf, in) == NULL) {
			printf("Short file\n");
			exit(10);
		}
		n = DEC(buf[0]);
		if (n <= 0)
			break;

		bp = &buf[1];
		while (n > 0) {
			outdec(bp, out, n);
			bp += 4;
			n -= 3;
		}
	}
}

/*
 * output a group of 3 bytes (4 input characters).
 * the input chars are pointed to by p, they are to
 * be output to file f.  n is used to tell us not to
 * output all of them at the end of the file.
 */
outdec(p, f, n)
char *p;
FILE *f;
{
	int c1, c2, c3;

	c1 = DEC(*p) << 2 | DEC(p[1]) >> 4;
	c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
	c3 = DEC(p[2]) << 6 | DEC(p[3]);
	if (n >= 1)
		putc(c1, f);
	if (n >= 2)
		putc(c2, f);
	if (n >= 3)
		putc(c3, f);
}


/* fr: like read but stdio */
int
fr(fd, buf, cnt)
FILE *fd;
char *buf;
int cnt;
{
	int c, i;

	for (i=0; i<cnt; i++) {
		c = getc(fd);
		if (c == EOF)
			return(i);
		buf[i] = c;
	}
	return (cnt);
}

/*
 * Return the ptr in sp at which the character c appears;
 * NULL if not found
 */

#define	NULL	0

char *
index(sp, c)
register char *sp, c;
{
	do {
		if (*sp == c)
			return(sp);
	} while (*sp++);
	return(NULL);
}
@EOF
size=`wc -c <uudecode.c`; if test $size -ne 2949 ; then
	echo ERROR: uudecode.c is $size bytes but should be 2949.
fi

chmod 644 uudecode.c

echo x - uuencode.1c
cat >uuencode.1c <<'@EOF'
.TH UUENCODE 1C "1 June 1980"
.UC 4
.SH NAME
uuencode,uudecode \- encode/decode a binary file for transmission via mail
.SH SYNOPSIS
.B uuencode
[ source ] remotedest |
.B mail
sys1!sys2!..!decode
.br
.B uudecode
[ file ]
.SH DESCRIPTION
.I Uuencode
and
.I uudecode
are used to send a binary file via uucp (or other) mail.
This combination can be used over indirect mail links
even when
.IR uusend (1C)
is not available.
.PP
.I Uuencode
takes the named source file (default standard input) and
produces an encoded version on the standard output.
The encoding uses only printing ASCII characters,
and includes the mode of the file and the
.I remotedest
for recreation on the remote system.
.PP
.I Uudecode
reads an encoded file,
strips off any leading and trailing lines added by mailers,
and recreates the original file with the specified mode and name.
.PP
The intent is that all mail to the user ``decode'' should be filtered
through the uudecode program.  This way the file is created automatically
without human intervention.
This is possible on the uucp network by either using
.I sendmail
or by making
.I rmail
be a link to
.I Mail
instead of
.I mail.
In each case, an alias must be created in a master file to get
the automatic invocation of uudecode.
.PP
If these facilities are not available, the file can be sent to a
user on the remote machine who can uudecode it manually.
.PP
The encode file has an ordinary text form and can be edited
by any text editor to change the mode or remote name.
.SH SEE\ ALSO
uuencode(5), uusend(1C), uucp(1C), uux(1C), mail(1)
.SH AUTHOR
Mark Horton
.SH BUGS
The file is expanded by 35% (3 bytes become 4 plus control information)
causing it to take longer to transmit.
.PP
The user on the remote system who is invoking
.I uudecode
(often
.I uucp)
must have write permission on the specified file.
@EOF
size=`wc -c <uuencode.1c`; if test $size -ne 1840 ; then
	echo ERROR: uuencode.1c is $size bytes but should be 1840.
fi

chmod 644 uuencode.1c

echo x - uuencode.c
cat >uuencode.c <<'@EOF'
#ifndef lint
static char sccsid[] = "@(#)uuencode.c	5.1 (Berkeley) 7/2/83";
#endif

/*
 * uuencode [input] output
 *
 * Encode a file so it can be mailed to a remote system.
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

/* ENC is the basic 1 character encoding function to make a char printing */
#define ENC(c) (((c) & 077) + ' ')

main(argc, argv)
char **argv;
{
	FILE *in;
	struct stat sbuf;
	int mode;

	/* optional 1st argument */
	if (argc > 2) {
		if ((in = fopen(argv[1], "r")) == NULL) {
			perror(argv[1]);
			exit(1);
		}
		argv++; argc--;
	} else
		in = stdin;

	if (argc != 2) {
		printf("Usage: uuencode [infile] remotefile\n");
		exit(2);
	}

	/* figure out the input file mode */
	fstat(fileno(in), &sbuf);
	mode = sbuf.st_mode & 0777;
	printf("begin %o %s\n", mode, argv[1]);

	encode(in, stdout);

	printf("end\n");
	exit(0);
}

/*
 * copy from in to out, encoding as you go along.
 */
encode(in, out)
FILE *in;
FILE *out;
{
	char buf[80];
	int i, n;

	for (;;) {
		/* 1 (up to) 45 character line */
		n = fr(in, buf, 45);
		putc(ENC(n), out);

		for (i=0; i<n; i += 3)
			outdec(&buf[i], out);

		putc('\n', out);
		if (n <= 0)
			break;
	}
}

/*
 * output one group of 3 bytes, pointed at by p, on file f.
 */
outdec(p, f)
char *p;
FILE *f;
{
	int c1, c2, c3, c4;

	c1 = *p >> 2;
	c2 = (*p << 4) & 060 | (p[1] >> 4) & 017;
	c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03;
	c4 = p[2] & 077;
	putc(ENC(c1), f);
	putc(ENC(c2), f);
	putc(ENC(c3), f);
	putc(ENC(c4), f);
}

/* fr: like read but stdio */
int
fr(fd, buf, cnt)
FILE *fd;
char *buf;
int cnt;
{
	int c, i;

	for (i=0; i<cnt; i++) {
		c = getc(fd);
		if (c == EOF)
			return(i);
		buf[i] = c;
	}
	return (cnt);
}
@EOF
size=`wc -c <uuencode.c`; if test $size -ne 1707 ; then
	echo ERROR: uuencode.c is $size bytes but should be 1707.
fi

chmod 644 uuencode.c

exit 0