#!/usr/bin/perl -w
# Smeadmin - panel cgi perl affichant les infos dans le server-manager
# Copyright (C) 2006
# This file is distributed under the GPL license.
# Landry Breuil <landry@firewall-services.com>, 2006.

# heading : Administration
# description : Smeadmin 
# navigation : 4000 4020 


#----------------------------------------------------------------
#inclusion des modules
use strict;
no strict 'refs';
use CGI':all';
use CGI::Carp qw(fatalsToBrowser);

use DBD::mysql;
use RRDs;

use esmith::cgi;
use esmith::ConfigDB;
use esmith::I18N;

use POSIX;
use Locale::gettext;

##raid status
use Getopt::Long;
#----------------------------------------------------------------
#declaration de variables globales

my ($DomainName,$SystemName,$SystemMode,$ExternalInterface,$InternalInterface,$ExternalIP,$InternalIP);
my $progname="smeadmin";

#handle de la db sme
my $smedb=esmith::ConfigDB->open;
my $smeadmindb = $smedb->get('smeadmind') || die "Error opening smeadmind db\n";
#handle de la bd mysql
my $bd;

my $rrddir="/var/lib/smeadmin";
my $imgdir="/etc/e-smith/web/panels/manager/html/smeadmin";
#my $maxping=0.1;
my $maxping=0.5;
my $SshPort;
#----------------------------------------------------------------
#declaration des fonctions
#webpages-funcs
sub showConf;
sub showAlertConf;
sub readConf;
sub changeOk;
sub accueil;
sub svcControl;
sub showAdvancedTest;
#details de services
sub showHttpd;
sub showSquid;
sub showSamba;
sub showAfp;
sub showFtp;
sub showPppoe;
sub showVpn;
sub showSsh;
sub showDhcpd;
sub showQpsmtpd;
sub showQmail;
#graph-pages-funcs
sub showHardGraph;
sub showNetGraph;
sub showSystmGraph;

#misc-funcs
sub ipnum2ipdot;
sub connectDB;
sub deconnectDB;
sub printPopupMenu;
sub showService;
sub showSvcGraph;
sub showDbData;
#----------------------------------------------------------------
#----------------------------------------------------------------
#debut pre-main
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'} = '/bin:/usr/bin:/sbin';
	$ENV {'SHELL'} = '/bin/bash';
	delete $ENV {'ENV'};
}

my $i18n = new esmith::I18N;
my $http_lang = $i18n->preferredLanguage( $ENV{HTTP_ACCEPT_LANGUAGE} );
if ($http_lang =~ /^([a-z]{2})$/) { $http_lang .= "_" .uc($1) }

$http_lang =~ s/([a-z]{2})-([a-z]{2})/"$1_".uc($2)/e;

$ENV{LC_MESSAGES} = "$http_lang";
unless(setlocale(LC_MESSAGES, "")){
	$http_lang = 'en_US';
	$ENV{LC_MESSAGES} = "$http_lang";
	setlocale(LC_MESSAGES, "");
}

bindtextdomain("smeadmin","/usr/share/locale");
textdomain("smeadmin");
bind_textdomain_codeset "smeadmin", 'utf-8';

#la locale est reglee => on peut balancer les gettext

#rapide hash de labels utilise dans les 3 pages de graphes
my %labels=("-1h"=>gettext("Graphs on one hour, average on 5mn."),
        "-6h"=>gettext("Graphs on six hours, average on 5mn."),
        "-1d"=>gettext("Graphs on one day, average on 5mn."),
        "-3d"=>gettext("Graphs on three days, average on 30mn."),
        "-7d"=>gettext("Graphs on one week, average on 30mn."),
        "-1m"=>gettext("Graphs on one month, average on 2h"),
        "-6months"=>gettext("Graphs on six months, average on 1d."),
        "-1y"=>gettext("Graphs on one year, average on 1d"));

#chaines de caracteres pour le tableau de bounds
my %strings=(
	'MaxMailIn'=>gettext("Maximum number of incoming e-mails "),
	'MaxMailOut'=>gettext("Maximum number of outgoing e-mails "),
	'MaxDiskSpace'=>gettext("Maximum % of hard disk usage "),
	'MaxCpu'=>gettext("Maximum % of cpu usage "),
	'MaxHwTemp'=>gettext("Maximum temperature for cpu and motherboard "),
	'MaxHdTemp'=>gettext("Maximum hard disk temperature "),
	'MaxSamba'=>gettext("Maximum number of samba sessions "),
	'MaxSsh'=>gettext("Maximum number of ssh sessions "),
	'MaxFtp'=>gettext("Maximum number of ftp sessions "),
	'MaxVpn'=>gettext("Maximum number of vpn sessions "));

#hash faisant correspondre la cle (nom du param) a sa valeur [ICI, CE SONT LES VALEURS PAR DEFAUT !!]
#idem dans le daemon /usr/bin/smeadmind
my %params=(
	'DbName'=>"smeadmin",
	'DbPassword'=>"pass",
	'DbUser'=>"smeadmin",
#	'if_internal'=>"eth0",
#	'if_external'=>"eth1",

   	'ImgFormat'=>"PNG",
	'ImgWidth'=>"500",
	'ImgHeight'=>"300",
   	# /sbin/e-smith/db domains keys pour voir les autres domaines du serveur
   	'OtherMailDomains'=>"",
   	'PingTarget'=>"www.google.fr",
   
   	'hd1'=>"hda",
   	'hd2'=>"",
        'hd3'=>"",
        'hd4'=>"",
        'hd5'=>"",
        'hd6'=>"",

   	'UseDu'=>"on",
   	'SensorsTag1'=>"temp1",
   	'SensorsTag2'=>"temp2",
   	'SensorsTagFan'=>"fan1",
        'SensorsTagFan2'=>"",

  
   	'LimitPppoeDisconnect'=>"1",
	'LimitPppoeDuration'=>"4",
	'LimitVpnDuration'=>"2",
	
   	'AlertMailRecipient'=>'admin',
	'StatusMailRecipient'=>'admin',
	'StatusInterval'=>"3",
                                        
   	'MaxMailIn'=>"1",
	'MaxMailOut'=>"1",
	'MaxDiskSpace'=>"60",
	'MaxCpu'=>"50",
	'MaxHwTemp'=>"40",
	'MaxHdTemp'=>"40",
	'MaxSamba'=>"1",
	'MaxSsh'=>"1",
	'MaxFtp'=>"1",
	'MaxVpn'=>"1");
#----------------------------------------------------------------
#----------------------------------------------------------------
	#debut MAIN
	#on envoie le cgi
   	esmith::util::setRealToEffective ();
   	my $q = new CGI;
	$q->charset('utf-8');
	
    #on lit les parametres dans la db
	readConf();

   	#on genere l'entete de la page
    $q->default_dtd('-//W3C//DTD XHTML 1.0 Transitional//EN');

   	print $q->header ('text/html');
    print $q->start_html (
   	    -TITLE => "$progname - $DomainName",
       	-AUTHOR => 'landry@firewall-services.com',
       	-CLASS => "main",
   	    -STYLE => {
       	    	-verbatim => '@import url("/server-common/css/sme_main.css");',
       		    -src => '/server-common/css/sme_core.css'});

   	print $q->h1 ("$progname : $DomainName");
	

    #examine le param 'state' pour savoir quelle page on demande

    #METTRE UN SWITCH ??? => NON, le switch PERL est LEEEEEEEENT *4
    # a voir : un hash de fonctions
    if (! grep (/^state$/, $q->param)) {accueil();}
    elsif ($q->param('state') eq 'conf') {showConf();}
    elsif ($q->param('state') eq 'conf_alert') {showAlertConf();}
    elsif ($q->param('state') eq 'validate') {changeOk();}
    elsif ($q->param('state') eq 'service_control') {svcControl();}
    elsif ($q->param('state') eq 'advanced') {showAdvancedTest();}
    elsif ($q->param('state') eq 'service_detail') {showService();}
    elsif ($q->param('state') eq 'hard') {showHardGraph();}
    elsif ($q->param('state') eq 'net')	{showNetGraph();}
    elsif ($q->param('state') eq 'systm') {showSystmGraph();}
    else { print $q->p("PrOTcH !! No page !!");}
	esmith::cgi::genFooter ($q);

	exit (0);

	#fin MAIN
