# Copyright 1999-2012. Parallels IP Holdings GmbH. All Rights Reserved.
package CapabilityInfoDumper;

use strict;
eval{require warnings;1;};
use Logging;
use HostingDumper;
use DAL;
use MiscConfigParser;
use AgentConfig;
use PleskStructure;
use HelpFuncs;
use PleskVersion;

use vars qw|$pleskX $packer|;

sub new {
  my $self = {};
  bless( $self, shift );
  $self->_init(@_);
  return $self;
}

sub _init {
  my ($self, $agent) = @_;
  $pleskX = $agent;
  $packer = $pleskX->{packer};
  $self->{dbs_params} = ();     # MySQL servers variables cache
  return;
}

sub _dumpScripting {
  my ($self, $components, $domainIds) = @_;
  
  foreach my $domainId (@{$domainIds}) {
    
    my $hostingParams = DAL::getHostingParams($domainId);
    
    my (undef, $scripting) = HostingDumper::getScripting($hostingParams);
    
    while ( my ( $name, $value ) = each(%{$scripting}) ) {
      if ($value eq 'true') {
        $components->{$name} = $value;
      }
    }
    
    $components->{'phphandler.id'} = $scripting->{'php_handler_id'} if exists $scripting->{'php_handler_id'};
    
    if ( defined( $hostingParams->{'webstat'} ) and $hostingParams->{'webstat'} ne 'none' and $hostingParams->{'webstat'} ne '') {
      my $webstatName;
      if (PleskVersion::atLeast( 8, 1, 0 )) {
        $webstatName = $hostingParams->{'webstat'};
      } else {
        $webstatName = 'webalizer';
      }
      $components->{$webstatName} = 'true';
    }

    my $quota = DAL::getSysUserQuotaByDomainId($domainId);
    if ($quota > 0) {
        $components->{'hard_quota'} = 'true';
    }

    if ($hostingParams->{'traffic_bandwidth'} > 0 || $hostingParams->{'max_connection'} > 0) {
        $components->{'mod_bw'} = 'true';
    }
  }
  
  return $components;
}

sub _dumpHostingParams {
  my ($self, $misc, $components, $domainId) = @_;
  
  my $hostingParams = DAL::getHostingParams($domainId);
  
  if ( defined $hostingParams->{'sys_user_id'} ) {
    my $sysuserInfo = HostingDumper::getSysUserInfo($hostingParams->{'sys_user_id'});
    $components->{'shell'} = $sysuserInfo->{'shell'};
    $misc->{'sysuser'} = $sysuserInfo->{'login'};
  }

  my %users;
  $users{'webuser'} = DAL::getWebUsers($domainId);
  $users{'ftpuser'} = DAL::getAdditionalFtpUsers($domainId);

  foreach my $userType (keys %users) {
    foreach my $user (@{$users{$userType}}) {
     my $userInfo = HostingDumper::getSysUserInfo($user->{'sys_user_id'});
     push @{$misc->{$userType}}, $userInfo->{'login'};
    }
  }

  my $domParams = DAL::getDomainParams($domainId);
  if (exists $domParams->{'webmail'} && $domParams->{'webmail'} ne 'none') {
    $components->{'webmail'} = $domParams->{'webmail'};
  }
  if (exists $domParams->{'stat_ttl'}) {
    $misc->{'stat_ttl'} = $domParams->{'stat_ttl'};
  }
  
  return ($misc, $components);
}

sub _getDbParam {
  my ($self, $dbServerId, $param) = @_;

  my $key = 'db'.$dbServerId.$param;
  if (exists $self->{dbs_params}->{$key}) {
    return $self->{dbs_params}->{$key};
  }

  my $dbServer = DAL::getDatabaseServer($dbServerId);
  return if (!$dbServer);
  
  my $dbPasswd = PleskStructure::getDbServerAdminPassword($dbServer);

  my $wrapMysql = Db::DbConnect::getDbConnect(
    $dbServer->{'type'},       $dbServer->{'admin_login'}, $dbPasswd, undef,
    $dbServer->{'host'}, undef,   undef,     undef,
    undef,         $dbServer->{'port'}
  );
  if ( ref($wrapMysql) eq 'HASH' ) {
    if ( $wrapMysql->{'EXECUTE'}->("SHOW VARIABLES LIKE \"$param\"") )
    {
      my $ptrRow = $wrapMysql->{'FETCHROW'}->();
      if ($ptrRow) {
        $self->{dbs_params}->{$key} = $ptrRow->[1];
      }
      $wrapMysql->{'FINISH'}->();
    }
  }
  
  if (exists $self->{dbs_params}->{$key}) {
    return $self->{dbs_params}->{$key};
  }
}

