per@philabs.UUCP (05/02/84)
# The rest of this file is a shell script which will extract: # README Makefile btoa.1 btoa.c atob.c tarmail untarmail echo x - README cat >README <<'!Funky!Stuff!' These programs encode binary files as printable ascii files that should pass through mail. They also calculate and check end to end checksums. btoa "binary to ascii" atob "ascii to binary" (checks checksums, no output if bad) "tarmail" and "untarmail" are shell scripts which make it convenient to tar up directory structures, mail them to remote sites, and untar them. The use of tar ensures that protection modes, file dates, and (if su) owners are recreated at the other end. Using mail has been more convienent (in our situation) than using uucp directly. IF you are on a 16-bit machine, you will have to run around changing "int" to "long" before these filters work. If the c style looks a bit strange, that is because the programs were written using a strange preprocessor. !Funky!Stuff! echo x - Makefile cat >Makefile <<'!Funky!Stuff!' install: atob btoa tarmail untarmail mv atob btoa /usr/local/bin cp tarmail untarmail /usr/local/bin cp btoa.1 /usr/man/man1/btoa.1 cp btoa.1 /usr/man/man1/tarmail.1 btoa: btoa.c cc -O -s btoa.c -o btoa atob: atob.c cc -O -s atob.c -o atob clean: rm -f atob btoa *.o !Funky!Stuff! echo x - btoa.1 cat >btoa.1 <<'!Funky!Stuff!' .TH btoa LOCAL .SH NAME btoa, atob, tarmail, untarmail \- encode/decode binary to printable ASCII .SH SYNOPSIS .B btoa < inbinary > outtext .PP .B atob < intext > outbinary .PP .B tarmail who subject files ... .SH DESCRIPTION .I btoa is a filter that reads anything from the standard input, and encodes it into printable ASCII on the standard output. It also attaches checksum information used by the reverse filter "atob" to check integrity. atob gives NO output (and exits with an error message) if its input is garbage or the checksums do not check. .PP tarmail ralph here-it-is-ralph foo.c a.out .PP .I tarmail is a shell that tar's up all the given files, pipes them through btoa, and mails them to the given person with the given subject phrase. "tarmail" with no args will print a short message reminding you what the required args are. When the mail is received at the other end, that person should use mail to save the message in some temporary file name (say "xx"). Then saying "untarmail xx" will decode the message and untar it. By using tarmail, binary files and entire directory structures can be easily transmitted between machines. Naturally, you should understand what tar itself does before you use tarmail. .PP Other uses: .PP crypt < secrets | btoa | mail ralph .PP will mail the encrypted contents of the file "secrets" to ralph. If ralph knows the encryption key, he can decode it by saving the mail (say in "xx"), and then running: .PP atob < xx | crypt .PP (crypt requests the key from the terminal, and the "secrets" come out on the terminal). .SH FILES /usr/local/bin: the programs .SH AUTHOR Paul Rutter .SH FEATURES It uses a compact base-85 encoding so that 4 bytes are encoded into 5 characters. .SH BUGS It uses an obscure base-85 "squoz code" scheme to encode 4 bytes into 5 characters. !Funky!Stuff! echo x - btoa.c cat >btoa.c <<'!Funky!Stuff!' /*stream filter to change 8 bit bytes into printable ascii*/ /*computes the number of bytes, and three kinds of simple checksums*/ /*assumes that int is 32 bits*/ /*incoming bytes are collected into 32-bit words, then printed in base 85*/ /* exp(85,5) > exp(2,32) */ /*the characters used are between ' ' and 't'*/ /*'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data.*/ #include <stdio.h> #define reg register #define MAXPERLINE 78 int Ceor = 0; int Csum = 0; int Crot = 0; int ccount = 0; int bcount = 0; int word; #define EN(c) ((c) + ' ') encode(c) reg c; { Ceor ^= c; Csum += c; Csum += 1; if ((Crot & 0x80000000)) { Crot <<= 1; Crot += 1; } else{ Crot <<= 1; } Crot += c; word <<= 8; word |= c; if (bcount == 3) { wordout(word); bcount = 0; } else{ bcount += 1; } } wordout(word) reg word; { if (word == 0) { charout('z'); } else{ /*first division must be unsigned*/; charout(EN((unsigned) word / (unsigned)(85 * 85 * 85 * 85))); word = (unsigned) word % (unsigned)(85 * 85 * 85 * 85); charout(EN(word / (85 * 85 * 85))); word %= (85 * 85 * 85); charout(EN(word / (85 * 85))); word %= (85 * 85); charout(EN(word / 85)); word %= 85; charout(EN(word)); } } charout(c) { putchar(c); ccount += 1; if (ccount == MAXPERLINE) { putchar('\n'); ccount = 0; } } main(argc,argv) char **argv; { reg c, n; if (argc != 1) { fprintf(stderr,"bad args to %s\n", argv[0]); exit(2); } printf("xbtoa Begin\n"); n = 0; while ((c = getchar()) != EOF) { encode(c); n += 1; } while (bcount != 0) { encode(0); } /* n is written twice as crude cross check*/ printf("\nxbtoa End N %d %x E %x S %x R %x\n", n, n, Ceor, Csum, Crot); } !Funky!Stuff! echo x - atob.c cat >atob.c <<'!Funky!Stuff!' /*stream filter to change printable ascii from "btoa" back into 8 bit bytes*/ /*if bad chars, or Csums do not match: exit(1) [and NO output]*/ /*assumes that int is 32 bits*/ #include <stdio.h> #define reg register #define streq(s0, s1) strcmp(s0, s1) == 0 int Ceor = 0; int Csum = 0; int Crot = 0; int bcount = 0; int word = 0; fatal() { fprintf(stderr, "bad format or Csum to atob\n"); exit(1); } #define DE(c) ((c) - ' ') decode(c) reg c; { if (c == 'z') { if (bcount != 0) { fatal(); } else{ byteout(0); byteout(0); byteout(0); byteout(0); } } else if ((c >= ' ') && (c < (' ' + 85))) { if (bcount == 0) { word = DE(c); ++bcount; } else if (bcount < 4) { word *= 85; word += DE(c); ++bcount; } else{ word = ((unsigned) word * (unsigned) 85) + DE(c); byteout((word >> 24) & 255); byteout((word >> 16) & 255); byteout((word >> 8) & 255); byteout(word & 255); word = 0; bcount = 0; } } else{ fatal(); } } FILE *tmpfile; byteout(c) reg c; { Ceor ^= c; Csum += c; Csum += 1; if ((Crot & 0x80000000)) { Crot <<= 1; Crot += 1; } else{ Crot <<= 1; } Crot += c; putc(c, tmpfile); } main(argc, argv) char **argv; { reg c, i; char tmpname[100]; char buf[100]; int n1, n2, oeor, osum, orot; if (argc != 1) { fprintf(stderr,"bad args to %s\n", argv[0]); exit(2); } sprintf(tmpname, "/usr/tmp/atob.%x", getpid()); tmpfile = fopen(tmpname, "w+"); if (tmpfile == NULL) { fatal(); } /*search for header line*/ for (;;) { if (fgets(buf, sizeof buf, stdin) == NULL) { fatal(); } if (streq(buf, "xbtoa Begin\n")) { break; } } while ((c = getchar()) != EOF) { if (c == '\n') { continue; } else if (c == 'x') { break; } else{ decode(c); } } if (scanf("btoa End N %d %x E %x S %x R %x\n", &n1, &n2, &oeor, &osum, &orot) != 5) { fatal(); } if ((n1 != n2) || (oeor != Ceor) || (osum != Csum) || (orot != Crot)) { fatal(); } else{ /*copy OK tmp file to stdout*/; fseek(tmpfile, 0, 0); for (i = n1; --i >= 0;) { putchar(getc(tmpfile)); } unlink(tmpname); } } !Funky!Stuff! echo x - tarmail cat >tarmail <<'!Funky!Stuff!' # #tar up files, pipe through btoa to mail. #recieve by saving mail in temp file, then "untarmail temp" if ($#argv < 3) then echo "usage: tarmail mailpath subject-string directory-or-file-name(s)" exit else set mailpath = $1 echo mailpath = $mailpath shift set subject = $1 echo subject-string = $subject shift echo files = $* tar cvf - $* | btoa | mail -s $subject $mailpath endif !Funky!Stuff! echo x - untarmail cat >untarmail <<'!Funky!Stuff!' # #atob and untar mail sent via tarmail atob < $1 | tar xvpf - mv $1 /usr/tmp/$1.$$ echo tarmail file moved to: /usr/tmp/$1.$$ !Funky!Stuff!
leif@erix.UUCP (Leif Samuelsson) (05/05/84)
I have made the changes necessary to run these in the Apollo AUX environment. I will mail it to anyone who's interested. Leif Samuelsson LM ERICSSON Tel. Co. ..{decvax, philabs}!mcvax!enea!erix!leif