#----------------------------------------------------------------
#----------------------------------------------------------------
# definition des fonctions
#----------------------------------------------------------------
sub accueil
{
    #affichage des liens vers les autres pages
    print $q->p(gettext("View graphs on :"),$q->ul(
        $q->li($q->a ({href => "$progname?state=hard"},gettext("server's hardware (sensors)\n"))),
        $q->li($q->a ({href => "$progname?state=net"},gettext("network use (connections,sessions,load)\n"))),
        $q->li($q->a ({href => "$progname?state=systm"},gettext("system performance (cpu, memory, hard disk)\n"))))),
        $q->p($q->a ({href => "$progname?state=advanced"},gettext("Advanced connection tests on services\n"))),
        $q->p($q->a ({href => "$progname?state=conf"},gettext("Configuration of smeadmin\n"))),
		$q->hr({width=>'80%'});
	
    #hack pour la mise en forme : a) debut 1er case a gauche
    print $q->start_table,$q->start_Tr,$q->start_td;
    
    #affichage du tableau des connexions reseau actives
    print $q->p(gettext("Active tcp connections tcp with external(blue)/local(green) connections highlighted :\n")),$q->br;
	print	$q->start_table({-border => '1'}),
			$q->Tr($q->th(gettext("Local IP:port")),$q->th(gettext("Remote IP:port")),$q->th(gettext("State")),$q->th(gettext("PID/Process")));
			
	foreach (`/bin/netstat --tcp --numeric-host --program `) 
	{
		 my($proto,undef,undef,$loc,$dist,$stat,$prog)=split(/\s+/,$_);
		 #mise en couleur de l'ip en fct ext/loc
         if ($proto eq 'tcp')
         {
		    print $q->Tr($q->td({bgcolor=>(($loc =~ /($InternalIP|127.0.0.1):/o)?"#32CD32":(($loc =~ /$ExternalIP:/o)?"#1E90FF":"#FFFFFF"))},$loc),$q->td($dist),$q->td($stat),$q->td($prog));
         }
	}
    print $q->end_table,$q->br;
    #hack pour la mise en forme : b) fin 1er case a gauche et debut 2e case
    print $q->end_td,$q->td({-width=>'20'}),$q->start_td({-valign=>'top'});
    
    #affichage du resultat de 'uptime'
    my $uptime=`/usr/bin/uptime`; 
    print $q->p(gettext("Stats :\n")),$q->p($uptime);

##Start to check linux raid status and display the content 
    my $Raidcheck = `/bin/cat /proc/mdstat`;
    if ( $Raidcheck =~ "raid")
{
    print $q->br;
    print $q->p(gettext("Status of Linux software RAID :")); 
    my $file = "/proc/mdstat";
    my $device = "all";

    # Get command line options.
    GetOptions ('file=s' => \$file,
    'device=s' => \$device,
    'help' => sub { &usage() } );

    ## Strip leading "/dev/" from --device in case it has been given
    $device =~ s/^\/dev\///;

    ## This is a global return value - set to the worst result we get overall
    my $retval = 0;

    my (%active_devs, %failed_devs, %spare_devs);

    open FILE, "< $file" or die "Can't open $file : $!";
    while (<FILE>) {
    next if ! /^(md\d+)+\s*:/;
    next if $device ne "all" and $device ne $1;
    my $dev = $1;

    my @array = split(/ /);
    for $_ (@array) {
        next if ! /(\w+)\[\d+\](\(.\))*/;
        if (defined $2 && $2 eq "(F)") {
            $failed_devs{$dev} .= "$1,";
        }
        elsif (defined $2 && $2 eq "(S)") {
            $spare_devs{$dev} .= "$1,";
        }
        else {
            $active_devs{$dev} .= "$1,";
        }
    }
    if (! defined($active_devs{$dev})) { $active_devs{$dev} = "none"; }
        else { $active_devs{$dev} =~ s/,$//; }
    if (! defined($spare_devs{$dev}))  { $spare_devs{$dev}  = "none"; }
        else { $spare_devs{$dev} =~ s/,$//; }
    if (! defined($failed_devs{$dev})) { $failed_devs{$dev} = "none"; }
        else { $failed_devs{$dev} =~ s/,$//; }
    
    $_ = <FILE>;
    /\[(\d+)\/(\d+)\]\s+\[(.*)\]$/;
    my $devs_total = $1;
    my $devs_up = $2;
    my $stat = $3;
    my $result = "OK";
    if ($devs_total > $devs_up or $failed_devs{$dev} ne "none") {
        $result = "CRITICAL";
    }

    my @raidstatus = "$result - $dev [$stat] has $devs_up of $devs_total devices active (active=$active_devs{$dev} failed=$failed_devs{$dev} spare=$spare_devs{$dev})\n";
    foreach my $raid (@raidstatus)
        {
        #if the raid is degraded (but not failed) on one drive then we get the orange colour, else green
              if ( $raid =~ ("CRITICAL" && "failed=none") ){
            print $q->table( $q->td($q->td({bgcolor=>(($raid =~ "CRITICAL")?"orange":"#32CD32")},$raid)));}

        #if the raid is degraded and failed on drive(s) then we get the red colour, else green
              elsif ( $raid =~ ("CRITICAL" && "_") ){
            print $q->table ($q->td($q->td({bgcolor=>(($raid =~ "CRITICAL")?"red":"#32CD32")},$raid)));}
        }
    
    }
}    


    #s'il ya des users connectes on affiche le resultat de la commande 'w'
    if (!($uptime =~ /0 user /))
    {
        print $q->br;
        print $q->p(gettext("Connected users :")),$q->start_table({-border => '1'}),
    		$q->Tr($q->th(gettext("Login")),$q->th(gettext("TTY")),$q->th(gettext("From")),$q->th(gettext("Since")),$q->th(gettext("Idle")),$q->th(gettext("Command")));
        #root     pts/3    pc-00010:S.0     17:09   58.00s  1.13s  1.05s vim smeadmin
        #root     pts/2    pc-00010.plop.gr 17:07    0.00s  0.19s  0.05s w -h
        foreach(`/usr/bin/w -h`)
        {
		    my($user,$tty,$src,$since,$idle,undef,undef,@cmd)=split(/\s+/,$_);
            print $q->Tr($q->td({bgcolor=>(($user eq "root")?"red":"white")},$user),
                $q->td({bgcolor=>(($tty =~ /tty/)?"orange":"white")},$tty),$q->td($src),$q->td($since),$q->td($idle),$q->td(@cmd));
        }
            
        print $q->end_table;
    }
    print $q->end_td,$q->end_Tr,$q->end_table;
    
    print $q->hr({width=>'80%'});
    
	
    #liste des services et classification					
 	my @services =	("#".gettext("Web services"),"httpd-e-smith","httpd-admin","httpd-bkpc","httpd-fpbx","httpd-pki","httpd-isoqlog","squid","php-fpm", "php55-php-fpm", "php56-php-fpm", "php70-php-fpm", "php71-php-fpm", "php72-php-fpm", "php73-php-fpm", "php74-php-fpm", "php80-php-fpm", "php81-php-fpm", "php82-php-fpm", "php83-php-fpm",
                    "#".gettext("Administrative services"), "sshd", "smeadmind",
                    "#".gettext("Network services"),"wan","dhcpd","pptpd","ippp","bridge","openvpn-s2s","openvpn-routed","openvpn-bridge","wireguard","ipsec","vpnserver",
                    "#".gettext("File-sharing services"),"smb","smbd","nmbd","ftp","nfs","madsonic", 
		    "#".gettext("E-mail services"),"dovecot","pop3","pop3s","imaps","imap","qmail","altqmail","qpsmtpd","sqpsmtpd","clamd","freshclam","spamassassin","mailman",#mail
                    "#".gettext("DNS services"),"tinydns","dnscache", "dnscache.forwarder", "DynDNS", #dns
                    "#".gettext("Authentication services"),"oidentd","ldap","smtp-auth-proxy","radiusd","cvm-unix", #auth
                    "#".gettext("Misc. services"),"mariadb","ntpd","lpd", "backuppc", "bandwidthd","unifi", #misc
                    "#".gettext("System services"),"crond","rsyslog","ulogd","acpid","raidmonitor","local", "yum"); #sys et materiel

    #hack pour la mise en forme : a) debut 1er case a gauche
    print $q->start_table,$q->start_Tr,$q->start_td;
    
	#affichage du tableau des services
	print $q->p(gettext("System services (Click on a service name for details) :\n")),$q->br,
			$q->start_table({-border => '1'});
			$q->Tr($q->th(gettext("Service")),$q->th(gettext("State")),$q->th(gettext("Nb process")),$q->th(gettext("Action")));

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

		  
	foreach my $svc (@services)
	{
        # si le service pppoe est disabled on n'affiche pas la ligne correspondante 
        next if ($svc eq 'pppoe' && $smedb->get('pppoe')->prop('status') eq 'disabled'); 
		my $cmd;
        my $details=0;
        #si c'est un 'header'
        if ($svc=~/^#(.*)/)
        {       
               print $q->Tr(),$q->Tr($q->th($1),$q->th(gettext("State")),$q->th(gettext("Action")),$q->th("DB Status"),$q->th("DB Action"));
        }
        else
        {
		#si c'est un service pour lequel on a des infos complementaires...
    		if($svc=~/^(httpd-e-smith|httpd-admin|smb|smbd|nmbd|squid|pptpd|dhcpd|sshd|ftp|pppoe|pppd|wan|altqmail|qmail|qpsmtpd|sqpsmtpd)$/) {$details=1;}
                if ($svc=~/^(imaps|imap|pop3|pop3s)$/) { $cmd = "/usr/bin/systemctl is-active dovecot"; }
                else {$cmd = "/usr/bin/systemctl is-active $svc";}
	    	my @res=`$cmd`;
		
		foreach (@res)
    		{
		    my $dbsv=$smedb->get("$svc") ||next;
    		    # workaround to see db config status
    		    my $dbstatus="not defined";
		    
    		    if ( length(`/sbin/e-smith/db configuration show $svc`) > 1 )
		    {$dbstatus=$smedb->get("$svc")->prop('status')||"disabled";} # trouver un moyen de verifier que le nom du service est bien trouvé dans liste
		    else
		    {$dbstatus="";}    

		    if ($svc=~/^(imaps|imap|pop3|pop3s)$/)
		    {
                                print $q->Tr(
					(($details==1)? $q->td($q->a({href=>"$progname?state=service_detail&service=$svc"},"$svc")) : $q->td("$svc")),
                                        $q->td(""),$q->td( "dovecot" ) ,
					$q->td("$dbstatus"),                                        
					$q->td( ( ("$dbstatus" ne "") ? (("$dbstatus" eq "enabled" )? $q->submit(-name=>"disabled_$svc",-value=>'disable'): $q->submit(-name=>"enabled_$svc",-value=>'enable')) : " ") )  
					);


		    }
            	    #si le service est arrete^:il ya down ou  il n'y a pas de () pour le pid et ca ne fini pas par ...
		    elsif(/^down:/ ||  /^([a-zA-Z0-9]*) [^(^)]*([^.]{3})$/ || /^failed/ || /^unknown/|| /^inactive/)
		    {
		    		#on fait une conditionnelle pour savoir si on met le nom du service en lien ou pas
	    			print $q->Tr((($details==1)? $q->td($q->a({href=>"$progname?state=service_detail&service=$svc"},"$svc")) : $q->td("$svc")),
		    			$q->td(gettext("Stopped")),$q->td( (("$dbstatus" eq "enabled" || "$dbstatus" eq ""  )? $q->submit(-name=>"start_$svc",-value=>'start'): "disabled") ) ,$q->td("$dbstatus"),
		    			$q->td( ( ("$dbstatus" ne "") ? (("$dbstatus" eq "enabled" )? $q->submit(-name=>"disabled_$svc",-value=>'disable'): $q->submit(-name=>"enabled_$svc",-value=>'enable')) : " ") )  );
		    }
		    elsif (/^run:(.*)\(pid ([\d\s]+)\)/ || /^([a-zA-Z0-9]*) \(pid ([\d\s]+)\).*\.\.\.$/ || /^active/ )
    		    {
	    			#$2=liste pids
		    		my @pids;
				@pids=split(/ /,$2) if defined $2;	
	    
		    		print $q->Tr(
					(($details==1)? $q->td($q->a({href=>"$progname?state=service_detail&service=$svc"},"$svc")) : $q->td("$svc")),
					$q->td(gettext("Started")),
					$q->td($q->submit(-name=>"stop_$svc",-value=>'stop')) ,$q->td("$dbstatus"),
					$q->td( ( ("$dbstatus" ne "") ? (("$dbstatus" eq "enabled" )? $q->submit(-name=>"disabled_$svc",-value=>'disable'): $q->submit(-name=>"enabled_$svc",-value=>'enable')) : " ") )  );
		     }
                }
	    }
	}

    #service_control est le parametre qui prend le nom du service a arreter/demarrer
	print $q->hidden(-name=>'state',-default=>'service_control',-override=>1),
		$q->end_table,
		$q->endform;
    
        
    #hack pour la mise en forme : b) fin 1er case a gauche et debut 2e case
    print $q->end_td,$q->td({-width=>'100'}),$q->start_td({-valign=>'top'});
    
    #affichage du tableau des connexions reseau en ecoute
    print $q->p(gettext("Listening tcp sockets, and corresponding process :\n")),$q->br;
	print	$q->start_table({-border => '1'}),
			$q->Tr($q->th(gettext("Local IP:port")),$q->th(gettext("PID/Process")));
			
	foreach (`/bin/netstat --tcp --numeric-host --program --listen`) 
	{
		 my($proto,undef,undef,$loc,undef,undef,$prog)=split(/\s+/,$_);
		 #mise en couleur de l'ip en fct ext/loc
         if ($proto eq 'tcp')
         {
		    print $q->Tr($q->td($loc),$q->td($prog));
         }
	}
	print $q->end_table;
    print $q->end_td,$q->end_Tr,$q->end_table;
    print $q->br,$q->hr({width=>'80%'});
	
    if (-e "/usr/sbin/clamd")
	{
		#affichage des infos sur l'antivirus
		my $sigs=0;
	
		foreach (`/usr/bin/tail -n 6 /var/log/freshclam/current`)
		{
			#ClamAV update process started at Thu Jul 29 18:36:00 2004
			if (/ClamAV update process started at (\w{3} \w{3}\s{1,2}\d{1,3} [0-9:]{8} \d{4})/) 
			{print $q->p(sprintf(gettext("Last update of ClamAV antivirus : %s.\n"),$1));}

            #LOL !! le guide  du routard galactique
			if (/DON'T PANIC/) 
			{print $q->p(gettext("Warning ! Your antivirus may not be up-to-date.\n"));}
#	main.cvd is up to date (version: 24, sigs: 21793, f-level: 2, builder: tomek)
#	daily.cvd is up to date (version: 428, sigs: 1177, f-level: 2, builder: acab)
#   Database updated (23150 signatures) from database
#    2005-12-01 21:46:29.777100500 ClamAV update process started at Thu Dec  1    21:46:29 2005
#    2005-12-01 21:46:29.981397500 WARNING: Your ClamAV installation is    OUTDATED!
#    2005-12-01 21:46:29.981407500 WARNING: Local version: 0.87 Recommended    version: 0.87.1
#    2005-12-01 21:46:29.981414500 DON'T PANIC! Read    http://www.clamav.net/faq.html
#    2005-12-01 21:46:29.981420500 main.cvd is up to date (version: 34, sigs: 39625, f-level: 5, builder: tkojm)
#    2005-12-01 21:46:29.981428500 daily.cvd is up to date (version: 1200, sigs: 1669, f-level: 6, builder: tomek)
    
			if (/sigs: (\d+)/) {$sigs+=$1;}
		}
		print $q->p(sprintf(gettext("The database contains %s virus signatures.\n"),$sigs));
	}
	
    #un peu de bug report ?
    # rem jpp waiting for full dormmagick translation. Landry do not support anymore this contrib, will have a direct link to bugzilla here
#	print $q->p(gettext("Some feature request, comment or bug report ? send an e-mail to "),$q->b($q->i(gettext("landry at firewall-services dot com\n"))));

	
}
#----------------------------------------------------------------
# lecture de la conf dans la smedb et dans le fichier de conf
sub readConf
{
	
    #lecture des parametres contenus dans la db de sme
    my $smedb=esmith::ConfigDB->open; 
    $DomainName = $smedb->get('DomainName')->value;
	$SystemName = $smedb->get('SystemName')->value;
	$SystemMode = $smedb->get("SystemMode")->value;
    
    #on n'a une external ip que si on est en server-passerelle
	if ($SystemMode =~ /servergateway/)
   	{
       	$ExternalIP = $smedb->get("ExternalIP")->value;
		$ExternalInterface = $smedb->get("ExternalInterface")->prop('Name');
   	}
	else{
		$ExternalIP = '';
		$ExternalInterface ='';
	}
	$InternalIP = $smedb->get("LocalIP")->value;

	foreach my $key (keys(%params)){
		$params{$key} = $smeadmindb->prop($key);
	}

	$SshPort = $smedb->get('sshd')->prop('TCPPort');
}

#----------------------------------------------------------------
#affiche le formulaire permettant de parametrer smeadmin

sub showConf 
{
	
	print $q->startform (-method => 'GET', -action => $q->url (-absolute => 1 )),
		$q->i($q->p(gettext("Configuration of status e-mails.\n"))),
		$q->p(gettext("If you set the frequency to 0, status e-mails are disabled. You can put only the username if the recipient is a local user.\n")),
		$q->start_table,
		esmith::cgi::genNameValueRow($q,gettext("Status e-mails recipient"),"StatusMailRecipient",$params{"StatusMailRecipient"}),
		esmith::cgi::genNameValueRow($q,gettext("Frequency of status e-mails (* 5min)"),"StatusInterval",$params{"StatusInterval"}),
	    	$q->end_table,
		$q->hr({width=>'50%'});
    
    #partie MySQL du formulaire
	print $q->i($q->p(gettext("Configuration of MySQL connection.\n"))),
            $q->p(gettext("You shall only modify these settings if you change the default values with phpMyAdmin or mysqladmin. These settings don't directly affect the configuration of MySQL.")),$q->br,
        	$q->start_table,
	    	esmith::cgi::genNameValueRow($q,gettext("Database"),'DbName',$params{'DbName'}),
        	esmith::cgi::genNameValueRow($q,gettext("MySQL user"),'DbUser',$params{'DbUser'}),
        	esmith::cgi::genNameValueRow($q,gettext("Password"),'DbPassword',$params{'DbPassword'}),
	    	$q->end_table,$q->hr({width=>'50%'});
    	
    #partie reseau du formulaire
	print $q->i($q->p(gettext("Configuration of network settings.\n"))), 
        	$q->p(gettext('You can specify the names of the network interfaces to monitor, the e-mail domains and adresses to count in the e-mail graph (list of domains or adresses separated by semicolons. "me@domain.fr ; other-domain.com ; virtual.domain.fr" - the primary domain name and virtual domains are already counted). You can already choose a target for the ping latency graph (www.google.fr, default gateway,...)')),$q->br,
        	$q->start_table;
        
    	print esmith::cgi::genNameValueRow($q,gettext("Other e-mail domains"),'OtherMailDomains',$params{'OtherMailDomains'}),
        	esmith::cgi::genNameValueRow($q,gettext("Ping target"),'PingTarget',$params{'PingTarget'}),
	    	$q->end_table,$q->hr({width=>'50%'});

    	#partie graphique/interface
	print $q->i($q->p(gettext("Web panel configuration.\n"))),
        	$q->p(gettext("You can set the format and size of graphs, and the bounds upon which pppoe and vpn connections need to be highlighted.\n")),$q->br,
        	$q->start_table,
            #vieux hack pour récuperer la css du NameValueRow
            #	esmith::cgi::genNameValueRow($q,gettext("Format d'image (PNG/GIF)"),'img_format',$params{'img_format'}),
           $q->Tr ($q->td ({-class => "sme-noborders-label"},gettext("Image Format:")),"\n",
                    $q->td($q->popup_menu(-name=>'ImgFormat', -values=>['PNG','GIF'], -default=>$params{'ImgFormat'}))),
        	esmith::cgi::genNameValueRow($q,gettext("Graphs width"),'ImgWidth',$params{'ImgWidth'}),
        	esmith::cgi::genNameValueRow($q,gettext("Graphs height"),'ImgHeight',$params{'ImgHeight'}),
        	esmith::cgi::genNameValueRow($q,gettext("Pppoe disconnection lasting more than (in minutes)"),'LimitPppoeDisconnect',$params{'LimitPppoeDisconnect'}),
        	esmith::cgi::genNameValueRow($q,gettext("Pppoe connection lasting less than (in hours)"),'LimitPppoeDuration',$params{'LimitPppoeDuration'}),
        	esmith::cgi::genNameValueRow($q,gettext("Vpn connection lasting more than (in hours)"),'LimitVpnDuration',$params{'LimitVpnDuration'}),
	    	$q->end_table,$q->hr({width=>'50%'});

	#partie senseurs materiels
	print $q->i($q->p(gettext("Configuration of hardware sensors.\n"))),
        	$q->p(gettext("For the hard disks, generally you have 'hda' or 'hdb' with IDE and 'sda' or 'sdb' with SATA/SCSI. If you have only on disk, let the second field blank. You can choose to activate the computing of the main directories' size of SME. (maybe long and resource-consuming on large disks). To find available sensors, execute 'sensors' in a shell, and look for the keywords corresponding to the working sensors ('temp1','CPU Temp','MB Temp','fan3',....). Let the fields blank if you have no sensors available.\n")),$q->br,
        	$q->start_table,
           	$q->Tr ($q->td ({-class => "sme-noborders-label"},gettext("Activate du -s:")),"\n",
                    $q->td($q->popup_menu(-name=>'UseDu', -values=>['on','off'], -default=>$params{'UseDu'}))),
	    	esmith::cgi::genNameValueRow($q,gettext("First hard disk"),'hd1',$params{'hd1'}),
        	esmith::cgi::genNameValueRow($q,gettext("Second hard disk"),'hd2',$params{'hd2'}),
                esmith::cgi::genNameValueRow($q,gettext("Third hard disk"),'hd3',$params{'hd3'}),
                esmith::cgi::genNameValueRow($q,gettext("Fourth hard disk"),'hd4',$params{'hd4'}),
                esmith::cgi::genNameValueRow($q,gettext("Fifth hard disk"),'hd5',$params{'hd5'}),
                esmith::cgi::genNameValueRow($q,gettext("Sixth hard disk"),'hd6',$params{'hd6'}),

        	esmith::cgi::genNameValueRow($q,gettext("First sensor (cpu)"),'SensorsTag1',$params{'SensorsTag1'}),
        	esmith::cgi::genNameValueRow($q,gettext("Second sensor (motherboard)"),'SensorsTag2',$params{'SensorsTag2'}),
        	esmith::cgi::genNameValueRow($q,gettext("Third sensor (fan)"),'SensorsTagFan',$params{'SensorsTagFan'}),
                esmith::cgi::genNameValueRow($q,gettext("Fourth sensor (fan)"),'SensorsTagFan2',$params{'SensorsTagFan2'}),

	    	$q->end_table,$q->hr({width=>'50%'});
        
    	#partie alertes
        
	print $q->i($q->p(gettext("Configuration of alerts.\n"))),
        	$q->p(gettext("You should notice that these values are not limits FOR the system, but just values beyond which an alert e-mail is sent. If you set the limit to 0, the alert is disabled. You can put only the username if the recipient is a local user.\n")),$q->br;

   	print $q->start_table,
		esmith::cgi::genNameValueRow($q,gettext("Alert e-mails recipient "),"AlertMailRecipient",$params{"AlertMailRecipient"});
	
    	#affichage du tableau des strings/limites parametree
	foreach my $key (keys(%strings))
	{
		print esmith::cgi::genNameValueRow($q,$strings{$key},$key,$params{$key});
   	}
	
	print $q->end_table,
		$q->hr({width=>'50%'}),
		esmith::cgi::genButtonRow($q,$q->submit(-name=>'action',-value=>gettext("Save"))),
		$q->hidden(-name=>'state',-default=>'validate',-override=>1),
		$q->endform;
}

#----------------------------------------------------------------
#little patch : on montre juste la limite pour UNE alerte (cible du lien contenu dans le mail d'alerte)
# cette fonction affiche juste un petit formulaire pour modifier la limite
sub showAlertConf
{
    my $key=$q->param('alert');
	print $q->startform (-method => 'GET', -action => $q->url (-absolute => 1 )),
        $q->i($q->p(gettext("Alert configuration.\n"))),$q->p(gettext("Put 0 to desactivate it.\n")),$q->br,
   	    $q->start_table,
		esmith::cgi::genNameValueRow($q,$strings{$key},$key,$params{$key}),
	    $q->end_table,$q->br,
		esmith::cgi::genButtonRow($q,$q->submit(-name=>'action',-value=>gettext("Save"))),
		$q->hidden(-name=>'state',-default=>'validate',-override=>1),
		$q->hidden(-name=>'alert',-default=>"$key",-override=>1),
		$q->endform;
}
#----------------------------------------------------------------
#verifie et sauve les nouveaux parametres
sub changeOk
{
    # faire juste une verification des valeurs, et afficher le formulaire vert changements appliques (meme si rien n'est modifie)
    # eventuellement un message si les mails de status viennent d'etre desactives
    # sinon, ne rien appliquer, donner la raison de l'erreur et afficher le formulaire rouge
	#Verification des parametres
	my $modified=0;
	my $verifok=1;
    my $str;
    #il y a deux cas : 
    # - on verifie TOUTE la conf (on vient de changer plusieurs params)
    # - on verifie UN parametre (on vient de changer une limite numerique)
    # cas 1 :)
    if (!defined $q->param ('alert'))
    {
       	# on regarde si un parametre a ete modifie
    	foreach my $key (keys(%params))
	    {		
			#print $key.": ".$q->param("$key")."<br>";
		    $modified=1 if ($params{$key} ne $q->param("$key"));
    	}

        # ces 2 verifs ont ete "assouplies" pour permettre de ne mettre qu'un username local au serveur sans mettre tout l'adresse mail complete
    	#verification validite e-mail alertes
	    if (! ($q->param('AlertMailRecipient') =~ /^[\w.-]+(@[\dA-Za-z-.]+)?$/) )
    	{
	    	$verifok=0;
    	    $str=sprintf(gettext("\"%s\" is not a valid e-mail address.\n"),$q->param("AlertMailRecipient"));  
        	print esmith::cgi::genTextRow($q,$q->p($str));
	    }
	
    	#verification validite e-mail status
	    if (! ($q->param('StatusMailRecipient') =~ /^[\w.-]+(@[\dA-Za-z-.]+)?$/) )
    	{
	    	$verifok=0;
    	    $str=sprintf(gettext("\"%s\" is not a valid e-mail address.\n"),$q->param("StatusMailRecipient"));  
        	print esmith::cgi::genTextRow($q,$q->p($str));
	    }

       	#verification valeurs numeriques
	    foreach my $key ( 'ImgWidth', 'ImgHeight', 'LimitPppoeDisconnect', 'LimitPppoeDuration', 'LimitVpnDuration',
		    'StatusInterval', 'MaxMailIn', 'MaxMailOut', 'MaxDiskSpace', 'MaxCpu', 'MaxHdTemp', 
    		'MaxHwTemp', 'MaxSamba', 'MaxSsh', 'MaxFtp', 'MaxVpn')
	    {
		    if (!($q->param("$key")=~/\d+/))
    		{
	    		$verifok=0;
	        	$str=sprintf(gettext("\"%s\" is not an integer numeric value for the setting '%s'.\n"),$q->param("$key"),$key);  
	    	    print esmith::cgi::genTextRow($q,$q->p($str));
    		}
	    }
	
    	# si on vient de desactiver les mails de status, on affiche un message
	    if ($params{'StatusInterval'} != 0 && $q->param('StatusInterval') == 0)
    	{
	    	print esmith::cgi::genTextRow($q,$q->p(gettext("Status e-mails have been disabled.\n")));
       	}
	if ($modified){
		foreach my $key (keys(%params))
                {
                        $smeadmindb->set_prop($key,$q->param($key));
                }
	}
    }
    else
    #cas 2 :)
    {
        my $key=$q->param('alert');
        $modified=1 if ($params{$key} ne $q->param("$key"));
	    if (!($q->param("$key")=~/\d+/))
   		{
    		$verifok=0;
        	$str=sprintf(gettext("\"%s\" is not an integer numeric value for the setting '%s'.\n"),$q->param("$key"),$key);  
    	    print esmith::cgi::genTextRow($q,$q->p($str));
   		}
        else
        {
            #on applique la nouvelle valeur
            $params{$q->param('alert')}=$q->param("$key");
        }
	$smeadmindb->set_prop($key,$q->param($key)) if ($modified); 
    }
    
	if ($verifok)
	{    
		if ($modified)
	    {	
	    
	        #si un param a ete change, on notifie le demon avec un -SIGHUP
           # `pkill -SIGHUP smeadmind`;
           #notify the deamon is not enough we want to restart it when parameters are changed
           system ('service smeadmind restart  2>&1 1>/dev/null') == 0 or die 'ERROR: the service smeadmind can not be restarted';

            print $q->table({-class =>"sme-borders"},
                $q->Tr(
                $q->td( '<img src="/server-common/tickmark.jpg" ALT="SUCCESS" >'),
                $q->td( $q->div( {-class=>"success"}, gettext("New settings have been saved."))))) ;
		}
        else
        {
            print esmith::cgi::genTextRow($q,$q->p(gettext("The settings are the same, nothing has been modified.\n")));
        }
    }
	else
	{
        print $q->table({-class =>"sme-borders"},
            $q->Tr(
            $q->td( '<img src="/server-common/checkmark.jpg" ALT="ERROR" >'),
            $q->td( $q->div( {-class=>"error"}, gettext("An error occured. Check the settings you provided."))))) ;
	}

	print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}


#----------------------------------------------------------------
#arret/demarrage du service (bourrin, oui, j'utilise pas serviceControl)
sub svcControl
{
	#pour tous les champs du formulaire qu'on a recu (normalement , juste 'state', et un 'start_$service' ou 'stop_$service' 
	foreach ($q->param())
	{
		#si le nom du parametre est (start|stop)_$svc
		if(/^(stop|start)_([\w-]+)$/) 
		{
			#$_ est le nom du champ
			#$1 est l'action
			#$2 est le nom du service==doit etre egal a la valeur
			#si la valeur correspond a l'action
			if ($q->param("$_") eq "$1")
			{
				
				my $cmd='';
				$cmd=`/usr/bin/systemctl $1 $2`;
				my @res=$cmd;    
				foreach (@res)
            			{ print $q->p("$_\n");}
			}
			else 
			#on a affaire a un petit malin qui bricole les parametres
			{
				print $q->p("Parametre incorrect1\n");
		  	}
		}
		#si le nom du parametre est (enable|disable)_$svc
		if(/^(enabled|disabled)_([\w-]+)$/) 
		{
			#$_ est le nom du champ
			#$1 est l'action
			#$2 est le nom du service==doit etre egal a la valeur
			#si la valeur correspond a l'action
			if ($q->param("$_")."d" eq "$1")
			{
				my @res=`/sbin/e-smith/db configuration setprop $2 status $1`;
				push(@res,`/sbin/e-smith/db configuration printprop $2 status`);
				# we should restart the service here because it should be stop if disabled !!! 
				my $ordre="";
				if ( $1 eq "enabled")
				    {$ordre="start";}
				if ( $1 eq "disabled")
				    {$ordre="stop";}
				
				my $cmd='';
				if ($2=~/^(ulogd|smbd|nmbd|rsyslog)$/)#(-d "/service/$2")
				{$cmd = `/usr/bin/sv $ordre $2`;}
				else 
				    {$cmd=`/sbin/e-smith/service $2 $ordre`;}
				push(@res,$cmd);
				    
				    
				foreach (@res)
            			{ print $q->p("$_\n");}
			}
			else 
			#on a affaire a un petit malin qui bricole les parametres
			{
				print $q->p("Parametre incorrect2\n");
		  	}
		}
		
		
		
		
		
	}
	print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}


#----------------------------------------------------------------
#Tests de connexion aux services de SME
sub showAdvancedTest
{
	#affichage de la liste des tests si le param 'service' n'est pas défini.
	if (!defined($q->param('service')))
	{
		print $q->p(gettext("These differents tests may produce false positives, do not take care of them.")),
			$q->p(gettext("Execute them only if you know what they do, and how to analyse their results.")),$q->br,
			$q->start_table,
			$q->Tr($q->td(gettext("Test http service")),
			$q->td($q->a ({href => "$progname?state=advanced&service=http"},"http@\n"))),
			$q->Tr($q->td(gettext("Test samba service")),
			$q->td($q->a ({href => "$progname?state=advanced&service=samba"},"smbcontrol\n"))),
			$q->Tr($q->td(gettext("Test network latency")),
			$q->td($q->a ({href => "$progname?state=advanced&service=ping"},"ping\n"))),
			$q->Tr($q->td(gettext("Test ftp service")),
			$q->td($q->a ({href => "$progname?state=advanced&service=ftp"},"telnet 21\n"))),
			$q->Tr($q->td(gettext("Test ssh service")),
			$q->td($q->a ({href => "$progname?state=advanced&service=ssh"},"telnet ${SshPort}\n"))),
			$q->Tr($q->td(gettext("Test pop service")),
			$q->td($q->a ({href => "$progname?state=advanced&service=pop"},"telnet 110\n"))),
			$q->Tr($q->td(gettext("Test smtp service")),
			$q->td($q->a ({href => "$progname?state=advanced&service=smtp"},"telnet 25\n"))),
			$q->end_table;
		
	    print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
    }
	#on fait le test avance
	else 
	{
        #hack this to handle the server-only case
	    my $record;
        $record = $smedb->get("SystemMode");
    	#on n'a une external ip que si on est en server-passerelle
    	if ($record->value =~ /servergateway/)
   	    {
       	    $record = $smedb->get("ExternalIP");
   	    }
	    else
        {
            $record = $smedb->get("LocalIP");
        }
        my $ip =$record->value;

        #test du service http => http@
		if ($q->param('service') eq 'http')
		{
		 	print $q->p($q->b(gettext("Execution of 'http\@' (should return html source code of server's homepage):"))),$q->br;
			foreach (`/usr/local/bin/http@ 2>&1`)
			{			
				print escapeHTML($_),$q->br;
			}
		}
        #test du service samba => smbcontrol smbd ping
		elsif ($q->param('service') eq 'samba')
		{
			print $q->p($q->b(gettext("Execution of 'smbcontrol smbd ping' (samba server answers giving its PID):"))),$q->br;
			foreach (`/usr/bin/smbcontrol smbd ping 2>&1`)
			{
				 print $q->p($_);
			}
		}
        #test du service http => http@
		elsif ($q->param('service') eq 'ping')
		{
			print $q->p($q->b(gettext("Execution of 'ping google.fr -c 1' (latency):"))),$q->br;
			foreach (`/bin/ping google.fr -c 1 2>&1`)
			{
				 print $q->p($_);
			}
		}
		elsif ($q->param('service') eq 'ftp')
		{
			print $q->p($q->b(sprintf(gettext("Execution of 'echo \"SYST\" | nc %s 21' (ftp opened to the external network):"),$ip))),$q->br;
			foreach (`/bin/echo "SYST" | /usr/bin/nc $ip 21 2>&1`)
			{
				 print $q->p($_);
			}
		}
		elsif ($q->param('service') eq 'ssh')
		{
			print $q->p($q->b(sprintf(gettext("Execution of 'echo \"hello\" | nc %s %s' (ssh opened to the external network):"),$ip,$SshPort))),$q->br;
			foreach (`/bin/echo "hello" | /usr/bin/nc $ip $SshPort 2>&1`)
			{
				 print $q->p($_);
			}
		}
		elsif ($q->param('service') eq 'pop')
		{
			print $q->p($q->b(sprintf(gettext("Execution of 'echo \"quit\" | nc %s 110' (pop server running):"),$ip))),$q->br;
			foreach (`/bin/echo "quit" | /usr/bin/nc $ip 110 2>&1`)
			{
				 print $q->p($_);
			}
		}
		elsif ($q->param('service') eq 'smtp')
		{
			print $q->p($q->b(sprintf(gettext("Execution of 'echo \"quit\" | nc -i 2 %s 25' (smtp server running):"),$ip))),$q->br;
			foreach (`/bin/echo "quit" | /usr/bin/nc -i 2 $ip 25 2>&1`)
			{
				 print $q->p($_);
			}
		}
		print $q->p($q->a ({href => "$progname?state=advanced"},gettext("Another test\n")));
		print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
	}
}


#----------------------------------------------------------------
#DBI:mysql, connecte MOI
sub connectBD
{
    $bd=DBI->connect ("DBI:mysql:$params{'DbName'}","$params{'DbUser'}","$params{'DbPassword'}");
    if (!defined ($bd)) 
    {
        print $q->p("MySQL error : $DBI::errstr");
        die (gettext("Check MySQL connection settings.\n"));
    }
}

#----------------------------------------------------------------
#DBI:mysql, deconnecte MOI
sub deconnectBD
{
	$bd->disconnect;
    if (!defined ($bd)) 
    {
        print $q->p("MySQL error : $DBI::errstr");
        die (gettext("Check MySQL connection settings.\n"));
    }
}

#----------------------------------------------------------------
# fonction prenant une ip numerique et renvoyant une ip format a.b.c.d
# rapide hack peut-etre efficace... 
# (en fait j'ai trouve mieux dans esmith::util::IPaddrToQuad, je repompe le
# code pour pas avoir a loader tout esmith::util)
sub ipnum2ipdot
{
    my ($addrBits) = @_;
    return sprintf( "%d.%d.%d.%d",
                    ( $addrBits >> 24 ) & 0xff,
                    ( $addrBits >> 16 ) & 0xff,
                    ( $addrBits >> 8 ) & 0xff,
                    $addrBits & 0xff );
}
#----------------------------------------------------------------
# affiche un menu deroulant pour le choix de la duree des graphes
sub printPopupMenu
{
	my ($msg)=(@_);
	my %labels=("-1h"=>gettext("one hour"),
        "-6h"=>gettext("six hours"),
        "-1d"=>gettext("the day"),
        "-3d"=>gettext("three days"),
        "-7d"=>gettext("one week"),
        "-1m"=>gettext("one month"),
        "-6months"=>gettext("six months"),
        "-1y"=>gettext("one year"));
    
    print $q->start_form,
        $msg,
        $q->popup_menu(-name=>'duree', -values=>['-1h','-6h','-1d','-3d','-7d','-1m','-6months','-1y'], -default=>'-1d', -labels=>\%labels),
        $q->submit('action',"Go !"),
		$q->hidden(-name=>'state',-default=>$q->param('state'),-override=>1),
		$q->hidden(-name=>'service',-default=>$q->param('service'),-override=>1),
        $q->end_form,"\n";
}

#----------------------------------------------------------------
#cette fonction cree et affiche le graphe supervisant $svc
# $svc = {httpd, squid, samba, afp}
sub showSvcGraph
{
	my ($svc,$msg)=(@_);
 	my $start='-1d';	
    printPopupMenu($msg);                                                                                                    
    $start=$q->param('duree') if defined($q->param('duree'));
	
    #creation du graphe
	createShowGraph("","$svc$start",
		"--title=Service $svc",
		"--start=$start",
		"DEF:cpu=$rrddir/$svc.rrd:cpu:AVERAGE","DEF:maxcpu=$rrddir/$svc.rrd:cpu:MAX",
		"DEF:mem=$rrddir/$svc.rrd:mem:AVERAGE","DEF:maxmem=$rrddir/$svc.rrd:mem:MAX",
		"DEF:nbproc=$rrddir/$svc.rrd:nbproc:AVERAGE","DEF:maxnbproc=$rrddir/$svc.rrd:nbproc:MAX",
		"COMMENT:    ",    	"AREA:mem#1144BB:\%Mem",	"LINE2:cpu#FFDD00:\%Cpu",	"LINE2:nbproc#CC1100:Nb Proc",	"COMMENT:\\n",
		"COMMENT:Max\\:", 	"GPRINT:maxmem:MAX:%2.2lf %%",	"GPRINT:maxcpu:MAX:%2.2lf %%",	"GPRINT:maxnbproc:MAX:%2lg"  );
		
	print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}



#----------------------------------------------------------------
#cette fonction est juste un "aiguillage" vers la fonction qui affiche le service demande
# on passe par ici en cliquant sur les liens correspondant aux noms des services
sub showService
{
	#les 4 premiers sont les services qui ont des rrds
	#les 7 derniers sont ceux qui ont des donnees dans mysql
	if ($q->param('service') eq 'httpd-e-smith' || $q->param('service') eq 'httpd-admin') {showHttpd();}
	elsif ($q->param('service') eq 'squid') {showSquid();}
	elsif ($q->param('service') eq 'smbd' || $q->param('service') eq 'smb' || $q->param('service') eq 'nmbd') {showSamba();}
	elsif ($q->param('service') eq 'atalkd') {showAfp();}
	elsif ($q->param('service') eq 'pptpd') {showVpn();}
	elsif ($q->param('service') eq 'dhcpd') {showDhcpd();}
	elsif ($q->param('service') eq 'sshd') {showSsh();}
	elsif ($q->param('service') eq 'proftpd') {showFtp();}
	elsif ($q->param('service') eq 'ftp') {showFtp();}	
	elsif ($q->param('service') eq 'pppoe' || $q->param('service') eq 'wan' || $q->param('service') eq 'pppd' ) {showPppoe();}
	elsif ($q->param('service') eq 'qpsmtpd' || $q->param('service') eq 'sqpsmtpd' ) {showQpsmtpd();}
	elsif ($q->param('service') eq 'qmail') {showQmail();}
        elsif ($q->param('service') eq 'altqmail') {showQmail();}
}

#----------------------------------------------------------------
#details du service httpd
sub showHttpd
{
	showSvcGraph("httpd",gettext("System load for the apache web server (httpd-e-smith & httpd-admin processes) on "));
}
#----------------------------------------------------------------
#details du service qmail
sub showQmail
{
    my $start='-1d';
    printPopupMenu(gettext("View graphs on "));
    $start=$q->param('duree') if defined($q->param('duree'));
    print $q->p($q->b($labels{"$start"}));
    print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
    #qmail local and remote email
    createGraphQmail($start);
    createGraphAltQmail($start);
}
#----------------------------------------------------------------
#details du service s?qpsmtpd
sub showQpsmtpd
{
    my $start='-1d';
    printPopupMenu(gettext("View graphs on "));
    $start=$q->param('duree') if defined($q->param('duree'));
    print $q->p($q->b($labels{"$start"}));
    print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
    #qpsmtpd incoming emails from outside the server( local network and internet)
    createGraphQpsmtpd($start);

}
#----------------------------------------------------------------
#details du service squid
sub showSquid
{
	showSvcGraph("squid",gettext("System load for the transparent http/ftp proxy squid on "));
}
#----------------------------------------------------------------
#details du service samba
sub showSamba
{
    #voir plus bas pour explication des params
    showDbData( [ 
                    [gettext("IP Address"),sub { return ipnum2ipdot(@_); } ],
                    [gettext("Login"),],
                    [gettext("Hostname"),], 
                    [gettext("Start"),],
                    [gettext("End"),]
                ],
	    \"SELECT ip,login,machine,debut,derniere_vue FROM samba ORDER BY debut DESC",
	    \gettext("Detailed list of the last times a host has connected to a samba share.\n"));
        
    #affichage du graphe
	showSvcGraph("samba",gettext("System load for the samba server (smbd & nmbd processes) on "));
}

#----------------------------------------------------------------
#details du service appletalk
sub showAfp
{
    #voir plus bas pour explication des params
    showDbData( [ 
                    [gettext("Start"),],
                    [gettext("End"),],
                    [gettext("IP Address"),sub { return ipnum2ipdot(@_); } ],
                    [gettext("Login"),],
                    [gettext("Written data (Ko)"),],
                    [gettext("Read data (Ko)"),] 
                ],
        \"SELECT debut,fin,ip,login,volume_read,volume_write FROM afp WHERE debut > CURDATE() - INTERVAL 7 DAY ORDER BY debut DESC",
        \gettext("Detailed list of the last connections (on the last 7 days) to the afp service (Apple File Protocol).\n"));
    #affichage du graphe
	showSvcGraph("afp",gettext("System load for the appletalk server (atalkd, papd, afpd and cnid_metad processes)."));
}

#----------------------------------------------------------------
#details du service pptpd vpn
sub showVpn
{
    showDbData( [
                    [gettext("Start"),],
                    [gettext("End"),],
                    [gettext("Duration"),],
                    [gettext("Client IP address"),sub { return ipnum2ipdot(@_); } ],
                    [gettext("Client local IP address"),sub { return ipnum2ipdot(@_); } ],
                    [gettext("Incoming data (Ko)"),sub {return sprintf('%.2f',$_[0]/1024);}],
                    [gettext("Outgoing data (ko)"),sub {return sprintf('%.2f',$_[0]/1024);}],
                    [gettext("Login"),]
                ],
	    \"SELECT debut,fin,duree,ip,vpn_clt,volume_in,volume_out,login FROM vpn ORDER BY debut DESC",
	    \gettext("Detailed list of vpn connections (Virtual Private Network).\n"));
}
#----------------------------------------------------------------
#details du service dhcpd
sub showDhcpd
{
	showDbData( [
                    [gettext("IP Address"),sub { return ipnum2ipdot(@_); } ],
                    [gettext("MAC Address"),],
                    [gettext("Hostname"),], 
                    [gettext("Date of renewal"),]
                ],
        \"SELECT ip,mac,hostname,debut FROM dhcpd ORDER BY debut DESC",
        \gettext("List of the last dhcp leases renewal (Dynamic Host Control Protocol).\n"));
}
#----------------------------------------------------------------
#details du service pppoe
sub showPppoe
{
# get first db entry
my $requete="SELECT substr(debut,1,4), substr(debut,6,2)  FROM pppoe  WHERE debut >= CURDATE() - INTERVAL 24 MONTH ORDER BY debut ASC LIMIT 1";

    #connexion a la base de donnees mySQL
        connectBD();
        #recuperation des donnees
        my $rq=$bd->prepare($requete) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete,$bd->errstr));
        $rq->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq->errstr));
        
	my @debut = $rq->fetchrow_array();
# get first db entry
my $requete_DESC="SELECT substr(fin,1,4), substr(fin,6,2)  FROM pppoe WHERE debut >= CURDATE() - INTERVAL 24 MONTH ORDER BY debut DESC LIMIT 1";

    #connexion a la base de donnees mySQL
        connectBD();
        #recuperation des donnees
        my $rq_DESC=$bd->prepare($requete_DESC) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete_DESC,$bd->errstr));
        $rq_DESC->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq_DESC->errstr));

        my @fin = $rq_DESC->fetchrow_array();
	#$debut[1] -- if ($debut[1] == $fin[1]);
 
	my $end_yymm = $debut[0].$debut[1];
	my $yymm = $fin[0].$fin[1];
	my $startMonth  = $debut[1];
	my $startYear = $debut[0];
	my $endMonth; 
	my $endYear;
	my $preMonth;
	my $preYear; 
	my $i=0;

