#!/usr/bin/perl -w

use strict;
use Getopt::Std;
use File::Basename;
use Term::ReadKey;

use vars qw( %hOpts );

sub _usage
{
  print("vant-setup [ OPTIONS ]\n");
  print("OPTIONS:\n");
  print("    -c <config file> :   Config file to use instead of default.\n");
  print("    -h :                 Help (this message)\n");
}

sub _create_db
{
  my $p_sCxn = shift;
  my $p_sUser = shift;
  my $p_iUID = shift;
  my $p_sHomeDir = shift;

  if (!defined($p_sCxn))
  {
    warn("No connection?");
  }
  else
  {
    my $bSentinel = 0;
    my $sDir = "/usr/local/";
    print("Did you allow Vantages to be installed in its default base dir (prefix) '$sDir' [Y/n]? ");
    my $sResp =  <>;
    chomp($sResp);
    if ($sResp !~ /^[YyNn]$/ && $sResp ne "")
    {
      warn("Didn't recognize input '$sResp'");
    }
    elsif ($sResp =~ /^[Nn]$/)
    {
       print("Enter base dir now> ");
       $sResp = <>;
       chomp($sResp);
       $bSentinel = 1;
    }
    else
    {
      $bSentinel = 1;
    }

    if ($bSentinel)
    {
      my $sCxnDir = dirname($p_sCxn);
      system("mkdir -p $sCxnDir");
      $sDir .= "share/vantages/sql";
      system('create-db.pl', $sDir, $p_sCxn);
      chown($p_iUID, -1, $p_sCxn);
    }
  }
}

sub _config_key
{
  my $p_sCxn = shift;
  my $p_sUser = shift;
  my $p_iUID = shift;
  my $p_sHomeDir = shift;

  if (!defined($p_sCxn))
  {
    warn("Unable to configure key without DB connection string.");
  }
  elsif (!defined($p_sHomeDir) || "" eq $p_sHomeDir)
  {
    warn("Unabe to configure GPG key for user that does not have a home dir (this is where the keys are stored).")
  }
  else
  {
    print("Please type the email address for your GPG key\n");
    print("Key > ");
    my $sKeyName = <>;
    chomp($sKeyName);
    print("Is this the right value: '$sKeyName' [Y/n]? > ");
    my $sResp = <>;
    chomp($sResp);
    if ($sResp =~ /^y$/i
        || $sResp eq "")
    {
      system("echo 'delete from PS_LOCAL_KEY;' | sqlite3 $p_sCxn");
      system("echo \"insert into PS_LOCAL_KEY (NAME) values ('$sKeyName');\" | sqlite3 $p_sCxn");
    }
    elsif ($sResp !~ /^n$/i)
    {
      warn("Unknown response: '$sResp'\n");
    }
  }
}

sub _config_pp
{
  my $p_sCxn = shift;
  my $p_sUser = shift;
  my $p_iUID = shift;
  my $p_sHomeDir = shift;

  if (!defined($p_sCxn))
  {
    warn("Unable to configure passphrase without DB connection string.");
  }
  else
  {
    my $sPP = undef;
    print("Passphrase> ");
    # don't echo
    ReadMode('noecho');
    $sPP = <STDIN>;
    # back to normal
    ReadMode(0);

    system("echo \"update PS_LOCAL_KEY set PHRASE = '$sPP';\" | sqlite3 $p_sCxn");
  }
}

sub _create_key
{
  my $p_sCxn = shift;
  my $p_sUser = shift;
  my $p_iUID = shift;
  my $p_sHomeDir = shift;

  if (!defined($p_sCxn))
  {
    warn("Unable to configure key without DB connection string.");
  }
  elsif (!defined($p_sHomeDir) || "" eq $p_sHomeDir)
  {
    warn("Unabe to create GPG key for user that does not have a home dir (this is where the keys are stored).")
  }
  else
  {
    print("We are now going to generate a GPG key.  This is\n");
    print("the key that others will use to verify data from\n");
    print("your Vantages daemon.\n");
    print("Follow the prompts that come next.  You can specify\n");
    print("any 'real name' 'eamil address,' 'comment,' etc. that\n");
    print("you want, but remember that this key will be used by\n");
    print("any Vantages daemons that you peer with.\n");

    my $iErr = system("gpg --homedir $p_sHomeDir/.gnupg --gen-key");
    my @lFiles = glob("$p_sHomeDir/.gnupg/*");
    chown($p_iUID, -1, @lFiles);
    if (0 != $iErr)
    {
      warn("Unable to generate key.");
    }
    else
    {
      _config_key($p_sCxn, $p_sHomeDir);
    }
  }
}

