#!/usr/local/bin/perl
#
# program to convert BrokenWindows mailtool-style messages to MIME.
# author: Keith Moore
#
# Permission is granted to use this for whatever purpose you wish,
# provided you don't hold me responsible if this doesn't work like
# you want it to.
#
# customization: add your own types at will...
# if a conversion is necessary, add an entry in $convert{} also...
#
$tmp1="/usr/tmp/$$.1" ;
$tmp2="/usr/tmp/$$.2";
$new_type{'text'} = 'text/plain; charset=us-ascii';
$new_type{'audio-file'} = 'audio/basic';
$new_type{'default'} = 'application/octet-stream';
$new_type{'postscript-file'} = 'application/postscript';
$new_type{'gif-file'} = 'image/gif';
#
# sun raster files need to be translated to gif files so they'll be
# mime-compatible.
# "convert" is from ImageMagick; pbm tools would work also.
#
$new_type{'sun-raster'} = 'image/gif';
$convert{'sun-raster'} = 'convert - gif:-';
#
#
# Yes I know this is lame.  Pick a better boundary marker if you want.
# 
$boundary = 'xyzzy';
#
#
$[ = 1;			# set array base to 1
$, = ' ';		# set output field separator
$\ = "\n";		# set output record separator

sub uue_to_b64 {
    local($z) = @_;
    local($x, $inlen, $outlen, $fc);

    if ($z =~ /^begin / || $z =~ /^end/) {
	return;
    }
    # figure out how many characters should be in the line
    # first char has encoded length of the # of characters (before
    # encoding) there are in the line.
    $fc = substr ($z, 1, 1);
    $inlen = ((unpack("c", $fc) - 0x20) & 0x3f);
    if ($inlen == 0) {
        return ;
    }
    $outlen = int (($inlen + 2) / 3) * 4;
    # pad line to the right # of spaces in case it's gotten truncated
    # in shipment. discard length character while we're at it.
    $x = substr($z . "                 ", 2, $outlen);
    # delete any characters not in uuencode's set
    $x =~ tr/ `!"#$%&'()*+,-.\/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_//cd ;
    # transliterate to base64.
    # some uuencode's use SPACE for zero, others backquote, so
    # translate both.
    $x =~ tr/ `!"#$%&'()*+,-.\/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_/AABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\//d ;
    $x =~ tr/ /A/d ;
    if (($inlen % 3) == 2) {
        $x =~ s/.$/=/;
    }
    elsif (($inlen % 3) == 1) {
        $x =~ s/..$/==/;
    }
    print $x;
    return;
}

sub copyout {
    local ($x, $proc);

    close PROC;
    if ($pipein ne '') {
	$proc=$pipein . " < $tmp1 | uuencode tmp.file |";
    }
    else {
	$proc="uuencode tmp.file < $tmp1 |";
    }
    print STDERR "running ". $proc;
    open (PROC, $proc);
    line2: while ($x = <PROC>) {
	if ($xlate_uue_to_b64) {
	    do uue_to_b64 ($x);
	}
	else {
	    print $x;
	}
    }
    close PROC;
    unlink "$tmp1", "$tmp2";
}

$phase = 0;

line: while (<>) {
    chop;	# strip record separator
    @Fld = split(' ', $_, 9999);
    if (/^Content-Type:/ && $phase == 0) {
	print "content-type: multipart/mixed; boundary=\"" . $boundary . "\"";
	print 'mime-version: 1.0';
	next line;
    }
    if (/^ *$/ && $phase == 0) {
	print $_;
	$phase = 1;
	next line;
    }
    if (/^---------- *$/ && ($phase == 3 || $phase == 1 || $phase == 0)) {
	if ($phase == 3 && $useproc eq "yes") {
	    do copyout ();
	    $useproc = "no";
	}
	elsif ($phase == 0) {
	    print "content-type: multipart/mixed; boundary=\"" .
		$boundary . "\"";
	    print 'mime-version: 1.0';
	}
	$content_type = '';
	$filename = '';
	$description = '';
	$lines = 0;
	$encoding = '';
	$xlate_uue_to_b64 = 0;
	$useproc = "no";
	$phase = 2;
	next line;
    }
    if (/^X-Sun-Data-Type:/ && $phase == 2) {
	$old_type = $Fld[2];
	$content_type = $new_type{$old_type};
	if ($content_type eq '') {
	    $content_type = 'application/octet-stream; type="x-'.$old_type.'"';
	}
	if ($convert{$old_type} ne '') {
	    $pipein = $convert{$old_type};
	}
	next line;
    }
    if (/^X-Sun-Data-Name:/ && $phase == 2) {
	if ($Fld[2] ne "text") {
	    $filename = $Fld[2];
	}
	next line;
    }
    if (/^X-Sun-Data-Description:/ && $phase == 2) {
	if ($Fld[2] ne "text") {
	    $description = $Fld[2];
	}
	next line;
    }
    if (/^X-Sun-Content-Lines:/ && $phase == 2) {
	$lines = $Fld[2] + 0;
	next line;
    }
    if (/^X-Sun-Encoding-Info:/ && $phase == 2) {
	$old_encoding = substr($_, length($Fld[1]) + 2,
	  length($_) - length($Fld[1]) - 1);
	if ($old_encoding eq 'uuencode') {
	    $xlate_uue_to_b64 = 1;
	    $encoding = 'base64';
	}
	elsif ($old_encoding eq 'default-compress, uuencode') {
	    $useproc = "yes";
	    $pipeout = "| uudecode ;  zcat < $tmp2 > $tmp1";
	    $xlate_uue_to_b64 = 1;
	    $encoding = 'base64';
	}
	else {
	    $encoding = 'x-' . $old_encoding;
	}
	next line;
    }
    if (/^ *$/ && $phase == 2) {
	print '';
	print '--' . $boundary;
	if ($filename eq '') {
	    print 'content-type: ' . $content_type;
	}
	else {
	    print 'content-type: ' . $content_type . "; filename = \"" .
	      $filename . "\"";
	}
	if ($description ne '') {
	    print 'content-description: ' . $description;
	}
	if ($encoding ne '') {
	    print 'content-transfer-encoding: ' . $encoding;
	}
	if ($useproc eq "yes") {
	    print STDERR "running " . $pipeout ;
	    open (PROC, $pipeout);
	}
	$phase = 3;
	print $_;
	next line;
    }
    if ($phase == 3) {
	--$lines;
	if ($useproc eq "yes") {
	    if ($_ =~ /^begin /) {
		print PROC "begin 600 $tmp2" ;
	    }
	    else {
		print PROC $_;
	    }
	}
	elsif ($xlate_uue_to_b64) {
	    do uue_to_b64 ($_);
        }
	else {
	    print $_;
	}
	next line;
    }
    print $_;
}
if ($phase == 3 && $useproc eq "yes") {
	do copyout ();
}
print '';
print '--' . $boundary . '--';
