#!/usr/bin/perl -wT

# vim: ts=8 sw=4 noet:
#----------------------------------------------------------------------
# heading     : Configuration
# description : Domains
# navigation  : 6000 6600
#----------------------------------------------------------------------
#----------------------------------------------------------------------
# copyright (C) 1999-2003 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.
#----------------------------------------------------------------------

use strict;
use CGI ':all';
use CGI::Carp qw(fatalsToBrowser);
use esmith::FormMagick;

my $fm = esmith::FormMagick->new();
$fm->parse_xml();

use esmith::cgi;
use esmith::util;
use esmith::ConfigDB;
use esmith::DomainsDB;

sub showInitial ($$$);
sub genContentMenu ($$);
sub createDomain ($);
sub performCreateDomain ($);
sub modifyDomain ($);
sub performModifyDomain ($);
sub deleteDomain ($);
sub performDeleteDomain ($);

BEGIN
{
    # Clear PATH and related environment variables so that calls to
    # external programs do not cause results to be tainted. See
    # "perlsec" manual page for details.

    $ENV {'PATH'} = '';
    $ENV {'SHELL'} = '/bin/bash';
    delete $ENV {'ENV'};
}

esmith::util::setRealToEffective ();

$CGI::POST_MAX=1024 * 100;  # max 100K posts
$CGI::DISABLE_UPLOADS = 1;  # no uploads

my $conf = esmith::ConfigDB->open_ro() or die "Unable to open configuration db";
my %conf = $conf->as_hash;

my $domainsdb = esmith::DomainsDB->open
    or die "Could not open Domains DB\n";

#------------------------------------------------------------
# examine state parameter and display the appropriate form
#------------------------------------------------------------

my $q = new CGI;

if (! grep (/^state$/, $q->param))
{
    showInitial ($q, '', 0);
}

elsif ($q->param ('state') eq "create")
{
    createDomain ($q);
}

elsif ($q->param ('state') eq "performCreate")
{
    performCreateDomain ($q);
}

elsif ($q->param ('state') eq "modify")
{
    modifyDomain ($q);
}

elsif ($q->param ('state') eq "performModify")
{
    performModifyDomain ($q);
}

elsif ($q->param ('state') eq "delete")
{
    deleteDomain ($q);
}

elsif ($q->param ('state') eq "performDelete")
{
    performDeleteDomain ($q);
}

else
{
    esmith::cgi::genStateError ($q, \%conf);
}

exit (0);

#------------------------------------------------------------
# subroutine to display initial form
#------------------------------------------------------------