print $q->p(gettext("Traffic by Month"));
    print                    $q->start_table({-border=>'1'}),
                       $q->start_Tr;
        print $q->th(gettext("year-month"));
        print $q->th(gettext("IN (GB)"));
        print $q->th(gettext("OUT (GB)"));
        print $q->th(gettext("TOTAL (GB)"));
         $q->end_Tr;
    my $nblines = 0;
    while ($end_yymm < $yymm ||  $nblines < 1) {
    $nblines =1;
    if ($startMonth eq '12') {
        $endMonth = 1;
        $endYear = $startYear + 1;
    } else {
      $endMonth = $startMonth + 1;
      $endYear = $startYear;
    }
    ## Now that you have the end year and month incremented setup the end_yymm variable again to be picked up in the while statement:
    $end_yymm = $startYear . ${\(length($startMonth) == 1 ? '0' : '')} . $startMonth;

	if ($startMonth eq '1') {
		$preMonth=12;
		$preYear=$startYear-1;
	}
	else {
		$preMonth=$startMonth-1;
		$preYear= $startYear;
	}
     # ...... carry on with the rest of your code
#    print "**$end_yymm<br>\n";

	 $requete="SELECT substring(`fin`,1,7) as 'month', 
round(SUM(`volume_in`)/1000/1000/1000,3) as 'In (Go)' , 
round(SUM(`volume_out`) /1000/1000/1000,3)  as 'Out (Go)' , 
round(SUM(`volume_in` + `volume_out`)/1000/1000/1000,3) as 'Total (Go)' , 
SUM(TIME_TO_SEC(`duree`))/3600/24 as 'duree'
FROM `pppoe` WHERE
# mois
(`debut`> '$startYear-$startMonth-01 00:00:00' and `fin`< '$endYear-$endMonth-01 00:00:00')
# bordure
or ( `debut`> '$preYear-$preMonth-01 00:00:00' and `debut`< '$startYear-$startMonth-01 00:00:00' and `fin`> '$startYear-$startMonth-01 00:00:00')
or ( `debut`< '$endYear-$endMonth-01 00:00:00' and `fin`> '$endYear-$endMonth-01 00:00:00' and `fin`< '$endYear-$endMonth-28 00:00:00')";

        my $rq=$bd->prepare($requete) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete,$bd->errstr));
        $rq->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq->errstr));
	
