#!/usr/bin/perl -w

#----------------------------------------------------------------------
# copyright (C) 2002 Mitel Networks Corporation
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 		
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 		
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
# 
# Technical support for this program is available from Mitel Networks 
# Please visit our web site www.mitel.com/sme/ for details.
#----------------------------------------------------------------------

#--------------------------------------------------
# Names in the hosts database can be:
# - Internal name only (name for host on local LAN)
#    hp4500=host|InternalIP|192.168.16.201|MacAddress|aa:bb:cc:dd:ee:ff
#
# - Hosted by e-smith server (internal/external on e-smith server)
#    mail=host|ExternalIP|self|InternalIP|self
#
# - Externally hosted
#    www=host|ExternalIP|a.b.c.d
#
# - Internal machine behind port-forwarding firewall
#    secure=host|ExternalIP|d.e.f.g|InternalIP|w.x.y.z
#
# Unqualified names in the key apply to all domains
# FQDNs apply to specific domains and override the wildcard shortnames
#--------------------------------------------------
package esmith;

use strict;
use Errno;
use esmith::config;
use esmith::db;

my %conf;
if( $ENV{ESMITH_CONFIG_DB} ) {
    tie %conf, 'esmith::config', $ENV{ESMITH_CONFIG_DB};
}
else {
    tie %conf, 'esmith::config';
}

my %hosts;
if( $ENV{ESMITH_HOSTS_DB} ) {
    tie %hosts, 'esmith::config', $ENV{ESMITH_HOSTS_DB};
}
else {
    tie %hosts, 'esmith::config', '/home/e-smith/hosts';
}

=begin testing

use esmith::TestUtils qw(scratch_copy);

my $h_tmp = '50-hosts/hosts.conf.4.1.2';
my $c_scratch = scratch_copy('50-hosts/configuration.conf');
$ENV{ESMITH_HOSTS_DB}  = $h_tmp;
$ENV{ESMITH_CONFIG_DB} = $c_scratch;

# 4.1.2 Hosts DB which caused bug 2495
open(TMP, ">$h_tmp") || die $!;
print TMP <<'OUT';
archie=host|ExternalIP|209.28.139.23|InternalIP|self
e-smith=host|ExternalIP|self|InternalIP|self
e-smith-manager=host|ExternalIP|self|InternalIP|self
ftp=host|ExternalIP|self|InternalIP|self
mail=host|ExternalIP|self|InternalIP|self
proxy=host|ExternalIP|self|InternalIP|self
server=host|ExternalIP|self|InternalIP|self
www=host|ExternalIP|self|InternalIP|202.49.164.27
OUT
close TMP;

END { unlink $h_tmp }

system($^X, $Original_File);

use esmith::ConfigDB;
use esmith::HostsDB;
my $migrated = esmith::HostsDB->open;
my $config   = esmith::ConfigDB->open;
my $domain = $config->get('DomainName')->value;

my $www = $migrated->get("www.$domain");
isa_ok( $www, 'esmith::DB::Record' );
is( $www->prop('InternalIP'), '202.49.164.27' );
is( $www->prop('ExternalIP'), '' );
is( $www->prop('HostType'),   'Local' );

my $archie = $migrated->get("archie.$domain");
isa_ok( $archie, 'esmith::DB::Record' );
is( $archie->prop('InternalIP'), '',                    'InternalIP');
is( $archie->prop('ExternalIP'), '209.28.139.23',       'ExternalIP' );
is( $archie->prop('HostType'),   'Remote',              'HostType' );


my @migrated = grep { $_->key !~ /^(archie|www)/ } 
               $migrated->get_all_by_prop(type => 'host');
is_deeply( [ sort map { $_->key } @migrated ],
           [ sort map { "$_.$domain" } 
                  qw( e-smith e-smith-manager ftp mail proxy server )],
                             'domain names fully qualified'
);

foreach my $host (@migrated) {
    my $dn = $host->key;
    is( $host->prop('HostType'),        'Self',  "$dn - HostType");
    is( $host->prop('ExternalIP'),      ''    ,  "      ExternalIP" );
    is( $host->prop('InternalIP'),      ''    ,  "      InternalIP" );
}

=end testing

=cut

#------------------------------------------------------------
# Populate the hosts database with default entries if they
# they don't already exist
#------------------------------------------------------------
my $event = $ARGV [0];

#------------------------------------------------------------
# Migrate existing hosts to new format for primary domain, and
# for any existing virtual domains
#
# eg. www=host|...   -> www.{$DomainName}=host|...
#------------------------------------------------------------

