#!/usr/bin/perl
# Filename:     forge
# Author:       David Ljung
# Description:  Forges email
# TODO:  Get the headers out of the email in case they've changed
#        (Such as a new from address changes the from_machine)
use strict;
use English;

$ENV{'PATH'} = '/bin:/usr/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

my ($SAVE_UID,$SAVE_GID) = ($UID,$GID);
($UID,$GID) = ($EUID,$EGID);	# XXX: initgroups() not called

umask 022;

##################################################
# Setup the variables
##################################################
my $PROGNAME = $0;
$PROGNAME =~ s|.*/||;

	# Where to save mail
my $OUTBOUND = "/home/madison/Mail/OUTBOUND/new";

	# Sendmail method:
my $SENDMAIL="/usr/lib/sendmail";

	# Port 25 method:  Where we normally send mail through
my $DEFAULT_MAILHOST="localhost";
my $TELNET="/usr/bin/telnet";

	# Choose an editor
my $EDITOR = "/bin/vim";
$EDITOR = "/usr/bin/vim" if (!$EDITOR || ! -x $EDITOR);
$EDITOR = "/bin/vi" if (!$EDITOR || ! -x $EDITOR);
$EDITOR = "/usr/bin/vi" if (!$EDITOR || ! -x $EDITOR);
die("[$PROGNAME] Couldn't find editor to use\n")
  if (!$EDITOR || ! -x $EDITOR);

	# Sig file (or a directory of sigs - we'll pick one randomly)
my $SIG="~/.sig";

#my $SIG="~/.elm/sigs";
my $DEFAULT_SIG = "-- \nDavid Ljung Madison             http://GetDave.com\n";

##################################################
# Usage
##################################################
sub usage {
  my $msg;
  foreach $msg (@_) { print "ERROR:  $msg\n"; }
  print "\n";
  print "Usage:\t$MAIN::PROGNAME [-f from] [-F name] [-s subject] [-t to]\n";
  print "      \t\t[-d] [-25 [mail_host]]\n";
  print "\tForges a mail message\n";
  print "\t-f\tFrom address\n";
  print "\t-F\tFrom full name\n";
  print "\t-t\tTo address\n";
  print "\t-s\tSubject\n";
  print "\n";
  print "\t-d\tSet debug mode\n";
  print "\t-25\tUse port 25 method\n";
  print "\n";
  exit -1;
}

sub parse_args {
  my $host;
  my ($from,$from_full,$to,$subject);

  # DEFAULTS
  $from = "some.com\@daveola.com";
  $from_full = "David Ljung Madison";
  #$to = "svlug\@lists.svlug.org";
  $to = "madison";

  while ($#ARGV>=0) {
    $a=shift(@ARGV);
    if($a =~ /^-h$/) { &usage; }
    if($a =~ /^-d$/) { $MAIN::DEBUG=1; next; }
    if($a =~ /^-25$/) { $MAIN::PORT25=1; next; }
    if($a =~ /^-f$/) { $from=shift(@ARGV); next; }
    if($a =~ /^-F$/) { $from_full=shift(@ARGV); next; }
    if($a =~ /^-t$/) { $to=shift(@ARGV); next; }
    if($a =~ /^-s$/) { $subject=shift(@ARGV); next; }
    if($a =~ /^-/) { &usage("Unknown option: $a"); }
    &usage("You can only specify one mailhost [$a and $host]") if(defined($host));
    $host=$a;
  }
  $host=$DEFAULT_MAILHOST if(!defined($host));

  ($host,$from,$from_full,$to,$subject);
}

##################################################
# Char-by-char mode
##################################################
sub char_mode {
  my $ttyname=`/usr/bin/tty`;
  $ttyname =~ /(.+)/;  $ttyname = $1;	# Ignore taint warnings
  system "/bin/stty -icanon -echo min 1 < $ttyname " if (! $?);
}

sub line_mode {
  my $ttyname=`/usr/bin/tty`;
  $ttyname =~ /(.+)/;  $ttyname = $1;	# Ignore taint warnings
  `/usr/bin/tty -s`;
  system "/bin/stty icanon echo < $ttyname " if (! $? );
}

sub get_char {
  my $ans;
  read(STDIN,$ans,1);
  return $ans;
}