my @ligne = $rq->fetchrow_array();
print                        $q->start_Tr;
 print $q->td("$startYear-". ${\(length($startMonth) == 1 ? '0' : '')} ."$startMonth");
 print $q->td($ligne[1]);
 print $q->td($ligne[2]);
 print $q->td($ligne[3]);
 print $q->end_Tr;

	# get ready for next loop
    if ($startMonth eq '12') {
       $startMonth = 1;
       $startYear++;
    } else {
       $startMonth++
    }

    } # end the while loop	
print $q->end_table;

deconnectBD();


    showDbData( [
                    [gettext("Start"),],
                    [gettext("End"),],
                    [gettext("Duration"),],
                    [gettext("IP Address"),sub { return ipnum2ipdot(@_); } ],
                    [gettext("Connection peer"),sub { return ipnum2ipdot(@_); } ],
                    [gettext("Incoming data (MB)"),sub {return sprintf('%.2f',$_[0]/1000/1000);}],
                    [gettext("Outgoing data (MB)"),sub {return sprintf('%.2f',$_[0]/1000/1000);}]
                ],
	    \"SELECT debut,fin,duree,ip,peer,volume_in,volume_out,fin-debut as 'encours' FROM pppoe WHERE debut >= CURDATE() - INTERVAL 24 MONTH ORDER BY debut DESC",
        \gettext("Detailed list of ADSL/PPPoE connections.\n"));
}
#----------------------------------------------------------------
#details du service ssh
sub showSsh
{
    showDbData( [
                    [gettext("Start"),],
                    [gettext("IP Address"),sub {return ipnum2ipdot(@_);}],
                    [gettext("Login"),],
                    [gettext("Connected ?"),sub {return (($_[0])?gettext('Yes'):gettext('No'));}]
                ],
        #pour cause de sprintf, la requete est dans le showDbData
    	\"",
	    \gettext("Detailed list of ssh connections (Secure SHell).\n"));
}

#----------------------------------------------------------------
#details du service ftp
sub showFtp
{
    #WARN ! Highly complicated !!
    # @tab est un tableau a 2 dimensions, chaque "ligne" du tableau contient 2 champs :
    # - le label/entete de la colonne a afficher
    # - une fonction inline de modification de l'affichage de la valeur allant dans la colonne
    # ( pour ce champ, il peut etre nul (d'ou le ["Start",]).
    my @tab=([gettext("Start"),],
            [gettext("End"),],
            [gettext("Duration"),],
            [gettext("IP Address"),sub {return ipnum2ipdot(@_);}],
            [gettext("Login"),],
            [gettext("Connected ?"),sub {return (($_[0])?gettext('Yes'):gettext('No'));}],
            [gettext("Written data (Ko)"),sub {return sprintf('%.2f',$_[0]/1024);}],
            [gettext("Read data (Ko)"),sub {return sprintf('%.2f',$_[0]/1024);}]);

    #appel de la fonction qui va interroger la bdd et afficher le tableau
    #passage des params par REFERENCE (tab, requete et titre a afficher)
    showDbData(\@tab,
        \"SELECT debut,fin,duree,ip,login,connecte,volume_in,volume_out FROM ftp WHERE debut > CURDATE() - INTERVAL 7 DAY ORDER BY debut DESC",
        \gettext("Detailed list of the last connections (on the last 7 days) to the ftp service (File Transfer Protocol).\n"));
}


#----------------------------------------------------------------
#DOCUMENT IT OR YOU'LL BE MAD - Magnifique HACK qui est trop elegant
#Fonction qui fait la requete vers la BDD, et affiche le resultat en fonction
#du @tab passe en param qui contient les entetes de colonne et les fonctions de
#modif d'affichage.
sub showDbData
{
    #recuperation des params et DEREFERENCEMENT
    my ($ref_tab,$ref_requete,$ref_title)=(@_);
    my @tab=@$ref_tab;
    my $requete=$$ref_requete;
    my $title=$$ref_title;
    
    my $i=0;
    #utilise uniquement si service=pppoe
    my $start_next_cnx;
    #utilise uniquement si service=sshd
    my $interval;
    
    if ($q->param('service') eq 'sshd')
    {
        #gruika hack pour avoir le tableau sur plusieurs periodes
        printPopupMenu(gettext("See the records on "));
        $interval=$q->param('duree');
        #somebody please put a SWITCH CASE !!
        if ((!defined($interval)) || $interval eq '-7d') {$interval="7 DAY";}
        elsif ($interval eq '-1h') {$interval="1 HOUR";}
        elsif ($interval eq '-6h') {$interval="6 HOUR";}
        elsif ($interval eq '-1d') {$interval="1 DAY";}
        elsif ($interval eq '-3d') {$interval="3 DAY";}
        elsif ($interval eq '-1m') {$interval="1 MONTH";}
        elsif ($interval eq '-6months') {$interval="6 MONTH";}
        elsif ($interval eq '-1y') {$interval="1 YEAR";}
        $requete="SELECT debut,ip,login,ok FROM ssh WHERE debut > NOW() - INTERVAL $interval ORDER BY debut DESC";
    }
    #connexion a la base de donnees mySQL
	connectBD();
	#recuperation des donnees
	my $rq=$bd->prepare($requete) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete,$bd->errstr));
	$rq->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq->errstr));

    #affichage du debut de page
	print $q->p(gettext($title));

    #affichage des eventuelles mises en evidence
    if ($q->param('service') eq 'pptpd')
    {
        print $q->table($q->Tr($q->td(gettext("Connections which lasted ")),
			$q->td({bgcolor=>"#FF4444"},sprintf(gettext("more than %s hours are highlighted.\n"),$params{'LimitVpnDuration'}))));
    }
    elsif ($q->param('service') eq 'wan'|| $q->param('service') eq 'pppoe' )
    {
        print $q->table($q->Tr($q->td(gettext("Connections which lasted ")),
			$q->td({bgcolor=>"#FF4444"},sprintf(gettext("less than %s hours are highlighted.\n"),$params{'LimitPppoeDuration'})))),
            $q->table($q->Tr($q->td(gettext("Disconnections which lasted ")),
			$q->td({bgcolor=>"#9999FF"},sprintf(gettext("more than %s minutes are highlighted.\n"),$params{'LimitPppoeDisconnect'}))));
    }
    elsif ($q->param('service') eq 'sshd') 
    {
        print $q->table($q->Tr($q->td(gettext("Successful ")),$q->td({bgcolor=>"#33CC00"},gettext(" root connections are highlighted.\n"))));
    }
    
    print   $q->br,
			$q->start_table({-border=>'1'}),
			$q->start_Tr;
    #affichage des entetes du tableau
    foreach (@tab)
    {
        #j'aimerai bien comprendre le pourquoi du comment du 1er [0]
        #le $i est pour recup la "ligne" du tab passe en param
        #le 2e [0] est pour recup le label, 1ere valeur de la ligne
        print $q->th(gettext($_[0][$i][0]));
        $i++;
    }
	print $q->end_Tr;

    #boucle sur les lignes / resultats de la requete SQL
	while(my @ligne = $rq->fetchrow_array())
	{
        $i=0;
        #affichage des lignes speciales (pour pptpd,ssh et pppoe only)
       
        if ($q->param('service') eq 'pptpd')
        {
		    $ligne[2]=~/(\d{2}):\d{2}:\d{2}/;
		    #si le nb d'heure > limite, surbrillance
		    print $q->start_Tr({bgcolor=>(($1 >= $params{'LimitVpnDuration'})?"#FF4444":"#FFFFFF")});
        }
        elsif ($q->param('service') eq 'wan' || $q->param('service') eq 'pppoe')
        {
		    #on interroge la bd pour voir si il y a eu une longue deconnexion
    		#(beaucoup plus simple que de parser les 2 dates et faire une difference, la on utilise la possibilite de calcul de diff de dates de MySQL)
	    	$requete="select '$start_next_cnx' > '$ligne[1]' + interval $params{'LimitPppoeDisconnect'} minute";
	        my $rq2=$bd->prepare($requete) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete,$bd->errstr));
        	$rq2->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq->errstr));
		    #on sauve le debut de la cnx pour faire la comparaison au debut de boucle
    		$start_next_cnx=$ligne[0];
		
            #si on a trouve que la connexion suivante avait commence apres la fin de connexion precedente + interval defini
            #alors afficher une ligne de separation
		    print $q->Tr($q->td({bgcolor=>"#9999FF",colspan=>"7"},sprintf(gettext("Disconnection lasted more than %s minutes"),$params{'LimitPppoeDisconnect'}))) if (($rq2->fetchrow_array)[0] eq '1');
		
		    #on match le nb d'heure de la duree cnx
		my $curdur;
    		if  ($ligne[2]) {
                      # ended connection 
                      $ligne[2]=~/(\d{2}):\d{2}:\d{2}/;
                      $curdur=$1;
                }else{
                      # ongoing connection
                      $curdur=$ligne[7]/3600;
                }
	    	#si le nb d'heure < limite et different de null, surbrillance
		    print $q->start_Tr({bgcolor=>((($curdur < $params{'LimitPppoeDuration'}) && ($1 ne ''))?"#FF4444":"#FFFFFF")});
        }
        elsif ($q->param('service') eq 'sshd')
        {
		    #si login root && connecte, surbrillance
    	    print $q->start_Tr({bgcolor=>(($ligne[2] eq 'root')&& $ligne[3])?"#33CC00":"#FFFFFF"});
        }
        else
        {
		    print $q->start_Tr;
        }
        #boucle sur les champs de la ligne
        foreach (@tab)
        {
            #on recupere la fonction de mise en forme de la valeur
            my $func=$_[0][$i][1];
            #si elle existe
            if (defined ($func))
            #on l'applique a la valeur (contenue dans $ligne[$i])
            { print $q->td(&$func($ligne[$i]));}
            else
            #sinon, on affiche directement la valeur
            { print $q->td($ligne[$i]);}
            $i++;
        }
        print $q->end_Tr;
	}			
	print $q->end_table,
			$q->p($q->a ({href => "$progname"},gettext("Back\n")));
	deconnectBD();
}

