#!/usr/bin/perl

########## Confixx(R) 3.0 Professional ############
####### Copyright SWsoft, Inc. 2004-2005 ##########
#### http://www.sw-soft.com - info@sw-soft.com ####

use File::Copy;

use lib_module_common;

use strict;

# -------------------- writeMHost -------------------- #
sub writeMHost{
	my ( $myConfixxIP, $confixx_domain, $confixx_accessLog, 
			 $confixx_errorLog, $confixx_port, $ptrVHostsHash ) = @_;

#
# init paths to log if they are empty
#
	if ( $confixx_IP =~ /^\d+\.\d+\.\d+\.\d+$/ ) {
	  $myConfixxIP = $confixx_IP;
	}

	unless ( $confixx_accessLog && $confixx_errorLog ) {
		my $confixxLogDir = $apacheLogDir;
		$confixxLogDir =~ s/\/[^\/]+$//; ## get dirname
		unless (-d $confixxLogDir) {
			$confixxLogDir = $apacheLogDir;
		}
		
		$confixx_accessLog ||= "$confixxLogDir/$confixx_domain\_access.log";
		$confixx_errorLog ||= "$confixxLogDir/$confixx_domain\_error.log";
	}

	my ($myDbh,$myConnect,$dbaddress,$cssl,$port,$ptrGlobalSettings,
			@ports,%listen,$documentRoot);

	$ptrGlobalSettings = &parseHttpdConf();
	if ( ref($ptrGlobalSettings) =~ /HASH/ ) { ## parsing is success
		
		my ($port);
		if( $port = $ptrGlobalSettings->{'Listen'} ) {
			if ( ref($port) =~ /ARRAY/ ) {
				@ports = sort { $a <=> $b } map {$_ =~ s/^.*://; $_} @{$port};  ## 0.0.0.0:80 -> 80
				
			} else {
				$port =~ s/^.*://; ## 0.0.0.0:80 -> 80
				@ports = ($port);
			}

			@ports = sort { $a <=> $b } @ports;

			if ( ($ports[0] > 0 ) && ( $ports[0] < $confixx_port ) ) {
				$confixx_port = $ports[0];
			}
		}

#
#		To take into account the instruction 'Port' to determinate the confixx's port
#
		if ( $port= $ptrGlobalSettings->{'Port'}  ) {
			my (@portPorts);
			if ( ref($port) =~ /ARRAY/ ) {
				@portPorts = sort { $a <=> $b } map {$_ =~ s/^.*://; $_} @{$port};  ## 0.0.0.0:80 -> 80

			} else {
				$port =~ s/^.*://; ## 0.0.0.0:80 -> 80
				@portPorts = ($port);
			}

			if ( ($portPorts[0] > 0 ) && ( $portPorts[0] < $confixx_port ) ) {
				$confixx_port = $portPorts[0];
			}
		}
	}

	$confixx_port = 80 unless $confixx_port;
	

	my $time = localtime();
	open ( FILE, ">$mhost_conf" );
	
	print FILE << "HEADER_INC";
################### CONFIXX APACHE MAIN CONFIG FILE ######################
# created at $time
#
#            !!! Do not make any changes in this file !!!
#
# 1. We cannot guarantee that the software will work properly, if 
# the contents of this file are modified.
# 2. This file would be rewritten after each Confixx software update and 
# in some other cases. Thus all your changes would be lost unless you made
# a backup of the file.
#
# If you need to modify this file, you can insert some custom "Include" 
# directives. E.g. 
#   Include /path/to/your/file
# Includes inserted directly after <VirtualHost> tag would keep their 
# location inchanged after the file is updated. Other includes would 
# be moved to be inserted before the </VirtualHost> tag.
##########################################################################

HEADER_INC

	if ( ref($ptrVHostsHash) =~ /HASH/ && $ptrVHostsHash->{'listen'} ) {
		$port = $ptrVHostsHash->{'listen'};

	} else {
		if ( ref($ptrGlobalSettings) =~ /HASH/ ) { ## httpd.conf is success parsed
			$port = 443;
		}else{
			$port = undef;
		}
	}

	if(ref($port)=~/ARRAY/){
		%listen = map { $_ => 1 } @{$port};

	} elsif ( $port =~ /^\d+$/ ) {
		%listen = ( $port => 1 );
	}

	if ( ref($ptrGlobalSettings) =~ /HASH/ ) { ## httpd.conf is success parsed
		$listen{$confixx_port} = 1;  # add main port
	}

	map {delete $listen{$_}} @ports;  ## delete alreade listen
	unless($bin_openssl && -x $bin_openssl && 
		 $sslKeyDir && -d $sslKeyDir && 
		 $sslCrtDir && -d $sslCrtDir){
		delete $listen{443};  ## delete 443 if has not SSL
	}

	foreach $port (sort {$a<=>$b} keys %listen){
		next unless $port =~ /^\d+$/;
		print FILE "Listen $port\n";
	}

#
# add global php settings
#
	if(exists($ptrGlobalSettings->{'DocumentRoot'}) && 
		 !ref($ptrGlobalSettings->{'DocumentRoot'})){
		$documentRoot = $ptrGlobalSettings->{'DocumentRoot'};
	}

	if ( ref( $ptrGlobalSettings ) =~ /HASH/ ) { ## httpd.conf is success parsed
		my $ptrPhp = $ptrGlobalSettings->{'php_admin_value'};
		if ( ref($ptrPhp) =~ /HASH/ ) {
			if ( !exists($ptrPhp->{'open_basedir'} ) && $documentRoot ) {
				print FILE "php_admin_value open_basedir $documentRoot\n";
			}
			my($found,@includes,$paths);
			if ( ( $paths = $ptrPhp->{'include_path'} ) =~ /^(['"])(.*)\1$/ ) {
				$paths = $2;
			}
			@includes = split(/:/,$paths);
			map { $found ||= 1 if /^\.$/ } @includes;
			unless($found){
				push @includes,'.';
				print FILE 'php_admin_value include_path "',join(':',@includes),"\"\n";
			}

		} else {
			if ( $documentRoot ) {
				print FILE "php_admin_value open_basedir $documentRoot\n";
			}
			print FILE "php_admin_value include_path .\n";
		}
	}
#
# end add global php settings
#

	if( $confixx_homeDir  ){

		print FILE <<"VHOST_CONF";

<Directory "$confixx_htmlDir">

  AllowOverride all

  <IfModule mod_access.c>
    Allow from all
  </IfModule>

  <IfModule mod_rewrite.c>

    RewriteEngine On
    Options +FollowSymlinks

    RewriteRule ^reseller/res[0-9]+/(.*)\$ reseller/\$1 [L]

    RewriteRule ^user/[a-zA-Z][-a-zA-Z0-9_]{0,4}[0-9]+/(.*)\$ user/\$1 [L]

    RewriteRule ^ftplogin/[a-zA-Z][-a-zA-Z0-9_]{0,4}[0-9]+/(.*)\$ ftplogin/\$1 [L]
    RewriteRule ^ftplogin/[a-zA-Z][-a-zA-Z0-9_]{0,4}[0-9]+f[0-9]+/(.*)\$ ftplogin/\$1 [L]

    RewriteRule ^poplogin/[a-zA-Z][-a-zA-Z0-9_]{0,4}[0-9]+p[0-9]+/(.*)\$ poplogin/\$1 [L]

  </IfModule>

  AddDefaultCharset off

</Directory>

VHOST_CONF

		my ($ptrHash,$ptrSslVHost) = &getConfixxVHost($ptrVHostsHash, undef, $myConfixxIP);

		unless( ref($ptrHash)=~/HASH/ ) {
			$ptrHash = {'ServerName' => $confixx_domain,
									'ip' => $myConfixxIP,
									'port' => $confixx_port,
									'access_log' => $confixx_accessLog,
									'error_log' => $confixx_errorLog
							 };
		}		

#
# leave CustomLog/ErrorLog empty if they were empty
#
#		unless ( exists($ptrHash->{'access_log'} ) ) {
#			$ptrHash->{'access_log'} = $confixx_accessLog;
#		}
#		unless ( exists($ptrHash->{'error_log'} ) ) {
#			$ptrHash->{'error_log'} = $confixx_errorLog;
#		}
#
		&printVirtualHost(*FILE,$ptrHash);

		my (%sslHosts,@key,$ip,$pathKey,$pathCrt,$keyKey,$keyCrt,@log);
	
		unless( ref( $ptrVHostsHash ) =~ /HASH/ ) {
				
			if($bin_openssl && -x $bin_openssl && 
				 $sslKeyDir && -d $sslKeyDir && 
				 $sslCrtDir && -d $sslCrtDir){

				$sslHosts{$myConfixxIP} = {};
				unless( ref($ptrSslVHost) =~ /HASH/ ) {
					$ptrSslVHost = {};
				}
				$sslHosts{$myConfixxIP}->{443} = {'ServerName' => $confixx_domain,
																				 'ip' => $myConfixxIP,
																				 'port' => 443,
																				 'CustomLog' => $ptrSslVHost->{'CustomLog'},
																				 'ErrorLog' => $ptrSslVHost->{'ErrorLog'}
																				};
				$ptrHash = $sslHosts{$myConfixxIP}->{443};
				$ptrHash->{'SSLEngine'} = 'on';
				$ptrHash->{'SSLCertificateKeyFile'} = "$sslKeyDir/$confixx_domain.key";
				$ptrHash->{'SSLCertificateFile'} = "$sslCrtDir/$confixx_domain.crt";
						
				unless (-e "$sslKeyDir/$confixx_domain.key" &&
								-e "$sslCrtDir/$confixx_domain.crt"){

					unless(&createSSLFiles($confixx_domain)){
						delete $sslHosts{$myConfixxIP}->{ 443 };
					}
				}
			}else{
				delete $ptrHash->{'SSLEngine'};
			}
					
			$ptrVHostsHash = \%sslHosts;
		}


		foreach $ip (sort keys %{$ptrVHostsHash}){
			foreach $port (sort keys %{$ptrVHostsHash->{$ip}}){
				$ptrHash = $ptrVHostsHash->{$ip}->{$port};
				if ( ( exists($ptrHash->{'SSLEngine'}) && ( $ptrHash->{'SSLEngine'} =~ /on|yes|1/i ) ) or
					 exists($ptrHash->{'SSLEnable'})){
						
					$ptrHash->{'ip'} = $ip;
					$ptrHash->{'port'} = $port;
					
					if ( exists( $ptrHash->{'SSLEngine'} ) ) {
						$keyKey = 'SSLCertificateKeyFile';
						$keyCrt = 'SSLCertificateFile'
					} elsif ( exists($ptrHash->{'SSLEnable'} ) ) {
						$keyKey = 'SSL_KeyFile';
						$keyCrt = 'SSL_CertFile';
					}
					
					$pathKey=$ptrHash->{$keyKey};
					$pathCrt=$ptrHash->{$keyCrt};

#
# prepare log files for the ssl host
#						
					$ptrHash->{'access_log'} = $ptrHash->{'CustomLog'} || 
						&insertSsl($ptrHash->{'access_log'} || $confixx_accessLog );
					$ptrHash->{'error_log'} = $ptrHash->{'ErrorLog'} || 
						&insertSsl( $ptrHash->{'error_log'} || $confixx_errorLog );

					unless ($pathKey && $pathCrt &&
									-e $pathKey && -e $pathCrt){
								
						unless( &createSSLFiles( $pathKey,$pathCrt ) ) {
							next;  ## there are not key & crt
						}
					}

					if ($pathKey && $pathCrt &&
							( -f $pathKey ) && ( -f $pathCrt ) ) {
						&printVirtualHost(*FILE, $ptrHash);
					}
				}
			}
		}
	}

	print FILE "Include $vhost_conf\n" .
		"# ^- " . &ltext('install_httpdconf_comment') . "\n" .
		"## /CONFIXX\n";

	close(FILE);
	
	open(FILE, ">>$vhost_conf");
	print FILE "#### CONFIXX VHOST FILE #### \n";
	close(FILE);
	
}
# -------------------- end writeMHost -------------------- #

sub insertSsl {
	my $logFile = shift;
	my ( $dir,$name,$tok );

## extract name of file
	if ( $logFile =~ /^(.*)\/([^\/]+)$/ ){ 
		$dir = $1;
		$name = $2;
	} else {
		$name = $logFile;
	}
## parse name
	my @log = split( /\./, $name );
	if ( @log > 1 ) {
		$tok = '.';
	} else {
		@log = split( /_/, $name );
		$tok = '_';
	}

## insert 'ssl' if there is not 
	my $foundSSL = 0;
	map {$foundSSL ||= ($_ eq 'ssl')?1:0} @log;
	unless ( $foundSSL ) {
		if ( @log ) {
## insert 'ssl' into the next-to-last position
			splice ( @log, $#log, 0, 'ssl' ); 
		} else {
## insert 'ssl' into the last position
			push @log, 'ssl';
		}
		$name = join($tok, @log);
	}

## make a full name
	$logFile = $dir? $dir.'/'.$name: $name;

	return $logFile;
}

sub printVirtualHost {
	my($fh,$ptrHash) = @_;

	my ($ip,$port,$serverName,$accessLog,$errorLog,$serverAlias);
	$ip = $ptrHash->{'ip'};
	$port = $ptrHash->{'port'};
	$accessLog = $ptrHash->{'access_log'} || $ptrHash->{'CustomLog'};
	$errorLog = $ptrHash->{'error_log'} || $ptrHash->{'ErrorLog'};

	$serverName = $ptrHash->{'ServerName'};
	$serverAlias = $ptrHash->{'ServerAlias'};

	print $fh "\nNameVirtualHost $ip\:$port\n".
		           "<VirtualHost $ip\:$port>\n";

	if ( exists ( $ptrHash->{'include_top'} ) ) {
		print $fh join("\n",map{$_?'  Include '.$_:''} ('',@{$ptrHash->{'include_top'}},''));
	}

	print $fh "\n  ServerName $serverName\n" if $serverName;
	print $fh "  ServerAlias $serverAlias\n" if $serverAlias;

	if ( exists ( $ptrHash->{'Redirect'} ) ) {
		print $fh "\n  Redirect / ",$ptrHash->{'Redirect'},"\n";

	} else {
		print $fh <<"VHOST_BODY";
	
  #User $confixx_user
  #Group $confixx_group
  DocumentRoot $confixx_htmlDir
  Options FollowSymLinks

  php_admin_flag safe_mode Off
  php_admin_flag file_uploads On
  php_admin_flag track_vars On
  php_admin_flag magic_quotes_runtime Off
  php_admin_flag magic_quotes_gpc Off
  php_admin_value upload_tmp_dir $confixx_homeDir/tmp
  php_admin_value include_path ".:$confixx_htmlDir/include:$confixx_htmlDir"
  php_admin_value default_charset none
  php_admin_value open_basedir $confixx_homeDir

  php_admin_value session.cookie_path /
  php_admin_value session.auto_start 0
  php_admin_value session.gc_maxlifetime 1800
  php_admin_value session.use_cookies 1
  php_admin_value session.cookie_lifetime 0
  php_admin_value session.cookie_secure Off
  php_admin_value session.use_trans_sid 0

  ScriptAlias /cgi-bin/ $confixx_cgiDir/
	
  <IfModule mod_dir.c>
    DirectoryIndex index.html index.htm index.shtml index.cgi index.php
  </IfModule>

VHOST_BODY

#
# SSL part
#

		if($ptrHash->{'SSLEngine'} eq 'on'){

			my $SSLCipherSuite = $ptrHash->{'SSLCipherSuite'}?
				'SSLCipherSuite '.$ptrHash->{'SSLCipherSuite'}:
				'';

			my $pathKey = $ptrHash->{'SSLCertificateKeyFile'}||"$sslKeyDir/$serverName.key";
			my $pathCrt = $ptrHash->{'SSLCertificateFile'}||"$sslCrtDir/$serverName.crt";

			print $fh <<"VHOST_SSL2";

  <IfModule mod_ssl.c>

    SSLEngine on
    SSLCertificateKeyFile $pathKey
    SSLCertificateFile $pathCrt
    $SSLCipherSuite

    SetEnvIf User-Agent ".*MSIE.*" \\
      nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0

    <Files ~ "\\.(cgi|shtml|phtml|php3?)\$">
      SSLOptions +StdEnvVars
    </Files>

    <Directory "$confixx_cgiDir">
      SSLOptions +StdEnvVars
    </Directory>

  </IfModule>
		
VHOST_SSL2

		} elsif ( exists$ptrHash->{'SSLEnable'} ) {

			my $SSLRequiredCiphers = $ptrHash->{'SSLRequiredCiphers'}?
				'SSLRequiredCiphers '.$ptrHash->{'SSLRequiredCiphers'}:
				'';

			my $pathKey = $ptrHash->{'SSL_KeyFile'}||"$sslKeyDir/$serverName.key";
			my $pathCrt = $ptrHash->{'SSL_CertFile'}||"$sslCrtDir/$serverName.crt";


			print $fh <<"VHOST_SSL";

  <IfModule mod_ssl.c>

    SSLEnable
    SSL_KeyFile $pathKey
    SSL_CertFile $pathCrt
    $SSLRequiredCiphers

    SetEnvIf User-Agent ".*MSIE.*" \\
      nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0

  </IfModule>
		
VHOST_SSL

		}
#
# end SSL part
#
	
#
# logging
#	
		print $fh "\n";
		if ( $accessLog ) {
			print $fh "  CustomLog $accessLog ",
				'"%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\""',
				"\n";
		}
		if ( $errorLog ) {
			print $fh "  ErrorLog $errorLog\n";
		}
		print $fh "\n";
#
# end logging
#
	}

	if(exists($ptrHash->{'include_bottom'})){
		print $fh join("\n",map{$_?'  Include '.$_:''} ('',@{$ptrHash->{'include_bottom'}},''));
	}
	print $fh "\n</VirtualHost>\n";

}

#
# parseMHost
#
#  argument:
#     $pathMHost - path to confixx_mhost.conf ( default $::mhost_conf)
#
#  return:
#     pointer to hash of virtual hosts: 
#                          keys   - (<ip>,<port>)
#                          values - pointer to hash with SSL directives
#

sub parseMHost {
	my $pathMHost = shift || $::mhost_conf;
	my $ptrHash = shift;
	unless( $pathMHost && -T $pathMHost ) {
		return undef;
	}

	unless( open( MHOST, '<'.$pathMHost ) ) {
		warn "Unable to open $pathMHost: $!\n";
		return undef;
	}

	my($ip,$port,%vhosts,$state,$line);
	if ( ref($ptrHash) =~ /HASH/ ) {
		%vhosts = %{$ptrHash}; ## init hash
	}
	$state=0;
	while (<MHOST>){
		chomp;
		next if /^\s*#/;  ## skip comment
		next if /^\s*$/;  ## skip blank
		$line=$_;
		$line=~s/^\s+//; ## ltrim
		if($state==0){
			if($line=~/^NameVirtualHost (\d+\.\d+\.\d+\.\d+):(\d+)/){
				$ip = $1;
				$port = $2;
				$vhosts{$ip}={} unless exists $vhosts{$ip};
				$vhosts{$ip}->{$port}={} unless exists $vhosts{$ip}->{$port};
			} elsif ( $line =~ /^<VirtualHost (\d+\.\d+\.\d+\.\d+):(\d+)/ ) {
				$ip = $1;
				$port = $2;
				$state = 1;
				$vhosts{$ip} = {} unless exists $vhosts{$ip};
				$vhosts{$ip}->{$port} = {} unless exists $vhosts{$ip}->{$port};
				$ptrHash = $vhosts{$ip}->{$port};
			}
		}elsif($state>0){
			if($line=~/^<\/VirtualHost/){
				$state = 0;
				$ptrHash = undef;
				next;
			}
			if($state==1){
				if($line=~/^Include\s+(.+)\s*$/){
					push @{$ptrHash->{'include_top'}},$1;
					next;
				}else{
					$state=2;
				}
			}
			if($state>1){

				if ( $line =~ /^(ServerName|ServerAlias)\s+(\S*)/ ) {
					$ptrHash->{$1}=$2;

				} elsif ( $line =~ /^(SSL\w+)\s+(\S*)/ ) {
					$ptrHash->{$1}=$2;

				} elsif ( $line =~ /^(CustomLog|ErrorLog|DocumentRoot)\s+(\S+)/ ) {
					$ptrHash->{$1}=$2;

				} elsif ( $line =~ /^(Redirect)\s+\/\s+(\S.*)\s*$/){ ## Redirect / <url>
					$ptrHash->{$1}=$2;
					
				} elsif ( $line =~ /^Include\s+(.+)\s*$/ ) {
					push @{$ptrHash->{'include_bottom'}},$1;

				}
			}
		}
	}
	close (MHOST);
	return \%vhosts;
}

#
# creteSSLFiles - crete SSL key & self-signed certificate
#
#   parameters:
#     1.   one parameter - name of domain - prefix of the file names 
#
#     2.   two parameters - full pathes to files
#
#  return:
#          1 - success. Files are created.
#          0 - fail
# 
sub createSSLFiles {
	my ($name,$fullPathKey,$fullPathCrt);
	if(@_==1){
		$name = shift;
		$fullPathKey = "$sslKeyDir/$name.key";
		$fullPathCrt = "$sslCrtDir/$name.crt";
	}else{
		($fullPathKey,$fullPathCrt)=@_;
		if($fullPathKey=~/([^\/]+)\.[^.]+$/){
			$name = $1;
		}
	}

	$bin_openssl ||= 'openssl';

	if(-l $fullPathKey){
		unlink $fullPathKey;
	}	

 	my $cmd = "$bin_openssl genrsa -rand -des3 -out $fullPathKey 1024";
	unless(system($cmd)==0){
	  warn "Error execute command: $cmd : $!\n";
	  return 0;
	}	  
	
	
	my $sslSrc = "$confixx_tmpDir/ssl.src";
	unless(open(SRC,">$sslSrc")){
	    warn "Unable to open file '$sslSrc' for writing: $!\n";
	    return 0;	
	}
	
	print SRC <<"SETTINGS";
US
Virginia
Herndon
SWsoft, Inc.
Confixx
confixx
info\@confixx.com
	
SETTINGS
	
	close (SRC);

	if(-l $fullPathCrt){
		unlink $fullPathCrt;
	}	

	
	$cmd = "cat $sslSrc | $bin_openssl req  -new -x509 -days 365 -key $fullPathKey -out $fullPathCrt";

	unless(system($cmd)==0){
	    warn "Error execute command: $cmd : $!\n";
	    return 0;
	}

	unlink $sslSrc;

	chmod 0400,$fullPathKey;
	chmod 0400,$fullPathCrt;

	return 1;
}

sub getConfixxVHost {
	my ($ptrMHost,$confixxPort,$confixxIP) = @_;
	unless(ref($ptrMHost)=~/HASH/){
		return undef;
	}
	if( $confixxPort =~ /^\d+\.\d+\.\d+\.\d+$/ ){
		$confixxIP = $confixxPort;
		$confixxPort = undef;
	}

	my($ip,$port,$ptrVHost,$ptrConfixxVHost,$ptrConfixxSSLVHost);
	my $pat = qr/^\Q$confixx_htmlDir\E(\s|$)/;

	foreach $ip (keys %{$ptrMHost}){
		foreach $port ( keys %{$ptrMHost->{$ip}}){
			if ( $confixxPort && ( $port ne $confixxPort ) ) {
				next; ## search port
			}

			$ptrVHost = $ptrMHost->{$ip}->{$port};

			if ( $ptrVHost->{'DocumentRoot'} =~ /$pat/ ) {

				$ptrVHost->{'ip'} = $ip;
				$ptrVHost->{'port'} = $port;

				if ( ( exists( $ptrVHost->{'SSLEngine'} ) && ( $ptrVHost->{'SSLEngine'}=~/on|yes|1/i ) ) ||
						 exists( $ptrVHost->{'SSLEnable'} ) ) {
## SSL virtual host
					$ptrConfixxSSLVHost = $ptrVHost;

				} else {
## non SSL virtual host
					$ptrConfixxVHost = $ptrVHost unless $ptrConfixxVHost;
				}

			} else {
				if ( ( $confixxIP eq $ip ) && exists ( $ptrVHost->{'Redirect'} ) ) {

					$ptrVHost->{'ip'} = $ip;
					$ptrVHost->{'port'} = $port;

					$ptrConfixxVHost = $ptrVHost;
				}
			}
		}

	}
	if(wantarray()){
		return ($ptrConfixxVHost,$ptrConfixxSSLVHost);
	}else{
		return $ptrConfixxVHost || $ptrConfixxSSLVHost;
	}
}


sub checkSSLFiles {
	my $ptrMHost = shift;

	unless($sslKeyDir && -d $sslKeyDir){
		return 0;
	}

	my($ip,$port,$keyKey,$keyCrt,$pathKey,$pathCrt,$ptrVHost,$confixxKey,$confixxCrt,
		$confixx_domain);

	if(ref($ptrMHost)=~/HASH/){

		foreach $ip (keys %{$ptrMHost}){
			foreach $port ( keys %{$ptrMHost->{$ip}}){
				$ptrVHost = $ptrMHost->{$ip}->{$port};
				if(exists($ptrVHost->{'SSLEngine'})){
					$keyKey = 'SSLCertificateKeyFile';
					$keyCrt = 'SSLCertificateFile'
				}elsif(exists($ptrVHost->{'SSLEnable'})){
					$keyKey = 'SSL_KeyFile';
					$keyCrt = 'SSL_CertFile';
				}else{
					next;
				}
				
#
# get old path
#
				$pathKey = $ptrVHost->{$keyKey};
				$pathCrt = $ptrVHost->{$keyCrt};

				$confixx_domain = $ptrVHost->{'ServerName'};

				$confixxKey = "$sslKeyDir/$confixx_domain.key";
				$confixxCrt = "$sslCrtDir/$confixx_domain.crt";
				
				if(-f $pathKey && -f $pathCrt){
					if(&safeSymLink($pathKey,$confixxKey)){
						$ptrVHost->{$keyKey}=$confixxKey;
					}
					if(&safeSymLink($pathCrt,$confixxCrt)){
						$ptrVHost->{$keyCrt}=$confixxCrt;
					}
					last;
				}
			}
		}
	}
			
#
# end safe SSL files
#
	return 1;
}

sub safeSymLink {
	my($src,$dst)=@_;
	return 1 if ($src eq $dst);
	return 1 unless -f $src;
	if(-e $dst){
		my $dstBak = "$dst.confixx_backup";
		if (-e $dst){
			unlink $dstBak;
			rename $dst,$dstBak;
		}
	}
	symlink($src,$dst) 
		or return 0;
	return 1;
}
#
# parseHttpdConf - parsing of httpd.conf to extract global settings
#                  ignore <If...> tags 
#
#  arguments:
#             $pathConf - path of file to parse
#             $ptrHash - pointer to hash with results
#  return:
#             undef - fail
#             $ptrHash - pointer to hash with results
#
#
sub parseHttpdConf {
	my $pathConf = shift || $httpd_conf;
	my $ptrHash = shift || {};
	my ($fh,$line,$patTag);
	unless ( open( $fh, "<$pathConf" ) ) {
		warn "Error open file: '$pathConf': $!\n";
		return undef;
	}

	while ( <$fh> ) {
		chomp;
		s/^\s+//; # ltrim
		next unless $_; # skip blank line
		next if /^#/; # skip comment
		next if /^<\/?If(Module|Define)/; # ignore <If..> </If..>
		$line=$_;
		if($patTag){ ## skip content of tag
			if($line=~/$patTag/){
				$patTag = undef;
			}
		}else{
			if ( $line =~ /^<(\w+)/ ) { ## a tag is found
				$patTag = qr/^<\/\Q$1\E/;  ## pattern to find the end tag
			} elsif ( $line =~ /^Include\s+(\S+)/ ) {
				my $pathInclude = $1;

				next if $pathInclude =~ /\/confixx_[mv]host\.conf$/; ## skip confixx part

				unless ( $pathInclude =~ /^\// ) { ## unless begin with '/'
					if ( $ptrHash->{'ServerRoot'} ) {
						my $rootDir = $ptrHash->{'ServerRoot'};
						$rootDir =~ s/\/$//;
						$pathInclude = "$rootDir/$pathInclude";
					}
				}
				if ( -T $pathInclude ) {
					&parseHttpdConf( $pathInclude,$ptrHash ); ## !!! recursion !!!

				} elsif ( $pathInclude =~ /[*%]/ ) {  ## is a wildcard
					my @list = glob($pathInclude);
					foreach $pathInclude ( @list ) {
						chomp $pathInclude;
						if ( -T $pathInclude ) {
							&parseHttpdConf( $pathInclude,$ptrHash ); ## !!! recursion !!!
						}
					}
				}
			}else{
				my ($key,$tail) = split(' ',$line,2);
				if ( $key =~ /^php_admin_(flag|value)/ ) {
					my ($phpKey,$phpValue) = split(' ',$tail,2);
					$ptrHash->{$key} = {} unless exists $ptrHash->{$key};
					$ptrHash->{$key}->{$phpKey} = $phpValue;
				}else{
					$tail=~s/\s+$//; # rtrim
					if($tail=~/^(['"])(.*)\1$/){ ## remove quotes
						$tail=$2;
					}
				
					if(exists($ptrHash->{$key})){
						unless( ref( $ptrHash->{$key} ) =~ /ARRAY/ ) {
							$ptrHash->{$key} = [$ptrHash->{$key}]; ## convert to array
						}
						push @{$ptrHash->{$key}},$tail; ## add new value to array
					}else{
						$ptrHash->{$key} = $tail;
					}
				}
			}
		}
	}
	close($fh);
	return $ptrHash;
}

#
# &removeVHost - remove confixx's VirtualHost from apahce's config.
#                an original config have saved with name "$pathToConf.confixx_save"
#                use a temporary file "$pathToConf.confixx_new"
#
# arguments:
#            $pathToConf   - a full path to apache's config file
#            $DocumentRoot - a full path to confixx's document root
#
# return:
#            1 - OK
#            0 - fail
#
sub removeVHost {
	my ( $pathToConf, $DocumentRoot ) = @_;

	unless ( $pathToConf && -T $pathToConf ) {
		warn "Error: file '$pathToConf' is not found\n";
		return 0;
	}
	unless ( $DocumentRoot ) {
		warn "Error: DocumentRoot is not set\n";
		return 0;
	}
	unless ( open (CONF,'<'.$pathToConf) ) {
		warn "Error: unable to open file '$pathToConf' to read: $!\n";
		return 0;
	}
	my $newConf = $pathToConf.'.confixx_new';
	unless ( open (OUT, '>'.$newConf ) ) {
		warn "Error: unable to open file '$newConf' to write: $!\n";
		return 0;
	}
	
	my ($state,$out,$orig,$line,@vh,$path);
	
	while (<CONF>) { ## read source
		$orig = $line = $_;
		chomp $line;

		$out = 1 unless $state;

		unless ( ( $state != 1 ) && ( $line =~ /^\s*(#|$)/ ) ) {
			$line =~ s/^\s+//; ## ltrim

			if ( $state == 1) { ## VirtualHost

				push @vh, $orig;

				if ( $line =~ /^DocumentRoot\s+(.+)/ ) {
					$path = $1;
					if ( $path =~ /^(["'])(.*)\1/ ) { ## extract quotes
						$path = $2;
					}
					unless ( $path eq $DocumentRoot ) {
						$orig = join( '', @vh );
						$out = 1;
					}
					$state = 2; ## find the end tag
				}elsif ( $line =~ /^<\/VirtualHost>/ ) { ## the end tag is found
					$state = 0;
				}

			} elsif ( $state == 2 ) { ## to find the end tag
				if ( $line =~ /^<\/VirtualHost>/ ) {
					$state = 0;
				}

			} elsif ( $state == 3 ) { ## to find the end tag
				if ( $line =~ /^<\/Directory>/ ) {
					$state = 0;
				}
	
			} else { ## the main state
	
				if ( $line =~ /^<VirtualHost\s/i ){ ## start of VirtualHost
					@vh = ($orig);
					$out = 0;
					$state = 1;

				} elsif ( $line =~ /^<Directory\s+(.+)/i ) { ## start of Directory
					$path = $1;
					if ( $path =~ /^(["'])(.*)\1/ ) { ## extract quotes
						$path = $2;
					} else {
						$path =~ s/\s*>.*$//;
					}
					$state = 3; ## to find the end tag
					$out =  ( $path eq $DocumentRoot )? 0: 1;
				}
			}
		}

		if ( $out ){ ## write to destination
			print OUT $orig;
		}
	}

	close OUT;
	close CONF;

	my $saveConf = $pathToConf.'.confixx_backup';	

	my ($mode,$uid,$gid) = (stat($pathToConf))[2,4,5];
	$mode &= 07777;
	move( $pathToConf, $saveConf );
	move( $newConf, $pathToConf );

	my $ret=0;

	if ( $mode ) { ## restore ownership & permission
		if ( chmod ($mode, $pathToConf)
				 &&
				 chown ($uid, $gid, $pathToConf) 
			 ) {
			$ret = 1; ## OK
		}
	}
	return $ret;
}

1;