sub showInitial ($$$)
{
    my ($q, $msg, $error) = @_;

    #------------------------------------------------------------
    # If there's a message, we just finished an operation so show the
    # status report. If no message, this is a new list of domains.
    #------------------------------------------------------------
    my $remove = $fm->localise('REMOVE');
    my $modify = $fm->localise('MODIFY');

    if ($msg eq '')
    {
	esmith::cgi::genHeaderNonCacheable ($q, \%conf,
	    $fm->localise('FORM_TITLE'));
    }
    else
    {
	esmith::cgi::genHeaderNonCacheable ($q, \%conf,
	    $fm->localise('OPERATION_STATUS_REPORT'));
	my $class = $error ? 'error' : 'success';
	print $q->div ({-class => $class},$msg);
	print $q->hr;
    }

    #------------------------------------------------------------
    # Look up domains and domain descriptions
    #------------------------------------------------------------

    my @virtualDomains = $domainsdb->domains;

    print $q->p ($fm->localise('FORM_DESCRIPTION'));

    my $numDomains = @virtualDomains;
    if ($numDomains == 0)
    {
	print $q->h3($fm->localise('NO_VIRTUAL_DOMAINS'));
    }
    else
    {
	print $q->h3($fm->localise('CURRENT_LIST_OF_DOMAINS'));

	print $q->start_table ({-CLASS => "sme-border"});

	print $q->Tr (esmith::cgi::genSmallCell ($q,
			    $fm->localise('DOMAIN'),"header"),
			esmith::cgi::genSmallCell ($q,
			    $fm->localise('DESCRIPTION'),"header"),
			esmith::cgi::genSmallCell ($q,
			    $fm->localise('CONTENT_LABEL'),"header"),
			esmith::cgi::genSmallCell ($q,
                            $fm->localise('ACTION'),"header", 2));

	foreach my $domain (sort { $a->key cmp $b->key } @virtualDomains)
	{
	    my $content = $domain->prop('Content') || '';
	    $content = $content eq 'Primary' ?
			$fm->localise('PRIMARY_SITE') :
			$fm->localise('CONTENT', {content => $content});

	    my $description = $domain->prop('Description') || '';
	    my $is_removable = (($domain->prop('Removable') || 'yes') eq "yes");
	    $domain = $domain->key;

	    my $actionModify = "&nbsp;"
				. $q->a ({href => $q->url (-absolute => 1) 
				. "?state=modify&domain=" . $domain}, $modify)
				. "&nbsp;";
	    my $actionRemove .= "&nbsp;";

	    if ($is_removable)
	    {
		$actionRemove   .= $q->a ({href => $q->url (-absolute => 1) 
				. "?state=delete&domain=" . $domain}, $remove)
				. "&nbsp;";
	    }
	    else
	    {
		# If no other entries, ensure that empty "Remove" action column
		# is same size as "Modify" column by adding 10 spaces.
		$actionRemove .= "&nbsp;" x 10;
	    }

	    print $q->Tr (
		esmith::cgi::genSmallCell ($q, 
		    $domain, "sme-noborders-content"),
		esmith::cgi::genSmallCell ($q, 
		    $description, "sme-noborders-content"),
		esmith::cgi::genSmallCell ($q, 
		    $content, "sme-noborders-content"),
		esmith::cgi::genSmallCell ($q, 
		    $actionModify, "sme-noborders-content"),
		esmith::cgi::genSmallCell ($q, 
		    $actionRemove, "sme-noborders-content")),"\n";

	}
	print $q->end_table;
    }

    esmith::cgi::genFooter($fm);
}

#------------------------------------------------------------
# 
#------------------------------------------------------------

sub genContentMenu ($$)
{
    my ($q, $currentSetting) = @_;

    $currentSetting ||= 'Primary';   # this chooses the primary web site

    use esmith::AccountsDB;
    my $accounts = esmith::AccountsDB->open;

    # We do some subversion here to localize the label of "Primary".
    my %labels = map { $_->key => $_->prop('Name') } 
		    grep { $_->key ne "Primary" } $accounts->ibays;
    my @values = sort (keys %labels);

    $labels {'Primary'} = $fm->localise('PRIMARY_SITE');
    unshift @values, 'Primary';
    
    return esmith::cgi::genCell ($q,
	$q->popup_menu (-name    => 'domainContent',
			 -values  => \@values,
			 -default => $currentSetting,
			 -labels  => \%labels));
}

sub createDomain ($)
{
    my ($q) = @_;

    esmith::cgi::genHeaderNonCacheable
	($q, \%conf, $fm->localise('CREATE_TITLE'));
 
    print $q->startform (-method => 'POST',
			 -action => $q->url (-absolute => 1));

    print $q->table ({-CLASS => "sme-noborders"},

	esmith::cgi::genNameValueRow ($q,
                                      $fm->localise('DOMAIN_NAME_LABEL'),
				      "domainName",
				      ""),

	esmith::cgi::genNameValueRow ($q,
                                      $fm->localise('DESCRIPTION_LABEL'),
				      "domainDesc",
				      ""),

	esmith::cgi::genTextRow ($q,
	    $q->p ( $fm->localise('CONTENT_FIELD_DESCRIPTION'))),

        $q->Tr (
            esmith::cgi::genCell ($q, 
                $fm->localise('CONTENT_LABEL'), 
                "sme-noborders-label"),
	    genContentMenu ($q, '')),

	esmith::cgi::genButtonRow ($q,
				   $q->submit (-name => 'action',
					       -value =>
                                               $fm->localise('CREATE'))));

    print $q->hidden (-name => 'state',
		      -override => 1,
		      -default => 'performCreate');

    print $q->endform;
    
    esmith::cgi::genFooter($fm);
    return;
}

#------------------------------------------------------------
# 
#------------------------------------------------------------