#----------------------------------------------------------------
#fonction faisant les appels a RRDs::graph
#creation de l'image, affichage d'un titre, affichage de l'image
sub createShowGraph
{
    my($title,$imgFilename,@rrdparams)=(@_);
    # print "<br>" . join("|", @rrdparams) . "<br>";
    my (undef,$xsize,$ysize)=RRDs::graph ("$imgdir/$imgFilename.$params{'ImgFormat'}",
        "--imgformat=$params{'ImgFormat'}",
        "--width=$params{'ImgWidth'}",
        "--height=$params{'ImgHeight'}",
        @rrdparams);

    my $error=RRDs::error;
    print $q->p(sprintf(gettext("Error at RRDs::graph(%s) : %s\n"),"$imgFilename.$params{'ImgFormat'}",$error)) if $error;

    print $q->p($title),$q->br,
        $q->img({src=>"../smeadmin/$imgFilename.$params{'ImgFormat'}",alt=>"../smeadmin/$imgFilename.$params{'ImgFormat'}",width=>$xsize,height=>$ysize});
}
                                       
        
#----------------------------------------------------------------
#affiche les graphes avec les sensors materiels
# - temp process, mb & hdd1/2
# - vitesse rotation ventilateur
#----------------------------------------------------------------
sub showHardGraph
{
 	my $start='-1d';	
    printPopupMenu(gettext("View graphs on "));
    $start=$q->param('duree') if defined($q->param('duree'));
  
	print $q->p($q->b($labels{"$start"}));
    
    print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
    
	my @tab=("--title=".gettext("Temperatures"),
		"--vertical-label=T°C",
		"--start=$start",
		"DEF:t1=$rrddir/sensors.rrd:t1:AVERAGE",    "DEF:maxt1=$rrddir/sensors.rrd:t1:MAX", "DEF:mint1=$rrddir/sensors.rrd:t1:MIN",
		"DEF:t2=$rrddir/sensors.rrd:t2:AVERAGE",    "DEF:maxt2=$rrddir/sensors.rrd:t2:MAX",	"DEF:mint2=$rrddir/sensors.rrd:t2:MIN",
                "COMMENT:    ",     "LINE2:t1#1000FF:Temp 1 ",      "LINE2:t2#00EEBB:Temp 2 ",
                "COMMENT:\\n", "COMMENT:Max\\: ",    "GPRINT:maxt1:MAX:%5.2lf °C",	"GPRINT:maxt2:MAX:%5.2lf °C  ",
                "COMMENT:\\n", "COMMENT:Min\\: ",	"GPRINT:mint1:MIN:%5.2lf °C",	"GPRINT:mint2:MIN:%5.2lf °C  ",
                "COMMENT:\\n", "COMMENT:Avg\\: ",	"GPRINT:t1:AVERAGE:%5.2lf °C",	"GPRINT:t2:AVERAGE:%5.2lf °C  ",
                "COMMENT:\\n", "COMMENT:Last\\:",	"GPRINT:t1:LAST:%5.2lf °C",	    "GPRINT:t2:LAST:%5.2lf °C  ",
                "COMMENT:\\n");
    
    #creation du graphe des temperatures
         createShowGraph(gettext("Hardware temperatures (Processor, motherboard)."),"temperature",@tab);

    #start to retrieve data for the hard disks sensors

   my $has_second_hd=1;
   $has_second_hd=0 if ($params{'hd2'} eq '');
   my $has_third_hd=1;
   $has_third_hd=0 if ($params{'hd3'} eq '');
   my $has_fourth_hd=1;
   $has_fourth_hd=0 if ($params{'hd4'} eq '');
   my $has_fifth_hd=1;
   $has_fifth_hd=0 if ($params{'hd5'} eq '');
   my $has_sixth_hd=1;
   $has_sixth_hd=0 if ($params{'hd6'} eq '');


        my @HDtab=("--title=".gettext("Hard-disks Temperatures"),
                "--vertical-label=T°C",
                "--start=$start",
                "DEF:thd1=$rrddir/sensors.rrd:thd1:AVERAGE",    "DEF:maxthd1=$rrddir/sensors.rrd:thd1:MAX",     "DEF:minthd1=$rrddir/sensors.rrd:thd1:MIN");
    push @HDtab, "DEF:thd2=$rrddir/sensors.rrd:thd2:AVERAGE",     "DEF:maxthd2=$rrddir/sensors.rrd:thd2:MAX",     "DEF:minthd2=$rrddir/sensors.rrd:thd2:MIN" if ($has_second_hd);
    push @HDtab, "DEF:thd3=$rrddir/sensors.rrd:thd3:AVERAGE",     "DEF:maxthd3=$rrddir/sensors.rrd:thd3:MAX",     "DEF:minthd3=$rrddir/sensors.rrd:thd3:MIN" if ($has_third_hd);
    push @HDtab, "DEF:thd4=$rrddir/sensors.rrd:thd4:AVERAGE",     "DEF:maxthd4=$rrddir/sensors.rrd:thd4:MAX",     "DEF:minthd4=$rrddir/sensors.rrd:thd4:MIN" if ($has_fourth_hd);
    push @HDtab, "DEF:thd5=$rrddir/sensors.rrd:thd5:AVERAGE",     "DEF:maxthd5=$rrddir/sensors.rrd:thd5:MAX",     "DEF:minthd5=$rrddir/sensors.rrd:thd5:MIN" if ($has_fifth_hd);
    push @HDtab, "DEF:thd6=$rrddir/sensors.rrd:thd6:AVERAGE",     "DEF:maxthd6=$rrddir/sensors.rrd:thd6:MAX",     "DEF:minthd6=$rrddir/sensors.rrd:thd6:MIN" if ($has_sixth_hd);
    push @HDtab, "COMMENT:    ",  "LINE2:thd1#CC5500:Temp hd 1";
    push @HDtab, "LINE2:thd2#550000:Temp hd 2" if ($has_second_hd);
    push @HDtab, "LINE2:thd3#1000FF:Temp hd 3" if ($has_third_hd);
    push @HDtab, "LINE2:thd4#00EEBB:Temp hd 4" if ($has_fourth_hd);
    push @HDtab, "LINE2:thd5#FF2222:Temp hd 5" if ($has_fifth_hd);
    push @HDtab, "LINE2:thd6#FFD700:Temp hd 6" if ($has_sixth_hd);
    push @HDtab, "COMMENT:\\n", "COMMENT:Max\\:",    "GPRINT:maxthd1:MAX:%5.2lf °C     ";
    push @HDtab, "GPRINT:maxthd2:MAX:%5.2lf °C      " if ($has_second_hd);
    push @HDtab, "GPRINT:maxthd3:MAX:%5.2lf °C      " if ($has_third_hd);
    push @HDtab, "GPRINT:maxthd4:MAX:%5.2lf °C      " if ($has_fourth_hd);
    push @HDtab, "GPRINT:maxthd5:MAX:%5.2lf °C      " if ($has_fifth_hd);
    push @HDtab, "GPRINT:maxthd6:MAX:%5.2lf °C" if ($has_sixth_hd);
    push @HDtab, "COMMENT:\\n", "COMMENT:Min\\: ",    "GPRINT:minthd1:MIN:%5.2lf °C     ";
    push @HDtab, "GPRINT:minthd2:MIN:%5.2lf °C      " if ($has_second_hd);
    push @HDtab, "GPRINT:minthd3:MIN:%5.2lf °C      " if ($has_third_hd);
    push @HDtab, "GPRINT:minthd4:MIN:%5.2lf °C      " if ($has_fourth_hd);
    push @HDtab, "GPRINT:minthd5:MIN:%5.2lf °C      " if ($has_fifth_hd);
    push @HDtab, "GPRINT:minthd6:MIN:%5.2lf °C" if ($has_sixth_hd);
    push @HDtab, "COMMENT:\\n", "COMMENT:Avg\\: ",    "GPRINT:thd1:AVERAGE:%5.2lf °C    ";
    push @HDtab, "GPRINT:thd2:AVERAGE:%5.2lf °C      " if ($has_second_hd);
    push @HDtab, "GPRINT:thd3:AVERAGE:%5.2lf °C      " if ($has_third_hd);
    push @HDtab, "GPRINT:thd4:AVERAGE:%5.2lf °C      " if ($has_fourth_hd);
    push @HDtab, "GPRINT:thd5:AVERAGE:%5.2lf °C      " if ($has_fifth_hd);
    push @HDtab, "GPRINT:thd6:AVERAGE:%5.2lf °C" if ($has_sixth_hd);
    push @HDtab, "COMMENT:\\n", "COMMENT:Last\\:",   "GPRINT:thd1:LAST:%5.2lf °C     ";
    push @HDtab, "GPRINT:thd2:LAST:%5.2lf °C      " if ($has_second_hd);
    push @HDtab, "GPRINT:thd3:LAST:%5.2lf °C      " if ($has_third_hd);
    push @HDtab, "GPRINT:thd4:LAST:%5.2lf °C      " if ($has_fourth_hd);
    push @HDtab, "GPRINT:thd5:LAST:%5.2lf °C      " if ($has_fifth_hd);
    push @HDtab, "GPRINT:thd6:LAST:%5.2lf °C" if ($has_sixth_hd);
    push @HDtab, "COMMENT:\\n";
 
    #creation du graphe des temperatures
         createShowGraph(gettext("Hard disks temperatures."),"HD temperature",@HDtab);

    #start to retrieve data for the Fan speed

 my $has_second_fan=1;
    $has_second_fan=0 if ($params{'SensorsTagFan2'} eq '');


 my @tabfan=("--title=".gettext("Fan speed"),
                "--vertical-label=".gettext("Rpm"),
                "--start=$start",
                "DEF:fspd=$rrddir/sensors.rrd:fspd:AVERAGE","DEF:maxfspd=$rrddir/sensors.rrd:fspd:MAX","DEF:minfspd=$rrddir/sensors.rrd:fspd:MIN");
   push @tabfan, "DEF:fspd2=$rrddir/sensors.rrd:fspd2:AVERAGE",     "DEF:maxfspd2=$rrddir/sensors.rrd:fspd2:MAX",     "DEF:minfspd2=$rrddir/sensors.rrd:fspd2:MIN" if ($has_second_fan);
   push @tabfan, "COMMENT:    ",     "LINE2:fspd#1000FF:".gettext("Fan speed") . "     ";
   push @tabfan, "LINE2:fspd2#550000:".gettext("Fan speed"),  "COMMENT:\\n" if ($has_second_fan);
   push @tabfan, "COMMENT:\\n", "COMMENT:Max\\: ",    "GPRINT:maxfspd:MAX:%5.0lf ".gettext("Rpm"). "                   ";
   push @tabfan, "GPRINT:maxfspd2:MAX:%5.0lf ".gettext("Rpm") if ($has_second_fan);
   push @tabfan, "COMMENT:\\n", "COMMENT:Min\\:  ",      "GPRINT:minfspd:MIN:%5.0lf ".gettext("Rpm"). "                   ";
   push @tabfan, "GPRINT:minfspd2:MIN:%5.0lf ".gettext("Rpm") if ($has_second_fan);
   push @tabfan, "COMMENT:\\n", "COMMENT:Avg\\: ",      "GPRINT:fspd:AVERAGE:%5.0lf ".gettext("Rpm"). "                   ";
   push @tabfan,  "GPRINT:fspd2:AVERAGE:%5.0lf ".gettext("Rpm") if ($has_second_fan);
   push @tabfan, "COMMENT:\\n", "COMMENT:Last\\: ",      "GPRINT:fspd:LAST:%5.0lf ".gettext("Rpm"). "                   ";
   push @tabfan, "GPRINT:fspd2:LAST:%5.0lf ".gettext("Rpm") if ($has_second_fan);
   push @tabfan, "COMMENT:\\n";
   
    #creation of the fan speed sensors
        createShowGraph(gettext("Processor fan speed."),"fanspeed",@tabfan);

   
    print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}
