#!/usr/bin/perl -w
#<msend: creates MIME-formatted mail messages.

use Getopt::Long;
use Pod::Usage;
use File::Basename;
use strict;

use subs qw(manpage myuuid usage version where);
$ENV{'PATH'} = join ":", qw(/bin /usr/bin /usr/local/bin /opt/sfw/bin);

my $myname = basename($0);
$myname =~ s/\.\w*$//;    # strip any extension

my @files = ();
my @to    = ();
my $exten = '';
my ($Aflg, $hflg, $mflg, $uflg, $vflg, $wflg) = (0, 0, 0, 0, 0, 0);
my $tfile = '';
my $subj  = "No subject";

Getopt::Long::config("noignorecase", "bundling");

usage unless GetOptions(
    "a=s" => \@files,     # attachment
    "A"   => \$Aflg,      # get attachments from stdin
    "h"   => \$hflg,      # print usage
    "m"   => \$mflg,      # print manpage
    "s=s" => \$subj,      # subject
    "t=s" => \$tfile,     # textfile used for start of the message
    "u"   => \$uflg,      # print UUID
    "v"   => \$vflg,      # print version
    "w"   => \$wflg       # print source location
    );

manpage if $mflg;
myuuid  if $uflg;
version if $vflg;
where   if $wflg;
usage   if $hflg || !@ARGV;

# Verify destination.
foreach (@ARGV) {
    push @to, $_;
}
$#to >= 0 or die "$myname: missing recipient(s)\n";

# If anything is coming in via stdin and we're not using
# it for a list of attachments, use it for the leading
# text in the email.
#
# If the -t option was used, it overrides stdin.

my $intro = "Here are the files you wanted.\n";
if (-f STDIN || -p STDIN) {
    if ($Aflg) {
        chomp(@files = <STDIN>);
    }
    else {
        undef $/;
        $intro = <STDIN>;
    }
}

if (length($tfile)) {
    open(my $fh, "< $tfile") || die;
    $intro = do { local $/; <$fh> };
    close($fh);
}

# Verify files.
$#files >= 0 or die "$myname: no files specified!\n";

#---------------------------------------------------------------------
# Set the MIME-type and encoding based on file extension, if any.

my $deftype   = 'application/octet-stream';
my $defencode = 'base64';

# Generated by mime2perl
my %filetype = qw(
  PS     application/postscript
  Z      application/x-compress
  ai     application/postscript
  bat    text/plain
  bmp    image/x-ms-bmp
  c      text/x-csrc
  c++    text/x-c++src
  cc     text/x-c++src
  cgi    text/x-perl
  cpio   application/x-cpio
  cpp    text/x-c++src
  csh    text/x-csh
  css    text/css
  cxx    text/x-c++src
  desc   text/plain
  eps    application/postscript
  gif    image/gif
  gz     application/x-gzip
  h      text/x-chdr
  h++    text/x-c++hdr
  hh     text/x-c++hdr
  hpp    text/x-c++hdr
  htm    text/html
  html   text/html
  hxx    text/x-c++hdr
  jpe    image/jpeg
  jpeg   image/jpeg
  jpg    image/jpeg
  js     text/x-javascript
  ksh    text/x-ksh
  latex  text/x-latex
  m1v    video/mpeg
  man    text/x-troff-man
  me     text/x-troff-me
  mp2    video/mpeg
  mpa    video/mpeg
  mpe    video/mpeg
  mpeg   video/mpeg
  mpg    video/mpeg
  ms     text/x-troff-ms
  pbm    image/x-portable-bitmap
  pdf    application/pdf
  pgm    image/x-portable-graymap
  php    text/x-httpd-php
  pht    text/x-httpd-php
  phtml  text/x-httpd-php
  pl     text/x-perl
  pm     text/x-perl
  png    image/png
  pnm    image/x-portable-anymap
  ppm    image/x-portable-pixmap
  ps     application/postscript
  py     text/x-python
  rdf    application/xml
  roff   text/x-troff
  sh     text/x-sh
  shar   text/x-shar
  t      text/x-troff
  tar    application/x-tar
  tar.gz application/x-tar-gz
  tcl    text/x-tcl
  tex    text/x-tex
  texi   text/x-texinfo
  texinf text/x-texinfo
  txt    text/plain
  tgz    application/x-tar-gz
  tif    image/tiff
  tiff   image/tiff
  tk     text/x-tcl
  tr     text/x-troff
  ustar  application/x-ustar
  xbm    image/x-xbitmap
  xml    text/xml
  xpm    image/x-xpixmap
  xsl    application/xml
  xwd    image/x-xwindowdump
  zip    application/x-zip-compressed
  );