##################################################
# Get the header fields
##################################################
sub get_header {
  my ($query,$default) = @_;
  my $ret;
  print STDERR $default ? "$query [$default]: " : "$query: ";
  chomp($ret = <>);
  $ret || $default;
}

##################################################
# Get the signature file
##################################################
sub get_sig {
  my $txt;

  my $sig_file=$SIG;

  # Handle '~' in path
  $sig_file =~ s/\~/$ENV{HOME}/g if (defined($ENV{HOME}));

  # If it's a directory then pick one file
  if (-d $sig_file) {
    if (!opendir(SIG,$sig_file)) {
      print STDERR "Couldn't open sig directory: $sig_file\n";
      sleep 1;
      return "";
    }
    my @sigs=grep(!/^\.{1,2}$/,readdir(SIG));
    closedir(SIGS);
    $sig_file="$sig_file/".$sigs[int(rand(scalar(@sigs)))];
  }

  # Read the file and return the text
  if (open(SIG,"<$sig_file")) {
    $txt=join('',<SIG>);
    close(SIG);
    return $txt;
  }
  return $DEFAULT_SIG;

#  print STDERR "Couldn't open sig file: $sig_file\n";
#  sleep 1;
#  return "";
}

##################################################
# Main code
##################################################
sub main {
  my ($host,$from,$from_full,$to,$subject) = parse_args();

  my $file = "${PROGNAME}.$$";
  die unless $file =~ /^([-\w.]+)$/;
  $file = $1;
  $file = "/tmp/$file";

  #########################
  # Get the mail information
  #########################
  $from=get_header("From address",$from);
  $from_full=get_header("From name",$from_full);
  $to=get_header("To",$to);
  $subject=get_header("Subject",$subject);
  my $date = gmtime();

  my $sig=get_sig();
  my $from_machine=$from;
  $from_machine =~ s/.*\@//;

  #########################
  # Create the file
  #########################
  open(FILE,">$file") || die("Couldn't write $file\n");
  # Headers
  print FILE "From: $from_full <$from>\n";
  print FILE "Subject: $subject\n";
  print FILE "To: $to\n";
  print FILE "Date: $date\n";
  print FILE "X-Mailer: DaveMail [version 6.0]\n";
  print FILE "In-Reply-To: your_mom\n";
  print FILE "\n";
  # Body
  print FILE "EMAIL_TEXT_GOES_HERE\n";
  # Sig
  print FILE "\n$sig";
  close(FILE);

  #########################
  # Edit loop
  #########################
  while(1) {
    system("$EDITOR $file");
    print STDERR "S)end the message, E)dit it again, F)orget it (saved), X)eXit\n";
    print STDERR "\nWhat is your choice? s";
    char_mode();
    my $ans=get_char;
    line_mode();
    print "$ans\n";
    if ($ans =~ /X/i) {
      unlink($file);
      exit;
    }
    if ($ans =~ /F/i) {
      print "File saved in: $file\n";
      chown $SAVE_UID, $SAVE_GID, $file;
      exit;
    }
    next if ($ans =~ /E/i);
    last if ($ans =~ /S/i || $ans =~ /\n/);
  }

  #########################
  # Mail it
  #########################
  if ($MAIN::PORT25) {
    open(FILE,"<$file") || die("Couldn't open mail file! $file\n");

    open(MAIL,"|$TELNET $host 25 > /dev/null") || die("Couldn't open socket to $host\n");
    print MAIL "helo $from_machine\n";
    print MAIL "mail from: $from\n";
    print MAIL "rcpt to: $to\n";
    print MAIL "data\n";
    while(<FILE>) {
      # Make sure we don't die early
      s/^\.$/. /g;
      print MAIL;
    }
    print MAIL ".\n";
    print MAIL "quit\n";
    close(MAIL);
    close(FILE);
  } else {
    system("$SENDMAIL -i -f $from -F \"$from_full\" $to < $file");
  }
  ($UID,$GID) = ($SAVE_UID,$SAVE_GID);

  # Save a copy (hack!)
  if ($OUTBOUND && open(OUT,">>$OUTBOUND")) {
    if (open(MAIL,"<$file")) {
      print OUT "\nFrom $from $date\n";
      while (<MAIL>) { print OUT; }
      close(MAIL);
    }
    close(OUT);
  }

  # Delete the file
  unlink($file);
}
&main;