sub performCreateDomain ($)
{
    my ($q) = @_;

    #------------------------------------------------------------
    # Validate parameters and untaint them
    #------------------------------------------------------------

    my $domainName = $q->param ('domainName');
    if ($domainName =~ /^([a-zA-Z0-9\-\.]+)$/)
    {
	$domainName = $1;
    }
    else
    {
	showInitial ($q, $fm->localise('DOMAIN_NAME_VALIDATION_ERROR',
                                       {domainName => $domainName}), 1);
	return;
    }
    # Force to lower case
    $domainName = lc($domainName);
    $q->param(-name=>'domainName', -value=>$domainName);

    my $domainDesc = $q->param ('domainDesc');
    if ($domainDesc =~ /^([\-\'\w][\-\'\w\s\.]*)$/)
    {
	$domainDesc = $1;
    }
    else
    {
	showInitial ($q, $fm->localise('DOMAIN_DESCRIPTION_VALIDATION_ERROR',
                     {domainDesc => $domainDesc}), 1);
	return;
    }

    my $domainContent = $q->param ('domainContent');
    if ($domainContent =~ /^(.*)$/)
    {
	$domainContent = $1;
    }
    else
    {
	$domainContent = "";
    }

    #------------------------------------------------------------
    # Looks good. Find out if this domain has been taken
    #------------------------------------------------------------

    if ($domainsdb->get($domainName))
    {
	showInitial ($q, $fm->localise('DOMAIN_IN_USE_ERROR',
		     {domainName => $domainName}), 1);
	return;
    }

    my $DomainName = $conf->get('DomainName')->value || '';
    if ($DomainName eq $domainName)
    {
        showInitial ($q, $fm->localise('SYSTEM_DOMAIN_ERROR',
                     {domainName => $domainName}), 1);
        return;
    }

    #------------------------------------------------------------
    # Domain is available! Update domains database and signal the
    # domain-create event.
    #------------------------------------------------------------

    $domainsdb->new_record($domainName,
	    {
		type => 'domain',
		Description => $domainDesc,
		Content => $domainContent,
	    });

    my $msg = system ("/sbin/e-smith/signal-event",
		    "domain-create", "$domainName") ?
			'ERROR_CREATING_DOMAIN' :
			'SUCCESSFULLY_CREATED' ;

    showInitial ($q, $fm->localise($msg, {domainName => $domainName}), 0);
    open STDOUT, ">/dev/null";
    system ("/etc/e-smith/events/actions/restart-httpd-full") == 0
	or die ("Error occurred while restarting httpd.\n");
}

#------------------------------------------------------------
# 
#------------------------------------------------------------

sub modifyDomain ($)
{
    my ($q) = @_;

    esmith::cgi::genHeaderNonCacheable ($q, \%conf,
        $fm->localise('MODIFY_TITLE'));

    print $q->startform (-method => 'POST',
		    -action => $q->url (-absolute => 1));

    my $domain = $q->param ('domain');

    if (my $d = $domainsdb->get($domain))
    {
	my $description = $d->prop('Description') || '';
	my $content = $d->prop('Content') || 'Primary';

	print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},

			 $q->Tr (esmith::cgi::genCell ($q,
			     $fm->localise('DOMAIN_NAME_LABEL')),
			         esmith::cgi::genCell ($q, $domain)),

		         esmith::cgi::genNameValueRow ($q,
			     $fm->localise('DESCRIPTION_LABEL'),
				     "domainDesc", $description),

			 $q->Tr (esmith::cgi::genCell ($q,
                         $fm->localise('CONTENT_LABEL')),
				 genContentMenu ($q, $content)),

		         esmith::cgi::genButtonRow ($q,
					$q->submit (-name => 'action',
					-value => $fm->localise('SAVE'))));

	print $q->hidden (-name => 'domainName',
			  -override => 1,
			  -default => $domain);

	print $q->hidden (-name => 'state',
			  -override => 1,
			  -default => 'performModify');
    }

    print $q->endform;
    esmith::cgi::genFooter($fm);
    return;
}

#------------------------------------------------------------
# 
#------------------------------------------------------------

sub performModifyDomain ($)
{
    my ($q) = @_;

    #------------------------------------------------------------
    # Validate parameters and untaint them
    #------------------------------------------------------------

    my $domainName = $q->param ('domainName');
    if ($domainName =~ /^([a-zA-Z0-9\-\.]+)$/)
    {
	$domainName = $1;
    }
    else
    {
	showInitial ($q, $fm->localise('DOMAIN_NAME_VALIDATION_ERROR',
                                       {domainName => $domainName}), 1);
	return;
    }

    my $domainDesc = $q->param ('domainDesc');
    if ($domainDesc =~ /^([\-\'\w][\-\'\w\s]*)$/)
    {
	$domainDesc = $1;
    }
    else
    {
	showInitial ($q, $fm->localise('DOMAIN_DESCRIPTION_VALIDATION_ERROR',
                     {domainName => $domainName, domainDesc => $domainDesc}), 1);
	return;
    }

    my $domainContent = $q->param ('domainContent');
    if ($domainContent =~ /^(.*)$/)
    {
	$domainContent = $1;
    }
    else
    {
	$domainContent = "";
    }

    #------------------------------------------------------------
    # Looks good. Make sure this is a valid domain
    #------------------------------------------------------------

    my $d = $domainsdb->get($domainName);
    unless ($d && ($d->prop('type') eq 'domain'))
    {
        showInitial ($q, $fm->localise('NONEXISTENT_DOMAIN_ERROR',
                     {domainName => $domainName}), 1);
        return;
    }

    #------------------------------------------------------------
    # Update domains database and signal the domain-modify event.
    #------------------------------------------------------------

    $d->merge_props(
	    Description => $domainDesc,
	    Content => $domainContent,
	);

    my $msg = system ("/sbin/e-smith/signal-event",
			"domain-modify", "$domainName") ?
			'ERROR_MODIFYING_DOMAIN' :
			'SUCCESSFULLY_MODIFIED';
    showInitial ($q, $fm->localise($msg, {domainName => $domainName}), 0);
    open STDOUT, ">/dev/null";
    system ("/etc/e-smith/events/actions/restart-httpd-full") == 0
	or die ("Error occurred while restarting httpd.\n");
}

#------------------------------------------------------------
# 
#------------------------------------------------------------

sub deleteDomain ($)
{
    my ($q) = @_;

    esmith::cgi::genHeaderNonCacheable ($q, \%conf,
		$fm->localise('REMOVE_TITLE'));

    print $q->startform (-method => 'POST',
		-action => $q->url (-absolute => 1));

    my $domain = $q->param ('domain');
    my $d = $domainsdb->get($domain);

    if ($d)
    {
	my $domainDesc = $d->prop('Description') || '';

	print $q->p($fm->localise('REMOVE_DESCRIPTION',
                    {domain => $domain, 
                    domainDesc => $domainDesc}));
	
	print $q->submit (-name => 'action',
		    -value => $fm->localise('REMOVE'));
	print $q->hidden (-name => 'domain',
		    -override => 1, -default => $domain);

	print $q->hidden (-name	    => 'state',
			  -override => 1,
			  -default  => 'performDelete');
    }

    print $q->endform;
    esmith::cgi::genFooter($fm);
    return;
}

#------------------------------------------------------------
# 
#------------------------------------------------------------

sub performDeleteDomain ($)
{
    my ($q) = @_;

    #------------------------------------------------------------
    # Attempt to delete domain
    #------------------------------------------------------------

    my $domain = $q->param ('domain');

    if ($domain =~ /^([a-zA-Z0-9\-\.]+)$/)
    {
	$domain = $1;
    }
    else
    {
	# FIXME - ERROR_WHILE_REMOVING_DOMAIN doesn't adequately describe
	# a data validation error
	showInitial ($q, $fm->localise('ERROR_WHILE_REMOVING_DOMAIN',
                     {domain => $domain}), 1);
	return;
    }

    my $d = $domainsdb->get($domain);
    unless ($d && ($d->prop('type') eq 'domain'))
    {
        showInitial ($q, $fm->localise('NONEXISTENT_DOMAIN_ERROR',
                     {domainName => $domain}), 1);
        return;
    }


    $d->merge_props(type => 'domain-deleted');

    my $msg = system ("/sbin/e-smith/signal-event", "domain-delete", "$domain")
	? 'ERROR_WHILE_REMOVING_DOMAIN' : 'SUCCESSFULLY_DELETED';
    $d->delete;

    showInitial ($q, $fm->localise($msg, {domain => $domain}), 0);
    open STDOUT, ">/dev/null";
    system ("/etc/e-smith/events/actions/restart-httpd-full") == 0
	or die ("Error occurred while restarting httpd.\n");
}


__DATA__
<form>
</form>