my %encoding = qw(
  PS     base64
  Z      base64
  ai     base64
  bat    quoted-printable
  bmp    base64
  c      8bit
  c++    8bit
  cc     8bit
  cgi    8bit
  cpio   base64
  cpp    8bit
  csh    8bit
  css    8bit
  cxx    8bit
  desc   8bit
  eps    base64
  gif    base64
  gz     base64
  h      8bit
  h++    8bit
  hh     8bit
  hpp    8bit
  htm    quoted-printable
  html   quoted-printable
  hxx    8bit
  jpe    base64
  jpeg   base64
  jpg    base64
  js     8bit
  ksh    8bit
  latex  8bit
  m1v    base64
  man    8bit
  me     8bit
  mp2    base64
  mpa    base64
  mpe    base64
  mpeg   base64
  mpg    base64
  ms     8bit
  pbm    base64
  pdf    base64
  pgm    base64
  php    8bit
  pht    8bit
  phtml  8bit
  pl     8bit
  pm     8bit
  png    base64
  pnm    base64
  ppm    base64
  ps     base64
  py     8bit
  rdf    base64
  roff   8bit
  sh     8bit
  shar   8bit
  t      8bit
  tar    base64
  tar.gz base64
  tcl    8bit
  tex    8bit
  texi   8bit
  texinf 8bit
  txt    quoted-printable
  tgz    base64
  tif    base64
  tiff   base64
  tk     8bit
  tr     8bit
  ustar  base64
  xbm    base64
  xml    8bit
  xpm    base64
  xsl    base64
  xwd    base64
  zip    base64
  );

# End of code by mime2perl

# Create a new multipart message.
#
# We don't include the MIME stuff until here because we don't
# need it if we're just printing the version or usage.
# A "use" statement runs the equivalent of a BEGIN block,
# so "require" saves some startup time.
#
# FIXME: the "Encoding" line is a hack to prevent "binary" from
#        being used in the overall content-type-encoding: header
#        line.  "Binary" causes problems when the resulting
#        message is run through hypermail.  Easiest fix is to
#        simply delete the content-type-encoding: header.

require MIME::Lite;

my $msg = new MIME::Lite
  To        => join(', ', @to),
  Subject   => "$subj",
  Datestamp => 0,
  Encoding  => '8bit',
  Type      => 'multipart/mixed';

# Add attachments.
attach $msg Type => 'TEXT',
  Data           => $intro;

foreach (@files) {
    # get the filename extension, and remove the leading dot.
    # fileparse is fussy; use single quotes for the suffix type.

    (undef, undef, $exten) = fileparse($_, '\.[^\.]*');
    $exten = substr($exten, 1) if length($exten);

    attach $msg Type => ($filetype{$exten} || $deftype),
      Encoding       => ($encoding{$exten} || $defencode),
      Path           => $_,
      Filename       => basename($_);
}

# Output the message to stdout.
print "Reply-To: $ENV{'REPLYTO'}\n" if $ENV{'REPLYTO'};
$msg->print(\*STDOUT);
exit(0);

#---------------------------------------------------------------------
# Print a usage message from the comments and exit.

sub usage {
    my ($emsg) = @_;

    use Pod::Usage qw(pod2usage);
    warn "$emsg\n" if defined $emsg;
    pod2usage(-verbose => 99, -sections => "NAME|SYNOPSIS|OPTIONS");
}

sub manpage {
    my $pager = $ENV{'PAGER'} || "less";
    system("pod2man $0 | nroff -man | $pager");
    exit(0);
}

#---------------------------------------------------------------------
# Print the UUID, current version, or source location.

