#!/usr/bin/perl -wT

#----------------------------------------------------------------------
# e-smith manager functions: navigation
#
# 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.e-smith.com for details.
#----------------------------------------------------------------------
package esmith;

use strict;
use CGI ':no_xhtml', ':all';
use CGI::Carp qw(fatalsToBrowser);

use esmith::cgi;
use esmith::config;
use esmith::NavigationDB;
use esmith::util;
use esmith::I18N;

sub determineGroup;
sub showNavigation ($);

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

# Use the one script for navigation and noframes
my $NO_FRAMES = ($0 =~ /noframes/);

my %conf;
tie %conf, 'esmith::config';

my $q = new CGI;

showNavigation ($q);
exit (0);


#------------------------------------------------------
# subroutine to determine which group a user belongs to
#------------------------------------------------------

sub determineGroup
{
	my ($user) = shift;

	# Group file for authentication
	my $group_file = '/etc/group';
	open ( GF, $group_file )
	    or die "Cannot open group file: $group_file: $!\n";

	# list of groups this user belongs to
	my @groupList;
	while (<GF>) 
	{
		if (/[:,]$user\b/) 
		{
			my ($groupName, undef) = split(/:/);
			push @groupList, $groupName;
		}
	}
	close GF;	
	return @groupList;
}

#------------------------------------------------------------
# subroutine to display navigation bar
#------------------------------------------------------------