sub _isLocalhost {
  my ($host) = @_;
  return $host eq 'localhost' || $host eq '127.0.0.1';
}

sub _dumpDatabases {
  my ($self, $misc, $components, $domainId, $dbServers) = @_;
  
  my $databases = DAL::getDomainDatabases($domainId);
  my $hasRemoteDatabases = 0;
  my $hasPgDatabases = 0;
  if (scalar @{$databases} > 0) {
    foreach my $db (@{$databases}) {
      if ($db->{'type'} eq 'mysql') {
        my $key = 'dbsrv.'.$db->{'db_server_id'}.'.max_allowed_packet';
        if (not defined $misc->{$key}) {
          my $maxAllowedPacket = $self->_getDbParam($db->{'db_server_id'}, 'max_allowed_packet');
          $misc->{$key} = $maxAllowedPacket if $maxAllowedPacket;
        }
      } elsif ($db->{'type'} eq 'postgresql') {
        $components->{$db->{'type'}} = AgentConfig::getPostgresqlVersion();
        $hasPgDatabases = 1;
      } else {
        $components->{$db->{'type'}} = 'true';
      }

      my $dbServer = $dbServers->{$db->{'db_server_id'}};
      $hasRemoteDatabases ||= !_isLocalhost($dbServer->{'host'});
    }

    $misc->{'has_remote_databases'} = ($hasRemoteDatabases ? 'true' : 'false');

    if ($hasPgDatabases && (!(-e AgentConfig::pgdumpBin()) || !(-e AgentConfig::psqlBin()))) {
        $misc->{'no_postgresql_commands'} = 'true';
    }
  }
  
  return ($misc, $components);
}

sub _dumpMail {
  my ($self, $components, $domainIds) = @_;
  
  my $misc = DAL::getMisc();
  my $virusfilterName = 'drweb';

  if (exists $misc->{'virusfilter'}) {
    $virusfilterName = $misc->{'virusfilter'};
  }  
  
  foreach my $domainId (@{$domainIds}) {
    my $maillists = DAL::getDomainMaillists($domainId);
    if (scalar @{$maillists} > 0) {
      $components->{'maillists'} = 'true';
    }
    
    my $mails = DAL::getDomainMails($domainId);

    if ( scalar(@{$mails}) > 0 ) {
      $components->{'mail'} = 'true';
    }

    my $domainAsciiName = DAL::getDomainAsciiNameById($domainId);
    
    if ( PleskVersion::atLeast( 8, 1, 0 ) ) {
      foreach my $mail (@{$mails}) {
        my $mailInfo = DAL::getMailNameInfo($mail->[0]);
        if ($mailInfo->{'spamfilter'} eq 'true') {
          $components->{'spamfilter'} = 'true';
          last;
        }
      }
    } elsif ( PleskVersion::atLeast( 7, 0, 0 ) ) {
      my $sql = "SELECT COUNT(*) FROM sa_conf WHERE mailname LIKE '%@". $domainAsciiName . "' AND flt_enabled <> ''";
      if ( $pleskX->{dbh}->execute_rownum($sql) ) {
        if ( @{ $pleskX->{dbh}->fetchrow() }[0] ne "0" ) {
          $components->{'spamfilter'} = 'true';
        }
      }
      $pleskX->{dbh}->finish();
    }
    
    foreach my $mail (@{$mails}) {
      my $mailInfo = DAL::getMailNameInfo($mail->[0]);
      my $mailName = $mailInfo->{'mail_name'};
      if ( PleskVersion::atLeast( 8, 1, 1 ) ) {
        if ( $mailInfo->{'virusfilter'} ne 'none' ) {
          $components->{'antivirus'} = $virusfilterName;
          last;
        }
      } else {
        my $state = MiscConfigParser::parseDrWebConfig( $mailName . '@' . $domainAsciiName );
        if (defined($state) and ($state ne 'none')) {
          $components->{'antivirus'} = 'drweb';
          last;
        }
      }
    }
    
    my $domainKeysState = DAL::getDomainKeysState($domainId);
    if (defined $domainKeysState && $domainKeysState eq 'true') {
      $components->{'domain_keys'} = 'true';
    }
    
    if ( PleskVersion::atLeast( 9,0,0 ) ) {
      my $domParams = DAL::getDomainParams($domainId);
      my $glParams = DAL::getGLParams();
      my $glState = (exists $domParams->{'gl_filter'} ) ? $domParams->{'gl_filter'} : 'on';
      if ($glState eq 'on' && $glParams->{'enabled'} eq 'true') {
        $components->{'grey_listing'} = 'true';
      }
    }
  }
  
  return $components;
}

