#!/usr/bin/perl -w
# @(#) filemail.pl	Email utility for large binary files.
#			Version 2.08, 2005-02-17.
#
# Copyright (c) 2005 Graham Jenkins <grahjenk@cpan.org>. All rights reserved.
# This program is free software; you can redistribute it and/or modify it under
# the same terms as Perl itself.

use strict;		# Parts are encoded and sent via a double-buffer scheme.
use File::Basename;	# Uuencoding is used to reduce module dependence.
use Net::Config;
use Net::hostent;
use Net::SMTP;
my  $PSize = 700;	# Default (input) part-size.
my  ($Count,$Sum,$Size,$Total,$InpBuf,$InpLen,$OutBuf,$j,$PriBuf,@Hosts);

if ($#ARGV eq 2) { if ($ARGV[0] =~ m/^-\d+$/ ) { $PSize=0-$ARGV[0]; shift } } 

die "Usage: cat file  |".basename($0)." [-KbPerPart] destination filename\n".
    " e.g.: tar cf - .|".basename($0)." -64 smith\@popser.acme.com mydir.tar\n".
    "(Note: default un-encoded part size = $PSize","kb)\n"  if ($#ARGV ne 1);
die "No SMTP Hosts defined!\n" if ! (@Hosts=@{$NetConfig{smtp_hosts}});
die "Can't read input!\n"      if ! open(INFILE,"-");

binmode INFILE;
$Count=0; $Total="";   # Loop until no further input available.

do { $InpLen = read(INFILE, $InpBuf, 1024 * $PSize);
     $Total  = $Count if $InpLen lt 1;
     do { $Size = length($OutBuf);
          print STDERR "$ARGV[1] part $Count/$Total => $ARGV[0] $Size bytes\n";
          $Sum  = unpack("%32C*", $OutBuf);
          foreach $j (1,2) {$Sum = ($Sum & 0xffff) + int($Sum/0x10000)}
          $j = $Count ; while (length($j) < 3 ) { $j = "0" . $j }
          $j = dirname($ARGV[1])."/".$j if dirname($ARGV[1]) ne "."; 
          $j =$j."_".basename($ARGV[1]);
          $PriBuf="Subject: ".
            "$ARGV[1] part $Count/$Total size/sum $Size/$Sum\n".
            "MIME-Version: 1.0\n".
            "Content-Type: application/octet-stream; name=$j\n".
            "Content-Transfer-Encoding: uuencode\n\n".
            "begin 644 $j\n";
          foreach my $Host (@Hosts) {
            my $smtp;
            if ( gethost($Host)          && ($smtp=Net::SMTP->new($Host)) &&
                 $smtp->mail($ENV{USER}) &&  $smtp->to($ARGV[0])          && 
                 $smtp->data($PriBuf.pack("u",$OutBuf)."\`\nend\n")       &&
                                             $smtp->quit ) { $PriBuf=""; last } 
          }
          die "Failed!\n" if length($PriBuf) > 0
                                                        } if $Count gt 0;
     $Count++; $OutBuf = $InpBuf                          } until $InpLen lt 1;

exit 0
__END__

=head1 NAME

filemail - an email utility for large binary files

=head1 README

filemail breaks an input stream into parts, then encodes
each part and emails it to a designated recipient.

=head1 DESCRIPTION

This is a simple utility for emailing large
binary files. An input stream is broken into parts,
and each part is uuencoded for transmission to a
designated email address.

Uuencoding is used to reduce module dependence, and
an option is available to change the default part
size.

=head1 USAGE

=over 4

filemail [-part_size] recipient_address file_name

=back

By default, the input stream is broken into parts of size
700kb. This can be adjusted by specifying a part-size
on the command line (e.g. -500 for a 500kb part-size).

Each part is then named by prepending "001_", "002_", etc. to
the basename of the designated file-name, and uuencoded for
transmission.

A list of SMTP servers is determined using Net::Config and
each is tried in turn if necessary.

The recipient can recover the original data stream by
uudecoding each part, then concatenating each part.

=head1 SCRIPT CATEGORIES

UNIX/System_administration
Networking

=head1 AUTHOR

Graham Jenkins <grahjenk@cpan.org>

=head1 COPYRIGHT

Copyright (c) 2005 Graham Jenkins. All rights reserved.
This program is free software; you can redistribute it
and/or modify it under the same terms as Perl itself.

=cut