sub showNavigation ($)
{
    my $q = shift;
 
    # enable utf8 binmode so new translations work
    binmode STDOUT, ":utf8";

    # Use this variable throughout to keep track of files
    # list of just the files
    my $c = "1";
    my @files = ();
    my %files_hash = ();
    my @panel_group = $ENV{'REMOTE_USER'} eq "admin" ?
	("admin") : determineGroup($ENV{'REMOTE_USER'});
	
    #-----------------------------------------------------
    # Determine the directory where the functions are kept
    #----------------------------------------------------- 
	
    my $navigation_ignore = 
	"(\.\.?|navigation|noframes|online-manual|(internal|pleasewait)(-.*)?)";

    my $cgidir = 'nowhere';
    if ($panel_group[0] eq 'admin')
    {
	$cgidir = '/etc/e-smith/web/panels/manager/cgi-bin/';

	if (opendir (DIR, $cgidir))
	{
	    @files = grep (!/^${navigation_ignore}$/,
		readdir (DIR));
	    closedir (DIR);
	}
	else
	{
	    warn "Can't open directory $cgidir\n";
	}

	foreach my $file (@files)
	{
	    next if (-d "$cgidir/$file");
	    $files_hash{$file} = $cgidir;
	}
    }
    else
    {
	foreach	my $panel (@panel_group)
	{
	    $cgidir = "/etc/e-smith/web/panels/manager/$panel/cgi-bin";

	    if (opendir (DIR, $cgidir))
	    {
		@files = grep (!/^${navigation_ignore}$/,
		    readdir (DIR));
		closedir (DIR);
		foreach my $file (@files)
		{
		    next if (-d "$cgidir/$file");
		    $files_hash{$file} = $cgidir;
		}
	    }
	    else
	    {
		warn "Can't open directory $cgidir\n";
	    }
	}
    }

    #-------------------------------------------------- 
    # For each script, extract the description and category
    # information. Build up an associative array mapping headings
    # to heading structures. Each heading structure contains the
    # total weight for the heading, the number of times the heading
    # has been encountered, and another associative array mapping
    # descriptions to description structures. Each description
    # structure contains the filename of the particular cgi script
    # and a weight.
    #-------------------------------------------------- 
    my %nav = ();

    use constant NAVIGATIONDIR => '/home/e-smith/db/navigation';
    use constant WEBFUNCTIONS  => '/etc/e-smith/web/functions';

    my $i18n = new esmith::I18N;

    my $language = $i18n->preferredLanguage( $ENV{HTTP_ACCEPT_LANGUAGE} );

    my $navinfo = NAVIGATIONDIR . "/navigation.$language";

    my $navdb = esmith::NavigationDB->open_ro( $navinfo ) or
	die "Couldn't open $navinfo\n";

    # Check the navdb for anything with a UrlPath, which means that it doesn't
    # have a cgi file to be picked up by the above code. Ideally, only pages
    # that exist should be in the db, but that's not the case. Anything
    # without a cgi file will have to remove themselves on uninstall from the
    # navigation dbs.
    foreach my $rec ($navdb->get_all)
    {
	if ($rec->prop('UrlPath'))
	{
	    $files_hash{$rec->{key}} = $cgidir;
	}
    }

    foreach my $file (keys %files_hash)
    {
	my $heading = 'Unknown';
	my $description = $file;
	my $headingWeight = 99999;
	my $descriptionWeight = 99999;
	my $urlpath = '';

	my $rec = $navdb->get($file);

	if (defined $rec)
	{
	    $heading = $rec->prop('Heading');
	    $description = $rec->prop('Description');
	    $headingWeight = $rec->prop('HeadingWeight');
	    $descriptionWeight = $rec->prop('DescriptionWeight');
	    $urlpath = $rec->prop('UrlPath') || '';
	}

	#-------------------------------------------------- 
	# add heading, description and weight information to data structure
	#-------------------------------------------------- 

	unless (exists $nav {$heading})
	{
	    $nav {$heading} = { COUNT => 0, WEIGHT => 0, DESCRIPTIONS => [] };
	}

	$nav {$heading} {'COUNT'} ++;
	$nav {$heading} {'WEIGHT'} += $headingWeight;

	# Check for manager panel, and assign the appropriate
	#  cgi-bin prefix for the links.
	# Grab the last 2 directories by splitting for '/'s and
	#  then concatenating the last 2
	# probably a better way, but I don't know it.
	my @filename = split /\//, $files_hash{$file};
	my $path = ($cgidir eq '/etc/e-smith/web/panels/manager/cgi-bin/') ? 
	    "/$filename[scalar @filename - 1]" : 
	    "/$filename[scalar @filename - 2]/$filename[scalar @filename - 1]";
	
	push @{ $nav {$heading} {'DESCRIPTIONS'} },
		{ DESCRIPTION => $description,
		  WEIGHT => $descriptionWeight, 
		  FILENAME => $urlpath ? $urlpath : "$path/$file",
		  CGIPATH => $path
		};
    }

    #-------------------------------------------------- 
    # generate list of headings sorted by average weight
    #-------------------------------------------------- 
    if ( $NO_FRAMES )
    {
	esmith::cgi::genNoframesHeader ($q);
    }
    else
    {
        esmith::cgi::genNavigationHeader ($q, undef);
	print "\n<TABLE BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">\n";
    }

  print '<script language="JavaScript" type="text/javascript">
  <!-- Hide script
  //This swap the class of the selected item.
    function swapClass() {
    var i,x,tB,j=0,tA=new Array(),arg=swapClass.arguments;
    if(document.getElementsByTagName){for(i=4;i<arg.length;i++){tB=document.getElementsByTagName(arg[i]);
    for(x=0;x<tB.length;x++){tA[j]=tB[x];j++;}}for(i=0;i<tA.length;i++){
    if(tA[i].className){if(tA[i].id==arg[1]){if(arg[0]==1){
    tA[i].className=(tA[i].className==arg[3])?arg[2]:arg[3];}else{tA[i].className=arg[2];}
    }else if(arg[0]==1 && arg[1]==\'none\'){if(tA[i].className==arg[2] || tA[i].className==arg[3]){
    tA[i].className=(tA[i].className==arg[3])?arg[2]:arg[3];}
    }else if(tA[i].className==arg[2]){tA[i].className=arg[3];}}}}}
    ';
    print "
  //This swap the class of the selected item.
    function swapClasses() {
    var arg=swapClasses.arguments;
    swapClass(0,'none','item-current','item','a');
    swapClass(0,'none','warn-current','warn','a');
    swapClass(0,arg[0],'item-current','item','a');
    }

    // End script hiding -->
    </script>
    ";

    foreach my $h (sort {
	 ($nav{$a}{'WEIGHT'}/$nav{$a}{'COUNT'}) <=>
	($nav{$b}{'WEIGHT'}/$nav{$b}{'COUNT'}) } keys %nav)
    {
        if ( $NO_FRAMES )
	{
	    print $q->h2 ($h);
	}
	else
	{
	    print "\n", $q->Tr ($q->td({class => "section"},$q->span({class => "section"}, $h)));
	}

	#-------------------------------------------------- 
	# generate list of descriptions sorted by weight
	#-------------------------------------------------- 
        print "<ul>\n" if ( $NO_FRAMES );

	foreach (sort { $a->{'WEIGHT'} <=> $b->{'WEIGHT'} }  @{$nav {$h}{'DESCRIPTIONS'}})
	{
	    my $href = "/server-manager" .  $_->{'FILENAME'};
	    if ( $NO_FRAMES )
	    {
		print $q->li ($q->a ({href => "$href?noframes=1"}, $_->{'DESCRIPTION'}));
	    }
	    else
  	    {
		print "\n",$q->Tr(
			     $q->td ({-class => "menu-cell"},
				     $q->a ({-id => "sme$c",
                                            -class => "item",
                                            -onClick => "swapClasses('sme$c')",
                                            href => $href, 
                                            target => 'main'}, 
                                        $_->{'DESCRIPTION'})
				     ));
                        }
                        $c++;
                        
	}
        print "</ul>\n" if ($NO_FRAMES);
    }

    unless ( $NO_FRAMES )
    {
	print "\n</TABLE>\n";
        esmith::cgi::genNavigationFooter ($q);
    }
}