#----------------------------------------------------------------
#affiche les graphes reseau
# - sessions
# - volume brut transfert / reseau local / externe / route
# - baux dhcp
# - volume mail/spam/virus
# - latency
#----------------------------------------------------------------
sub showNetGraph
{
 	my $start='-1d';	
    printPopupMenu(gettext("View graphs on "));
    $start=$q->param('duree') if defined($q->param('duree'));
	print $q->p($q->b($labels{$start}));

    print $q->p($q->a ({href => "$progname"},gettext("Back\n")));

	#sessions par netstat
	createShowGraph(gettext("Number of opened tcp connections for ssh, ftp, vpn, afp and netbios protocols."),"sessions",
		"--title=".gettext("Opened connections"),
		"--start=$start",
		"DEF:ssh=$rrddir/sessions.rrd:ssh:AVERAGE",	"DEF:maxssh=$rrddir/sessions.rrd:ssh:MAX",	"DEF:minssh=$rrddir/sessions.rrd:ssh:MIN",		
        "DEF:vpn=$rrddir/sessions.rrd:vpn:AVERAGE",	"DEF:maxvpn=$rrddir/sessions.rrd:vpn:MAX",	"DEF:minvpn=$rrddir/sessions.rrd:vpn:MIN",
		"DEF:ftp=$rrddir/sessions.rrd:ftp:AVERAGE",	"DEF:maxftp=$rrddir/sessions.rrd:ftp:MAX",	"DEF:minftp=$rrddir/sessions.rrd:ftp:MIN",
		"DEF:netbios=$rrddir/sessions.rrd:netbios:AVERAGE",	"DEF:maxnetbios=$rrddir/sessions.rrd:netbios:MAX",	"DEF:minnetbios=$rrddir/sessions.rrd:netbios:MIN",
		"DEF:afp=$rrddir/sessions.rrd:afp:AVERAGE",	"DEF:maxafp=$rrddir/sessions.rrd:afp:MAX",	"DEF:minafp=$rrddir/sessions.rrd:afp:MIN",
		"COMMENT:      ","LINE2:ssh#0000FF:ssh ($SshPort)","LINE2:ftp#FF2222:ftp (21)","LINE2:vpn#AA3300:vpn (1723)",
        "LINE2:netbios#33B010:netbios (139)","LINE2:afp#FFD700:afp (548)","COMMENT:\\n",
		"COMMENT:Max\\: ","GPRINT:maxssh:MAX:%4.0lf      ","GPRINT:maxftp:MAX:%4.0lf       ","GPRINT:maxvpn:MAX:%4.0lf        ",
		"GPRINT:maxnetbios:MAX:%4.0lf           ","GPRINT:maxafp:MAX:%4.0lf ","COMMENT:\\n",
		"COMMENT:Min\\: ","GPRINT:minssh:MIN:%4.0lf      ","GPRINT:minftp:MIN:%4.0lf       ","GPRINT:minvpn:MIN:%4.0lf        ",
		"GPRINT:minnetbios:MIN:%4.0lf           ","GPRINT:minafp:MIN:%4.0lf ","COMMENT:\\n",
		"COMMENT:Last\\:","GPRINT:ssh:LAST:%4.0lf      ","GPRINT:ftp:LAST:%4.0lf       ","GPRINT:vpn:LAST:%4.0lf        ",
		"GPRINT:netbios:LAST:%4.0lf           ","GPRINT:afp:LAST:%4.0lf ","COMMENT:\\n");

	#baux dhcp, smbstatus:S
    createShowGraph(gettext("Number of dhcp leases renewals and opened samba shares."),"dhcpsmb",
		"--title=".gettext("Dhcp & Smbstatus"),
		"--start=$start",
		"DEF:samba=$rrddir/net.rrd:samba:AVERAGE",  "DEF:maxsamba=$rrddir/net.rrd:samba:MAX",	"DEF:minsamba=$rrddir/net.rrd:samba:MIN",
		"DEF:dhcp=$rrddir/net.rrd:dhcp:AVERAGE",	"DEF:maxdhcp=$rrddir/net.rrd:dhcp:MAX",		"DEF:mindhcp=$rrddir/net.rrd:dhcp:MIN",
		"COMMENT:      ","LINE2:dhcp#8B4513:Dhcp","LINE2:samba#DAA520:Samba","COMMENT:\\n",
		"COMMENT:Max\\: ","GPRINT:maxdhcp:MAX:%4.0lf    ","GPRINT:maxsamba:MAX:%4.0lf","COMMENT:\\n",
		"COMMENT:Min\\: ","GPRINT:mindhcp:MIN:%4.0lf    ","GPRINT:minsamba:MIN:%4.0lf","COMMENT:\\n",
		"COMMENT:Last\\:","GPRINT:dhcp:LAST:%4.0lf    ","GPRINT:samba:LAST:%4.0lf","COMMENT:\\n");
    
        #qmail local and remote email
     createGraphQmail($start);
	#qpsmtpd incoming emails from outside the server( local network and internet)
     createGraphQpsmtpd($start);

	#ping latency	
    createShowGraph(gettext("Average and maximal ping with the selected target."),"latency",
		"--title=".gettext("Target ping latency"),
		"--vertical-label=s/%",
		"--start=$start",
		"DEF:avglatency=$rrddir/net.rrd:avglatency:AVERAGE","DEF:maxavglatency=$rrddir/net.rrd:avglatency:MAX","DEF:minavglatency=$rrddir/net.rrd:avglatency:MIN",
		"DEF:maxlatency=$rrddir/net.rrd:maxlatency:AVERAGE","DEF:maxmaxlatency=$rrddir/net.rrd:maxlatency:MAX","DEF:minmaxlatency=$rrddir/net.rrd:maxlatency:MIN",
		"DEF:minlatency=$rrddir/net.rrd:minlatency:AVERAGE","DEF:maxminlatency=$rrddir/net.rrd:minlatency:MAX",	"DEF:minminlatency=$rrddir/net.rrd:minlatency:MIN",
		"DEF:loss=$rrddir/net.rrd:loss:AVERAGE","DEF:maxloss=$rrddir/net.rrd:loss:MAX","DEF:minloss=$rrddir/net.rrd:loss:MIN",
		"CDEF:adjavglatency=avglatency,$maxping,MIN","CDEF:adjmaxlatency=maxlatency,$maxping,MIN","CDEF:adjloss=loss,1000,/",
		"COMMENT:      ","AREA:adjmaxlatency#00008B:".gettext("Max ping"),"AREA:adjavglatency#00EE22:".gettext("Avg ping"),
		"LINE1:adjloss#FF4444:".gettext("Pkt loss"),"COMMENT:\\n",
		"COMMENT:Max\\: ",'GPRINT:maxmaxlatency:MAX:%6.2lf %ss   ','GPRINT:maxavglatency:MAX:%6.2lf %ss   ','GPRINT:maxloss:MAX:%6.2lf %%',"COMMENT:\\n",
		"COMMENT:Min\\: ",'GPRINT:minmaxlatency:MIN:%6.2lf %ss   ','GPRINT:minavglatency:MIN:%6.2lf %ss   ','GPRINT:minloss:MAX:%6.2lf %%',"COMMENT:\\n",
		"COMMENT:Last\\:",'GPRINT:maxlatency:LAST:%6.2lf %ss   ','GPRINT:avglatency:LAST:%6.2lf %ss   ','GPRINT:loss:LAST:%6.2lf %%',"COMMENT:\\n");

	#trafic sur l'interface cote reseau local	
    createShowGraph(gettext("Load on the local network interface."),"if_loc",
		"--title=".gettext("Local network load"),
		"--vertical-label=KB/s",
		"--start=$start","--base=1000","--lower-limit=0",
		"DEF:bin=$rrddir/if_loc.rrd:bin:AVERAGE","DEF:maxbin=$rrddir/if_loc.rrd:bin:MAX","DEF:bout=$rrddir/if_loc.rrd:bout:AVERAGE","DEF:maxbout=$rrddir/if_loc.rrd:bout:MAX","DEF:minbin=$rrddir/if_loc.rrd:bin:MIN","DEF:minbout=$rrddir/if_loc.rrd:bout:MIN",
		"CDEF:adj_bout=0,bout,-",
		"COMMENT:      ","AREA:bin#0066FF:".gettext("Incoming Kilobytes"),"AREA:adj_bout#FF6633:".gettext("Outgoing Kilobytes"),"COMMENT:\\n",
		"COMMENT:Max\\: ",'GPRINT:maxbin:MAX:%8.2lf %sKB/s','GPRINT:maxbout:MAX:%8.2lf %sKB/s',"COMMENT:\\n",
		"COMMENT:Min\\: ",'GPRINT:minbin:MIN:%8.2lf %sKB/s','GPRINT:minbout:MIN:%8.2lf %sKB/s',"COMMENT:\\n",
		"COMMENT:Last\\:",'GPRINT:bin:LAST:%8.2lf %sKB/s','GPRINT:bout:LAST:%8.2lf %sKB/s',"COMMENT:\\n");

    #si on a une 2e interface reseay
    if ($ExternalInterface ne "")
    {
	    #trafic sur l'interface cote reseau externe	
	    createShowGraph(gettext("Load on the external network interface (to internet)."),"if_ext",
    		"--title=".gettext("External network load"),
	    	"--vertical-label=KB/s",
		    "--start=$start","--base=1000","--lower-limit=0",
    		"DEF:bin=$rrddir/if_ext.rrd:bin:AVERAGE","DEF:maxbin=$rrddir/if_ext.rrd:bin:MAX","DEF:bout=$rrddir/if_ext.rrd:bout:AVERAGE","DEF:maxbout=$rrddir/if_ext.rrd:bout:MAX","DEF:minbin=$rrddir/if_ext.rrd:bin:MIN","DEF:minbout=$rrddir/if_ext.rrd:bout:MIN",
	    	"CDEF:adj_bout=0,bout,-",
		    "COMMENT:      ","AREA:bin#FF6633:".gettext("Incoming Kilobytes"),"AREA:adj_bout#0066FF:".gettext("Outgoing Kilobytes"),"COMMENT:\\n",
		"COMMENT:Max\\: ",'GPRINT:maxbin:MAX:%8.2lf %sKB/s','GPRINT:maxbout:MAX:%8.2lf %sKB/s',"COMMENT:\\n",
		"COMMENT:Min\\: ",'GPRINT:minbin:MIN:%8.2lf %sKB/s','GPRINT:minbout:MIN:%8.2lf %sKB/s',"COMMENT:\\n",
		"COMMENT:Last\\:",'GPRINT:bin:LAST:%8.2lf %sKB/s','GPRINT:bout:LAST:%8.2lf %sKB/s',"COMMENT:\\n");

	    print $q->p(gettext("Network load on the server except routing.")),
			$q->ul(
				$q->li(gettext("If the blue curve is :")),
				$q->ul(
					$q->li(gettext("positive => download from the internet")),
					$q->li(gettext("negative => upload from the local network")),
			  	),
			  	$q->li(gettext("If the red curve is :")),
				$q->ul(
					$q->li(gettext("positive => upload from the internet")),
					$q->li(gettext("negative => download from the local network"))
			  )),$q->br;
        
        createShowGraph("","if_delta",
		    "--title=".gettext("Network load on the server"),
    		"--vertical-label=KB/s",
	    	"--start=$start","--base=1000","--lower-limit=0",
		    "DEF:extbin=$rrddir/if_ext.rrd:bin:AVERAGE","DEF:maxextbin=$rrddir/if_ext.rrd:bin:MAX","DEF:extbout=$rrddir/if_ext.rrd:bout:AVERAGE","DEF:maxextbout=$rrddir/if_ext.rrd:bout:MAX",
    		"DEF:locbin=$rrddir/if_loc.rrd:bin:AVERAGE","DEF:maxlocbin=$rrddir/if_loc.rrd:bin:MAX","DEF:locbout=$rrddir/if_loc.rrd:bout:AVERAGE","DEF:maxlocbout=$rrddir/if_loc.rrd:bout:MAX",
		"CDEF:loc_srv=extbout,locbin,-","CDEF:srv_net=extbin,locbout,-",
		"COMMENT:      ","LINE2:loc_srv#3300FF:Server=>Net - Local=>Server","LINE2:srv_net#FF0033:Net=>Server - Server=>Local","COMMENT:\\n");
	
    }

	print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
        
}
#----------------------------------------------------------------
#----------------------------------------------------------------
#affiche les graphes systeme
# - cpu:user/system/nice
# - cpu:load1/load5/load15/total
# - cpu:runq/plist
# - cpu:uptime
# - mem:used/cached/buffer/free
# - mem:swap used/free
# - hd:du
# - hd:blkread/blkwrite
sub showSystmGraph
{
 	my $start='-1d';	
    printPopupMenu(gettext("View graphs on "));
    $start=$q->param('duree') if defined($q->param('duree'));

	print $q->p($q->b($labels{$start}));
    print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
    
	#repartition user/nice/system
    createShowGraph(gettext("Distribution of cpu usage for system, user and niced processes."),"cpu_usage",
		"--title=".gettext("Cpu usage"),
		"--vertical-label=%",
		"--start=$start","--base=1000","--lower-limit=0",
		"DEF:user=$rrddir/cpu.rrd:user:AVERAGE","DEF:maxuser=$rrddir/cpu.rrd:user:MAX","DEF:minuser=$rrddir/cpu.rrd:user:MIN",
		"DEF:system=$rrddir/cpu.rrd:system:AVERAGE","DEF:maxsystem=$rrddir/cpu.rrd:system:MAX","DEF:minsystem=$rrddir/cpu.rrd:system:MIN",
		"DEF:nice=$rrddir/cpu.rrd:nice:AVERAGE","DEF:maxnice=$rrddir/cpu.rrd:nice:MAX","DEF:minnice=$rrddir/cpu.rrd:nice:MIN",
		"COMMENT:      ",    "AREA:system#0066FF: System    ",	"STACK:nice#330066: Nice    ",	"STACK:user#00FF33: User",	"COMMENT:\\n",
		"COMMENT:Max\\: ",	'GPRINT:maxsystem:MAX:%7.2lf %%',	'GPRINT:maxnice:MAX:   %7.2lf %%',	'GPRINT:maxuser:MAX:  %7.2lf %%',	"COMMENT:\\n",
		"COMMENT:Min\\: ",	'GPRINT:minsystem:MIN:%7.2lf %%',	'GPRINT:minnice:MIN:   %7.2lf %%',	'GPRINT:minuser:MIN:  %7.2lf %%',	"COMMENT:\\n",
		"COMMENT:Avg\\: ",	'GPRINT:system:AVERAGE:%7.2lf %%',	'GPRINT:nice:AVERAGE:   %7.2lf %%',	'GPRINT:user:AVERAGE:  %7.2lf %%',	"COMMENT:\\n",
		"COMMENT:Last\\:",	'GPRINT:system:LAST:%7.2lf %%',	    'GPRINT:nice:LAST:   %7.2lf %%',	'GPRINT:user:LAST:  %7.2lf %%',"COMMENT:\\n");
		
	#load average sur 1/5 & 15mn // total cpu
	createShowGraph(gettext("System load average on 1mn,5mn,15mn compared to cpu usage."),"cpu_load",
		"--title=".gettext("System load / Cpu %"),
		"--vertical-label={Load*10} / %",
		"--start=$start","--base=1000","--lower-limit=0",
		"DEF:load1=$rrddir/cpu.rrd:load1:AVERAGE",	"DEF:maxload1=$rrddir/cpu.rrd:load1:MAX",	"DEF:minload1=$rrddir/cpu.rrd:load1:MIN",
		"DEF:load5=$rrddir/cpu.rrd:load5:AVERAGE",	"DEF:maxload5=$rrddir/cpu.rrd:load5:MAX",	"DEF:minload5=$rrddir/cpu.rrd:load5:MIN",
		"DEF:load15=$rrddir/cpu.rrd:load15:AVERAGE","DEF:maxload15=$rrddir/cpu.rrd:load15:MAX",	"DEF:minload15=$rrddir/cpu.rrd:load15:MIN",
		"DEF:total=$rrddir/cpu.rrd:total:AVERAGE",	"DEF:maxtotal=$rrddir/cpu.rrd:total:MAX",	"DEF:mintotal=$rrddir/cpu.rrd:total:MIN",
		"CDEF:adjload1=load1,10,*",	"CDEF:adjload5=load5,10,*",	"CDEF:adjload15=load15,10,*",
		"COMMENT:      ",    "AREA:total#22BB00: Cpu  ","LINE1:adjload1#0000DD: Load1    ",
        "LINE1:adjload5#EE2200: Load5    ","LINE1:adjload15#EEFF00: Load15   ",	"COMMENT:\\n",
		"COMMENT:Max\\: ",'GPRINT:maxtotal:MAX:%7.2lf %%','GPRINT:maxload1:MAX:%7.3lf  ',	
        'GPRINT:maxload5:MAX:   %7.3lf   ',	'GPRINT:maxload15:MAX:  %7.3lf   ',	"COMMENT:\\n",
		"COMMENT:Min\\: ",'GPRINT:mintotal:MIN:%7.2lf %%','GPRINT:minload1:MIN:%7.3lf  ',
        'GPRINT:minload5:MIN:   %7.3lf   ',	'GPRINT:minload15:MIN:  %7.3lf   ',	"COMMENT:\\n",
		"COMMENT:Avg\\: ",'GPRINT:total:AVERAGE:%7.2lf %%','GPRINT:load1:AVERAGE:%7.3lf  ',
		'GPRINT:load5:AVERAGE:   %7.3lf   ','GPRINT:load15:AVERAGE:  %7.3lf   ',"COMMENT:\\n",
		"COMMENT:Last\\:",'GPRINT:total:LAST:%7.2lf %%','GPRINT:load1:LAST:%7.3lf  ',
		'GPRINT:load5:LAST:   %7.3lf   ','GPRINT:load15:LAST:  %7.3lf   ',"COMMENT:\\n");	
	
	#process list/run queue
    createShowGraph(gettext("Number of running processes on the server, and kernel run queue size."),"cpu_process",
		"--title=".gettext("Number of processes / run queue size"),
		"--vertical-label=Nb proc / {Rq*10}",
		"--start=$start","--base=1000","--lower-limit=0",
		"DEF:plist=$rrddir/cpu.rrd:plist:AVERAGE","DEF:maxplist=$rrddir/cpu.rrd:plist:MAX","DEF:minplist=$rrddir/cpu.rrd:plist:MIN",
		"DEF:runq=$rrddir/cpu.rrd:runq:AVERAGE","DEF:maxrunq=$rrddir/cpu.rrd:runq:MAX","DEF:minrunq=$rrddir/cpu.rrd:runq:MIN",
		"CDEF:adjrunq=runq,10,*",
		"COMMENT:      ",    "AREA:plist#FFDD00: ".gettext("Processes"),"LINE1:adjrunq#EE3300: ".gettext("Run queue"),	"COMMENT:\\n",
		"COMMENT:Max\\: ",	'GPRINT:maxplist:MAX:%4.0lf     ','GPRINT:maxrunq:MAX:   %7.3lf ',	"COMMENT:\\n",
		"COMMENT:Min\\: ",	'GPRINT:minplist:MIN:%4.0lf     ','GPRINT:minrunq:MIN:   %7.3lf ',	"COMMENT:\\n",
		"COMMENT:Avg\\: ",	'GPRINT:plist:AVERAGE:%4.0lf     ',	'GPRINT:runq:AVERAGE:   %7.3lf ',"COMMENT:\\n",
		"COMMENT:Last\\:",	'GPRINT:plist:LAST:%4.0lf     ',	'GPRINT:runq:LAST:   %7.3lf',"COMMENT:\\n");
		
	#uptime
	createShowGraph(gettext("Server uptime."),"cpu_uptime",
		"--title=".gettext("Uptime"),
		"--vertical-label=".gettext("Days"),
		"--start=$start","--base=1000","--lower-limit=0",
		"DEF:uptime=$rrddir/cpu.rrd:uptime:AVERAGE","DEF:maxuptime=$rrddir/cpu.rrd:uptime:MAX","DEF:minuptime=$rrddir/cpu.rrd:uptime:MIN",
		"CDEF:adjuptime=uptime,86400,/",	"CDEF:adjmaxuptime=maxuptime,86400,/",	"CDEF:adjminuptime=minuptime,86400,/",
		"COMMENT:      ",    "AREA:adjuptime#FF1100: ".gettext("Uptime"),"COMMENT:\\n",
		"COMMENT:Max\\: ",	'GPRINT:adjmaxuptime:MAX: %4.1lf',	"COMMENT:\\n",
		"COMMENT:Min\\: ",	'GPRINT:adjminuptime:MIN: %4.1lf',	"COMMENT:\\n",
		"COMMENT:Last\\: ",	'GPRINT:adjuptime:LAST:%4.1lf',"COMMENT:\\n");		

	#memoire : used/cached/buffers/free
    createShowGraph(gettext("Detailed usage of the server memory."),"mem",
		"--title=".gettext("Memory usage"),
		"--vertical-label=".gettext("Bytes"),
		"--start=$start","--base=1024","--lower-limit=0",
		"DEF:used=$rrddir/mem.rrd:memused:AVERAGE","DEF:maxused=$rrddir/mem.rrd:memused:MAX","DEF:minused=$rrddir/mem.rrd:memused:MIN",
		"DEF:cached=$rrddir/mem.rrd:memcached:AVERAGE","DEF:maxcached=$rrddir/mem.rrd:memcached:MAX","DEF:mincached=$rrddir/mem.rrd:memcached:MIN",
		"DEF:buffers=$rrddir/mem.rrd:membuffers:AVERAGE","DEF:maxbuffers=$rrddir/mem.rrd:membuffers:MAX","DEF:minbuffers=$rrddir/mem.rrd:membuffers:MIN",
		"DEF:actualfree=$rrddir/mem.rrd:memactualfree:AVERAGE","DEF:maxactualfree=$rrddir/mem.rrd:memactualfree:MAX","DEF:minactualfree=$rrddir/mem.rrd:memactualfree:MIN",
		"DEF:total=$rrddir/mem.rrd:memtotal:AVERAGE",
        "COMMENT:      ",    "AREA:used#000066: ".gettext("Used"),"STACK:buffers#6633CC: ".gettext("Buffers"),"STACK:cached#339933: ".gettext("Cached"),
		"STACK:actualfree#00FF99: ".gettext("Free"),"LINE1:total#FF0000: ".gettext("Total"),"COMMENT:\\n",
		"COMMENT:Max\\: ",'GPRINT:maxused:MAX:%6.2lf%sb','GPRINT:maxbuffers:MAX:%6.2lf%sb','GPRINT:maxcached:MAX:%6.2lf%sb',
		'GPRINT:maxactualfree:MAX:%6.2lf%sb',"COMMENT:\\n",
		"COMMENT:Min\\: ",'GPRINT:minused:MIN:%6.2lf%sb','GPRINT:minbuffers:MIN:%6.2lf%sb','GPRINT:mincached:MIN:%6.2lf%sb',
		'GPRINT:minactualfree:MIN:%6.2lf%sb',"COMMENT:\\n",
		"COMMENT:Avg\\: ",'GPRINT:used:AVERAGE:%6.2lf%sb','GPRINT:buffers:AVERAGE:%6.2lf%sb','GPRINT:cached:AVERAGE:%6.2lf%sb',
		'GPRINT:actualfree:AVERAGE:%6.2lf%sb',"COMMENT:\\n",
		"COMMENT:Last\\:",'GPRINT:used:LAST:%6.2lf%sb','GPRINT:buffers:LAST:%6.2lf%sb','GPRINT:cached:LAST:%6.2lf%sb',
		'GPRINT:actualfree:LAST:%6.2lf%sb','GPRINT:total:LAST:%6.2lf%sb',"COMMENT:\\n");
		
	#memoire : swap used/free/total
    createShowGraph(gettext("Swap usage (virtual memory) on the server's hard disk."),"swap",
		"--title=".gettext("Swap usage"),
		"--vertical-label=".gettext("Bytes"),
		"--start=$start","--base=1024","--lower-limit=0",
		"DEF:used=$rrddir/mem.rrd:swapused:AVERAGE","DEF:maxused=$rrddir/mem.rrd:swapused:MAX","DEF:minused=$rrddir/mem.rrd:swapused:MIN",
		"DEF:free=$rrddir/mem.rrd:swapfree:AVERAGE","DEF:maxfree=$rrddir/mem.rrd:swapfree:MAX","DEF:minfree=$rrddir/mem.rrd:swapfree:MIN",
		"DEF:total=$rrddir/mem.rrd:swaptotal:AVERAGE","DEF:maxtotal=$rrddir/mem.rrd:swaptotal:MAX","DEF:mintotal=$rrddir/mem.rrd:swaptotal:MIN",
		"COMMENT:      ",    "AREA:used#FF0033: ".gettext("Used"),"STACK:free#FF9966: ".gettext("Free"),"LINE1:total#006600: ".gettext("Total"),
		"COMMENT:\\n",
		"COMMENT:Max\\: ",
		'GPRINT:maxused:MAX:%6.2lf%sb','GPRINT:maxfree:MAX:%6.2lf%sb','GPRINT:maxtotal:MAX:%6.2lf%sb',"COMMENT:\\n",
		"COMMENT:Min\\: ",'GPRINT:minused:MIN:%6.2lf%sb','GPRINT:minfree:MIN:%6.2lf%sb','GPRINT:mintotal:MIN:%6.2lf%sb',"COMMENT:\\n",
		"COMMENT:Avg\\: ",'GPRINT:used:AVERAGE:%6.2lf%sb','GPRINT:free:AVERAGE:%6.2lf%sb','GPRINT:total:AVERAGE:%6.2lf%sb',"COMMENT:\\n",
		"COMMENT:Last\\:",'GPRINT:used:LAST:%6.2lf%sb','GPRINT:free:LAST:%6.2lf%sb','GPRINT:total:LAST:%6.2lf%sb',"COMMENT:\\n");
		
	#taux d'ecriture/lecture sur le disque dur	
	createShowGraph(gettext("Amount of raw data read/written on the hard disk."),"hd_hard",
		"--title=".gettext("Data written/read"),
		"--vertical-label=".gettext("Blocks/s"),
		"--start=$start","--base=1024",
		"DEF:read=$rrddir/hd.rrd:blckread:AVERAGE","DEF:maxread=$rrddir/hd.rrd:blckread:MAX","DEF:minread=$rrddir/hd.rrd:blckread:MIN",
		"DEF:write=$rrddir/hd.rrd:blckwrite:AVERAGE","DEF:maxwrite=$rrddir/hd.rrd:blckwrite:MAX","DEF:minwrite=$rrddir/hd.rrd:blckwrite:MIN",
		"CDEF:adjread=0,read,-",
		"COMMENT:      ",    "LINE1:adjread#FF0033: ".gettext("Read"),"LINE1:write#3300FF: ".gettext("Written"),"COMMENT:\\n",
		"COMMENT:Max\\: ",'GPRINT:maxread:MAX:%6.2lf %sblk/s','GPRINT:maxwrite:MAX:%6.2lf %sblk/s',"COMMENT:\\n",
		"COMMENT:Min\\: ",'GPRINT:minread:MIN:%6.2lf %sblk/s','GPRINT:minwrite:MIN:%6.2lf %sblk/s',"COMMENT:\\n",
		"COMMENT:Avg\\: ",'GPRINT:read:AVERAGE:%6.2lf %sblk/s','GPRINT:write:AVERAGE:%6.2lf %sblk/s',"COMMENT:\\n",
		"COMMENT:Last\\:",'GPRINT:read:LAST:%6.2lf %sblk/s','GPRINT:write:LAST:%6.2lf %sblk/s',"COMMENT:\\n");	

    #ici, hack en fonction du param du_enabled : on met toutes les infos ou juste used/free/total
    #taux de remplissage du hd, place prise par log/squidcache/mysql/smefiles
    my $du_enabled=$params{'UseDu'};
    my @tab=(
		"--title=".gettext("Hard disk usage"),
		"--vertical-label=".gettext("Bytes"),
		"--start=$start","--base=1024","--lower-limit=0",
		"DEF:used=$rrddir/hd.rrd:used:AVERAGE","DEF:maxused=$rrddir/hd.rrd:used:MAX","DEF:minused=$rrddir/hd.rrd:used:MIN",
		"DEF:free=$rrddir/hd.rrd:free:AVERAGE","DEF:maxfree=$rrddir/hd.rrd:free:MAX","DEF:minfree=$rrddir/hd.rrd:free:MIN",
		"DEF:total=$rrddir/hd.rrd:total:AVERAGE");
    push @tab,
        "DEF:log=$rrddir/hd.rrd:log:AVERAGE","DEF:maxlog=$rrddir/hd.rrd:log:MAX","DEF:minlog=$rrddir/hd.rrd:log:MIN",
		"DEF:squid=$rrddir/hd.rrd:squid:AVERAGE","DEF:maxsquid=$rrddir/hd.rrd:squid:MAX","DEF:minsquid=$rrddir/hd.rrd:squid:MIN",
		"DEF:files=$rrddir/hd.rrd:files:AVERAGE","DEF:maxfiles=$rrddir/hd.rrd:files:MAX","DEF:minfiles=$rrddir/hd.rrd:files:MIN",
		"DEF:mysql=$rrddir/hd.rrd:mysql:AVERAGE","DEF:maxmysql=$rrddir/hd.rrd:mysql:MAX","DEF:minmysql=$rrddir/hd.rrd:mysql:MIN" if ($du_enabled eq "on");
    push @tab,"COMMENT:      ",    "AREA:used#FF0033:".gettext("Used"),"STACK:free#44CCFF:".gettext("Free");
    push @tab,"AREA:files#23EF41:Files","STACK:squid#AA1A00:Squid",	"STACK:log#11AA00:Log",	"STACK:mysql#FFFF00:Mysql" if ($du_enabled eq "on");	
    push @tab,"LINE1:total#0000FF:Total",	"COMMENT:\\n",
		"COMMENT:Max\\: ",'GPRINT:maxused:MAX:%5.1lf%sb ','GPRINT:maxfree:MAX:%5.1lf%sb ';
    push @tab,'GPRINT:maxfiles:MAX:%5.1lf%sb','GPRINT:maxsquid:MAX:%5.1lf%sb','GPRINT:maxlog:MAX:%5.1lf%sb','GPRINT:maxmysql:MAX:%5.1lf%sb' if ($du_enabled eq "on");
    push @tab,"COMMENT:\\n","COMMENT:Min\\: ",'GPRINT:minused:MIN:%5.1lf%sb ','GPRINT:minfree:MIN:%5.1lf%sb ';
    push @tab,'GPRINT:minfiles:MIN:%5.1lf%sb','GPRINT:minsquid:MIN:%5.1lf%sb','GPRINT:minlog:MIN:%5.1lf%sb','GPRINT:minmysql:MIN:%5.1lf%sb' if ($du_enabled eq "on");
    push @tab,"COMMENT:\\n","COMMENT:Avg\\: ",'GPRINT:used:AVERAGE:%5.1lf%sb ','GPRINT:free:AVERAGE:%5.1lf%sb ';
    push @tab,'GPRINT:files:AVERAGE:%5.1lf%sb','GPRINT:squid:AVERAGE:%5.1lf%sb','GPRINT:log:AVERAGE:%5.1lf%sb','GPRINT:mysql:AVERAGE:%5.1lf%sb' if ($du_enabled eq "on");
    push @tab,"COMMENT:\\n","COMMENT:Last\\:",'GPRINT:used:LAST:%5.1lf%sb ','GPRINT:free:LAST:%5.1lf%sb ';
    push @tab,'GPRINT:files:LAST:%5.1lf%sb','GPRINT:squid:LAST:%5.1lf%sb','GPRINT:log:LAST:%5.1lf%sb','GPRINT:mysql:LAST:%5.1lf%sb' if ($du_enabled eq "on");
    push @tab,'GPRINT:total:LAST:%5.1lf%sb',"COMMENT:\\n";
	
    my $title=gettext("Detailed usage of disk space (squid cache, mysql databases, log files, user files..).");
    $title=gettext("Disk space usage.") if ($du_enabled eq "off");
    createShowGraph($title,"hd_usage",@tab);
		
    print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}

