#!/usr/bin/perl -wT #---------------------------------------------------------------------- # User manager functions: navigation # # copyright (C) 2011 Firewall Services # daniel@firewall-services.com # # 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 # #---------------------------------------------------------------------- package esmith; use strict; use CGI ':no_xhtml', ':all'; use CGI::Carp qw(fatalsToBrowser); use esmith::cgi; use esmith::config; use esmith::AccountsDB; use esmith::NavigationDB; use esmith::util; use esmith::I18N; 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 $accdb = esmith::AccountsDB->open_ro || die "Couldn't open AccountsDB\n"; my $q = new CGI; showNavigation ($q); exit (0); #------------------------------------------------------------ # subroutine to display navigation bar #------------------------------------------------------------ sub showNavigation ($) { my $q = shift; # enable utf8 binmode so new translations work binmode STDOUT, ":utf8"; my $acctName = $ENV{'REMOTE_USER'}; my $user = $accdb->get($acctName) || die "User $acctName not found in AccountsDB\n"; my $availablePanels = $user->prop('AdminPanels') || ''; foreach ($accdb->user_group_list($acctName)){ my $group = $accdb->get($_) || die "Group $_ not found in AccountsDB\n"; $availablePanels .= ',' . ($group->prop('AdminPanels') || ''); } my $glob = $accdb->get('globalUP'); my $globalPanels = $glob->prop('AdminPanels') || ''; my @adminpanels; if ( defined ($availablePanels) && defined ($globalPanels) ) { @adminpanels = ((split (/,/, $availablePanels, -1)),(split (/,/, $globalPanels, -1))); } elsif ( defined ($globalPanels) ) { @adminpanels = split (/,/, $globalPanels, -1); } elsif ( defined ($availablePanels) ) { @adminpanels = split (/,/, $availablePanels, -1); } # Use this variable throughout to keep track of files # list of just the files my $c = "1"; my @files = (); my %files_hash = (); #----------------------------------------------------- # Determine the directory where the functions are kept #----------------------------------------------------- my $navigation_ignore = "(\.\.?|navigation|noframes|online-manual|(internal|pleasewait)(-.*)?)"; my $cgidir = '/etc/e-smith/web/panels/user/cgi-bin/'; if (opendir (DIR, $cgidir)) { @files = grep (!/^(\..*|userpanel-navigation|userpanel-noframes|userpanel-initial|pleasewait)$/, readdir (DIR)); closedir (DIR); } else { warn "Can't open directory $cgidir\n"; } foreach my $file (@files) { foreach my $adminpanel (@adminpanels) { if ( $file eq $adminpanel ) { $files_hash{$file} = $cgidir; } } } #-------------------------------------------------- # 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/user/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\n"; } print ' "; 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 "\n" if ($NO_FRAMES); } unless ( $NO_FRAMES ) { print "\n
\n"; esmith::cgi::genNavigationFooter ($q); } }