#
#


=head1 NAME

Net::DNS::SEC::Maint::Config - Module used in DNSSEC Maintenance shell. 



=head1 DESCRIPTION

This class is used to get and set configuration paramaters. 

=cut


package Net::DNS::SEC::Maint::Config;
use strict;
use Term::ReadLine;
use IO::File;
use Log::Log4perl qw(get_logger :levels);

use vars qw (
             $AUTOLOAD
	     $VERSION
	     $conffile
	     );




use Data::Dumper;
$VERSION = do { my @r=(q$Revision: 1.7 $=~/\d+/g); sprintf "%d."."%03d"x$#r,@r };

$conffile='/usr/local/etc/dnssecmaint.conf';


my $default_log4perl_conf=q(
    log4perl.category.MAINTKEYDB         = INFO, Logfile, Screen

    log4perl.appender.Logfile          = Log::Log4perl::Appender::File
    log4perl.appender.Logfile.filename = test.log
    log4perl.appender.Logfile.layout   = Log::Log4perl::Layout::PatternLayout
    log4perl.appender.Logfile.layout.ConversionPattern = [%r] %F %L %m%n

    log4perl.appender.Screen         = Log::Log4perl::Appender::Screen
    log4perl.appender.Screen.stderr  = 0
    log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
  );






=head1 CLASS METHODS

=head2 new


=cut


sub new {
    my $caller=shift;
    my $class=ref($caller)||$caller;


    if (-f "/usr/local/etc/log4perl.conf"){
	Log::Log4perl::init_once("/usr/local/etc/log4perl.conf");
      }elsif(-f "/etc/log4perl.conf" ){
	  Log::Log4perl::init_once("/etc/log4perl.conf");
	}else{
	    Log::Log4perl::init_once(\$default_log4perl_conf);
	  }




    my $logger=get_logger();

    my $self={
    };
    bless $self,$class;



    $logger->debug("initializing in class : $class\n");

    $self->set_default_conf;

    return $self;
}


=head2 read_config_file

Overwrites the default configuration paramaters by using reading the
config file. Normally you would use the following secuence.
    my $config=Net::DNS::SEC::Maint::Config->new();
    $config->set_default_conf;
    $config->read_config_file;


=cut




sub read_config_file {
    my $self=shift;
    my $logger=get_logger();
    $self->setconf('conffile',$conffile,
		   "specifies where the configuration file can be found");

    # Overwrite the default values by reading from the config file.
    $conffile=$self->getconf("conffile");
    $logger->debug("opening $conffile\n");

    if (open (CONF,$conffile)){
	$logger->debug("Overwriting with values from $conffile \n");
	while (<CONF>){
	
	    s/\#.*$//;        # strip comments
	    next if /^\s+$/;  # skip space only 
	    /^\s*(\S+)\s*=\s*(.*)\s*$/;
	    next if ! $2;     # no value with parameter
	    $self->setconf($1,$2);

	}
	close(CONF);
	$logger->debug("Done reading $conffile \n");
	}else{
	    $logger->warn("Could not open $conffile, using default values");
	    print "\nWARNING: Could not open $conffile, using default values\n";

	}


1;
}

=head2 makeconfig

  use Net::DNS::SEC::Maint::Config;
  Net::DNS::SEC::Maint::Config->makeconfig;

This method can be used to create a configuration file.  It will open
a terminal start asking the values for all configuration parameters,
giving current details. The method comes in handy at installation
time and should be used sparely.

The configfile contains lines with 'parameter=value' pairs. Trailing
and leading spaces are ignored.

All tokens on a line behind and including a '#' sign are considdered
comments


=cut


sub makeconfig {
    my $caller=shift;
    my $class=ref($caller)||$caller;
    my $self={};


    if (-f "/usr/local/etc/log4perl.conf"){
	Log::Log4perl::init_once("/usr/local/etc/log4perl.conf");
      }elsif(-f "/etc/log4perl.conf" ){
	  Log::Log4perl::init_once("/etc/log4perl.conf");
	}else{
	    Log::Log4perl::init_once(\$default_log4perl_conf);
	  }




    my $logger=get_logger;
    $logger->debug("calling function");
    bless $self,$class;
    $self->set_default_conf;
    
    my $term= new Term::ReadLine::Gnu "CONFIG_MAKECONFIG";
    $SIG{INT}=sub {  print "Next time use 'exit' to quit\n"; exit; };
    
    return "No Terminal" if ! $term;
    
    my $prompt;
  KEYLOOP:    foreach my $key ( sort keys %{$self}){
      next if $key !~ /^_config_(.*)$/;
      my $configentry=$1;
      print "       ----\n";
      print $configentry . " " . $self->getdescription($configentry). "\n" if $self->getdescription($configentry) ;
      print "This vallue is currently set using the DNSSECMAINT_".uc($configentry)."\n" if $ENV{"DNSSECMAINT_".uc($configentry)};
      $prompt="Enter value for ".$configentry.">";
      print $configentry ." is set to " .$self->getconf($configentry) . "\n";
      while ( defined ($_ = $term->readline($prompt,$self->getconf($configentry) )) ) {
	  return if /^\s*exit\s*$/;   
	  return if /^\s*quit\s*$/;   
	  if ( ! /^\s*$/ ){
	      $self->setconf("$configentry",$_);
	      next KEYLOOP;
	  }
      }
      
  } # end KEYLOOP
    
    my $configfile=$self->getconf("conffile");
    my @completion= qw (yes no);
    my $inline;
    my $confirm;
    $term->{completion_word} = \@completion;
    while ( 
	    defined ($inline = 
		     $term->readline("Save configuration file to:".$configfile."? (yes|no)>",))){
	$inline=lc($inline);
	if ( $inline =~ /^\s*yes\s*$/ ) {  
	    $confirm=1;
	    last;
	}elsif ($inline =~ /^\s*no\s*$/ ) {  
	    $confirm=0;
	    last;
	}else{
	    print "Invallid input: \"yes\" or \"no\"\n";  
	}
    }
    if ($confirm){
	open (CONF,"> ".$configfile )  or die "Could not open ".$configfile."(".$!.")\n";

	print CONF "# Configuration file generated by makeconfig " . gmtime() ."(CET)\n#\n#\n";

	foreach my $key (keys %{$self}){
	    next if $key !~ /^_config_(.*)$/;
	    my $configentry=$1;
	    next if $configentry eq "conffile";
	    print CONF "##########################################################################\n";
	    print CONF "# ".$configentry."\t: ".$self->getdescription($configentry)."\n";
	    print CONF "#       \t overwritten by DNSSECMAINT_".uc($configentry). " environment variable if specified.\n";
	    print CONF "#\n";
	    print CONF $configentry ."=" . $self->getconf($configentry)."\n\n\n";
	}

	print "To use this configuration file you have to set ".
	    "DNSSECMAINT_CONFFILE=".$configfile."\n";

	close (CONF);


	my $gid=getgrnam $self->getconf("maintgroup");
	if (!defined $gid){
	    print "    ". $self->getconf("maintgroup") . " is an unknown group\n";
	    print "    Please add the group to /etc/group or\n";
	} else {
	    chown(-1,$gid,$configfile) or die "Can't change group of  $configfile to $gid: $!";
	    chmod (0660, $configfile) or die "Can't change file permissions on $configfile: $!";
	}



    }    
    return (0);
}    

=head1 OBJECT METHODS
    

=head2 setconf

    $config->setconf("parameter","value");
    $config->setconf("parameter","value","description");

This method creates an entry in the parameter table and sets the (default value) to "value".
An optional 3rd paramater will be used for the discription.


=cut

sub  setconf {
    my $self=shift;
    my $logger=get_logger();
    my $parametername=lc shift;
    $self->{"_config_".$parametername}=shift;
    my $description=shift;
    $logger->debug("arguments:" .$parametername ."\t".$self->{"_config_".$parametername} );
    $self->setdescription($parametername,$description) if (defined $description);
    return ;
}



=head2 setdescription getdescription

    $config->setdescription("parameter","description");
    $description=$config->getdescription("parameter");

This method sets or gets a discription of a particular paramater.


=cut


sub  setdescription {
    my $self=shift;
    my $parametername=lc shift;
    my $logger=get_logger();
    $self->{"_description_".$parametername}=shift;
    $logger->debug($parametername ."\t".$self->{"_description_".$parametername} );
    return ;
}


sub getdescription {    
    my $self=shift;
    my $attr=lc shift;
    return ($self->{"_description_".$attr}) if $self->{"_description_".$attr};
    return "";
}





=head2 set_default_conf

    $config->set_default_conf;

Sets all default parameters as specified in the code. 

=cut



=head2 getconf

    $value=$config->getconf("parameter");

Returns the parameter value. 

The actual vallue of the paramater is read from  from a configuration file
specified in the DNSSECMAINT_CONFFILE configuration variable. If that
variable is not set or the file specified therein can not be read than
the parameters are read from the file called '/etc/dnsmaint.conf'.

If a configuration file cannot be found than the defaults are used,
these are hard-coded in the perl sources. 

If a parameter has been specified using a environment variable of the
form DNSSECMAINT_<PARAMNAME> then that value has precedence over the
value as specified in the configuration file or the defaults.


In the configuration file the first entry on a line is taken as the
parameter name, the rest of the line is interpreted as parameter
value.  Empty lines are ignored text between a pound sign '#' and a
new-line are interpreted as comment.


=cut

sub getconf {    
    my $self=shift;

    my $attr=lc shift;
    exists $self->{"_config_".$attr}  or die "No such attribute: $attr";
    return $ENV{ "DNSSECMAINT_".uc($attr) } if  $ENV{ "DNSSECMAINT_".uc($attr) } ;

    return $self->{"_config_".$attr};
}


=head1 PARAMAETER AND DEFAULT VALUES

All these parameters are set during 'set_default_conf'. 

=cut

sub  set_default_conf {
    my $self=shift;



=head2 logdir ( DNSSECMAINT_LOGDIR )

Full path to the directory where log files are stored.

=cut

    $self->setconf('logdir',"/usr/local/var/dnssec_maint/log",
		   "specifies the directory under logfiles are stored"
		   );





=head2 logdir ( DNSSECMAINT_TMPDIR )

Full path to the directory where temporary files are stored. Note that these files may be
large e.g (signed) zone files.

=cut

    $self->setconf('tmpdir',"/usr/local/var/dnssec_maint/tmp",
		   "specifies the directory under tmpfiles are stored"
		   );




=head2 group ( DNSSECMAINT_MAINTGROUP )

The name of the group that may access the key database. Defaults to 'dnssecmt'

=cut

    $self->setconf('maintgroup',"dnssecmt",
		   "Name of group that has R/W access to the dnssecmt"
		   );






    #### 
    #  Ending set_default conf
    1;

}




sub DESTROY
{
    return 1;
}



sub AUTOLOAD 
{
    my $self=shift;
    die "No such method $AUTOLOAD";
}

    



1;