sub _parse_config
{
  my $p_sConfigFile = shift;

  my $pRet = undef;

  if (!open(CONFIG, "< $p_sConfigFile"))
  {
    warn("Unable to open config file: '$p_sConfigFile'");
  }
  else
  {
    $pRet = {};
    while (my $sLine = <CONFIG>)
    {
      chomp($sLine);
      $sLine =~ s/^\s+//;
      $sLine =~ s/\s+$//;
      if ($sLine !~ /^#/
          && $sLine =~ m/^(\S+)\s*=\s*(.+)$/)
      {
        my ($sKey, $sVal) = ($1, $2);
        $pRet->{$sKey} = $sVal;
      }
    }

    close(CONFIG);
  }

  return $pRet;
}

if (!getopts("c:h", \%hOpts))
{
  warn("Unable to get opts.");
  _usage();
}
elsif (defined($hOpts{'h'}))
{
  _usage();
}
else
{
  my $sUser = $ENV{'USER'};
  my $iUID = $<;
  if ($iUID != 0)
  {
    warn("Warning, it is possible that as a non-root user this script will not be able to create and/or modify all the necessary files.\n");
    print("Do you want to continue as user '$sUser'? [y/N] > ");
    my $sResp = <>;
    if ($sResp !~ /^y$/i)
    {
      exit(1);
    }
  }
  else
  {
    print("Input user name that vantaged will run under (or leave blank for root):\nuser [root]> ");
    $sUser = <>;
    chomp($sUser);
    if (!defined($sUser) || "" eq $sUser)
    {
      $sUser = "root";
      $iUID = 0;
    }
  }

  my $sHomeDir = undef;
  my @lList;

  if ($sUser =~ /^\d+$/)
  {
    @lList = getpwuid($sUser);
  }
  else
  {
    @lList = getpwnam($sUser);
  }

  if (0 == scalar(@lList))
  {
    die("Unable to locate information about user: $sUser");
  }
  $sUser = $lList[0];
  $iUID = $lList[2];
  $sHomeDir = $lList[7];

  my $sConfigFile = "/etc/vantaged.conf";
  if (exists($hOpts{'c'}))
  {
    $sConfigFile = $hOpts{'c'};
  }


  my $pConfig = _parse_config($sConfigFile);
  if (!defined($pConfig))
  {
    warn("Unable to setup without valid config file.");
  }
  else
  {
    open(LOG, "> " . $pConfig->{'ps_log_file'});
    close(LOG);
    chown($iUID, -1, $pConfig->{'ps_log_file'});

    my %hOptions = (
                     '1' => 'Initialize database',
                     '2' => 'Generate GPG key',
                     '3' => 'Configure GPG key for signing',
                     '4' => 'Configure passphrase for GPG key (so daemon can start automatically)',
                     'q' => 'Quit',
                   );

    my $sChoice = "";
    while ($sChoice !~ /^[Qq]$/)
    {
      print("\n\nPlease choose from the following menu\n-------------\n");
      foreach my $sOpt (sort(keys(%hOptions)))
      {
        print("$sOpt  - ", $hOptions{$sOpt}, "\n");
      }
      print("\n\$ ");

      $sChoice = <>;
      if (!defined($sChoice))
      {
        $sChoice = "";
      }

      chomp($sChoice);

      my $sCxn = $pConfig->{'db_cxn_string'};
      if (1 eq $sChoice)
      {
        _create_db($sCxn, $sUser, $iUID, $sHomeDir);
      }
      elsif (2 eq $sChoice)
      {
        _create_key($sCxn, $sUser, $iUID, $sHomeDir);
      }
      elsif (3 eq $sChoice)
      {
        _config_key($sCxn, $sUser, $iUID, $sHomeDir);
      }
      elsif (4 eq $sChoice)
      {
        _config_pp($sCxn, $sUser, $iUID, $sHomeDir);
      }
      elsif ($sChoice !~ /^[Qq]$/)
      {
        print("Unrecognized choice: \"$sChoice\"\n");
      }
    }
  }
}
