#!/usr/bin/perl -w
#
# dgrey-cmd - Send a command to the dgrey daemon
#
# Copyright (C) 2008 Oskar Liljeblad
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Please see the dgrey(1) manual page for usage details.
# Please note that this file is automatically updated by make.
#

use strict;
use Getopt::Long;
use IO::Socket;

$::PACKAGE = 'dgrey'; # This line is automatically updated by make
$::VERSION = '0.1.0'; # This line is automatically updated by make
$::BUG_EMAIL = 'oskar@osk.mine.nu'; # This line is automatically updated by make
$::PROGRAM = $::PACKAGE.'-cmd';

my %opt = ();
Getopt::Long::Configure('bundling');
Getopt::Long::GetOptions(\%opt,
  'connect|c=s', 'config-file|f=s', 'local-connect|l', 'public-connect|p',
  'quiet|q', 'input-file|i=s', 'stdin|s', 'version', 'help');

if ($opt{'version'}) {
  print "$::PROGRAM ($::PACKAGE) $::VERSION\n";
  print "Copyright (C) 2008 Oskar Liljeblad\n";
  print "This is free software.  You may redistribute copies of it under the terms of\n";
  print "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n";
  print "There is NO WARRANTY, to the extent permitted by law.\n\n";
  print "Written by Oskar Liljeblad.\n";
  exit;
}
if ($opt{'help'}) {
  print "Usage: $0 [OPTION].. COMMAND [ARGUMENT]...\n";
  print "Send a command to the $::PACKAGE daemon.\n\n";
  print "Options:\n";
  print " -c, --connect=HOST:PORT   socket to connect to\n";
  print " -l, --local-connect       connect to local socket from config-file\n";
  print " -p, --public-connect      connect to public socket from config-file\n";
  print " -f, --config-file=FILE    read configuration from FILE\n";
  print " -q, --quiet               do not print any output\n";
  print " -s, --stdin               read input for command from standard input\n";
  print " -i, --input-file=FILE     read input for command from FILE\n";
  print "     --help                display this help and exit\n";
  print "     --version             output version information and exit\n";
  print "\nPlease see the $::PACKAGE documentation for a list of commands and arguments.\n";
  print "\nReport bugs to <", $::BUG_EMAIL, ">.\n";
  exit;
}

die "$0: local-connect and public-connect are mutually exclusive\n" if $opt{'local-connect'} && $opt{'public-connect'};
my $auth_key;
if (exists $opt{'config-file'}) {
  open(my $fh, '<', $opt{'config-file'}) || die $opt{'config-file'}, ": cannot open: $!\n";
  while (<$fh>) {
    $auth_key = 
    s/^\s*(.*?)\s*$/$1/;
    if (/^([a-z-]+)\s*=\s*(.*?)\s*$/) {
      my ($key,$value) = ($1,$2);
      if ($value =~ /^\"(\\.|[^\\"])*\"$/) {
        $value = $1;
        $value =~ s/\\(.)/$1/g;
      }
      if ($key eq 'auth_key') {
        $auth_key = $value;
      } elsif (($key eq 'local-listen' && $opt{'local-connect'}) || ($key eq 'public-connect' && $opt{'public-listen'})) {
        $opt{'connect'} = $value;
      }
    } elsif (!/^$/ && !/^#/) {
      die $opt{'config-file'}, ':', $., ': unparsable line', "\n";
    }
  }
  close($fh);
}
die "$0: missing connect option\n" if !defined $opt{'connect'};
die "$0: invalid connect address `$opt{'connect'}'\n" if $opt{'connect'} !~ /^(.*):\d+$/;
die "$0: missing command argument\n" if !@ARGV;
die "$0: specify one of `-s/--stdin' and `-i/--input-file'\n" if $opt{'stdin'} && defined $opt{'input-file'};
my $command = shift;

my $input_fh;
if ($opt{'stdin'}) {
  $input_fh = \*STDIN;
} elsif ($opt{'input-file'}) {
  open($input_fh, '<', $opt{'input-file'}) || die $opt{'input-file'}, ': cannot open file - ', $!, "\n";
}

my $fh = new IO::Socket::INET('PeerAddr' => $opt{'connect'}, 'Proto' => 'TCP');
if (!defined $fh) {
  die "$0: cannot connect to `$opt{'connect'}': $!\n" if !$opt{'quiet'};
  exit 1;
}

my $salt =  join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64];
print $fh '_'.$::PACKAGE.'_auth_digest='.crypt($auth_key, $salt)."\n" if defined $auth_key;
print $fh '_'.$::PACKAGE.'_request=', $command, "\n";
print $fh join("\n", @ARGV), "\n" if @ARGV;
print $fh "\n";
if (defined $input_fh) {
  while (defined (my $line = <$input_fh>)) {
    print $fh $line;
  }
  exit 0;
}
my $result;
my $line = <$fh>;
exit 2 if !defined $line;
chomp $line;
my ($rc) = ($line =~ /^rc=(\d+)$/);
exit 3 if !defined $rc;
while (defined (my $line = <$fh>)) {
  print $line if !$opt{'quiet'};
}
close($fh);
exit $rc;