my @FQDNHostList = ();
my @ShortHostList = ();

foreach my $host (keys %hosts)
{
    if ($host =~ /\./)
    {
	# keep track of fully qualified domain name hosts
	push @FQDNHostList, $host;
    }
    else
    {
	# keep track of single word hosts
	push @ShortHostList, $host;
    }
}

# Add the primary domain to the list of domains
my $DomainName = db_get (\%conf, 'DomainName');

my @domainsList = ( $DomainName );

eval "require esmith::NetworkServicesDB";

unless ($@)
{
    my $nsdb = esmith::NetworkServicesDB->open();

    if ($nsdb)
    {
	my $service_domain = $nsdb->service_domain();

        push @domainsList, $service_domain if $service_domain;
    }
}

my %domains;
tie %domains, 'esmith::config', '/home/e-smith/domains';

# Add each virtual domain to the list of domains
foreach my $domain ( keys %domains )
{
    next unless (db_get_type(\%domains, $domain) eq 'domain');

    push @domainsList, $domain;
}

#-------------------------------------------------------
# Iterate over each domain to propagate the single host
# entries for each virtual domain
#-------------------------------------------------------

foreach my $domain ( @domainsList )
{
    # default visibility property is 'Local' as this never existed before

    my %properties = (
    		Visibility => 'Local'
    );

    foreach my $host ( @ShortHostList )
    {
	$properties{'InternalIP'} = 
		db_get_prop (\%hosts, $host, 'InternalIP') || '';

	$properties{'ExternalIP'} = 
		db_get_prop (\%hosts, $host, 'ExternalIP') || '';

	$properties{'MACAddress'} = 
		db_get_prop (\%hosts, $host, 'MACAddress') || '';

	my $FQDN = "$host.$domain";

	next if (defined db_get (\%hosts, $FQDN));

	# If defined as host 'self', change to new format
	if (($properties{'InternalIP'} eq 'self') && 
            ($properties{'ExternalIP'} eq 'self'))
	{
	    $properties{'HostType'} = 'Self';
	    $properties{'InternalIP'} = '';
	    $properties{'ExternalIP'} = '';
	    $properties{'MACAddress'} = '';
	}
        # defined as 'local' entry in new format
	elsif( $properties{InternalIP} ne 'self' )
	{
	    $properties{'HostType'} = 'Local';
            $properties{ExternalIP} = '';
	}
        elsif( $properties{ExternalIP} ne 'self' ) 
        {
            $properties{'HostType'} = 'Remote';
            $properties{InternalIP} = '';
        }
        else {
            warn "$host has no InternalIP or ExternalIP!\n";
        }

	db_set (\%hosts, $FQDN, 'host', \%properties);
    }
}

#-------------------------------------------------------
# Iterate over all of the fully qualified domain names,
# setting valid ones (from @domainsList) with appropriate
# values and flagging other non-expected ones with errors
#-------------------------------------------------------

foreach my $key ( @FQDNHostList )
{
    # Skip the hosts if already in the new format
    next if (defined db_get_prop (\%hosts, $key, 'HostType'));

    my %properties = (
	Visibility => 'Local'
    );

    my ($tempHost, $tempDomain) = split /\./, $key, 2;

    my @matches = grep(/$tempDomain/, @domainsList);

    unless (@matches)
    {
	# doesn't match an existing domain, set error flag
	$properties{'error'} = 'Host has no matching domain in system';
    }

    $properties{'InternalIP'} = db_get_prop (\%hosts, $key, 'InternalIP') || '';
    $properties{'ExternalIP'} = db_get_prop (\%hosts, $key, 'ExternalIP') || '';
    $properties{'MACAddress'} = db_get_prop (\%hosts, $key, 'MACAddress') || '';

    # If defined as host 'self', change to new format
    if ($properties{'InternalIP'} eq 'self')
    {
	$properties{'HostType'} = 'Self';
	$properties{'InternalIP'} = '';
	$properties{'ExternalIP'} = '';
	$properties{'MACAddress'} = '';
    }
    else  # defined as 'local' entry in new format
    {
	$properties{'HostType'} = 'Local';
	$properties{'ExternalIP'} = '';
    }

    db_set (\%hosts, $key, 'host', \%properties);
}


# Remove the old single host entries
foreach my $host ( @ShortHostList )
{
    db_delete (\%hosts, $host);
}

exit (0);
