#!/usr/bin/perl
# CHANGE ABOVE PATH TO MATCH YOUR PERL LOCATION! 
##############################################################################
# routers.cgi : Version v2.11
# Create router monitoring pages 
# 
# This code is covered by the Gnu GPL.  See the README file, or the Gnu
# web site for more details.
# Developed and tested with RRDTool v1.0.37, Perl 5.005_03, under Linux (RH6.1)
# Also tested with ActivePerl 5.6 with Apache under NT
# Note - 95th percentile calcs DO NOT WORK under RRDTool v1.0.24 or earlier
##############################################################################
# DONT FORGET TO CHANGE THE LOCATION OF THE CONFIG FILE DEFINED BELOW!
##############################################################################
use strict;
use CGI;              # for CGI
use File::Basename;   # for identifying filenames under different OSs
use Text::ParseWords; # for parsing MRTG .conf file
use FileHandle;       # to have multiple conf files in recursion
##############################################################################
# You MUST set this to the location of the configuration file!
# NT users: note that you will need to give a DOUBLE \ for a path separator
my ($conffile) = "/etc/mrtg/routers2.conf";
##############################################################################
my ($VERSION) = "v2.11";
my ($APPURL ) = "http://www.cheshire.demon.co.uk/pub/";
my ($APPMAIL) = "mailto:steve\@cheshire.demon.co.uk";
##############################################################################

my ($mtype,$gtype,$defgopts, $defgtype, $defrouter, $defif, $cookie, @cookies);
my ($gopts, $baropts, $defbaropts, $uopts);
my (%routers, %interfaces, %gtypes, @gorder, $querystring, $statistic);
my (%gstyles, @sorder, $gstyle, $defgstyle, %gstylenames);
my (%headeropts, @cfgfiles, $lastupdate, $workdir, $interval);
my ($pagetype);
my (%config) = ();
my ($graphsuffix) = "gif";
my ($NT) = 0;             # gets set to 1 if using NT 
my ($pathsep) = "/";      # gets set to "\\" if you have NT
my ($dailylabel) = "%k";  # gets set to "%H" if you have ActivePerl
my ($monthlylabel) = "%V";# use "%W" for alternate week numbering method
                          # gets set to %W if you have ActivePerl
my ($usesixhour) = 0;
my ($twinmenu) = 0;
my ($rrdoutput) = "";
my ($rrdxsize, $rrdysize);
my ($router, $interface);
my ($uselastupdate) = 0;
my ($ksym,$k,$M,$G) = ("K",1024,1024000,1024000000); # mixed option
my ($grouping) = 0;       # Do we group when sorting routers?
my ($group) = "";
my ($csvmime) = "text/comma-separated"; # MIME type for CSV downloads
my ($toptitle) = "Router Monitor"; # Title at top of page
my ($timezone) = 0;
my ($bits, $factor) = ("!bits",8);
my ($defbgcolour) = "#ffd0ff";
my ($menubgcolour) = "#d0d0d0";
my ($linkcolour) = "#2020ff";
my ($extra) = "";
my ($archiveme) = 0;
my ($archive) = "";
my ($myname) = 'routers2.cgi';
my ($debugmessage) = "";

########################################################################
# You MAY configure the descriptions in the lines below if you require
# or, remove some entries from the @sorder Styles list.
########################################################################

%gtypes = ( d=>"Daily",w=>"Weekly", m=>"Monthly",y=>"Yearly", 
	dwmy=>"All Graphs", dwmys=>"Compact", 6=>"6 hour",
	"m-"=>"Last Month", "w-"=>"Last week", "d-"=>"Yesterday", 
	"y-"=>"Last Year", x1=>"X1", x2=>"X2", x3=>"X3", x4=>"X4"
 );
@gorder = qw/d w m y dwmy dwmys/; # you might prefer to have the order reversed
# NOTE: the first word of these is the key used in the routers.conf for default
%gstyles = ( s=>"Short (PDA)", n=>"Normal (640x480)", t=>"Stretch", l=>"Long", 
	n2=>"Tall", l2=>"Big (800x600)", x2=>"Huge (1024x768)", x=>"ExtraLong",
	sbp=>"Palm III/V", nbp=>"Psion 3/3x/5", np=>"WinCE-1", sp=>"WinCE-2",
	l2p=>"Web TV" );
@sorder = qw/s t n n2 l l2 x x2 sbp nbp np l2p/; 
			# you might want to remove some of these

########################################################################
# Nothing else to configure after this line
########################################################################

# initialize CGI
use vars qw($q);
$q = new CGI;

my $meurl = $q->url();
$router = $interface = "";

#################################
# For sorting

sub numerically { 
	return ($a cmp $b) if( $a !~ /\d/ or $b !~ /\d/ );
	$a <=> $b; 
} 
my ( $traffic );
sub bytraffic {
	return -1 if(!$a or !$b or !$traffic);
	return -1 if(!defined $interfaces{$a}{$traffic}
		or !defined $interfaces{$b}{$traffic});
	$interfaces{$b}{$traffic} <=> $interfaces{$a}{$traffic};
}
sub byiflongdesc {
	my ( $da, $db ) = ( "#$a","#$b" );
	# is this an invalid interface?
	return 0 if(!defined $interfaces{$a} or !defined $interfaces{$b});
	return 1 if(!$interfaces{$a}{inmenu});
	return -1 if(!$interfaces{$b}{inmenu});
	if( defined $config{'targetnames-ifsort'} ) {
		if( $config{'targetnames-ifsort'} eq 'icon' ) {
			return $interfaces{$a}{icon} cmp $interfaces{$b}{icon}
				if($interfaces{$a}{icon} ne $interfaces{$b}{icon});
		} elsif( $config{'targetnames-ifsort'} eq 'mode' ) {
			return $interfaces{$a}{mode} cmp $interfaces{$b}{mode}
				if($interfaces{$a}{mode} ne $interfaces{$b}{mode});
		}
	} else {
		return $interfaces{$a}{mode} cmp $interfaces{$b}{mode}
			if($interfaces{$a}{mode} ne $interfaces{$b}{mode});
	}
	# we always sort by description in the end
	$da = $interfaces{$a}{shdesc} if( defined $interfaces{$a}{shdesc} );
	$db = $interfaces{$b}{shdesc} if( defined $interfaces{$b}{shdesc} );
	$da = $interfaces{$a}{desc} if( defined $interfaces{$a}{desc} );
	$db = $interfaces{$b}{desc} if( defined $interfaces{$b}{desc} );
	$da cmp $db;
}
sub byifdesc {
	my ( $da, $db ) = ( "#$a","#$b" );
	# is this an invalid interface?
	return 0 if(!defined $interfaces{$a} or !defined $interfaces{$b});
	return 1 if(!$interfaces{$a}{inmenu});
	return -1 if(!$interfaces{$b}{inmenu});

	if( defined $config{'targetnames-ifsort'} ) {
		if( $config{'targetnames-ifsort'} eq 'icon' ) {
			return $interfaces{$a}{icon} cmp $interfaces{$b}{icon}
				if($interfaces{$a}{icon} ne $interfaces{$b}{icon});
		} elsif( $config{'targetnames-ifsort'} eq 'mode' ) {
			return $interfaces{$a}{mode} cmp $interfaces{$b}{mode}
				if($interfaces{$a}{mode} ne $interfaces{$b}{mode});
		}
	} else {
		return $interfaces{$a}{mode} cmp $interfaces{$b}{mode}
			if($interfaces{$a}{mode} ne $interfaces{$b}{mode});
	}
	# we always sort by description in the end
	$da = $interfaces{$a}{shdesc} if( defined $interfaces{$a}{shdesc} );
	$db = $interfaces{$b}{shdesc} if( defined $interfaces{$b}{shdesc} );
	$da cmp $db;
}
sub bydesc { 
	my ( $da, $db ) = ($routers{$a}{desc}, $routers{$b}{desc});
#	if( $grouping ) {
#		my ( $ga ) = $routers{$a}{group};
#		my ( $gb ) = $routers{$b}{group};
#		$ga=$config{"targetnames-$ga"} if(defined $config{"targetnames-$ga"});
#		$gb=$config{"targetnames-$gb"} if(defined $config{"targetnames-$gb"});
#		my ( $c  ) = $ga cmp $gb;
#		if($c) {
# commented out so that selected group is NOT always first
#			return 1 if( $ga eq $group );
#			return -1 if( $gb eq $group );
#			return $c;
#		}
#	}
	$da = $a if ( ! $da );
	$db = $b if ( ! $db );
	$da cmp $db; 
}
sub byshdesc { 
	my ( $da, $db ) = ($routers{$a}{shdesc}, $routers{$b}{shdesc});
	if( $grouping ) {
		my ( $ga ) = $routers{$a}{group};
		my ( $gb ) = $routers{$b}{group};
		$ga=$config{"targetnames-$ga"} if(defined $config{"targetnames-$ga"});
		$gb=$config{"targetnames-$gb"} if(defined $config{"targetnames-$gb"});
		my ( $c  ) = $ga cmp $gb;
		if($c) {
# commented out so that selected group is NOT always first
#			return 1 if( $ga eq $group );
#			return -1 if( $gb eq $group );
			return $c;
		}
	}
	$da = $a if ( ! $da );
	$db = $b if ( ! $db );
	$da cmp $db; 
}

######################
# calculate short date string from given time index

sub shortdate($)
{
	my( $dformat ) = "%c"; # windows perl doesnt have %R
	my( $datestr, $fmttime ) = ("",0);
	return "DATE ERROR 1" if(!$_[0]);
	$fmttime = $_[0];
	$fmttime = time if(!$fmttime);	
	my( $sec, $min, $hour, $mday, $mon, $year ) = localtime($fmttime);
	# try to get local formatting
	$dformat = $config{'web-shortdateformat'}
		if(defined $config{'web-shortdateformat'});
	$dformat =~ s/&nbsp;/ /g;
	eval { require POSIX; };
	if($@) {
		$datestr = $mday."/".($mon+1)."/".($year-100);
	} else {
		$datestr = POSIX::strftime($dformat,
			0,$min,$hour,$mday,$mon,$year);
	}
	return "DATE ERROR 2" if(!$datestr);
	return $datestr;
}

#################################
# For string trims.  Remove leading and trailing blanks
sub trim($)
{
	my($x)=$_[0];
	$x=~s/\s*$//;
	$x=~s/^\s*//;
	$x;
}

#################################
# build up option string
sub optionstring(%)
{
	my(%o,$options);
	%o = %{$_[0]};

	$o{page}="graph" if(!defined $o{page});
	$o{xgtype}="$gtype" if($gtype and !defined $o{xgtype});
	$o{xmtype}="$mtype" if($mtype and !defined $o{xmtype});
	$o{xgstyle}="$gstyle" if($gstyle and !defined $o{xgstyle});
	$o{xgopts}="$gopts" if($gopts and !defined $o{xgopts});
	$o{bars}="$baropts" if($baropts and !defined $o{bars});
	$o{rtr}="$router" if($router and !defined $o{rtr});
	$o{if}="$interface" if($interface and !defined $o{if});
	$o{extra}="$extra" if($extra and !defined $o{extra});
	$o{uopts}="$uopts" if($uopts and !defined $o{uopts});

	$options = "";
	foreach ( keys %o ) {
		if( $o{$_} ) {
			$options .= "&" if ($options);
			$options .= "$_=".$q->escape($o{$_});
		}
	}
	return $options;
}

#################################
# Generate the javascript for the page header
sub make_javascript(%)
{
	my($js);
	my(%opa,%opb);

	return("function LoadMenu() { }") if($q->param('nomenu'));

	%opa = ( page=>"menu" );
	foreach ( keys %{$_[0]} ) { $opa{$_}=$_[0]->{$_}; }

	if( $twinmenu ) {
		%opb = %opa;
		$opa{xmtype} = "routers";
		$opb{page} = "menub"; $opb{xmtype} = "options";
		$js = "
function LoadMenu() 
{ 
	if(parent.menu){
		parent.menu.location = \"$meurl?".optionstring(\%opa)."#top\"; 
		parent.menub.location = \"$meurl?".optionstring(\%opb)."#top\"; 
	}
}";
	} else { # not twinmenu mode
		$opa{xmtype}="routers" 
		if($router eq "none" or (defined $opa{rtr} and $opa{rtr} eq "none"));
		$js = "
function LoadMenu() 
{ 
	if(parent.menu){
		parent.menu.location = \"$meurl?".optionstring(\%opa)."#top\"; 
	}
}";
	}

	return $js;
}

#################################
# Create a bar graph, as requested by the CGI parameters.
# This should be given two CGI parameters: IN and OUT.  Use GD libraries if
# available to make a simple bar with green bar and blue line. IN and OUT are
# supposed to be percentages.
sub do_bar()
{
	my( $gd, $black, $white, $green, $blue, $grey );
	my( $w, $h ) = (400,10);
	my($x);

	eval { require GD; };
	if($@) {
		# GD libraries not available.  So, redirect to error message graphic.
		print $q->redirect($config{'routers.cgi-iconurl'}."error.gif");
		return;
	}

	if( defined $q->param('L') ) 
		{ $w = $q->param('L') if($q->param('L') >100); }

	# We have GD.  So, make up a simple bar graphic and print it - after
	# giving the correct HTML headers of course.
	$gd = new GD::Image($w,$h);
	$black = $gd->colorAllocate(0,0,0);
	$white = $gd->colorAllocate(255,255,255);
	$green = $gd->colorAllocate(0,255,0);
	$blue  = $gd->colorAllocate(0,0,255);
	$grey  = $gd->colorAllocate(192,192,192);

	if( $q->param('IN') < 0 and $q->param('OUT') < 0) {
		# unknown data
		$gd->fill(1,1,$grey); # background
	} else {
		$gd->fill(1,1,$white); # background
		$x = $w * $q->param('IN') /100.0 ; 
		$gd->rectangle(0,0,$x-1,($h/2)-1,$green) if($x>1);
		$gd->fill(1,1,$green) if($x > 2);
		$x = $w * $q->param('OUT') /100.0 ; 
		#$gd->line($x,0,$x,$h-1,$blue) if($x>0);
		$gd->rectangle(0,$h/2,$x-1,$h-1,$blue) if($x>1);
		$gd->fill(1,$h-2,$blue) if($x > 2);
	}
	$gd->rectangle(0,0,$w-1,$h-1,$black); # box around it

	if( defined $config{'web-png'} and $config{'web-png'}=~/[1y]/i ) {
		print $q->header({ -type=>"image/png", -expires=>"now" });
		binmode STDOUT;
		print $gd->png();
	} else {
		print $q->header({ -type=>"image/gif", -expires=>"now" });
		binmode STDOUT;
		print $gd->gif();
	}
}

#################################
# Read in configuration file

# readconf: pass it a list of section names
sub readconf(@)
{
	my ($inlist, $i, @secs, $sec, $usersec);
	
	@secs = @_;
	%config = ();

	$usersec = "";
	$usersec = "user-".(lc $q->user_name) if( $q->user_name );

	# set defaults
	%config = (
		'routers.cgi-confpath' => ".",
		'routers.cgi-cfgfiles' => "*.conf *.cfg",
		'web-png' => 0
	);

	( open CFH, "<".$conffile ) || do {
		print $q->header({-expires=>"now"});	
		print $q->start_html({ -title => "Error", -bgcolor => "#ffd0d0"  });	
		print $q->h1("Error").$q->p("Cannot read config file $conffile.");
		print $q->end_html();
		exit(0);
	};

	$inlist=0;
	$sec = "";
	while( <CFH> ) {
		/^\s*#/ && next;
		/\[(.*)\]/ && do { 
			$sec = lc $1;
			$inlist=0;	
			foreach $i ( @secs ) {
				if ( $i eq $1 ) { $inlist=1; last; }
			}
			# override for additional sections
			# put it here so people cant break things easily
			if( !$inlist and 
				( $sec eq $extra or $sec eq $myname or $sec eq $usersec ) ) {
				$sec = 'routers.cgi'; $inlist = 1;
			}
			next;
		};
		# note final \s* to strip all trailing spaces (which works because
		# the *? operator is non-greedy!)  This should also take care of
		# stripping trailing CR if file created in DOS mode (yeuchk).
		if ( $inlist ) { /(\S+)\s*=\s*(\S.*?)\s*$/ and $config{"$sec-$1"}=$2; }
	}
	close CFH;
	
	# legacy support for old dbdrive directive
	if(defined $config{'routers.cgi-dbdrive'} 
		and $config{'routers.cgi-dbdrive'}) {
		$pathsep = "\\"; # and use the DOS path separator
		if( $config{'routers.cgi-dbpath'} !~ /^\w:/ ) {
			# backwards compatibility to add DB drive on, if not there already
			$config{'routers.cgi-dbpath'} = $config{'routers.cgi-dbdrive'}
				.":".$config{'routers.cgi-dbpath'};
		}
	}

	# Activate NT compatibility options.
	# $^O is the OS name, NT usually produces 'MSWin32'.  By checking for 'Win'
	# we should be able to cover most possibilities.
	if ( (defined $config{'web-NT'} and $config{'web-NT'}=~/[1y]/i) 
		or $^O =~ /Win/ or $^O =~ /DOS/i  ) {
		$dailylabel = "%H";   # Activeperl cant support %k option to strftime
		$monthlylabel = "%W"; # Activeperl cant support %V option either....
		$pathsep = "\\";
		$NT = 1;
	}

	# backwards compatibility for old v1.x users
	$config{'routers.cgi-iconurl'} = $config{'routers.cgi-iconpath'}
		if( !defined $config{'routers.cgi-iconurl'} 
			and defined $config{'routers.cgi-iconpath'} );

	# some path corrections: remove trailing path separators on f/s paths
	foreach ( qw/dbpath confpath graphpath graphurl/ ) {
		$config{"routers.cgi-$_"} =~ s/[\/\\]$//;
	}
	# and add a trailing path separator on URL paths...
	$config{'routers.cgi-iconurl'} = "/rrdicons/" 
		if(!defined $config{'routers.cgi-iconurl'} );
	$config{'routers.cgi-iconurl'} .= "/" 
		if( $config{'routers.cgi-iconurl'} !~ /\/$/ );

	# get list of configuration files
	@cfgfiles = ();
	foreach ( split " ", $config{'routers.cgi-cfgfiles'} ) {
		# this may push a 'undef' onto the list, if the glob doesnt match
		# anything.  We avoid this later...
		push @cfgfiles, glob($config{'routers.cgi-confpath'}.$pathsep.$_);
	}

	# fix defaultinterface, if not specified correctly
	if( defined $config{'routers.cgi-defaulttarget'} 
		and ! defined $config{'routers.cgi-defaultinterface'}  ) {
		$config{'routers.cgi-defaultinterface'} =
			$config{'routers.cgi-defaulttarget'} ;
	}
	if( defined $config{'routers.cgi-defaultinterface'} 
		and $config{'routers.cgi-defaultinterface'} !~ /^_/
	) {
		$config{'routers.cgi-defaultinterface'} =
			"__".$config{'routers.cgi-defaultinterface'};
		$config{'routers.cgi-defaultinterface'} = "_outgoing"
			if( $config{'routers.cgi-defaultinterface'} eq "__outgoing" );
		$config{'routers.cgi-defaultinterface'} = "_incoming"
			if( $config{'routers.cgi-defaultinterface'} eq "__incoming" );
	}

	# escaping
	if( $NT ) {
		$config{'routers.cgi-defaultrouter'} =~ s/\\/\//g
			if( defined $config{'routers.cgi-defaultrouter'} );
	}

	# allow [routers.cgi] section to override [web] section for some
	# parameters
	$config{'web-backurl'} = $config{'routers.cgi-backurl'}
		if(defined $config{'routers.cgi-backurl'});
}

#################################
# Read in files

###########################################################################
# identify the type of file/interface and set up defaults
sub inlist($@)
{
	my($pat) = shift @_;
	return 0 if(!defined $pat or !$pat or !@_);
	foreach (@_) { return 1 if( $_ and /$pat/i ); }
	return 0;
}
sub routerdefaults($)
{
	my( $key, $k, %identify );
	
	$k = $_[0];
	%identify = ();
	$identify{icon} = guess_icon(1,$k, $routers{$k}{shdesc}, $routers{$k}{hostname} );

	foreach $key ( keys %identify ) {
		$routers{$k}{$key} = $identify{$key} if(!$routers{$k}{$key} );
	}
}
# possible MODEs: interface, cpu, memory, generic (more to come) 
sub identify($) {
	my( $key, %identify, $k, @d, $mode );
	my($unit,$totunit,$okfile);
	my($timel, $times);

	$k = $_[0];

	# description defaults
	if(defined $config{"targetnames-$k"}) {
		$interfaces{$k}{shdesc} = $config{"targetnames-$k"};
	}
	if(defined $config{"targettitles-$k"}) {
		$interfaces{$k}{desc} = $config{"targettitles-$k"};
	}
	if(!defined $interfaces{$k}{shdesc}) {
		if(!defined $config{'targetnames-ifdefault'}
			or $config{'targetnames-ifdefault'} !~ /target/ ) {
			if(defined $interfaces{$k}{ipaddress}) {
				$interfaces{$k}{shdesc} = $interfaces{$k}{ipaddress};
			} elsif(defined $interfaces{$k}{ifdesc}) {
				$interfaces{$k}{shdesc} = $interfaces{$k}{ifdesc};
			} elsif(defined $interfaces{$k}{ifno}) {
				$interfaces{$k}{shdesc} = "#".$interfaces{$k}{ifno};
			} else {
#				$interfaces{$k}{desc} =~ /^(\S+)/;
#				$interfaces{$k}{shdesc} = $1;
				$interfaces{$k}{shdesc} = $interfaces{$k}{desc};
			}
		}
		$interfaces{$k}{shdesc} = $k if(!defined $interfaces{$k}{shdesc});
	}

	# try and identify the interface
	@d = ( $k, $interfaces{$k}{desc}, $interfaces{$k}{shdesc} );
	$mode = "";
	$mode = $interfaces{$k}{mode} if(defined $interfaces{$k}{mode});
	%identify = ();
	if(! $mode) {
		if( inlist( "cpu", @d ) and ($interfaces{$k}{maxbytes}==100) )
			{ $mode = "cpu"; }
		elsif( defined $interfaces{$k}{ifno} or defined $interfaces{$k}{ifdesc} 
			or $interfaces{$k}{isif} or  defined $interfaces{$k}{ipaddress} ) 
			{ $mode = "interface"; $interfaces{$k}{isif} = 1; }
		elsif( inlist( "interface", @d ) or inlist("serial",@d)
			or inlist( "ATM", @d )  or inlist( "port", @d ))
			{ $mode = "interface"; }
		elsif( inlist( "mem", @d ) ) { $mode = "memory"; }
		else { $mode = "generic"; }
		$interfaces{$k}{mode} = $mode;
	}

	# set appropriate defaults for thismode
	if(!defined $interfaces{$k}{mult}) { 
		if($mode eq "interface" and 
			(!defined $config{'routers.cgi-bytes'} 
			or $config{'routers.cgi-bytes'} !~ /y/ )
		) { $interfaces{$k}{mult} = 8; }
		else { $interfaces{$k}{mult} = 1; }
	}
	
	# defaults for everything...
	$timel = "second"; $times = "s"; $unit = ""; $totunit = "";
	if($mode eq "interface") { $totunit = "bytes"; }
	if($interfaces{$k}{mult} > 3599 ) {
		$timel = "hour"; $times = "hr";
		if($interfaces{$k}{mult} > 3600) { $totunit = "bits"; }
	} elsif($interfaces{$k}{mult} >59 ) {
		$timel = "minute"; $times = "min";
		if($interfaces{$k}{mult} > 60) { $totunit = "bits"; }
	} elsif($interfaces{$k}{mult} > 1) { $totunit = "bits"; }
	$unit = "$totunit/$times";
	$unit = "bps" if($unit eq "bits/s");
	$identify{ylegend} = "per $timel";
	$identify{background} = $defbgcolour;
	$identify{legendi} = "In: ";
	$identify{legendo} = "Out:";
	$identify{legend1} = "Incoming" ;
	$identify{legend2} = "Outgoing";
	$identify{legend3} = "Peak inbound";
	$identify{legend4} = "Peak outbound";
	$identify{total} = 1;
	$identify{percentile} = 1;
	$identify{percent} = 1;
	$identify{unit} = $unit;
	$identify{totunit} = $totunit;
	$identify{unscaled} = "";

	if($mode eq "interface") {
		$identify{ylegend} = "traffic in $unit";
		$identify{legendi} = "In: ";
		$identify{legendo} = "Out:";
		$identify{legend1} = "Incoming traffic";
		$identify{legend2} = "Outgoing traffic";
		$identify{legend3} = "Peak inbound traffic";
		$identify{legend4} = "Peak outbound traffic";
		$identify{icon} = "interface-sm.gif";
		$identify{background} = "#ffffff";
		$identify{unscaled} = "6dwmy";
		$identify{total} = 1;
	} elsif( $mode eq "cpu" ) {
		$identify{ylegend} = "Percentage use";
		$identify{legendi} = "CPU";
		$identify{unit} = "%";
		$identify{fixunits} = 1;
		$identify{totunit} = "";
		$identify{legend1} = "CPU usage";
		$identify{legend3} = "Peak CPU usage";
		$identify{legend2} = "";
		$identify{legend4} = "";
		$identify{icon} = "cpu-sm.gif";
		$identify{background} = "#ffffd0";
		$identify{unscaled} = "6dwmy";
		$identify{percent} = 0;
		$identify{total} = 0;
	} elsif( $mode eq "memory" ) {
		$identify{ylegend} = "Bytes used";
		$identify{legendi} = "MEM";
		$identify{legendo} = "MEM";
		$identify{legend1} = "Memory usage";
		$identify{legend3} = "Peak memory usage";
		$identify{legend2} = "Sec. memory usage";
		$identify{legend4} = "Peak sec memory usage";
		$identify{icon} = "cpu-sm.gif";
		$identify{background} = "#d0d0ff";
		$identify{total} = 0;
		$identify{unit} = "bytes"; 
		$identify{unit} = "bits" if($interfaces{$k}{bits}); 
		$identify{totunit} = "";
	}

	# unscaled default option
	if( defined $config{'routers.cgi-unscaled'} ) {
		if( $config{'routers.cgi-unscaled'} =~ /y/i ) {
			$identify{unscaled} = "6dwmy" ;
		} else {
			$identify{unscaled} = "" ;
		}
	}

	# set icon
	$identify{icon} = guess_icon( 0, $k, $interfaces{$k}{desc}, $interfaces{$k}{shdesc} ) if(!defined $identify{icon});

	# set the defaults
	foreach $key ( keys %identify ) {
		$interfaces{$k}{$key} = $identify{$key} 
			if(!defined $interfaces{$k}{$key} );
	}

	$interfaces{$k}{mult} = 1 if(!defined $interfaces{$k}{mult});
	$interfaces{$k}{maxbytes} = 0 if(!defined $interfaces{$k}{maxbytes});
	$interfaces{$k}{max} = $interfaces{$k}{maxbytes} * $interfaces{$k}{mult};
	$interfaces{$k}{max1} = $interfaces{$k}{maxbytes1} * $interfaces{$k}{mult}
		if(defined $interfaces{$k}{maxbytes1});
	$interfaces{$k}{max2} = $interfaces{$k}{maxbytes2} * $interfaces{$k}{mult}
		if(defined $interfaces{$k}{maxbytes2});
	$interfaces{$k}{max} = $interfaces{$k}{max1} if(defined $interfaces{$k}{max1} and $interfaces{$k}{max1} > $interfaces{$k}{max} );
	$interfaces{$k}{max} = $interfaces{$k}{max2} if(defined $interfaces{$k}{max2} and $interfaces{$k}{max2} > $interfaces{$k}{max} );
	$interfaces{$k}{absmax} 
		= $interfaces{$k}{absmaxbytes} * $interfaces{$k}{mult}
		if(defined $interfaces{$k}{absmaxbytes});
	if(defined $interfaces{$k}{factor} ) {
		$interfaces{$k}{max} *= $interfaces{$k}{factor};
		$interfaces{$k}{absmax} *= $interfaces{$k}{factor}	
			if(defined $interfaces{$k}{absmax});
		$interfaces{$k}{max1} *= $interfaces{$k}{factor}	
			if(defined $interfaces{$k}{max1});
		$interfaces{$k}{max2} *= $interfaces{$k}{factor}	
			if(defined $interfaces{$k}{max2});
	}
	$interfaces{$k}{noo} = 1 if(!$interfaces{$k}{legend2});
	$interfaces{$k}{noi} = 1 if(!$interfaces{$k}{legend1});

	# catch the stupid people
	if($interfaces{$k}{noo} and $interfaces{$k}{noi}) {
		$interfaces{$k}{inmenu} = 0;
		$interfaces{$k}{insummary} = 0;
		$interfaces{$k}{inout} = 0;
	}

}
# guess an appropriate icon.  1st param is 1 for devices menu, 0 for targets
# other parameters are a list of attributes to check
sub guess_icon($@)
{
	my($m) = shift @_;

	if($m) {
		# these tests for devices menu only
		return "cisco-sm.gif" if( inlist "cisco",@_ );
		return "3com-sm.gif" if( inlist "3com",@_ );
		return "intel-sm.gif" if( inlist "intel",@_ );
		return "router-sm.gif" if( inlist "router",@_ );
		return "switch-sm.gif" if( inlist "switch",@_ );
		return "firewall-sm.gif" if( inlist "firewall",@_ );
		return "ibm-sm.gif" if( inlist "ibm",@_ );
		return "linux-sm.gif" if( inlist "linux",@_ );
		return "freebsd-sm.gif" if( inlist "bsd",@_ );
		return "novell-sm.gif" if( inlist "novell",@_ );
# these commented out as patterns are too short to be reliable
#		return "mac-sm.gif" if( inlist "mac|apple",@_ );
#		return "sun-sm.gif" if( inlist "sun",@_ );
#		return "hp-sm.gif" if( inlist "hp",@_ );
		return "win-sm.gif" if( inlist "windows",@_ );
	}
	return "mail-sm.gif"    if( inlist 'mail|messages',@_ );
	return "web-sm.gif"     if( inlist 'internet',@_  or inlist 'proxy',@_ );
	return "phone-sm.gif"   if( inlist 'phone',@_ );
	return "modem-sm.gif"   if( inlist 'modem',@_ );
	return "disk-sm.gif"    if( inlist 'nfs\w',@_ or inlist 'dsk',@_ );
	return "globe-sm.gif"   if( inlist 'dns\w',@_ );
	return "people-sm.gif"  if( inlist 'user[s ]',@_ );
	return "server-sm.gif"  if( inlist 'server|host',@_ );
	return "web-sm.gif"     if( inlist 'web',@_ );
	return "traffic-sm.gif" if( inlist 'traffic',@_ );
	return "chip-sm.gif"    if( inlist 'memory|cpu',@_ );
	return "interface-sm.gif" if(!$m and  inlist 'interface|serial',@_ );
	return "disk-sm.gif"    if( inlist 'dis[kc]|filesystem',@_ );
	return "clock-sm.gif"   if( inlist 'time|rtt|ping',@_ );
	return "temp-sm.gif"    if( inlist 'temp|climate|environment|heat',@_ );
	return "menu-sm.gif"    if( inlist '\wlog',@_ );
	return "interface-sm.gif" if(!$m and  inlist 'BRI|eth|tok|ATM|hme',@_ );
	return "load-sm.gif"    if( inlist 'load|weight',@_ );
	return "web-sm.gif"     if( inlist 'www',@_ );
	
	if($m) {
		# last chance with these less reliable ones
		return "mac-sm.gif" if( inlist "mac|apple",@_ );
		return "sun-sm.gif" if( inlist "sun",@_ );
		return "hp-sm.gif"  if( inlist "hp",@_ );
		return "win-sm.gif" if( inlist "win|pdc|bdc",@_ );
	}

	if($m) {
		return $config{'targeticons-filedefault'} 
			if(defined $config{'targeticons-filedefault'});
		return "menu-sm.gif";
	} else {
		return $config{'targeticons-ifdefault'} 
			if(defined $config{'targeticons-ifdefault'});
		return "target-sm.gif";
	}
}