sub _dumpTomcat {
  my ($self, $components, $domainIds) = @_;
  
  foreach my $domainId (@{$domainIds}) {
    my $webapps = DAL::getDomainWebApps($domainId);
    if (scalar %{$webapps} > 0) {
      $components->{'tomcat'} = 'true';
      last;
    }
  }
  
  return $components;
}

sub _dumpDns {
  my ($self, $components, $domainIds) = @_;
  
  if ( PleskVersion::atLeast( 11, 5, 22 ) ) {
    foreach my $domainId (@{$domainIds}) {
      my $domainAsciiName = DAL::getDomainAsciiNameById($domainId);
      my $domainPtr = DAL::getDomainPtrByAsciiName($domainAsciiName);
      if ( $domainPtr->{'dns_zone_id'} != 0 ) {
        $components->{'dns'} = 'true';
      }
    }
  } else {
    $components->{'dns'} = 'true';
  }
  
  return $components;
}

sub dumpDomain {
  my ($self, $domainId, $domainName, $domainAsciiName) = @_;

  if ($packer->{listingOnlyMode} && $packer->{migrationMode}) {
    
    my ($components, $misc, $domainResourceUsageInfo);
    
    my (@domainsToProcess);    
    
    push @domainsToProcess, $domainId;
    
    if ( PleskVersion::atLeast( 10, 0, 0) ) {
      my $sites = DAL::getSitesByWebspaceId($domainId);
      if (scalar @{$sites} > 0) {
        foreach my $site (@{$sites}) {
          push @domainsToProcess, $site->{'id'};
        }
      }
    }
    
    $components = $self->_dumpScripting($components, \@domainsToProcess);
    
    ($misc, $components) = $self->_dumpHostingParams($misc, $components, $domainId);

    my %dbServersById;
    foreach my $dbs (@{DAL::getDatabaseServers()}) { $dbServersById{$dbs->{'id'}} = $dbs; }
    ($misc, $components) = $self->_dumpDatabases($misc, $components, $domainId, \%dbServersById);
    
    $components = $self->_dumpMail($components, \@domainsToProcess);
    
    $components = $self->_dumpTomcat($components, \@domainsToProcess);

    $components = $self->_dumpDns($components, \@domainsToProcess);
    
    $domainResourceUsageInfo = $self->_getDomainResourceUsage($domainName, $domainAsciiName, \@domainsToProcess);
    
    my %capabilityInfo;
    $capabilityInfo{'components'} = $components;
    $capabilityInfo{'resource-usage'} = $domainResourceUsageInfo;
    $capabilityInfo{'miscellaneous'} = $misc;

    $packer->makeCapabilityInfoNode(\%capabilityInfo, $domainId);
  }
}

sub _getDomainResourceUsage {
  my ($self, $domainName, $domainAsciiName, $domainIds) = @_;
  
  my $domainId = $domainIds->[0];
  
  use BackupSizeCalculator;
  my $calc = BackupSizeCalculator->new( $pleskX );
  my $domainResourceUsageInfo = $calc->getDomainDiskUsage($domainId, $domainName, $domainAsciiName);
  
  my $webs = DAL::getWebUsers($domainId);
  $domainResourceUsageInfo->{'resource.webusers'} = scalar @{$webs};
  
  foreach my $id (@{$domainIds}) {
    if ( PleskVersion::atLeast( 8, 0, 0 ) ) {
      my $aliases = DAL::getDomainAliases($id);
      $domainResourceUsageInfo->{'resource.aliases'} += scalar @{$aliases};
    }
    
    my $mails = DAL::getDomainMails($id);
    $domainResourceUsageInfo->{'resource.mailaccounts'} += scalar @{$mails};
  }
  
  return $domainResourceUsageInfo;
}