sub createGraphQmail {
	my($start)=(@_);
        #qmail entrant/sortant
    createShowGraph(gettext("Number of local/remote e-mails handled by the internal mail service (including other service generated e-mails)."),"qmail",
                "--title=".gettext("Local/Remote e-mails"),
                "--start=$start",
                "DEF:local_failure=$rrddir/qmail.rrd:local_failure:AVERAGE","DEF:maxlocal_failure=$rrddir/qmail.rrd:local_failure:MAX","DEF:minlocal_failure=$rrddir/qmail.rrd:local_failure:MIN",
                "DEF:local_deferral=$rrddir/qmail.rrd:local_deferral:AVERAGE","DEF:maxlocal_deferral=$rrddir/qmail.rrd:local_deferral:MAX","DEF:minlocal_deferral=$rrddir/qmail.rrd:local_deferral:MIN",
                "DEF:local_success=$rrddir/qmail.rrd:local_success:AVERAGE","DEF:maxlocal_success=$rrddir/qmail.rrd:local_success:MAX","DEF:minlocal_success=$rrddir/qmail.rrd:local_success:MIN",
                "DEF:local_total=$rrddir/qmail.rrd:local_total:AVERAGE","DEF:maxlocal_total=$rrddir/qmail.rrd:local_total:MAX","DEF:minlocal_total=$rrddir/qmail.rrd:local_total:MIN",
                "DEF:remote_failure=$rrddir/qmail.rrd:remote_failure:AVERAGE","DEF:maxremote_failure=$rrddir/qmail.rrd:remote_failure:MAX","DEF:minremote_failure=$rrddir/qmail.rrd:remote_failure:MIN",
                "DEF:remote_deferral=$rrddir/qmail.rrd:remote_deferral:AVERAGE","DEF:maxremote_deferral=$rrddir/qmail.rrd:remote_deferral:MAX","DEF:minremote_deferral=$rrddir/qmail.rrd:remote_deferral:MIN",
                "DEF:remote_success=$rrddir/qmail.rrd:remote_success:AVERAGE","DEF:maxremote_success=$rrddir/qmail.rrd:remote_success:MAX","DEF:minremote_success=$rrddir/qmail.rrd:remote_success:MIN",
                "DEF:remote_total=$rrddir/qmail.rrd:remote_total:AVERAGE","DEF:maxremote_total=$rrddir/qmail.rrd:remote_total:MAX","DEF:minremote_total=$rrddir/qmail.rrd:remote_total:MIN",
                "DEF:local_queue=$rrddir/qmail.rrd:local_queue:AVERAGE","DEF:maxlocal_queue=$rrddir/qmail.rrd:local_queue:MAX","DEF:minlocal_queue=$rrddir/qmail.rrd:local_queue:MIN",
                "DEF:remote_queue=$rrddir/qmail.rrd:remote_queue:AVERAGE","DEF:maxremote_queue=$rrddir/qmail.rrd:remote_queue:MAX","DEF:minremote_queue=$rrddir/qmail.rrd:remote_queue:MIN",
                "CDEF:adj_remote_total=0,remote_total,-", "CDEF:adj_remote_queue=0,remote_queue,-",
                "CDEF:adj_remote_failure=0,remote_failure,-", "CDEF:adj_remote_deferral=0,remote_deferral,-","CDEF:adj_remote_success=0,remote_success,-",
                "COMMENT:Last\\t Min\\t Avg\\t Max\\r",
                "COMMENT:\\n","AREA:local_total#1ED408:".gettext("Total local e-mails"),"COMMENT:\\u","GPRINT:local_total:LAST:%4.0lf  ","GPRINT:minlocal_total:MIN:%4.0lf  ","GPRINT:local_total:AVERAGE:%4.0lf  ","GPRINT:maxlocal_total:MAX:%4.0lf  \\r",
		"COMMENT:\\n","COMMENT:  ".gettext("Total remote e-mails"), "COMMENT:\\u","GPRINT:remote_total:LAST:%4.0lf  ","GPRINT:minremote_total:MIN:%4.0lf  ","GPRINT:remote_total:AVERAGE:%4.0lf  ","GPRINT:maxremote_total:MAX:%4.0lf  \\r",

                "COMMENT:\\n","COMMENT: ","AREA:adj_remote_success#0000ff:".gettext("Remote e-mail success"), "COMMENT:\\u","GPRINT:remote_success:LAST:%4.0lf  ","GPRINT:minremote_success:MIN:%4.0lf  ","GPRINT:remote_success:AVERAGE:%4.0lf  ","GPRINT:maxremote_success:MAX:%4.0lf  \\r",
                "COMMENT:\\n","COMMENT: ","AREA:adj_remote_deferral#ffff00:".gettext("Remote e-mail deferral").":STACK", "COMMENT:\\u","GPRINT:remote_deferral:LAST:%4.0lf  ","GPRINT:minremote_deferral:MIN:%4.0lf  ","GPRINT:remote_deferral:AVERAGE:%4.0lf  ","GPRINT:maxremote_deferral:MAX:%4.0lf  \\r",
                "COMMENT:\\n","COMMENT: ","AREA:adj_remote_failure#ff0000:".gettext("Remote e-mail failure").":STACK", "COMMENT:\\u","GPRINT:remote_failure:LAST:%4.0lf  ","GPRINT:minremote_failure:MIN:%4.0lf  ","GPRINT:remote_failure:AVERAGE:%4.0lf  ","GPRINT:maxremote_failure:MAX:%4.0lf  \\r",

                "COMMENT:\\n","LINE2:local_queue#666666:".gettext("Local queue"),"COMMENT:\\u", "GPRINT:local_queue:LAST:%4.0lf  ","GPRINT:minlocal_queue:MIN:%4.0lf  ","GPRINT:local_queue:AVERAGE:%4.0lf  ","GPRINT:maxlocal_queue:MAX:%4.0lf  \\r",
                "COMMENT:\\n","LINE2:adj_remote_queue#000000:".gettext("Remote queue"),"COMMENT:\\u", "GPRINT:remote_queue:LAST:%4.0lf  ","GPRINT:minremote_queue:MIN:%4.0lf  ","GPRINT:remote_queue:AVERAGE:%4.0lf  ","GPRINT:maxremote_queue:MAX:%4.0lf  \\r",
                "COMMENT:\\n");


}

sub createGraphAltQmail {
        my($start)=(@_);
        #qmail entrant/sortant
    createShowGraph(gettext("Number of remote e-mails handled by the alternative mail service (altqmail)."),"altqmail",
                "--title=".gettext("Remote e-mails (altqmail)"),
                "--start=$start",
                "DEF:local_failure=$rrddir/altqmail.rrd:local_failure:AVERAGE","DEF:maxlocal_failure=$rrddir/altqmail.rrd:local_failure:MAX","DEF:minlocal_failure=$rrddir/altqmail.rrd:local_failure:MIN",
                "DEF:local_deferral=$rrddir/altqmail.rrd:local_deferral:AVERAGE","DEF:maxlocal_deferral=$rrddir/altqmail.rrd:local_deferral:MAX","DEF:minlocal_deferral=$rrddir/altqmail.rrd:local_deferral:MIN",
                "DEF:local_success=$rrddir/altqmail.rrd:local_success:AVERAGE","DEF:maxlocal_success=$rrddir/altqmail.rrd:local_success:MAX","DEF:minlocal_success=$rrddir/altqmail.rrd:local_success:MIN",
                "DEF:local_total=$rrddir/altqmail.rrd:local_total:AVERAGE","DEF:maxlocal_total=$rrddir/altqmail.rrd:local_total:MAX","DEF:minlocal_total=$rrddir/altqmail.rrd:local_total:MIN",
                "DEF:remote_failure=$rrddir/altqmail.rrd:remote_failure:AVERAGE","DEF:maxremote_failure=$rrddir/altqmail.rrd:remote_failure:MAX","DEF:minremote_failure=$rrddir/altqmail.rrd:remote_failure:MIN",
                "DEF:remote_deferral=$rrddir/altqmail.rrd:remote_deferral:AVERAGE","DEF:maxremote_deferral=$rrddir/altqmail.rrd:remote_deferral:MAX","DEF:minremote_deferral=$rrddir/altqmail.rrd:remote_deferral:MIN",
                "DEF:remote_success=$rrddir/altqmail.rrd:remote_success:AVERAGE","DEF:maxremote_success=$rrddir/altqmail.rrd:remote_success:MAX","DEF:minremote_success=$rrddir/altqmail.rrd:remote_success:MIN",
                "DEF:remote_total=$rrddir/altqmail.rrd:remote_total:AVERAGE","DEF:maxremote_total=$rrddir/altqmail.rrd:remote_total:MAX","DEF:minremote_total=$rrddir/altqmail.rrd:remote_total:MIN",
                "DEF:local_queue=$rrddir/altqmail.rrd:local_queue:AVERAGE","DEF:maxlocal_queue=$rrddir/altqmail.rrd:local_queue:MAX","DEF:minlocal_queue=$rrddir/altqmail.rrd:local_queue:MIN",
                "DEF:remote_queue=$rrddir/altqmail.rrd:remote_queue:AVERAGE","DEF:maxremote_queue=$rrddir/altqmail.rrd:remote_queue:MAX","DEF:minremote_queue=$rrddir/altqmail.rrd:remote_queue:MIN",
                "CDEF:adj_remote_total=0,remote_total,-", "CDEF:adj_remote_queue=0,remote_queue,-",
                "CDEF:adj_remote_failure=0,remote_failure,-", "CDEF:adj_remote_deferral=0,remote_deferral,-","CDEF:adj_remote_success=0,remote_success,-",
                "COMMENT:Last\\t Min\\t Avg\\t Max\\r",
                "COMMENT:\\n","AREA:local_total#1ED408:".gettext("Total local e-mails"),"COMMENT:\\u","GPRINT:local_total:LAST:%4.0lf  ","GPRINT:minlocal_total:MIN:%4.0lf  ","GPRINT:local_total:AVERAGE:%4.0lf  ","GPRINT:maxlocal_total:MAX:%4.0lf  \\r",
                "COMMENT:\\n","COMMENT:  ".gettext("Total remote e-mails"), "COMMENT:\\u","GPRINT:remote_total:LAST:%4.0lf  ","GPRINT:minremote_total:MIN:%4.0lf  ","GPRINT:remote_total:AVERAGE:%4.0lf  ","GPRINT:maxremote_total:MAX:%4.0lf  \\r",

                "COMMENT:\\n","COMMENT: ","AREA:adj_remote_success#0000ff:".gettext("Remote e-mail success"), "COMMENT:\\u","GPRINT:remote_success:LAST:%4.0lf  ","GPRINT:minremote_success:MIN:%4.0lf  ","GPRINT:remote_success:AVERAGE:%4.0lf  ","GPRINT:maxremote_success:MAX:%4.0lf  \\r",
                "COMMENT:\\n","COMMENT: ","AREA:adj_remote_deferral#ffff00:".gettext("Remote e-mail deferral").":STACK", "COMMENT:\\u","GPRINT:remote_deferral:LAST:%4.0lf  ","GPRINT:minremote_deferral:MIN:%4.0lf  ","GPRINT:remote_deferral:AVERAGE:%4.0lf  ","GPRINT:maxremote_deferral:MAX:%4.0lf  \\r",
                "COMMENT:\\n","COMMENT: ","AREA:adj_remote_failure#ff0000:".gettext("Remote e-mail failure").":STACK", "COMMENT:\\u","GPRINT:remote_failure:LAST:%4.0lf  ","GPRINT:minremote_failure:MIN:%4.0lf  ","GPRINT:remote_failure:AVERAGE:%4.0lf  ","GPRINT:maxremote_failure:MAX:%4.0lf  \\r",

                "COMMENT:\\n","LINE2:local_queue#666666:".gettext("Local queue"),"COMMENT:\\u", "GPRINT:local_queue:LAST:%4.0lf  ","GPRINT:minlocal_queue:MIN:%4.0lf  ","GPRINT:local_queue:AVERAGE:%4.0lf  ","GPRINT:maxlocal_queue:MAX:%4.0lf  \\r",
                "COMMENT:\\n","LINE2:adj_remote_queue#000000:".gettext("Remote queue"),"COMMENT:\\u", "GPRINT:remote_queue:LAST:%4.0lf  ","GPRINT:minremote_queue:MIN:%4.0lf  ","GPRINT:remote_queue:AVERAGE:%4.0lf  ","GPRINT:maxremote_queue:MAX:%4.0lf  \\r",
                "COMMENT:\\n");


}

