# Copyright 1999-2015. Parallels IP Holdings GmbH. All Rights Reserved.
package SpamAssassinCfg;

use AgentConfig;
use Logging;
use File::Spec;



sub parseConfig{
  my( $filename, $homedir ) = @_;

  my %config = ();
  my $cfg = \%config;

  readConfigLines( $filename, $cfg, $homedir );

  return $cfg;
}


sub readConfigLines{
  my ( $filename, $cfg, $homedir ) = @_;
  my $ifcount = 0;
  my $linenum = 0;
  Logging::debug( "Parse spamassassin config file:$filename" );
  if( not -e $filename ){
	Logging::error( "File $filename does not exists." );
        return;
  }
  open CFG, $filename;
  while(<CFG>) {
    chomp;
    my $line = $_;
    $linenum += 1;

    $line =~ s/(?<!\\)#.*$//; # remove comments
    $line =~ s/\\#/#/g; # hash chars are escaped, so unescape them
    $line =~ s/^\s+//;  # remove leading whitespace
    $line =~ s/\s+$//;  # remove tailing whitespace
    next unless($line); # skip empty lines

    my($key, $value) = split(/\s+/, $line, 2);
    $key = lc $key;
    # convert all dashes in setting name to underscores.
    $key =~ s/-/_/g;

    # Do a better job untainting this info ...
    $value = '' unless defined($value);
    $value =~ /^(.*)$/;
    $value = $1;

    if( $key eq 'if' or $key eq 'ifplugin' ){
    	$ifcount += 1;
        Logging::debug( "If condition ( text skipped ). Line $line, depth $ifcount" );
        next;
    }
    if( $key eq 'endif' ){
       if( $ifcount<=0 ){
       	 Logging::error( "EndIf found without if. Break parsing." );
         close CFG;
         return;
       }
       $ifcount -= 1;
       Logging::debug( "EndIf condition found. Line $line, depth $ifcount" );
    }

    next if $ifcount>0;
    if( $key eq 'include' ){
      my $incfile = fix_path_relative_to_current_file( $value, $filename, $homedir );
      Logging::debug( "Fix include path '$value' to '$incfile'" ) if $incfile ne $value;
      Logging::debug( "Include config file '$incfile'" );
      readConfigLines( $incfile, $cfg, $homedir );
    }
    if( exists $cfg->{$key} ){
      push @{${$cfg}{$key}}, $value;
    }
    else{
        my @temp;
        push @temp, $value;
    	${$cfg}{$key} = \@temp;
    }
  }
  close CFG;
}


sub fix_path_relative_to_current_file {
  my ($incfile, $curfile, $homedir) = @_;
  # the path may be specified as "~/foo", so deal with that
  $incfile = $homedir . substr( $incfile, 1 ) if $incfile =~ /^~.*/;

  if (!File::Spec->file_name_is_absolute ($incfile)) {
    my ($vol, $dirs, $file) = File::Spec->splitpath ( $curfile );
    $incfile = File::Spec->catpath ($vol, $dirs, $incfile);
  }
  return $incfile;
}


sub getConfigBlackList{
  my( $cfg ) = @_;
  return getConfigOptions( $cfg, 'blacklist_from' );
}

sub getConfigUnBlackList{
  my( $cfg ) = @_;
  return getConfigOptions( $cfg, 'unblacklist_from' );
}

sub getConfigWhiteList{
  my( $cfg ) = @_;
  return getConfigOptions( $cfg, 'whitelist_from' );
}

sub getConfigUnWhiteList{
  my( $cfg ) = @_;
  return getConfigOptions( $cfg, 'unwhitelist_from' );
}

sub getConfigRequireScore{
  my( $cfg ) = @_;
  my $ret = getConfigOptions( $cfg, 'required_score' );
  if( $ret and scalar( @{$ret} )==1 ){  return $ret->[0]; }
  #deprecated but still supported option
  $ret = getConfigOptions( $cfg, 'required_hits' );
  if( $ret and scalar( @{$ret} )==1 ){  return $ret->[0]; }
  return undef;
}


sub getConfigScore{
  my( $cfg ) = @_;
  return getConfigOptions( $cfg, 'score' );
}

sub getConfigRewriteHeadr{
  my( $cfg ) = @_;
  return getConfigOptions2( $cfg, 'rewrite_header' );
}


sub getConfigOptions{
  my( $cfg, $option ) = @_;
  if( exists $cfg->{$option} ){
     my @values = ();
     foreach $value( @{${$cfg}{$option}} ){
       push @values, split(/\s+/, $value);
     }
     return \@values;
  }
  return undef;
}

sub getConfigOptions2{
  my( $cfg, $option ) = @_;
  if( exists $cfg->{$option} ){
     my @values = ();
     foreach $value( @{${$cfg}{$option}} ){
       push @values, split(/\s+/, $value, 2);
     }
     return \@values;
  }
  return undef;
}


1;