[net.sources] binary to printable ASCII filters, and "tarmail"

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