sub myuuid {
    my $UUID = $1
      if q$UUID: aa2782a4-27fb-3707-adf9-e0144fb6103c $ =~ /UUID: (.*) /;
    print "$UUID\n";
    exit(0);
}

sub version {
    my $VERSION = sprintf("%d.%02d", q$Revision: 1.9 $ =~ /(\d+)\.(\d+)/);
    my $DATE = $1 if q$Date: 2010/03/11 03:17:20 $ =~ /Date: (.*) /;
    print "$myname $VERSION $DATE\n";
    exit(0);
}

sub where {
    my $SOURCE = $1
      if q$Source: /mir02/repo/src/mail/mime/msend/RCS/msend,v $ =~ /Source: (.*) /;
    my $HOST = $1 if q$Host: sys7.com $ =~ /Host: (.*) /;
    print "file://$HOST", "$SOURCE\n";
    exit(0);
}

#---------------------------------------------------------------------
__END__

=head1 NAME

msend - creates MIME-formatted mail messages

=head1 SYNOPSIS

msend [-hmuvw]

msend [-s subj] -a file [-a file ...] [-t textfile] to [to ...]

msend [-s subj] -a file [-a file ...] to [to ...] < textfile

msend [-s subj] -A to [to ...] < attachment-list

=head1 OPTIONS

=over 4

=item B<-a> file

One or more attached file(s).

=item B<-A>

Read a list of attached files from stdin.

=item B<-h>

Print a brief help message and exit.

=item B<-m>

Print the manual page and exit.

=item B<-s> subject

Is an optional message subject.

=item B<-t> textfile

Reads the starting message from a file.

=item B<-u>

Print the script UUID and exit.

=item B<-v>

Print the version and exit.

=item B<-w>

Print the source location and exit.

=item B<to>

Is one or more email recipients.

=back

=head1 DESCRIPTION

B<msend> reads files from the command line, and writes a MIME-formatted mail
message to stdout.  The "mutt" mailer does a similar job, but doesn't
give me a choice about how it encodes files.

The default MIME-type is 'application/octet-stream', and the default
encoding used is 'base64'.  The MIME-type and encoding used depends
on the file extension; see the "filetype" and "encoding" variables.

Requires the MIME::Lite module.

=head1 EXAMPLES

B<msend -a file1.txt -a file2.pl -a file3-1.1.tar.gz you@your.host>

 will produce output looking like this:

 Content-Transfer-Encoding: binary
 Content-Type: multipart/mixed; boundary="_----------=_102683910912380"
 MIME-Version: 1.0
 X-Mailer: MIME::Lite 2.117  (F2.6; B2.12; Q2.03)
 To: you@your.host
 Subject: No subject

 This is a multi-part message in MIME format.

 --_----------=_102683910912380
 Content-Disposition: inline
 Content-Length: 31
 Content-Transfer-Encoding: binary
 Content-Type: text/plain

 Here are the files you wanted.

 --_----------=_102683910912380
 Content-Disposition: inline; filename="file1.txt"
 Content-Transfer-Encoding: 8bit
 Content-Type: text/plain; name="file1.txt"

 Contents of file1.txt go here

 --_----------=_102683910912380
 Content-Disposition: inline; filename="file2.pl"
 Content-Transfer-Encoding: 8bit
 Content-Type: text/x-perl; name="file2.pl"

 #!/bin/perl
 # some perl script goes here.

 --_----------=_102683910912380
 Content-Disposition: inline; filename="file3-1.1.tar.gz"
 Content-Transfer-Encoding: base64
 Content-Type: application/octet-stream; name="file3-1.1.tar.gz"

 H4sIAJplKj0AA+xd+0PbRvLvr/iv2ChOAi1+P+gXjBqXOCl3BPiC016u6lHZ
 ...
 GTyDZ/AMnsEzeAbP4Bk8g2fwDJ7BM3gGz+AZPIPn0Of/A3Gim4YA4AEA

 --_----------=_102683910912380--

=head1 AUTHOR

 Karl Vogel <vogelke+unix@pobox.com>
 Array Information Technology

 Based on mimesend by Eryq, eryq@zeegee.com, 8 Jan 1997

=cut
