package CS::Config;

use Carp;
use strict;
use vars qw(@ISA @EXPORT $VERSION);

require Exporter;

$VERSION = '0.1';
@ISA = qw(Exporter);
@EXPORT = qw(getpluginc gethostc checkpluginc checkhostc);

=head1 NAME

CS::Config - Checkservice config parsing

=head1 SYNOPSIS

  use CS::Config;

  my $error;
  
  return print STDERR "$error\n" 
    if $error = checkpluginc('warning', 'sms');
  my $beepconfig = getpluginc('warning', 'sms');

  return print STDERR "$error\n"
    if $error = checkhostc('groupA/subgroupB', 'host1');
  my $hostconfig = gethostc('groupA/subgroupB', 'host1');

=head1 DESCRIPTION
 
I<CS::Config> provides two kinds of config parsers for two types of configfiles.

=head1 FUNCTIONS

The following functions are provided. The functions uses
'/etc/checkservice' as default configroot unless $CS::Config::root is
set to a valid directory.

=cut

our ($root);
$root = '/etc/checkservice' unless (defined $root and -d $root);

=over 4

=item getpluginc(TYPE, PLUGIN)

Hashes a config file with format 'key=value' so information can be
retrieved from the hash returned using $ref->{key}.

  my $config = getpluginc('warning', 'test');

  print "Value of key: ", $config->{key}, "\n";

=cut

sub getpluginc {
  my %conf;
  my ($type, $plugin) = @_;
  my ($key, $value);

  (! -d "$root/plugins/$type") and 
    croak "Couldn\'t find config dir \'$root/plugins/$type\', moduletype may not exist\n";
  (! -r "$root/plugins/$type/$plugin.conf") and 
    croak "Configfile \'$root/plugins/$type/$plugin.conf\' not found or not readable\n";

  open CONF, "$root/plugins/$type/$plugin.conf" or 
    croak "Couldn't open configfile \'$root/plugins/$type/$plugin.conf\' for reading!\n";

  while (<CONF>) {
    chomp; s/#.*//;
    if (($key, $value) = /^\s*(\S+)\s*=\s*(\S.*)/) { $conf{$key} = $value; } 
  }
  
  close CONF;

  return \%conf;
}

=item checkpluginc(TYPE, PLUGIN)

Checks the validaty, readability and accessibility of PLUGIN of type
TYPE. Returns 0 if config is valid, or a string if an (parse)error
occurs. The string can be a notification of the fact that the
configfile isn't readable/accessible or that a parse error occured on
a given line.

  if ($error = checkpluginc('warning', 'beep') {
    print STDERR "beeplugin: $error\n";   # Error reporting if ran manual
    return 3;                             # Returncode 3: plugin error!
  }
  else {
    my $config = getpluginc('warning', 'beep');
  }

=cut

sub checkpluginc {
  my ($type, $plugin) = @_;

  return "Unable to read/find $root/plugins/$type/$plugin.conf: $!"
    unless ( -r "$root/plugins/$type/$plugin.conf");
    
  return parseconf("$root/plugins/$type/$plugin.conf");
}

=item gethostc([GROUPPATH], HOST)

Returns a hash with three keys: url, mailto, and services
Where url is a string, mailto a reference to an array and
services a reference to an hash, where the keys are the (first of the)
portnumber(s) to check and the values a reference to another hash,
representing a service, which is an hash with it's own 5
keys: ports, shortname, longname, checktype and action.

Visualization:
  
  \%hash (url)      --> "http://www.linvision.com/checkservice"
         (mailto)   --> \(paul@linvision.com, root@linvision.com)
         (services) --> \%services (21)  --> \%service (ports)     --> \(21)
                                                       (shortname) --> "ftp"
                                                       (longname)  --> "WuFTPd"
                                                       (checktype) --> "x"
                                                       (action)    --> ""
                                   (137) --> \%service (ports)     --> \(137,139)
                                                       (shortname) --> "samba"
                                                       ...etc
                                   ...etc
 				 
Example:

  my $hostc = gethostc('groupA', 'host1');

  print "URL:\t $hostc->{url}\n";
  print "Mailto:\t ", join(',', @($host->{'mailto'})), "\n";
  print "Services to check: ";
  foreach (keys %{$hostc->{'services'}}) {
    print $hostc->{'services'}->{$_}->{'shortname'}, " ";
  }
  print "\n";

=cut

sub gethostc {
  my $host = pop;
  my $path = shift;
  my ($url, @mailto, %services);

  $path .= '/' unless !$path or $path =~ /\/$/;
  (! -r "$root/hosts/$path$host") and 
    croak "Hostfile \'$root/hosts/$path$host\' not found or not readable!\n";

  open CONF, "$root/hosts/$path$host" or 
    croak "Couldn't open configfile \'$root/hosts/$path$host\' for reading!\n";

  my %conf = (url       => \$url,
              mailto    => \@mailto,
	      services  => \%services);

  while (<CONF>) {
    chomp; s/#.*//;
    if (/^\s*service\s*=\s*([\d,]+):(\w+):([sxn]):([^:]*):?(.*)$/) {
      my @ports = split ',', $1;
      my %service = (ports     => \@ports,
                     shortname => $2,
		     checktype => $3,
		     longname  => $4,
		     action    => $5);
      $services{$ports[0]} = \%service;
    }
    elsif (/^\s*mailto\s*=\s*(([\w._-]+@[\w_.-]+:)*[\w._-]+@[\w_.-]+)$/) {
      @mailto = split ':', $1;
    }
    elsif (/^\s*url\s*=\s*((\w+):\/\/[\w_.?&]+)$/) {
      $url = $1;
    }
  }
  close CONF;
  
  return \%conf;
}

=item checkhostc([GROUPPATH], HOST)

Checks the validity, readability and accessability of configfile for
HOST, grouped in optional GROUPPATH.. Returns 0 if config is
valid, return string with failed-reason if something went wrong.
(see also checkpluginc() above).

=cut

sub checkhostc {
  my $host = pop;
  my $path = shift;

  $path .= '/' unless !$path or $path =~ /\/$/;
  return "Unable to read/find $root/hosts/$path$host: $!"
    unless ( -r "$root/hosts/$path$host");

  return parseconf("$root/hosts/$path$host");
}

sub parseconf {
  my $cfile = shift;
  
  open CONF, $cfile or return "Couldn't open configfile $cfile: $!";
  
  while (<CONF>) {
    chomp; s/#.*//;
    return "Parse error on line $. of $cfile: $_"
      unless $_ =~ /^\s*(\S+)\s*=\s*(\S.*)/ or $_ =~ /^\s*$/;
  }
  
  return 0;
}

=head1 BUGS

checkpluginc() and checkhostc() returns parse errors on configfiles that ARE
parsable by getpluginc() and gethostc().

=head1 COPYRIGHT

Copyright (c) 2001 Paul van Tilburg.  All rights reserved.  This program
is free software; you can redistribute it and/or modify it under the same
terms as Checkservice itself.
  
=head1 AUTHOR INFORMATION

Paul van Tilburg <paul@linvision.com>, Checkservice homepage:
http://www.linvision.com/checkservice/
      
=head1 SEE ALSO

L<perl(1)>, L<checkservice(5)>.
              
=cut

1;


syntax highlighted by Code2HTML, v. 0.9.1