sub createGraphQpsmtpd {
	my($start)=(@_);
       #qpsmtpd
        #check_basicheaders:check_goodrcptto:clamav:karma:tls_failed:rhsbl:check_earlytalker:resolvable_fromhost:dnsbl:fcrdns:spf:check_spamhelo:uribl:dmarc:total_denied:spam_denied:other_denied:spam_queued:queued:total
    createShowGraph(gettext("Number of incoming  e-mail connections to qpsmtpd services (outside of server incoming e-mails) and amount of spam/viruses filtered."),"qpsmtpd",
                "--title=".gettext("Incoming qpsmtpd connections spam/virus/e-mails"),
                "--start=$start",
                "DEF:check_basicheaders=$rrddir/qpsmtpd.rrd:check_basicheaders:AVERAGE","DEF:maxcheck_basicheaders=$rrddir/qpsmtpd.rrd:check_basicheaders:MAX","DEF:mincheck_basicheaders=$rrddir/qpsmtpd.rrd:check_basicheaders:MIN",
                "DEF:check_goodrcptto=$rrddir/qpsmtpd.rrd:check_goodrcptto:AVERAGE","DEF:maxcheck_goodrcptto=$rrddir/qpsmtpd.rrd:check_goodrcptto:MAX","DEF:mincheck_goodrcptto=$rrddir/qpsmtpd.rrd:check_goodrcptto:MIN",
                "DEF:clamav=$rrddir/qpsmtpd.rrd:clamav:AVERAGE","DEF:maxclamav=$rrddir/qpsmtpd.rrd:clamav:MAX","DEF:minclamav=$rrddir/qpsmtpd.rrd:clamav:MIN",
                "DEF:karma=$rrddir/qpsmtpd.rrd:karma:AVERAGE","DEF:maxkarma=$rrddir/qpsmtpd.rrd:karma:MAX","DEF:minkarma=$rrddir/qpsmtpd.rrd:karma:MIN",
                "DEF:tls_failed=$rrddir/qpsmtpd.rrd:tls_failed:AVERAGE","DEF:maxtls_failed=$rrddir/qpsmtpd.rrd:tls_failed:MAX","DEF:mintls_failed=$rrddir/qpsmtpd.rrd:tls_failed:MIN",
                "DEF:auth_failed=$rrddir/qpsmtpd.rrd:auth_failed:AVERAGE","DEF:maxauth_failed=$rrddir/qpsmtpd.rrd:auth_failed:MAX","DEF:minauth_failed=$rrddir/qpsmtpd.rrd:auth_failed:MIN",
                "DEF:rhsbl=$rrddir/qpsmtpd.rrd:rhsbl:AVERAGE","DEF:maxrhsbl=$rrddir/qpsmtpd.rrd:rhsbl:MAX","DEF:minrhsbl=$rrddir/qpsmtpd.rrd:rhsbl:MIN",
                "DEF:check_earlytalker=$rrddir/qpsmtpd.rrd:check_earlytalker:AVERAGE","DEF:maxcheck_earlytalker=$rrddir/qpsmtpd.rrd:check_earlytalker:MAX","DEF:mincheck_earlytalker=$rrddir/qpsmtpd.rrd:check_earlytalker:MIN",
                "DEF:resolvable_fromhost=$rrddir/qpsmtpd.rrd:resolvable_fromhost:AVERAGE","DEF:maxresolvable_fromhost=$rrddir/qpsmtpd.rrd:resolvable_fromhost:MAX","DEF:minresolvable_fromhost=$rrddir/qpsmtpd.rrd:resolvable_fromhost:MIN",
                "DEF:dnsbl=$rrddir/qpsmtpd.rrd:dnsbl:AVERAGE","DEF:maxdnsbl=$rrddir/qpsmtpd.rrd:dnsbl:MAX","DEF:mindnsbl=$rrddir/qpsmtpd.rrd:dnsbl:MIN",
                "DEF:fcrdns=$rrddir/qpsmtpd.rrd:fcrdns:AVERAGE","DEF:maxfcrdns=$rrddir/qpsmtpd.rrd:fcrdns:MAX","DEF:minfcrdns=$rrddir/qpsmtpd.rrd:fcrdns:MIN",
                "DEF:spf=$rrddir/qpsmtpd.rrd:spf:AVERAGE","DEF:maxspf=$rrddir/qpsmtpd.rrd:spf:MAX","DEF:minspf=$rrddir/qpsmtpd.rrd:spf:MIN",
                "DEF:check_spamhelo=$rrddir/qpsmtpd.rrd:check_spamhelo:AVERAGE","DEF:maxcheck_spamhelo=$rrddir/qpsmtpd.rrd:check_spamhelo:MAX","DEF:mincheck_spamhelo=$rrddir/qpsmtpd.rrd:check_spamhelo:MIN",
                "DEF:uribl=$rrddir/qpsmtpd.rrd:uribl:AVERAGE","DEF:maxuribl=$rrddir/qpsmtpd.rrd:uribl:MAX","DEF:minuribl=$rrddir/qpsmtpd.rrd:uribl:MIN",
                "DEF:dmarc=$rrddir/qpsmtpd.rrd:dmarc:AVERAGE","DEF:maxdmarc=$rrddir/qpsmtpd.rrd:dmarc:MAX","DEF:mindmarc=$rrddir/qpsmtpd.rrd:dmarc:MIN",
                "DEF:total_denied=$rrddir/qpsmtpd.rrd:total_denied:AVERAGE","DEF:maxtotal_denied=$rrddir/qpsmtpd.rrd:total_denied:MAX","DEF:mintotal_denied=$rrddir/qpsmtpd.rrd:total_denied:MIN",
                "DEF:spam_denied=$rrddir/qpsmtpd.rrd:spam_denied:AVERAGE","DEF:maxspam_denied=$rrddir/qpsmtpd.rrd:spam_denied:MAX","DEF:minspam_denied=$rrddir/qpsmtpd.rrd:spam_denied:MIN",
                "DEF:other_denied=$rrddir/qpsmtpd.rrd:other_denied:AVERAGE","DEF:maxother_denied=$rrddir/qpsmtpd.rrd:other_denied:MAX","DEF:minother_denied=$rrddir/qpsmtpd.rrd:other_denied:MIN",

                "DEF:spam_queued=$rrddir/qpsmtpd.rrd:spam_queued:AVERAGE","DEF:maxspam_queued=$rrddir/qpsmtpd.rrd:spam_queued:MAX","DEF:minspam_queued=$rrddir/qpsmtpd.rrd:spam_queued:MIN",
                "DEF:queued=$rrddir/qpsmtpd.rrd:queued:AVERAGE","DEF:maxqueued=$rrddir/qpsmtpd.rrd:queued:MAX","DEF:minqueued=$rrddir/qpsmtpd.rrd:queued:MIN",
                "DEF:total=$rrddir/qpsmtpd.rrd:total:AVERAGE","DEF:maxtotal=$rrddir/qpsmtpd.rrd:total:MAX","DEF:mintotal=$rrddir/qpsmtpd.rrd:total:MIN",
                "CDEF:total_accepted=queued,spam_queued,+",
                "COMMENT:Last\\t Min\\t Avg\\t Max\\r",

                "COMMENT:\\n","COMMENT:".gettext("Total"),"COMMENT:\\u","GPRINT:total:LAST:%4.0lf  ","GPRINT:mintotal:MIN:%4.0lf  ","GPRINT:total:AVERAGE:%4.0lf  ","GPRINT:maxtotal:MAX:%4.0lf  \\r",
		"COMMENT:".gettext("Total accepted e-mails"),"COMMENT:\\u","GPRINT:total_accepted:LAST:%4.0lf  ","GPRINT:total_accepted:MIN:%4.0lf  ","GPRINT:total_accepted:AVERAGE:%4.0lf  ","GPRINT:total_accepted:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:spam_queued#8fd487:".gettext("Accepted e-mails")."\\: ".gettext("spam queued"),"COMMENT:\\u","GPRINT:spam_queued:LAST:%4.0lf  ","GPRINT:minspam_queued:MIN:%4.0lf  ","GPRINT:spam_queued:AVERAGE:%4.0lf  ","GPRINT:maxspam_queued:MAX:%4.0lf  \\r",
                "COMMENT:\\n","AREA:queued#1ED408:".gettext("Accepted e-mails")."\\: ".gettext("queued").":STACK","COMMENT:\\u","GPRINT:queued:LAST:%4.0lf  ","GPRINT:minqueued:MIN:%4.0lf  ","GPRINT:queued:AVERAGE:%4.0lf  ","GPRINT:maxqueued:MAX:%4.0lf  \\r",

               "COMMENT:\\n", "COMMENT:".gettext("Total denied e-mails"),"COMMENT:\\u","GPRINT:total_denied:LAST:%4.0lf  ","GPRINT:mintotal_denied:MIN:%4.0lf  ","GPRINT:total_denied:AVERAGE:%4.0lf  ","GPRINT:maxtotal_denied:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:check_spamhelo#007a7a:".gettext("Denied e-mails")."\\: ".gettext("check_spamhelo").":STACK","COMMENT:\\u","GPRINT:check_spamhelo:LAST:%4.0lf  ","GPRINT:mincheck_spamhelo:MIN:%4.0lf  ","GPRINT:check_spamhelo:AVERAGE:%4.0lf  ","GPRINT:maxcheck_spamhelo:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:other_denied#666666:".gettext("Denied e-mails")."\\: ".gettext("other reasons").":STACK","COMMENT:\\u","GPRINT:other_denied:LAST:%4.0lf  ","GPRINT:minother_denied:MIN:%4.0lf  ","GPRINT:other_denied:AVERAGE:%4.0lf  ","GPRINT:maxother_denied:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:tls_failed#990099:".gettext("Denied e-mails")."\\: ".gettext("tls failed").":STACK","COMMENT:\\u","GPRINT:tls_failed:LAST:%4.0lf  ","GPRINT:mintls_failed:MIN:%4.0lf  ","GPRINT:tls_failed:AVERAGE:%4.0lf  ","GPRINT:maxtls_failed:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:auth_failed#FFA500:".gettext("Denied e-mails")."\\: ".gettext("auth failed").":STACK","COMMENT:\\u","GPRINT:auth_failed:LAST:%4.0lf  ","GPRINT:minauth_failed:MIN:%4.0lf  ","GPRINT:auth_failed:AVERAGE:%4.0lf  ","GPRINT:maxauth_failed:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:spf#00004f:".gettext("Denied e-mails")."\\: ".gettext("spf").":STACK","COMMENT:\\u","GPRINT:spf:LAST:%4.0lf  ","GPRINT:minspf:MIN:%4.0lf  ","GPRINT:spf:AVERAGE:%4.0lf  ","GPRINT:maxspf:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:resolvable_fromhost#ff99ff:".gettext("Denied e-mails")."\\: ".gettext("resolvable_fromhost").":STACK","COMMENT:\\u","GPRINT:resolvable_fromhost:LAST:%4.0lf  ","GPRINT:minresolvable_fromhost:MIN:%4.0lf  ","GPRINT:resolvable_fromhost:AVERAGE:%4.0lf  ","GPRINT:maxresolvable_fromhost:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:karma#ffff00:".gettext("Denied e-mails")."\\: ".gettext("karma").":STACK","COMMENT:\\u","GPRINT:karma:LAST:%4.0lf  ","GPRINT:minkarma:MIN:%4.0lf  ","GPRINT:karma:AVERAGE:%4.0lf  ","GPRINT:maxkarma:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:check_basicheaders#ff00ff:".gettext("Denied e-mails")."\\: ".gettext("check_basicheaders").":STACK","COMMENT:\\u","GPRINT:check_basicheaders:LAST:%4.0lf  ","GPRINT:mincheck_basicheaders:MIN:%4.0lf  ","GPRINT:check_basicheaders:AVERAGE:%4.0lf  ","GPRINT:maxcheck_basicheaders:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:check_goodrcptto#00ffff:".gettext("Denied e-mails")."\\: ".gettext("check_goodrcptto").":STACK","COMMENT:\\u","GPRINT:check_goodrcptto:LAST:%4.0lf  ","GPRINT:mincheck_goodrcptto:MIN:%4.0lf  ","GPRINT:check_goodrcptto:AVERAGE:%4.0lf  ","GPRINT:maxcheck_goodrcptto:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:uribl#4c004c:".gettext("Denied e-mails")."\\: ".gettext("uribl").":STACK","COMMENT:\\u","GPRINT:uribl:LAST:%4.0lf  ","GPRINT:minuribl:MIN:%4.0lf  ","GPRINT:uribl:AVERAGE:%4.0lf  ","GPRINT:maxuribl:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:rhsbl#7f7f7f:".gettext("Denied e-mails")."\\: ".gettext("rhsbl").":STACK","COMMENT:\\u","GPRINT:rhsbl:LAST:%4.0lf  ","GPRINT:minrhsbl:MIN:%4.0lf  ","GPRINT:rhsbl:AVERAGE:%4.0lf  ","GPRINT:maxrhsbl:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:dnsbl#0000ff:".gettext("Denied e-mails")."\\: ".gettext("dnsbl").":STACK","COMMENT:\\u","GPRINT:dnsbl:LAST:%4.0lf  ","GPRINT:mindnsbl:MIN:%4.0lf  ","GPRINT:dnsbl:AVERAGE:%4.0lf  ","GPRINT:maxdnsbl:MAX:%4.0lf  \\r",
                 "COMMENT:\\n", "AREA:check_earlytalker#7c7cff:".gettext("Denied e-mails")."\\: ".gettext("check_earlytalker").":STACK","COMMENT:\\u","GPRINT:check_earlytalker:LAST:%4.0lf  ","GPRINT:mincheck_earlytalker:MIN:%4.0lf  ","GPRINT:check_earlytalker:AVERAGE:%4.0lf  ","GPRINT:maxcheck_earlytalker:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:fcrdns#827f00:".gettext("Denied e-mails")."\\: ".gettext("fcrdns").":STACK","COMMENT:\\u","GPRINT:fcrdns:LAST:%4.0lf  ","GPRINT:minfcrdns:MIN:%4.0lf  ","GPRINT:fcrdns:AVERAGE:%4.0lf  ","GPRINT:maxfcrdns:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:dmarc#7f0000:".gettext("Denied e-mails")."\\: ".gettext("dmarc").":STACK","COMMENT:\\u","GPRINT:dmarc:LAST:%4.0lf  ","GPRINT:mindmarc:MIN:%4.0lf  ","GPRINT:dmarc:AVERAGE:%4.0lf  ","GPRINT:maxdmarc:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:spam_denied#DAA520:".gettext("Denied e-mails")."\\: ".gettext("spam denied").":STACK","COMMENT:\\u","GPRINT:spam_denied:LAST:%4.0lf  ","GPRINT:minspam_denied:MIN:%4.0lf  ","GPRINT:spam_denied:AVERAGE:%4.0lf  ","GPRINT:maxspam_denied:MAX:%4.0lf  \\r",
                "COMMENT:\\n", "AREA:clamav#ff0000:".gettext("Denied e-mails")."\\: ".gettext("virus").":STACK","COMMENT:\\u","GPRINT:clamav:LAST:%4.0lf  ","GPRINT:minclamav:MIN:%4.0lf  ","GPRINT:clamav:AVERAGE:%4.0lf  ","GPRINT:maxclamav:MAX:%4.0lf  \\r",
                "COMMENT:\\n");

}
