bryce%cogsci.Berkeley.EDU@ucbvax.Berkeley.EDU (Bryce Nesbitt) (09/08/87)
This is the uuencode that will be used for this newsgroup unless otherwise noted. I have reviewed a couple of versions and have decided that this one is the most compatible with the current uuencode. Thanx to Bryce for his help on this! -Doc # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # uudecode.c # uuencode.c # uuencode.1 # This archive created: Tue Sep 8 13:00:35 1987 # By: Craig Norborg (Purdue University Computing Center) cat << \SHAR_EOF > uudecode.c /* #ifndef lint static char sccsid[] = "@(#)uudecode.c 5.3-1 (Berkeley) 4/10/85"; #endif */ /* Written by Mark Horton */ /* Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums */ /* Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for compatibility */ /* Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix some very misleading error messages on the Amiga port, to fix a bug that prevented decoding certain files, to work even if trailing spaces have been removed from a file, to check the filesize (if present), to add some error checking, and to loop for multiple decodes from a single file. Also kludged around a missing string function in Aztec C */ /* * uudecode [input] * * Decode a file encoded with uuencode. */ #include <stdio.h> #include <ctype.h> #ifdef AMIGA #define AMIGA_LATTICE /* Set for Amiga Lattice C */ #define MCH_AMIGA #define MPU68000 #endif #ifdef unix #include <pwd.h> #include <sys/types.h> #include <sys/stat.h> #endif #define SUMSIZE 64 #define DEC(c) (((c) - ' ') & 077) /* single character decode */ main(argc, argv) char **argv; { FILE *in, *out; int through_loop=0; /* Dejavu indicator */ int mode; /* file's mode (from header) */ long filesize; /* theoretical file size (from header) */ char dest[128]; char buf[80]; #ifdef AMIGA_LATTICE extern int Enable_Abort; Enable_Abort=1; #endif /* A filename can be specified to be uudecoded, or nothing can be specified, and the input will come from STDIN */ switch (argc) { case 1: in=stdin; break; case 2: if ((in = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "ERROR: can't find %s\n", argv[1]); fprintf(stderr, "USAGE: uudecode [infile]\n"); exit(10); } break; default: fprintf(stderr, "USAGE: uudecode [infile]\n"); exit(11); break; } /* Loop through file, searching for headers. Decode anything with a header, complain if there where no headers. */ for (;;) { /* search file for header line */ for (;;) { if (fgets(buf, sizeof buf, in) == NULL) { if (!through_loop) { fprintf(stderr, "ERROR: no `begin' line!\n"); exit(12); } else { exit(0); } } if (strncmp(buf, "begin ", 6) == 0) break; } sscanf(buf, "begin %o %s", &mode, dest); #ifdef unix /* 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(13); } *sl++ = 0; user = getpwnam(dest+1); if (user == NULL) { fprintf(stderr, "No such user as %s\n", dest); exit(14); } strcpy(dnbuf, user->pw_dir); strcat(dnbuf, "/"); strcat(dnbuf, sl); strcpy(dest, dnbuf); } #endif /* create output file */ if ((out = fopen(dest, "w")) == NULL) { fprintf(stderr, "ERROR: can't open output file %s\n", dest); exit(15); } #ifdef unix chmod(dest, mode); #endif decode(in, out, dest); if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3)) { /* don't be overly picky about newline ^ */ fprintf(stderr, "ERROR: no `end' line\n"); exit(16); } if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3))) { sscanf(buf, "size %ld", &filesize); if (ftell(out) != filesize) { fprintf(stderr, "ERROR: file should have been %ld bytes long but was %ld.\n", filesize, ftell(out)); exit(17); } } through_loop = 1; } /* forever */ } /* main */ /* * Copy from in to out, decoding as you go. * If a return or newline is encountered too early in a line, it is * assumed that means that some editor has truncated trailing spaces. */ decode(in, out, dest) FILE *in; FILE *out; char *dest; { char buf[80]; char *bp; int nosum=0; #ifndef unix extern errno; #endif register int j; register int n; int checksum, line; for (line = 1; ; line++) /* for each input line */ { if (fgets(buf, sizeof buf, in) == NULL) { fprintf(stderr, "ERROR: input ended unexpectedly!\n"); exit(18); } /* Pad end of lines in case some editor truncated trailing spaces */ for (n=0;n<79;n++) /* search for first \r, \n or \000 */ { if(buf[n]=='\r'||buf[n]=='\n'||buf[n]=='\000') break; } for (;n<79;n++) /* when found, fill rest of line with space */ { buf[n]=' '; } buf[79]=0; /* terminate new string */ checksum = 0; n = DEC(buf[0]); if (n <= 0) break; /* 0 bytes on a line?? Must be the last line */ bp = &buf[1]; /* FOUR input characters go into each THREE output charcters */ while (n >= 4) { j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4; putc(j, out); checksum += j; j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2; putc(j, out); checksum += j; j = DEC(bp[2]) << 6 | DEC(bp[3]); putc(j, out); checksum += j; checksum = checksum % SUMSIZE; bp += 4; n -= 3; } j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4; checksum += j; if (n >= 1) putc(j, out); j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2; checksum += j; if (n >= 2) putc(j, out); j = DEC(bp[2]) << 6 | DEC(bp[3]); checksum += j; if (n >= 3) putc(j, out); checksum = checksum % SUMSIZE; bp += 4; n -= 3; #ifndef unix /* Error checking under UNIX??? You must be kidding... */ /* Check if an error occured while writing to that last line */ if (errno) { fprintf(stderr, "ERROR: error writing to %s\n",dest); exit(19); } #endif /* The line has been decoded; now check that sum */ nosum |= !isspace(*bp); if (nosum) /* Is there a checksum at all?? */ { if (checksum != DEC(*bp)) /* Does that checksum match? */ { fprintf(stderr, "ERROR: checksum mismatch decoding %s, line %d.\n",dest, line); } } /* sum */ } /* line */ } /* function */ #ifdef unix /* * Return the ptr in sp at which the character c appears; * 0 if not found */ char * index(sp, c) register char *sp, c; { do { if (*sp == c) return(sp); } while (*sp++); return(0); } #endif unix SHAR_EOF cat << \SHAR_EOF > uuencode.c /* #ifndef lint static char sccsid[] = "@(#)uuencode.c 5.3-1 (Berkeley) 1/22/85"; #endif */ /* Written by Mark Horton */ /* Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums */ /* Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for compatibility */ /* Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix a very misleading error message on the Amiga port, enable CTRL-C for LATTICE, and add a transparant file size trailer for later check. */ /* * uuencode >outfile infile name * * Encode a file so it can be mailed to a remote system. This version * transparantly adds line checksums and a file size for sanity checks. * */ #include <stdio.h> #ifdef AMIGA #define AMIGA_LATTICE /* Set for Amiga Lattice C */ #define MCH_AMIGA #define MPU68000 #endif #ifdef unix #include <sys/types.h> #include <sys/stat.h> #endif #define SUMSIZE 64 /* 6 bits */ /* ENC is the basic 1 character encode function to make a char printing */ /* Each output character represents 6 bits of input */ #define ENC(c) ((c) ? ((c) & 077) + ' ': '`') long totalsize=0; /* Used to count the file size because ftell() does not return sane results for pipes */ main(argc, argv) char **argv; { FILE *in; int mode; #ifdef unix struct stat sbuf; #endif #ifdef AMIGA_LATTICE extern int Enable_Abort; /* Enable CTRL-C for Lattice */ Enable_Abort=1; #endif /* optional 1st argument */ if (argc > 2) { if ((in = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "ERROR: can't find %s\n", argv[1]); fprintf(stderr, "USAGE: uuencode >outfile infile name\n"); exit(10); } argv++; argc--; } else in = stdin; if (argc != 2) { fprintf(stderr, "USAGE: uuencode >outfile infile name\n"); exit(11); } #ifdef unix /* figure out the input file mode */ fstat(fileno(in), &sbuf); mode = sbuf.st_mode & 0777; #else mode = 0644; /* Default permissions */ #endif printf("\nbegin %o %s\n", mode, argv[1]); encode(in, stdout); printf("end\n"); printf("size %ld\n",totalsize); exit(0); } /* * copy from in to out, encoding as you go along. */ encode(in, out) FILE *in; FILE *out; { #ifndef unix extern errno; #endif char buf[80]; int i, n, checksum; for (;;) { /* 1 (up to) 45 character line */ n = fr(in, buf, 45); putc(ENC(n), out); checksum = 0; for (i=0; i<n; i += 3) checksum = (checksum+outdec(&buf[i], out)) % SUMSIZE; putc(ENC(checksum), out); putc('\n', out); #ifndef unix /* Error checking under UNIX?? You must be kidding! */ if (errno) { fprintf(stderr, "ERROR: error writing to output\n"); exit(12); } #endif if (n <= 0) break; } } /* * output one group of 3 bytes, pointed at by p, on file f. * return the checksum increment. */ int 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); return((p[0]+p[1]+p[2]) % SUMSIZE); } /* 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); totalsize++; buf[i] = c; } return (cnt); } SHAR_EOF cat << \SHAR_EOF > uuencode.1 .TH UUENCODE 1 "17 July 1987" .UC 4 .SH NAME uuencode,uudecode \- encode/decode a binary file for transmission via (plain text) mail .SH SYNOPSIS .B uuencode [source] remotedest | .B mail sys1!sys2!..!decode .br .B uuencode >outfile.uue source remotedest .br .B uuencode >outfile.uue <source remotedest .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) or other direct binary transmission methods are 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 lines added by mailers, and recreates the original file with the specified mode and name. If there are other uuencoded files in the same input, they will be decoded as well. .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 uudecoded 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. .PP This version of uuencode automatically adds checksums to each line, and an overall file size to the end. Old versions of uudecode will ignore this extra information, new versions will check it and complain if it is in error. .SH SEE\ ALSO uuencode(5), uusend(1C), uucp(1C), uux(1C), mail(1) .SH AUTHOR Mark Horton .br Checksums and Amiga port by Alan J. Rosenthal .br More fixes by Fred Fish .br File size check and various refinements by Bryce Nesbitt .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 SHAR_EOF # End of shell archive exit 0