sub _getLicenseResourceUsage {
  # Objects that are controlled by license
  my ($self, $userAccounts, $domains, $domainAliases, $mailAccounts, $webUsers);
  $domains = PleskStructure::getDomainsCount('');
  $userAccounts = PleskStructure::getClientsCount('');
  $domainAliases = PleskVersion::atLeast( 8, 0, 0 ) ? scalar @{DAL::getDomainAliases(undef)} : 0;
  $webUsers = scalar @{DAL::getWebUsers(undef)};
  $mailAccounts = scalar @{DAL::getDomainMails(undef)};
  
  my %result = (
    'resource.domains' => $domains
    , 'resource.accounts' => $userAccounts
    , 'resource.aliases' => $domainAliases
    , 'resource.webusers' => $webUsers
    , 'resource.mailaccounts' => $mailAccounts
  );  
  return \%result;
}

sub _getPhpHandlers {
  my ($self) = @_;
  my $phphandlers = HostingDumper::getPhpHandlers();  
  
  my %result;
  
  if ($phphandlers) {
    foreach my $handlerName (keys %{$phphandlers}) {
      my $prefix = 'phphandler.'.$handlerName.'.';
      $result{$prefix.'id'} = $phphandlers->{$handlerName}{'id'};
      $result{$prefix.'type'} = $phphandlers->{$handlerName}{'type'};
      $result{$prefix.'typeName'} = $phphandlers->{$handlerName}{'typeName'};
      $result{$prefix.'version'} = $phphandlers->{$handlerName}{'version'};
      $result{$prefix.'displayname'} = $phphandlers->{$handlerName}{'displayname'};
      $result{$prefix.'registered'} = $phphandlers->{$handlerName}{'registered'};
    }
  }
  
  return \%result;
}

sub _getSoftwarePackages {
  my $packages = DAL::getSoftwarePackages();

  my %result;
  if ($packages) {
    foreach my $name (keys %{$packages}) {
      $result{'package.'.$name} = $packages->{$name};
    }
  }

  return \%result;
}

sub _getDatabaseServers {
  my $servers = DAL::getDatabaseServers();

  my @result;
  foreach my $row (@$servers) {
    my %server = (
      'type' => $row->{'type'},
      'host' => $row->{'host'},
      'port' => $row->{'port'},
      'version' => $row->{'server_version'},
      'local' => (_isLocalhost($row->{'host'}) ? 'true' : 'false')
    );
    push(@result, \%server);
  }

  return \@result;
}


sub _getApacheModules {

   my %modules;
   my $httpdModulesUtil = AgentConfig::get("PRODUCT_ROOT_D") . "/admin/bin/httpd_modules_ctl";
   my $output = `$httpdModulesUtil -s`;
   my $retCode = $? >> 8;
   if ($retCode == 0) {
       my @lines = split /\n/, $output;
       foreach my $line( @lines ) {
           my @tokens = split(/\s+/, $line);
           $modules{@tokens[0]} = @tokens[1];
       }
   } else {
       Logging::debug("Unable to get apache modules: '$output'");
   }
   return \%modules;
}


sub dumpServer {
  my ($self) = @_;
  if ($packer->{listingOnlyMode} && $packer->{migrationMode}) {
    $packer->setServerSettings() unless defined $packer->{serverNode};
    my $resourceUsage = $self->_getLicenseResourceUsage();
    my %misc;
    my $miscParams = DAL::getMisc();
    $misc{'spamfilter_use_mailuser_prefs'} = $miscParams->{'spamfilter_use_mailuser_prefs'} if $miscParams->{'spamfilter_use_mailuser_prefs'} eq 'true';
    $misc{'ftpOverSsl'} = $miscParams->{'ftpOverSsl'} if exists $miscParams->{'ftpOverSsl'};
    %misc = (%misc, %{DAL::getIPAddressesFtps()});

    $misc{'dir_for_local_db_dump'} = AgentConfig::dumpDir() . '/databases';
    $misc{'allow_short_pop3_names'} = $miscParams->{'allow_short_pop3_names'} if $miscParams->{'allow_short_pop3_names'} eq 'enabled';

    $resourceUsage->{'resource.freespace'} = HelpFuncs::calculateFreeSpace($packer->{storage}->getFullOutputPath());

    my %capabilityInfo;
    $capabilityInfo{'components'} = {%{$self->_getPhpHandlers()}, %{$self->_getSoftwarePackages()}};
    $capabilityInfo{'database-servers'} = $self->_getDatabaseServers();
    if ( PleskVersion::atLeast( 10, 4, 0 ) ) {
        $capabilityInfo{'apache-modules'} = $self->_getApacheModules();
    }
    $capabilityInfo{'resource-usage'} = $resourceUsage;
    $capabilityInfo{'miscellaneous'} = \%misc;
    $packer->makeServerCapabilityInfoNode(\%capabilityInfo);
  }
}

1;