# read in all routers files.

# routers hash: key= filename (within confpath)
#         data: hash: 
#               keys: filename (full), shdesc, desc, inmenu, hasinout
#                     group, icon

my ( $readinrouters ) = 0;
sub read_routers()
{
	my( $matchstr, $curfile, $curpat, $key, $bn, $group, $f );
	my( $arg, $desc, $url, $icon, $targ );

	return if($readinrouters);

	%routers = ();

	for $curpat ( split " ",$config{'routers.cgi-cfgfiles'} ) {
FILE:	for $curfile (glob($config{'routers.cgi-confpath'}.$pathsep.$curpat)) {
			$key = $curfile;
			$matchstr = $config{'routers.cgi-confpath'}.$pathsep;
			$matchstr =~ s/\\/\\\\/g;
			$key =~ s/^$matchstr//;
			$f = $bn = basename($curfile,'');
			$f =~ s/\.c(fg|onf)$//;
			$group = dirname($curfile);
			# set the defaults
			$routers{$key} = { 
				file=>$curfile, inmenu=>1, group=>$group, icon=>"",
				interval=>5, hastarget=>0
			};

			# read the file for any overrides
			open CFG,"<$curfile" || do {
#				$routers{$key}{inmenu}=0;
				$routers{$key}{desc}="Error opening file";
				$routers{$key}{icon}="alert-sm.gif";
				next;
			};
LINE:		while( <CFG> ) {
				/^\s*#/ && next;
				/^\s*routers\.cgi\*Options\s*:\s*(.*)/i and do {
					$routers{$key}{inmenu} = 0 if($1 =~ /ignore/i );
					next;
				};
				/^\s*routers\.cgi\*(Descr?|Name)\s*:\s*(.*)/i and do {
					$routers{$key}{desc} = $2;
					next;
				};
				/^\s*routers\.cgi\*Short(Descr?|Name)\s*:\s*(.*)/i and do {
					$routers{$key}{shdesc} = $2;
					next;
				};
				if( /^\s*Target\[\S+\]\s*:.*@([^:\s]+)/i ) {
					$routers{$key}{hostname}=$1;
					$routers{$key}{hastarget}=1;
					next;
				}
				if( /^\s*Target\[\S+\]/i ) {
					$routers{$key}{hastarget}=1;
					next;
				}
				if( /^\s*Include\s*:/i ) {
					$routers{$key}{hastarget}=1; # make the assumption
					next;
				}
				if( /^\s*Title\[\S+\]\s*:\s*(.*)/i ) {
					$routers{$key}{firsttitle}=$1;
					last if(defined $routers{$key}{hostname});
					next;
				}
				if( /^\s*routers\.cgi\*Icon\s*:\s*(.*)/i ) {
					$routers{$key}{icon}=$1;
					next;
				}
				if( /^\s*WorkDir\s*:\s*(.*)/i ) {
					$routers{$key}{workdir}=$1;
					next;
				}
				if( /^\s*Interval\s*:\s*(\d+)/i ) {
					$routers{$key}{interval}=$1;
					next;
				}
				if( /^\s*routers\.cgi\*Ignore\s*:\s*(\S+)/i ) {
					$arg = $1;
					if($arg =~ /y/i) {
						delete $routers{$key};
						next FILE;
					}
					next;
				}
				if( /^\s*routers\.cgi\*InMenu\s*:\s*(\S+)/i ) {
					$arg = $1;
					$routers{$key}{inmenu}=0 if($arg =~ /n/i);
					next;
				}
				if( /^\s*routers\.cgi\*RoutingTable\s*:\s*(\S+)/i ) {
					$arg = $1;
					$routers{$key}{routingtable}="n" if($arg =~ /n/i);
					next;
				}
				if( /^\s*routers\.cgi\*Extensions?\s*:\s*(\S.*)/i ) {
					$arg = $1;
					( $desc, $url, $icon, $targ ) = quotewords('\s+',0,$arg);
					
					next if(!$url or !$desc);
					if( $icon !~ /\.(gif|png)$/  and !$targ ) {
						$targ = $icon; $icon = "";
					}
					$icon = "cog-sm.gif" if (!$icon);
					$targ = "graph" if(!$targ);
					$routers{$key}{extensions} = [] 
						if(!defined $routers{$key}{extensions});
					push @{$routers{$key}{extensions}}, 
						{desc=>$desc, url=>$url, icon=>$icon, target=>$targ };
					# brace yourselves for this one....
#$routers{$key}{extensions}->[$#{$routers{$key}{extensions}}]->{target}=$targ 
#						if($targ);
					next;
				}
			}
			close CFG;

			# desc default
			if(!$routers{$key}{shdesc}) {
				if($config{'targetnames-routerdefault'} =~ /hostname/ ) {
					if(defined $routers{$key}{hostname} ) {
						$routers{$key}{shdesc} = $routers{$key}{hostname};
					} else {
						$routers{$key}{shdesc} = $f;
					}
				} elsif($config{'targetnames-routerdefault'} =~ /ai/
					and defined $routers{$key}{firsttitle} ) {
					$routers{$key}{firsttitle} =~ /([^\s:\(]+)/;
					$routers{$key}{shdesc} = $1;
					$routers{$key}{desc} = $routers{$key}{firsttitle};
				} else {
					$routers{$key}{shdesc} = $f;
#					$routers{$key}{desc} = $curfile if(!$routers{$key}{desc});
				}
			}
			$routers{$key}{desc} = $routers{$key}{shdesc}
				if(!$routers{$key}{desc});

			# check routers.conf for any overrides
			if(defined $config{"targetnames-$bn"}) {
				$routers{$key}{shdesc} = $config{"targetnames-$bn"};
				$routers{$key}{desc} = $config{"targetnames-$bn"}; 
			}
			$routers{$key}{desc} = $config{"targettitles-$bn"}
				if(defined $config{"targettitles-$bn"});
			$routers{$key}{icon} = $config{"targeticons-$bn"}
				if(defined $config{"targeticons-$bn"});

			routerdefaults $key;
		} # files
	} # patterns

	foreach $key ( keys %routers ) {
		$routers{$key}{inmenu} = 0 if(!$routers{$key}{hastarget});
	}

	if( $config{'routers.cgi-servers'} ) {
		foreach ( keys %config ) {
			if( /^servers-(\S+)/i ) {
				$routers{"#SERVER#$1"} = { 
					file=>"", inmenu=>1, group=>"SERVERS", 
					icon=>"server-sm.gif", server=>$1, interval=>5, 
					hastarget=>1, inmenu=>1, desc=>$config{$_},
					shdesc=>$config{$_}
				};
				$routers{"#SERVER#$1"}{icon} = $config{"targeticons-$1"}
					if(defined $config{"targeticons-$1"});
			}
		}
	}

	$readinrouters = 1;
}

###########################################################################
# set pseudointerfaces for a server target
sub set_svr_ifs()
{
	my( $server );

	%interfaces = ();
	$server = $router;
	$server =~ s/^#SERVER#//;

	$interfaces{"CPU"} = { file=>"",  icon=>"chip-sm.gif",
		rrd=>($config{'routers.cgi-dbpath'}.$pathsep."$server.rrd"), 
		shdesc=>"CPU Usage", mult=>1, unit=>"%", fixunits=>1,
		legendi=>"User:", legendo=>"System:", ylegend=>"Percentage",
		legend1=>"User processes", legend2=>"System Processes",
		legend3=>"Max User Processes", legend4=>"Max System processes",
		legendx=>"System Wait", legendxx=>"Max system wait",
		desc=>"CPU Usage on $server", mode=>"SERVER", hostname=>$server,
		insummary=>1, incompact=>0, inmenu=>1, isif=>0, inout=>0,
		interval=>5, nomax=>1, noabsmax=>1, maxbytes=>100, max=>100  };
	$interfaces{"Users"} = { file=>"",   mult=>1,icon=>"people-sm.gif",
		rrd=>($config{'routers.cgi-dbpath'}.$pathsep."$server.rrd"), 
		shdesc=>"Users", noo=>1, integer=>1, percent=>0, fixunits=>1,
		ylegend=>"User count",
		legendi=>"Users:", legend1=>"User count", legend3=>"Max user count",
		desc=>"User count on $server", mode=>"SERVER", hostname=>$server,
		insummary=>1, incompact=>0, inmenu=>1, isif=>0, inout=>0,
		interval=>5, nomax=>1, noabsmax=>1, maxbytes=>10000  };
	$interfaces{"Page"} = { file=>"",   mult=>1, icon=>"disk-sm.gif",
		rrd=>($config{'routers.cgi-dbpath'}.$pathsep."$server.rrd"), 
		shdesc=>"Paging", noo=>1, unit=>"pps", fixunits=>1,
		legendi=>"Activity:", legend1=>"Paging activity", 
		legend3=>"Max paging activity", percent=>0, ylegend=>"Pages per second",
		desc=>"Paging activity on $server", mode=>"SERVER", hostname=>$server,
		insummary=>1, incompact=>0, inmenu=>1, isif=>0, inout=>0,
		interval=>5, nomax=>1, noabsmax=>1, maxbytes=>10000  };
}

###########################################################################
# read in a specified cfg file (default to current router file)

# interfaces hash: key= targetname
#            data: hash:
#            keys: lots.

sub read_cfg_file($)
{
	my($cfgfile) = $_[0];
	my($opts, $graph, $key, $k, $fd, $buf, $curif, @myifs, $arg);
	my($ifcnt, @ifarr, $t, $desc, $url, $icon, $targ, $newfile, $targfile);
	my( $lasthostname, $lastcommunity ) = ("","");

	my( $inpagetop, $inpagefoot ) = (0,0);

	return if(!$cfgfile);

	$debugmessage .= "$cfgfile ";

	$fd = new FileHandle ;

	if(! $fd->open( "<$cfgfile" )) {
		$interfaces{$cfgfile} = {
			shdesc=>"Error", desc=>"Cannot open file $cfgfile", inmenu=>0,
			rrd=>"", insummary=>0, inout=>0, incompact=>0, mode=>"ERROR",
			icon=>"alert-sm.gif" };
		return;
	}

	$key = ""; $curif = ""; @myifs = ();
	while ( $buf = <$fd> ) {
		next if( $buf =~ /^\s*#/ );
		next if( $buf =~ /^\s*$/ ); # bit more efficient
		if( $inpagefoot ) {
			if( $curif and $buf =~ /^\s+\S/ ) {
				$interfaces{$curif}{pagefoot} .= $buf;
				next;
			}
			$inpagefoot = 0;
		}
		if( $inpagetop ) {
			if( $curif and $buf =~ /^\s+\S/ ) {
				$interfaces{$curif}{pagetop} .= $buf;
				next;
			}
			$inpagetop = 0;
		}
		if( $buf =~ /^\s*Target\[(\S+)\]\s*:\s*(.+)/i ) {
			$curif = $1; $arg = $2;
			next if(defined $interfaces{$curif});
			push @myifs, $curif;
			$interfaces{$curif} = { file=>$cfgfile, target=>$curif,
					insummary=>1, incompact=>1, inmenu=>1, isif=>0,
					interval=>$interval, nomax=>0, noabsmax=>0  };
			$interfaces{$curif}{rrd} = $workdir.$pathsep.(lc $curif).".rrd";
			if( $arg =~ /^-?(\d+):([^\@:\s]+)\@([\w\-\.]+)/ ) {
				# interface number
				$interfaces{$curif}{isif} = 1;
				$interfaces{$curif}{ifno} = $1;
				$interfaces{$curif}{community} = $2;
				$interfaces{$curif}{hostname} = $3;
				$interfaces{$curif}{mode} = "interface";
			} elsif( $arg =~ /^-?\/(\d+\.\d+\.\d+\.\d+):([^\@:\s]+)\@([\w\-\.]+)/ ) {
				# IP address
				$interfaces{$curif}{isif} = 1;
				$interfaces{$curif}{ipaddress} = $1;
				$interfaces{$curif}{community} = $2;
				$interfaces{$curif}{hostname} = $3;
				$interfaces{$curif}{mode} = "interface";
			} elsif( $arg =~ /^-?[\\#!](\S.*?):([^\@:\s]+)\@([\w\-\.]+)/ ) {
				$interfaces{$curif}{isif} = 1;
				$interfaces{$curif}{ifdesc} = $1;
				$interfaces{$curif}{community} = $2;
				$interfaces{$curif}{hostname} = $3;
				$interfaces{$curif}{mode} = "interface";
				$interfaces{$curif}{ifdesc} =~ s/\\(.)/\1/g ;
			} elsif( $arg =~ /&\w*[\d\.]+:(\S+)\@([\w\-\.]+)/ ) {
				# explicit OIDs
				$interfaces{$curif}{community} = $1;
				$interfaces{$curif}{hostname} = $2;
			} elsif( $arg =~ /`/ ) {
				# external program
				$interfaces{$curif}{insummary} = 1;
				$interfaces{$curif}{incompact} = 1;
			} else { # a target of some sort we dont yet know
				$interfaces{$curif}{insummary} = 0;
				$interfaces{$curif}{incompact} = 0;
			}
			$interfaces{$curif}{inout} = $interfaces{$curif}{isif};
			foreach $k ( qw/isif inout incompact insummary inmenu/ ) {
				$interfaces{$curif}{$k} = $interfaces{'_'}{$k}
					if(defined $interfaces{'_'}{$k});
			}
			$lasthostname = $interfaces{$curif}{hostname}
				if(defined $interfaces{$curif}{hostname});
			$lastcommunity= $interfaces{$curif}{community}
				if(defined $interfaces{$curif}{community});
			next;
		}
		if( $buf =~ /^\s*(routers\.cgi\*)?(Title|Descr?)\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $3; $arg = $4;
			if(!defined $interfaces{$curif}) {
				$curif = "_$curif";
				next if(!defined $interfaces{$curif});
			}
			$interfaces{$curif}{desc} = $arg;
			next;
		}
		if( $buf =~ /^\s*Options\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $1;
			next if(!defined $interfaces{$curif});
			$interfaces{$curif}{options} = "" if(!$interfaces{$curif}{options});
			$interfaces{$curif}{options} .= ' '.$2;
			next;
		}
		if( $buf =~ /^\s*(routers\.cgi\*)?PageTop\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $2;  $arg = $3;
			next if(!defined $interfaces{$curif});
			$interfaces{$curif}{pagetop} = $arg;
			$inpagetop = 1;
			next;
		}
		if( $buf =~ /^\s*(routers\.cgi\*)?PageFoot\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $2;  $arg = $3;
			next if(!defined $interfaces{$curif});
			$interfaces{$curif}{pagefoot} = $arg;
			$inpagefoot = 1;
			next;
		}
		if( $buf =~ /^\s*SetEnv\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $1; $arg = $2;
			next if(!defined $interfaces{$curif});
			foreach $k ( quotewords('\s+',0,$arg) ) {
				if( $k =~ /MRTG_INT_IP=\s*(\d+\.\d+\.\d+\.\d+)/ ) {
					$interfaces{$curif}{ipaddress}=$1
					if(!defined $interfaces{$curif}{ipaddress});
					next;
				}
				if( $k =~ /MRTG_INT_DESCR?=\s*(\S.*)/ ) {
					$interfaces{$curif}{shdesc}=$1
					if(!defined $interfaces{$curif}{shdesc});
					next;
				}
			}
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*Short(Name|Descr?)\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $2; $arg = $3;
			$curif = "_".$curif if(!defined $interfaces{$curif});
			next if(!defined $interfaces{$curif});
			$interfaces{$curif}{shdesc} = $arg if($arg);
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*Options\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			next if(!defined $interfaces{$1});
			$interfaces{$1}{cgioptions}="" if(!$interfaces{$1}{cgioptions});
			$interfaces{$1}{cgioptions} .= " ".$2;
			next;
		}
		if( $buf =~ /^\s*(routers\.cgi\*)?MaxBytes\[(\S+)\]\s*:\s*(\d+)/i ) { 
			next if(!defined $interfaces{$2});
			$interfaces{$2}{maxbytes} = $3;
			next;
		}
		if($buf=~ /^\s*(routers\.cgi\*)?Unscaled\[(\S+)\]\s*:\s*([6dwmy]*)/i){ 
			next if(!defined $interfaces{$2});
			$interfaces{$2}{unscaled} = $3;
			next;
		}
		if($buf=~ /^\s*(routers\.cgi\*)?WithPeak\[(\S+)\]\s*:\s*([dwmy]*)/i) { 
			next if(!defined $interfaces{$2});
			$interfaces{$2}{withpeak} = $3;
			next;
		}
		if( $buf =~ /^\s*(routers\.cgi\*)?YLegend\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $2;
			$curif = "_$curif" if(!defined $interfaces{$curif});
			next if(!defined $interfaces{$curif});
			$interfaces{$curif}{ylegend} = $3;
			next;
		}
		if($buf=~ /^\s*(routers\.cgi\*)?ShortLegend\[(\S+)\]\s*:\s*(.*)/i){ 
			next if(!defined $interfaces{$2});
			$interfaces{$2}{unit} = $3;
			$interfaces{$2}{unit} =~ s/&nbsp;/ /g;
			next;
		}
		if($buf=~ /^\s*routers\.cgi\*TotalLegend\[(\S+)\]\s*:\s*(.*)/i){ 
			$curif = $1; $arg = $2;
			next if(!defined $interfaces{$curif});
			$arg =~ s/&nbsp;/ /g;
			$interfaces{$curif}{totunit} = $arg;
			next;
		}
		if( $buf =~ /^\s*(routers\.cgi\*)?(Legend[IO1234TA][IO]?)\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $3; $key = lc $2; $arg = $4;
			$curif = "_$curif" if(!defined $interfaces{$curif});
			next if(!defined $interfaces{$curif});
			$arg =~ s/&nbsp;/ /;
			$interfaces{$curif}{$key} = $arg;
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*Mode\[(\S+)\]\s*:\s*(\S+)/i ) {
			next if(!defined $interfaces{$1});
			$interfaces{$1}{mode} = $2;
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*RoutingTable\s*:\s*(\S.*)/i ) {
			$arg = $1;
			$routers{$router}{routingtable} = "n" if($arg =~ /n/i);
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*Extensions?\s*:\s*(\S.*)/i 
			and !$readinrouters) {
			$arg = $1;
			( $desc, $url, $icon, $targ ) = quotewords('\s+',0,$arg);
			next if(!$url or !$desc);
			if( $icon !~ /\.(gif|png)$/ and !$targ) {
				$targ = $icon; $icon = "";
			}
			$icon = "cog-sm.gif" if(!$icon);
			$targ = "graph" if(!$targ);
			$routers{$router}{extensions} = [] 
				if(!defined $routers{$router}{extensions});
			push @{$routers{$router}{extensions}}, 
				{desc=>$desc, url=>$url, icon=>$icon, target=>$targ,
				hostname=>$lasthostname, community=>$lastcommunity};
#$routers{$router}{extensions}->[$#{$routers{$router}{extensions}}]->{target}
#					= $targ if($targ);
					next;
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*Extensions?\[(\S+)\]\s*:\s*(\S.*)/i ) {
			$curif = $1; $arg = $2;
			( $desc, $url, $icon, $targ ) = quotewords('\s+',0,$arg);
			next if(!$url or !$desc);
			if( $icon !~ /\.(gif|png)$/ and !$targ ) {
				$targ = $icon; $icon = "";
			}
			$icon = "cog-sm.gif" if(!$icon);
			$targ = "graph" if(!$targ);
			$interfaces{$curif}{extensions} = [] 
				if(!defined $interfaces{$curif}{extensions});
			push @{$interfaces{$curif}{extensions}}, 
				{ desc=>$desc, url=>$url, icon=>$icon, target=>$targ };
#$interfaces{$curif}{extensions}->[$#{$interfaces{$curif}{extensions}}]->{target}
#					= $targ if($targ);
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*Link\[(\S+)\]\s*:\s*(\S.*)/i ) {
			$curif = $1; $arg = $2;
			( $desc, $targfile, $targ, $icon ) = quotewords('\s+',0,$arg);
			next if(!$targfile or !$desc);
			if( $targ =~ /\.(gif|png)$/ and !$icon ) {
				$icon = $targ; $targ = "";
			}
			$icon = "target-sm.gif" if(!$icon);
			$url = $meurl."?rtr=".$q->escape($targfile)
				."&if=".$q->escape($targ)."&page=graph&xmtype=options";
			$interfaces{$curif}{extensions} = [] 
				if(!defined $interfaces{$curif}{extensions});
			push @{$interfaces{$curif}{extensions}}, 
				{ desc=>$desc, url=>$url, icon=>$icon, target=>"graph" };
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*Graph\[(\S+)\]\s*:\s*(\S.*)/i ) {
			$curif = $1; $arg = $2;
			$arg =~ /^(\S+)\s*:?(.*)/;
			$opts = $2; $graph = $1;
				next if(!$graph);
			$interfaces{$curif}{usergraphs} = [] 
				if(!defined $interfaces{$curif}{usergraphs});
			push @{$interfaces{$curif}{usergraphs}}, $graph;
			if( defined $interfaces{"_$graph"} ) {
				push @{$interfaces{"_$graph"}{targets}}, $curif;
				$interfaces{"_$graph"}{cgioptions} .= " $opts";
			} else {
				$interfaces{"_$graph"} = {
					shdesc=>$graph,  targets=>[$curif], 
					cgioptions=>$opts, mode=>"\177_USER",
					usergraph=>1, icon=>"cog-sm.gif", inout=>0, incompact=>0,
					insummary=>0, inmenu=>1, desc=>"User defined graph $graph",
					withtotal=>0, withaverage=>0
				};
				$interfaces{"_$graph"}{withtotal} = 1 
					if( defined $config{'routers.cgi-showtotal'}
						and $config{'routers.cgi-showtotal'}=~/y/i);
				push @myifs, "_$graph";
			}
			next;
		}
		if( $buf =~ /^\s*routers.cgi\*Icon\[(\S+)\]\s*:\s*(\S+)/i ) {
			if(!defined $interfaces{$1}) {
				$1 = "_$1";
				next if(!defined $interfaces{$1});
			}
			next if(!defined $interfaces{$1});
			$interfaces{$1}{icon} = $2;
			next;
		}
		if( $buf =~ /^\s*routers.cgi\*Ignore\[(\S+)\]\s*:\s*(\S+)/i ) {
			$curif = $1; $arg = $2;
			next if(!defined $interfaces{$curif});
			if( $arg =~ /y/i ) {  
				$interfaces{$curif}{insummary} = 0;
				$interfaces{$curif}{inmenu} = 0;
				$interfaces{$curif}{inout} = 0;
				$interfaces{$curif}{isif} = 0;
			}
			next;
		}
		if( $buf =~ /^\s*routers.cgi\*InSummary\[(\S+)\]\s*:\s*(\S+)/i ) {
			$curif = $1; $arg = $2;
			next if(!defined $interfaces{$curif});
			if( $arg =~ /[1y]/i ) {  $interfaces{$curif}{insummary} = 1; }
			else { $interfaces{$curif}{insummary} = 0; }
			next;
		}
		if( $buf =~ /^\s*routers.cgi\*InMenu\[(\S+)\]\s*:\s*(\S+)/i ) {
			$curif = $1; $arg = $2;
			next if(!defined $interfaces{$curif});
			if( $arg =~ /[1y]/i ) {  $interfaces{$curif}{inmenu} = 1; }
			else { $interfaces{$curif}{inmenu} = 0; }
			next;
		}
		if( $buf =~ /^\s*routers.cgi\*InOut\[(\S+)\]\s*:\s*(\S+)/i ) {
			$curif = $1; $arg = $2;
			next if(!defined $interfaces{$curif});
			if( $arg =~ /[1y]/i ) {  $interfaces{$curif}{inout} = 1; }
			else { $interfaces{$curif}{inout} = 0; }
			next;
		}
		if( $buf =~ /^\s*routers.cgi\*InCompact\[(\S+)\]\s*:\s*(\S+)/i ) {
			$curif = $1; $arg = $2;
			next if(!defined $interfaces{$curif});
			if( $arg =~ /[1y]/i ) {  $interfaces{$curif}{incompact} = 2; }
			else { $interfaces{$curif}{incompact} = 0; }
			next;
		}
		if( $buf =~ /^\s*Background\[(\S+)\]\s*:\s*(#[a-f\d]+)/i ) { 
			next if(!defined $interfaces{$1});
			$interfaces{$1}{background} = $2;
			next;
		}
		if( $buf =~ /^\s*Timezone\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			next if(!defined $interfaces{$1});
			$interfaces{$1}{timezone} = $2;
			next;
		}
		if( $buf =~ /^\s*Directory\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $1; $arg = $2;
			next if(!defined $interfaces{$curif});
			$arg =~ s/[\s\\\/]+$//; # trim trailing spaces andpath separators!
			$interfaces{$curif}{rrd} = 
				$workdir.$pathsep.$arg.$pathsep.(lc $curif).".rrd";
			next;
		}
		if( $buf =~ /^\s*Workdir\s*:\s*(\S+)/i ) { 
			$workdir = $1; $workdir =~ s/[\\\/]+$//; next; }
		if( $buf =~ /^\s*Interval\s*:\s*(\d+)/i ) { $interval = $1; next; }
		if( $buf =~ /^\s*Include\s*:\s*(\S+)/i ) { 
			$newfile = $1;
			$newfile = (dirname $cfgfile).$pathsep.$newfile
				if( $newfile !~ /^([a-zA-Z]:)?[\/\\]/ );
			read_cfg_file($newfile); 
			next; 
		}
		if( $buf =~ /^\s*LibAdd\s*:\s*(\S+)/i ) { push @INC, $1; next; }
		if($buf=~ /^\s*(routers\.cgi\*)?MaxBytes(\d)\[(\S+)\]\s*:\s*(\d+)/i ){
			$curif = $3; $arg = $4;
			next if(!defined $interfaces{$curif});
			$interfaces{$curif}{"maxbytes$2"} = $arg;
			$interfaces{$curif}{maxbytes} = $arg
				if(!$interfaces{$curif}{maxbytes});
			next;
		}
		# the regexp from hell
		if( $buf =~ /^\s*(routers\.cgi\*)?Colou?rs\[(\S+)\]\s*:\s*[^#]*(#[\da-f]{6})[\s,]+[^#]*(#[\da-f]{6})[\s,]+[^#]*(#[\da-f]{6})[\s,]+[^#]*(#[\da-f]{6})/i ) { 
			$curif = $2; 
			$curif = "_$curif" if(!defined $interfaces{$curif});
			next if(!defined $interfaces{$curif});
			$interfaces{$curif}{colours} = [ $3,$4,$5,$6 ];
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*MBLegend\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $1; 
			$curif = "_$curif" if(!defined $interfaces{$curif});
			$interfaces{$curif}{mblegend} = $2;
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*AMLegend\[(\S+)\]\s*:\s*(\S.*)/i ) { 
			$curif = $1; 
			$curif = "_$curif" if(!defined $interfaces{$curif});
			$interfaces{$curif}{amlegend} = $2;
			next;
		}
		if( $buf =~ /^\s*(routers\.cgi\*)?AbsMax\[(\S+)\]\s*:\s*(\d+)/i ) { 
			next if(!defined $interfaces{$2});
			$interfaces{$2}{absmaxbytes} = $3;
			next;
		}
		if( $buf =~ /^\s*WeekFormat(\[\S+\])?\s*:\s*%?([UVW])/i ) {
			# yes I know this is ugly, it is being retrofitted
			$monthlylabel = "%".$2;
			next;
		}
		if( $buf =~ /^\s*routers\.cgi\*GraphStyle\[(\S+)\]\s*:\s*(\S+)/i ) { 
			$curif = $1; $arg = $2;
			$curif = "_$curif" if(!defined $interfaces{$curif});
			next if(!defined $interfaces{$curif});
			$interfaces{$curif}{graphstyle} = $arg;
			next;
		}
		if( $buf =~ /^\s*(routers\.cgi\*)?Factor\[(\S+)\]\s*:\s*(\d+)/i ) { 
			$curif = $2; $arg = $3;
			next if(!defined $interfaces{$curif});
			$interfaces{$curif}{factor} = $arg if($arg > 0);
			next;
		}
	}
	$fd->close;

	# now take the current file defaults
	foreach $key ( keys %{$interfaces{'_'}} ) {
		foreach $curif ( @myifs ) {
			$interfaces{$curif}{$key} = $interfaces{'_'}{$key}
				if(!defined $interfaces{$curif}{$key});
		}
	}
	foreach $key ( keys %{$interfaces{'^'}} ) {
		foreach $curif ( @myifs ) {
			$interfaces{$curif}{$key} = $interfaces{'^'}{$key}.' '.$interfaces{$curif}{$key};
		}
	}
	foreach $key ( keys %{$interfaces{'$'}} ) {
		foreach $curif ( @myifs ) { 
			$interfaces{$curif}{$key} .= ' '.$interfaces{'$'}{$key};
		}
	}

	# now process the options
	foreach $curif ( @myifs ) {
		next if(!$curif);
		if(defined $interfaces{$curif}{options} ) {
		foreach $k ( split /[\s,]+/,$interfaces{$curif}{options} ) {
			$interfaces{$curif}{noo} = 1 if( $k eq "noo");
			$interfaces{$curif}{noi} = 1 if( $k eq "noi");
			if( $k eq "bits") { $interfaces{$curif}{bits} = 1; }
			if( $k eq "perminute") {
				$interfaces{$curif}{perminute} = 1
					if(!defined $interfaces{$curif}{perhour}
						and !defined $interfaces{$curif}{perminute});
			}
			if( $k eq "perhour") {
				$interfaces{$curif}{perhour} = 1
					if(!defined $interfaces{$curif}{perhour}
						and !defined $interfaces{$curif}{perminute});
			}
			if( $k eq "nopercent") {
				$interfaces{$curif}{percent} = 0 ;
				# default incompact to NO if target has nopercent set
				$interfaces{$curif}{incompact} = 0 
					if($interfaces{$curif}{incompact} == 1);
			}
			$interfaces{$curif}{integer} = 1 if( $k eq "integer");
		} }
		if ( defined $interfaces{$curif}{cgioptions} ) {
		  foreach $k ( split /[\s,]+/,$interfaces{$curif}{cgioptions} ) {
			$interfaces{$curif}{noo} = 1 if( $k eq "noo");
			$interfaces{$curif}{noi} = 1 if( $k eq "noi");
#			$interfaces{$curif}{mult} = 8 if( $k eq "bits");
#			$interfaces{$curif}{mult} = 1 if( $k eq "bytes");
			$interfaces{$curif}{noi} = 1 if( $k eq "noi");
			if( $k eq "bytes") { $interfaces{$curif}{bytes} = 1; 
				$interfaces{$curif}{bits} = 0; }
			if( $k eq "bits") { $interfaces{$curif}{bits} = 1;
				$interfaces{$curif}{bytes} = 0;  }
			if( $k eq "perminute") {
				$interfaces{$curif}{perminute} = 1
					if(!defined $interfaces{$curif}{perhour}
						and !defined $interfaces{$curif}{perminute});
			}
			if( $k eq "perhour") {
				$interfaces{$curif}{perhour} = 1
					if(!defined $interfaces{$curif}{perhour}
						and !defined $interfaces{$curif}{perminute});
			}
			$interfaces{$curif}{isif} = 1 if($k eq "interface");
			if( $k eq "ignore") {
				$interfaces{$curif}{inmenu} = 0 ;
				$interfaces{$curif}{insummary} = 0 ;
				$interfaces{$curif}{inout} = 0 ;
				$interfaces{$curif}{incompact} = 0 ;
			}
			$interfaces{$curif}{unscaled} = "" if( $k eq "scaled");
			$interfaces{$curif}{total} = 0 if( $k eq "nototal");
			$interfaces{$curif}{percentile} = 0 if( $k eq "nopercentile");
			if( $k eq "summary" ) {
				$interfaces{$curif}{summary} = 1;
				$interfaces{$curif}{compact} = 0;
				$interfaces{$curif}{withtotal} = 0;
				$interfaces{$curif}{withaverage} = 0;
				$interfaces{$curif}{insummary} = 0 ;
				$interfaces{$curif}{incompact} = 0 ;
			}
			if( $k eq "compact" ) {
				$interfaces{$curif}{summary} = 0;
				$interfaces{$curif}{compact} = 1;
				$interfaces{$curif}{withtotal} = 0;
				$interfaces{$curif}{withaverage} = 0;
				$interfaces{$curif}{insummary} = 0 ;
				$interfaces{$curif}{incompact} = 0 ;
			}
			if( $k eq "total") {
				 $interfaces{$curif}{withtotal} = 1 ;
				 $interfaces{$curif}{total} = 1 ;
			}
			$interfaces{$curif}{withaverage} = 1 if( $k eq "average");
			$interfaces{$curif}{nolegend} = 1 if( $k eq "nolegend");
			$interfaces{$curif}{nodetails} = 1 if( $k eq "nodetails");
			$interfaces{$curif}{nomax} = 1 if( $k eq "nomax");
			$interfaces{$curif}{noabsmax} = 1 if( $k eq "noabsmax");
			$interfaces{$curif}{percent} = 0 if( $k eq "nopercent");
			$interfaces{$curif}{integer} = 1 if( $k eq "integer");
			if( $k =~ /^#[\da-fA-F]{6}$/ ) {
				$interfaces{$curif}{colours} = []
					if(!defined $interfaces{$curif}{colours});
				push @{$interfaces{$curif}{colours}}, $k;
			}
			$interfaces{$curif}{fixunits} = 1 
				if( $k =~ /^fixunits?/i or $k =~ /^nounits?/i );
		  }
		}
		# fix the mult
		if($interfaces{$curif}{bytes}) {
			$interfaces{$curif}{mult} = 1;
		} elsif($interfaces{$curif}{bits} ) {
			$interfaces{$curif}{mult} = 8;
		}
		if($interfaces{$curif}{perminute}) {
			$interfaces{$curif}{mult}=1 if(!$interfaces{$curif}{mult});
			$interfaces{$curif}{mult} *= 60;
		} elsif($interfaces{$curif}{perhour}) {
			$interfaces{$curif}{mult}=1 if(!$interfaces{$curif}{mult});
			$interfaces{$curif}{mult} *= 3600;
		}
		# sanity check
		if( $interfaces{$curif}{incompact} and !$interfaces{$curif}{maxbytes}){
			$interfaces{$curif}{incompact} = 0;
		}
	}

	# now read the corresponding .ok file, if it exists
	$cfgfile =~ s/\.conf$/.ok/;
	$cfgfile =~ s/\.cfg$/.ok/;
	if( open OK, "<$cfgfile" )  {
		my( %ifdesc ) = ();
		my( %ifip ) = ();
		while( <OK> ) {
			if( /\tDescr\t(.+)\t(\d+)/ ) {
				$ifdesc{$2} = $1; $ifdesc{$1} = $2;
			} 
			if( /\tIp\t(.+)\t(\d+)/ ) {
				$ifip{$2} = $1; $ifip{$1} = $2;
			} 
		}
		close OK;

		foreach $curif ( @myifs ) {
		if(!defined $interfaces{$curif}{ifno}) {
			$interfaces{$curif}{ifno} = $ifdesc{$interfaces{$curif}{ifdesc}}
			if(defined $interfaces{$curif}{ifdesc}
				and defined $ifdesc{$interfaces{$curif}{ifdesc}});
			$interfaces{$curif}{ifno} = $ifip{$interfaces{$curif}{ipaddress}}
			if(defined $interfaces{$curif}{ipaddress}
				and defined $ifip{$interfaces{$curif}{ipaddress}});
		}
		if(defined $interfaces{$curif}{ifno}) {
			$key = $interfaces{$curif}{ifno};
			$interfaces{$curif}{ifdesc} = $ifdesc{$key}
			if(defined $ifdesc{$key} and !defined $interfaces{$curif}{ifdesc});
			$interfaces{$curif}{ipaddress} = $ifip{$key}
			if(defined $ifip{$key} and !defined $interfaces{$curif}{ipaddress});
		}
		}
	} # ok file exists

	# now set up userdefined graphs for Incoming and Outgoing, if it is
	# necessary.
	$ifcnt = 0; @ifarr = (); $curif="";
	foreach ( @myifs ) { 
		$curif = $_ if(!$curif and $interfaces{$_}{community}
				and $interfaces{$_}{hostname} );
		if($interfaces{$_}{inout}) {
			$ifcnt++;
			push @ifarr, $_;
		}
	}
	$debugmessage .= "ifcnt=$ifcnt ";
	if($ifcnt) {
		$t = "";
		$t = $routers{$router}{shdesc}.": " 
			if($router and defined $routers{$router}
				and defined $routers{$router}{shdesc});
		if( defined $interfaces{'_incoming'} ) {
			push @{$interfaces{'_incoming'}{targets}},@ifarr
				if( $interfaces{'_incoming'}{mode} =~ /_AUTO/ );
		} else {
			$interfaces{'_incoming'} = {
			usergraph=>1, insummary=>0, inmenu=>1, inout=>0, incompact=>0,
			shdesc=>"Incoming",  targets=>[@ifarr], noo=>1, mult=>8,
			icon=>"incoming-sm.gif", mode=>"\177_AUTO",
			desc=>$t."Incoming traffic",
			withtotal=>0, withaverage=>0
			};
			if(defined $config{'routers.cgi-showtotal'} 
				and $config{'routers.cgi-showtotal'}=~ /y/i ) {
				$interfaces{'_incoming'}{withtotal} = 1;
			}
		}
		if( defined $interfaces{'_outgoing'}  ) {
			push @{$interfaces{'_outgoing'}{targets}},@ifarr
				if( $interfaces{'_outgoing'}{mode} =~ /_AUTO/ );
		} else {
			$interfaces{'_outgoing'} = {
			usergraph=>1, insummary=>0, inmenu=>1, inout=>0, incompact=>0,
			shdesc=>"Outgoing",  targets=>[@ifarr], noi=>1, mult=>8,
			icon=>"outgoing-sm.gif", mode=>"\177_AUTO",
			desc=>$t."Outgoing traffic",
			withtotal=>0, withaverage=>0
			};
			if(defined $config{'routers.cgi-showtotal'} 
				and $config{'routers.cgi-showtotal'}=~ /[1y]/i ) {
				$interfaces{'_outgoing'}{withtotal} = 1;
			}
		}
	}

	# Can we call out to the routingtable.cgi program?
	if( defined $config{'routers.cgi-routingtableurl'} and $curif 
		and ( !defined $routers{$router}{routingtable}
			or $routers{$router}{routingtable} =~ /[1y]/i )) {
		$routers{$router}{extensions} = []
			if( !defined $routers{$router}{extensions} );
		push @{$routers{$router}{extensions}}, { 
			url=>$config{'routers.cgi-routingtableurl'},
			desc=>"Routing Table", icon=>"router-sm.gif",
			community=>$interfaces{$curif}{community},
			hostname=>$interfaces{$curif}{hostname}
		};
	}
}

sub read_cfg()
{
	my($cfgfile) = $_[0];
	my($l,$key,$k);
	
	$cfgfile = $routers{$router}{file} 
		if(!$cfgfile and $router and defined $routers{$router});
	$cfgfile = $config{'routers.cgi-confpath'}.$pathsep.$router 
		if(!$cfgfile and $router);
	return if (!$cfgfile);

	%interfaces = ( '_'=>{x=>0}, '^'=>{x=>0}, '$'=>{x=>0} );
	$interval = 5;
	$workdir = $config{'routers.cgi-dbpath'};

	read_cfg_file($cfgfile); # recursive

	# zap defaults
	delete $interfaces{'_'};
	delete $interfaces{'$'};
	delete $interfaces{'^'};
	delete $interfaces{''} if(defined $interfaces{''});

	# first pass for interfaces
	foreach $key ( keys %interfaces ) { 
		next if($interfaces{$key}{usergraph});
		identify $key; 
	}
	# second pass for user graphs
	foreach $key ( keys %interfaces ) {
		next if(!$interfaces{$key}{usergraph});
		$k = $key; $k=~ s/^_//; # chop off initial _ prefix
		$interfaces{$key}{shdesc} = $config{"targetnames-$k"}
		if(defined $config{"targetnames-$k"});
		$interfaces{$key}{desc} = $config{"targettitles-$k"}
		if(defined $config{"targettitles-$k"});
		$interfaces{$key}{icon} = $config{"targeticons-$k"}
		if(defined $config{"targeticons-$k"});
		foreach $k ( keys %{$interfaces{$interfaces{$key}{targets}->[0]}} ) {
			$interfaces{$key}{$k} 
				= $interfaces{$interfaces{$key}{targets}->[0]}{$k}
				if(!defined $interfaces{$key}{$k});
		}
	}
}


#############################################################################
# reformat to look nice
# params -- number, fix flag, integer flag
sub doformat($$$)
{
	my( $sufx ) = "";
	my( $val, $fix, $intf ) = @_;

	return "???" if(!defined $val or $val !~ /\d/ );
	return $val if( $val == 0 );

	if(!$fix) {
		if( $val > $G ) {
			$val /= $G; $sufx = "G";
		} elsif( $val > $M  ) {
			$val /= $M; $sufx = "M";
		} elsif( $val > $k ) {
			$val /= $k; $sufx = $ksym;
		}
	} 
	
	return sprintf "%.0f %s",$val,$sufx 
		if( $intf or ( int($val*100) == (100*int($val)) ) );
	return sprintf "%.2f %s",$val,$sufx;
}

#################################
# Calculate nth percentile (bits), and total bandwidth (bits), for current rrd
# and for specified interval (d,w,m,y)
# Returns ( desc, [inpercentile,intotal,emsg], [outpercentile,outtotal,emsg] )

sub calc_percentile($$$)
{
	my( $thisif, $pcinterval, $percentile ) = @_; # dwmy, 95
	my( @rv, $e, @opts );
	my( $rrd, $ds );
	my( $resolution, $startpoint, $desc ); # fetch input values
	my( $datastart, $datastep, $dsnames, $dsdata ); # fetch return values
	my( $pc, $row, $totalbits, @pcarray, $idx, $pcidx );

	return ("",["-","-","No interface"],["-","-",""]) 
		if(!$thisif); # just in case

	$rrd = $interfaces{$thisif}{rrd};
	foreach ( $pcinterval ) {
		/y/ and do { $resolution = 3600; $startpoint = "-1y"; 
			$desc = "last year"; last; };
		/m/ and do { $resolution = 1800; $startpoint = "-1month"; 
			$desc = "last calendar month"; last; };
		/w/ and do { $resolution = 300; $startpoint = "-7d"; 
			$desc = "last 7 days"; last; };
		/6/ and do { $resolution = 60*$interfaces{$thisif}{interval}; 
			$desc = "last 6 hours";
			$startpoint = "-6h"; last; };
		$resolution = 60*$interfaces{$thisif}{interval}; # interval
		$startpoint = "-24h"; # 1 day
		$desc = "last 24 hours";
	}
	$desc =~ s/last/previous/ if($pcinterval =~ /-/);
	$resolution = 300 if(!$resolution);
	push @rv, $desc;
	
	# fetch the data
	eval { require 'RRDs.pm'; };
	if( $@ ) {
		return ("",
			["-","-","No RRDs.pm"],["-","-",""]) ;
	}
	if( $pcinterval =~ /-/ ) {
		@opts = ( $rrd,"AVERAGE","-e","now$startpoint","-s","end$startpoint" );
	} elsif( $uselastupdate ) {
		@opts = ( $rrd,"AVERAGE","-e",$lastupdate,"-s","end$startpoint" );
	} else {
		@opts = ( $rrd, "AVERAGE", "-s", $startpoint );
	}
	( $datastart, $datastep, $dsnames, $dsdata ) = RRDs::fetch( @opts );
	$e = RRDs::error();
	if ( $e ) {
		@rv = ("",["?","?",$e],
			["?","?","fetch ".(join " ",@opts)]);
		return @rv;
	}

	# now we do two calculations: the total traffic ( $datastep*sum(value) )
	# for both in and out, and the percentile (95% into sorted array )
	foreach $idx ( 0..1 ) {
		$totalbits = 0; @pcarray = ();
		foreach $row ( @$dsdata ) {
			next if(!defined $row->[$idx]);
			if( $row->[$idx] =~ /\d/ ) {
			$totalbits += $row->[$idx]*$interfaces{$thisif}{mult}*$datastep;
			push @pcarray, ( $row->[$idx] * $interfaces{$thisif}{mult} );
			}
		}	
		@pcarray = sort numerically @pcarray if($#pcarray>0);
		$pcidx = int($#pcarray * $percentile / 100);
# Now, at this point, if $thisif is a RANGE, we should do percentile and
# 100-percentile , ie, the opposite for the 'from'.
		if( $idx and $interfaces{$thisif}{graphstyle} eq "range" ) {
			$pcidx = int($#pcarray * (100-$percentile) / 100);
		}
		$pc = $pcarray[$pcidx];
		push @rv, [ $pc, $totalbits, "" ];
#		push @rv, [ $pc, $totalbits, $$dsnames[$idx]." $idx: 0=[".$pcarray[0]
#	."] $#pcarray=[".$pcarray[$#pcarray]."] , i=$pcidx, st=$datastep, s="
#	.localtime($datastart).", e=".localtime($datastart+($datastep*$#pcarray))];
	}

	return @rv;
}

#################################
# Top menu

sub do_head()
{
my($iconsuffix) = "";

$iconsuffix = "-bw" if( $gstyle =~ /b/ );

print $q->start_html({ -title => $toptitle ,
	-link=>$linkcolour, -vlink=>$linkcolour, -alink=>$linkcolour,
					   -bgcolor => $menubgcolour});

print $q->table( { -border=>"0", -width=>"100%", cellspacing=>0, cellpadding=>1 },
  $q->Tr( { -valign=>"TOP", -width=>"100%" }, 
    $q->td({ -align=>"LEFT", -width=>150, -valign=>"TOP" }, 
	($config{'web-backurl'}?(
      $q->a({ href=>$config{'web-backurl'}, target=>"_top"}, 
      $q->img({ src=>"${config{'routers.cgi-iconurl'}}mainmenu$iconsuffix.gif", alt=>"Main Menu", border=>0,
		width=>100, height=>20 }))."\n".$q->br
	):"")
	.$q->a({href=>"javascript:parent.graph.location.reload(true)"},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}refresh$iconsuffix.gif",alt=>"Refresh", border=>"0",
		width=>100, height=>20}))
    )."\n"
    .$q->td({ -align=>"CENTER" }, $q->h1($toptitle))."\n"
    .$q->td({ -align=>"RIGHT", -width=>200, -valign=>"TOP" }, 
		$q->a( { href=>"http://www.rrdtool.org/", target=>"_new" } ,
			$q->img({ src=>"${config{'routers.cgi-iconurl'}}rrdtool.gif", 
				alt=>"RRDTool", border=>0 })
		)
	)."\n"
  )
),"\n";

# Finish off the page
print $q->end_html();
}

###########################
# Side menu

# $mtype specified 'routers' (list routers) or 'options' (list options)


sub do_menu()
{
my ($iflabel);
my ($target) = "graph";
my ($rtrdesc,$gs,$adesc);
my ($iconsuffix) = "";
my ($groupdesc, $lastgroup, $thisgroup);
my ($hassummary) = 0;
my ($hascompact) = 0;
my ($explore) = "y";
my (@archive) = ();
my ($archivepat);

# explore will contain either y, n, or i
$explore = $config{'routers.cgi-allowexplore'}
	if( defined $config{'routers.cgi-allowexplore'} );
$mtype = "options" if( $explore !~ /y/i );

$iconsuffix = "-bw" if( $gstyle =~ /b/ );
$target = "_top" if( $gstyle =~ /p/ );

# Start it off
print $q->start_html({ -title => $toptitle,
	-link=>$linkcolour, -vlink=>$linkcolour, -alink=>$linkcolour,
					   -bgcolor => $menubgcolour, nowrap => "yes"});

print "<DIV NOWRAP>\n";

# top link for other stuff
if( $mtype eq "options" or !$router or $router eq "none"
	or $router eq "__none" or $interface eq "__none" ) {
	print $q->a({name=>"top"},"");
}
print "<FONT size=".$config{'routers.cgi-menufontsize'}.">\n"
	if( defined $config{'routers.cgi-menufontsize'} );

# Main stuff and links
if ( $mtype eq "options" ) {
	# check for inout graphs
	foreach ( keys %interfaces ) {
		if( $interfaces{$_}{insummary} ) { $hassummary = 1; }
		if( $interfaces{$_}{incompact} ) { $hascompact = 1; }
	}
	# check for archive
	if( defined $config{'routers.cgi-archive'} 
		and $config{'routers.cgi-archive'} !~ /^n/i ) {
		$archivepat = $router; $archivepat =~ s/[\?#\\\/]//g;
		$archivepat = $config{'routers.cgi-graphpath'}.$pathsep
			.$archivepat.$pathsep.$interface.$pathsep."*.*";
		# do this in an eval because some Perl implementations treat a null 
		# glob as an error (why??)
		eval { @archive = glob($archivepat); };
	}

	# now show it all
	if( !$twinmenu ) {
	print $q->a({ href=>"$meurl?".optionstring(
		{ page=>"menu",xmtype=>"routers" }), target=>"_self",
		onMouseOver=>"if(devices){devices.src='${config{'routers.cgi-iconurl'}}devices-dn-w.gif'; window.status='Show list of routers';}", 
		onmouseout=>"if(devices){devices.src='${config{'routers.cgi-iconurl'}}devices-dn$iconsuffix.gif'; window.status='';}" },
		$q->img({ src=>"${config{'routers.cgi-iconurl'}}devices-dn$iconsuffix.gif", alt=>"Devices", border=>0 , name=>"devices",
		width=>100, height=>20}))."\n".$q->br."\n"
		if( $explore =~ /y/i );
	}
	# list options
	if( $explore !~ /n/i and $router ne "none") {
	print  $q->img({ src=>"${config{'routers.cgi-iconurl'}}targets$iconsuffix.gif", alt=>"Targets",
		width=>100, height=>20 }), $q->br,"\n";
	foreach ( sort byifdesc keys( %interfaces ) ) {
		next if(!$_); # avoid the '#' interface...
		next if(!$interfaces{$_}{inmenu}); # if not in menu...
		$iflabel = $interfaces{$_}{shdesc} if(defined $interfaces{$_}{shdesc});
		$iflabel = "#$_" unless ( $iflabel );
		$iflabel =~ s/ /\&nbsp;/g; # get rid of spaces...
		print "<NOBR>";
		if( $_ eq $interface ) { print $q->a({name=>"top"},""); }
		if( $interfaces{$_}{icon} ) {
			print $q->img({ 
				src=>($config{'routers.cgi-iconurl'}.$interfaces{$_}{icon}),
				width=>15, height=>15, alt=>$interfaces{$_}{desc} }),"&nbsp;";
		} elsif( $interfaces{$_}{isif} ) {
			print $q->img({
				src=>($config{'routers.cgi-iconurl'}."interface-sm.gif"),
				width=>15, height=>15, alt=>$interfaces{$_}{desc} }),"&nbsp;";
		} else {
			print $q->img({
				src=>($config{'routers.cgi-iconurl'}."target-sm.gif"),
				width=>15, height=>15, alt=>$interfaces{$_}{desc} }),"&nbsp;";
		}
		if ( $interface eq $_ ) {
			print $q->b($iflabel);
		} else {
			if( $gstyle =~ /p/ ) {
				print $q->a({ href=>"$meurl?".optionstring(
	{ page=>"main", if=>"$_" }), target=>"_top" }, $iflabel );
			} else {
				print $q->a({ href=>"$meurl?".optionstring(
	{ if=>"$_" }), target=>"graph" }, $iflabel );
			}
		}	
		print "</NOBR>".$q->br."\n";
	
	} #  special targets - summary, compact, info, userdefined
	if( $router ne "none" and $router ne "__none" ) {
		if($hassummary) {
		print "<NOBR>";
		print $q->img({ src=>"${config{'routers.cgi-iconurl'}}summary-sm.gif",
			width=>15, height=>15  }),"&nbsp;";
		if( $interface eq "__summary" ) {
			print $q->b("Summary");
		} else {
			if( $gstyle =~ /p/ ) {
			print $q->a({ href=>"$meurl?".optionstring( 
	{ page=>"main", if=>"__summary" }), target=>"_top" },"Summary");	
			} else {
			print $q->a({ href=>"$meurl?".optionstring(
	{ if=>"__summary" }), target=>"graph" },"Summary");	
			}
		}
		print "</NOBR>".$q->br."\n";
		} # has summary?
		if($hascompact) {
		if( ! defined $config{'routers.cgi-compact'}
			or $config{'routers.cgi-compact'} !~ /n/i ) {
		print "<NOBR>";
		print $q->img({ src=>"${config{'routers.cgi-iconurl'}}compact-sm.gif",
			width=>15, height=>15  }),"&nbsp;";
		if( $interface eq "__compact" ) {
			print $q->b("Compact&nbsp;summary");
		} else {
			if( $gstyle =~ /p/ ) {
			print $q->a({ href=>"$meurl?".optionstring( 
	{ page=>"main", if=>"__compact" }), target=>"_top" },"Compact&nbsp;summary");	
			} else {
			print $q->a({ href=>"$meurl?".optionstring(
	{ if=>"__compact" }), target=>"graph" },"Compact&nbsp;summary");	
			}
		}
		print "</NOBR>".$q->br."\n";
		} # compact option
		} # hascompact
		if( $router !~ /^#SERVER#/ ) {
		print $q->img({ src=>"${config{'routers.cgi-iconurl'}}menu-sm.gif",
			width=>15, height=>15  }),"&nbsp;";
		if( $interface eq "__info" ) {
			print $q->b("Information"),$q->br,"\n";
		} else {
			if( $gstyle =~ /p/ ) {
			print $q->a({ href=>"$meurl?".optionstring(
	{ page=>"main",if=>"__info"}), target=>"_top"},"Information"),$q->br,"\n";	
			} else {
			print $q->a({ href=>"$meurl?".optionstring(
	{ if=>"__info" }), target=>"graph" },"Information"),$q->br,"\n";	
			}
		}
		} # not SERVER
	# any userdefined's for this router?
	if ( defined $routers{$router}{extensions} ) {
		my( $u, $ext, $targ );
		foreach $ext ( @{$routers{$router}{extensions}} ) {
			$targ = "graph";
			$targ = $ext->{target} if( defined $ext->{target} );
			$u = $ext->{url};
			$u .= "?x=1" if( $u !~ /\?/ );
			$u .= "&fi=".$q->escape($router)
				."&url=".$q->escape($meurl);
			$u .= "&t=".$q->escape($targ); 
			$u .= "&r=".$q->escape($ext->{hostname})
			."&h=".$q->escape($ext->{hostname}) if(defined $ext->{hostname});
			$u .= "&c=".$q->escape($ext->{community})
				if(defined $ext->{community});
			$u .= "&b=".$q->escape("javascript:history.back();history.back()")
				."&conf=".$q->escape($conffile);
			print $q->img({ src=>(${config{'routers.cgi-iconurl'}}
				.$ext->{icon}), width=>15, height=>15  }),"&nbsp;";
			print $q->a({ href=>$u, target=>$targ },
				$ext->{desc} ),$q->br,"\n";
		}
	} # extensions defined
	} # not 'none' router
	print $q->br;
	} # explore

	print "\n";
	if( !$archive and $interface ne "__none") {
	print $q->img({ src=>"${config{'routers.cgi-iconurl'}}graphs$iconsuffix.gif", alt=>"Graphs",
		width=>100, height=>20 }), $q->br,"\n";
	foreach ( @gorder ) {
		print $q->img({ src=>"${config{'routers.cgi-iconurl'}}clock-sm.gif",
			width=>15, height=>15  }),"&nbsp;";
		if($gtype eq $_) {
			print $q->b($gtypes{$_}),$q->br,"\n";
		} elsif((($interface eq "__summary" or $interface eq "__compact")
			and (length > 2 ))
			or ( $router eq "none" )) {
			print $gtypes{$_},$q->br,"\n";
		} else {
			if( $gstyle =~ /p/ ) {
			print $q->a({ href=>"$meurl?".optionstring(
				{ page=>"main", xgtype=>"$_" }), 
				target=>"_top" }, $gtypes{$_} ), $q->br,"\n";
			} else {
			print $q->a({ href=>"$meurl?".optionstring(
	{ xgtype=>"$_" }), target=>"graph" }, $gtypes{$_} ),$q->br,"\n";
			}
		}
	}
		print $q->br;
	} # ! viewing archive
	print "\n";
	if( @archive ) {
		print  $q->img({ 
			src=>"${config{'routers.cgi-iconurl'}}archive-h$iconsuffix.gif", 
			alt=>"Archive", width=>100, height=>20 }), $q->br,"\n";
			if($archive) {
		print "<NOBR>";
			print $q->img({ src=>"${config{'routers.cgi-iconurl'}}graph-sm.gif",
					width=>15, height=>15  }),"&nbsp;";
			$adesc = "Live&nbsp;graph";
			if( $gstyle=~/p/ ) {
				print $q->a({ href=>"$meurl?".optionstring( { page=>"main" }), 
					target=>"_top" }, $adesc );
			} else {
				print $q->a({ href=>"$meurl?".optionstring( { page=>"graph" }), 
					target=>"graph" }, $adesc );
			}
			print "</NOBR>".$q->br."\n";
		}
		foreach ( sort @archive ) {
			if(/(\d+)-(\d+)-(\d+)-(\d+)-(\d+)-(\S+)\.(gif|png)$/) {
				# try to get local formatting
#				$adesc = "$4:$5&nbsp;$3/$2/$1&nbsp;(".$gtypes{$6}.")";
				my( $dformat ) = "%c";
				$dformat = $config{'web-shortdateformat'}
					if(defined $config{'web-shortdateformat'});
				eval { require POSIX; };
				if($@) {
					$adesc = "$4:$5&nbsp;$3/$2/$1&nbsp;(".$gtypes{$6}.")";
				} else {
					$adesc = POSIX::strftime($dformat,
						0,$5,$4,$3,($2-1),($1+100))." (".$gtypes{$6}.")";
					$adesc =~ s/ /\&nbsp;/g;
				}
				print "<NOBR>";
		print $q->img({ src=>"${config{'routers.cgi-iconurl'}}graph-sm.gif",
				width=>15, height=>15  }),"&nbsp;";
				if( $gstyle=~/p/ ) {
					print $q->a({ href=>"$meurl?".optionstring( { page=>"main",
						archive=>(basename $_), xgtype=>"$6"}), 
						target=>"_top" }, $adesc );
				} else {
					print $q->a({ href=>"$meurl?".optionstring( {
						page=>"graph",
						archive=>(basename $_), xgtype=>"$6"}), 
						target=>"graph" }, $adesc );
				}
				print "</NOBR>".$q->br."\n";
			} else {
				print "<!-- Error in archive [$_] -->\n";
			}
		}
		print $q->br."\n";
	}

	if( !$archive and $interface ne "__none" ) {
	print  $q->img({ 
		src=>"${config{'routers.cgi-iconurl'}}styles$iconsuffix.gif", 
		alt=>"Styles", width=>100, height=>20 }), $q->br,"\n";
	foreach ( @sorder ) {
		next if (!defined $gstyles{$_});
		print "<NOBR>";
		print $q->img({ src=>"${config{'routers.cgi-iconurl'}}pbrush-sm.gif",
			width=>15, height=>15  }),"&nbsp;";
		$gs = $gstyles{$_};
		$gs =~ s/ /\&nbsp;/g;
		if($gstyle eq $_) {
			print $q->b($gs);
		} elsif( $router eq "none" ) {
			print $gs;
		} else {
			# PDAs cant be relied on to have javascript support
			if( /p/ ) {
			print $q->a({ href=>"$meurl?".optionstring(
	{ page=>"main", xgstyle=>"$_"}), target=>"_top" }, $gs );
			} else {
			print $q->a({ href=>"$meurl?".optionstring(
	{ xgstyle=>"$_"}), target=>"graph" }, $gs );
			}
		}
		print "</NOBR>".$q->br."\n";
	}
		print $q->br;
	} # ! archive viewing
	print  $q->img({ src=>"${config{'routers.cgi-iconurl'}}otherstuff$iconsuffix.gif", alt=>"Other Stuff",
		width=>100, height=>20 }), $q->br,"\n";
	print $q->img({ src=>"${config{'routers.cgi-iconurl'}}prefs-sm.gif",
			width=>15, height=>15  }),"&nbsp;";
	print $q->a({href=>"$meurl?".optionstring(
	{ page=>"config" }) , target=>"graph"}, 
		"Preferences"),$q->br,"\n";
	print $q->img({ src=>"${config{'routers.cgi-iconurl'}}info-sm.gif" }),"&nbsp;";
	print $q->a({href=>"$meurl?".optionstring({page=>"help"}), target=>"graph"}, 
		"Information"),$q->br,"\n";
#	print $q->img({ src=>"${config{'routers.cgi-iconurl'}}error-sm.gif" }),"&nbsp;";
#	print $q->a({href=>("$meurl?page=verify&rtr="
#		.$q->escape($router)),target=>"_new"},"Configuration&nbsp;check")
#		.$q->br."\n";
	# twin menu
	print $q->img({ src=>"${config{'routers.cgi-iconurl'}}menu-sm.gif" }),
		"&nbsp;";
	if( $twinmenu ) {
		$uopts=~ s/[tT]//g; $uopts .= "T";
		print $q->a({ href=>"$meurl?".optionstring({ page=>"main"}), 
			target=>"_top" },"Close&nbsp;second&nbsp;menu" )
	} else {
		$uopts=~ s/[tT]//g; $uopts .= "t";
		print $q->a({ href=>"$meurl?".optionstring({page=>"main"}), 
			target=>"_top" }, "Twin&nbsp;menu&nbsp;view" )
	}
	print $q->br."\n";
} else {
	# Routers menu list
	#
	if( ! $twinmenu ) {
		print $q->a({ href=>"$meurl?".optionstring(
			{ page=>"menu", xmtype=>"options" }), target=>"_self" ,
		onMouseOver=>"if(options){options.src='${config{'routers.cgi-iconurl'}}options-dn-w.gif'; window.status='Show display options';}", 
		onmouseout=>"if(options){options.src='${config{'routers.cgi-iconurl'}}options-dn$iconsuffix.gif'; window.status='';}" },
		$q->img({ src=>"${config{'routers.cgi-iconurl'}}options-dn$iconsuffix.gif", alt=>"Options", border=>0, name=>"options",
			height=>20, width=>100 }))."\n".$q->br."\n";
	}
	# list routers
	print  $q->img({ src=>"${config{'routers.cgi-iconurl'}}devices$iconsuffix.gif", alt=>"Devices",
			height=>20, width=>100 }), $q->br,"\n";
	$grouping = 1 if( defined $config{'routers.cgi-group'}
		and $config{'routers.cgi-group'} =~ /y/i );
	if($grouping) {
		$group=$lastgroup="";
		$group=$routers{$router}{group} if(defined $routers{$router});
	}
	foreach ( sort byshdesc keys(%routers) ) {
		next if(!$routers{$_}{inmenu});
		if( $grouping ) {
			$thisgroup =  $routers{$_}{group};
			if( $thisgroup ne $lastgroup ) {
				if( defined $config{"targetnames-$thisgroup"} ) {
					$groupdesc = $config{"targetnames-$thisgroup"};
				} else {
					$groupdesc = basename( $thisgroup,'' ).$pathsep;
				}
				print "<NOBR>";
				if( $thisgroup eq $group ) {
					print $q->img({
					src=>"${config{'routers.cgi-iconurl'}}g-sm.gif",
					width=>15, height=>15, alt=>$groupdesc }),"&nbsp;";
					print $q->b($groupdesc);
				} else {
					print $q->img({ 
						src=>"${config{'routers.cgi-iconurl'}}plus-sm.gif",
						width=>15, height=>15, alt=>$groupdesc }),"&nbsp;";
					if( $gstyle =~ /p/ ) {
						print $q->a({href=>"$meurl?"
							.optionstring({page=>"main", if=>"",rtr=>"$_"}), 
							target=>"_top" },$q->b($groupdesc) );
					} else {
						print $q->a({ href=>"$meurl?"
							.optionstring({ rtr=>"$_", if=>"" }), 	
							target=>"graph" },$q->b($groupdesc) );
					}
				}
				print "</NOBR>".$q->br."\n";
				$lastgroup = $thisgroup;
			}
			next if( $thisgroup ne $group );
		}
		$rtrdesc = $routers{$_}{shdesc};
		$rtrdesc = $_ if(! $rtrdesc );
		$rtrdesc =~ s/ /\&nbsp\;/g; # stop breaking of line on spaces

		print "<NOBR>";
		print "&nbsp;" if($grouping);
		if( $_ eq $router ) { print $q->a({name=>"top"},""); }
		print $q->img({ src=>($config{'routers.cgi-iconurl'}.$routers{$_}{icon}),
			width=>15, height=>15, alt=>"$rtrdesc"
			}),"&nbsp;";
		if( $_ eq $router ) {
			print $q->b($rtrdesc);
		} else {
			if( $gstyle =~ /p/ ) {
			print $q->a({href=>"$meurl?".optionstring({page=>"main",
				rtr=>"$_", if=>""}), target=>"_top" },$rtrdesc );
			} else {
			print $q->a({ href=>"$meurl?".optionstring({ rtr=>"$_", if=>"" }), 	
				target=>"graph" },$rtrdesc );
			}
		}
		print "</NOBR>".$q->br."\n";
	}
}

# Finish off the page
print "</FONT>\n" if( defined $config{'routers.cgi-menufontsize'} );
print "</DIV>\n<!-- Version $VERSION -->\n";
print $q->end_html();
}

############################
# Main frame set

sub do_main()
{
	my( $javascript, $framethree );
	my( $urla, $urlb, $urlc, $urlh );
	my( $menuwidth ) = 150;

	$gtype = "" if(!defined $gtype);
	$mtype = "" if(!defined $mtype);
	$gstyle = "" if(!defined $gstyle);
	$gopts = "" if(!defined $gopts);
	$baropts = "cam" if(!defined $baropts);

	$menuwidth = $config{'routers.cgi-menuwidth'}
		if( defined $config{'routers.cgi-menuwidth'} );
	$menuwidth = 150 if ( $menuwidth < 100 or $menuwidth > 500
		or $menuwidth !~ /^\d+$/ );

# Javasciript funtion to reload the page with a specified set of params.
	$javascript = "
	function makebookmark(rtr,rtrif,xgtype,xgstyle,xgopts,bars,extra) {
		var newurl;
		newurl = '$meurl?rtr='+escape(rtr)+'&if='+escape(rtrif);
		if ( xgtype != '' ) { newurl = newurl + '&xgtype='+xgtype; }
		if ( xgstyle != '' ) { newurl = newurl + '&xgstyle='+xgstyle; }
		if ( xgopts  != '' ) { newurl = newurl + '&xgopts='+xgopts ; }
		if ( extra != '' ) { newurl = newurl + '&extra='+escape(extra) ; }
		if ( bars  != '' && rtrif == '__compact' ) { newurl = newurl + '&bars='+bars ; }
		window.location = newurl;
	}
	function makearchmark(rtr,rtrif,extra,arch) {
		var newurl;
		newurl = '$meurl?rtr='+escape(rtr)+'&if='+escape(rtrif)
			+'&archive='+arch;
		if ( extra != '' ) { newurl = newurl + '&extra='+escape(extra) ; }
		window.location = newurl;
	}
";

	$urlb = $meurl."?".optionstring({ page=>"graph" });

	if( $twinmenu ) {	
		$urla = $meurl."?".optionstring({ page=>"menu", xmtype=>"routers",
			nomenu=>1  }) ."#top";
		$urlc = $meurl."?".optionstring({ page=>"menub", xmtype=>"options",
			nomenu=>1 }) ."#top";
		$framethree = "<FRAMESET border=1 marginheight=1 marginwidth=1 
	cols=$menuwidth,*,$menuwidth bgcolor=$menubgcolour >
  <FRAME name=menu src=$urla scrolling=auto nowrap>
  <FRAME name=graph src=$urlb scrolling=auto>
  <FRAME name=menub src=$urlc scrolling=auto nowrap>
 </FRAMESET>\n";
	} else {
		$urla = $meurl."?".optionstring({ page=>"menu", nomenu=>1 })."#top";
		$framethree = "<FRAMESET border=1 marginheight=1 marginwidth=1 
cols=$menuwidth,* bgcolor=$menubgcolour >
  <FRAME name=menu src=$urla scrolling=auto nowrap>
  <FRAME name=graph src=$urlb scrolling=auto>
 </FRAMESET>\n";
	}

	$urlh = $meurl."?".optionstring({ page=>"head" });

	print <<"EOT"
<HTML><HEAD><TITLE>$toptitle</TITLE></HEAD>
<SCRIPT language=JavaScript><!--
$javascript
//--></SCRIPT>
<FRAMESET border=1 marginheight=1 marginwidth=1 rows=60,* bgcolor=$menubgcolour>
 <FRAME name=head src=$urlh noresize scrolling=no>
  $framethree
</FRAMESET>
<NOFRAMES>
 <BODY>
  Sorry, routers.cgi does not support non-frames browsers.  
  Upgrade to Netscape 4.x or later, or MSIE 4.x or later.
 </BODY>
</NOFRAMES>
<!-- Version $VERSION -->
<!-- $debugmessage -->
<!-- NOTE:
     You must not run routers.cgi from the command line.  It is intended to
     be used as a CGI script, called by your Web Server.  When installed in
     this way, you should be able to view the output in your web browser by
     calling the CGI script through your web server.
  -->
</HTML>
EOT
;
# now clean up the verify stuff if it's there
# we cant do this in the do_verify subroutine because the file is required
# by a future connection.
unlink ($config{'routers.cgi-graphpath'}.$pathsep."redsquare.png")
	if( -f $config{'routers.cgi-graphpath'}.$pathsep."redsquare.png" );

}

##########################
sub do_footer()
{
	print $q->hr."\n".$q->small("routers.cgi Version $VERSION : &copy; "
		.$q->a({href=>$APPMAIL},"Steve Shipway")
		." 2000-2002 : ".$q->a({ href=>$APPURL, target=>"_top" },$APPURL)
	),"\n";
	print "<!-- [$router] [$interface] [$archive] -->\n";
	print "<!-- $debugmessage\n-->\n" if($debugmessage);
}

##########################
# Graph panel

my(@params);

sub usr_params(@)
{
	my($ds0,$ds1,$mds0,$mds1);
	my($lin, $lout);
	my($dwmy,$interface) = @_;
	my($ssin, $ssout, $sin, $sout);
	my($l,$defrrd, $curif);
	my($legendi,$legendo);
	my(@clr,$ifcnt, $c, $escunit);
	my($totindef,$totoutdef,$incnt, $outcnt);
	my($stacking) = 0;
	my($max1, $max2);

	# stacking?
	if( defined $interfaces{$interface}{graphstyle}
		and $interfaces{$interface}{graphstyle} =~ /stack/i ) {
		$stacking = 1; # first is AREA, then STACK
	}
	# identify colours
	if( defined $interfaces{$interface}{colours} ) {
		@clr = @{$interfaces{$interface}{colours}};
	}
	if(! @clr ) {
		if( $gstyle =~ /b/ ) {
		@clr = ( "#000000","#888888","#cccccc","#dddddd","#666666","#444444",
		"#222222", "#aaaaaa", "#eeeeee", "#bbbbbb", "#555555", "#333333" );
		} else {
		@clr = ( "#0000ff","#00ff00","#ff0000","#00cccc","#cccc00","#cc00cc",
		"#8800ff", "#88ff00", "#ff8800", "#0088ff", "#ff0088", "#00ff88" );
		}
	}
	$ifcnt = $#{$interfaces{$interface}{targets}};
	while( $#clr < $ifcnt ) { push @clr, @clr; }

	$totindef = "CDEF:totin=0"; $totoutdef = "CDEF:totout=0";
	$ifcnt = 0; $incnt = $outcnt = 0;
	foreach $curif ( @{$interfaces{$interface}{targets}} ) {
		# loop through all interfaces	
		$ifcnt++;

	$defrrd = $interfaces{$curif}{rrd};
	$defrrd =~ s/:/\\:/g;

	$escunit = $interfaces{$curif}{unit};
	$escunit =~ s/%/%%/g;
	$escunit =~ s/:/\\:/g;
	$escunit =~ s/&nbsp;/ /g;

	$sin="In: "; $sout="Out:";
	$ssin = $ssout = "";
	$sin = $interfaces{$curif}{legendi}
		if( defined $interfaces{$curif}{legendi} );
	$sout= $interfaces{$curif}{legendo}
		if( defined $interfaces{$curif}{legendo} );
	$l = length $sin; $l = length $sout if($l < length $sout);
	$sin = substr($sin.'                ',0,$l);
	$sout= substr($sout.'                ',0,$l);
	$sin =~ s/:/\\:/g; $sout =~ s/:/\\:/g;
	$sin =~ s/%/%%/g; $sout =~ s/%/%%/g;
	if( $interfaces{$curif}{integer} ) {
		$ssin = "%5.0lf"; $ssout = "%5.0lf";
	} elsif( $interfaces{$curif}{fixunits} ) {
		$ssin = "%7.2lf "; $ssout = "%7.2lf ";
	} else {
		$ssin = "%6.2lf %s"; $ssout = "%6.2lf %s";
	}
	if( defined $config{'routers.cgi-legendunits'}
		and $config{'routers.cgi-legendunits'} =~ /y/i ) {
		$ssin .= $escunit; $ssout .= $escunit;
	}
	$sin .= $ssin; $sout .= $ssout;
	
	if ( $dwmy =~ /s/ ) {
		$lin=""; $lout="";
	} else {
		$lin = "Inbound"; $lout = "Outbound";
		$lin = $interfaces{$curif}{legend1}
			if( defined $interfaces{$curif}{legend1} );
		$lout = $interfaces{$curif}{legend2}
			if( defined $interfaces{$curif}{legend2} );
		if( $interfaces{$interface}{noo} or $interfaces{$interface}{noi} ) {
			$lin = $interfaces{$curif}{desc}." ($lin)";
			$lout= $interfaces{$curif}{desc}." ($lout)";
		}
		$lin =~ s/:/\\:/g; $lout=~ s/:/\\:/g;
		$lin = ':'.$lin; $lout = ':'.$lout;
		if($interfaces{$interface}{noo}) { $lin .= "\\l";  } 
		else { $lout .= "\\l"; }
	}
	$lin = substr( $lin."                                ",0,30 ) 
		if($lin and !$interfaces{$interface}{noo});

	if( $interfaces{$interface}{nolegend} or
		$interfaces{$interface}{nodetails} ) {
		$lin = $lout = "";
	}

	($ds0, $ds1) = ("ds0", "ds1");
	push @params,
		"DEF:in$ifcnt=".$defrrd.":$ds0:AVERAGE", 
		"DEF:out$ifcnt=".$defrrd.":$ds1:AVERAGE";
	($ds0, $ds1) = ("in$ifcnt", "out$ifcnt");
### do this if we are using BITS
	if( $interfaces{$curif}{mult} ne 1 ) {
		push @params, "CDEF:fin$ifcnt=$ds0,".$interfaces{$curif}{mult}.",*", 
			"CDEF:fout$ifcnt=$ds1,".$interfaces{$curif}{mult}.",*";
		($ds0, $ds1) = ("fin$ifcnt", "fout$ifcnt");
	}
	if( defined $interfaces{$curif}{factor} ) {
		push @params, "CDEF:ffin$ifcnt=$ds0,".$interfaces{$curif}{factor}.",*", 
			"CDEF:ffout$ifcnt=$ds1,".$interfaces{$curif}{factor}.",*";
		($ds0, $ds1) = ("ffin$ifcnt", "ffout$ifcnt");
	}
	if(!$interfaces{$curif}{noi} ) { $totindef .= ",$ds0,+";  $incnt++; }
	if(!$interfaces{$curif}{noo} ) { $totoutdef .= ",$ds1,+"; $outcnt++; }
#	now for the peaks stuff
	($mds0, $mds1) = ("ds0", "ds1");
	push @params,
		"DEF:min$ifcnt=".$defrrd.":$mds0:MAX", 
		"DEF:mout$ifcnt=".$defrrd.":$mds1:MAX";
	($mds0, $mds1) = ("min$ifcnt", "mout$ifcnt");
### Do this if we are using BITS
	if( $interfaces{$curif}{mult} ne 1 ) {
		push @params, "CDEF:fmin$ifcnt=$mds0,".$interfaces{$curif}{mult}.",*", 
			"CDEF:fmout$ifcnt=$mds1,".$interfaces{$curif}{mult}.",*";
		($mds0, $mds1) = ("fmin$ifcnt", "fmout$ifcnt");
	}
	if( defined $interfaces{$curif}{factor} ) {
		push @params,"CDEF:ffmin$ifcnt=$mds0,"
				.$interfaces{$curif}{factor}.",*", 
			"CDEF:ffmout$ifcnt=$mds1,".$interfaces{$curif}{factor}.",*";
		($mds0, $mds1) = ("ffmin$ifcnt", "ffmout$ifcnt");
	}
###
# And the percentages
	$max1 = $max2 = $interfaces{$curif}{max};
	$max1 = $interfaces{$curif}{max1} if(defined $interfaces{$curif}{max1});
	$max2 = $interfaces{$curif}{max2} if(defined $interfaces{$curif}{max2});
	if( $max1 && $dwmy !~ /s/ ) {
		push @params,
			"CDEF:pcin$ifcnt=$ds0,100,*,".$max1.",/",
			"CDEF:mpcin$ifcnt=$mds0,100,*,".$max1.",/";
	}
	if( $max2 && $dwmy !~ /s/ ) {
		push @params,
			"CDEF:pcout$ifcnt=$ds1,100,*,".$max2.",/",
			"CDEF:mpcout$ifcnt=$mds1,100,*,".$max2.",/";
	}

	if( !$interfaces{$interface}{nolegend} and 
		!$interfaces{$interface}{nodetails} ) {
		push @params, "COMMENT:".$interfaces{$curif}{desc}.":\\l"
			if(!$interfaces{$interface}{noi} and !$interfaces{$interface}{noo});
	}
	if(!$interfaces{$interface}{noi} and !$interfaces{$curif}{noi}) {
		$c = shift @clr; push @clr, $c;
		if( !$stacking ) {
			push @params, "LINE1:$ds0".$c.$lin ;
		} elsif( $stacking > 1 ) {
			push @params, "STACK:$ds0".$c.$lin ;
		} else {
			push @params, "AREA:$ds0".$c.$lin ;
			$stacking = 2;
		}
	}
	if(!$interfaces{$interface}{noo} and !$interfaces{$curif}{noo}) {
		$c = shift @clr; push @clr, $c;
		if( !$stacking ) {
			push @params, "LINE1:$ds1".$c.$lout ;
		} elsif( $stacking > 1 ) {
			push @params, "STACK:$ds1".$c.$lout ;
		} else {
			push @params, "AREA:$ds1".$c.$lout ;
			$stacking = 2;
		}
	}

#	now for the labels at the bottom
	if( !$interfaces{$interface}{nolegend} and
		!$interfaces{$interface}{nodetails} ) {
	if( $dwmy !~ /s/ ) {
		if( $max1 ) {
			if(!$interfaces{$interface}{noi}
				and !$interfaces{$curif}{noi}) {
				push @params, "GPRINT:$mds0:MAX:Max $sin\\g" ;
				push @params ,"GPRINT:mpcin$ifcnt:MAX: (%2.0lf%%)\\g"
					if($interfaces{$curif}{percent});
				push @params,"GPRINT:$ds0:AVERAGE:  Avg $sin\\g" ;
				push @params ,"GPRINT:pcin$ifcnt:AVERAGE: (%2.0lf%%)\\g"
					if($interfaces{$curif}{percent});
				push @params,"GPRINT:$ds0:LAST:  Cur $sin\\g" ;
				push @params ,"GPRINT:pcin$ifcnt:LAST: (%2.0lf%%)\\g"
					if($interfaces{$curif}{percent});
				push @params, "COMMENT:\\l" ;
			}
			if(!$interfaces{$interface}{noo}
				and !$interfaces{$curif}{noo}) {
				push @params, "GPRINT:$mds1:MAX:Max $sout\\g" ;
				push @params ,"GPRINT:mpcout$ifcnt:MAX: (%2.0lf%%)\\g"
					if($interfaces{$curif}{percent});
				push @params,"GPRINT:$ds1:AVERAGE:  Avg $sout\\g" ;
				push @params ,"GPRINT:pcout$ifcnt:AVERAGE: (%2.0lf%%)\\g"
					if($interfaces{$curif}{percent});
				push @params,"GPRINT:$ds1:LAST:  Cur $sout\\g" ;
				push @params ,"GPRINT:pcout$ifcnt:LAST: (%2.0lf%%)\\g"
					if($interfaces{$curif}{percent});
				push @params, "COMMENT:\\l" ;
			}
		} else {
			push @params,
			"GPRINT:$mds0:MAX:Max $sin\\g",
			"GPRINT:$ds0:AVERAGE:  Avg $sin\\g",
			"GPRINT:$ds0:LAST:  Cur $sin\\l" 
					if(!$interfaces{$interface}{noi}
						and !$interfaces{$curif}{noi});
			push @params,
			"GPRINT:$mds1:MAX:Max $sout\\g",
			"GPRINT:$ds1:AVERAGE:  Avg $sout\\g",
			"GPRINT:$ds1:LAST:  Cur $sout\\l"
					if(!$interfaces{$interface}{noo}
						and !$interfaces{$curif}{noo});
		}
	} else {
		($legendi,$legendo)=("IN:","OUT:");
		$legendi = $interfaces{$curif}{legendi} if(defined $interfaces{$curif}{legendi});
		$legendo = $interfaces{$curif}{legendo} if(defined $interfaces{$curif}{legendo});
		$legendi =~ s/:/\\:/g;
		$legendo =~ s/:/\\:/g;
		
		push @params,
			"PRINT:$mds0:MAX:".$q->b($legendi)." Max $ssin, ",
			"PRINT:$ds0:AVERAGE:Avg $ssin, ",
			"PRINT:$ds0:LAST:Last $ssin ".$q->br
					if(!$interfaces{$interface}{noi}
						and !$interfaces{$curif}{noi});
		push @params,
			"PRINT:$mds1:MAX:".$q->b($legendo)." Max $ssout, ",
			"PRINT:$ds1:AVERAGE:Avg $ssout, ",
			"PRINT:$ds1:LAST:Last $ssout ".$q->br
					if(!$interfaces{$interface}{noo}
						and !$interfaces{$curif}{noo});
	} # s mode
	} # not nolegend mode
	} # end of loop through interfaces

	# add total line if necessary
	if($interfaces{$interface}{withtotal} 
		or $interfaces{$interface}{withaverage} ) {
		push @params, $totindef if(!$interfaces{$interface}{noi} and $incnt);
		push @params, $totoutdef if(!$interfaces{$interface}{noo} and $outcnt);
		$lin = ":Total ".$interfaces{$interface}{legend1}; 
		$lin = ":".$interfaces{$interface}{legendti} 
			if($interfaces{$interface}{legendti});
		$lin = substr($lin.'                          ',0,30);
		if($interfaces{$interface}{noo} or !$outcnt) { $lin .= "\\l"; } 
		$lout = ":Total ".$interfaces{$interface}{legend2}."\\l";
		$lout = ":".$interfaces{$interface}{legendto}."\\l"
			if($interfaces{$interface}{legendto});
		if($interfaces{$interface}{withtotal} ) {
			if($interfaces{$interface}{nolegend} ) {
				$lin = $lout = "";
			} else {
				push @params, "COMMENT:Total values:\\l"
					if(!$interfaces{$interface}{noi} 
						and !$interfaces{$interface}{noo}
						and !$interfaces{$interface}{nodetails});
			}
			if(!$interfaces{$interface}{noi} and $incnt ) {
				$c = shift @clr; push @clr, $c;
				push @params, "LINE1:totin".$c.$lin;
			}
			if(!$interfaces{$interface}{noo} and $outcnt ) {
				$c = shift @clr; push @clr, $c;
				push @params, "LINE1:totout".$c.$lout;
			}
			if( $dwmy !~ /s/ ) {
				if(!$interfaces{$interface}{nolegend} ) {
				push @params,
				"GPRINT:totin:MAX:Max $sin\\g",
				"GPRINT:totin:AVERAGE:  Avg $sin\\g",
				"GPRINT:totin:LAST:  Cur $sin\\l" 
					if(!$interfaces{$interface}{noi} and $incnt);
				push @params,
				"GPRINT:totout:MAX:Max $sout\\g",
				"GPRINT:totout:AVERAGE:  Avg $sout\\g",
				"GPRINT:totout:LAST:  Cur $sout\\l"
					if(!$interfaces{$interface}{noo} and $outcnt);
				}
			} else {
				($legendi,$legendo)=("IN:","OUT:");
				$legendi = $interfaces{$interface}{legendi} 
					if(defined $interfaces{$interface}{legendi});
				$legendo = $interfaces{$interface}{legendo} 
					if(defined $interfaces{$interface}{legendo});
				$legendi =~ s/:/\\:/g;
				$legendo =~ s/:/\\:/g;
				push @params,
					"PRINT:totin:MAX:".$q->b($legendi)." Max $ssin, ",
					"PRINT:totin:AVERAGE:Avg $ssin, ",
					"PRINT:totin:LAST:Last $ssin ".$q->br
							if(!$interfaces{$interface}{noi} and $incnt);
				push @params,
					"PRINT:totout:MAX:".$q->b($legendo)." Max $ssout, ",
					"PRINT:totout:AVERAGE:Avg $ssout, ",
					"PRINT:totout:LAST:Last $ssout ".$q->br
							if(!$interfaces{$interface}{noo} and $outcnt);
			}
		}
	}

	# add average line if necessary
	if($interfaces{$interface}{withaverage} ) {
		push @params,"CDEF:avgin=totin,$incnt,/"
			if(!$interfaces{$interface}{noi} and $incnt);
		push @params,"CDEF:avgout=totout,$outcnt,/"
			if(!$interfaces{$interface}{noo} and $outcnt);
		$lin = ":Average ".$interfaces{$interface}{legend1}; 
		$lin = ":".$interfaces{$interface}{legendai} 
			if($interfaces{$interface}{legendai});
		$lin = substr($lin.'                          ',0,30);
		$lout= ":Average ".$interfaces{$interface}{legend2}."\\l";
		if($interfaces{$interface}{noo} or !$outcnt){ $lin .= "\\l"; } 
		$lout = ":".$interfaces{$interface}{legendao}."\\l"
			if($interfaces{$interface}{legendao});
		if($interfaces{$interface}{nolegend}) {
			$lin = $lout = "";
		} else {
			push @params, "COMMENT:Average values:\\l"
				if(!$interfaces{$interface}{noi} 
					and !$interfaces{$interface}{noo}
					and !$interfaces{$interface}{nodetails});
		}
		if(!$interfaces{$interface}{noi} and $incnt) {
			$c = shift @clr; push @clr, $c;
			push @params, "LINE1:avgin".$c.$lin;
		}
		if(!$interfaces{$interface}{noo} and $outcnt) {
			$c = shift @clr; push @clr, $c;
			push @params, "LINE1:avgout".$c.$lout;
		}
		if( $dwmy !~ /s/ ) {
			if(!$interfaces{$interface}{nolegend} ) {
				push @params,
				"GPRINT:avgin:MAX:Max $sin\\g",
				"GPRINT:avgin:AVERAGE:  Avg $sin\\g",
				"GPRINT:avgin:LAST:  Cur $sin\\l" 
					if(!$interfaces{$interface}{noi} and $incnt);
				push @params,
				"GPRINT:avgout:MAX:Max $sout\\g",
				"GPRINT:avgout:AVERAGE:  Avg $sout\\g",
				"GPRINT:avgout:LAST:  Cur $sout\\l"
					if(!$interfaces{$interface}{noo} and $outcnt);
			}
		} else {
			($legendi,$legendo)=("IN:","OUT:");
			$legendi = $interfaces{$interface}{legendi} 
				if(defined $interfaces{$interface}{legendi});
			$legendo = $interfaces{$interface}{legendo} 
				if(defined $interfaces{$interface}{legendo});
			$legendi =~ s/:/\\:/g;
			$legendo =~ s/:/\\:/g;
			push @params,
				"PRINT:avgin:MAX:".$q->b($legendi)." Max $ssin, ",
				"PRINT:avgin:AVERAGE:Avg $ssin, ",
				"PRINT:avgin:LAST:Last $ssin ".$q->br
						if(!$interfaces{$interface}{noi} and $incnt);
			push @params,
				"PRINT:avgout:MAX:".$q->b($legendo)." Max $ssout, ",
				"PRINT:avgout:AVERAGE:Avg $ssout, ",
				"PRINT:avgout:LAST:Last $ssout ".$q->br
						if(!$interfaces{$interface}{noo} and $outcnt);
		} # small graph
	} # with average line
} # usr_params

sub rtr_params(@)
{
	my($ds0,$ds1,$ds2,$mds0,$mds1, $mds2)=("","","","","","");
	my($lin, $lout, $mlin, $mlout, $lextra);
	my($dwmy,$interface) = @_;
	my($ssin, $ssout, $sin, $sout, $sext);
	my($l,$defrrd);
	my($workday) = 0;
	my($legendi,$legendo);
	my(@clr, $escunit);
	my($max1, $max2);

	# are we going to work out the 'working day' averages as well?
	if( defined $config{'routers.cgi-daystart'} 
		and defined $config{'routers.cgi-dayend'}
		and $config{'routers.cgi-daystart'}<$config{'routers.cgi-dayend'}
		and $dwmy !~ /y/ ){
		$workday = 1;
		$timezone = 0;
		# Calculate timezone.  We only need to do this if we're making a graph,
		# and we have a 'working day' defined.
		if( defined $config{'web-timezone'} ) {
			# If its been defined explicitly, then use that.
			$timezone = $config{'web-timezone'};
		} else {
			# Do we have Time::Zone?
			eval { require Time::Zone; };
			if ( $@ ) {
				my( @gm, @loc, $hourdif );
				eval { @gm = gmtime; @loc = localtime; };
				if( $@ ) {
					# Can't work out local timezone, so assume GMT
					$timezone = 0; 
				} else {
					$hourdif = $loc[2] - $gm[2];
					$hourdif += 24 if($loc[3]>$gm[3] or $loc[4]>$gm[4] );
					$hourdif -= 24 if($loc[3]<$gm[3] or $loc[4]<$gm[4] );
					$timezone = $hourdif;
				}
			} else {
				# Use the Time::Zone package since we have it
				$timezone = Time::Zone::tz_local_offset() / 3600; 
				# it's in seconds so /3600
			}
		}
	}

	# escaped unit string
	$escunit = $interfaces{$interface}{unit};
	$escunit =~ s/%/%%/g;
	$escunit =~ s/:/\\:/g;
	$escunit =~ s/&nbsp;/ /g;

	# identify colours
	if( defined $interfaces{$interface}{colours} ) {
		@clr = @{$interfaces{$interface}{colours}};
	}
	if(! @clr ) {
		if( $gstyle =~ /b/ ) {
			@clr =  ("#888888", "#000000", "#cccccc","#444444", "#222222");
		} else {
			@clr = ("#00cc00", "#0000ff","#006600", "#ff00ff", "#ff0000" );
		}
	}

	$defrrd = $interfaces{$interface}{rrd};
	$defrrd =~ s/:/\\:/g;

	$sin="In: "; $sout="Out:"; $sext = "Ext:";
	$ssin = $ssout = "";
	$sin = $interfaces{$interface}{legendi}
		if( defined $interfaces{$interface}{legendi} );
	$sout= $interfaces{$interface}{legendo}
		if( defined $interfaces{$interface}{legendo} );
	$l = length $sin; $l = length $sout if($l < length $sout);
	$sin = substr($sin.'                ',0,$l);
	$sout= substr($sout.'                ',0,$l);
	$sin =~ s/:/\\:/g; $sout =~ s/:/\\:/g;
	$sin =~ s/%/%%/g; $sout =~ s/%/%%/g;
	if( $interfaces{$interface}{integer} ) {
		$ssin = "%5.0lf"; $ssout = "%5.0lf";
	} elsif( $interfaces{$interface}{fixunits} ) {
		$ssin = "%7.2lf "; $ssout = "%7.2lf ";
	} else {
		$ssin = "%6.2lf %s"; $ssout = "%6.2lf %s";
	}
	if( defined $config{'routers.cgi-legendunits'}
		and $config{'routers.cgi-legendunits'} =~ /y/i ) {
		$ssin .= $escunit; $ssout .= $escunit;
	}
	$sin .= $ssin; $sout .= $ssout;
	if( $interfaces{$interface}{mode} eq "SERVER"
		and $interface eq "CPU" ) {
		$sin = "usr\\:%6.2lf%%"; $sout = "sys\\:%6.2lf%%"; 
		$sext = "wa\\: %6.2lf%%";
	}
	
	if ( $dwmy =~ /s/ ) {
		$lin=""; $lout=""; $lextra="";
		$mlin=""; $mlout="";
	} else {
		$lin = ":Inbound"; $lout = ":Outbound";
		$mlin = ":Peak Inbound"; $mlout = ":Peak Outbound";
		$lin = ":".$interfaces{$interface}{legend1}
			if( defined $interfaces{$interface}{legend1} );
		$lout = ":".$interfaces{$interface}{legend2}
			if( defined $interfaces{$interface}{legend2} );
		$mlin = ":".$interfaces{$interface}{legend3}
			if( defined $interfaces{$interface}{legend3} );
		$mlout = ":".$interfaces{$interface}{legend4}
			if( defined $interfaces{$interface}{legend4} );
		if($interfaces{$interface}{noo} ) {
			$lin .= "\\l";  
		} else { 
			if( defined $interfaces{$interface}{graphstyle} 
			and $interfaces{$interface}{graphstyle} =~ /range/i ) {
				$lin .= "\\l";  
			}
			$lout .= "\\l"; 
			$mlout .= "\\l" if( !$interfaces{$interface}{noi} );
		}
		$lextra = ":Other\\l";
		$lextra = ":".$interfaces{$interface}{legendx}."\\l"
			if( defined $interfaces{$interface}{legendx} );
	}
	$lin = substr( $lin."                                ",0,30 ) 
		if($lin and !$interfaces{$interface}{noo}
			and $lin !~ /\\l$/ );
	$mlin = substr( $mlin."                                ",0,30 ) 
		if ($mlin and $mlin !~ /\\l$/ );

	if( $interfaces{$interface}{nolegend} ) { $lin = $lout = ""; }

	($ds0, $ds1) = ("ds0", "ds1");
	if( $interfaces{$interface}{mode} eq "SERVER" ) {
		($ds0, $ds1, $ds2) = ("user", "system", "wait") if($interface eq "CPU");
		($ds0, $ds1) = ("page", "page") if($interface eq "Page");
		($ds0, $ds1) = ("usercount", "usercount") if($interface eq "Users");
	}
#	($ds0, $ds1) = ( $ds1, $ds0 ) if($interfaces{$interface}{reverse});
	push @params,
		"DEF:in=".$defrrd.":$ds0:AVERAGE", 
		"DEF:out=".$defrrd.":$ds1:AVERAGE";
	push @params,
		"DEF:extra=".$defrrd.":$ds2:AVERAGE"  if($ds2);
	($ds0, $ds1) = ("in", "out");
	$ds2 = "extra" if($ds2);
### do this if we are using BITS
	if( $interfaces{$interface}{mult} ne 1 ) {
		push @params, "CDEF:fin=$ds0,".$interfaces{$interface}{mult}.",*", 
			"CDEF:fout=$ds1,".$interfaces{$interface}{mult}.",*";
		($ds0, $ds1) = ("fin", "fout");
	}
###
	if( defined $interfaces{$interface}{factor} ) {
		push @params, "CDEF:ffin=$ds0,".$interfaces{$interface}{factor}.",*", 
			"CDEF:ffout=$ds1,".$interfaces{$interface}{factor}.",*";
		($ds0, $ds1) = ("ffin", "ffout");
	}
#	now for the peaks stuff
	($mds0, $mds1) = ("ds0", "ds1");
	if( $interfaces{$interface}{mode} eq "SERVER" ) {
		($mds0,$mds1,$mds2) = ("user","system","wait") if($interface eq "CPU");
		($mds0,$mds1) = ("page", "page") if($interface eq "Page");
		($mds0,$mds1) = ("usercount", "usercount") if($interface eq "Users");
	}
#	($mds0, $mds1) = ("ds1", "ds0") if($interfaces{$interface}{reverse});
	push @params,
		"DEF:min=".$defrrd.":$mds0:MAX", 
		"DEF:mout=".$defrrd.":$mds1:MAX";
	($mds0, $mds1) = ("min", "mout");
	if( $interfaces{$interface}{mode} eq "SERVER" and $mds2 ) {
		push @params, "DEF:mx=".$defrrd.":$mds2:MAX";
		$mds2 = "mx";
	}
### Do this if we are using BITS
	if( $interfaces{$interface}{mult} ne 1 ) {
		push @params, "CDEF:fmin=$mds0,".$interfaces{$interface}{mult}.",*", 
			"CDEF:fmout=$mds1,".$interfaces{$interface}{mult}.",*";
		($mds0, $mds1) = ("fmin", "fmout");
	}
###
	if( defined $interfaces{$interface}{factor} ) {
		push @params, "CDEF:ffmin=$mds0,".$interfaces{$interface}{factor}.",*", 
			"CDEF:ffmout=$mds1,".$interfaces{$interface}{factor}.",*";
		($mds0, $mds1) = ("ffmin", "ffmout");
	}
# And the percentages
	$max1 = $max2 = $interfaces{$interface}{max};
	$max1 = $interfaces{$interface}{max1} 
		if(defined $interfaces{$interface}{max1});
	$max2 = $interfaces{$interface}{max2} 
		if(defined $interfaces{$interface}{max2});
	if( $max1 && $dwmy !~ /s/ ) {
		push @params,
			"CDEF:pcin=$ds0,100,*,".$max1.",/",
			"CDEF:mpcin=$mds0,100,*,".$max1.",/";
	}
	if( $max2 && $dwmy !~ /s/ ) {
		push @params,
			"CDEF:pcout=$ds1,100,*,".$max2.",/",
			"CDEF:mpcout=$mds1,100,*,".$max2.",/";
	}

# Now the workday averages, if required
	if( $workday ) {
		push @params, "CDEF:wdin="
			."TIME,3600,/,$timezone,+,DUP,24,/,7,%,DUP,4,LT,EXC,2,GE,+,2,LT,"
			."EXC,24,%,DUP,"
			.trim($config{'routers.cgi-daystart'}).",GE,EXC,"
			.trim($config{'routers.cgi-dayend'}).",LT,+,2,EQ,$ds0,"
			."UNKN,IF,UNKN,IF",
			"CDEF:wdout="
			."TIME,3600,/,$timezone,+,DUP,24,/,7,%,DUP,4,LT,EXC,2,GE,+,2,LT,"
			."EXC,24,%,DUP,"
			.trim($config{'routers.cgi-daystart'}).",GE,EXC,"
			.trim($config{'routers.cgi-dayend'}).",LT,+,2,EQ,$ds1,"
			."UNKN,IF,UNKN,IF";
		push @params, "CDEF:wdx="
			."TIME,3600,/,$timezone,+,DUP,24,/,7,%,DUP,4,LT,EXC,2,GE,+,2,LT,"
			."EXC,24,%,DUP,"
			.trim($config{'routers.cgi-daystart'}).",GE,EXC,"
			.trim($config{'routers.cgi-dayend'}).",LT,+,2,EQ,$ds2,"
			."UNKN,IF,UNKN,IF" if($ds2);
		# mark the working day background, if not in b&w mode
		push @params, "CDEF:wd=wdin,UN,0,INF,IF", "AREA:wd#ffffcc"
			if( $gstyle !~ /b/ );
	}

	if( $interfaces{$interface}{mode} eq "SERVER" and $ds2 ) {
		push @params, "AREA:$ds0".$clr[0].$lin,
			"STACK:$ds1".$clr[1].$lout,
			"STACK:$ds2".$clr[4].$lextra;
	} else {
#	now for the actual lines : put the peaklines for d only if we have a 6 hr
#	dont forget to use more friendly colours if this is black and white mode
		if(!defined $config{'routers.cgi-withpeak'} 
			or $config{'routers.cgi-withpeak'} =~ /y/i ) {
			if( $dwmy =~ /[wmy]/ or ( $dwmy =~ /d/ and $usesixhour )) {
				push @params, "LINE1:$mds0".$clr[2].$mlin 
					if(!$interfaces{$interface}{noi});
				push @params, "LINE1:$mds1".$clr[3].$mlout
					if(!$interfaces{$interface}{noo});
			}
		} # with peaks
		push @params, "AREA:$ds0".$clr[0].$lin
			if(!$interfaces{$interface}{noi});
		if(!$interfaces{$interface}{noo}) {
			if( defined $interfaces{$interface}{graphstyle} ) {
				if( $interfaces{$interface}{graphstyle} =~ /stack/i ) {
					push @params, "STACK:$ds1".$clr[1].$lout;
				} elsif( $interfaces{$interface}{graphstyle} =~ /range/i ) {
					push @params, "AREA:$ds1#ffffff"; # erase lower part
					# if workingday active, put HIGHLIGHTED lower in
					if( $workday and $gstyle !~ /b/) {
						push @params, "CDEF:lwday=wdin,UN,0,$ds1,IF",
							"AREA:lwday#ffffcc";
					}
					push @params, "LINE1:$ds1".$clr[0]; # replace last pixel
				} else {
					push @params, "LINE1:$ds1".$clr[1].$lout;
				}
			} else {
				push @params, "LINE1:$ds1".$clr[1].$lout;
			}
		}
	} # server mode

# data unavailable
	push @params,
		"CDEF:down=in,UN,INF,0,IF","AREA:down#d0d0d0";
# the max line
	if( $interfaces{$interface}{max} 
		and ! ( defined $config{'routers.cgi-maxima'}
			and  $config{'routers.cgi-maxima'} =~ /n/i )
		and !$interfaces{$interface}{nomax}
	) {
		my( $lmax ) = "";
		my( $lamax ) = "";
		if( $dwmy !~ /s/ ) {
			if( defined $interfaces{$interface}{mblegend} ) {
				$lmax = $interfaces{$interface}{mblegend};
				$lmax =~ s/:/\\:/g; $lmax = ':'.$lmax;
			} elsif( $interfaces{$interface}{isif} ) {
				$lmax =":100% Bandwidth";
			} else { $lmax =":Maximum"; } 
			if( $max1 and $max2 and ($max1 != $max2) ) {
			$lmax .= " (".doformat($max1,$interfaces{$interface}{fixunits},0) 
				.$interfaces{$interface}{unit}.","
				.doformat($max2,$interfaces{$interface}{fixunits},0) 
				.$interfaces{$interface}{unit}.")\\l";
			} else {
			$lmax .= " (".doformat($interfaces{$interface}{max},
					$interfaces{$interface}{fixunits},0) 
				.$interfaces{$interface}{unit}.")\\l";
			}
			if( defined $interfaces{$interface}{absmax} ) {
				if( defined $interfaces{$interface}{amlegend} ) {
					$lamax = ":".$interfaces{$interface}{amlegend};
				} else { $lamax =":Hard Maximum"; } 
				$lamax .= " (".doformat($interfaces{$interface}{absmax},
					$interfaces{$interface}{fixunits},1) 
					.$interfaces{$interface}{unit}.")\\l";
			}
		}
		if( $max1 and $max2 and ($max1 != $max2)) {
			if( $gstyle =~ /b/ ) {
				push @params, "HRULE:".$max1."#cccccc$lmax";
				push @params, "HRULE:".$max2."#cccccc";
			} else {
				push @params, "HRULE:".$max1."#ff0000$lmax";
				push @params, "HRULE:".$max2."#ff0000";
			}
		} else {
			if( $gstyle =~ /b/ ) {
			push @params, "HRULE:".$interfaces{$interface}{max}."#cccccc$lmax";
			} else {
			push @params, "HRULE:".$interfaces{$interface}{max}."#ff0000$lmax";
			}
		}
		if( defined $interfaces{$interface}{absmax}
			and !$interfaces{$interface}{noabsmax} ) {
			if( $gstyle =~ /b/ ) {
				push @params, "HRULE:".$interfaces{$interface}{absmax}
					."#aaaaaa$lamax";
			} else {
				push @params, "HRULE:".$interfaces{$interface}{absmax}
					."#ff0080$lamax";
			}
		}
	}
#	now for the labels at the bottom
	if( $dwmy !~ /s/ ) {
		if( $max1 ) {
			if(!$interfaces{$interface}{noi}) {
				push @params, "GPRINT:$mds0:MAX:Max $sin\\g" ;
				push @params ,"GPRINT:mpcin:MAX: (%2.0lf%%)\\g"
					if($interfaces{$interface}{percent});
				push @params,"GPRINT:$ds0:AVERAGE:  Avg $sin\\g" ;
				push @params ,"GPRINT:pcin:AVERAGE: (%2.0lf%%)\\g"
					if($interfaces{$interface}{percent});
				push @params,"GPRINT:$ds0:LAST:  Cur $sin\\g" ;
				push @params ,"GPRINT:pcin:LAST: (%2.0lf%%)\\g"
					if($interfaces{$interface}{percent});
				push @params, "COMMENT:\\l" ;
			}
			if(!$interfaces{$interface}{noo}) {
				push @params, "GPRINT:$mds1:MAX:Max $sout\\g" ;
				push @params ,"GPRINT:mpcout:MAX: (%2.0lf%%)\\g"
					if($interfaces{$interface}{percent});
				push @params,"GPRINT:$ds1:AVERAGE:  Avg $sout\\g" ;
				push @params ,"GPRINT:pcout:AVERAGE: (%2.0lf%%)\\g"
					if($interfaces{$interface}{percent});
				push @params,"GPRINT:$ds1:LAST:  Cur $sout\\g" ;
				push @params ,"GPRINT:pcout:LAST: (%2.0lf%%)\\g"
					if($interfaces{$interface}{percent});
				push @params, "COMMENT:\\l" ;
			}
			if($ds2) {
				push @params, "GPRINT:$mds2:MAX:Max $sext\\g" ;
				push @params,"GPRINT:$ds2:AVERAGE:  Avg $sext\\g" ;
				push @params,"GPRINT:$ds2:LAST:  Cur $sext\\g" ;
				push @params, "COMMENT:\\l" ;
			}
			if($workday) {
				push @params, "COMMENT:Working day averages\\g";
				push @params,"GPRINT:wdin:AVERAGE: $sin\\g"
					if(!$interfaces{$interface}{noi});
				push @params,"GPRINT:wdout:AVERAGE: $sout\\g"
					if(!$interfaces{$interface}{noo});
				push @params,"GPRINT:wdx:AVERAGE: $sext\\g"
					if($ds2);
				push @params, "COMMENT:\\l";
			}
			if( defined $config{'routers.cgi-maxima'}
				and $config{'routers.cgi-maxima'} =~ /n/i
				and !$interfaces{$interface}{nomax} ) {
				my( $comment );
				if(defined $interfaces{$interface}{mblegend}) {
					$comment = $interfaces{$interface}{mblegend};
					$comment =~ s/:/\\:/g; $comment = "COMMENT:".$comment;
				} elsif($interfaces{$interface}{isif}) {
					$comment = "COMMENT:100% Bandwidth";
				} else {
					$comment = "COMMENT:Maximum value";
				}
				$comment .= " ".doformat($interfaces{$interface}{max},
						$interfaces{$interface}{fixunits},0)
					.$escunit."\\l";
				push @params, $comment;
 		 	}
		} else {
			push @params,
				"GPRINT:$mds0:MAX:Max $sin\\g",
				"GPRINT:$ds0:AVERAGE:  Avg $sin\\g",
				"GPRINT:$ds0:LAST:  Cur $sin\\l" 
					if(!$interfaces{$interface}{noi});
			push @params,
				"GPRINT:$mds1:MAX:Max $sout\\g",
				"GPRINT:$ds1:AVERAGE:  Avg $sout\\g",
				"GPRINT:$ds1:LAST:  Cur $sout\\l"
					if(!$interfaces{$interface}{noo});
			push @params,
				"GPRINT:$mds2:MAX:Max $sext\\g",
				"GPRINT:$ds2:AVERAGE:  Avg $sext\\g",
				"GPRINT:$ds2:LAST:  Cur $sext\\l"
					if($ds2);
			if($workday) {
				push @params, "COMMENT:Working day averages\\g";
				push @params,"GPRINT:wdin:AVERAGE: $sin\\g"
					if(!$interfaces{$interface}{noi});
				push @params,"GPRINT:wdout:AVERAGE: $sout\\g"
					if(!$interfaces{$interface}{noo});
				push @params,"GPRINT:wdx:AVERAGE: $sext\\g"
					if($ds2);
				push @params, "COMMENT:\\l";
			}
		}
	} else {
		($legendi,$legendo)=("IN:","OUT:");
		$legendi = $interfaces{$interface}{legendi} if(defined $interfaces{$interface}{legendi});
		$legendo = $interfaces{$interface}{legendo} if(defined $interfaces{$interface}{legendo});
		$legendi =~ s/:/\\:/g;
		$legendo =~ s/:/\\:/g;
		
		push @params,
			"PRINT:$mds0:MAX:".$q->b($legendi)." Max $ssin, ",
			"PRINT:$ds0:AVERAGE:Avg $ssin, ",
			"PRINT:$ds0:LAST:Last $ssin ".$q->br
					if(!$interfaces{$interface}{noi});
		push @params,
			"PRINT:$mds1:MAX:".$q->b($legendo)." Max $ssout, ",
			"PRINT:$ds1:AVERAGE:Avg $ssout, ",
			"PRINT:$ds1:LAST:Last $ssout ".$q->br
					if(!$interfaces{$interface}{noo});
		
		if($workday) {
			my($pfx) = "<TR><TD>Working day average\\:</TD>";
			my($sfx) = "";
			if(!$interfaces{$interface}{noi}) {
				$sfx = "</TR>" if($interfaces{$interface}{noo});
				push @params, 
					"PRINT:wdin:AVERAGE:$pfx<TD align=right>$ssin"
					."</TD>$sfx";
				$pfx = "";
			}
			push @params,
				"PRINT:wdout:AVERAGE:$pfx<TD align=right>$ssout"
					."</TD>$sfx"
				if(!$interfaces{$interface}{noo});
		}
	}
}

########################################################################
# Actually create the necessary graph, and output the IMG tag.

sub make_graph(@)
{
	my ($e, $thisgraph, $thisurl, $s, $autoscale);
	my ($tstr, $gheight, $width, $gwidth, $gtitle);
	my( $maxwidth ) = 30;
	my( $endtime );
	my($dwmy,$interface) = @_;

# Shall we scale it, etc
	$autoscale = 1;
	$s = $dwmy; $s =~ s/s//;
	if( $interfaces{$interface}{unscaled} ) {
		$autoscale = 0 if ($interfaces{$interface}{unscaled} =~ /$s/i);
	}

	$tstr = "6-hour" if( $dwmy =~ /6/ ) ;
	$tstr = "Daily" if( $dwmy =~ /d/ ) ;
	$tstr = "Weekly" if( $dwmy =~ /w/ ) ;
	$tstr = "Monthly" if( $dwmy =~ /m/ ) ;
	$tstr = "Yearly" if( $dwmy =~ /y/ ) ;

	$gtitle = $interfaces{$interface}{desc};
	if( ($dwmy.$gstyle)=~/s/ ) {
		if($gstyle=~/x/) { $maxwidth = 50; }
		elsif($gstyle=~/l/) { $maxwidth = 40; }
		else { $maxwidth = 30; }
	}
	if(!$gtitle or ((length($gtitle)>$maxwidth)and(($dwmy.$gstyle) =~ /s/))) {
		$gtitle = "";
		$gtitle .= $routers{$router}{shdesc}.": " 
				if( defined $routers{$router}{shdesc});
		$gtitle .= $interfaces{$interface}{shdesc};
	}

	@params = ();
	$thisgraph = "${router}-${interface}-${dwmy}-${gstyle}.${graphsuffix}";
	$thisgraph =~ s/[\?#\/\\]//g;
	$thisurl   = $config{'routers.cgi-graphurl'}."/".$q->escape($thisgraph);
	$thisgraph = $config{'routers.cgi-graphpath'}.$pathsep.$thisgraph;

	# width is the data unit width (400 max). gwidth is the pixel width of
	# the actual graph.  Thus, if gwidth > width, it is stretched.
	# Short: for PDAs, unstretched, shorter data window
	# Stretch: normal graph size, short data window (for easier viewing)
	# Long: normal data width, slightly bigger graph (for 800/600 screens)
	# Xlong: normal data width, double graph size (for 1024/768 screens)
	# gheight is the height of the graphic.  This is doubled for
	# Tall (n2), big (l2) and huge (x2).
	# The 1st char is the width indicator, then optional 2 (double height) and
	# b (black & white)
	if ( $gstyle =~ /^s/ ) { $width = 200; $gwidth = 200; } #short
	elsif ( $gstyle =~ /^t/ ) { $width = 200; $gwidth = 400; } #stretch
	elsif ( $gstyle =~ /^l/ ) { $width = 400; $gwidth = 530; } #long
	elsif ( $gstyle =~ /^x/ ) { $width = 400; $gwidth = 800; } #xlong
	else { $width = 400; $gwidth = 400; } # default (normal)
	if ( $gstyle =~ /2/ ) { $gheight = 200; }
	else { $gheight = 100; }
	# now, if $dwmy contains an s, this is a summary graph, and should be
	# half of the expected data width and half the expected screen width.
	# We also force the graph to be normal height.
	# The magic 60 in the graph width is the width of the axis, as gwidth is
	# the width of the AXIS, not the width of the graphic.
	if ( $dwmy =~ /s/ ) { $width /= 2;  $gwidth = $gwidth/2 - 60; 
		$gheight = 100; }

	push @params, $thisgraph;
	if( $graphsuffix eq "png" ) {
		push @params, '--imgformat',uc $graphsuffix;
	}
	push @params,"--base", $k;
	push @params, qw/--lazy -l 0 --interlaced/;
	push @params,"--units-exponent",0
		if($interfaces{$interface}{fixunits}
			and $RRDs::VERSION >= 1.00030 );
	# only force the minimum upper-bound of graph if we have a max,
	# and we dont have maxima=n, and we dont have unscaled=n
	if( ! $autoscale ) {
		if( $interfaces{$interface}{max} and ( 
			!defined $config{'routers.cgi-maxima'}
			or $config{'routers.cgi-maxima'} !~ /n/i
		) ) {
			push @params, "-u", $interfaces{$interface}{max} ;
		} else {
			push @params, "-u", 1;
		}
	} else {
		push @params, "-u", 1;
	}
# could have added a "-r" there to enforce the upper limit rigidly
#	push @params, "-v", $config{$statistic}{-v};
	push @params, "-w", $gwidth, "-h", $gheight;
	if( $dwmy =~ /-/ ) {
		if ( $dwmy =~ /6/ ) {
			push @params, "-e", "now-6h"; $endtime=time - (6*3600); }
		if ( $dwmy =~ /d/ ) {
			push @params, "-e", "now-24h"; $endtime=time - (24*3600); }
		if ( $dwmy =~ /w/ ) {
			push @params, "-e", "now-7d"; $endtime=time - (7*24*3600); }
		if ( $dwmy =~ /m/ ) {
			push @params, "-e", "now-30d"; $endtime=time - (30*24*3600); }
		if ( $dwmy =~ /y/ )  {
			push @params, "-e", "now-365d"; $endtime = time - (365*24*3600); }
	} elsif($lastupdate and $uselastupdate) {
		push @params, "-e", $lastupdate;
		$endtime = $lastupdate;
	} else {
		$endtime = time;
	}
	push @params, "-s", "end".(-1 * $width)."m"  if ( $dwmy =~ /6/ );
	push @params, "-s", "end".(-5 * $width)."m"  if ( $dwmy =~ /d/ );
	push @params, "-s", "end".(-25 * $width)."m" if ( $dwmy =~ /w/ );
	push @params, "-s", "end".(-2 * $width)."h"  if ( $dwmy =~ /m/ );
	push @params, "-s", "end".(-1 * $width)."d"   if ( $dwmy =~ /y/ );
	push @params,"--x-grid","MINUTE:15:HOUR:1:HOUR:1:0:$dailylabel"  
		if ( $dwmy =~ /6/ );
	push @params,"--x-grid","HOUR:1:HOUR:24:HOUR:2:0:$dailylabel"  
		if ( $dwmy =~ /d/ );
	push @params,"--x-grid","HOUR:6:DAY:1:DAY:1:86400:%a" 
		if ( $dwmy =~ /w/ );
	push @params,"--x-grid","DAY:1:WEEK:1:WEEK:1:604800:Week"
			.(($NT and $RRDs::VERSION < 1.00039)?"_":" ").$monthlylabel  
		if ( $dwmy =~ /m/ and $RRDs::VERSION >= 1.00029  );
	push @params,"--title", $gtitle;

	if ( defined $interfaces{$interface}{ylegend} ) {
		push @params, "--vertical-label", $interfaces{$interface}{ylegend};
	} else {
		push @params, "--vertical-label", $interfaces{$interface}{unit};
	}

	if( $interfaces{$interface}{usergraph} ) {
		usr_params($dwmy,$interface);
	} else {
		rtr_params($dwmy,$interface);
	}

	if ( defined $config{'routers.cgi-withdate'}
		and $config{'routers.cgi-withdate'}=~/y/ ) {
		push @params, "COMMENT:".shortdate($endtime)."\\r";
	}
	

	if($config{'routers.cgi-debug'} and $pagetype ne "image") {
		print "\n<!--- Call to RRDs\nrrdtool graph \n";
		foreach ( @params ) { print "'$_'\n"; }
		print " -->\n";
	}

	( $rrdoutput, $rrdxsize, $rrdysize ) = RRDs::graph(@params);
	$e = RRDs::error();
	if ( $pagetype eq "image" ) {
		if($e) {
		print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
		} else {
			# output the graphic directly from disk
			open GRAPH, "<$thisgraph";
			binmode GRAPH;
			binmode STDOUT;
			print $q->header({ -type=>"image/$graphsuffix", -expires=>"now",
				-Content-Disposition=>"filename=\"image.$graphsuffix\"" });
			while( <GRAPH> ) { print; }
			close GRAPH;
		}
		return;	
	}
	if ( $e ) {
		print $q->p("RRD Error: $e"),"\n";
		print $q->p("You can visit the configuration verification page "
			.$q->a({href=>("$meurl?page=verify&rtr="
				.$q->escape($router)),target=>"_new"},"here."));
		print $q->p("RRD: ".$interfaces{$interface}{rrd}.$q->br.
			"Device: [$router] ".$routers{$router}{desc}.$q->br.
			"Interface: $interface".$q->br.
			"Interfaces: ".(join ",",keys(%interfaces))
		);
		print "Params: ".(join " ",@params).$q->br;
	} else {
		print $q->img({src=>$thisurl,alt => $gtitle,border => 0,
			width => $rrdxsize, height => $rrdysize });
		if( $archiveme ) {
			# copy this graph into the archive dir, 
			# graphdir/file/target/ymdhm-siz.ext
			my( $arch ) = "";
			my( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time);
			$arch = $router; $arch =~ s/[\?#\/\\]//g;
			$arch = $config{'routers.cgi-graphpath'}.$pathsep.$arch;
			mkdir $arch,0755 if(! -d $arch);
			$arch .= $pathsep.$interface;
			mkdir $arch,0755 if(! -d $arch);
			$min = '0'.$min if($min < 10);
			$mday = '0'.$mday if($mday < 10);
			$mon += 1; $mon = '0'.$mon if($mon < 10);
			$arch .= $pathsep.($year +1900).'-'.$mon.'-'
				.$mday.'-'.$hour.'-'.$min.'-'.$dwmy.'.'.$graphsuffix;
			if( open ARCH, '>'.$arch ) {
				binmode ARCH;
				if( open GRAPH, '<'.$thisgraph ) {
					binmode GRAPH;
					while ( <GRAPH> ) { print ARCH; }
					print $q->br.$q->b("Archived OK");
					close GRAPH;
				} else {
					print $q->br.$q->b("Archiving FAILED (cannot read)");
				}
				close ARCH;
			} else {
				print $q->br.$q->b("Archiving FAILED (cannot write)");
			}
		}
	}
}

###############
# Calculations of average and max from fetched data
sub get_max($)
{
	my($rows) = $_[0];
	my($maxin, $maxout) = (0,0);

	foreach ( @$rows ) {
		$maxin = $$_[0] if($$_[0]>$maxin);
		$maxout = $$_[1] if($$_[1]>$maxout);
	}
	return ($maxin, $maxout);
}
sub get_avg($)
{
	my($rows) = $_[0];
	my($avgin, $avgout) = (0,0);
	my($numrows) = $#{@$rows};

	return (0,0) if($numrows < 1);
	foreach ( @$rows ) { 
		$avgin += $$_[0];
		$avgout += $$_[1];
	}
	$avgin /= $numrows;
	$avgout /= $numrows;

	return ($avgin,$avgout);
}
#######################################################
# For the compact summary.  This will call the bar function a lot!
# bar images are: $meurl?page=bar&IN=xx&OUT=yy for percentages xx yy
# images are 400x15 pixels
sub do_compact()
{
my ($javascript);
my ($curif);
my ($e, $interval, $resolution, $rrd, $seconds);
my ($curin, $curout, $avgin, $avgout, $maxin, $maxout );
my ($curinpc, $curoutpc, $avginpc, $avgoutpc, $maxinpc, $maxoutpc );
my ($perinpc, $peroutpc, $perin, $perout);
my ($start, $from, $step, $names, $values);
my ($c,$a,$m,$p,$io, $heading);
my ($d, $inarr, $outarr,$barlen);
my (@iforder);
my ($legendi,$legendo,$fix,$intf);
my ($unit) = "";
my ($max1, $max2);

$javascript = make_javascript({});

print $q->start_html({ -title => $toptitle, -bgcolor => $defbgcolour,
	-link=>$linkcolour, -vlink=>$linkcolour, -alink=>$linkcolour,
	-expires => "+5s",  -script => $javascript,
	-onload => "LoadMenu()" }),"\n";
print $config{'routers.cgi-pagetop'},"\n"
	if( defined $config{'routers.cgi-pagetop'} );
#
# Now for the RRD stuff
eval { require 'RRDs.pm'; };
if( $@ ) {
	print $q->h1("Error")."<CODE>Cannot find RRDs.pm in ".(join " ",@INC )."</CODE>\n";
	print $q->p("You can visit the configuration verification page "
		.$q->a({href=>("$meurl?page=verify&rtr=".$q->escape($router)),
		target=>"_new"},"here."));
	do_footer();
	return;
}

# First, the header to select which are visible:
($c,$a,$m,$p,$io) = ("","","","","i");
$c = $1 if( $baropts =~ /(c)/i ); # this preserves the case
$a = $1 if( $baropts =~ /(a)/i );
$m = $1 if( $baropts =~ /(m)/i );
$p = $1 if( $baropts =~ /(p)/i );
if( $baropts =~ /o/i ) { $io = "o"; } else { $io = "i"; }
print "<TABLE width=100% border=0 cellspacing=0 cellpadding=0><TR>\n";
print "<TD><SMALL>Last: "
	.$q->a({href=>"$meurl?".optionstring({bars=>"Ci".(lc "$a$m$p")})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}sort-g-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Sort by current incoming"})
	).$q->a({href=>"$meurl?".optionstring({bars=>"Co".(lc "$a$m$p")})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}sort-b-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Sort by current outgoing"})
	);
if( $c ) {
	print $q->a({href=>"$meurl?".optionstring({bars=>"$a$m$p$io"})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}cross-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Remove current bar"})
	);
} else {
	print $q->a({href=>"$meurl?".optionstring({bars=>"c$a$m$p$io"})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}tick-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Add Current bar"})
	);
}
print "</SMALL></TD>\n";
print "<TD><SMALL>Average: "
	.$q->a({href=>"$meurl?".optionstring({bars=>"Ai".(lc "$c$m$p")})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}sort-g-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Sort by average incoming"})
	).$q->a({href=>"$meurl?".optionstring({bars=>"Ao".(lc "$c$m$p")})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}sort-b-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Sort by average outgoing"})
	);
if( $a ) {
	print $q->a({href=>"$meurl?".optionstring({bars=>"$c$m$p$io"})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}cross-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Remove Average bar"})
	);
} else {
	print $q->a({href=>"$meurl?".optionstring({bars=>"a$c$m$p$io"})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}tick-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Add Average bar"}));
}
print "</SMALL></TD>\n";
print "<TD><SMALL>Maximum: "
	.$q->a({href=>"$meurl?".optionstring({bars=>"Mi".(lc "$c$a$p")})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}sort-g-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Sort by Maximum incoming"})
	).$q->a({href=>"$meurl?".optionstring({bars=>"Mo".(lc "$c$a$p")})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}sort-b-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Sort by Maximum outgoing"})
	);
if( $m ) {
	print $q->a({href=>"$meurl?".optionstring({bars=>"$a$c$p$io"})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}cross-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Remove Maximum bar"}));
} else {
	print $q->a({href=>"$meurl?".optionstring({bars=>"m$a$c$p$io"})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}tick-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Add Maximum bar"}));
}
print "</SMALL></TD>\n";
if( defined $config{'routers.cgi-percentile'}
	and $config{'routers.cgi-percentile'} =~ /y/i ) {
	print "<TD><SMALL>95<SUP>th</SUP> Percentile: "
		.$q->a({href=>"$meurl?".optionstring({bars=>"Pi".(lc "$c$a$m")})},
			$q->img({src=>"${config{'routers.cgi-iconurl'}}sort-g-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Sort by Incoming 95th percentile"})
		).$q->a({href=>"$meurl?".optionstring({bars=>"Po".(lc "$c$a$m")})},
			$q->img({src=>"${config{'routers.cgi-iconurl'}}sort-b-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Sort by Outgoing 95th percentile"})
		);
	if( $p ) {
		print $q->a({href=>"$meurl?".optionstring({bars=>"$a$m$c$io"})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}cross-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Remove 95th percentile bar"}));
	} else {
		print $q->a({href=>"$meurl?".optionstring({bars=>"p$a$m$c$io"})},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}tick-vsm.gif",
			border=>0,height=>10,width=>10,alt=>"Add 95th percentile bar"}));
	}
	print "</SMALL></TD>\n";
}
print "</TR></TABLE>\n";

# Now, we set up the necessary resolution variables to use in the fetch:
$resolution = 60; $interval = "6h"; $seconds = 6*3600;
$heading = "Six hourly calculations";
if ( $gtype =~ /d/ ) { $resolution=300; $interval="24h"; $seconds=86400; 
	$heading = "Daily calculations"; }
elsif ($gtype =~ /w/){ $resolution=1800; $interval="7d"; $seconds=7*86400; 
	$heading = "Weekly calculations"; }
elsif ($gtype =~ /m/){ $resolution=7200; $interval="1month"; $seconds=30*86400;
	$heading = "Monthly calculations"; }
elsif ($gtype =~ /y/){ $resolution=86400; $interval="1y"; $seconds=365*86400;
	$heading = "Yearly calculations"; }

print $q->h2($heading);

# we now process each interface with incompact=>1 in turn.
foreach $curif ( keys(%interfaces) ) {
	next if(!$curif); # avoid rogue records
	next if(!$interfaces{$curif}{incompact});

	$interfaces{$curif}{errors} = "";

	# now we fetch the necessary information from the RRD
	$curin = $maxin = $avgin = -1; # error
	$from = "now"; $e = 0;
	$rrd = $interfaces{$curif}{rrd};
	if( $gtype =~ /-/ ) {
		$from = "now-$interval";
	} elsif($config{'routers.cgi-uselastupdate'}=~/y/) {
		$from = RRDs::last($rrd);
		$e = RRDs::error();
		if($e) {
			$from = "now";
			$interfaces{$curif}{errors}.= $q->br.$q->small("Error: $e")."\n";
		}
	}
	$max1 = $max2 = $interfaces{$curif}{max};
	$max1 = $interfaces{$curif}{max1} if(defined $interfaces{$curif}{max1});
	$max2 = $interfaces{$curif}{max2} if(defined $interfaces{$curif}{max2});
	$lastupdate = $from;
	if( $c ) {
	( $start, $step, $names, $values ) = 
		RRDs::fetch($rrd,"AVERAGE","-s","$from-$resolution",
			"-e",$from,"-r",$resolution);
	$e = RRDs::error();
	if($e) { 
		$interfaces{$curif}{errors} .= $q->br.$q->small("Error: $e");
	} else {
		( $curin, $curout ) = @{$values->[0]};
		$curin *= $interfaces{$curif}{mult}; 
		$curout *= $interfaces{$curif}{mult};
		$curin = 0 if($interfaces{$curif}{noi});
		$curout= 0 if($interfaces{$curif}{noo});
	}
	if(defined $curin) { $curinpc = $curin*100.0/$max1; }
	else { $curin = -1; $curinpc = 0; }
	if(defined $curout) { $curoutpc = $curout*100.0/$max2; }
	else { $curout = -1; $curoutpc = 0; }
	$interfaces{$curif}{barcurin}    = $curin;
	$interfaces{$curif}{barcurinpc}  = $curinpc;
	$interfaces{$curif}{barcurout}   = $curout;
	$interfaces{$curif}{barcuroutpc} = $curoutpc;
	} # c
	if( $a ) {
	( $start, $step, $names, $values ) = 
		RRDs::fetch($rrd,"AVERAGE","-s","$from-$interval",
			"-e",$from,"-r",$seconds);
	$e = RRDs::error();
	if($e) { 
		$interfaces{$curif}{errors} .= $q->br.$q->small("Error: $e");
	} else {
		($avgin, $avgout) = get_avg($values);
		$avgin *= $interfaces{$curif}{mult}; 
		$avgout *= $interfaces{$curif}{mult};
		$avgin = 0 if($interfaces{$curif}{noi});
		$avgout= 0 if($interfaces{$curif}{noo});
	}
	if(defined $avgin) { $avginpc = $avgin*100.0/$max1; }
	else { $avgin = -1; $avginpc = 0; }
	if(defined $avgout) { $avgoutpc = $avgout*100.0/$max2; }
	else { $avgout = -1; $avgoutpc = 0; }
	$interfaces{$curif}{baravgin}    = $avgin;
	$interfaces{$curif}{baravgout}   = $avgout;
	$interfaces{$curif}{baravginpc}  = $avginpc;
	$interfaces{$curif}{baravgoutpc} = $avgoutpc;
	} # a
	if( $m ) {
	( $start, $step, $names, $values ) = 
		RRDs::fetch($rrd,"MAX","-s","$from-$interval",
			"-e",$from,"-r",$seconds);
	$e = RRDs::error();
	if($e) { 
		$interfaces{$curif}{errors} .= $q->br.$q->small("Error: $e");
	} else {
		($maxin, $maxout) = get_max($values);
		$maxin *= $interfaces{$curif}{mult}; 
		$maxout *= $interfaces{$curif}{mult};
		$maxin = 0 if($interfaces{$curif}{noi});
		$maxout= 0 if($interfaces{$curif}{noo});
	}
	if(defined $maxin) { $maxinpc = $maxin*100.0/$max1; }
	else { $maxin = -1; $maxinpc = 0; }
	if(defined $maxout) { $maxoutpc = $maxout*100.0/$max2; }
	else { $maxout = -1; $maxoutpc = 0; }
	$interfaces{$curif}{barmaxin}    = $maxin;
	$interfaces{$curif}{barmaxout}   = $maxout;
	$interfaces{$curif}{barmaxinpc}  = $maxinpc;
	$interfaces{$curif}{barmaxoutpc} = $maxoutpc;
	} # m
	if( $p ) {
		($d,$inarr,$outarr) = calc_percentile($curif,$gtype,95);
		$perin = ${$inarr}[0];
		$perout= ${$outarr}[0];
		$perin = 0 if($interfaces{$curif}{noi});
		$perout= 0 if($interfaces{$curif}{noo});
		if(defined $perin) { $perinpc = $perin*100.0/$max1; }
		else { $perin = -1; $perinpc = 0; }
		if(defined $perout) { $peroutpc = $perout*100.0/$max2; }
		else { $perout = -1; $peroutpc = 0; }
		$interfaces{$curif}{barperin}    = $perin;
		$interfaces{$curif}{barperout}   = $perout;
		$interfaces{$curif}{barperinpc}  = $perinpc;
		$interfaces{$curif}{barperoutpc} = $peroutpc;
		if(!$d) {
			$interfaces{$curif}{errors} .= $q->br.$q->small($$inarr[2])
				.$q->br.$q->small($$outarr[2]);
		}
	} # p
} # end of data collection
	
# Work out the order of the interfaces
$traffic = "";
if ( $c eq "C" ) {
	$traffic = "cur";
} elsif( $a eq "A" ) {
	$traffic = "avg";
} elsif( $m eq "M" ) {
	$traffic = "max";
} elsif( $p eq "P" and defined $config{'routers.cgi-percentile'}
  and $config{'routers.cgi-percentile'} =~ /y/i ) {
	$traffic = "per";
}
if($traffic) {
	$traffic .= 'in' if( $io eq "i" );
	$traffic .= 'out' if( $io eq "o" );
	$traffic = 'bar'.$traffic.'pc';
	@iforder = sort bytraffic keys(%interfaces);
} else {
	@iforder = sort byifdesc keys(%interfaces);
}

# we now print the bars.
$barlen = 400;                            # 800x600
$barlen = 600 if ( $gstyle =~ /x/i );     # 1024x768
$barlen = 280 if ( $gstyle =~ /[nts]/i ); # 640x480 and pda
print "<TABLE border=0 cellpadding=0 cellspacing=0 nowrap>\n";
foreach $curif ( @iforder ) {
	next if(!$curif); # avoid rogue records
	next if(!$interfaces{$curif}{incompact});

	# the unit string, if any
	$unit = "";
	$unit = $interfaces{$curif}{unit}
		if(!defined $config{'routers.cgi-legendunits'}
			or $config{'routers.cgi-legendunits'} =~ /y/i );
	$fix = $interfaces{$curif}{fixunits};
	$fix = 0 if(!defined $fix);
	$intf = $interfaces{$curif}{integer};
	$intf = 0 if(!defined $intf);

	# the legends
	($legendi,$legendo)=("IN","OUT");
	$legendi = $interfaces{$curif}{legendi} if(defined $interfaces{$curif}{legendi});
	$legendo = $interfaces{$curif}{legendo} if(defined $interfaces{$curif}{legendo});
	$legendi = "" if($interfaces{$curif}{noi});
	$legendo = "" if($interfaces{$curif}{noo});

	print "<TR><TD align=left colspan=2 width=$barlen>\n";
	print $q->a({href=>"$meurl?".optionstring({if=>$curif})},
		$q->small($interfaces{$curif}{desc}
		.(($interfaces{$curif}{desc} ne $interfaces{$curif}{shdesc})?
			(" (".$interfaces{$curif}{shdesc}.")"):"")
		))."\n";
	print $interfaces{$curif}{errors};
	print "</TD><TD align=center valign=bottom><B><FONT color=#00d000><SMALL>$legendi</SMALL></FONT></B></TD><TD align=center valign=bottom><B><FONT color=#0000ff><SMALL>$legendo</SMALL></FONT></B></TD></TR>\n";

	# now print the bar graphs up
	if( $c ) {
	$curin =   $interfaces{$curif}{barcurin};
	$curout=   $interfaces{$curif}{barcurout};
	$curinpc = $interfaces{$curif}{barcurinpc};
	$curoutpc= $interfaces{$curif}{barcuroutpc};
	print "<TR><TD align=left><SMALL>Last</SMALL></TD><TD align=left width=$barlen nowrap><SMALL>";
	print $q->img({border=>0,height=>10,width=>$barlen,src=>"$meurl?page=bar&L=$barlen&IN=$curinpc&OUT=$curoutpc"});
	print "</SMALL></TD><TD align=right nowrap>";
	print $q->small("&nbsp;&nbsp;<FONT color=#00d000>".doformat($curin,$fix,$intf)
		."$unit</FONT>")
		if($curin>=0 and $legendi);
	print $q->small(" <FONT color=#00d000>(".doformat($curinpc,1,0)."%)</FONT>")
		if($curinpc>=0 and $legendi and $interfaces{$curif}{percent});
	print "</TD><TD align=right nowrap>";
	print $q->small("&nbsp;&nbsp;<FONT color=#0000ff>".doformat($curout,$fix,$intf)
		."$unit</FONT>")
		if($curout>=0 and $legendo);
	print $q->small(" <FONT color=#0000ff>(".doformat($curoutpc,1,0)."%)</FONT>")
		if($curoutpc>=0 and $legendo and $interfaces{$curif}{percent});
	print "</TD></TR>\n";
	} # c
	if( $a ) {
	$avgin =   $interfaces{$curif}{baravgin};
	$avgout=   $interfaces{$curif}{baravgout};
	$avginpc = $interfaces{$curif}{baravginpc};
	$avgoutpc= $interfaces{$curif}{baravgoutpc};
	print "<TR><TD align=left><SMALL>Avg</SMALL></TD><TD align=left><SMALL>";
	print $q->img({border=>0,height=>10,width=>$barlen,src=>"$meurl?page=bar&L=$barlen&IN=$avginpc&OUT=$avgoutpc"});
	print "</SMALL></TD><TD align=right nowrap>";
	print $q->small("&nbsp;&nbsp;<FONT color=#00d000>".doformat($avgin,$fix,$intf)."$unit</FONT>")
		if($avgin>=0 and $legendi);
	print $q->small(" <FONT color=#00d000>(".doformat($avginpc,1,0)."%)</FONT>")
		if($avginpc>=0 and $legendi and $interfaces{$curif}{percent});
	print "</TD><TD align=right nowrap>";
	print $q->small("&nbsp;&nbsp;<FONT color=#0000ff>".doformat($avgout,$fix,$intf)."$unit</FONT>")
		if($avgout>=0 and $legendo);
	print $q->small(" <FONT color=#0000ff>(".doformat($avgoutpc,1,0)."%)</FONT>")
		if($avgoutpc>=0 and $legendo and $interfaces{$curif}{percent});
	print "</TD></TR>\n";
	} # a
	if( $m ) {
	$maxin =   $interfaces{$curif}{barmaxin};
	$maxout=   $interfaces{$curif}{barmaxout};
	$maxinpc = $interfaces{$curif}{barmaxinpc};
	$maxoutpc= $interfaces{$curif}{barmaxoutpc};
	print "<TR><TD align=left><SMALL>Max</SMALL></TD><TD align=left><SMALL>";
	print $q->img({border=>0,height=>10,width=>$barlen,src=>"$meurl?page=bar&L=$barlen&IN=$maxinpc&OUT=$maxoutpc"});
	print "</SMALL></TD><TD align=right nowrap>";
	print $q->small("&nbsp;&nbsp;<FONT color=#00d000>".doformat($maxin,$fix,$intf)."$unit</FONT>")
		if($maxin>=0 and $legendi);
	print $q->small(" <FONT color=#00d000>(".doformat($maxinpc,1,0)."%)</FONT>")
		if($maxinpc>=0 and $legendi and $interfaces{$curif}{percent});
	print "</TD><TD align=right nowrap>";
	print $q->small("&nbsp;&nbsp;<FONT color=#0000ff>".doformat($maxout,$fix,$intf)."$unit</FONT>")
		if($maxout>=0 and $legendo);
	print $q->small(" <FONT color=#0000ff>(".doformat($maxoutpc,1,0)."%)</FONT>")
		if($maxoutpc>=0 and $legendo and $interfaces{$curif}{percent});
	print "</TD></TR>\n";
	} # m
	if( $p ) {
	$perin =   $interfaces{$curif}{barperin};
	$perout=   $interfaces{$curif}{barperout};
	$perinpc = $interfaces{$curif}{barperinpc};
	$peroutpc= $interfaces{$curif}{barperoutpc};
	print "<TR><TD align=left><SMALL>95<sup>th</sup></SMALL></TD><TD align=left><SMALL>";
	print $q->img({border=>0,height=>10,width=>$barlen,src=>"$meurl?page=bar&L=$barlen&IN=$perinpc&OUT=$peroutpc"});
	print "</SMALL></TD><TD align=right nowrap>";
	print $q->small("&nbsp;&nbsp;<FONT color=#00d000>".doformat($perin,$fix,$intf)."$unit</FONT>")
		if($perin>=0 and $legendi);
	print $q->small(" <FONT color=#00d000>(".doformat($perinpc,1,0)."%)</FONT>")
		if($perinpc>=0 and $legendi and $interfaces{$curif}{percent});
	print "</TD><TD align=right nowrap>";
	print $q->small("&nbsp;&nbsp;<FONT color=#0000ff>".doformat($perout,$fix,$intf)."$unit</FONT>")
		if($perout>=0 and $legendo);
	print $q->small(" <FONT color=#0000ff>(".doformat($peroutpc,1,0)."%)</FONT>")
		if($peroutpc>=0 and $legendo and $interfaces{$curif}{percent});
	print "</TD></TR>\n";
	} # p
} # foreach interface
print "</TABLE>\n";

# Page foot
print $config{'routers.cgi-pagefoot'},"\n"
	if( defined $config{'routers.cgi-pagefoot'} );
if( $gstyle !~ /p/ ) {
	my( $ngti, $ngto ) = ("","");
	print $q->hr;
	print "\n",$q->a({href=>"javascript:location.reload(true)"},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}refresh.gif",
		alt=>"Refresh",border=>"0",width=>100,height=>20})),"&nbsp;\n";
#	print $q->a({href=>"javascript:parent.makebookmark('"
#		.$q->escape($router)."','__compact','$gtype','$gstyle','$gopts','$baropts','".$q->escape($extra)."')"},
#		$q->img({src=>"${config{'routers.cgi-iconurl'}}bookmark.gif",
#		alt=>"Bookmark",border=>"0",width=>100,height=>20})),"&nbsp;\n";
	print $q->a({href=>"$meurl?".optionstring({page=>"", xmtype=>"",
		if=>"__compact", xgstyle=>""}), target=>"_top" },
		$q->img({src=>"${config{'routers.cgi-iconurl'}}bookmark.gif",
		alt=>"Bookmark",border=>"0",width=>100,height=>20})),"&nbsp;\n";
	if( $gtype eq "6" ) { $ngto = "d"; }
	elsif( $gtype eq "d" ) { $ngto = "w"; $ngti = "6" if($usesixhour); }
	elsif( $gtype eq "w" ) { $ngti = "d"; $ngto = "m"; }
	elsif( $gtype eq "m" ) { $ngti = "w"; $ngto = "y"; }
	elsif( $gtype eq "y" ) { $ngti = "m"; }
	if( $ngti ) {
		print $q->a({href=>"$meurl?".optionstring({xgtype=>"$ngti"}), target=>"graph"},
			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomin.gif",
			alt=>"Zoom In",border=>"0",width=>100,height=>20})),"&nbsp;\n";
	}
	if( $ngto ) {
		print $q->a({href=>"$meurl?".optionstring({xgtype=>"$ngto"}), target=>"graph"},
			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomout.gif",
			alt=>"Zoom Out",border=>"0",width=>100,height=>20})),"&nbsp;\n";
	}
	print $q->br,"\n";
}
		
print "<!-- CAMPIO=[$c][$a][$m][$p][$io] gtype=$gtype baropts=$baropts -->\n";

do_footer();
}

#######################################################
# This is for the summary of interfaces view
sub do_summary()
{
# Start off.  We use onload() and Javascript to force reload the 
# lefthand (menu) panel.
my ($javascript, $e);
my ($rrd, $curif);
my ($m, $a, $l );
my ($start,$step, $names, $data);
my ($savetz) = "";
my ($legendi, $legendo);
my ($donehead) = 0;

$javascript = make_javascript({});

print $q->start_html({ -title => $toptitle, 
	-link=>$linkcolour, -vlink=>$linkcolour, -alink=>$linkcolour,
	-expires => "+5s",  -script => $javascript,-bgcolor => $defbgcolour ,
	-onload => "LoadMenu()" }),"\n";

print $config{'routers.cgi-pagetop'},"\n"
	if( defined $config{'routers.cgi-pagetop'} );
#
# Now for the RRD stuff
eval { require 'RRDs.pm'; };
if( $@ ) {
	print $q->h1("Error")."<CODE>Cannot find RRDs.pm in ".(join " ",@INC )."</CODE>\n";
		print $q->p("You can visit the configuration verification page "
			.$q->a({href=>("$meurl?page=verify&rtr=".$q->escape($router)),
			target=>"_new"},"here."));
	do_footer();
	return;
}

print "<TABLE border=0 width=100% align=center>\n";

$savetz = $ENV{TZ};
foreach $curif ( sort byifdesc keys(%interfaces) ) {
	next if(!$curif); # avoid rogue records
	next if(!$interfaces{$curif}{insummary});

	($legendi,$legendo)=("IN:","OUT:");
	$legendi = $interfaces{$curif}{legendi} if(defined $interfaces{$curif}{legendi});
	$legendo = $interfaces{$curif}{legendo} if(defined $interfaces{$curif}{legendo});


	# timezone information
	$ENV{TZ} = $interfaces{$curif}{timezone} if($interfaces{$curif}{timezone});

	print "<TR WIDTH=100% VALIGN=TOP>";

	print "<TD VALIGN=TOP>";

	if( defined $interfaces{$curif}{rrd} ) {
		$rrd = $interfaces{$curif}{rrd};
		# Last update stuff.
		$lastupdate = RRDs::last($rrd);
		$e = RRDs::error();
	} else {
		$rrd = "";
		$e = "No RRD file defined for interface '$curif'";
	}
	if( $e ) {
		print $q->p($q->b("Error reading RRD database $rrd"),$q->br,$e),"\n";
		print "</TD><TD>\n";
		print $q->h3($interfaces{$curif}{shdesc}),"\n";
		print $q->p($interfaces{$curif}{desc}),$q->br;
#		print $q->dump;
	} else {
		make_graph($gtype."s",$curif);
		print $q->br.$q->small("Target: ".$q->i($interfaces{$curif}{target}));
		print "</TD><TD>\n";
		print $q->a({href=>"$meurl?".optionstring({if=>"$curif"}), 
			target=>"graph"}, $q->b($interfaces{$curif}{desc}));
		print $q->br,"Last update: ".scalar(localtime($lastupdate)),
			$q->br,"\n";
		print "Timezone: ".$interfaces{$curif}{timezone}.$q->br."\n"
			if($interfaces{$curif}{timezone});
		if ( $interfaces{$curif}{max} 
			and !$interfaces{$curif}{nomax} ) {
			if ( defined $interfaces{$curif}{mblegend} ) { 
				print $interfaces{$curif}{mblegend}; 
			} elsif ( $interfaces{$curif}{isif} ) { print "Bandwidth"; }
			else { print "Maximum"; }
			if(defined $interfaces{$curif}{max1} 
				and defined $interfaces{$curif}{max2}) {
				print ": ".doformat( $interfaces{$curif}{max1},
					$interfaces{$curif}{fixunits},0)
					.$interfaces{$curif}{unit}."/"
					.doformat( $interfaces{$curif}{max2}, 
						$interfaces{$curif}{fixunits},0)
					.$interfaces{$curif}{unit}.$q->br,"\n";
			} else {
				print ": ".doformat( $interfaces{$curif}{max},
					$interfaces{$curif}{fixunits},0);
				print $interfaces{$curif}{unit}.$q->br,"\n";
			}
			if( defined $interfaces{$curif}{absmax} 
				and !$interfaces{$curif}{noabsmax} ) {
				if ( defined $interfaces{$curif}{amlegend} ) { 
					print $interfaces{$curif}{amlegend}; 
				} else { print "Hard Maximum"; }
				print ": ".doformat ($interfaces{$curif}{absmax},
								$interfaces{$curif}{fixunits},1)
					.$interfaces{$curif}{unit}.$q->br,"\n";
			}
		}
		print "Address: ".$interfaces{$curif}{address},$q->br,"\n"
			if ( defined $interfaces{$curif}{address} );
		print "Interface IP: ".$interfaces{$curif}{ipaddress},$q->br,"\n"
			if ( defined $interfaces{$curif}{ipaddress} );
		print "Interface # ".$interfaces{$curif}{ifno},$q->br,"\n" 
			if(defined $interfaces{$curif}{ifno});
		print "Interface name: ".$interfaces{$curif}{ifdesc},$q->br,"\n" 
			if(defined $interfaces{$curif}{ifdesc});
# insert here the last/current/max values.
#		print @$rrdoutput if($rrdoutput);
		$donehead = 0;
		if($rrdoutput) {
			foreach ( @$rrdoutput ) {
				if( /^<TR>/i and !$donehead ) { 
					$donehead = 1;
					print "<TABLE border=1 cellspacing=0><TR><TD></TD>";
				print $q->td($q->b($legendi)) if(!$interfaces{$curif}{noi});
				print $q->td($q->b($legendo)) if(!$interfaces{$curif}{noo});
					print "</TR>\n";
				}
				print;
			}
		}
# now the 95th percentile, if required
		if( defined $config{'routers.cgi-percentile'}
			and $config{'routers.cgi-percentile'} =~ /y/i ) {
			my( $pcdesc, $inarr, $outarr );
			if(!$donehead) {
				print "<TABLE border=1 cellspacing=0><TR><TD></TD>";
				print $q->td($q->b($legendi)) if(!$interfaces{$curif}{noi});
				print $q->td($q->b($legendo)) if(!$interfaces{$curif}{noo});
				print "</TR>\n";
				$donehead = 1;
			}
			( $pcdesc, $inarr, $outarr ) = calc_percentile($curif,$gtype,95);	
			if($pcdesc) {
				if($interfaces{$curif}{total}) {
					print "<TR>".$q->td("Total over $pcdesc:");
					print $q->td({ align=>"right"},doformat($$inarr[1],
$interfaces{$curif}{fixunits},$interfaces{$curif}{integer}) 
	.$interfaces{$curif}{totunit}) if(!$interfaces{$curif}{noi});
					print $q->td({ align=>"right"},doformat($$outarr[1],
$interfaces{$curif}{fixunits},$interfaces{$curif}{integer})
	.$interfaces{$curif}{totunit}) if(!$interfaces{$curif}{noo});
					print "</TR>\n";
				}
				if($interfaces{$curif}{percentile}) {
					print "<TR>".$q->td("95th Percentile for $pcdesc:");
					print $q->td({ align=>"right"},doformat($$inarr[0],
$interfaces{$curif}{fixunits},0)
	.$interfaces{$curif}{unit}) if(!$interfaces{$curif}{noi});
					print $q->td({ align=>"right"},doformat($$outarr[0],
$interfaces{$curif}{fixunits},0)
	.$interfaces{$curif}{unit}) if(!$interfaces{$curif}{noo});
				}
			} else {
				print "<TR>".$q->td("Error in 95th percentile calcs:")
					.$q->td($$inarr[2]).$q->td($$outarr[2])."\n";
			}
		}
		print "</TABLE>" if($donehead);
		print $q->br."\n";

	}
	print "</TD></TR>\n";
	$ENV{TZ}=$savetz if($savetz);
} # foreach
print "</TABLE>\n";

# Page foot
print $config{'routers.cgi-pagefoot'},"\n"
	if( defined $config{'routers.cgi-pagefoot'} );
if( $gstyle !~ /p/ ) {
	my( $u, $ngti, $ngto ) = ("","","");
	print $q->hr;
	print "\n",$q->a({href=>"javascript:location.reload(true)"},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}refresh.gif",
		alt=>"Refresh",border=>"0",width=>100,height=>20})),"&nbsp;\n";
#	print $q->a({href=>"javascript:parent.makebookmark('"
#		.$q->escape($router)."','__summary','$gtype','$gstyle','$gopts','$baropts','".$q->escape($extra)."')"},
	print $q->a({href=>"$meurl?".optionstring({page=>"", bars=>"", xmtype=>"",
		if=>"__summary", xgstyle=>""}), target=>"_top" },
		$q->img({src=>"${config{'routers.cgi-iconurl'}}bookmark.gif",
		alt=>"Bookmark",border=>"0",width=>100,height=>20})),"&nbsp;\n";
	if( $gtype eq "6" ) { $ngto = "d"; }
	elsif( $gtype eq "d" ) { $ngto = "w"; $ngti = '6' if($usesixhour); }
	elsif( $gtype eq "w" ) { $ngti = "d"; $ngto = "m"; }
	elsif( $gtype eq "m" ) { $ngti = "w"; $ngto = "y"; }
	elsif( $gtype eq "y" ) { $ngti = "m"; }
	if( $ngti ) {
		print $q->a({href=>"$meurl?".optionstring({xgtype=>"$ngti"}), target=>"graph"},
			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomin.gif",
			alt=>"Zoom In",border=>"0",width=>100,height=>20})),"&nbsp;\n";
	}
	if( $ngto ) {
		print $q->a({href=>"$meurl?".optionstring({xgtype=>"$ngto"}), target=>"graph"},
			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomout.gif",
			alt=>"Zoom Out",border=>"0",width=>100,height=>20})),"&nbsp;\n";
	}
		
	print $q->br,"\n";
}
do_footer();
}

sub do_empty()
{
	my ($javascript);

	$javascript = make_javascript({});

	print $q->start_html({ -title => $toptitle, 
		-link=>$linkcolour, -vlink=>$linkcolour, -alink=>$linkcolour,
		-expires => "+5s",  -script => $javascript,
		-onload => "LoadMenu()", -bgcolor => "#ffffff" }),"\n";

	if( $router eq "none" ) {
		print $q->h3("Please select a device");
	} else {	
		print $q->h3("Please select a target");
	}
	do_footer();
	print $q->end_html();
}

sub do_graph($)
{
# Start off.  We use onload() and Javascript to force reload the 
# lefthand (menu) panel.
my ($javascript, $e);
my ($rrd, $curif);
my ($iconsuffix) = "";
my ($bgcolor,$legendi,$legendo);
my ($inhtml) = $_[0]; # true if we want HTML page

$iconsuffix = "-bw" if( $gstyle =~ /b/ );

$javascript = make_javascript({});

$bgcolor = $defbgcolour;
$bgcolor = $interfaces{$interface}{background} if($interface and defined $interfaces{$interface} and defined $interfaces{$interface}{background});

if($inhtml) {
	print $q->start_html({ -title => $toptitle, 
		-link=>$linkcolour, -vlink=>$linkcolour, -alink=>$linkcolour,
		-expires => "+5s",  -script => $javascript,
		-onload => "LoadMenu()", -bgcolor => $bgcolor }),"\n";
}

# Catch for if there are NO cfg files.
if( ! $interface or ! $router
    or $interface eq "none" or $interface =~ /^__/  
	or $router eq "none" ) {
	if(!$inhtml) {
		print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
		return;
	}
	print $q->h3("No valid interface selected");
	if( $#cfgfiles eq -1 ) {
		print $q->p("You have no valid MRTG configuration files.  You should check your configuration in $conffile.".$q->br."["
			.$config{'routers.cgi-confpath'}.$pathsep
			.$config{'routers.cgi-cfgfiles'}."]"),"\n";
		print $q->p("NT users should check that this includes the correct drive letter.")."\n" if($config{'web-NT'});
		print $q->p("confpath = ".$config{'routers.cgi-confpath'});
		print $q->p("cfgfiles = ".$config{'routers.cgi-cfgfiles'});
	}
	do_footer();
	print $q->end_html();
	return;
}

# Now for the RRD stuff
eval { require 'RRDs.pm'; };
if( $@ ) {
	if(!$inhtml) {
		print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
		return;
	}
	print $q->h1("Error"),"<CODE>cannot find RRDs.pm in ".(join " ",@INC)."</CODE>\n";
		print $q->p("You can visit the configuration verification page "
			.$q->a({href=>("$meurl?page=verify&rtr=".$q->escape($router)),
			target=>"_new"},"here."));
	do_footer();
	return 0;
}
# Now, we have to do this differently depending on which gtype we have
# We do a switch for the different graphs.
# We have to call RRD to create them, and the IMG tag is created ready to
# stuff into the page!
$rrd = "";
if ( $interface =~ /^__/ ) { # compact and summary
	$curif = (keys(%interfaces))[0];
	$rrd = $interfaces{$curif}{rrd};
} else {
	$rrd = $interfaces{$interface}{rrd}
		if( defined $interfaces{$interface}{rrd} );
}

# Timezone
$ENV{TZ} = $interfaces{$interface}{timezone} 
	if($interfaces{$interface}{timezone});

# Last update stuff.
if( $rrd ) {
	$lastupdate = RRDs::last($rrd);
	$e = RRDs::error();
} else {
	$e = "No RRD file defined for interface '$interface'";
}
if( $e ) {
	if(!$inhtml) {
		print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
		return;
	}
	print $q->h3("$interfaces{$interface}{shdesc}"),"\n";
	print $q->p("$interfaces{$interface}{desc}"),"\n";
	print $q->p($q->b("Error reading RRD database $rrd"),$q->br,$e),"\n";
	print $q->p("You can visit the configuration verification page "
		.$q->a({href=>("$meurl?page=verify&rtr=".$q->escape($router)),
		target=>"_new"},"here."));
	print $q->p("File: [$router] ".$routers{$router}{desc}.$q->br
		."Target: $interface".$q->br
		."Target list: ".(join ", ",keys(%interfaces))
	);
#	print $q->dump;
} else {
	# any defined pagetop stuff
	if($inhtml) {
		print $config{'routers.cgi-pagetop'},"\n"
			if( defined $config{'routers.cgi-pagetop'} );
		if( defined $config{'routers.cgi-mrtgpagetop'} 
			and $config{'routers.cgi-mrtgpagetop'} =~ /y/ 
			and $interfaces{$interface}{pagetop}
			and !$interfaces{$interface}{usergraph} ) {
			print $interfaces{$interface}{pagetop},"\n";
		}
	}
	my $suffix = ( $gtype =~ /s/ ) ? "s" : "";
	$suffix .= "-" if( $gtype =~ /-/ );
	make_graph("6$suffix",$interface) if ( $gtype =~ /6/ );
	make_graph("d$suffix",$interface) if ( $gtype =~ /d/ );
	make_graph("w$suffix",$interface) if ( $gtype =~ /w/ );
	print $q->br,"\n" if ( $inhtml and length($gtype) > 2 );
	make_graph("m$suffix",$interface) if ( $gtype =~ /m/ );
	make_graph("y$suffix",$interface) if ( $gtype =~ /y/ );
	print $q->br,"\n" if ( $inhtml and length($gtype) > 2 );

	if(!$inhtml) { # we can leave now
		return;
	}

	print $q->br.$q->br."Last update: ".scalar(localtime($lastupdate)).$q->br."\n";
	print "Timezone: ".$interfaces{$interface}{timezone}.$q->br."\n"
		if($interfaces{$interface}{timezone});
	if( defined $config{'routers.cgi-percentile'}
		and $config{'routers.cgi-percentile'} =~ /y/i 
		and !$interfaces{$interface}{usergraph} ) {
		my( $i, $pcdesc, $inarr, $outarr, $sfx );
		$sfx = "";
		($legendi,$legendo)=("IN:","OUT:");
		$legendi=$interfaces{$interface}{legendi} 
			if(defined $interfaces{$interface}{legendi});
		$legendo=$interfaces{$interface}{legendo} 
			if(defined $interfaces{$interface}{legendo});
		$sfx = "-" if( $gtype =~ /-/ );
		foreach $i  ( qw/d w m y/ ) {
		next if((index $gtype, $i) < 0);
		( $pcdesc, $inarr, $outarr ) = calc_percentile($interface,$i.$sfx,95);
		if($pcdesc) {
			print "<TABLE border=0 >\n";
#			print "<TR>".$q->td("").$q->td($q->b($legendi))
#				.$q->td($q->b($legendo));
		if($interfaces{$interface}{total}) {
			print "<TR>".$q->td($q->b("Total over $pcdesc:"));
			print $q->td($legendi).$q->td({align=>"right"},doformat($$inarr[1],
$interfaces{$interface}{fixunits},$interfaces{$interface}{integer})
	.$interfaces{$interface}{totunit}) if(!$interfaces{$interface}{noi});
			print $q->td($legendo).$q->td({align=>"right"},doformat($$outarr[1],
$interfaces{$interface}{fixunits},$interfaces{$interface}{integer})
	.$interfaces{$interface}{totunit}) if(!$interfaces{$interface}{noo});
			print "</TR>\n";
		}
		if($interfaces{$interface}{percentile}) {
		print "<TR>".$q->td($q->b("95th Percentile for $pcdesc:"));
		print $q->td($legendi).$q->td({align=>"right"},doformat($$inarr[0],
$interfaces{$interface}{fixunits},0)
		.$interfaces{$interface}{unit}) if(!$interfaces{$interface}{noi});
		print $q->td($legendo).$q->td({align=>"right"},doformat($$outarr[0],
$interfaces{$interface}{fixunits},0)
		.$interfaces{$interface}{unit}) if(!$interfaces{$interface}{noo});
		print "</TR>\n";
		}
		print "</TABLE>\n";
		} else {
		print "Error in 95th percentile:".$q->br."[".$$inarr[2]."]".$q->br
			."[".$$outarr[2]."]".$q->br if($$inarr[2] or $$outarr[2]);
		} # pcdesc
		} # foreach
	}

	print $q->br;
	if( defined $config{'routers.cgi-mrtgpagefoot'} 
		and $config{'routers.cgi-mrtgpagefoot'} =~ /y/ 
		and $interfaces{$interface}{pagefoot}
		and !$interfaces{$interface}{usergraph}  ) {
		print $interfaces{$interface}{pagefoot},"\n";
	}
	print $config{'routers.cgi-pagefoot'},"\n"
		if( defined $config{'routers.cgi-pagefoot'} );

	# any extensions defined for this target?
	if( defined $interfaces{$interface}{extensions} ) {
		my($ext, $u, $targ);
		print $q->hr,"\n";
		foreach $ext ( @{$interfaces{$interface}{extensions}} ) {
			$targ = "graph";
			$targ = $ext->{target} if( defined $ext->{target} );
			$u=$ext->{url};
			$u .= "?x=2" if( $u !~ /\?/ );
			$u .= "&fi=".$q->escape($router)."&ta="
				.$q->escape($interface)."&url=".$q->escape($meurl);
			$u .= "&t=".$q->escape($targ); 
			$u .= "&h=".$q->escape($interfaces{$interface}{hostname}) 
				if(defined $interfaces{$interface}{hostname});
			$u .= "&c=".$q->escape($interfaces{$interface}{community})
				if(defined $interfaces{$interface}{community});
			$u .= "&ifno=".$interfaces{$interface}{ifno}
				if(defined $interfaces{$interface}{ifno});
			$u .= "&b=".$q->escape("javascript:history.back();history.back()")
				."&conf=".$q->escape($conffile);
			print $q->img( { height=>15, width=>15,
				src=>($config{'routers.cgi-iconurl'}.$ext->{icon}) })
				."&nbsp;";
			print $q->a( { href=>$u, target=>$targ },
					$ext->{desc}).$q->br."\n";
		}
	}

	# routers.cgi page footer
	if( $gstyle !~ /p/ ) {
		my( $u, $ngti, $ngto ) = ("","","");
	print $q->hr;
	print "\n",$q->a({href=>"javascript:location.reload(true)"},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}refresh$iconsuffix.gif",alt=>"Refresh",border=>"0",width=>100,height=>20})),"\n";
#	print $q->a({href=>"javascript:parent.makebookmark('"
#		.$q->escape($router)."','".$q->escape($interface)
#		."','$gtype','$gstyle','$gopts','$baropts','".$q->escape($extra)."')"},
	print $q->a({href=>"$meurl?".optionstring({page=>"", bars=>"",
		xmtype=>"", xgstyle=>""}), target=>"_top" },
		$q->img({src=>"${config{'routers.cgi-iconurl'}}bookmark$iconsuffix.gif",alt=>"Bookmark",border=>"0",width=>100,height=>20})), "\n";
	if( $gtype eq "6" ) { $ngto = "d"; }
	elsif( $gtype eq "d" ) { $ngto = "w"; $ngti='6' if($usesixhour); }
	elsif( $gtype eq "w" ) { $ngti = "d"; $ngto = "m"; }
	elsif( $gtype eq "m" ) { $ngti = "w"; $ngto = "y"; }
	elsif( $gtype eq "y" ) { $ngti = "m"; }
	if( $ngti ) {
		print $q->a({href=>"$meurl?".optionstring({xgtype=>"$ngti"}), target=>"graph"},
			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomin.gif",
			alt=>"Zoom In",border=>"0",width=>100,height=>20})),"\n";
	}
	if( $ngto ) {
		print $q->a({href=>"$meurl?".optionstring({xgtype=>"$ngto"}), target=>"graph"},
			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomout.gif",
			alt=>"Zoom Out",border=>"0",width=>100,height=>20})),"\n";
	}
	if(!$interfaces{$interface}{usergraph}) {
	print $q->a({href=>"$meurl?".optionstring({page=>"csv"}), target=>"graph"},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}csv.gif",
		alt=>"CSV Download",border=>"0",width=>100,height=>20})),"\n";
	}
	if( $config{'routers.cgi-archive'} =~ /y/i ) {
	print $q->a({href=>"$meurl?".optionstring({page=>"archive"}), 
		target=>"graph"},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}archive.gif",
		alt=>"Add to archive",border=>"0",width=>100,height=>20})),"\n";
	}

	print $q->br,"\n";
		
	}
}

# Finish off the page (this does the ending body and html tags)
do_footer();
print $q->end_html();
}

# Information on this router
sub do_info()
{
# Start off.  We use onload() and Javascript to force reload the 
# lefthand (menu) panel.
my ($javascript, $ifkey,$x, $icon);
my ($acount,$archivepat,@archive,$archives);

$javascript = make_javascript({});

print $q->start_html({ -title => $toptitle, 
	-link=>$linkcolour, -vlink=>$linkcolour, -alink=>$linkcolour,
	-expires => "+5s",  -script => $javascript, -bgcolor => $defbgcolour,
	-onload => "LoadMenu()" }),"\n";

# Here we build up a page of info, with lotsalinks.
print $q->h2("Device Information"),"\n";

print $q->a({href=>"$meurl?".optionstring({page=>"graph",if=>"__summary"}),
	target=>"graph"},
	$q->b("$router: ".$routers{$router}{desc})),$q->br,"\n";
print $q->br.$q->b("MRTG config file: ").$routers{$router}{file}.$q->br."\n";
print "<UL>";
$ifkey = ""; # we want this later
foreach (sort byifdesc keys (%interfaces)) {
	next if(!$_); # avoid rogue records
	next if($interfaces{$_}{mode} =~ /^\177_AUTO/); # system created
	# count archived copies
	$archivepat = $router; $archivepat =~ s/[\?#\\\/]//g;
	$archivepat = $config{'routers.cgi-graphpath'}.$pathsep
		.$archivepat.$pathsep.$_.$pathsep."*.*";
	@archive = glob($archivepat);
	$acount = $#archive + 1;
	# now the data line
	$icon = $q->img({src=>($config{'routers.cgi-iconurl'}.$interfaces{$_}{icon})
		,width=>15,height=>15})." ";
	$ifkey = $_ if(!$ifkey and $interfaces{$_}{community} 
		and $interfaces{$_}{hostname});
	if( $acount == 1 ) {
		$archives = $q->br."This target has one archived graph.";
	} elsif( $acount > 1 ) {
		$archives = $q->br."This target has $acount archived graphs.";
	} else {
		$archives = "";
	}
	if( $interfaces{$_}{usergraph} ) {
		print $q->li( $icon.$q->a( 
			{href=>"$meurl?".optionstring({if=>"$_"}),
			target=>"graph"},
			$interfaces{$_}{desc})." [$_] \n$archives");
	} elsif( defined $interfaces{$_}{ifno} ) {
		# interface number
		print $q->li( $icon.$q->a( 
			{href=>"$meurl?".optionstring({if=>"$_"}),
			target=>"graph"},
			"#".$interfaces{$_}{ifno}.": ".$interfaces{$_}{desc}
		)." [".$interfaces{$_}{target}."] Max "
			.doformat($interfaces{$_}{max},$interfaces{$_}{fixunits},1)
			.$interfaces{$_}{unit}
			." {".$interfaces{$_}{mode}."}$archives"),"\n";
	} elsif( defined $interfaces{$interface}{ifdesc} ) {
		# interface description
		print $q->li( $icon.$q->a( 
			{href=>"$meurl?".optionstring({if=>"$_"}),
			target=>"graph"},
			$interfaces{$_}{shdesc}.": ".$interfaces{$_}{desc}
		)." [".$interfaces{$_}{target}."] Max "
			.doformat($interfaces{$_}{max},$interfaces{$_}{fixunits},1)
			.$interfaces{$_}{unit}
			." {".$interfaces{$_}{mode}."}$archives"),"\n";
	} elsif( defined $interfaces{$interface}{ipaddress} ) {
		# IP address
		print $q->li( $icon.$q->a( 
			{href=>"$meurl?".optionstring({if=>"$_"}),
			target=>"graph"},
			$interfaces{$_}{ipaddress}.": ".$interfaces{$_}{desc}
		)." [".$interfaces{$_}{target}."] Max "
			.doformat($interfaces{$_}{max},$interfaces{$_}{fixunits},1)
				.$interfaces{$_}{unit}
			." {".$interfaces{$_}{mode}."}$archives"),"\n";
	} else {
		# userdefined and unknown
		print $q->li( $icon.$q->a( 
			{href=>"$meurl?".optionstring({if=>"$_"}),
			target=>"graph"},
			$interfaces{$_}{desc})." [".$interfaces{$_}{target}."] Max "
				.doformat($interfaces{$_}{max},$interfaces{$_}{fixunits},1)
				.$interfaces{$_}{unit}
				." {".$interfaces{$_}{mode}."}$archives"),"\n";
	}
}
print "</UL>\n";

# Can we call out to the routingtable.cgi program?
if( defined $config{'routers.cgi-routingtableurl'} 
	and ( !defined $routers{$router}{routingtable}
		or $routers{$router}{routingtable} eq "y" )) {
	if($ifkey) {
	print $q->a({target=>"_self",
		href=>($config{'routers.cgi-routingtableurl'}
		."?r=".$q->escape($interfaces{$ifkey}{hostname})
		."&h=".$q->escape($interfaces{$ifkey}{hostname})
		."&c=".$q->escape($interfaces{$ifkey}{community})
		."&url=".$q->escape($meurl)
		."&t=graph&b=javascript:".$q->escape("history.back();history.back()")
		."&conf=".$q->escape($conffile))},
		"Show routing table for this router")." (may take some time)",
			$q->br,$q->br,"\n";
	} else {
		print "Routing table information not available.",$q->br,
			$q->br,"\n";
	}
}

# Finish off the page (this does the ending body and html tags)
do_footer();
print $q->end_html();
}

############################################################################
# Export of data to CSV format.
sub do_export()
{
	my( $start, $step, $names, $data, $line );
	my( $rrd, @opts, $e, $d, $t, $i, $r, @dat );
	my( $thisif, $startpoint, $endpoint, $resolution );
	
	eval { require 'RRDs.pm'; };
	if( $@ ) {
 		print "Cannot find RRDs.pm!";
		return;
	}
	if( !$interface ) {
		print "No interface selected!";
		return;
	}
	$thisif = $interface;

	# Header line
	print '"Hostname","Target","Sample Date YMD","Sample Time HHMM","Count in seconds"';
	print ',"'.$interfaces{$interface}{legend1}.' in '
		.$interfaces{$interface}{unit}.'"'
		if($interfaces{$interface}{legend1} and !$interfaces{$interface}{noi});
	print ',"'.$interfaces{$interface}{legend2}.' in '
		.$interfaces{$interface}{unit}.'"'
		if($interfaces{$interface}{legend2} and !$interfaces{$interface}{noo});
	print "\r\n";
	$i = $interfaces{$interface}{shdesc};
	$r = $routers{$router}{desc};
	$r = $interfaces{$interface}{hostname} if(!$r);
	$r = $router if(!$r);
	$r = "Unknown" if(!$r);

	$rrd = $interfaces{$thisif}{rrd};
	foreach ( $gtype ) {
		/y/ and do { $resolution = 3600; $startpoint = "-1y"; 
			last; };
		/m/ and do { $resolution = 1800; $startpoint = "-1month"; 
			last; };
		/w/ and do { $resolution = 300; $startpoint = "-7d"; 
			last; };
		/6/ and do { $resolution = 60*$interfaces{$thisif}{interval}; 
			$startpoint = "-6h"; last; };
		$resolution = 60*$interfaces{$thisif}{interval}; # interval
		$startpoint = "-24h"; # 1 day
	}
	$resolution = 300 if(!$resolution);

	if( $gtype =~ /-/ ) {
		@opts = ( $rrd, "AVERAGE", "-e", "now".$startpoint, 
			"-s", "end".$startpoint );
	} elsif( $uselastupdate ) {
		$lastupdate = RRDs::last($rrd);
		$e = RRDs::error();
		if(!$lastupdate) {
			print "Error reading rrd:\n$e\n";
			return;
		}
		@opts = ( $rrd, "AVERAGE", "-e", $lastupdate, "-s", "end".$startpoint );
	} else {
		@opts = ( $rrd, "AVERAGE", "-s", $startpoint );
	}

	# Fetch data
	( $start, $step, $names, $data ) = RRDs::fetch( @opts );
	if( !$start or !$data ) {
		$e = RRDs::error();
		print "Error retrieving data - do you have enough stored?\n";
		print "Check that you have enough real data gathered to be able to export.\n";
		print "$e\n";
		return;
	}

	# Print data
	foreach $line ( @$data ) {
		@dat = localtime $start;
		#$d = sprintf "%02d/%02d/%04d",$dat[3],($dat[4]+1),($dat[5]+1900);
		$d = sprintf "%04d/%02d/%02d",($dat[5]+1900),($dat[4]+1),$dat[3];
		$t = sprintf "%02d:%02d",$dat[2],$dat[1]; # hh:mm
		print "\"$r\",\"$i\",$d,$t,$start";
		printf ",%12.1f", ($$line[0]*$interfaces{$thisif}{mult}) 
			if(!$interfaces{$interface}{noi});
		printf ",%12.1f", ($$line[1]*$interfaces{$thisif}{mult})
			if(!$interfaces{$interface}{noo});
		printf "\r\n";
		$start += $step;
	}

}

############################################################################
# Help page

sub do_help()
{
	my($vurl,$iurl);
	my($javascript);

	$javascript = make_javascript({if=>"__none",rtr=>"none"});

	print $q->start_html({-script => $javascript, -onload => "LoadMenu()",
	-link=>$linkcolour, -vlink=>$linkcolour, -alink=>$linkcolour,
		-bgcolor => $defbgcolour });

	$vurl = "$meurl?page=verify&rtr=".$q->escape($router);
	$iurl = $config{'routers.cgi-iconurl'};

	print $q->h1("Information and Help");

	print <<EOT
<h2>Updates and support</h2>
Updates to the routers.cgi script may be obtained from
<a href=$APPURL>$APPURL</a>. During development phases there may be daily 
updates, so check every so often.  Support is available via the 
<a href=http://groups.yahoo.com/group/steveshipway/>mailing list</a> and 
directly - check this link for more details.
<hr>
<h2>Online help</h2>
<UL>
<li>Diagnose configuration problems 
<a target=_new href=$vurl>here</a> (opens new window)</li>
<li>Show available link icons 
<a target=_new href=$iurl>here</a> (opens new window)</li>
</UL>
<hr>
<h2>Credits</h2>
Thanks to the following people for supporting the development of 
this software by 
<a target=_new href=http://www.cheshire.demon.co.uk/pub/wishlist.html >
sending me a gift</a> on either my
<a target=_new href=http://www.amazon.co.uk/exec/obidos/wishlist/3S0PX0NTU8KDC >
Amazon WishList</a>
or via 
<a href=http://www.paypal.com/cgi-bin/webscr?cmd=_xclick&item_name=routers.cgi&no_shipping=1&business=steve\@cheshire.demon.co.uk>PayPal</a>.
All listed in no particular order, in case you were wondering.
<UL>
<LI>Pall Wiberg Joensen, Faroese Telecom, Faroe Islands</li>
<li>Ben Higgins, Dovetail Internet, USA</li>
<li>Mike Bernhardt, Arsin, USA</li>
<li>EDS Europe</li>
<li>Ruedi Kehl, Manor AG, Switzerland (twice!)</li>
<li>Allied Domecq, UK</li>
<li>Rob</li>
<li>Peter Cohen, Telia, USA</li>
<li>Jay Christopherson</li>
<li>David Hares, Network One</li>
<li>Reuben Farrelly, Netfilter, Australia</li>
<li>Network Operations, Roche Diagnostics GmbH, Germany</li>
<li>Keith Johnson, UK</li>
<li>J Herrera, Brown Publishing</LI>
<li>Kristin Gorman, New York, USA</li>
<li>Inigo T Storm, ASV AG, Hamburg, Germany</li>
<li>M Williams, London, UK</li>
<li>Various generous but anonymous people</li>
</ul>
V2.0 Beta testers:
<UL>
<li>Garry Cook, MacTec Inc.</li>
<li>Ed Stalnaker, Rollins Corp, USA</li>
<li>Francesco Duranti, Kuwait Petroleum Italia</li>
<li>Neil Pike, Protech Computing</li>
<li>Brian Wilson, North Carolina State University</li>
<li>Martijn Koopsen, Energis NL</li>
</UL>
Contributors:
<UL>
<li>Ed Stalnaker (modified cfgmaker script)</li>
<li>Brian Wilson, Garry Cook, Aid Arslanagic, Andy Jezierski, Leo Artnts, James Keane, Todd Wiese (alternative icon sets)</li>
<li>Many other people for suggestions and bug reports.</li>
</UL>
Additional thanks to all the other people who have assisted by sending in
bug reports and suggestions for improvement.  Also, major thanks to 
Tobi Oetiker, the author of <a href=http://www.mrtg.org/ target=_new>MRTG</a>
and <a href=http://www.rrdtool.org/ target=_new>RRDTool</a>, without whom 
this interface would never have been created.
<hr>
<h2>Legal Jargon</h2>
This software is available under the GNU GPL.  More information is available
in the text files accompanying this software, or on the web site.  Please note
that this software is provided without any warranty, or guarantee, and you
use it at your own risk.  In no event shall myself, my employers, or the 
owner of any
web site distributing this software, be held liable for any loss or damage 
caused as a result of the use or misuse of this software or the instructions
that accompany it.
<p>
EOT
;
	do_footer();
	print $q->end_html();
}

# set cookies etc. for defaults.
# the way we do this is by refreshing ourself with extra parameters.
# The existence of the extra parameters causes the cookie to be set.
sub do_config()
{
	my ( $javascript, %routerdesc, $k );

	$javascript = make_javascript({if=>"__none",rtr=>"none"});

	print $q->start_html({-script => $javascript, -onload => "LoadMenu()",
	-link=>$linkcolour, -vlink=>$linkcolour, -alink=>$linkcolour,
		-bgcolor => $defbgcolour });

	print $q->h2("Personal Preferences"),"\n";

	if( $q->param('xset') ) {
		print $q->p($q->b("Options have been saved.")),"\n";
	}

	foreach ( keys %routers ) { $routerdesc{$_} = $routers{$_}{desc}; }
	$routerdesc{''} = "No preference";
	
	if($config{'routers.cgi-6hour'} =~ /y/i ) {
		@gorder = ( '6', @gorder ) if($gorder[0] ne "6");
	}

	print $q->p("Options set here will persist over future invocations of this script.  Note that this uses cookies, so you must have them enabled.");

	print $q->hr;
	print "<FORM METHOD=GET ACTION=$meurl>\n";
	
# now a couple of hidden fields to preserve mtype and page
	print $q->hidden({ name=>"page", value=>"config" }),"\n",
		$q->hidden({ name=>"xmtype", value=>$mtype }) ,"\n",
		$q->hidden({ name=>"xset", value=>"yes" }) ,"\n";

# Now the main fields, defrouter and defgtype.  Dropdown lists.  In a table.

	$defgstyle = $q->cookie('gstyle');
	$defgstyle = 'n' if(!$defgstyle);

	print $q->table( { -border=>0 },
		$q->Tr( { -border=>"0", align=>"left" } ,
			$q->td("Default device:" )."\n", $q->td( 
				$q->popup_menu( {name=>"defrouter", 
					values=>["",sort bydesc keys(%routers)],
					labels=>{%routerdesc}, default=>$q->cookie('router')})
			)."\n" 
		),
		$q->Tr( { -border=>"0", align=>"left" } ,
			$q->td("Default target/interface:" )."\n", $q->td( 
				$q->popup_menu({ name=>"defif", values=>["",
					"__first",
					"__interface","__cpu","__memory","__summary",
					"__compact", "__incoming","__outgoing","__info"],
					labels=>{__first=>"First target", __summary=>"Summary page",
						__info=>"Info Page", _incoming=>"Incoming data",
						_outgoing=>"Outgoing data", __cpu=>"CPU performance",
						__memory=>"Memory Usage", __userdef=>"First user graph",
						__interface=>"First Interface target",
						__incoming=>"Incoming Graph", 
						__outgoing=>"Outgoing graph",
						__compact=>"Compact Summary",
						""=>"No preference" }, 
					default=>$q->cookie('if') })
			)."\n" 
		),
		$q->Tr( { -border=>"0", align=>"left" } ,
			$q->td("Default graph type:" )."\n", $q->td( 
				$q->popup_menu({ name=>"defgtype", values=>[@gorder],
					labels=>{%gtypes}, default=>$q->cookie('gtype') })
			)."\n" 
		),
		$q->Tr( { -border=>"0", align=>"left" } ,
			$q->td("Default graph style:" )."\n", $q->td( 
				$q->popup_menu({ name=>"defgstyle", values=>[@sorder],
					labels=>{%gstyles}, default=>"$defgstyle" })
			)."\n" 
		),
		$q->Tr( { align=>"left" },
			$q->td(""),$q->td(
				$q->submit({ name=>"Submit", value=>"Set Defaults" })
			)."\n"
		)
	),"\n";

	print "</FORM>";

	print $q->br({clear=>"BOTH"}),"\n";

	print $q->center($q->b($q->a({target=>"_top",href=>$meurl},
		"Go to the current default page"))).$q->br,"\n";

	do_footer();
	print $q->end_html();
}

###########################
# Show an archive graph.

sub do_archive($)
{
	my( $javascript, $thisgraph, $thisgraphurl );
	my( $inhtml ) = $_[0];

	$javascript = make_javascript({archive=>$archive});

	print $q->start_html({ -title => $toptitle, 
	-link=>$linkcolour, -vlink=>$linkcolour, -alink=>$linkcolour,
		-script => $javascript, -onload => "LoadMenu()" }),"\n";

	$thisgraphurl = $router; $thisgraphurl =~ s/[\?#\\\/]//g;
	$thisgraph = $thisgraphurl;
	$thisgraph = $config{'routers.cgi-graphpath'}.$pathsep.$thisgraph
		.$pathsep.$interface.$pathsep.$archive;
	$thisgraphurl = $config{'routers.cgi-graphurl'}.'/'.$thisgraphurl
		.'/'.$interface.'/'.$archive;

	print $q->h2("Archive graph");
	# any defined pagetop stuff
	print $config{'routers.cgi-pagetop'},"\n"
		if( defined $config{'routers.cgi-pagetop'} );
	if( defined $config{'routers.cgi-mrtgpagetop'} 
		and $config{'routers.cgi-mrtgpagetop'} =~ /y/ 
		and $interfaces{$interface}{pagetop}
		and !$interfaces{$interface}{usergraph} ) {
		print $interfaces{$interface}{pagetop},"\n";
	}
	if( -f $thisgraph ) {
		print $q->img({ src=>$thisgraphurl, alt=>$archive }).$q->br."\n";
	} else {
		print $q->p($q->b("This graph has been deleted."))."\n";
	}

	if( $archive =~ /(\d+)-(\d+)-(\d+)-(\d+)-(\d+)-([dwmys6]+)\./ ) {
		# try to get local formatting
		my( $dformat ) = "%c";
		$dformat = $config{'web-shortdateformat'}
			if(defined $config{'web-shortdateformat'});
		eval { require POSIX; };
		if($@) {
			print $q->br, $q->p("Archive time: $4:$5 $3/$2/$1 ("
				.$gtypes{$6}.")");
		} else {
			print $q->br, $q->p("Archive time: "
				.POSIX::strftime($dformat,0,$5,$4,$3,($2-1),($1+100))
				." (".$gtypes{$6}.")");
		}
	}
	print $q->br;
	if( defined $config{'routers.cgi-mrtgpagefoot'} 
		and $config{'routers.cgi-mrtgpagefoot'} =~ /y/ 
		and $interfaces{$interface}{pagefoot}
		and !$interfaces{$interface}{usergraph}  ) {
		print $interfaces{$interface}{pagefoot},"\n";
	}
	print $config{'routers.cgi-pagefoot'},"\n"
		if( defined $config{'routers.cgi-pagefoot'} );

	print $q->hr."\n";
#	print $q->a({href=>"javascript:parent.makearchmark('"
#		.$q->escape($router)."','".$q->escape($interface)
#		."','".$q->escape($extra)."','$archive')"},
	print $q->a({href=>"$meurl?".optionstring({page=>"", bars=>"", xmtype=>"",
		archive=>"$archive", xgtype=>"", xgstyle=>""}), target=>"_top"},
		$q->img({src=>"${config{'routers.cgi-iconurl'}}bookmark.gif",
		alt=>"Bookmark",border=>"0",width=>100,height=>20})),"\n";

	# only for Yes, not for Read
	if( $config{'routers.cgi-archive'} =~ /y/i ) {
	print $q->a( { href=>$meurl.'?'.optionstring({archive=>$archive,
		page=>'graph',delete=>1}) },
		$q->img({ border=>0, alt=>"Delete this graph", width=>100, height=>20,
			src=>$config{'routers.cgi-iconurl'}."delete.gif" })).$q->br;
	}
	do_footer();
	print $q->end_html();
}

###########################
# Verification of everything.
# This is more a debug utility, really.  We display all the routers and
# interfaces, also the available icons and check the sanity of the
# routers.conf, and the graph directory.

sub yesno($)
{
	if(!$_[0]) { print $q->td({bgcolor=>"#ff0000",align=>"center"},"No"); }
	else { print $q->td({bgcolor=>"#00ff00",align=>"center"},"Yes"); }
}
sub do_verify()
{
	my($server,$iconpath, $ipath, $confpath, $iconurl,$graphpath, $graphurl);
	my($curif, $key, $rtr);
	my($testfile, $okfile);
	my($username) = "";
	my($e,$rrdok, $rrdinfo);

	$server = "localhost";
	$server = $1 if($meurl =~ /http:\/\/([\w\.\-]+)\//);
	$confpath = $config{'routers.cgi-confpath'};
	$graphpath = $config{'routers.cgi-graphpath'};
	$graphurl = $config{'routers.cgi-graphurl'};
	$iconurl = $config{'routers.cgi-iconurl'};
	$ipath = $iconurl; $ipath =~ s#/#\\#g if($NT);
	$iconpath = $graphpath.$pathsep."..".$ipath;
	$iconpath = $graphpath.$pathsep."..".$pathsep."..".$ipath
		if(!-d $iconpath);
	$iconpath = "" if(!-d $iconpath);
	$username = $q->user_name if($q->user_name);

	print $q->start_html({-title=>"Configuration Verification"});

	print $q->h1("Configuration Verification");
	print $q->ul(
		$q->li($q->a({href=>"#conf"},"Check routers.conf")),
		$q->li($q->a({href=>"#files"},"Check MRTG files")),
		$q->li($q->a({href=>"#targets"},"Check MRTG targets")),
		$q->li($q->a({href=>"#icons"},"Check available icons")),
		$q->li($q->a({href=>"#settings"},"Configuration settings"))
	).$q->hr."\n";

	print $q->a({name=>"conf"},$q->h2("routers.conf check"))."\n";
	print $q->p("This will check a number of the more critical definitions in the routers.conf file, and will give you any warnings for items that are a worry.")."\n";
	print "<TABLE align=center border=1>\n";
	print "<TR><TD>Script name</TD><TD>$myname  (Version $VERSION)</TD></TR>\n";
	print "<TR><TD>Configuration file<br>$conffile</TD>\n";
	if( -r $conffile ) { print "<TD>Exists and is readble</TD></TR>\n"; }
	else { print "<TD background=#ff0000>Unable to read file</TD></TR>\n"; }
	print "<TR><TD>Authenticated username</TD><TD>$username</TD></TR>\n"
		if($username);
	print "<TR><TD>Graphs path<br>$graphpath</TD>\n";
	if( -d $graphpath ) {
		$testfile = $graphpath.$pathsep
			."verylongfilename-------------testfile.png";
		if( open TEST, ">$testfile"  ) {
			print "<TD>Directory exists and is writeable</TD></TR>\n";
			close TEST;
			unlink $testfile;
		} else {
			print "<TD background=#ff0000>Unable to create files in directory!</TD></TR>\n"; 
		}
	} else {
		print "<TD background=#ff0000>Directory does not exist!</TD></TR>\n"; 
	}
	print "<TR><TD>Graph URL<br>$graphurl</TD>\n";
	$testfile = $graphpath.$pathsep."redsquare.png";
	unlink $testfile if( -f $testfile );
	if( open GRAPH, ">$testfile" ) {
		binmode GRAPH;
		# this generates a PNG of a red square.
		print GRAPH
"\211PNG\r\n\032\n\0\0\0\rIHDR\0\0\0\017\0\0\0\017\001\003\0\0\0\001\030"
."\a\t\0\0\0\003PLTE\377\0\0\031\342\t7\0\0\0\fIDATx\234c` \001\0\0\0-\0"
."\001\305\327\300\206\0\0\0\0IEND\256B`\202";
		close GRAPH;
		print "<TD>This should show a red square --&gt;"
			.$q->img({src=>$graphurl."/redsquare.png",alt=>"Red Square",
				width=>15,height=>15})
			."&lt;--<br>\n";
		print "If it doesn't, then your graphurl does not match your graphpath.</TD></TR>\n";
	} else {
		print "<TD background=#ff0000>Unable to create test file!<br>Check your graphpath setting above.</TD></TR>\n"; 
	}

	print "<TR><TD>Icon URL<br>$iconurl</TD><TD>\n";
	print "This should show a target --&gt;"
		.$q->img({src=>$iconurl."target-sm.gif",width=>15, height=>15})
		."&lt;--<br>\n"
  		."If it doesn't, then there is a problem.</td></tr>\n";
	print "<TR><TD>MRTG files<br>Path: ".$confpath
		.$q->br."Files: ".$config{'routers.cgi-cfgfiles'}."</TD>\n";
	if( @cfgfiles ) {
		print "<TD>".($#cfgfiles + 1)." files detected OK.";
	} else {
		if(!-d $confpath) {
			print "<TD gcolor=#ff0000>Directory does not exist or is not readable!";
		} else {
			print "<TD gcolor=#ff0000>No files found that match this pattern!";
		}
	}
	print "</TD></TR>\n";
	print "<TR><TD>Perl libraries<br>RRDs, GD</TD><TD>\n";	
	eval { require "RRDs.pm"; };
	if($@) { 
		print $q->b("RRDs library NOT FOUND.")." This may however not be a problem if the library path is amended by the <b>LibAdd</b> birective in the MRTG files.".$q->br;
		print $@.$q->br;
		$rrdok = 0;
	} else {
		my($v);
		$RRDs::VERSION =~ /(\d+)\.(\d\d\d)(\d\d)/;
		$v = "$1.".($2 + 0).".".($3 + 0);
		print "RRDs library found OK (Version $v)<br>";
		print "You should upgrade to at least v1.0.36 to avoid problems.<BR>"
			if($RRDs::VERSION < 1.00036);
		$rrdok = 1;
	}
	if( $config{'routers.cgi-compact'} =~ /n/i ) {
		print "GD library not required as compact is disabled in routers.conf";
	} else {
		eval { require GD; };
		if($@) {
			print $q->b("GD library NOT FOUND.")." This would not be a problem if you had compact=no in the routers.conf.".$q->br;
			print $@;
		} else {
			print "GD library found OK";
		}
	}
	print "</TD></TR><TR><TD>Routingtable extensions</TD><TD>";
	if(defined $config{'routers.cgi-routingtableurl'}) {
		eval { require Net::SNMP; };
		if($@) {
			print $q->b("Net::SNMP library NOT FOUND.")." This means that the routingtable extensions will NOT WORK.  You should therefore either install this package, or disable the extensions in the routers.conf.".$q->br;
			print $@;
		} else {
			print "Net::SNMP library found OK and extensions are enabled.";
		}
	} else {
		print "Routing table extensions are not enabled.";
	}
	print "</TD></TR></TABLE>\n";

	print $q->hr.$q->a({name=>"files"},$q->h2("MRTG files check"))."\n";
	print $q->p("There files are taken from the <b>cfgpath</b> and <b>cfgfiles</b> directives in the <b>[routers.cgi]</b> section of the routers.conf file.  If no files are listed below, then you should check that these definitions are correct.");
	print "confpath = ".$q->code($confpath).$q->br."\n";
	print "cfgfiles = ".$q->code($config{'routers.cgi-cfgfiles'}).$q->br."\n";

	print $q->br."<TABLE align=center border=1>\n";
	print "<TR><TD>MRTG file name</td><td>Description</td><td>Visible</td><td>Valid</td><td>Notes</td></tr>\n";
	foreach $rtr ( keys %routers ) {
		print "<TR><TD>";
		print $q->img({src=>$iconurl.$routers{$rtr}{icon},width=>15, height=>15})." " if(defined $routers{$rtr}{icon});
		print $q->a({href=>("$meurl?page=verify&rtr=".$q->escape($rtr))},$rtr);

		if( $rtr !~ /^#SERVER/ ) {
		$okfile = $confpath.$pathsep.$rtr;
		$okfile =~ s/\.conf$/.ok/; $okfile =~ s/\.cfg$/.ok/;
		print "<BR><B><font color=#ff0000>No .ok file found</font></b><br>\n"
			."Have you successfully run MRTG on this file yet?" 
				if(!-f $okfile);
		}
		print "</TD><TD>".$routers{$rtr}{shdesc}."</TD>";
		yesno $routers{$rtr}{inmenu};
		yesno $routers{$rtr}{hastarget};
		print "<TD><TABLE border=0>";
		print "<TR><TD>Group:</TD><TD>".$routers{$rtr}{group}."</TD></TR>"
			if($routers{$rtr}{group});
		print "<TR><TD>Server:</TD><TD>".$routers{$rtr}{server}."</TD></TR>"
			if($routers{$rtr}{server});
		print "<TR><TD>Hostname:</TD><TD>".$routers{$rtr}{hostname}."</TD></TR>"
			if($routers{$rtr}{hostname});
		print "</TABLE></TD></TR>\n";
	}
	print "</TABLE>";

	print $q->hr.$q->a({name=>"targets"},$q->h2("MRTG targets check"))."\n";
	print "Current device: ".$q->b($router)." (".$routers{$router}{desc}.")".$q->br."\n";
	print "MRTG file: ".$q->code($routers{$router}{file}).$q->br."\n";
	print $q->p("These targets are read from the MRTG file, and then displayed according to how they are interpreted.");
	print "<BR><TABLE border=1 align=center>\n";
	print "<TR><TD>Target<br>RRD File</TD><TD>Mode</TD><TD>In Menu</TD><TD>In Summary</TD><TD>In/Out</TD><TD>In Compact</TD><TD>Notes</TD></TR>\n";
	foreach $curif ( keys %interfaces ) {
		next if($interfaces{$curif}{usergraph});
		print "<TR><TD>";
		print $q->img({src=>$iconurl.$interfaces{$curif}{icon},width=>15, height=>15})." " if(defined $interfaces{$curif}{icon});
		print "$curif<br>".$interfaces{$curif}{rrd};
		if(!-r $interfaces{$curif}{rrd}) {
		print "<BR><B><font color=#ff0000>Unable to read RRD file!</font></B>"
		}
		print "</TD><TD>".$interfaces{$curif}{mode}."</TD>";
		yesno $interfaces{$curif}{inmenu};
		yesno $interfaces{$curif}{insummary};
		yesno $interfaces{$curif}{inout};
		yesno $interfaces{$curif}{incompact};
		print "<TD>";
		if($rrdok and -r $interfaces{$curif}{rrd}) {
			$rrdinfo = RRDs::info($interfaces{$curif}{rrd});
			$e = RRDs::error();
			if(defined $rrdinfo and !$e) {
				print "RRD file format is legal.";
				print "<BR>Interval ".($rrdinfo->{step}/60)
					." minutes" if($rrdinfo->{step} != 300);
				print "<BR><B>Not in MRTG format!</B>"
					if(!defined $rrdinfo->{"ds[ds0].type"});
				print "<BR>Extended timeframe"
					if($rrdinfo->{"rra[0].rows"} > 799);
			} else {
				print $q->b("Error reading rrd:").$q->br.$e;
			}
		}
		print "</TD>\n";
	}
	print "</TABLE>\n";

	print $q->hr.$q->a({name=>"icons"},$q->h2("Available Icons"))."\n";
	print "The available icons should be located in the <b>rrdicons</b> directory, currently defined to be:".$q->br."\n";
	print "URL: ".$q->code("http://$server".$config{'routers.cgi-iconurl'}).$q->br;
	print "If the menu page is installed, you can get to it "
		.$q->a({href=>$config{'routers.cgi-iconurl'}},"here").".".$q->br."\n";
	if($iconpath and -d $iconpath ) {
		# show available icons in here
		my( $c ) = 0; my($f,$b);
		print $q->br."<TABLE border=1 align=center>\n<TR>";
		foreach $f ( glob( $iconpath.$pathsep."*-sm.gif" ) ) {
			$b = basename $f;
			$c++;
			if($c eq 5) { $c = 1; print "</TR>\n<TR>"; }
			if( -r $f ) {
			print "<TD>".$q->img({src=>($iconurl.$b), width=>15, height=>15});
			print " ".$b."</TD>";
			} else {
				print "<TD bgcolor=#ff0000>Unable to read file $b</TD>";
			}
		}
		print "</TR></TABLE>";

		# verify
		print $q->p("If the above images do not display, then you may need to correct the <b>iconurl</b> parameter in the <b>[routers.cgi]</b> section of your routers.conf file.");
	} else {
		print "Checked directory $iconpath<br>\n";
		print $q->p("Unable to locate icon files in order to list them.  This is not necessarily a problem!  If the following image does not display, then you may need to correct the <b>iconurl</b> parameter in the <b>[routers.cgi]</b> section of your routers.conf file.");
	}
	print "This should show a target --&gt;"
		.$q->img({src=>$iconurl."target-sm.gif",width=>15, height=>15});
	print "&lt;--.  If it does not, correct your <b>iconurl</b> setting."
		.$q->br."\n";

	print $q->hr.$q->a({name=>"settings"},
		$q->h2("Active Configuration Settings"))."\n";
	print $q->p("These are the active settings, after taking into account any overrides due to application name ('$myname'), extra parameters ('$extra'), or authenticated user name ('$username').")."\n";
	print "<UL>\n";
	foreach ( sort keys %config ) {
		print $q->li($q->b($_)." = \"".$config{$_}."\"")."\n";
	}
	print "</UL>".$q->br;
	do_footer();
	print $q->end_html();
}

###########################
# If we get a bad page request

sub do_bad($)
{
	print $q->start_html({-title=>"routers.cgi Error",-bgcolor=>"#ffd0d0"});
	print $q->h1("Bad page request");
	print $q->p("Error message was [".$_[0]."]")."\n";
	print $q->p("Check the format of the URL parameters for the page you are requesting.")."\n";
	eval { print $q->dump; };
	print $q->hr.$q->small("Error message generated by routers.cgi")."\n";
	print $q->end_html();
}

########################################################################
# Initialise parameters

$pagetype="main";
$pagetype=$q->param('page') if( defined $q->param('page') );

if($pagetype eq "archive") {
	$archiveme = 1;
	$pagetype = "graph";
}
if( $q->param('archive') ){
	$archive = $q->param('archive');
}

# get these sections from the conf file.
$extra = lc $q->param('extra') if(defined $q->param('extra'));
$myname = lc basename $q->url();
readconf( 'routers.cgi','web','routerdesc','targetnames','targettitles',
	'targeticons', 'servers' ); 

# background colour (for the americans)
if ( defined $config{'routers.cgi-bgcolor'} 
	and $config{'routers.cgi-bgcolor'} =~ /(#[\da-f]{6})/i ) {
	$defbgcolour = $1;
}
if ( defined $config{'routers.cgi-menubgcolor'} 
	and $config{'routers.cgi-menubgcolor'} =~ /(#[\da-f]{6})/i ) {
	$menubgcolour = $1;
}
if ( defined $config{'routers.cgi-linkcolor'} 
	and $config{'routers.cgi-linkcolor'} =~ /(#[\da-f]{6})/i ) {
	$linkcolour = $1;
}
# background colour (for the british)
if ( defined $config{'routers.cgi-bgcolour'} 
	and $config{'routers.cgi-bgcolour'} =~ /(#[\da-f]{6})/i ) {
	$defbgcolour = $1;
}
if ( defined $config{'routers.cgi-menubgcolour'} 
	and $config{'routers.cgi-menubgcolour'} =~ /(#[\da-f]{6})/i ) {
	$menubgcolour = $1;
}
if ( defined $config{'routers.cgi-linkcolour'} 
	and $config{'routers.cgi-linkcolour'} =~ /(#[\da-f]{6})/i ) {
	$linkcolour = $1;
}

if( defined $config{'web-png'} and $config{'web-png'}=~/[1y]/i ) {
	$graphsuffix = "png";
}
if( defined $config{'routers.cgi-bytes'} 
	and $config{'routers.cgi-bytes'}=~/y/i ) {
	$bits = "!bytes";
	$factor = 1;
}

# Anyone giving us a cookie?
$defgstyle = $q->cookie('gstyle');
if( ! $defgstyle ) {
	if( $config{'routers.cgi-graphstyle'} ) {
		my( $w ); # match against all the possibilities
		foreach ( keys %gstyles ) {
			$gstyles{$_} =~ /(\w+)/;
			$w = lc $1;
			if( $w eq lc $config{'routers.cgi-graphstyle'}
				or $w eq $_ ) {
				$defgstyle = $_;
				last;
			}
		}
	}
	$defgstyle = 'n' if(!$defgstyle);
}
$defbaropts = "Cami";
if(defined $config{'routers.cgi-bars'}) {
	$defbaropts = $config{'routers.cgi-bars'};
}
$defgopts = $q->cookie('gopts');
$defgopts = "" if(!defined $defgopts);
$defgtype = $q->cookie('gtype');
$defgtype = $gorder[0] if(! $defgtype);
if(defined $config{'routers.cgi-sorder'} ) {
	@sorder = ();
	foreach ( split " ", $config{'routers.cgi-sorder'} ) {
		push @sorder, $_ if(defined $gstyles{$_});
	}
}

# identify menu type
$mtype = "routers";
$mtype  = $q->param('xmtype')  if( defined $q->param('xmtype') );
if( defined $config{'routers.cgi-allowexplore'} and $mtype ne "options" ) {
	$mtype = "options"
		if($config{'routers.cgi-allowexplore'} !~ /y/ );
}

# set the current router and interface...
$router = "";
$router = $defrouter = $q->cookie('router') if($q->cookie('router'));
$router = $q->param('rtr') if( $q->param('rtr') );
#$router = "" if(!defined $router or $router eq "none");
$router = "" if(!defined $router);
if(($pagetype eq "config") 
	or ($pagetype =~ /menu/ and ($mtype eq "routers" or !$router))
  or(!$router and $pagetype ne "help" and $pagetype ne "main" and
	$pagetype ne "head" and $pagetype ne "bar" and $pagetype)
  or($pagetype eq "graph" 
	and !-r $config{'routers.cgi-confpath'}.$pathsep.$router )
  or $pagetype eq "verify"
) {
	read_routers();
	if ((! $router or !defined $routers{$router} ) and $router ne "none") {
		if($config{'routers.cgi-defaultrouter'}
			and defined $routers{$config{'routers.cgi-defaultrouter'}}) {
			$router = $defrouter = $config{'routers.cgi-defaultrouter'};
		} else {
			$router = $defrouter = (sort bydesc keys(%routers))[0] ;
		}
	}
}

# Get interface information, if we need it
$defif = $q->cookie('if');
$defif = $config{'routers.cgi-defaultinterface'} 
	if(!$defif and defined $config{'routers.cgi-defaultinterface'});
$interface = ($q->param('if'))?$q->param('if'):$defif ;
$interface = "" if(! defined $interface );
if(( ($pagetype =~ /menu/ and $mtype ne "routers" )
	or $pagetype eq "csv" or $pagetype eq "graph" or $pagetype eq "summary"
	or $pagetype eq "info" or $pagetype eq "compact" 
	or $pagetype eq "verify" or $pagetype eq "image" )
		and $router ne "none" ) {
	if($router =~ /^#SERVER#/ ) {
		set_svr_ifs();
	} else {
		read_cfg();
	}
	if ( !$interface or $interface eq "__first"
		or $interface eq "__interface" or $interface eq "__memory" 
		or $interface eq "__cpu" or $interface eq "__userdef" 
		or ( $interface !~ /^__/ and !defined $interfaces{$interface} )
	) {
		my( @ifs ) = sort byifdesc keys(%interfaces);
		$defif = $ifs[0];
		foreach ( @ifs ) {
			if($interface eq "__interface" 
				and $interfaces{$_}{mode} eq "interface") 
			{ $defif = $_; last;  }
			if($interface eq "__memory" 
				and $interfaces{$_}{mode} eq "memory") 
			{ $defif = $_; last; }
			if($interface eq "__cpu" 
				and $interfaces{$_}{mode} eq "cpu") 
			{ $defif = $_; last; }
			if($interface eq "__userdef" and $interfaces{$_}{usergraph} ) 
			{ $defif = $_; last; }
		}
		$interface = $defif;
	}
} 

# Archive deletion
if( $q->param('delete') and $archive ) {
	# zap the requested archive
	my( $arch );
	$arch = $router; $arch =~ s/[\?#\/\\]//g;
	$arch = $config{'routers.cgi-graphpath'}.$pathsep.$arch.$pathsep
		.$interface.$pathsep.$archive;
	unlink $arch;
	$archive = "";
}

$gtype = $defgtype;
$gstyle = $defgstyle;
$gopts = $defgopts;
$baropts = $defbaropts;
$gtype  = $q->param('xgtype')  if( defined $q->param('xgtype') );
$gstyle = $q->param('xgstyle') if( defined $q->param('xgstyle'));
$gopts  = $q->param('xgopts')  if( defined $q->param('xgopts') );
$uopts  = $q->param('uopts')   if( defined $q->param('uopts')  );
$baropts= $q->param('bars')    if( defined $q->param('bars')   );
$gtype = "d" if(!$gtype);

# the graph time options
if( $interface and defined $interfaces{$interface}
	and $interfaces{$interface}{interval} < 5
	and defined $config{'routers.cgi-6hour'} 
	and $config{'routers.cgi-6hour'} =~ /y/i ) {
#	$gtypes{'6'} = "6-hour";
	@gorder = ( "6", @gorder ); # add it to the beginning of the list
	$usesixhour = 1;
}
# Should we verify that the RRA has enough data?  This would take a bit of
# extra time to do, but would prevent glitches.  However we could say that 
# anyone who switches this option on is taking the responsibility for making
# sure that the data is valid!
if( defined $config{'routers.cgi-extendedtime'}
	and $config{'routers.cgi-extendedtime'} =~ /y/i 
#	and $interface and defined $interfaces{$interface}
#	and $interfaces{$interface}{rrd} 
) {
	push @gorder, "d-","w-","m-","y-";
} elsif ( defined $config{'routers.cgi-extendedtime'}
	and $config{'routers.cgi-extendedtime'} =~ /t/i 
	and $interface and defined $interfaces{$interface}
	and $interfaces{$interface}{rrd} 
) {
	# see if we have more data available...
	eval { require RRDs; };
	if( !$@ ) {
		my( $infop ) = RRDs::info($interfaces{$interface}{rrd});
		push @gorder, "d-" if( ${$infop}{"rra[0].rows"} > 799 );
		push @gorder, "w-" if( ${$infop}{"rra[1].rows"} > 799 );
		push @gorder, "m-" if( ${$infop}{"rra[2].rows"} > 799 );
		push @gorder, "y-" if( ${$infop}{"rra[3].rows"} > 799 );
	} 
}

# sanity check
if( $gtype eq "6" and $interface !~ /^__/ and ( !$usesixhour 
	or ($interface and defined $interfaces{$interface} 
		and $interfaces{$interface}{interval} >= 5 ))) {
	 $gtype = $gorder[0];
#	$debugmessage .= "gtype=$gtype usesix=$usesixhour interface=$interface interval=".$interfaces{$interface}{interval};
}
if ( ! (defined $gtypes{$gtype}) or 
	( ($interface eq "__summary" or $interface eq "__compact")
		 and (length ($gtype) > 2) )) {
	$gtype = $gorder[0];
}
if( defined $config{'routers.cgi-uselastupdate'} 
	and $config{'routers.cgi-uselastupdate'} =~ /y/i ) {
	$uselastupdate = 1; # set the flag for later.
} else { $uselastupdate = 0; }
# How big is a K ? Some people prefer 1024, some prefer 1000
if( defined $config{'routers.cgi-usebigk'} ) {
	if( $config{'routers.cgi-usebigk'} =~ /y/i )      # yes
		{ $k = 1024; $M = $k * 1024; $G = $M * 1024; $ksym = "K"; }
	elsif( $config{'routers.cgi-usebigk'} =~ /n/i )   # no
		{ $k = 1000; $M = 1000000; $G = $M * 1000; $ksym = "k"; }
	elsif( $config{'routers.cgi-usebigk'} =~ /m/i )   # mixed
		{ $k = 1024; $M = 1024000; $G = $M * 1000; $ksym = "K"; }
	else 
		{ $k = 1024; $M = 1024000; $G = $M * 1000; $ksym = "K"; } # default
} else {
	$k = 1024; $M = 1024000; $G = $M * 1000; $ksym = "K"; # default (mixed)
}
# Define page title and so on.
$toptitle = $config{'routers.cgi-windowtitle'} 
	if ( defined $config{'routers.cgi-windowtitle'} );

# Date format labels
$monthlylabel=$config{'web-weeknumber'}
	if( defined $config{'web-weeknumber'} 
	and $config{'web-weeknumber'} =~ /%[UVW]/ );

# Menu format
if( (defined $config{'routers.cgi-twinmenu'}
	and $config{'routers.cgi-twinmenu'} =~ /y/i and $uopts !~ /T/ )
	or $uopts =~ /t/ ) {
	$twinmenu = 1;
}

# Start the page off

if( $pagetype eq "graph" and !$archive ) {
	my($rtime) = 1800;
	$rtime =900 if($gtype =~ /w/);
	$rtime =300 if($gtype =~ /d/);
	$rtime = 60 if($gtype =~ /6/);
	$rtime = $config{'routers.cgi-minrefreshtime'} 
		if( defined $config{'routers.cgi-minrefreshtime'}
			and $config{'routers.cgi-minrefreshtime'} > $rtime );
	$headeropts{-expires} = "+5s";
	$headeropts{-Refresh} = $rtime;
	$headeropts{-Refresh} .= "; URL=$meurl?".optionstring({}) if($archiveme);
}
$headeropts{-target} = $pagetype if($pagetype =~ /head|menub?|graph/ );
$headeropts{-target} = "graph" 
	if( $pagetype =~ /compact|summary|help|info|config/ );
$headeropts{-target} = "_top" if ( !$pagetype );

if ( $pagetype eq "config" and $q->param('xset')) {
	push @cookies, $q->cookie( -name=>'gstyle', -value=>$q->param('defgstyle'), 
		-path=>$q->url(-absolute=>1), -expires=>"+10y" ) 
			if( defined $q->param('defgstyle'));
	push @cookies, $q->cookie( -name=>'gtype', -value=>$q->param('defgtype'), 
		-path=>$q->url(-absolute=>1), -expires=>"+10y" ) 
			if( defined $q->param('defgtype') );
	push @cookies, $q->cookie( -name=>'router', -value=>$q->param('defrouter'), 
		-path=>$q->url(-absolute=>1), -expires=>"+10y" ) 
			if( defined $q->param('defrouter') );
	push @cookies, $q->cookie( -name=>'if', -value=>$q->param('defif'), 
		-path=>$q->url(-absolute=>1), -expires=>"+10y" ) 
			if( defined $q->param('defif') );
	$headeropts{-cookie} = [@cookies] if(@cookies);
}
if( $pagetype =~ /csv/ ) {
	my($fn) = "export.csv";
	$csvmime=$config{'web-csvmimetype'} if(defined $config{'web-csvmimetype'});
	$fn = $config{'web-csvmimefilename'}
		if(defined $config{'web-csvmimefilename'}) ;
	$csvmime .= "; filename=\"".$fn."\"";
	$headeropts{"-Content-Disposition"} = "filename=\"".$fn."\"";
	$headeropts{-type} = $csvmime ;
}

# The bar and image functions have to do their own headers as they may need 
# to redirect.
print $q->header( %headeropts ) if($pagetype !~ /bar|image/);

#
# Now, we check the passed parameters to find out what sort of page to
# serve up.  If we can't work out which one to do, then we just serve the
# index page
if($pagetype) {
	for($pagetype) {
		/head/ and do {	do_head(); last; };
		/menu/ and do { do_menu(); last; }; # matches menu and menub
		/csv/ and do {
			if( $interface =~ /^__/ ) {
				last; # oops, this shouldnt happen
			}
			do_export();
			last;
		};
		/image/ and do {
			if( $interface !~ /^__/ and defined $interfaces{$interface}) {
				if( $archive ) {
					do_archive(0);
				} else {
					do_graph(0);
				}
			} else {
		print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
			}
			last;
		};
		/graph|archive/ and do { 
			if( $interface eq "__summary") {
				do_summary();
			} elsif ( $interface eq "__info" ) {
				do_info();
			} elsif ( $interface eq "__compact" ) {
				do_compact();
			} elsif ( $interface eq "__none" ) {
				do_empty();
			} elsif ( $interface =~ /^__/ ) {
				do_bad("Bad interface: $interface");
			} else {
				if( $archive ) {
					do_archive(1);
				} else {
					do_graph(1);
				}
			}
			last; 
		};
		/help/ and do { do_help(); last; };
		/main/ and do { do_main(); last; };
		/info/ and do { do_info(); last; };
		/summary/ and do { do_summary(); last; };
		/compact/ and do { do_compact(); last; };
		/config/ and do { do_config(); last; };
		/bar/ and do { do_bar(); last; };
		/verify/ and do { do_verify(); last; };
		do_bad("Bad pagetype: $pagetype");
	}
} else { do_main() }
exit 0;
