1#!/usr/local/bin/perl
2# DONT FORGET TO CHANGE THE ABOVE PATH TO MATCH YOUR PERL LOCATION!
3#vim:ts=4
4##############################################################################
5# To use Speedycgi, you need to change the first line to this:
6###!/usr/local/bin/speedy -- -M20 -t3600 -gnone -r500
7# and then set the CACHE global variable (below) to 1.
8# To use mod_perl, you should be able to put the script directly into the
9# mod_perl directory and it will work.  This is not very thoroughly tested
10# though. You also need to set the CACHE global below to 1.
11##############################################################################
12# routers.cgi : Version v2.23
13# Create router monitoring pages
14#
15# This code is covered by the Gnu GPL.  See the README file, or the Gnu
16# web site for more details.
17#
18# Includes code derived from overlib (C) Eric Bosrup
19#
20# Developed and tested with RRDTool v1.4.4, Perl 5.8, under Linux (RHEL5)
21# Also partially tested with ActivePerl 5.6 with Apache under NT
22# Note - 95th percentile calcs DO NOT WORK under RRDTool v1.0.24 or earlier
23# Windows users should avoid RRDTool v1.0.33 - v1.0.39 due to a bug.
24#
25##############################################################################
26# DONT FORGET TO CHANGE THE LOCATION OF THE CONFIG FILE DEFINED BELOW!
27##############################################################################
28use strict;
29use CGI;              # for CGI
30use File::Basename;   # for identifying filenames under different OSs
31use Text::ParseWords; # for parsing MRTG .conf file
32use FileHandle;       # to have multiple conf files in recursion
33use Getopt::Std;      # For limited command line operation
34use POSIX qw(tzset strftime); # For timezone support
35#use Data::Dumper;     # For persistent caching
36use Time::Local 'timelocal_nocheck'; # For time conversions
37##CONFIG#START################################################################
38# You MUST set this to the location of the configuration file!
39my ($conffile) = '/usr/local/etc/routers2.conf';
40##############################################################################
41# Are we running in speedycgi or mod_perl mode?  Can we cache configs?
42# If you set this to 1 when you dont have speedycgi or mod_perl, it will
43# slightly slow things down, but will not break anything.
44# This can also be set in the routers2.conf with the cache=yes option
45my ($CACHE) = 0;
46##############################################################################
47# You should set this to something random and secret, if you are using
48# the script's internal authentication via cookies.  It's called this because
49# it is embedded into a cookie...
50my ($CHOCOLATE_CHIP) = 'fh89647jnvhtg678gtfpo9fuku86yhgs';
51##CONFIG#END##################################################################
52my ($VERSION) = 'v2.23';
53my ($APPURL ) = 'http://www.steveshipway.org/software/';
54my ($FURL   ) = 'http://www.steveshipway.org/forum/';
55my ($MLURL  ) = 'http://www.steveshipway.org/mailman/listinfo/support_steveshipway.org';
56my ($WLURL  ) = 'http://www.steveshipway.org/software/wishlist.html';
57my ($BURL   ) = 'http://www.steveshipway.org/book/';
58my ($APPMAIL) = 'mailto:steve@steveshipway.org';
59##GLOBAL#START################################################################
60# Global variables : uses 'use vars' for speeycgi and mod_perl
61use vars qw($opt_A $opt_D $opt_T $opt_r $opt_i $opt_s $opt_t $opt_I $opt_a $opt_U $opt_C $opt_G);
62use vars qw($meurl $meurlfull);
63use vars qw($mtype $gtype $defgopts  $defgtype  $defrouter  $defif  $cookie);
64($mtype,$gtype,$defgopts, $defgtype, $defrouter, $defif, $cookie) =
65	('','','','','','','');
66use vars qw(@cookies);
67@cookies=();
68use vars qw($gopts  $baropts  $defbaropts  $uopts);
69($gopts, $baropts, $defbaropts, $uopts) = ('','','','');
70use vars qw(%routers %routerscache); %routers = (); # loaded from cache
71use vars qw(%cachedays);
72use vars qw($readinrouters); $readinrouters = 0;
73use vars qw(%interfaces %ifstore);
74use vars qw(%lang $language); $language = '';
75use vars qw(%gtypes  @gorder);
76use vars qw(%gstyles  @sorder  %gstylenames);
77use vars qw($gstyle  $defgstyle  $archdate);
78($gstyle, $defgstyle, $archdate) = ('','','');
79use vars qw(%headeropts); %headeropts = ();
80use vars qw(@cfgfiles); @cfgfiles = ();
81use vars qw($lastupdate  $workdir  $interval);
82($lastupdate, $workdir, $interval) = ('','','');
83use vars qw($basetime); $basetime = 0;
84use vars qw($pagetype); $pagetype = '';
85use vars qw($donecfg); $donecfg = 0;
86use vars qw(%config);
87use vars qw($bn); $bn = '';
88use vars qw($graphsuffix); $graphsuffix = "gif";
89use vars qw($NT); $NT = 0;             # gets set to 1 if using NT
90use vars qw($pathsep); $pathsep = "/";      # gets set to "\\" if you have NT
91use vars qw($dailylabel); $dailylabel = "%k";  # set to "%H" if you have ActivePerl
92use vars qw($monthlylabel);
93$monthlylabel = "%V";# use "%W" for alternate week numbering method
94                         # gets set to %W if you have ActivePerl
95use vars qw($usesixhour); $usesixhour = 0;
96use vars qw($twinmenu); $twinmenu = 0;
97use vars qw($rrdoutput); $rrdoutput = "";
98use vars qw($rrdxsize  $rrdysize);
99($rrdxsize, $rrdysize) = (0,0);
100use vars qw($router  $interface);
101($router, $interface) = ('','');
102use vars qw($uselastupdate $archivetime); $uselastupdate = 0;
103use vars qw($ksym $k $M $G $T);
104($ksym,$k,$M,$G,$T) = ("K",1024,1024000,1024000000,1024000000000); # mixed
105use vars qw($grouping); $grouping = 0;       # Do we group when sorting routers?
106use vars qw($group); $group = "";
107use vars qw($csvmime);
108$csvmime = "text/comma-separated"; # MIME type for CSV downloads
109use vars qw($windowtitle); $windowtitle = "Systems Monitor"; # Widow title
110use vars qw($toptitle); $toptitle = "";                  # Title at top of page
111use vars qw($timezone); $timezone = 0;
112use vars qw($bits  $factor);
113($bits, $factor) = ("!bits",8);
114use vars qw($defbgcolour); $defbgcolour = "#ffffff";  # default colours
115use vars qw($deffgcolour); $deffgcolour = "#000000";
116use vars qw($menubgcolour); $menubgcolour = "#d0d0d0";
117use vars qw($menufgcolour); $menufgcolour = "#000000";
118use vars qw($authbgcolour); $authbgcolour = "#ffffff";
119use vars qw($authfgcolour); $authfgcolour = "#000000";
120use vars qw($linkcolour); $linkcolour = "#2020ff";
121use vars qw($extra); $extra = "";
122use vars qw($archiveme); $archiveme = 0;
123use vars qw($archive); $archive = "";
124use vars qw($myname); $myname = 'routers2.cgi';
125use vars qw($debugmessage); $debugmessage = "Instance: $$\n";
126use vars qw($authuser); $authuser  = "";
127use vars qw($crypthack); $crypthack = 0; # compatibility for broken crypt
128use vars qw(@params); @params = ();
129use vars qw($traffic); $traffic = "";
130use vars qw($seclevel); $seclevel = 0;
131use vars qw($comma); $comma = ','; # for CSV
132use vars qw(@pathinfo); @pathinfo = ();
133use vars qw($stime); $stime = (times)[0];
134use vars qw($linewidth); $linewidth = 1;
135use vars qw($charset); $charset = '';
136use vars qw($rrdcached); $rrdcached = '';
137use vars qw(@rrdcached); @rrdcached = ();
138use vars qw($PERCENT); $PERCENT = 95;
139
140##GLOBAL#END############################################################
141# You MAY configure the descriptions in the lines below if you require
142# or, remove some entries from the @sorder Styles list.
143########################################################################
144sub initlabels {
145	%gtypes = (
146		"d"=>"Daily",            "w"=>"Weekly",
147		"m"=>"Monthly",          "y"=>"Yearly",
148		"dwmy"=>"All Graphs",    "6dwmy"=>"All Graphs",
149		"6dwmys"=>"Compact",     "dwmys"=>"Compact",
150		"6"=>"6 hour",           "6-"=>"Six hours ago",
151		"m-"=>"Last Month",      "w-"=>"Last week",
152		"d-"=>"Yesterday",       "y-"=>"Last Year",
153		"dw"=>"Short term",      "my"=>"Long term",
154		"6s"=>"Compact 6 hour",
155		"ds"=>"Compact daily",   "ws"=>"Compact weekly",
156		"ms"=>"Compact monthly", "ys"=>"Compact yearly",
157		"dm"=>"Day+Month",       "wm"=>"Week+Month",
158		"dy"=>"Day+Year",
159		"x1"=>"X1", "x2"=>"X2", "x3"=>"X3", "x4"=>"X4"
160	 );
161	@gorder = qw/d w m y dwmy dwmys/;
162	# you might prefer to have the order reversed
163	# NOTE: first word of these is the key used in routers.conf for default
164	# base style: s t n l x y = widths; s t = half data width
165	# suffix: D = double data width, 2 3 = height multiplier
166    #         p = no javascript (pda), b = monochrome (b&w)
167	# so for example, tD is the same as n
168	%gstyles = (
169		s=>"Short (PDA)", n=>"Normal (640x480)", t=>"Stretch", l=>"Long",
170		n2=>"Tall", l2=>"Big (800x600)", x3=>"Huge (1024x768)", x=>"ExtraLong",
171		sbp=>"Palm III/V", nbp=>"Psion 3/3x/5", np=>"WinCE-1", sp=>"WinCE-2",
172		l2p=>"Web TV", x2=>"Very Big (1024x768)" ,
173		y3=>"Vast (widescreen)", x3D=>"Huge extended", l2D=>"Big extended",
174		x3H=>"Huge stretch", l2H=>"Big stretch",
175		x3T=>"Huge triple",
176	);
177	if(defined $config{'routers.cgi-sorder'} ) {
178		@sorder = ();
179		foreach ( split " ", $config{'routers.cgi-sorder'} ) {
180			push @sorder, $_ if(defined $gstyles{$_});
181		}
182	} else {
183		# you might want to remove some of these
184		@sorder = qw/s t n n2 l l2 l2D x x3 x3D sbp nbp np l2p/;
185	}
186}
187
188##CODE#START############################################################
189# Nothing else to configure after this line
190########################################################################
191
192# initialize CGI
193use vars qw($q);
194$q = new CGI; # At this point, parameters are parsed
195
196$meurl = $q->url(-absolute=>1); # /cgi-bin/routers2.cgi
197$meurlfull = $q->url(-full=>1); # http://server/cgi-bin/routers2.cgi
198$meurlfull = "" if($meurlfull !~ /\/\/.*\//); # avoid IIS bug, maybe
199$router = $interface = "";
200
201#################################
202# For RRD v1.2 compatibility: remove colons for COMMENT directive if
203# we are in v1.2 or later, else leave them there
204sub decolon($) {
205	my($s) = $_[0];
206	return $s if($RRDs::VERSION < 1.2 );
207	$s =~ s/:/\\:/g;
208	return $s;
209}
210
211#################################
212# For RRD archives: make 2chr subdir name from filename
213sub makehash($) {
214	my($x);
215# This is more balanced
216	$x = unpack( '%8C*',$_[0] );
217# This is easier to follow
218#	$x = substr($_[0],0,2);
219	return $x;
220}
221
222#################################
223# For expanding variables
224sub expandvars($) {
225	my($s) = $_[0];
226	my($luh);
227	my($rv,$tmp);
228	my($comm) = '';
229	my($dev) = '';
230	my($snmp,$snmperr,$resp) = ('','','');
231
232	# Process %INCLUDE(....)% symbols
233	while( $s =~ /\%INCLUDE\(\s*(\S+)\s*\)\%/ ) {
234		my($f) = $1;
235		my($d) = "";
236		if( open INC,"<$f" ) {
237			while ( <INC> ) { $d .= $_; }
238			close INC;
239		} else {
240			$d = "Error: File $f: $!";
241		}
242		$s =~ s/\%INCLUDE\(\s*$f\s*\)\%/$d/g;
243	}
244
245	# Process all standard symbols and their variants
246	$s =~ s/\%ROUTERS2?\%/$meurlfull/g;
247	$s =~ s/\%CFG(FILE)?\%/$routers{$router}{file}/g;
248	$s =~ s/\%INTERVAL\%/$routers{$router}{interval}/g;
249	$s =~ s/\%(ROUTER|DEVICE)\%/$router/g;
250	$s =~ s/\%(TARGET|INTERFACE)\%/$interface/g;
251	$s =~ s/\%STYLE\%/$gstyle/g;
252	$s =~ s/\%TYPE\%/$gtype/g;
253	$s =~ s/\%STYLENAME\%/$gstyles{$gstyle}/g;
254	$s =~ s/\%TYPENAME\%/$gtypes{$gtype}/g;
255	$s =~ s/\%L(U|ASTUPDATE)\%/$lastupdate/g;
256	if($lastupdate) { $luh = longdate($lastupdate); }
257	else { $luh = "Unknown"; }
258	$s =~ s/\%L(U|ASTUPDATE)H\%/$luh/g;
259	$s =~ s/\%ARCHDATE\%/$archdate/g;
260	$s =~ s/\%USER(NAME)?\%/$authuser/g;
261	$tmp = optionstring({page=>"image"});
262	$s =~ s/\%GRAPHURL\%/$meurlfull?$tmp/g;
263	$tmp = 300;
264	if( $gtype =~ /y/ ) { $tmp = 24 * 3600; }
265	elsif( $gtype =~ /m/ ) { $tmp = 7200; }
266	elsif( $gtype =~ /w/ ) { $tmp = 1800; }
267	$s =~ s/\%AVGINT\%/$tmp/g;
268
269
270	$rv = $routers{$router}{'cfgmaker-system'}; $rv="" if(!defined $rv);
271	$s =~ s/\%CMSYSTEM\%/$rv/g;
272	$rv = $routers{$router}{'cfgmaker-description'}; $rv="" if(!defined $rv);
273	$s =~ s/\%CMDESC(RIPTION)?\%/$rv/g;
274	$rv = $routers{$router}{'cfgmaker-contact'}; $rv="" if(!defined $rv);
275	$s =~ s/\%CMCONTACT\%/$rv/g;
276	$rv = $routers{$router}{'cfgmaker-location'}; $rv="" if(!defined $rv);
277	$s =~ s/\%CMLOCATION\%/$rv/g;
278
279	if( defined $interfaces{$interface} ) {
280		$rv = $interfaces{$interface}{maxbytes}; $rv = "" if(!defined $rv);
281		$s =~ s/\%(MAXBYTES|BANDWIDTH)\%/$rv/g;
282		$rv = $interfaces{$interface}{ipaddress}; $rv = "" if(!defined $rv);
283		$s =~ s/\%IP(ADDR(ESS)?)?\%/$rv/g;
284		$rv = $interfaces{$interface}{community};
285		$rv = $routers{$router}{community} if(! $rv);
286		$rv = "" if(!defined $rv);
287		$s =~ s/\%COMMUNITY\%/$rv/g;
288		$rv = $interfaces{$interface}{hostname};
289		$rv = $routers{$router}{hostname} if(! $rv);
290		$rv = "" if(!defined $rv);
291		$s =~ s/\%HOST(NAME)?\%/$rv/g;
292		$rv = $interfaces{$interface}{rrd}; $rv = "" if(!defined $rv);
293		$s =~ s/\%RRD(FILE)?\%/$rv/g;
294		$rv = $interfaces{$interface}{ifno}; $rv = "" if(!defined $rv);
295		$s =~ s/\%(IFNO|INTNUM)?\%/$rv/g;
296
297		$rv = $interfaces{$interface}{'cfgmaker-description'};
298		$rv = "" if(!defined $rv);
299		$s =~ s/\%CMIDESC(RIPTION)?\%/$rv/g;
300
301		if( defined $interfaces{$interface}{symbols} ) {
302			foreach my $sym ( keys %{$interfaces{$interface}{symbols}} ) {
303				my $v = $interfaces{$interface}{symbols}{$sym};
304				$s =~ s/\%$sym\%/$v/g;
305			}
306		}
307	} else {
308		$rv = $routers{$router}{community}; $rv = "" if(!defined $rv);
309		$s =~ s/\%COMMUNITY\%/$rv/g;
310		$rv = $routers{$router}{hostname}; $rv = "" if(!defined $rv);
311		$s =~ s/\%HOST(NAME)?\%/$rv/g;
312	}
313	if( defined $routers{$router}{symbols} ) {
314		foreach my $sym ( keys %{$routers{$router}{symbols}} ) {
315			my $v = $routers{$router}{symbols}{$sym};
316			$s =~ s/\%$sym\%/$v/g;
317		}
318	}
319
320	# Process %ENV(...)% symbols
321	while( $s =~ /\%ENV\(\s*(\S+)\s*\)\%/ ) {
322		my($a) = $1;
323		my($b) = $ENV{$a};
324		$s =~ s/\%ENV\($a\)\%/$b/g;
325	}
326
327	# Process %OID(....)% symbols
328	while( $s =~ /\%OID\(\s*(\S+)\s*\)\%/ ) {
329		my($a) = $1;
330		my($b) = '[Not yet supported]';
331		my($vb);
332		$comm = $routers{$router}{community} if($routers{$router}{community});
333		$dev  = $routers{$router}{hostname} if($routers{$router}{hostname});
334		if($interface and $interfaces{$interface} ) {
335			$comm = $interfaces{$interface}{community}
336				if($interfaces{$interface}{community});
337			$dev  = $interfaces{$interface}{hostname}
338				if($interfaces{$interface}{hostname});
339			$dev  = $interfaces{$interface}{ipaddress}
340				if($interfaces{$interface}{ipaddress});
341		}
342		if(! $comm) {
343			$b = "[No community: Cannot request OID]";
344		} elsif(! $dev) {
345			$b = "[No hostname/IP known: Cannot request OID]";
346		} else {
347			# look up the OID via SNMP
348			eval { require Net::SNMP; };
349			if($@) {
350				$b = "[Net::SNMP not available]";
351			} else {
352				if(!$snmp) {
353					($snmp, $snmperr) = Net::SNMP->session(
354						-hostname=>$dev, -community=>$comm, -timeout=>4 );
355				}
356				if($snmperr) { $b = "[SNMP Error: $snmperr]"; }
357				else {
358					$resp = $snmp->get_request( $a );
359					if( defined $resp ) {
360						$vb = $snmp->var_bind_types( $a );
361						$b = "";
362						foreach ( keys %$resp ) {
363							if($vb->{$_} eq *TIMETICKS ) {
364								$b .= ticks_to_time($resp->{$_});
365							} else { $b .= $resp->{$_}; }
366						}
367					} else { $b = "[SNMP Error:".$snmp->error()."]"; }
368				}
369			}
370		}
371		$s =~ s/\%OID\($a\)\%/$b/;
372	}
373	$snmp->close() if($snmp);
374
375	# Process %EXEC(...)% symbol
376	if(defined $config{'web-allow-execs'}
377		and $config{'web-allow-execs'}=~/[y1]/) {
378		while( $s =~ /\%EXEC\(([^\)]+)\)\%/ ) {
379			my($a) = $1;
380			my($b) = `$a`; # DANGER WILL ROBINSON!
381			$s =~ s/\%EXEC\($a\)\%/$b/;
382		}
383	}
384	return $s;
385}
386
387#################################
388# For sorting
389
390sub rev { $b cmp $a; }
391sub numerically {
392	return ($a cmp $b) if( $a !~ /\d/ or $b !~ /\d/ );
393	$a <=> $b;
394}
395sub bytraffic {
396	return -1 if(!$a or !$b or !$traffic);
397#	return -1 if(!defined $interfaces{$a}{$traffic}
398#		or !defined $interfaces{$b}{$traffic});
399	$interfaces{$b}{$traffic} <=> $interfaces{$a}{$traffic};
400}
401sub byiflongdesc {
402	my ( $da, $db ) = ( "#$a","#$b" );
403	# is this an invalid interface?
404	return 0 if(!defined $interfaces{$a} or !defined $interfaces{$b});
405	return 1  if(!$interfaces{$a}{inmenu} and $interfaces{$b}{inmenu});
406	return -1 if(!$interfaces{$b}{inmenu} and $interfaces{$a}{inmenu});
407	if( defined $config{'targetnames-ifsort'} ) {
408		if( $config{'targetnames-ifsort'} eq 'icon' ) {
409			return $interfaces{$a}{icon} cmp $interfaces{$b}{icon}
410				if($interfaces{$a}{icon} ne $interfaces{$b}{icon});
411		} elsif( $config{'targetnames-ifsort'} eq 'mode' ) {
412			return $interfaces{$a}{mode} cmp $interfaces{$b}{mode}
413				if($interfaces{$a}{mode} ne $interfaces{$b}{mode});
414		}
415	} else {
416		return $interfaces{$a}{mode} cmp $interfaces{$b}{mode}
417			if($interfaces{$a}{mode} ne $interfaces{$b}{mode});
418	}
419	# we always sort by description in the end
420	$da = $interfaces{$a}{shdesc} if( defined $interfaces{$a}{shdesc} );
421	$db = $interfaces{$b}{shdesc} if( defined $interfaces{$b}{shdesc} );
422	$da = $interfaces{$a}{desc} if( defined $interfaces{$a}{desc} );
423	$db = $interfaces{$b}{desc} if( defined $interfaces{$b}{desc} );
424	(lc $da) cmp (lc $db);
425}
426sub byifdesc {
427	my ( $da, $db ) = ( "#$a","#$b" );
428	# is this an invalid interface?
429	return 0 if(!defined $interfaces{$a} or !defined $interfaces{$b});
430	return 1  if(!$interfaces{$a}{inmenu} and $interfaces{$b}{inmenu});
431	return -1 if(!$interfaces{$b}{inmenu} and $interfaces{$a}{inmenu});
432
433	if( defined $config{'targetnames-ifsort'} ) {
434		if( $config{'targetnames-ifsort'} eq 'icon' ) {
435			return $interfaces{$a}{icon} cmp $interfaces{$b}{icon}
436				if($interfaces{$a}{icon} ne $interfaces{$b}{icon});
437		} elsif( $config{'targetnames-ifsort'} eq 'mode' ) {
438			return $interfaces{$a}{mode} cmp $interfaces{$b}{mode}
439				if($interfaces{$a}{mode} ne $interfaces{$b}{mode});
440		}
441	} else {
442		return $interfaces{$a}{mode} cmp $interfaces{$b}{mode}
443			if($interfaces{$a}{mode} ne $interfaces{$b}{mode});
444	}
445	# we always sort by description in the end
446	$da = $interfaces{$a}{shdesc} if( defined $interfaces{$a}{shdesc} );
447	$db = $interfaces{$b}{shdesc} if( defined $interfaces{$b}{shdesc} );
448	(lc $da) cmp (lc $db);
449}
450sub bydesc {
451	my ( $da, $db ) = ($routers{$a}{desc}, $routers{$b}{desc});
452	$da = $a if ( ! $da );
453	$db = $b if ( ! $db );
454	(lc $da) cmp (lc $db);
455}
456# Sorting function for devices menu
457sub byshdesc {
458	my ( $da, $db ) = ($routers{$a}{shdesc}, $routers{$b}{shdesc});
459	if( $grouping ) {
460		my ( $ga ) = $routers{$a}{group};
461		my ( $gb ) = $routers{$b}{group};
462		$ga=$config{"targetnames-$ga"} if(defined $config{"targetnames-$ga"});
463		$gb=$config{"targetnames-$gb"} if(defined $config{"targetnames-$gb"});
464		# Sort by group name first
465		my ( $c  ) = $ga cmp $gb;
466		if($c) { return $c; }
467	}
468	# Sort by description of device
469	$da = $a if ( ! $da );
470	$db = $b if ( ! $db );
471	(lc $da) cmp (lc $db);
472}
473# For sorting component targets in a userdefined
474# sort option can be MAX, AVG, LAST
475sub byoption {
476	return($interfaces{$b}{sorttmp} <=> $interfaces{$a}{sorttmp});
477}
478sub byoptionrev {
479	return($interfaces{$a}{sorttmp} <=> $interfaces{$b}{sorttmp});
480}
481sub sorttargets($$$) {
482	my($interface,$dwmy,$option) = @_;
483	my($from,$rrd,$e);
484	my($resolution,$interval,$seconds);
485	my($curif);
486	my(@sorted) = ();
487
488	return if(!$interfaces{$interface}{targets});
489
490	if( $option =~ /desc|name|title/i ) {
491		@sorted =
492			sort { (lc $interfaces{$a}{shdesc}) cmp (lc $interfaces{$b}{shdesc}); }
493				@{$interfaces{$interface}{targets}};
494		return @sorted;
495	}
496
497	$resolution = 60; $interval = "6h"; $seconds = 6*3600;
498	if ( $dwmy=~/d/ ){$resolution=300; $interval="24h"; $seconds=86400; }
499	elsif($dwmy=~/w/){$resolution=1800; $interval="7d"; $seconds=7*86400; }
500	elsif($dwmy=~/m/){$resolution=7200; $interval="1month"; $seconds=30*86400;}
501	elsif($dwmy=~/y/){$resolution=86400; $interval="1y"; $seconds=365*86400;}
502
503	$curif = $interfaces{$interface}{targets}[0];
504	$rrd = $interfaces{$curif}{rrd};
505	if($basetime) {
506		$from = $basetime;
507	} elsif( $dwmy =~ /-/ ) {
508		$from = "now-$interval";
509	} elsif($uselastupdate > 1 and $archivetime) {
510		$from = $archivetime;
511	} elsif($uselastupdate) {
512		$from = RRDs::last($rrd,@rrdcached);
513		$e = RRDs::error();
514		if($e) {
515			$from = "now";
516			$interfaces{$curif}{errors}.= $q->br.$q->small(langmsg(8999,"Error").": $e")."\n";
517		}
518	} else {
519		$from = "now-5min";
520	}
521
522	foreach $curif ( @{$interfaces{$interface}{targets}} ) {
523		$interfaces{$curif}{sorttmp} = 0;
524		$rrd = $interfaces{$curif}{rrd};
525		if( $option =~ /max/i ) {
526			my ( $start, $step, $names, $values ) =
527				RRDs::fetch($rrd,"MAX","-s","$from-$interval",
528					"-e",$from,"-r",$seconds,@rrdcached);
529			$e = RRDs::error();
530			if($e) {
531				$interfaces{$curif}{errors} .= $q->br.$q->small(langmsg(8999,"Error").": $e");
532			} else {
533				my ($maxin, $maxout) = get_max($values);
534				$interfaces{$curif}{sorttmp}=(($maxin>$maxout)?$maxin:$maxout);
535			}
536		} elsif( $option =~ /last/i ) {
537		} else { # avg
538			my ( $start, $step, $names, $values ) =
539				RRDs::fetch($rrd,"AVERAGE","-s","$from-$interval",
540					"-e",$from,"-r",$seconds,@rrdcached);
541			$e = RRDs::error();
542			if($e) {
543				$interfaces{$curif}{errors} .= $q->br.$q->small(langmsg(8999,"Error").": $e");
544			} else {
545				my ($avgin, $avgout) = get_avg($values);
546				$interfaces{$curif}{sorttmp}=(($avgin>$avgout)?$avgin:$avgout);
547			}
548		}
549	}
550
551	if($option=~/rev/) {
552		@sorted = sort byoptionrev @{$interfaces{$interface}{targets}};
553	} else {
554		@sorted = sort byoption @{$interfaces{$interface}{targets}};
555	}
556	return @sorted;
557}
558#####################
559# Timezone calculations
560# Calculate timezone.  We don't need to do this again if its already been
561# done in a previous iteration.  Now, we need this if we're making a graph
562# with working day intervals, or if we're on a graph/summary page with a
563# time popup - but we may as well do it every time.
564sub calctimezone() {
565	my( @gm, @loc, $hourdif );
566$timezone = 0;
567if( defined $config{'web-timezone'} ) {
568	# If its been defined explicitly, then use that.
569	$timezone = $config{'web-timezone'};
570} else {
571	# Do we have Time::Zone?
572	eval { require Time::Zone; };
573	if ( $@ ) {
574		eval { @gm = gmtime; @loc = localtime; };
575		if( $@ ) {
576			# Can't work out local timezone, so assume GMT
577			$timezone = 0;
578		} else {
579			$hourdif = $loc[2] - $gm[2];
580			$hourdif += 24 if($loc[3]>$gm[3] or $loc[4]>$gm[4] );
581			$hourdif -= 24 if($loc[3]<$gm[3] or $loc[4]<$gm[4] );
582			$timezone = $hourdif;
583		}
584	} else {
585		# Use the Time::Zone package since we have it
586		$timezone = Time::Zone::tz_local_offset() / 3600;
587		# it's in seconds so /3600
588	}
589}
590}
591
592######################
593# For grouping multilevel.  Work out which groups we need to display.
594# (activegroup, thisgroup, lastgroup)
595# returns [ [groupname,depth,active], ... ]
596sub getgroups($$$) {
597	my(@rv) = ();
598	my($ag,$tg,$lg) = @_;
599	my(@ag,@tg,@lg);
600	my($gs) = ':';
601	my($i) = 0;
602	my($actv) = 1;
603
604	$gs = $config{'routers.cgi-groupsep'}
605		if(defined $config{'routers.cgi-groupsep'});
606	$gs =~ s/\//\\\//g;
607
608	@ag = split /$gs/,$ag;
609	@tg = split /$gs/,$tg;
610	@lg = split /$gs/,$lg;
611
612	while( $i <= $#tg ) {
613		$actv = 0 if( $tg[$i] ne $ag[$i] );
614
615		if( $tg[$i] ne $lg[$i] ) {
616			$tg[$i] =~ s/^\s*//; # trim leading spaces
617			push @rv, [ $tg[$i], $i, $actv ];
618		}
619		last if(!$actv);
620		$i += 1;
621	}
622
623#	push @rv, [ $tg, 0, 0 ];
624	return @rv;
625}
626
627######################
628# Replacement for glob: find archives
629# return list of dates
630# This time, we also cache the list of archive dates, if we can
631sub findarch($$)
632{
633	my(@files) = ();
634	my($path,$file) = @_;
635
636	if ($config{'routers.cgi-archive-mode'} and
637		$config{'routers.cgi-archive-mode'}=~/hash/i ) {
638		foreach ( glob( $path.$pathsep.makehash($file).$pathsep.$file.".d".$pathsep."*-*-*.rrd" ) ) {
639			push @files, $1 if( /(\d\d\d\d-\d\d-\d\d).rrd/ );
640		}
641	} else {
642		opendir DIR, $path or return @files;
643		foreach ( readdir DIR ) {
644			push @files, $_ if( -f $path.$pathsep.$_ .$pathsep.$file );
645		}
646		closedir DIR;
647	}
648	return @files;
649}
650
651######################
652# calculate short date string from given time index
653
654sub shortdate($)
655{
656	my( $dformat ) = "%c"; # windows perl doesnt have %R
657	my( $datestr, $fmttime ) = ("",0);
658	return "DATE ERROR 1" if(!$_[0]);
659	$fmttime = $_[0];
660	$fmttime = time if(!$fmttime);
661	my( $sec, $min, $hour, $mday, $mon, $year ) = localtime($fmttime);
662	# try to get local formatting
663	$dformat = $config{'web-dateonlyformat'}
664		if(defined $config{'web-dateonlyformat'});
665	$dformat = $config{'web-shortdateformat'}
666		if(defined $config{'web-shortdateformat'});
667	$dformat =~ s/&nbsp;/ /g;
668	$datestr = POSIX::strftime($dformat,
669		0,$min,$hour,$mday,$mon,$year);
670	return "DATE ERROR 2" if(!$datestr);
671	return $datestr;
672}
673sub longdate($) {
674	# try to get local formatting
675	my( $dformat ) = "%c";
676	my( $datestr, $fmttime ) = ("",$_[0]);
677	my( $sec, $min, $hour, $mday, $mon, $year ) = localtime($fmttime);
678	$dformat = $config{'web-shortdateformat'}
679		if(defined $config{'web-shortdateformat'});
680	$dformat = $config{'web-longdateformat'}
681		if(defined $config{'web-longdateformat'});
682	$datestr = POSIX::strftime($dformat,0,$min,$hour,$mday,$mon,$year);
683	return $datestr;
684}
685
686#################################
687# For string trims.  Remove leading and trailing blanks
688sub trim($)
689{
690	my($x)=$_[0];
691	$x=~s/\s*$//;
692	$x=~s/^\s*//;
693	$x;
694}
695
696#################################
697# build up option string
698sub optionstring(%)
699{
700	my(%o,$options);
701	%o = %{$_[0]};
702
703	$o{page}="graph" if(!defined $o{page});
704	$o{xgtype}="$gtype" if($gtype and !defined $o{xgtype});
705	$o{xmtype}="$mtype" if($mtype and !defined $o{xmtype});
706	$o{xgstyle}="$gstyle" if($gstyle and !defined $o{xgstyle});
707	$o{xgopts}="$gopts" if($gopts and !defined $o{xgopts});
708	$o{bars}="$baropts" if($baropts and !defined $o{bars});
709	$o{rtr}="$router" if($router and !defined $o{rtr});
710	$o{if}="$interface" if($interface and !defined $o{if});
711	$o{extra}="$extra" if($extra and !defined $o{extra});
712	$o{uopts}="$uopts" if($uopts and !defined $o{uopts});
713	$o{arch}="$archdate" if($archdate and !defined $o{arch});
714# This shouldnt be propagated, really.
715#	$o{nomenu}=1 if($q->param('nomenu') and !defined $o{nomenu});
716
717	$options = "";
718	foreach ( keys %o ) {
719		if( $o{$_} ) {
720			$options .= "&" if ($options);
721			$options .= "$_=".$q->escape($o{$_});
722		}
723	}
724	return $options;
725}
726
727#################################
728# Generate the javascript for the page header
729sub make_javascript(%)
730{
731	my($js) = "";
732	my(%opa,%opb);
733	my($ua,$ub);
734
735	return("function LoadMenu() { }") if($q->param('nomenu') or $gstyle=~/p/);
736
737	%opa = ( page=>"menu" );
738	foreach ( keys %{$_[0]} ) { $opa{$_}=$_[0]->{$_}; }
739
740	$js = "
741	// these local versions are not optimised but avoid cross-site scripting
742	// problems when running in distributed mode
743	// Test for parent.menu in case someone is running graph frame standalone
744	function setlocationa(url) {
745		if(parent.makebookmark) { parent.setlocationa(url); }
746	}
747	function setlocationb(url) {
748		if(parent.makebookmark) { parent.setlocationb(url); }
749	}
750";
751	if( $twinmenu ) {
752		%opb = %opa;
753		$opa{xmtype} = "routers"; $opa{'if'} = "";
754		$opb{page} = "menub"; $opb{xmtype} = "options";
755		$ua = "$meurlfull?".optionstring(\%opa)."#top";
756		$ub = "$meurlfull?".optionstring(\%opb)."#top";
757		$js .= "function LoadMenu() { setlocationb(\"$ub\"); setlocationa(\"$ua\");	}\n";
758	} else { # not twinmenu mode
759		$opa{xmtype}="routers"
760		if($router eq "none" or (defined $opa{rtr} and $opa{rtr} eq "none"));
761		$opa{'if'}='' if($opa{xmtype}eq'routers');
762		$ua = "$meurlfull?".optionstring(\%opa)."#top";
763		$js .= "function LoadMenu() { setlocationa(\"$ua\"); } \n";
764	}
765
766	return $js;
767}
768# Makes the javascript for a popup time window on graphs.
769# This goes into a hidden div called dpopup at the top of the page.
770# This incorporates bits of code copied from the overlib javascript library
771# which is (C) Eric Bosrup
772sub graphpopupscript() {
773	my($js,$xpad,$ypad);
774	my($stretch) = 1;
775
776    if(( defined $config{'routers.cgi-javascript'}
777    	and $config{'routers.cgi-javascript'} =~ /[n0]/i )
778		or $gstyle =~ /p/ ) {
779        $js = " function clearpopup() { }
780            function timepopup() { }
781            function mousemove() { } ";
782    } else {
783		eval { require RRDs; }; # just in case
784		return "" if($@);
785		if( $RRDs::VERSION >= 1.4 ) { $xpad = 66; $ypad = 33; }
786		elsif( $RRDs::VERSION >= 1.2 ) { $xpad = 69; $ypad = 33; }
787		else { $xpad = 75; $ypad = 30; }
788		$stretch *= 2 if ($gstyle=~/D/);
789		$stretch /= 2 if ($gstyle=~/H/);
790		$stretch /= 2 if ($gstyle=~/^t/); # for stretch style, t==nH
791
792	$js = "// Function for RRDs version ".$RRDs::VERSION."\n";
793	$js .= "
794// This javascript code derived in part from Overlib by Eric Bosrup
795var tzoffset = 0;
796";
797	if(defined $config{'routers.cgi-actuals'}
798		and $config{'routers.cgi-actuals'}=~/[y1]/i
799		and (!defined $config{'routers.cgi-javascript'}
800		or $config{'routers.cgi-javascript'}=~/[y1]/i)) {
801		# larger offset if we're using actuals
802		$js .= "
803var ooffsety = -40; // above the cursor, to the right
804var ooffsetx = 10;  // offset of popup from cursor position
805";
806	} else {
807		$js .= "
808var ooffsety = -25; // above the cursor, to the right
809var ooffsetx = 5;  // offset of popup from cursor position
810";
811	}
812	$js .= "
813var owidth = 100;  // width of the popup
814var pop=null;
815var gx, gy, gw;
816var img=null;
817var interval = 0;
818var endtime = 0;
819var ns4=(document.layers)? true:false;
820var ns6=(document.getElementById)? true:false;
821var ie4=(document.all)? true:false;
822var ie5=false;
823var ie6=false;
824var dow=new Array(\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\",\"Sun\");
825var actual=new Array(5); // to hold 6/d/w/m/y arrays of 400 items
826var xactual=new Array(5); // to hold 6/d/w/m/y  flags
827xactual[0]=0; xactual[1]=0; xactual[2]=0; xactual[3]=0; xactual[4]=0; xactual[5]=0;
828if(ie4){
829	if((navigator.userAgent.indexOf('MSIE 5')> 0)
830	||(navigator.userAgent.indexOf('MSIE 6')> 0)
831	||(navigator.userAgent.indexOf('MSIE 7')> 0)
832	){ ie5=true; }
833	if((navigator.userAgent.indexOf('MSIE 6')> 0)
834	||(navigator.userAgent.indexOf('MSIE 7')> 0)
835	){ ie6=true; }
836	if(ns6){ ns6=false; }
837}
838
839function getextra(t) {
840	var idx;
841	var group;
842	var rv = \"\";
843	if(interval<1)return rv;
844	if(interval == 1800) { // weeks have only 333 not 400 dp in graph image
845	idx = 400-Math.floor((endtime-t)/(1500*$stretch)); // array index
846	} else {
847	idx = 400-Math.floor((endtime-t)/(interval*$stretch)); // array index
848	}
849	group = 0; // 6 hourly
850	if ( interval > 61  ) { group = 1; } // daily
851	if ( interval > 301 ) { group = 2; } // weekly
852	if ( interval > 1801 ) { group = 3; } // monthly
853	if ( interval > 7201 ) { group = 4; } // yealy
854	// now, see if we have stored any data for this interval
855	if( xactual[group]>0 && (\"\"+actual[group][idx])!=\"undefined\" ) { rv = \"<BR>\"+actual[group][idx]; }
856	return rv;
857}
858function clearpopup() {
859  if(pop != null ) {
860    if(ns4)pop.visibility=\"hide\";
861    else if(ie4)pop.visibility=\"hidden\";
862    else if(ns6)pop.style.visibility=\"hidden\";
863  } else { self.status = \"Error - no popup div defined.\"; }
864  endtime = 0;
865}
866function settext(s) {
867  if( pop != null ) {
868    if(ns4){
869      pop.document.write(s);
870      pop.document.close();
871      pop.visibility=\"show\";
872    }else if(ie4){
873      self.document.all['dpopup'].innerHTML=s;
874      pop.visibility=\"visible\";
875    }else if(ns6){
876      range=self.document.createRange();
877      range.setStartBefore(pop);
878      domfrag=range.createContextualFragment(s);
879      while(pop.hasChildNodes()){ pop.removeChild(pop.lastChild); }
880      pop.appendChild(domfrag);
881      pop.style.visibility=\"visible\";
882    } // else { self.status = \"Error - cannot determine brower\"; }
883  } else { self.status = \"Error - no popup div available\"; }
884}
885function repositionTo(obj,xL,yL){
886  if((ns4)||(ie4)){ obj.left=xL; obj.top=yL; }
887  else if(ns6){
888    obj.style.left=xL + \"px\";
889    obj.style.top=yL+ \"px\";
890  }
891}
892function fix(n) { var d = n; if(d<10) d=\"0\"+d; return d; }
893function findPosX(obj)
894{
895	var curleft = 0;
896	if (obj.offsetParent) {
897		while (obj.offsetParent) {
898			curleft += obj.offsetLeft;
899			if( obj.scrollLeft ) curtop -= obj.scrollLeft;
900			obj = obj.offsetParent;
901		}
902	}
903	else {
904		if (obj.x) curleft += obj.x;
905		if( obj.scrollLeft ) curtop -= obj.scrollLeft;
906	}
907	return curleft;
908}
909
910// Here we have a problem - IE gives offset relative to window, Netscape
911// gives relative to frame.  So a scrolled window doesnt work in IE.
912function findPosY(obj)
913{
914	var curtop = 0;
915	if (obj.offsetParent) {
916		while (obj.offsetParent) {
917			curtop += obj.offsetTop;
918			if( obj.scrollTop ) curtop -= obj.scrollTop;
919			 obj = obj.offsetParent;
920		}
921	}
922	else {
923		if (obj.y) curtop += obj.y;
924		if( obj.scrollTop ) curtop -= obj.scrollTop;
925	}
926	return curtop;
927}
928
929function mousemove(e) {
930  var msg, ox, oy, t, extra;
931  var placeX, placeY, winoffset, ohpos, ovpos, iwidth, iheight, scrollheight;
932  var scrolloffset, oaboveheight, d;
933
934  if( ! endtime ) return;
935	if(!e) { e=window.event; }
936	if( typeof(e.pageX)=='number' ) {
937       ox = e.pageX; oy=e.pageY;
938		winoffset = self.pageXOffset;
939		scrolloffset = self.pageYOffset;
940    } else if( typeof(e.clientX)=='number' ) {
941		if( document.documentElement) {
942			winoffset = document.documentElement.scrollLeft;
943			scrolloffset = document.documentElement.scrollTop;
944			ox = e.clientX + winoffset;
945			oy = e.clientY + scrolloffset;
946		} else {
947			winoffset = document.body.scrollLeft;
948			scrolloffset= document.body.scrollTop;
949			ox = e.clientX + winoffset;
950			oy = e.clientY + scrolloffset;
951		}
952	} else if(ie5) {
953		winoffset = self.document.body.scrollLeft;
954		scrolloffset = self.document.body.scrollTop;
955		ox=e.x+winoffset;
956		oy=e.y+scrolloffset;
957	} else {
958		ox = e.x; oy =e.y;
959		winoffset = 0;  // guess
960		scrolloffset = 0;
961	}
962
963// ox,oy is where the mouse is.  placeX,placeY is where the popup is going
964
965// now determine the frame size (inner width and height)
966  if(ie4){ iwidth=self.document.body.clientWidth;
967    iheight=self.document.body.clientHeight; }
968  else if(ns4){ iwidth=self.innerWidth; iheight=self.innerHeight; }
969  else if(ns6){ iwidth=self.outerWidth; iheight=self.outerHeight; }
970// iwidth is the actual page width. owidth is the bit outside.
971// winoffset is how much we've scrolled horizontally
972// X position for popup
973  placeX = ox+ooffsetx;
974  if(placeX > (iwidth-owidth+winoffset)){
975    placeX = iwidth-owidth+winoffset ;
976    if(placeX < 0) placeX = 0; // should be impossible
977  }
978// y position for popup
979  if((oy - scrolloffset)> iheight){ ovpos=35; }else{ ovpos=36; }
980  if(ovpos==35){
981    if(oaboveheight==0){
982      var divref=(ie4)? self.document.all['dpopup'] : pop;
983      oaboveheight=(ns4)? divref.clip.height : divref.offsetHeight;
984    }
985    placeY=oy -(oaboveheight + ooffsety);
986    if(placeY < scrolloffset)placeY=scrolloffset; // why doesnt this work?
987  }else{ placeY=oy + ooffsety; }
988// relative to image
989  ox -= findPosX(img); oy -= findPosY(img);
990// calculate time at cursor
991  if(( ox >= $xpad ) && ( ox <= (gx+$xpad)) && ( oy >= $ypad ) && ( oy <= (gy+$ypad) )) {
992    if( interval == 1800 ) { // special for weekly
993      t = endtime - 1500 * ($xpad+gx-ox)*gw/gx; // may only be approximate?
994    } else {
995      t = endtime - interval * ($xpad+gx-ox)*gw/gx; // may only be approximate?
996    }
997  } else { t = 0; }
998  if( t ) {
999	// the problem is we want to display this in the timezone of the TARGET.
1000	// t is the UTC time, and the Javascript Date object will give everything
1001	// relative to the workstation timezone.  So, we add the tz offset of
1002	// the Target, and subtract the tz offset of the workstation.
1003	// note that the passed tzoffset and that returned by getTimezoneOffset
1004	// seem to be different signs.
1005    d = new Date(t*1000);
1006    d.setTime((t+tzoffset+(d.getTimezoneOffset()*60))*1000);
1007    if( interval > 72000 ) { // dayofweek day/month (yearly graph)
1008";
1009	# I tawt I taw a Mewwican!
1010	if( defined $config{"web-shortdateformat"}
1011		and $config{"web-shortdateformat"}=~ /\/\%d|\%D/ ) {
1012		# I did! I did taw a Mewwican!
1013	    $js .= " msg = dow[d.getDay()]+\" \"+(d.getMonth()+1)+\"/\"+d.getDate();\n";
1014	} else {
1015		$js .= " msg = dow[d.getDay()]+\" \"+d.getDate()+\"/\"+(d.getMonth()+1);\n";
1016	}
1017	$js .= "
1018    } else if( interval > 4000 ) { // dayofweek day hour:00 (monthly graph)
1019      msg = dow[d.getDay()]+\" \"+d.getDate()+\" \"+fix(d.getHours())+\":00\";
1020    } else if( interval > 1000 ) { // dayofweek day time (weekly graph)
1021      msg = dow[d.getDay()]+\" \"+d.getDate()+\" \"+fix(d.getHours())+\":\"+fix(d.getMinutes());
1022    } else { // time (daily graph)
1023      msg = fix(d.getHours())+\":\"+fix(d.getMinutes());
1024    }
1025// for debugging the amazingly difficult timezone calculations
1026//	msg = msg + \" \" + d.getDay() + \"<BR>\" + endtime + \":\" + t + \"<BR>\" + tzoffset + \":\" + (d.getTimezoneOffset()*60);
1027	extra = getextra(t);
1028    settext(\"<STRONG>\"+msg+\"</STRONG>\"+extra);
1029	repositionTo(pop, placeX, placeY);
1030  } else {
1031    if(ns4)pop.visibility=\"hide\";
1032    else if(ie4)pop.visibility=\"hidden\";
1033    else if(ns6)pop.style.visibility=\"hidden\";
1034  }
1035}
1036
1037function timepopup(o,n,px,py,i,t,dx,tzo) {
1038  divname = n; img = o; gx = px; gy = py; interval = i; endtime = t; gw = dx;
1039  tzoffset = tzo;
1040  if(ns4) { pop=self.document.dpopup; }
1041  else if(ie4) { if(self.dpopup) { pop=self.dpopup.style;} else { endtime=0;}}
1042  else if(ns6) { pop=self.document.getElementById(\"dpopup\"); }
1043  else { endtime = 0; }
1044}";
1045	}
1046	return $js;
1047}
1048
1049#################################
1050# For persistent caching.  This requires the settings in the routers2.conf
1051# to specify caching, and specify a caching file.
1052# Return 0 if worked, 1 if it didnt.
1053# When loading the cache, set $^T to the modify date of the cache file.
1054sub write_cache()
1055{
1056	my($f);
1057	return 0 if(!defined $config{'routers.cgi-cachepath'});
1058	$debugmessage .= "Saving cache file...\n";
1059	eval { require  Data::Dumper; }; return 1 if($@);
1060	$f = $config{'routers.cgi-cachepath'}."/routers2.cache";
1061	open C,">$f" or return 1;
1062	print C Data::Dumper->Dump([\%routerscache],
1063		[qw(savrc)]);
1064#	print C Data::Dumper->Dump([\%routerscache,\%cachedays,\%ifstore],
1065#		[qw(savrc savcd savis)]);
1066	close C;
1067	$debugmessage .= "...done.\n";
1068	return 0;
1069}
1070sub load_cache()
1071{
1072	my(@s,$f,$d);
1073	my($savis,$savrc,$savcd);
1074	return 0 if(!defined $config{'routers.cgi-cachepath'});
1075	$debugmessage .= "Checking Cache file\n";
1076	return 0 if($readinrouters);
1077	$debugmessage .= "Attempting to load Cache file\n";
1078	eval { require Data::Dumper; };
1079	if($@) { $debugmessage .= "Unable to load: $@\n"; return 1; }
1080	$f = $config{'routers.cgi-cachepath'}."/routers2.cache";
1081	open C,"<$f" or do {
1082		$debugmessage .= "Failed to open cache file: $!\n";
1083		return 1; };
1084	$d = ""; while( <C> ) { $d .= $_; };
1085	@s = stat C; $^T = $s[9]; # in case the file is too old
1086	close C;
1087	$debugmessage .= "Trying to eval cache file contents\n";
1088	eval $d;
1089#	if($@) { %routerscache = (); %cachedays = (); %ifstore = (); return 1; }
1090#	%routerscache = %$savrc; %cachedays = %$savcd; %ifstore = %$savis;
1091	if($@ or !$savrc) { %routerscache = ();
1092		$debugmessage .= "Failed to eval: $@\n";
1093		return 1; }
1094	%routerscache = %$savrc;
1095	$debugmessage .= "Cache file loaded OK\n";
1096	return 0;
1097}
1098#################################
1099# Create a bar graph, as requested by the CGI parameters.
1100# This should be given two CGI parameters: IN and OUT.  Use GD libraries if
1101# available to make a simple bar with green bar and blue line. IN and OUT are
1102# supposed to be percentages.
1103sub do_bar()
1104{
1105	my( $gd, $black, $white, $green, $blue, $grey );
1106	my( $w, $h ) = (400,10);
1107	my($x1,$x2);
1108
1109	eval { require GD; };
1110	if($@) {
1111		# GD libraries not available.  So, redirect to error message graphic.
1112		print $q->redirect($config{'routers.cgi-iconurl'}."error.gif");
1113		return;
1114	}
1115
1116	if( defined $q->param('L') )
1117		{ $w = $q->param('L') if($q->param('L') >100); }
1118
1119	# We have GD.  So, make up a simple bar graphic and print it - after
1120	# giving the correct HTML headers of course.
1121	$gd = new GD::Image($w,$h);
1122	$black = $gd->colorAllocate(0,0,0);
1123	$white = $gd->colorAllocate(255,255,255);
1124	$green = $gd->colorAllocate(0,255,0);
1125	$blue  = $gd->colorAllocate(0,0,255);
1126	$grey  = $gd->colorAllocate(192,192,192);
1127
1128	if( $q->param('IN') < 0 and $q->param('OUT') < 0) {
1129		# unknown data
1130		$gd->fill(1,1,$grey); # background
1131	} else {
1132		$gd->fill(1,1,$white); # background
1133		$x1 = $w * $q->param('IN') /100.0 ;
1134		$x2 = $w * $q->param('OUT') /100.0 ;
1135		$gd->rectangle(0,0,$x1-1,(($x2>=0)?($h/2):$h)-1,$green) if($x1>1);
1136		$gd->fill(1,1,$green) if($x1 > 2);
1137		$gd->rectangle(0,(($x1>=0)?($h/2):0),$x2-1,$h-1,$blue) if($x2>1);
1138		$gd->fill(1,$h-2,$blue) if($x2 > 2);
1139	}
1140	$gd->rectangle(0,0,$w-1,$h-1,$black); # box around it
1141
1142	if(!$gd->can('gif') or( $gd->can('png')
1143		and defined $config{'web-png'} and $config{'web-png'}=~/[1y]/i )) {
1144		print $q->header({ -type=>"image/png", -expires=>"+6min" });
1145		binmode STDOUT;
1146		print $gd->png();
1147	} else {
1148		print $q->header({ -type=>"image/gif", -expires=>"+6min" });
1149		binmode STDOUT;
1150		print $gd->gif();
1151	}
1152}
1153# Thanks to Ciaran Anscomb for this idea
1154# Dont forget to add \n to help firefox and older browsers with line
1155# length limitations!
1156sub do_bar_html($$$$$) {
1157	my($barlen,$i,$o,$withi,$witho)=@_;
1158	my($bh)=4;
1159
1160	if( $config{'routers.cgi-stylesheet'} ) {
1161		$bh=8 if(!$witho or !$withi);
1162		print "<TD style='margin-left: 0.5em;'><SMALL>";
1163		print "<div style='border: 1px solid black; margin: 0; padding: 0; width: ".($barlen-2)."px; height: 8px; background-color: white;'>\n";
1164		print "<div style='width: $i\%; height: ${bh}px; background-color: #00ff00;'></div>\n" if($withi);
1165		print "<div style='width: $o\%; height: ${bh}px; background-color: #0000ff;'></div>\n" if($witho);
1166		print "</div></SMALL></TD>\n";
1167	} else {
1168		print "<TD align=left><SMALL>";
1169		print $q->img({border=>0,height=>10,width=>$barlen,src=>"$meurlfull?page=bar&L=$barlen&IN=$i&OUT=$o"});
1170 		print "</SMALL></TD>\n";
1171	}
1172
1173}
1174
1175#################################
1176# Read in language file
1177sub readlang($) {
1178	my($l) = $_[0];
1179	my($f,$sec);
1180
1181	return "Cached" if( defined $lang{$l} ); # already read it
1182	if(defined $config{'web-langdir'}) {
1183		$f = $config{'web-langdir'} ;
1184	} else {
1185		$f = dirname($conffile);
1186	}
1187	$f .= $pathsep."lang_$l.conf";
1188	return "Language file not present" if(! -r $f); # no language file defined
1189
1190	open LFH,"<$f" or return;
1191	$lang{$l} = { file=>$f };
1192	$sec = "";
1193	while( <LFH> ) {
1194		/^\s*#/ && next;
1195		/\[(.*)\]/ && do { $sec = lc $1; };
1196		chomp;
1197		/^\s*(\S+)\s*=\s*(\S.*?)\s*$/ and $lang{$l}{"$sec-$1"}=$2;
1198	}
1199	close LFH;
1200	return 0;
1201}
1202sub langmsg($$) {
1203	my($code,$default) = @_;
1204	return $default if(!$language);                # no language defined
1205	return $default if(!defined $lang{$language}); # language not loaded
1206	return $lang{$language}{"messages-$code"}
1207		if($lang{$language}{"messages-$code"});
1208	return $default;
1209}
1210sub langinfo {
1211	return "None" if(!$language);
1212	return "Language $language not loaded" if(!defined $lang{$language});
1213	return $lang{$language}{"global-description"}
1214		." Ver ".$lang{$language}{"global-version"}.", "
1215		.$lang{$language}{"global-author"};
1216}
1217sub langhtml($$) {
1218	my($m);
1219	$m = langmsg($_[0],$_[1]);
1220	$m =~ s/ /&nbsp;/g; $m =~ s/</&lt;/g; $m =~ s/>/&gt;/g;
1221	return $m;
1222}
1223sub initlang {
1224	my($l) = $_[0];
1225	my($rv);
1226
1227	initlabels();
1228	if($l) {
1229		$language = $l;
1230	} else {
1231		$language = '';
1232		$language = $config{'routers.cgi-language'}
1233			if(defined $config{'routers.cgi-language'});
1234		$language = $q->cookie('lang') if(!defined $l and $q->cookie('lang'));
1235	}
1236	return if(!$language);
1237	$rv = readlang($language);
1238	$debugmessage .= "Lang=[$rv] ";
1239	return if(!defined $lang{$language});
1240	# load the per-language defaults
1241	foreach ( qw/windowtitle iconurl charset weeknumber hournumber/ ) {
1242		$config{"routers.cgi-$_"} = $lang{$language}{"global-$_"}
1243			if(defined $lang{$language}{"global-$_"});
1244	}
1245	foreach ( qw/shortdateformat longdateformat dateonlyformat/ ) {
1246		$config{"web-$_"} = $lang{$language}{"global-$_"}
1247			if(defined $lang{$language}{"global-$_"});
1248	}
1249	$config{'routers.cgi-iconurl'} .= "/"
1250		if( $config{'routers.cgi-iconurl'} !~ /\/$/ );
1251	foreach ( keys %gtypes ) {
1252		$gtypes{$_} = $lang{$language}{"types-$_"}
1253			if( defined $lang{$language}{"types-$_"} );
1254	}
1255	foreach ( keys %gstyles ) {
1256		$gstyles{$_} = $lang{$language}{"styles-$_"}
1257			if( defined $lang{$language}{"styles-$_"} );
1258	}
1259}
1260
1261#################################
1262# Special start_html
1263#
1264# Attributes are defined at 4 levels.
1265# 1. style on element.  Only used for the popup div to override everything.
1266# 2. style in page header.  Used for user colour defaults in routers2.conf
1267# 3. stylesheet. Used for most stuff, unless...
1268# 4. element attributes. Only used if no stylesheet definitions
1269sub start_html_ss
1270{
1271	my($opts,$bgopt) = @_;
1272	my($ssheet) = "";
1273	my($bodies) = "body.summary, body.generic, body.compact, body.info, body.interface, body.cpu, body.memory";
1274
1275	$opts->{-encoding} = $charset if($charset);
1276
1277	$opts->{-head} = [] if(!$opts->{-head});
1278	push @{$opts->{-head}}, $q->meta({-http_equiv => 'Content-Type',
1279		-content => "text/html; charset=$charset"}) if($charset);
1280	push @{$opts->{-head}}, $q->meta({-http_equiv=>'Refresh',-content=>$headeropts{-Refresh}}) if($headeropts{-Refresh});
1281	$opts->{-meta} = {charset=>$charset} if($charset);
1282
1283	if(!defined $opts->{'-link'}) {
1284		$opts->{'-link'}=$linkcolour;
1285		$opts->{'-vlink'}=$linkcolour;
1286		$opts->{'-alink'}=$linkcolour;
1287	}
1288	$opts->{'-text'}=$deffgcolour if(!defined $opts->{'-text'});
1289	$opts->{'-bgcolor'}=$defbgcolour if(!defined $opts->{'-bgcolor'});
1290	$opts->{'-title'}=$windowtitle if(!defined $opts->{'-title'});
1291
1292	# If we have overridden things, then put it into the sheet here.
1293	# overriding style sheet using mrtg .cfg file options
1294	if( $bgopt and $opts->{-class}) {
1295		$ssheet .= "body.".$opts->{'-class'}." { background: $bgopt }\n";
1296		$bodies = "body.compact, body.info";
1297	}
1298	# overriding style sheet using routers2.conf options
1299	# default pages
1300	if( $config{"routers.cgi-bgcolour"} or $config{"routers.cgi-fgcolour"} ) {
1301		$ssheet .= "body, $bodies { ";
1302		$ssheet .= " color: ".$config{"routers.cgi-fgcolour"}."; "
1303			if($config{"routers.cgi-fgcolour"});
1304		$ssheet .= " background: ".$config{"routers.cgi-bgcolour"}
1305			if($config{"routers.cgi-bgcolour"});
1306		$ssheet .= "}\n";
1307	}
1308	# Auth pages
1309	if( $config{"routers.cgi-authbgcolour"} or $config{"routers.cgi-authfgcolour"} ) {
1310		$ssheet .= "body.auth { ";
1311		$ssheet .= " color: ".$config{"routers.cgi-authfgcolour"}."; "
1312			if($config{"routers.cgi-authfgcolour"});
1313		$ssheet .= " background: ".$config{"routers.cgi-authbgcolour"}
1314			if($config{"routers.cgi-authbgcolour"});
1315		$ssheet .= "}\n";
1316	}
1317	# Menus
1318	if( $config{"routers.cgi-menubgcolour"} or $config{"routers.cgi-menufgcolour"} ) {
1319		$ssheet .= "body.sidemenu, body.header { ";
1320		$ssheet .= " color: ".$config{"routers.cgi-menufgcolour"}."; "
1321			if($config{"routers.cgi-menufgcolour"});
1322		$ssheet .= " background: ".$config{"routers.cgi-menubgcolour"}
1323			if($config{"routers.cgi-menubgcolour"});
1324		$ssheet .= "}\n";
1325	}
1326	# links
1327	$ssheet .=  "A:link { color: ".$config{'routers.cgi-linkcolour'}. " }\n "
1328		."A:visited { color: ".$config{'routers.cgi-linkcolour'}. " }\n "
1329		."A:hover { color: ".$config{'routers.cgi-linkcolour'}. " } \n"
1330		if($config{'routers.cgi-linkcolour'});
1331
1332	$opts->{'-style'} = [ { -code=>$ssheet } ];
1333	if ( ! defined $opts->{'-script'} ) {
1334		$opts->{'-script'} = [ ];
1335	} elsif(! ref $opts->{'-script'} ) {
1336		$opts->{'-script'} = [ $opts->{'-script'} ];
1337	}
1338 	if($config{'routers.cgi-stylesheet'}) {
1339		push @{$opts->{'-style'}}, { -src=>$config{'routers.cgi-stylesheet'} };
1340	}
1341	if( $config{'routers.cgi-extendedtime'} and $config{'routers.cgi-extendedtime'}=~/f/i ) {
1342		push @{$opts->{'-style'}}, { -src=>'/JSCal2/css/jscal2.css' };
1343#		push @{$opts->{'-style'}}, { -src=>'/JSCal2/css/border-radius.css' };
1344		push @{$opts->{'-style'}}, { -src=>'/JSCal2/css/reduce-spacing-more.css' };
1345#		push @{$opts->{'-style'}}, { -src=>'/JSCal2/css/gold/gold.css' };
1346		push @{$opts->{'-script'}},
1347			{ -type=>'text/javascript', -src=>'/JSCal2/js/jscal2.js' };
1348		push @{$opts->{'-script'}},
1349			{ -type=>'text/javascript', -src=>'/JSCal2/js/lang/en.js' };
1350		if( $language =~ /^(..)/ and ($1 ne 'en')) {
1351			push @{$opts->{'-script'}},
1352				{ -type=>'text/javascript', -src=>"/JSCal2/js/lang/${1}.js" };
1353		}
1354	}
1355
1356	print $q->start_html($opts)."\n";
1357	print "<div id=\"dpopup\" style=\"position:absolute; visibility:hidden; z-index:1000;\" class=popup></div>\n";
1358}
1359#################################
1360# Read in configuration file
1361
1362# readconf: pass it a list of section names
1363# This should really be cached, keyed on $extra$myname$authuser
1364sub readconf(@)
1365{
1366	my ($inlist, $i, @secs, $sec, $usersec);
1367
1368	@secs = @_;
1369	%config = ();
1370
1371	$usersec = "\177";
1372	if( $authuser ) {
1373		$usersec = "user-".(lc $authuser) ;
1374	} else {
1375		$usersec = "user-none";
1376	}
1377
1378	# set defaults
1379	%config = (
1380		'routers.cgi-confpath' => ".",
1381		'routers.cgi-cfgfiles' => "*.conf *.cfg",
1382		'web-png' => 0
1383	);
1384
1385	( open CFH, "<".$conffile ) || do {
1386		print $q->header({-expires=>"now"});
1387		start_html_ss({ -title => langmsg(8999,"Error"),
1388			-bgcolor => "#ffd0d0", -class => 'error'  });
1389		print $q->h1(langmsg(8999,"Error"))
1390			.$q->p(langmsg(3002,"Cannot read config file")." $conffile.");
1391		print $q->end_html();
1392		exit(0);
1393	};
1394
1395	$inlist=0;
1396	$sec = "";
1397	while( <CFH> ) {
1398		/^\s*#/ && next;
1399		/^\s*\[(.*)\]/ && do {
1400			$sec = lc $1;
1401			$inlist=0;
1402			foreach $i ( @secs ) {
1403				if ( (lc $i) eq $sec ) { $inlist=1; last; }
1404			}
1405			# override for additional sections
1406			# put it here so people cant break things easily
1407			if( !$inlist and
1408				( $sec eq "extra-$extra" or $sec eq $myname
1409				or $sec eq $usersec ) ) {
1410				$sec = 'routers.cgi'; $inlist = 1;
1411			}
1412			next;
1413		};
1414		# note final \s* to strip all trailing spaces (which works because
1415		# the *? operator is non-greedy!)  This should also take care of
1416		# stripping trailing CR if file created in DOS mode (yeuchk).
1417		if ( $inlist ) {
1418			/^\s*(\S+)\s*=\s*(\S.*?)\s*$/ and $config{"$sec-$1"}=$2;
1419		}
1420	}
1421	close CFH;
1422
1423	# legacy support for old dbdrive directive
1424	if(defined $config{'routers.cgi-dbdrive'}
1425		and $config{'routers.cgi-dbdrive'}) {
1426		$pathsep = "\\"; # and use the DOS path separator
1427		if( $config{'routers.cgi-dbpath'} !~ /^\w:/ ) {
1428			# backwards compatibility to add DB drive on, if not there already
1429			$config{'routers.cgi-dbpath'} = $config{'routers.cgi-dbdrive'}
1430				.":".$config{'routers.cgi-dbpath'};
1431		}
1432	}
1433
1434	# Activate NT compatibility options.
1435	# $^O is the OS name, NT usually produces 'MSWin32'.  By checking for 'Win'
1436	# we should be able to cover most possibilities.
1437	if ( (defined $config{'web-NT'} and $config{'web-NT'}=~/[1y]/i)
1438		or $^O =~ /Win/ or $^O =~ /DOS/i  ) {
1439		$dailylabel = "%H";   # Activeperl cant support %k option to strftime
1440		$monthlylabel = "%W"; # Activeperl cant support %V option either....
1441		$pathsep = "\\";
1442		$NT = 1;
1443	}
1444
1445	# backwards compatibility for old v1.x users
1446	$config{'routers.cgi-iconurl'} = $config{'routers.cgi-iconpath'}
1447		if( !defined $config{'routers.cgi-iconurl'}
1448			and defined $config{'routers.cgi-iconpath'} );
1449
1450	# some path corrections: remove trailing path separators on f/s paths
1451	foreach ( qw/dbpath confpath graphpath graphurl/ ) {
1452		$config{"routers.cgi-$_"} =~ s/[\/\\]$//;
1453	}
1454	# and add a trailing path separator on URL paths...
1455	$config{'routers.cgi-iconurl'} = "/rrdicons/"
1456		if(!defined $config{'routers.cgi-iconurl'} );
1457	$config{'routers.cgi-smalliconurl'} = $config{'routers.cgi-iconurl'}
1458		if( !defined  $config{'routers.cgi-smalliconurl'});
1459	$config{'routers.cgi-iconurl'} = $config{'routers.cgi-alticonurl'}
1460		if( defined  $config{'routers.cgi-alticonurl'});
1461	$config{'routers.cgi-iconurl'} .= "/"
1462		if( $config{'routers.cgi-iconurl'} !~ /\/$/ );
1463	$config{'routers.cgi-smalliconurl'} .= "/"
1464		if( defined $config{'routers.cgi-smalliconurl'}
1465			and $config{'routers.cgi-smalliconurl'} !~ /\/$/ );
1466
1467	# get list of configuration files
1468	@cfgfiles = ();
1469	if( $config{'routers.cgi-cfgfiles'} ne 'none' ) {
1470	foreach ( split " ", $config{'routers.cgi-cfgfiles'} ) {
1471		# this may push a 'undef' onto the list, if the glob doesnt match
1472		# anything.  We avoid this later...
1473		push @cfgfiles, glob($config{'routers.cgi-confpath'}.$pathsep.$_);
1474	}
1475	}
1476
1477	# fix defaultinterface, if not specified correctly
1478	if( defined $config{'routers.cgi-defaulttarget'}
1479		and ! defined $config{'routers.cgi-defaultinterface'}  ) {
1480		$config{'routers.cgi-defaultinterface'} =
1481			$config{'routers.cgi-defaulttarget'} ;
1482	}
1483	if( defined $config{'routers.cgi-defaultinterface'}
1484		and $config{'routers.cgi-defaultinterface'} !~ /^_/
1485	) {
1486		$config{'routers.cgi-defaultinterface'} =
1487			"__".$config{'routers.cgi-defaultinterface'};
1488		$config{'routers.cgi-defaultinterface'} = "_outgoing"
1489			if( $config{'routers.cgi-defaultinterface'} eq "__outgoing" );
1490		$config{'routers.cgi-defaultinterface'} = "_incoming"
1491			if( $config{'routers.cgi-defaultinterface'} eq "__incoming" );
1492		$config{'routers.cgi-defaultinterface'} = "_summary_"
1493			if( $config{'routers.cgi-defaultinterface'} eq "__summary" );
1494	}
1495
1496	# escaping
1497	if( $NT ) {
1498		$config{'routers.cgi-defaultrouter'} =~ s/\\/\//g
1499			if( defined $config{'routers.cgi-defaultrouter'} );
1500	}
1501
1502	# allow [routers.cgi] section to override [web] section for some
1503	# parameters
1504	$config{'web-backurl'} = $config{'routers.cgi-backurl'}
1505		if(defined $config{'routers.cgi-backurl'});
1506
1507	# We see if we have specified cache mode, or are in mod_perl, or
1508	# are using speedycgi or fastcgi.
1509	$CACHE = 1 if ( ( defined $config{'routers.cgi-cache'}
1510		  and $config{'routers.cgi-cache'} =~ /[y1]/i )
1511		or (!defined $config{'routers.cgi-cache'} and (
1512		  $ENV{MOD_PERL} or $ENV{FCGI_PROCESS_ID}
1513		or (eval {require CGI::SpeedyCGI} && CGI::SpeedyCGI->i_am_speedy)
1514        )));
1515
1516	unshift @INC, (split /[\s,]+/,$config{'web-libadd'})
1517		if(defined $config{'web-libadd'});
1518}
1519
1520##########################
1521sub do_footer()
1522{
1523	print "<DIV class=footer>";
1524	if($uopts !~ /s/) {
1525		print $q->hr."\n<TABLE width=100% border=0 cellpadding=0 class=footer><TR class=footer>\n";
1526		print "<TD align=left valign=top class=footer id=ftleft width=125px>"
1527			.$q->a( { href=>$APPURL, target=>"_new", class=>'footer' } ,
1528			$q->img({ src=>"${config{'routers.cgi-smalliconurl'}}routers2.gif",
1529				alt=>"Routers2.cgi web page", border=>0, width=>120, height=>40, class=>'footer' })).$q->br
1530			.$q->center($q->small($q->a({href=>$WLURL,target=>"_new",class=>'footer',style=>'@media print { display:none; }'},"Say Thanks!")))
1531			."</TD><TD valign=top align=left class=footer id=ftmiddle>";
1532		print $q->small({class=>'footer'},"routers.cgi Version $VERSION : &copy; "
1533			.$q->a({href=>$APPMAIL, class=>'footer'},"Steve Shipway")
1534			." 2000-2008 : ".$q->a({ href=>$APPURL, target=>"_top", class=>'footer' },$APPURL)
1535		)."\n";
1536		if($language) {
1537			print $q->br()."<SMALL class=footer>Language pack [$language]";
1538			print ": ".$lang{$language}{'global-description'}
1539				if($lang{$language}{'global-description'});
1540			print " Version ".$lang{$language}{'global-version'}
1541				if($lang{$language}{'global-version'});
1542			print " by ".$lang{$language}{'global-author'}
1543				if($lang{$language}{'global-author'});
1544			print "</SMALL>\n";
1545		}
1546		if(!defined $config{'web-paranoia'} or $config{'web-paranoia'}!~/[1y]/i){
1547		if( -r "/proc/loadavg" ) {
1548			open LA,"</proc/loadavg";
1549			my($lal) = <LA> ;
1550			$lal =~ /^(\S+)\s+(\S+)\s+(\S+)/ ;
1551			print $q->br()."<SMALL class=footer><I class=footer>Current system load average: $1 $2 $3</I></SMALL>\n";
1552			close LA;
1553		}
1554		print $q->br()."<SMALL class=footer>Page took ".(int(((times)[0]-$stime)*100)/100)."s to generate</SMALL>";
1555		}
1556		print "</TD><TD align=right valign=top class=footer id=ftright width=125px>"
1557			.$q->a( { href=>"http://www.rrdtool.org/", target=>"_new", class=>'footer' } ,
1558			$q->img({ src=>"${config{'routers.cgi-smalliconurl'}}rrdtool.gif",
1559				alt=>"RRDTool", border=>0, class=>'footer' })
1560		).$q->br
1561			.$q->center($q->small($q->a({href=>"http://people.ee.ethz.ch/~oetiker/wish/",target=>"_new",class=>'footer',style=>'@media print { display:none; }'},"Say Thanks!")))
1562		."</TD><TR></TABLE>\n";
1563	} # uopts
1564	if(!defined $config{'web-paranoia'} or $config{'web-paranoia'}!~/[1y]/i){
1565		print "<!-- R:[$router]\n     I:[$interface]\n     A:[$archive]\n     U:[$authuser] -->\n";
1566		print "<!--\n$debugmessage-->\n" if($debugmessage);
1567		print "<!-- Refresh: ".$headeropts{-Refresh}." -->\n";
1568		print "<!-- Expires: ".$headeropts{-expires}." -->\n";
1569		print "<!-- Language: ".langinfo()." -->\n";
1570		print "<!-- CF: ".($interfaces{$interface}{cf}?$interfaces{$interface}{cf}:"Not defined")." -->\n";
1571		print "<!-- Archive requested -->\n" if($archiveme);
1572#		print "<!-- rrdtool version ".$RRDs::VERSION." -->\n";
1573		print "<!-- rrdcached=$rrdcached -->\n" if($rrdcached);
1574#		print "<!-- \@INC\n".(join "\n",@INC)."\n-->\n";
1575		print "<!-- Processing took ".((times)[0]-$stime)."s -->\n";
1576	}
1577	print "</DIV>";
1578	print $q->end_html();
1579}
1580sub do_simple_footer() {
1581	print "<DIV class=footer>";
1582	print $q->hr({class=>'footer'})."\n";
1583	if(!defined $config{'web-paranoia'}
1584		or $config{'web-paranoia'}=~/[n0]/i) {
1585		print $q->small({class=>'footer'},"routers.cgi Version $VERSION : &copy; "
1586			.$q->a({href=>$APPMAIL,class=>'footer'},"Steve Shipway")
1587			." 2000-2008 : ".$q->a({ href=>$APPURL, target=>"_top",class=>'footer' },$APPURL)
1588		)."\n" ;
1589		print "<!-- U:[$authuser] -->\n";
1590		print "<!-- $debugmessage\n-->\n" if($debugmessage);
1591	}
1592	print "</DIV>";
1593	print $q->end_html();
1594}
1595###########################################################################
1596# for security - create login page, verify username/password/cookie
1597# routers.conf:
1598#
1599# verify_id -- reads cookies and params, returns verified username
1600sub verify_id {
1601	my($uname,$cookie,$checksum, $token);
1602
1603	$uname = $q->remote_user(); # set by web server
1604	return $uname if($uname);
1605
1606	# now taste cookie
1607	$cookie = $q->cookie('auth');
1608	return '' if(!$cookie);                         # no cookie!
1609	return '' if($cookie !~ /^\s*([^:]+):(.*)$/);   # this isnt my cookie...
1610	($uname, $checksum) = ($1,$2);
1611	$token = $uname.$q->remote_host();
1612	$token .= $CHOCOLATE_CHIP;       # secret information
1613#   Can't do this because we havent read in the config file yet
1614#	$token .= $config{'web-auth-key'} if(defined $config{'web-auth-key'});
1615	$token = unpack('%32C*',$token); # checksum
1616	if( $config{'web-auth-debug'} ) {
1617		$debugmessage .= "\ncookie[given[$uname:$checksum],test[$token]]\n";
1618	}
1619	return $uname if( $token eq $checksum ); # yummy cookie
1620
1621	# bleah, nasty taste
1622	return '';
1623}
1624# call appropriate verification routine
1625sub user_verify($$) {
1626	my($rv) = 0; # default: refuse
1627	my($u,$p) = @_;
1628
1629	# get the auth configuration info
1630	readconf( 'web' );
1631
1632	if( defined( $config{'web-ldaps-server'} ) ) {
1633		$rv = ldap_verify($u,$p,1);
1634		return $rv if($rv);
1635	}
1636	if( !$rv and defined( $config{'web-ldap-server'} ) ) {
1637		$rv = ldap_verify($u,$p,0);
1638		return $rv if($rv);
1639	}
1640	if( !$rv and defined( $config{'web-mysql-server'} ) ) {
1641		$rv = mysql_verify($u,$p);
1642		return $rv if($rv);
1643	}
1644	if( defined( $config{'web-password-file'} ) ) {
1645		$rv = file_verify($config{'web-password-file'},$u,$p,0);
1646		return $rv if($rv);
1647	}
1648	if( defined( $config{'web-htpasswd-file'} ) ) {
1649		$rv = file_verify($config{'web-htpasswd-file'},$u,$p,1);
1650		return $rv if($rv);
1651	}
1652	if( defined( $config{'web-md5-password-file'} ) ) {
1653		$rv = file_verify($config{'web-md5-password-file'},$u,$p,2);
1654		return $rv if($rv);
1655	}
1656	if( defined( $config{'web-unix-password-file'} ) ) {
1657		$rv = file_verify($config{'web-unix-password-file'},$u,$p,3);
1658		return $rv if($rv);
1659	}
1660
1661	return 0;
1662}
1663# verify against a password file:   username:password
1664sub file_verify($$$$) {
1665	my($pwfile,$u,$p,$encmode) = @_;
1666	my($fp,$salt,$cp);
1667
1668	$debugmessage .= " file_verify($pwfile,$u,$p,$encmode)\n"
1669		if( $config{'web-auth-debug'} );
1670
1671	open PW, "<$pwfile" or return 0;
1672	while( <PW> ) {
1673		if( /([^\s:]+):([^:]+)/ ) {
1674			if($1 eq $u) {
1675				$fp = $2;
1676				chomp $fp;
1677				close PW; # we are returning whatever
1678				if($encmode == 0) { # unencrypted. eek!
1679					return 1 if($p eq $fp);
1680				} elsif ($encmode == 1) { # htpasswd (unix crypt)
1681					if($crypthack) {
1682					 require Crypt::UnixCrypt;
1683					 $Crypt::UnixCrypt::OVERRIDE_BUILTIN = 1;
1684					}
1685					$salt = substr($fp,0,2);
1686					$cp = crypt($p,$salt);
1687					return 1 if($fp eq $cp);
1688				} elsif ($encmode == 2) { # md5 digest
1689					require Digest::MD5;
1690					return 1 if($fp eq Digest::MD5::md5($p));
1691				} elsif ($encmode == 3) { # unix crypt
1692					if($crypthack) {
1693					 require Crypt::UnixCrypt;
1694					 $Crypt::UnixCrypt::OVERRIDE_BUILTIN = 1;
1695					}
1696					$salt = substr($fp,0,2);
1697					$cp = crypt($p,$salt);
1698					return 1 if($fp eq $cp);
1699				} # add new ones here...
1700				if( $config{'web-auth-debug'} ) {
1701					$debugmessage .= "Mismatch password [$u][$p]:[$fp]!=[$cp]\n";
1702				}
1703				return 0;
1704			} elsif( $config{'web-auth-debug'} ) {
1705				$debugmessage .= "Mismatch user [$1][$u]\n";
1706			}
1707		} elsif( $config{'web-auth-debug'} ) {
1708			$debugmessage .= "Bad format line $_";
1709		}
1710	}
1711	close PW;
1712
1713	return 0; # not found
1714}
1715# LDAP verify a username
1716sub ldap_verify($$$) {
1717	my($u, $p, $sec) = @_;
1718	my($dn,$context,$msg);
1719	my($ldap);
1720	my($attr,@attrlist);
1721
1722	if($sec) {
1723		# load the LDAPS module
1724		eval { require IO::Socket::SSL; require Net::LDAPS; };
1725		if($@) { return 0; } # no Net::LDAPS installed
1726	} else {
1727		# load the LDAP module
1728		eval { require Net::LDAP; };
1729		if($@) { return 0; } # no Net::LDAP installed
1730	}
1731
1732	# Connect to LDAP and verify username and password
1733	if($sec) {
1734		$ldap = new Net::LDAPS($config{'web-ldaps-server'});
1735	} else {
1736		$ldap = new Net::LDAP($config{'web-ldap-server'});
1737	}
1738	if(!$ldap) { return 0; }
1739	@attrlist = ( 'uid','cn' );
1740	@attrlist = split( " ", $config{'web-ldap-attr'} )
1741		if( $config{'web-ldap-attr'} );
1742
1743	foreach $context ( split ":", $config{'web-ldap-context'}  ) {
1744		foreach $attr ( @attrlist ) {
1745			$dn = "$attr=$u,".$context;
1746			$msg = $ldap->bind($dn, password=>$p) ;
1747			if(!$msg->is_error) {
1748				$ldap->unbind();
1749				return 1;
1750			}
1751		}
1752	}
1753
1754	return 0; # not found
1755}
1756# Use mysql to verify a username
1757sub mysql_verify($$) {
1758	my($u, $p) = @_;
1759	my($dsn,$dbh,$sthini);
1760	my($db,$rv,@row);
1761	my($bu,$bp);
1762
1763	eval { require DBI; require DBD::mysql; };
1764	if($@) { $debugmessage.="MySQL Error: $@\n"; return 0; }
1765
1766	$debugmessage .= "Starting MySQL authentication for user $u\n";
1767
1768	$db = $config{'web-mysql-database'};
1769	return 0 if(!$db);
1770	$bu = $config{'web-mysql-user'};
1771	$bp = $config{'web-mysql-password'};
1772
1773	$dsn = "DBI:mysql:database=$db;host=".$config{'web-mysql-server'};
1774	$dbh = DBI->connect($dsn, ($bu?$bu:$u), ($bu?$bp:$p));
1775	if(!$dbh) { # bind failed
1776		$debugmessage .= "Failed to bind to MySQL database as "
1777			.($bu?$bu:$u)."\n";
1778		return 0;
1779	}
1780	if(!$bu) { # just doing a bind check
1781		$dbh->disconnect(); # important for mod_perl etc
1782		return 1; # all OK
1783	}
1784	if( ! $config{'web-mysql-table'} ) {
1785		$debugmessage .= "ERROR: No mysql-table name was set in the routers2.conf, although mysql-user and mysql-password were.!\n";
1786		return 0;
1787	}
1788	$sthini = $dbh->prepare("SELECT PASSWORD(?) `tpass`,`pass` FROM `"
1789		.$config{'web-mysql-table'}."` WHERE `user`=?");
1790	if(!$sthini) {
1791		$debugmessage .= "Failed to prepare MySQL statement\n";
1792		$dbh->disconnect; return 0; }
1793	$rv = $sthini->execute($p,$u);
1794	if(!$rv) {
1795		$debugmessage .= "Failed to execute MySQL statement\n";
1796		$dbh->disconnect; return 0; }
1797	@row = $sthini->fetchrow_array;
1798	$sthini->finish; $dbh->disconnect;
1799	if (!$row[0]) {
1800		$debugmessage .= "User $u was not found in table\n";
1801		return 0;
1802	}
1803	if ($row[0] eq $row[1]) { return 1; }
1804	return 0;
1805}
1806
1807# generate_cookie -- returns a cookie with current usrname, expiry
1808sub generate_cookie {
1809	my($cookie);
1810	my($exp) = "+10min"; # note this stops wk/mon/yrly autoupdate from working
1811	my($token);
1812
1813	return "" if(!$authuser);
1814
1815	$exp = $config{'web-auth-expire'} if(defined $config{'web-auth-expire'});
1816	$exp = "+10min" if(!$exp); # some checking for format
1817
1818	$token = $authuser.$q->remote_host; # should really have time here also
1819	$token .= $CHOCOLATE_CHIP;          # secret information
1820#	$token .= $config{'web-auth-key'} if(defined $config{'web-auth-key'});
1821	$token = $authuser.':'.unpack('%32C*',$token); # checksum
1822
1823	$cookie = $q->cookie( -name=>'auth', -value=>$token,
1824		-path=>$q->url(-absolute=>1), -expires=>$exp ) ;
1825
1826	return $cookie;
1827}
1828# login_page -- output HTML login form that submits to top level
1829sub login_page {
1830	# this is sent if auth = y and page = top (or blank),
1831	# or if page = login
1832	print $q->header({ -target=>'_top', -expires=>"now" })."\n";
1833	start_html_ss({ -title =>langmsg(1000,"Login Required"),
1834	-onload => "document.login.username.focus();",
1835	-expires => "now", -bgcolor=>$authbgcolour, -text=>$authfgcolour,
1836	-class => 'auth' });
1837	print $q->h1(langmsg(1000,"Authentication required"))."\n";
1838
1839	print "<FORM NAME=login METHOD=POST ACTION=$meurl TARGET=_top>\n";
1840
1841	print $q->p(langmsg(1001,"Please log in with your appropriate username and password in order to get access to the system."))."\n";
1842
1843	print "<TABLE BORDER=0 ALIGN=CENTER>\n";
1844	print $q->Tr($q->td($q->b(langmsg(1002,"Username")))
1845		.$q->td($q->textfield({name=>'username'}) ))."\n";
1846	print $q->Tr($q->td($q->b(langmsg(1003,"Password")))
1847		.$q->td($q->password_field({name=>'password'}) ))."\n";
1848	print $q->Tr($q->td("")
1849		.$q->td($q->submit({name=>'login',value=>'Login'}) ))."\n";
1850	print "</TABLE></FORM>\n";
1851	do_simple_footer;
1852	#print $q->end_html;
1853}
1854# force_login -- output HTML that sends top level to login page
1855sub force_login {
1856	my($javascript);
1857	my($err) = shift;
1858	# Javascript that sets window.location to login URL
1859	# This is created if auth = y and page != login and !authuser
1860
1861	$javascript = "function redir() { ";
1862	$javascript .= "alert('$err'); " if($err);
1863	$javascript .= " window.location = '$meurlfull?page=login'; }";
1864
1865	$javascript = "function redir() {} " if($config{'web-auth-debug'});
1866
1867	print $q->header({ -target=>'_top', -expires=>"now" })."\n";
1868	start_html_ss({ -title =>langmsg(1000,"Login Required"),
1869	-expires => "now",  -script => $javascript , -onload => "redir()",
1870	-class => 'auth'});
1871	print $q->h1({class=>'auth'},langmsg(1000,"Authentication required"))."\n";
1872	print "Please ".$q->a({href=>"$meurlfull?page=login",class=>'auth'},"login")
1873		." before continuing.\n";
1874	print "<!-- $err -->\n";
1875	do_simple_footer;
1876	#print $q->end_html;
1877}
1878# logout -- set auth cookie to blank, expire now, and redirect to top
1879sub logout_page {
1880	my($cookie,$javascript);
1881	# Javascript that sets window.location to login URL
1882
1883	$javascript = "function redir() { window.location = '$meurlfull?page=main'; }";
1884	$cookie = $q->cookie( -name=>'auth', -value=>'',
1885		-path=>$q->url(-absolute=>1), -expires=>"now" ) ;
1886
1887	print $q->header({ -target=>'_top', -expires=>"now",
1888		-cookie=>[$cookie] })."\n";
1889	start_html_ss({ -title =>langmsg(1004,"Logout complete"),
1890	-expires => "now",  -script => $javascript , -onload => "redir()",
1891		-bgcolor=>$authbgcolour, -text=>$authfgcolour, -class => 'auth' });
1892	print $q->h1({class=>'auth'},langmsg(1004,"Logged out of system"))."\n";
1893	print "Please ".$q->a({href=>"$meurlfull?page=main",class=>'auth'},"go back to the front page")
1894		." to continue.\n";
1895	do_simple_footer;
1896	#print $q->end_html;
1897}
1898
1899#################################
1900# Read in files
1901
1902###########################################################################
1903# identify the type of file/interface and set up defaults
1904sub inlist($@)
1905{
1906	my($pat) = shift @_;
1907	return 0 if(!defined $pat or !$pat or !@_);
1908	foreach (@_) { return 1 if( $_ and /$pat/i ); }
1909	return 0;
1910}
1911sub routerdefaults($)
1912{
1913	my( $key, $k, %identify );
1914
1915	$k = $_[0];
1916	%identify = ();
1917	$identify{icon} = guess_icon(1,$k, $routers{$k}{shdesc}, $routers{$k}{hostname} );
1918
1919	foreach $key ( keys %identify ) {
1920		$routers{$k}{$key} = $identify{$key} if(!$routers{$k}{$key} );
1921	}
1922}
1923# possible MODEs: interface, cpu, memory, generic (more to come)
1924sub identify($) {
1925	my( $key, %identify, $k, @d, $mode );
1926	my($unit,$totunit,$okfile);
1927	my($timel, $times);
1928
1929	$k = $_[0];
1930
1931	# description defaults
1932	if(defined $config{"targetnames-$k"}) {
1933		$interfaces{$k}{shdesc} = $config{"targetnames-$k"};
1934	}
1935	if(defined $config{"targettitles-$k"}) {
1936		$interfaces{$k}{desc} = $config{"targettitles-$k"};
1937	}
1938	if(!defined $interfaces{$k}{shdesc}) {
1939		if(!defined $config{'targetnames-ifdefault'}
1940			or $config{'targetnames-ifdefault'} !~ /target/ ) {
1941			if(defined $interfaces{$k}{ipaddress}) {
1942				$interfaces{$k}{shdesc} = $interfaces{$k}{ipaddress};
1943			} elsif(defined $interfaces{$k}{ifdesc}) {
1944				$interfaces{$k}{shdesc} = $interfaces{$k}{ifdesc};
1945			} elsif(defined $interfaces{$k}{ifno}) {
1946				$interfaces{$k}{shdesc} = "#".$interfaces{$k}{ifno};
1947			} else {
1948#				$interfaces{$k}{desc} =~ /^(\S+)/;
1949#				$interfaces{$k}{shdesc} = $1;
1950				$interfaces{$k}{shdesc} = $interfaces{$k}{desc};
1951			}
1952		}
1953		if(defined $config{'targetnames-ifdefault'}
1954			and $config{'targetnames-ifdefault'} =~ /cfgmaker/i ) {
1955			if( $interfaces{$k}{pagetop} =~ /Port Name\s*:[^<]*<\/TD>\s*<TD[^>]*>\s*([^<>\s][^<>]+)</i ) {
1956				$interfaces{$k}{shdesc} = "$1" if($1);
1957			} elsif( $interfaces{$k}{pagetop} =~ /Description\s*:[^<]*<\/TD>\s*<TD[^>]*>\s*([^\s<>][^<>]+)</i ) {
1958				$interfaces{$k}{shdesc} = "$1" if($1);
1959				$interfaces{$k}{'cfgmaker-description'} = $1;
1960			} elsif( $interfaces{$k}{pagetop} =~ /(ifName|Interface)\s*:[^<]*<\/TD>\s*<TD[^>]*>\s*([^\s<>][^<>]+)</i ) {
1961				$interfaces{$k}{shdesc} = "$2" if($2);
1962			} elsif( $interfaces{$k}{pagetop} =~ /Traffic Analysis for (\S+)/i ) {
1963				$interfaces{$k}{shdesc} = "$1" if($1);
1964			};
1965			if(!$interfaces{$k}{shdesc} and defined $interfaces{$k}{ifdesc}) {
1966				$interfaces{$k}{shdesc} = $interfaces{$k}{ifdesc};
1967			};
1968		}
1969		$interfaces{$k}{shdesc} = $k if(!defined $interfaces{$k}{shdesc});
1970	}
1971
1972	# try and identify the interface
1973	@d = ( $k, $interfaces{$k}{desc}, $interfaces{$k}{shdesc} );
1974	$mode = "";
1975	$mode = $interfaces{$k}{mode} if(defined $interfaces{$k}{mode});
1976	%identify = ();
1977	if(! $mode) {
1978		if( inlist( "cpu", @d ) and ($interfaces{$k}{maxbytes}==100) )
1979			{ $mode = "cpu"; }
1980		elsif( defined $interfaces{$k}{ifno} or defined $interfaces{$k}{ifdesc}
1981			or $interfaces{$k}{isif} or  defined $interfaces{$k}{ipaddress} )
1982			{ $mode = "interface"; $interfaces{$k}{isif} = 1; }
1983		elsif(( inlist( "interface", @d ) or inlist("serial",@d)
1984			or inlist( "ATM", @d )  or inlist( "[^mxpe]port\s", @d ))
1985				and  !defined $interfaces{$k}{unit}
1986				and  !defined $interfaces{$k}{legendi} )
1987			{ $mode = "interface"; }
1988		elsif( inlist( "mem", @d ) ) { $mode = "memory"; }
1989#		elsif( inlist( "percent", @d )) { $mode = "percent"; }
1990		else { $mode = "generic"; }
1991		$interfaces{$k}{mode} = $mode;
1992	}
1993
1994	# defaults for everything...
1995	# set appropriate defaults for thismode
1996	$times = "s"; $unit = ""; $totunit = "";
1997	if(!defined $interfaces{$k}{mult}) {
1998		if($mode eq "interface" and
1999			(!defined $config{'routers.cgi-bytes'}
2000			       or $config{'routers.cgi-bytes'} !~ /y/ )
2001			and !$interfaces{$k}{bytes}
2002		) { $interfaces{$k}{mult} = 8; $unit = "bits"; }
2003		else { $interfaces{$k}{mult} = 1; }
2004	}
2005	if(!$unit and $interfaces{$k}{bytes}) { $unit = "bytes"; }
2006	if(!$unit and $interfaces{$k}{bits}) { $unit = "bits"; }
2007	if(!$unit and ($mode eq "interface")) { $unit = "bits"; }
2008	$timel = langmsg(2400,"second");
2009	if($interfaces{$k}{mult} > 3599 ) {
2010		$timel = langmsg(2402,"hour"); $times = "hr";
2011		if($interfaces{$k}{mult} > 3600) { $unit = "bits"; }
2012	} elsif($interfaces{$k}{mult} >59 ) {
2013		$timel = langmsg(2401,"minute"); $times = "min";
2014		if($interfaces{$k}{mult} > 60) { $unit = "bits"; }
2015	} elsif($interfaces{$k}{mult} > 1) { $unit = "bits"; }
2016	$totunit = "bytes" if($unit);
2017	$identify{ylegend} = "$unit per $timel";
2018	$unit = "$unit/$times";
2019	$unit = "bps" if($unit eq "bits/s");
2020	$unit = "Bps" if($unit eq "bytes/s");
2021	$identify{background} = $defbgcolour;
2022	$identify{legendi} = langmsg(6403,"In: ");
2023	$identify{legendo} = langmsg(6404,"Out:");
2024	$identify{legend1} = langmsg(6405,"Incoming") ;
2025	$identify{legend2} = langmsg(6406,"Outgoing");
2026	$identify{legend3} = langmsg(6407,"Peak inbound");
2027	$identify{legend4} = langmsg(6408,"Peak outbound");
2028	if( defined $config{'routers.cgi-percentile'}
2029		and $config{'routers.cgi-percentile'} =~ /y/i ) {
2030		$identify{percentile} = 1;
2031		$identify{total} = 1;
2032	} else {
2033		$identify{percentile} = 0;
2034		$identify{total} = 0;
2035	}
2036	$identify{factor} = 1;
2037	$identify{percent} = 1;
2038	$identify{unit} = $unit;
2039	$identify{totunit} = $totunit;
2040	$identify{unscaled} = "";
2041
2042	if($mode eq "interface") {
2043		$identify{ylegend} = "traffic in $unit";
2044		$identify{legendi} = langmsg(6403,"In: ");
2045		$identify{legendo} = langmsg(6404,"Out:");
2046		$identify{legend1} = langmsg(6405,"Incoming traffic") ;
2047		$identify{legend2} = langmsg(6406,"Outgoing traffic");
2048		$identify{legend3} = langmsg(6407,"Peak inbound traffic");
2049		$identify{legend4} = langmsg(6408,"Peak outbound traffic");
2050		$identify{icon} = "interface-sm.gif";
2051		$identify{background} = $defbgcolour; #"#ffffff";
2052		$identify{unscaled} = "6dwmy";
2053#		$identify{total} = 1;
2054	} elsif( $mode eq "cpu" ) {
2055		$identify{ylegend} = "Percentage use";
2056		$identify{legendi} = "CPU";
2057		$identify{unit} = "%";
2058		$identify{fixunits} = 1;
2059		$identify{totunit} = "";
2060		$identify{legend1} = "CPU usage";
2061		$identify{legend3} = "Peak CPU usage";
2062		$identify{legend2} = "";
2063		$identify{legend4} = "";
2064		$identify{icon} = "cpu-sm.gif";
2065		$identify{background} = $defbgcolour; #"#ffffd0";
2066		$identify{unscaled} = "6dwmy";
2067		$identify{percent} = 0;
2068		$identify{total} = 0;
2069		$identify{mult} = 1;
2070	} elsif( $mode eq "memory" ) {
2071		$identify{ylegend} = "Bytes used";
2072		$identify{legendi} = "MEM";
2073		$identify{legendo} = "MEM";
2074		$identify{legend1} = "Memory usage";
2075		$identify{legend3} = "Peak memory usage";
2076		$identify{legend2} = "Sec. memory usage";
2077		$identify{legend4} = "Peak sec memory usage";
2078		$identify{icon} = "cpu-sm.gif";
2079		$identify{background} = $defbgcolour; #"#d0d0ff";
2080		$identify{total} = 0;
2081		$identify{unit} = "bytes";
2082		$identify{unit} = "bits" if($interfaces{$k}{bits});
2083		$identify{totunit} = "";
2084	} elsif( $mode eq "ping" ) {
2085		$identify{totunit} = "";
2086		$identify{unit} = "ms";
2087		$identify{fixunits} = 1;
2088		$identify{ylegend} = "milliseconds";
2089		$identify{legendi} = "High:";
2090		$identify{legendo} = "Low:";
2091		$identify{legend1} = "Round trip time range";
2092		$identify{legend2} = "Round trip time range";
2093		$identify{legend3} = "High peak 5min RTT";
2094		$identify{legend4} = "Low peak 5min RTT";
2095		$identify{icon} = "clock-sm.gif";
2096		$identify{background} = $defbgcolour; #"#ffffdd";
2097		$identify{total} = 0;
2098		$identify{percent} = 0;
2099		$identify{percentile} = 0;
2100		$identify{unscaled} = "";
2101	} elsif( $mode eq "percent"  ) {
2102		$identify{totunit} = "";
2103		$identify{unit} = "%";
2104		$identify{fixunits} = 1;
2105		$identify{ylegend} = langmsg(2409,"percentage");
2106		$identify{total} = 0;
2107		$identify{percent} = 0;
2108		$identify{percentile} = 0;
2109	} elsif( $mode eq "relpercent" ) {
2110		$identify{totunit} = "";
2111		$identify{unit} = "%";
2112		$identify{fixunits} = 1;
2113		$identify{ylegend} = langmsg(2409,"percentage");
2114		$identify{total} = 0;
2115		$identify{percent} = 0;
2116		$identify{percentile} = 0;
2117		$identify{legendi} = langmsg(2410,"ratio:");
2118		$identify{legend1} = langmsg(2411,"Inbound as % of outbound");
2119		$identify{legend3} = langmsg(2412,"Peak Inbound as % of peak outbound");
2120		if( defined $interfaces{$k}{ifno} or defined $interfaces{$k}{ifdesc}
2121			or $interfaces{$k}{isif} or  defined $interfaces{$k}{ipaddress} ) {
2122			$identify{icon} = "interface-sm.gif";
2123		}
2124	}
2125
2126	# unscaled default option
2127	if( defined $config{'routers.cgi-unscaled'} ) {
2128		if( $config{'routers.cgi-unscaled'} =~ /[1y]/i ) {
2129			$identify{unscaled} = "6dwmy" ;
2130		} else {
2131			$identify{unscaled} = "" ;
2132		}
2133	}
2134
2135	# set icon
2136	$identify{icon} = guess_icon( 0, $k, $interfaces{$k}{desc}, $interfaces{$k}{shdesc} ) if(!defined $identify{icon});
2137
2138	# different default for totunit
2139	# if we have a custom 'unit' but no custom 'totunit', then try to be
2140	# a bit more clever.
2141	if( defined $interfaces{$k}{unit} ) {
2142		my( $u ) = $interfaces{$k}{unit};
2143		if( $u =~ /^(.*)\// ) {
2144			$identify{totunit} = $1;
2145		} elsif( $u =~ /^(.*)ps$/ ) {
2146			$identify{totunit} = $1;
2147		} else {
2148			$identify{totunit} = $u;
2149		}
2150	}
2151
2152	# set the defaults
2153	foreach $key ( keys %identify ) {
2154		$interfaces{$k}{$key} = $identify{$key}
2155			if(!defined $interfaces{$k}{$key} );
2156	}
2157
2158	$interfaces{$k}{unit2} = $interfaces{$k}{unit}
2159		if(!defined $interfaces{$k}{unit2});
2160	$interfaces{$k}{totunit2} = $interfaces{$k}{totunit}
2161		if(!defined $interfaces{$k}{totunit2});
2162
2163	$interfaces{$k}{mult} = 1 if(!defined $interfaces{$k}{mult});
2164	$interfaces{$k}{maxbytes} = 0 if(!defined $interfaces{$k}{maxbytes});
2165	$interfaces{$k}{max} = $interfaces{$k}{maxbytes} * $interfaces{$k}{mult};
2166	$interfaces{$k}{max1} = $interfaces{$k}{maxbytes1} * $interfaces{$k}{mult}
2167		if(defined $interfaces{$k}{maxbytes1});
2168	$interfaces{$k}{max2} = $interfaces{$k}{maxbytes2} * $interfaces{$k}{mult}
2169		if(defined $interfaces{$k}{maxbytes2});
2170	# Multiply thresholds by appropriate amount
2171	foreach ( qw/threshmini threshmaxi threshmino threshmaxo upperlimit lowerlimit/ ) {
2172		$interfaces{$k}{$_} *= $interfaces{$k}{mult}
2173			if(defined $interfaces{$k}{$_});
2174	}
2175	$interfaces{$k}{max} = $interfaces{$k}{max1} if(defined $interfaces{$k}{max1} and $interfaces{$k}{max1} > $interfaces{$k}{max} );
2176	$interfaces{$k}{max} = $interfaces{$k}{max2} if(defined $interfaces{$k}{max2} and $interfaces{$k}{max2} > $interfaces{$k}{max} );
2177	$interfaces{$k}{absmax}
2178		= $interfaces{$k}{absmaxbytes} * $interfaces{$k}{mult}
2179		if(defined $interfaces{$k}{absmaxbytes});
2180	if($interfaces{$k}{factor} and $interfaces{$k}{factor}!=1 ) {
2181		foreach ( 'max','absmax','max1','max2' ) {
2182			$interfaces{$k}{$_} *= $interfaces{$k}{factor}
2183				if(defined $interfaces{$k}{$_});
2184		}
2185		foreach my $mm ( 'max','min' ) { foreach my $io ( 'i','o' ) {
2186			$interfaces{$k}{"thresh$mm$io"} *= $interfaces{$k}{factor}
2187				if(defined $interfaces{$k}{"thresh$mm$io"});
2188		}}
2189	}
2190	$interfaces{$k}{noo} = 1 if(!$interfaces{$k}{legend2});
2191	$interfaces{$k}{noi} = 1 if(!$interfaces{$k}{legend1});
2192
2193	# catch the stupid people
2194	if($interfaces{$k}{noo} and $interfaces{$k}{noi}) {
2195		$interfaces{$k}{inmenu} = 0;
2196		$interfaces{$k}{insummary} = 0;
2197		$interfaces{$k}{inout} = 0;
2198	}
2199
2200}
2201# guess an appropriate icon.  1st param is 1 for devices menu, 0 for targets
2202# other parameters are a list of attributes to check
2203sub guess_icon($@)
2204{
2205	my($m) = shift @_;
2206
2207	if($m) {
2208		# these tests for devices menu only
2209		return "cisco-sm.gif" if( inlist "cisco",@_ );
2210		return "juniper-sm.gif" if( inlist "juniper",@_ );
2211		return "3com-sm.gif" if( inlist "3com",@_ );
2212		return "intel-sm.gif" if( inlist "intel",@_ );
2213		return "router-sm.gif" if( inlist "router",@_ );
2214		return "switch-sm.gif" if( inlist "switch",@_ );
2215		return "firewall-sm.gif" if( inlist "firewall",@_ );
2216		return "ibm-sm.gif" if( inlist "ibm",@_ );
2217		return "linux-sm.gif" if( inlist "linux",@_ );
2218		return "freebsd-sm.gif" if( inlist "bsd",@_ );
2219		return "novell-sm.gif" if( inlist "novell",@_ );
2220		return "win-sm.gif" if( inlist "windows",@_ );
2221	}
2222	return "mail-sm.gif"    if( inlist 'mail|messages',@_ );
2223	return "web-sm.gif"     if( inlist 'internet',@_  or inlist 'proxy',@_ );
2224	return "phone-sm.gif"   if( inlist 'phone',@_ );
2225	return "modem-sm.gif"   if( inlist 'modem',@_ );
2226	return "disk-sm.gif"    if( inlist 'nfs\w',@_ or inlist 'dsk',@_ );
2227	return "globe-sm.gif"   if( inlist 'dns\w',@_ );
2228	return "people-sm.gif"  if( inlist 'user[s ]',@_ );
2229	return "server-sm.gif"  if( inlist 'server|host',@_ );
2230	return "web-sm.gif"     if( inlist 'web',@_ );
2231	return "traffic-sm.gif" if( inlist 'traffic',@_ );
2232	return "chip-sm.gif"    if( inlist 'memory|cpu',@_ );
2233	return "interface-sm.gif" if(!$m and  inlist 'interface|serial',@_ );
2234	return "disk-sm.gif"    if( inlist 'dis[kc]|filesystem',@_ );
2235	return "clock-sm.gif"   if( inlist 'time|rtt|ping',@_ );
2236	return "temp-sm.gif"    if( inlist 'temp|climate|environment|heat',@_ );
2237	return "menu-sm.gif"    if( inlist '\wlog',@_ );
2238	return "interface-sm.gif" if(!$m and  inlist 'BRI|eth|tok|ATM|hme',@_ );
2239	return "load-sm.gif"    if( inlist 'load|weight',@_ );
2240	return "web-sm.gif"     if( inlist 'www',@_ );
2241
2242	if($m) {
2243		# last chance with these less reliable ones
2244		return "mac-sm.gif" if( inlist "mac|apple",@_ );
2245		return "sun-sm.gif" if( inlist "sun",@_ );
2246		return "hp-sm.gif"  if( inlist "hp",@_ );
2247		return "win-sm.gif" if( inlist "win|pdc|bdc",@_ );
2248	}
2249
2250	if($m) {
2251		return $config{'targeticons-filedefault'}
2252			if(defined $config{'targeticons-filedefault'});
2253		return "menu-sm.gif";
2254	} else {
2255		return $config{'targeticons-ifdefault'}
2256			if(defined $config{'targeticons-ifdefault'});
2257		return "target-sm.gif";
2258	}
2259}
2260
2261# Parse an extension parameters
2262sub parse_ext($) {
2263	my ( $desc, $url, $icon, $targ, $level, $insec, $noop ) =
2264		("","","cog-sm.gif","graph",0,0,0 );
2265	my( @tok ) = quotewords('\s+',0,$_[0]);
2266#	$desc = shift @tok;
2267#	$url = shift @tok;
2268	foreach (@tok) {
2269		if( /^(https?:|ftp|ssh:|telnet:)?\// and !$url ) { $url = $_; next; }
2270		if( /\.(gif|png|jpg)$/ ) { $icon = $_; next; }
2271		if(!$desc) { $desc = $_ ; next; }
2272		if( /^\d+$/ ) { $level = $_; next; }
2273		if( /^insec(ure)?$/ ) { $insec = 1; next; }
2274		if( /^noopt(ion)?s?$/ ) { $noop = 1; next; }
2275		if(!$url) { $url = $_ ; next; } # must be a strange URL
2276		$targ = $_; # Must be a target frame name
2277	}
2278	$desc = "Extension" if(!$desc);
2279	$url  = "/" if(!$url);
2280	return ($desc, $url, $icon, $targ, $level, $insec, $noop);
2281}
2282sub parse_link($) {
2283	my ( $desc, $targfile, $icon, $targ, $level ) =
2284		("Link",$router,"link-general-sm.gif","_summary",0 );
2285	my( @tok ) = quotewords('\s+',0,$_[0]);
2286	$desc = shift @tok;
2287	$targfile = shift @tok;
2288	foreach (@tok) {
2289		if( /^\d+$/ ) { $level = $_; next; }
2290		if( /\.(gif|png|jpg)$/ ) { $icon = $_; next; }
2291		$targ = $_; # Must be a target frame name
2292	}
2293	return ($desc, $targfile, $icon, $targ, $level);
2294}
2295
2296# read in all routers files.
2297
2298# routers hash: key= filename (within confpath)
2299#         data: hash:
2300#               keys: filename (full), shdesc, desc, inmenu, hasinout
2301#                     group, icon
2302
2303sub read_routers()
2304{
2305	my( $matchstr, $curfile, $curpat, $key, $bn, $group, $f );
2306	my( $arg, $desc, $url, $icon, $targ, $insec, $level, $noop, $targfile );
2307	my( $rckey );
2308	my( $optimise ) = 0;
2309
2310	if($CACHE and (-M $config{'routers.cgi-confpath'} >= 0)) {
2311	# cache key: people may have different cfg file sets!
2312		$rckey = $config{'routers.cgi-confpath'}
2313			.'/'.$config{'routers.cgi-cfgfiles'};
2314
2315		if(defined $routerscache{$rckey}) {
2316			%routers = %{$routerscache{$rckey}};
2317			if($router and defined $routers{$router} and
2318				# file has disappeared!
2319				! -f $routers{$router}{file} ) {
2320				$debugmessage .= "refresh(routers)";
2321				%routers = ();
2322				%routerscache = ();
2323			} elsif((-M $routers{$router}{file}) < 0 ) {
2324				# config files have changed!
2325				$^T = time; # set 'script init time' to first read of cfg files
2326				%ifstore = ();      # clean out all cached info
2327				%routerscache = (); # clean out all cached info
2328				$debugmessage .= "refresh(routers)\n";
2329				$readinrouters = 0;
2330				%cachedays = ();
2331			} else {
2332				$debugmessage .= "fromcache(routers)\n";
2333				$readinrouters = 1;
2334				return;
2335			}
2336		} else {
2337			load_cache();
2338			if(defined $routerscache{$rckey}
2339				and -f $routerscache{$rckey}{$router}{file}) {
2340				%routers = %{$routerscache{$rckey}};
2341				$debugmessage .= "fromdiskcache(routers)\n";
2342				$readinrouters = 1;
2343				return;
2344			} else {
2345				$debugmessage .= "Disk cache out of date.  Re-reading.\n";
2346			}
2347		}
2348	}
2349
2350	$optimise = 1 if( defined $config{'routers.cgi-optimise'}
2351		and $config{'routers.cgi-optimise'} =~ /[y1]/i );
2352
2353	%routers = ();
2354	if(-M $config{'routers.cgi-confpath'} < 0) {
2355		# config files have changed!
2356		$^T = time; # set 'script init time' to first read of cfg files
2357		%ifstore = ();      # clean out all cached info
2358		%routerscache = (); # clean out all cached info
2359			%cachedays = ();
2360		$debugmessage .= "refresh(routers)\n";
2361		$readinrouters = 0;
2362	}
2363
2364FILE: for $curfile ( @cfgfiles ) {
2365			next if(! -f $curfile or ! -r $curfile);
2366			$key = $curfile;
2367			$matchstr = $config{'routers.cgi-confpath'}.$pathsep;
2368			$matchstr =~ s/\\/\\\\/g;
2369			$key =~ s/^$matchstr//;
2370			$f = $bn = basename($curfile,'');
2371			$f =~ s/\.c(fg|onf)$//;
2372			$group = dirname($curfile);
2373			# set the defaults
2374			$routers{$key} = {
2375				file=>$curfile, inmenu=>1, group=>$group, icon=>"",
2376				interval=>5, hastarget=>0
2377			};
2378
2379			# read the file for any overrides
2380			open CFG,"<$curfile" || do {
2381#				$routers{$key}{inmenu}=0;
2382				$routers{$key}{desc}="Error opening file";
2383				$routers{$key}{icon}="alert-sm.gif";
2384				next;
2385			};
2386LINE:		while( <CFG> ) {
2387				/^#\s+System:\s+(.*)/ and do {
2388					$desc = $1;
2389					$routers{$key}{'cfgmaker-system'} = $desc;
2390					$routers{$key}{desc} = $desc
2391					if( $desc and defined $config{'targetnames-routerdefault'}
2392					and $config{'targetnames-routerdefault'} =~ /cfgmaker/i );
2393					next;
2394				};
2395				/^#\s+(Description|Contact|Location):\s+(.*)/ and do {
2396					($arg,$desc)=($1,$2);
2397					$routers{$key}{('cfgmaker-'.(lc $arg))} = $desc;
2398					next;
2399				};
2400				/^\s*#/ && next; # Optimise!
2401				if( /^\s*(routers2?\.cgi\*)?Target\[\S+\]\s*:.*:([^\s@]+)@([^:\s]+)/i ) {
2402					$routers{$key}{community}=$2 if(!$routers{$key}{community});
2403					$routers{$key}{hostname}=$3 if(!$routers{$key}{hostname});
2404					$routers{$key}{hastarget}=1;
2405					next;
2406				}
2407				if( /^\s*(routers2?\.cgi\*)?Target\[\S+\]/i ) {
2408					$routers{$key}{hastarget}=1;
2409					next;
2410				}
2411				if( /^\s*(routers2?\.cgi\*)?Include\s*:/i ) {
2412					$routers{$key}{hastarget}=1; # make the assumption
2413					next;
2414				}
2415				if( /^\s*Title\[\S+\]\s*:\s*(.*)/i ) {
2416					$routers{$key}{firsttitle}=$1;
2417					$routers{$key}{hastarget}=1;
2418					last if($optimise);
2419					next;
2420				}
2421				if( /^\s*WorkDir\s*:\s*(.*)/i ) {
2422					$routers{$key}{workdir}=$1;
2423					next;
2424				}
2425				if( /^\s*Interval\s*:\s*([\d\.]+):?(\d*)/i ) {
2426					$routers{$key}{interval}=$1;
2427					$routers{$key}{interval} += $2/60 if($2);
2428					next;
2429				}
2430				next unless( /^\s*routers2?\.cgi\*/i ); # Optimise!
2431				if( /^\s*routers2?\.cgi\*Options\s*:\s*(.*)/i ) {
2432					$routers{$key}{inmenu} = 0 if($1 =~ /ignore/i );
2433					next;
2434				}
2435				if( /^\s*routers2?\.cgi\*(Descr?|Name|Description)\s*:\s*(.*)/i ) {
2436					$routers{$key}{desc} = $2;
2437					next;
2438				}
2439				if( /^\s*routers2?\.cgi\*Short(Descr?|Name|Description)\s*:\s*(.*)/i ) {
2440					$routers{$key}{shdesc} = $2;
2441					next;
2442				}
2443				if( /^\s*routers2?\.cgi\*Icon\s*:\s*(.*)/i ) {
2444					$routers{$key}{icon}=$1;
2445					next;
2446				}
2447				if( /^\s*routers2?\.cgi\*Ignore\s*:\s*(\S+)/i ) {
2448					$arg = $1;
2449					if($arg =~ /y/i) {
2450						delete $routers{$key};
2451						close CFG;
2452						next FILE;
2453					}
2454					next;
2455				}
2456				if( /^\s*routers2?\.cgi\*InMenu\s*:\s*(\S+)/i ) {
2457					$arg = $1;
2458					$routers{$key}{inmenu}=0 if($arg =~ /n/i);
2459					next;
2460				}
2461				if( /^\s*routers2?\.cgi\*RoutingTable\s*:\s*(\S+)/i ) {
2462					$arg = $1;
2463					$routers{$key}{routingtable}="n" if($arg =~ /[0n]/i);
2464					$routers{$key}{routingtable}="y" if($arg =~ /[1y]/i);
2465					next;
2466				}
2467				if( /^\s*routers2?\.cgi\*ClearExtensions?\s*:\s*(\S.*)/i ) {
2468					$arg = $1;
2469					$routers{$key}{extensions} = [] if($arg =~ /[y1]/i);
2470					next;
2471				}
2472				if( /^\s*routers2?\.cgi\*Extensions?\s*:\s*(\S.*)/i ) {
2473					$arg = $1;
2474					( $desc, $url, $icon, $targ, $level, $insec, $noop ) =
2475						parse_ext($arg);
2476
2477					next if(!$url or !$desc);
2478					$routers{$key}{extensions} = []
2479						if(!defined $routers{$key}{extensions});
2480					my( $lasthostname,$lastcommunity ) = ( '','' );
2481					$lasthostname = $routers{$key}{hostname}
2482						if( defined $routers{$key}{hostname} );
2483					$lastcommunity= $routers{$key}{community}
2484						if( defined $routers{$key}{community} );
2485					push @{$routers{$key}{extensions}},
2486						{desc=>$desc, url=>$url, icon=>$icon, target=>$targ,
2487				hostname=>$lasthostname, community=>$lastcommunity,
2488						insecure=>$insec, level=>$level, noopts=>$noop };
2489					next;
2490				}
2491				if( /^\s*routers2?\.cgi\*Link\s*:\s*(\S.*)/i ) {
2492					$arg = $1;
2493					( $desc, $targfile, $icon, $targ, $level )
2494						= parse_link($arg);
2495					next if(!$targfile or !$desc);
2496					$icon = "link-general-sm.gif" if(!$icon);
2497					$url = $meurlfull."?rtr=".$q->escape($targfile)
2498						."&if=".$q->escape($targ)."&page=graph&xmtype=options";
2499					$routers{$key}{extensions} = []
2500						if(!defined $routers{$key}{extensions});
2501					push @{$routers{$key}{extensions}},
2502						{ desc=>$desc, url=>$url, icon=>$icon, target=>"graph",
2503							level=>$level, insecure=>0, noopts=>2 };
2504					next;
2505				}
2506				if( /^\s*routers2?\.cgi\*Redirect\s*:\s*(\S+)/i ) {
2507					$arg = $1;
2508					$routers{$key}{redirect} = $arg;
2509					$routers{$key}{inmenu} = 1;
2510					$routers{$key}{hastarget} = 1;
2511					next;
2512				}
2513				if( /^\s*routers2?\.cgi\*NoCache\s*:\s*(\S+)/i ) {
2514					$arg = $1;
2515					if($arg=~/[y1]/i) { $routers{$key}{nocache} = 1; }
2516					else { $routers{$key}{nocache} = 0; }
2517					next;
2518				}
2519				if( /^\s*routers2?\.cgi\*Summary\s*:\s*(.*)/i ) {
2520					$arg = $1;
2521					$routers{$key}{summaryoptions} = $arg;
2522					if($arg=~/active/i) { $routers{$key}{activesummary} = 1; }
2523#					if($arg=~/2/) { $routers{$key}{activesummary} = 1; }
2524					next;
2525				}
2526				if( /^\s*routers2?\.cgi\*InOut\s*:\s*(\S+)/i ) {
2527					$arg = $1;
2528					if($arg=~/[a2]/i) { $routers{$key}{activeinout} = 1; }
2529					$routers{$key}{inoutoptions} = $1;
2530					next;
2531				}
2532				if( /^\s*routers2?\.cgi\*(Set)?Symbol\s*:\s*(\S+)\s+(.*)/i ) {
2533					($arg,$desc)=($2,$3);
2534					$desc =~ s/^['"]//; $desc =~ s/['"]$//; # allow quotes
2535					$routers{$key}{symbols}{$arg}=$desc;
2536					next;
2537				}
2538				if( /^\s*routers2?\.cgi\*(Snmp)?Community\s*:\s*(\S+)/i ) {
2539					$routers{$key}{community} = $2;
2540					next;
2541				}
2542				if( /^\s*(routers2?\.cgi\*)?RRDCached\s*:\s*(\S+)/i ) {
2543					$routers{$key}{rrdcached} = $2;
2544					next;
2545				}
2546			}
2547			close CFG;
2548
2549			# desc default
2550			if(!$routers{$key}{shdesc}) {
2551				if($config{'targetnames-routerdefault'} =~ /hostname/ ) {
2552					if(defined $routers{$key}{hostname} ) {
2553						$routers{$key}{shdesc} = $routers{$key}{hostname};
2554					} else {
2555						$routers{$key}{shdesc} = $f;
2556					}
2557				} elsif($config{'targetnames-routerdefault'} =~ /ai/
2558					and defined $routers{$key}{firsttitle} ) {
2559					$routers{$key}{firsttitle} =~ /([^\s:\(]+)/;
2560					$routers{$key}{shdesc} = $1;
2561					$routers{$key}{desc} = $routers{$key}{firsttitle};
2562				} else {
2563					$routers{$key}{shdesc} = $f;
2564#					$routers{$key}{desc} = $curfile if(!$routers{$key}{desc});
2565				}
2566			}
2567			$routers{$key}{desc} = $routers{$key}{shdesc}
2568				if(!$routers{$key}{desc});
2569
2570			# check routers.conf for any overrides
2571			if(defined $config{"targetnames-$bn"}) {
2572				$routers{$key}{shdesc} = $config{"targetnames-$bn"};
2573				$routers{$key}{desc} = $config{"targetnames-$bn"};
2574			}
2575			$routers{$key}{desc} = $config{"targettitles-$bn"}
2576				if(defined $config{"targettitles-$bn"});
2577			$routers{$key}{icon} = $config{"targeticons-$bn"}
2578				if(defined $config{"targeticons-$bn"});
2579
2580			routerdefaults $key;
2581#		} # files
2582#	} # patterns
2583	} # files
2584
2585	foreach $key ( keys %routers ) {
2586		$routers{$key}{inmenu} = 0 if(!$routers{$key}{hastarget});
2587	}
2588
2589	if( $config{'routers.cgi-servers'} =~ /[yY1]/ ) {
2590		foreach ( keys %config ) {
2591			if( /^servers-(\S+)/i ) {
2592				$routers{"#SERVER#$1"} = {
2593					file=>"", inmenu=>1, group=>"SERVERS",
2594					icon=>"server-sm.gif", server=>$1, interval=>5,
2595					hastarget=>1, inmenu=>1, desc=>$config{$_},
2596					shdesc=>$config{$_}
2597				};
2598				$routers{"#SERVER#$1"}{icon} = $config{"targeticons-$1"}
2599					if(defined $config{"targeticons-$1"});
2600			}
2601		}
2602	}
2603
2604	# we need to copy the hash, not a hashref, since %routers will be
2605	# re-used in future invocations
2606	if($CACHE) {
2607		$routerscache{$rckey} = { %routers };
2608		$debugmessage .= "cached[routers] \n";
2609		write_cache;
2610	} else {
2611		$debugmessage .= "NOCACHE[routers] \n";
2612	}
2613	$readinrouters = 1 ; # for people without caching
2614}
2615
2616###########################################################################
2617
2618# set pseudointerfaces for a server target
2619sub set_svr_ifs()
2620{
2621	my( $server );
2622
2623	%interfaces = ();
2624	$server = $router;
2625	$server =~ s/^#SERVER#//;
2626
2627	$interfaces{"CPU"} = { file=>"",  icon=>"chip-sm.gif",
2628		rrd=>($config{'routers.cgi-dbpath'}.$pathsep."$server.rrd"),
2629		shdesc=>"CPU Usage", mult=>1, unit=>"%", fixunits=>1,
2630		legendi=>"User:", legendo=>"System:", ylegend=>"Percentage",
2631		legendx=>"Wait:",
2632		legend1=>"User processes", legend2=>"System Processes",
2633		legend3=>"Max User Processes", legend4=>"Max System processes",
2634		legend5=>"System Wait", legend6=>"Max system wait",
2635		desc=>"CPU Usage on $server", mode=>"SERVER", hostname=>$server,
2636		insummary=>1, incompact=>0, inmenu=>1, isif=>0, inout=>0,
2637		interval=>5, nomax=>1, noabsmax=>1, maxbytes=>100, max=>100,
2638		available=>1  };
2639	$interfaces{"Users"} = { file=>"",   mult=>1,icon=>"people-sm.gif",
2640		rrd=>($config{'routers.cgi-dbpath'}.$pathsep."$server.rrd"),
2641		shdesc=>"Users", noo=>1, integer=>1, percent=>0, fixunits=>1,
2642		ylegend=>"User count",
2643		legendi=>"Users:", legend1=>"User count", legend3=>"Max user count",
2644		desc=>"User count on $server", mode=>"SERVER", hostname=>$server,
2645		insummary=>1, incompact=>0, inmenu=>1, isif=>0, inout=>0,
2646		interval=>5, nomax=>1, noabsmax=>1, maxbytes=>10000,
2647		available=>1  };
2648	$interfaces{"Page"} = { file=>"",   mult=>1, icon=>"disk-sm.gif",
2649		rrd=>($config{'routers.cgi-dbpath'}.$pathsep."$server.rrd"),
2650		shdesc=>"Paging", noo=>1, unit=>"pps", fixunits=>1,
2651		legendi=>"Activity:", legend1=>"Paging activity",
2652		legend3=>"Max paging activity", percent=>0, ylegend=>"Pages per second",
2653		desc=>"Paging activity on $server", mode=>"SERVER", hostname=>$server,
2654		insummary=>1, incompact=>0, inmenu=>1, isif=>0, inout=>0,
2655		interval=>5, nomax=>1, noabsmax=>1, maxbytes=>10000,
2656		available=>1  };
2657}
2658
2659###########################################################################
2660# read in a specified cfg file (default to current router file)
2661
2662# interfaces hash: key= targetname
2663#            data: hash:
2664#            keys: lots.
2665
2666sub read_cfg_file($$)
2667{
2668	my($cfgfile,$makespecial) = @_;
2669	my($opts, $graph, $key, $k, $fd, $buf, $curif, @myifs, $arg, $argb, $rrd);
2670	my($argc);
2671	my($ifcnt, @ifarr, $t, $desc, $url, $icon, $targ, $newfile, $targfile);
2672	my( $lasthostname, $lastcommunity ) = ("","");
2673	my($level, $insec, $noop, $logdir);
2674
2675	my( $inpagetop, $inpagefoot ) = (0,0);
2676
2677	return if(!$cfgfile);
2678
2679	$debugmessage .= "$cfgfile ";
2680
2681	$fd = new FileHandle ;
2682
2683	if(! $fd->open( "<$cfgfile" )) {
2684		$interfaces{$cfgfile} = {
2685			shdesc=>"Error", desc=>"Cannot open file $cfgfile", inmenu=>0,
2686			rrd=>"", insummary=>0, inout=>0, incompact=>0, mode=>"ERROR",
2687			icon=>"alert-sm.gif" };
2688		return;
2689	}
2690
2691	$key = ""; $curif = ""; @myifs = ();
2692	while ( $buf = <$fd> ) {
2693		next if( $buf =~ /^\s*#/ );
2694		next if( $buf =~ /^\s*$/ ); # bit more efficient
2695		# solve problem of DOS cfg file under UNIX causing Pango layout issues
2696		$buf =~ s/\s+$//;
2697		if( $inpagefoot ) {
2698			if( $curif and $buf =~ /^\s+\S/ ) {
2699				$interfaces{$curif}{pagefoot} .= $buf;
2700				next;
2701			}
2702			$inpagefoot = 0;
2703		}
2704		if( $inpagetop ) {
2705			if( $curif and $buf =~ /^\s+\S/ ) {
2706				$interfaces{$curif}{pagetop} .= $buf;
2707				next;
2708			}
2709			$inpagetop = 0;
2710		}
2711		if( $buf =~ /^\s*(routers2?\.cgi\*)?Target\[(.+?)\]\s*:\s*(.+)/i ) {
2712			$curif = $2; $arg = $3;
2713			push @myifs, $curif;
2714			# This ***MIGHT*** save people who put their .cfg files
2715			# out of sequence?
2716			if(!defined $interfaces{$curif}) {
2717			$interfaces{$curif} = { file=>$cfgfile, target=>$curif,
2718					insummary=>1, incompact=>1, inmenu=>1, isif=>0,
2719					interval=>$interval, nomax=>0, noabsmax=>0  };
2720			} else {
2721			$interfaces{$curif} = { file=>$cfgfile, target=>$curif,
2722					insummary=>1, incompact=>1, inmenu=>1, isif=>0,
2723					interval=>$interval, nomax=>0, noabsmax=>0,
2724					%{$interfaces{$curif}}  };
2725			}
2726			if(defined $interfaces{_}{directory}) {
2727				$interfaces{$curif}{rrd} =
2728					$workdir.$pathsep.$interfaces{_}{directory}
2729					.$pathsep.(lc $curif).".rrd";
2730			} else {
2731				$interfaces{$curif}{rrd} = $workdir.$pathsep.(lc $curif).".rrd";
2732			}
2733			if( $arg =~ /^-?(\d+):([^\@:\s]+)\@([\w\-\.]+)/ ) {
2734				# interface number
2735				$interfaces{$curif}{isif} = 1;
2736				$interfaces{$curif}{ifno} = $1;
2737				$interfaces{$curif}{community} = $2;
2738				$interfaces{$curif}{hostname} = $3;
2739				$interfaces{$curif}{mode} = "interface";
2740			} elsif( $arg =~ /^-?\/(\d+\.\d+\.\d+\.\d+):([^\@:\s]+)\@([\w\-\.]+)/ ) {
2741				# IP address
2742				$interfaces{$curif}{isif} = 1;
2743				$interfaces{$curif}{ipaddress} = $1;
2744				$interfaces{$curif}{community} = $2;
2745				$interfaces{$curif}{hostname} = $3;
2746				$interfaces{$curif}{mode} = "interface";
2747			} elsif( $arg =~ /^-?[\\#!](\S.*?):([^\@:\s]+)\@([\w\-\.]+)/ ) {
2748				$interfaces{$curif}{isif} = 1;
2749				$interfaces{$curif}{ifdesc} = $1;
2750				$interfaces{$curif}{community} = $2;
2751				$interfaces{$curif}{hostname} = $3;
2752				$interfaces{$curif}{mode} = "interface";
2753				$interfaces{$curif}{ifdesc} =~ s/\\(.)/$1/g ;
2754			} elsif( $arg =~ /&\w*[\d\.]+:(\S+)\@([\w\-\.]+)/ ) {
2755				# explicit OIDs
2756				$interfaces{$curif}{community} = $1;
2757				$interfaces{$curif}{hostname} = $2;
2758			} elsif( $arg =~ /mrtg.ping.probe/ ) {
2759				# special for the mrtg-ping-probe.pl
2760				$interfaces{$curif}{mode} = "ping";
2761				$interfaces{$curif}{graphstyle} = "range";
2762				$interfaces{$curif}{incompact} = 1;
2763				$interfaces{$curif}{ifdesc} = langmsg(2413,"Response time") ;
2764			} elsif( $arg =~ /`/ ) {
2765				# external program
2766				$interfaces{$curif}{insummary} = 1;
2767				$interfaces{$curif}{incompact} = 1;
2768			} else { # a target of some sort we dont yet know
2769				$interfaces{$curif}{insummary} = 0;
2770				$interfaces{$curif}{incompact} = 0;
2771			}
2772			$interfaces{$curif}{inout} = $interfaces{$curif}{isif};
2773			foreach $k ( qw/isif inout incompact insummary inmenu/ ) {
2774				$interfaces{$curif}{$k} = $interfaces{'_'}{$k}
2775					if(defined $interfaces{'_'}{$k});
2776			}
2777			$lasthostname = $interfaces{$curif}{hostname}
2778				if(defined $interfaces{$curif}{hostname});
2779			$lastcommunity= $interfaces{$curif}{community}
2780				if(defined $interfaces{$curif}{community});
2781			next;
2782		}
2783		if( $buf =~ /^\s*(routers2?\.cgi\*)?(Title|Descr?|Description)\[(.+?)\]\s*:\s*(\S.*)/i ) {
2784			$curif = $3; $arg = $4;
2785			if(!defined $interfaces{$curif}) {
2786				if(defined $interfaces{"_$curif"}) {
2787					$curif = "_$curif";
2788				} else {
2789					$interfaces{$curif} = {note=>"Out of sequence"};
2790				}
2791			}
2792			$interfaces{$curif}{desc} = $arg;
2793			next;
2794		}
2795		if( $buf =~ /^\s*Options\[(.+?)\]\s*:\s*(\S.*)/i ) {
2796			$curif = $1;
2797			$curif = "_$curif" if(!defined $interfaces{$curif});
2798			next if(!defined $interfaces{$curif});
2799			$interfaces{$curif}{options} = "" if(!$interfaces{$curif}{options});
2800			$interfaces{$curif}{options} .= ' '.$2;
2801			next;
2802		}
2803		if( $buf =~ /^\s*(routers2?\.cgi\*)?PageTop\[(.+?)\]\s*:\s*(\S.*)/i ) {
2804			$curif = $2;  $arg = $3;
2805			$curif = "_$curif" if(!defined $interfaces{$curif});
2806			next if(!defined $interfaces{$curif});
2807			$interfaces{$curif}{pagetop} = $arg;
2808			$inpagetop = 1;
2809			next;
2810		}
2811		if( $buf =~ /^\s*(routers2?\.cgi\*)?PageFoot\[(.+?)\]\s*:\s*(\S.*)/i ) {
2812			$curif = $2;  $arg = $3;
2813			$curif = "_$curif" if(!defined $interfaces{$curif});
2814			next if(!defined $interfaces{$curif});
2815			$interfaces{$curif}{pagefoot} = $arg;
2816			$inpagefoot = 1;
2817			next;
2818		}
2819		if( $buf =~ /^\s*(routers2?\.cgi\*)?SetEnv\[(.+?)\]\s*:\s*(\S.*)/i ) {
2820			$curif = $2; $arg = $3;
2821			next if(!defined $interfaces{$curif});
2822			foreach $k ( quotewords('\s+',0,$arg) ) {
2823				if( $k =~ /MRTG_INT_IP=\s*["]?\s*(\d+\.\d+\.\d+\.\d+)/ ) {
2824					$interfaces{$curif}{ipaddress}=$1
2825					if(!defined $interfaces{$curif}{ipaddress});
2826					next;
2827				}
2828				if( $k =~ /MRTG_INT_DESCR?=\s*["]?\s*(\S[^"]*)/ ) {
2829					$interfaces{$curif}{shdesc}=$1
2830					if(!defined $interfaces{$curif}{shdesc});
2831					next;
2832				}
2833			}
2834			next;
2835		}
2836		if( $buf =~ /^\s*routers2?\.cgi\*Short(Name|Descr?|Description)\[(.+?)\]\s*:\s*(\S.*)/i ) {
2837			$curif = $2; $arg = $3;
2838			$curif = "_$curif" if(!defined $interfaces{$curif});
2839			next if(!defined $interfaces{$curif});
2840			$interfaces{$curif}{shdesc} = $arg if($arg);
2841			next;
2842		}
2843		if( $buf =~ /^\s*routers2?\.cgi\*Options\[(.+?)\]\s*:\s*(\S.*)/i ) {
2844			$curif = $1; $arg = $2;
2845			$curif = "_$curif" if(!defined $interfaces{$curif});
2846			next if(!defined $interfaces{$curif});
2847			$interfaces{$curif}{cgioptions}=""
2848				if(!$interfaces{$curif}{cgioptions});
2849			$interfaces{$curif}{cgioptions} .= " ".$arg;
2850			next;
2851		}
2852		if( $buf =~ /^\s*(routers2?\.cgi\*)?MaxBytes\[(.+?)\]\s*:\s*(\d+[\.,]?\d*)/i ) {
2853			next if(!defined $interfaces{$2});
2854			$interfaces{$2}{maxbytes} = $3;
2855			next;
2856		}
2857		if($buf=~ /^\s*(routers2?\.cgi\*)?Unscaled\[(.+?)\]\s*:\s*([6dwmyn]*)/i){
2858			$curif = $2; $arg = $3;
2859			next if(!defined $interfaces{$curif});
2860			$arg = "" if($arg =~ /n/i); # for 'none' or 'n' option
2861			$interfaces{$curif}{unscaled} = $arg;
2862			next;
2863		}
2864		if($buf=~ /^\s*(routers2?\.cgi\*)?WithPeaks?\[(.+?)\]\s*:\s*([dwmyn]*)/i) {
2865			next if(!defined $interfaces{$2});
2866			$interfaces{$2}{withpeak} = $3;
2867			next;
2868		}
2869		if( $buf =~ /^\s*(routers2?\.cgi\*)?(YLegend2?)\[(.+?)\]\s*:\s*(\S.*)/i ) {
2870			$curif = $3; $arg = $4; $key = lc $2;
2871			$curif = "_$curif" if(!defined $interfaces{$curif});
2872			next if(!defined $interfaces{$curif});
2873			$interfaces{$curif}{$key} = $arg;
2874			next;
2875		}
2876		if( $buf =~ /^\s*routers2?\.cgi\*ScaleShift\[(.+?)\]\s*:\s*(\S+)/i ) {
2877			$curif = $1; $arg = $2;
2878			$curif = "_$curif" if(!defined $interfaces{$curif});
2879			next if(!defined $interfaces{$curif});
2880			$interfaces{$curif}{scaleshift} = $arg;
2881			if($arg=~/(-?\d+\.?\d*)(:(-?\d+\.?\d*))?/) {
2882				$interfaces{$curif}{scale} = ($1?$1:1);
2883				$interfaces{$curif}{shift} = ($3?$3:0);
2884			}
2885			next;
2886		}
2887		if($buf=~ /^\s*(routers2?\.cgi\*)?ShortLegend(2?)\[(.+?)\]\s*:\s*(.*)/i){
2888			next if(!defined $interfaces{$3});
2889			$interfaces{$3}{"unit$2"} = $4;
2890			$interfaces{$3}{"unit$2"} =~ s/&nbsp;/ /g;
2891			next;
2892		}
2893		if($buf =~ /^\s*routers2?\.cgi\*TotalLegend(2?)\[(.+?)\]\s*:\s*(.*)/i){
2894			$curif = $2; $arg = $3; $key = "totunit$1";
2895			next if(!defined $interfaces{$curif});
2896			$arg =~ s/&nbsp;/ /g;
2897			$interfaces{$curif}{$key} = $arg;
2898			next;
2899		}
2900		# We now allow any number of digits for future expansion
2901		if( $buf =~ /^\s*(routers2?\.cgi\*)?(Legend[IOTA\d]\d*[IOTA]?)\[(.+?)\]\s*:\s*(\S.*)/i ) {
2902			$curif = $3; $key = lc $2; $arg = $4;
2903			$curif = "_$curif" if(!defined $interfaces{$curif});
2904			next if(!defined $interfaces{$curif});
2905			$arg =~ s/&nbsp;/ /;
2906			# for backwards compatibility. 1T used to be TI, etc
2907			# IT and OT are the new total versions of I and O for userdefineds
2908			$key = "legendti" if($key eq "legend1t");
2909			$key = "legendto" if($key eq "legend2t");
2910			$key = "legendai" if($key eq "legend1a");
2911			$key = "legendao" if($key eq "legend2a");
2912			$interfaces{$curif}{$key} = $arg;
2913			next;
2914		}
2915		if( $buf =~ /^\s*routers2?\.cgi\*Mode\[(.+?)\]\s*:\s*(\S+)/i ) {
2916			next if(!defined $interfaces{$1});
2917			$interfaces{$1}{mode} = $2;
2918			next;
2919		}
2920		if( $buf =~ /^\s*routers2?\.cgi\*RoutingTable\s*:\s*(\S.*)/i ) {
2921			$arg = $1;
2922			$routers{$router}{routingtable} = "y" if($arg =~ /y/i);
2923			$routers{$router}{routingtable} = "n" if($arg =~ /n/i);
2924			next;
2925		}
2926		if( $buf =~ /^\s*routers2?\.cgi\*ClearExtensions?\s*:\s*(\S.*)/i
2927			) {
2928#			and !$readinrouters) {
2929			$arg = $1;
2930			$routers{$router}{extensions} = [] if($arg =~ /[y1]/i);
2931			next;
2932		}
2933		if( # !$readinrouters and
2934			$buf =~ /^\s*routers2?\.cgi\*Extensions?\s*:\s*(\S.*)/i ) {
2935			$arg = $1;
2936			( $desc, $url, $icon, $targ, $level, $insec, $noop )
2937				= parse_ext($arg);
2938			next if(!$url or !$desc);
2939			$routers{$router}{extensions} = []
2940				if(!defined $routers{$router}{extensions});
2941			push @{$routers{$router}{extensions}},
2942				{desc=>$desc, url=>$url, icon=>$icon, target=>$targ,
2943				hostname=>$lasthostname, community=>$lastcommunity,
2944				insecure=>$insec, level=>$level, noopts=>$noop };
2945					next;
2946			next;
2947		}
2948		if( # !$readinrouters and
2949			$buf =~ /^\s*routers2?\.cgi\*Link\s*:\s*(\S.*)/i ) {
2950			$arg = $1;
2951			( $desc, $targfile, $icon, $targ, $level )
2952				= parse_link($arg);
2953			next if(!$targfile or !$desc);
2954			$icon = "link-general-sm.gif" if(!$icon);
2955			$url = $meurlfull."?rtr=".$q->escape($targfile)
2956				."&if=".$q->escape($targ)."&page=graph&xmtype=options";
2957			$routers{$router}{extensions} = []
2958				if(!defined $routers{$router}{extensions});
2959			push @{$routers{$router}{extensions}},
2960				{ desc=>$desc, url=>$url, icon=>$icon, target=>"graph",
2961					level=>$level, insecure=>0, noopts=>2 };
2962			next;
2963		}
2964		if( $buf =~ /^\s*routers2?\.cgi\*Extensions?\[(.+?)\]\s*:\s*(\S.*)/i ) {
2965			$curif = $1; $arg = $2;
2966			$curif = "_$curif" if(!defined $interfaces{$curif});
2967			next if(!defined $interfaces{$curif});
2968			( $desc, $url, $icon, $targ, $level, $insec, $noop )
2969				= parse_ext($arg);
2970			$interfaces{$curif}{extensions} = []
2971				if(!defined $interfaces{$curif}{extensions});
2972			push @{$interfaces{$curif}{extensions}},
2973				{ desc=>$desc, url=>$url, icon=>$icon, target=>$targ,
2974				hostname=>$interfaces{$curif}{hostname},
2975				community=>$interfaces{$curif}{community},
2976				level=>$level, insecure=>$insec, noopts=>$noop };
2977			next;
2978		}
2979		if( $buf =~ /^\s*routers2?\.cgi\*Link\[(.+?)\]\s*:\s*(\S.*)/i ) {
2980			$curif = $1; $arg = $2;
2981			$curif = "_$curif" if(!defined $interfaces{$curif});
2982			next if(!defined $interfaces{$curif});
2983#			( $desc, $targfile, $targ, $icon ) = quotewords('\s+',0,$arg);
2984			( $desc, $targfile, $icon, $targ, $level )
2985				= parse_link($arg);
2986			next if(!$targfile or !$desc);
2987#			if( $targ =~ /\.(gif|png)$/ and !$icon ) {
2988#				$icon = $targ; $targ = "";
2989#			}
2990			$icon = "link-general-sm.gif" if(!$icon);
2991			$url = $meurlfull."?rtr=".$q->escape($targfile)
2992				."&if=".$q->escape($targ)."&page=graph&xmtype=options";
2993			$interfaces{$curif}{extensions} = []
2994				if(!defined $interfaces{$curif}{extensions});
2995			push @{$interfaces{$curif}{extensions}},
2996				{ desc=>$desc, url=>$url, icon=>$icon, target=>"graph",
2997					level=>$level, insecure=>0, noopts=>2 };
2998			next;
2999		}
3000		if( $buf =~ /^\s*routers2?\.cgi\*(Graph|Summary)\[(.+?)\]\s*:\s*(\S.*)/i ) {
3001			$curif = $2; $arg = $3; $argb = (lc $1);
3002			next if( $curif eq '_' ); # not allowed
3003			if(!defined $interfaces{$curif}) {
3004				if( $argb eq "summary") {
3005					$curif = "_$curif" ;
3006				} else {
3007					# Create a dummy target...
3008					$interfaces{$curif} = { file=>$cfgfile, target=>$curif,
3009					insummary=>0, incompact=>0, inmenu=>0, isif=>0,
3010					interval=>$interval, nomax=>0, noabsmax=>0  };
3011					if(defined $interfaces{_}{directory}) {
3012						$interfaces{$curif}{rrd} =
3013							$workdir.$pathsep.$interfaces{_}{directory}
3014							.$pathsep.(lc $curif).".rrd";
3015					} else {
3016						$interfaces{$curif}{rrd}
3017							= $workdir.$pathsep.(lc $curif).".rrd";
3018					}
3019				}
3020			}
3021			next if(!defined $interfaces{$curif});
3022			if( $arg =~ /^"/ ) {
3023				$arg =~ /^"([^"]+)"\s*:?(.*)/;
3024				$opts = $2; $graph = $1;
3025			} else {
3026				$arg =~ /^(\S+)\s*:?(.*)/;
3027				$opts = $2; $graph = $1;
3028			}
3029			next if(!$graph);
3030			if( defined $interfaces{"_$graph"} ) {
3031				push @{$interfaces{"_$graph"}{targets}}, $curif
3032					if(!inlist("^$curif\$",@{$interfaces{"_$graph"}{targets}}));
3033				$interfaces{"_$graph"}{cgioptions} .= " $opts";
3034				$interfaces{"_$graph"}{usergraph} = 1;
3035			} else {
3036				$interfaces{$curif}{usergraphs} = []
3037					if(!defined $interfaces{$curif}{usergraphs});
3038				push @{$interfaces{$curif}{usergraphs}}, $graph;
3039				# here we set up various defaults.  Anything not set here
3040				# and not set by the user will be inherited from target 1
3041				if( $argb eq "summary" ) { # summary page
3042					$interfaces{"_$graph"} = {
3043						shdesc=>$graph,  targets=>[$curif],
3044						cgioptions=>$opts, mode=>"\177_USERSUMMARY",
3045						usergraph=>1, icon=>"summary-sm.gif",
3046						inout=>0, incompact=>0, withtotal=>0, withaverage=>0,
3047						insummary=>0, inmenu=>1, desc=>"Summary $graph",
3048						issummary=>1, pagetop=>"", pagefoot=>""
3049					};
3050				} else { # userdefined graph
3051					$interfaces{"_$graph"} = {
3052						shdesc=>$graph,  targets=>[$curif],
3053						cgioptions=>$opts, mode=>"\177_USER",
3054					usergraph=>1, icon=>"cog-sm.gif", inout=>0, incompact=>0,
3055					insummary=>0, inmenu=>1, desc=>"User defined graph $graph",
3056						withtotal=>0, withaverage=>0, issummary=>0,
3057						pagetop=>"", pagefoot=>"", factor=>1
3058					};
3059					$interfaces{"_$graph"}{rrd} = $interfaces{$curif}{rrd};
3060				}
3061				$interfaces{"_$graph"}{withtotal} = 1
3062					if( defined $config{'routers.cgi-showtotal'}
3063						and $config{'routers.cgi-showtotal'}=~/y/i);
3064				push @myifs, "_$graph";
3065			}
3066			next;
3067		}
3068		if( $buf =~ /^\s*routers2?\.cgi\*Icon\[(.+?)\]\s*:\s*(\S+)/i ) {
3069			$curif = $1; $arg = $2;
3070			$curif = "_$curif" if(!defined $interfaces{$curif});
3071			next if(!defined $interfaces{$curif});
3072			$interfaces{$curif}{icon} = $arg;
3073			next;
3074		}
3075		if( $buf =~ /^\s*routers2?\.cgi\*Ignore\[(.+?)\]\s*:\s*(\S+)/i ) {
3076			$curif = $1; $arg = $2;
3077			$curif = "_$curif" if(!defined $interfaces{$curif});
3078			next if(!defined $interfaces{$curif});
3079			if( $arg =~ /y/i ) {
3080				$interfaces{$curif}{insummary} = 0;
3081				$interfaces{$curif}{inmenu} = 0;
3082				$interfaces{$curif}{inout} = 0;
3083				$interfaces{$curif}{isif} = 0;
3084			}
3085			next;
3086		}
3087		if( $buf =~ /^\s*routers2?\.cgi\*InSummary\[(.+?)\]\s*:\s*(\S+)/i ) {
3088			$curif = $1; $arg = $2;
3089			$curif = "_$curif" if(!defined $interfaces{$curif});
3090			next if(!defined $interfaces{$curif});
3091			if( $arg =~ /[1y]/i ) {  $interfaces{$curif}{insummary} = 1; }
3092			elsif( $arg =~ /[2a]/i ) {  $interfaces{$curif}{insummary} = 2; }
3093			else { $interfaces{$curif}{insummary} = 0; }
3094			next;
3095		}
3096		if( $buf =~ /^\s*routers2?\.cgi\*InMenu\[(.+?)\]\s*:\s*(\S+)/i ) {
3097			$curif = $1; $arg = $2;
3098			$curif = "_$curif" if(!defined $interfaces{$curif});
3099			next if(!defined $interfaces{$curif});
3100			if( $arg =~ /[1y]/i ) {  $interfaces{$curif}{inmenu} = 1; }
3101			elsif( $arg =~ /[2a]/i ) {  $interfaces{$curif}{inmenu} = 2; }
3102			else { $interfaces{$curif}{inmenu} = 0; }
3103			next;
3104		}
3105		if( $buf =~ /^\s*routers2?\.cgi\*InOut\[(.+?)\]\s*:\s*(\S+)/i ) {
3106			$curif = $1; $arg = $2;
3107			next if(!defined $interfaces{$curif});
3108			if( $arg =~ /[1y]/i ) {  $interfaces{$curif}{inout} = 1; }
3109			elsif( $arg =~ /[2a]/i ) {  $interfaces{$curif}{inout} = 2; }
3110			else { $interfaces{$curif}{inout} = 0; }
3111			next;
3112		}
3113		if( $buf =~ /^\s*routers2?\.cgi\*InCompact\[(.+?)\]\s*:\s*(\S+)/i ) {
3114			$curif = $1; $arg = $2;
3115			next if(!defined $interfaces{$curif});
3116			if( $arg =~ /[1y]/i ) {  $interfaces{$curif}{incompact} = 1; }
3117			elsif( $arg =~ /[2a]/i ) {  $interfaces{$curif}{incompact} = 2; }
3118			else { $interfaces{$curif}{incompact} = 0; }
3119			next;
3120		}
3121		if( $buf =~ /^\s*(routers2?\.cgi\*)?Background\[(.+?)\]\s*:\s*(#[a-fA-F\d]+)/i ) {
3122			next if(!defined $interfaces{$2});
3123			$interfaces{$2}{background} = $3;
3124			$interfaces{$2}{xbackground} = $3; # if using stylesheets
3125			next;
3126		}
3127		if( $buf =~ /^\s*(routers2?\.cgi\*)?Timezone\[(.+?)\]\s*:\s*(\S.*)/i ) {
3128			next if(!defined $interfaces{$2});
3129			$interfaces{$2}{timezone} = $3;
3130			next;
3131		}
3132		if( $buf =~ /^\s*(routers2?\.cgi\*)?Directory\[(.+?)\]\s*:\s*(\S.*)/i ) {
3133			$curif = $2; $arg = $3;
3134			next if(!defined $interfaces{$curif});
3135			$arg =~ s/[\s\\\/]+$//; # trim trailing spaces and path separators!
3136			$interfaces{$curif}{rrd} =
3137				$workdir.$pathsep.$arg.$pathsep.(lc $curif).".rrd";
3138			$interfaces{$curif}{directory} = $arg;
3139			next;
3140		}
3141		if( $buf =~ /^\s*Logdir\s*:\s*(\S+)/i ) {
3142			$logdir = $1; $logdir =~ s/[\\\/]+$//; $workdir = $logdir; next; }
3143		if( $buf =~ /^\s*(routers2?\.cgi\*)?Workdir\s*:\s*(\S+)/i and !$logdir ) {
3144			$workdir = $2; $workdir =~ s/[\\\/]+$//; next; }
3145		if( $buf =~ /^\s*Interval\s*:\s*([\d\.]+):?(\d*)/i ) {
3146			$interval = $1; $interval += $2/60 if($2); next; }
3147		if( $buf =~ /^\s*(routers2?\.cgi\*)?Include\s*:\s*(\S+)/i ) {
3148			$newfile = $2;
3149			$newfile = (dirname $cfgfile).$pathsep.$newfile
3150				if( $newfile !~ /^([a-zA-Z]:)?[\/\\]/ );
3151			foreach my $d ( glob( $newfile ) ) {
3152				read_cfg_file($d,0);
3153			}
3154			next;
3155		}
3156		if( $buf =~ /^\s*(routers2?\.cgi\*)?LibAdd\s*:\s*(\S+)/i ) {
3157			$interfaces{$curif}{libadd} = $2;
3158			unshift @INC, $1; next; }
3159		if($buf=~ /^\s*(routers2?\.cgi\*)?MaxBytes(\d)\[(.+?)\]\s*:\s*(\d+)/i ){
3160			$curif = $3; $arg = $4;
3161			next if(!defined $interfaces{$curif});
3162			$interfaces{$curif}{"maxbytes$2"} = $arg;
3163			$interfaces{$curif}{maxbytes} = $arg
3164				if(!$interfaces{$curif}{maxbytes});
3165			next;
3166		}
3167		# the regexp from hell - preserved for posterity
3168#		if( $buf =~ /^\s*(routers2?\.cgi\*)?Colou?rs\[(.+?)\]\s*:\s*[^#]*(#[\da-f]{6})[\s,]+[^#]*(#[\da-f]{6})[\s,]+[^#]*(#[\da-f]{6})[\s,]+[^#]*(#[\da-f]{6})/i ) {
3169		if( $buf =~ /^\s*(routers2?\.cgi\*)?Colou?rs\[(.+?)\]\s*:\s*(.*)/i ) {
3170			$curif = $2; $arg = $3;
3171			$curif = "_$curif" if(!defined $interfaces{$curif});
3172			next if(!defined $interfaces{$curif});
3173			$interfaces{$curif}{colours} = []; # null array
3174			while( $arg =~ s/^[\s,]*[^#]*(#[\da-fA-F]{6})[\s,]*//i ) {
3175				push @{$interfaces{$curif}{colours}},$1;
3176			}
3177			$interfaces{$curif}{colours} = [ '#00ff00','#0000ff','#800080','#008000' ]
3178				if($#{$interfaces{$curif}{colours}}<0);
3179			next;
3180		}
3181		if( $buf =~ /^\s*routers2?\.cgi\*MBLegend\[(.+?)\]\s*:\s*(\S.*)/i ) {
3182			$curif = $1;
3183			$curif = "_$curif" if(!defined $interfaces{$curif});
3184			$interfaces{$curif}{mblegend} = $2;
3185			next;
3186		}
3187		if( $buf =~ /^\s*routers2?\.cgi\*AMLegend\[(.+?)\]\s*:\s*(\S.*)/i ) {
3188			$curif = $1;
3189			$curif = "_$curif" if(!defined $interfaces{$curif});
3190			$interfaces{$curif}{amlegend} = $2;
3191			next;
3192		}
3193		if( $buf =~ /^\s*(routers2?\.cgi\*)?AbsMax\[(.+?)\]\s*:\s*(\d+[\.,]?\d*)/i ) {
3194			next if(!defined $interfaces{$2});
3195			$interfaces{$2}{absmaxbytes} = $3;
3196			next;
3197		}
3198		if( $buf =~ /^\s*WeekFormat(\[.+?\])?\s*:\s*%?([UVW])/i ) {
3199			# yes I know this is ugly, it is being retrofitted
3200			$monthlylabel = "%".$2;
3201			next;
3202		}
3203		if( $buf =~ /^\s*routers2?\.cgi\*GraphStyle\[(.+?)\]\s*:\s*(\S+)/i ) {
3204			$curif = $1; $arg = $2;
3205			$curif = "_$curif" if(!defined $interfaces{$curif});
3206			next if(!defined $interfaces{$curif});
3207			$interfaces{$curif}{graphstyle} = $arg;
3208			next;
3209		}
3210		if( $buf =~ /^\s*(routers2?\.cgi\*)?Factor\[(.+?)\]\s*:\s*(-?[\d\.,]+)/i ) {
3211			$curif = $2; $arg = $3;
3212			$curif = "_$curif" if(!defined $interfaces{$curif});
3213			next if(!defined $interfaces{$curif});
3214			$interfaces{$curif}{factor} = $arg if($arg != 0);
3215			next;
3216		}
3217		if( $buf =~ /^\s*(routers2?\.cgi\*)?Supp?ress?\[(.+?)\]\s*:\s*(\S+)/i ) {
3218			$curif = $2; $arg = $3;
3219			$curif = "_$curif" if(!defined $interfaces{$curif});
3220			next if(!defined $interfaces{$curif});
3221			$interfaces{$curif}{suppress} = $arg;
3222			next;
3223		}
3224		if( $buf =~ /^\s*(routers2?\.cgi\*)?UpperLimit\[(.+?)\]\s*:\s*(\d+[\.,]?\d*)/i ) {
3225			$curif = $2; $arg = $3;
3226			$curif = "_$curif" if(!defined $interfaces{$curif});
3227			next if(!defined $interfaces{$curif});
3228			$interfaces{$curif}{upperlimit} = $arg;
3229			next;
3230		}
3231		if( $buf =~ /^\s*routers2?\.cgi\*IfNo\[(.+?)\]\s*:\s*(\d+)/i ) {
3232			$curif = $1; $arg = $2;
3233			$curif = "_$curif" if(!defined $interfaces{$curif});
3234			next if(!defined $interfaces{$curif});
3235			$interfaces{$curif}{ifno} = $arg;
3236			next;
3237		}
3238		if( $buf =~ /^\s*(routers2?\.cgi\*)?LowerLimit\[(.+?)\]\s*:\s*(\d+[\.,]?\d*)/i ) {
3239			$curif = $2; $arg = $3;
3240			$curif = "_$curif" if(!defined $interfaces{$curif});
3241			next if(!defined $interfaces{$curif});
3242			$interfaces{$curif}{lowerlimit} = $arg;
3243			next;
3244		}
3245		if( $buf =~ /^\s*(routers2?\.cgi\*)?(Thresh(Max|Min)[IO])\[(.+?)\]\s*:\s*(\d+[\.,]?\d*)(%?)/i ) {
3246			$curif = $4; $arg = $5; $argb = $6;
3247			$curif = "_$curif" if(!defined $interfaces{$curif});
3248			next if(!defined $interfaces{$curif});
3249			if( $argb ) { # Its a percentage! Set here for later usage
3250				$interfaces{$curif}{(lc $2)."pc"} = 1;
3251			}
3252			$interfaces{$curif}{(lc $2)} = $arg;
3253			next;
3254		}
3255		if( $buf =~ /^\s*routers2?\.cgi\*FixUnits?\[(.+?)\]\s*:\s*(\d+)/i ) {
3256			$curif = $1; $arg = $2;
3257			$curif = "_$curif" if(!defined $interfaces{$curif});
3258			next if(!defined $interfaces{$curif});
3259			$interfaces{$curif}{exponent} = $arg;
3260			$interfaces{$curif}{fixunits} = 1; # Implied
3261			next;
3262		}
3263		if( $buf =~ /^\s*routers2?\.cgi\*HRule\[(.+?)\]\s*:\s*(-?\d+[\.,]?\d*)\s*"?([^"]*)"?\s*(#([0-9a-f]{6}))?/i ) {
3264			$curif = $1; $arg = $2; $argb = $3; $argc = $5;
3265			$curif = "_$curif" if(!defined $interfaces{$curif});
3266			next if(!defined $interfaces{$curif});
3267			$interfaces{$curif}{hrule} = []
3268				if(!defined($interfaces{$curif}{hrule}));
3269			push @{$interfaces{$curif}{hrule}}, {
3270				value=>$arg, desc=>$argb, colour=>$argc
3271			};
3272			next;
3273		}
3274		# Experimental: routers.cgi*Line[target]: rpn expression
3275		if( $buf =~ /^\s*routers2?\.cgi\*Line\[(.+?)\]\s*:\s*(\S.*)$/i ) {
3276			$curif = $1; $arg = $2;
3277			$curif = "_$curif" if(!defined $interfaces{$curif});
3278			next if(!defined $interfaces{$curif});
3279			next if(!$interfaces{$curif}{usergraph});
3280			$interfaces{$curif}{lines} = []
3281				if(!defined($interfaces{$curif}{lines}));
3282			push @{$interfaces{$curif}{lines}}, {
3283				legend1=>"", legendi=>"", legendo=>"", units=>"",
3284				rpn=>[split /[\s,]/,$arg]
3285			};
3286			next;
3287		}
3288		if( $buf =~ /^\s*routers2?\.cgi\*(Set)?Symbol\[(.+?)\]\s*:\s*(\S+)\s+(.*)$/i ) {
3289			($curif,$arg,$desc)=($2,$3,$4);
3290			$curif = "_$curif" if(!defined $interfaces{$curif});
3291			next if(!defined $interfaces{$curif});
3292			$desc =~ s/^"//; $desc =~ s/"$//; # allow surrounding quotes
3293			$interfaces{$curif}{symbols}{$arg}=$desc;
3294			next;
3295		}
3296		if( $buf =~ /^\s*routers2?\.cgi\*Comment\[(.+?)\]\s*:\s*(.*)$/i ) {
3297			($curif,$arg)=($1,$2);
3298			$curif = "_$curif" if(!defined $interfaces{$curif});
3299			next if(!defined $interfaces{$curif});
3300			if(defined $interfaces{$curif}{comment}) {
3301				push @{$interfaces{$curif}{comment}},$arg;
3302			} else {
3303				$interfaces{$curif}{comment}=[$arg];
3304			}
3305			next;
3306		}
3307		if( $buf =~ /^\s*routers2?\.cgi\*SortBy\[(.+?)\]\s*:\s*(\S*)/i ) {
3308			($curif,$arg)=($1,$2);
3309			$curif = "_$curif" if(!defined $interfaces{$curif});
3310			next if(!defined $interfaces{$curif});
3311			$interfaces{$curif}{sortby}=$arg;
3312			next;
3313		}
3314		if( $buf =~ /^\s*(routers2?\.cgi\*)?Kilo\[(.+?)\]\s*:\s*(1024|1000)/i ) {
3315			($curif,$arg)=($2,$3);
3316			$curif = "_$curif" if(!defined $interfaces{$curif});
3317			next if(!defined $interfaces{$curif});
3318			$interfaces{$curif}{kilo}=$arg;
3319			next;
3320		}
3321		if( $buf =~ /^\s*(routers2?\.cgi\*)?Kmg\[(.+?)\]\s*:\s*(\S+)/i ) {
3322			($curif,$arg)=($2,$3);
3323			$curif = "_$curif" if(!defined $interfaces{$curif});
3324			next if(!defined $interfaces{$curif});
3325			$interfaces{$curif}{kmg}=[ split /,/,$arg ];
3326			next;
3327		}
3328	}
3329	$fd->close;
3330
3331	# now take the current file defaults
3332	foreach $key ( keys %{$interfaces{'_'}} ) {
3333		foreach $curif ( @myifs ) {
3334			$interfaces{$curif}{$key} = $interfaces{'_'}{$key}
3335				if(!defined $interfaces{$curif}{$key});
3336		}
3337	}
3338	foreach $key ( keys %{$interfaces{'^'}} ) {
3339		foreach $curif ( @myifs ) {
3340			$interfaces{$curif}{$key} = $interfaces{'^'}{$key}.' '.$interfaces{$curif}{$key};
3341		}
3342	}
3343	foreach $key ( keys %{$interfaces{'$'}} ) {
3344		foreach $curif ( @myifs ) {
3345			$interfaces{$curif}{$key} .= ' '.$interfaces{'$'}{$key};
3346		}
3347	}
3348	# now check for threshold percentages
3349	# we do this now because people may set maxbytes after setting thresh*,
3350	# or may set thresholds as percentages in the default target.
3351	foreach $curif ( @myifs ) {
3352		next if(!$curif);
3353		foreach ( qw/maxi maxo mini mino/ ) {
3354			if( $interfaces{$curif}{"thresh${_}pc"}
3355				and $interfaces{$curif}{maxbytes} ) {
3356				$interfaces{$curif}{"thresh${_}"} =
3357					$interfaces{$curif}{maxbytes}
3358					*( $interfaces{$curif}{"thresh${_}"} /100.0 );
3359			} #if
3360		}#foreach
3361	}#foreach
3362
3363	# now process the options
3364	foreach $curif ( @myifs ) {
3365		next if(!$curif);
3366		if(defined $interfaces{$curif}{options} ) {
3367		foreach $k ( split /[\s,]+/,$interfaces{$curif}{options} ) {
3368			if( $k eq "unknaszero") { $interfaces{$curif}{unknaszero} = 1; }
3369			$interfaces{$curif}{noo} = 1 if( $k eq "noo");
3370			$interfaces{$curif}{noi} = 1 if( $k eq "noi");
3371			if( $k eq "bits") {
3372				$interfaces{$curif}{bytes} = 0;
3373				$interfaces{$curif}{bits} = 1; }
3374			if( $k eq "perminute") {
3375				$interfaces{$curif}{perminute} = 1
3376					if(!defined $interfaces{$curif}{perhour}
3377						and !defined $interfaces{$curif}{perminute});
3378			}
3379			if( $k eq "perhour") {
3380				$interfaces{$curif}{perhour} = 1
3381					if(!defined $interfaces{$curif}{perhour}
3382						and !defined $interfaces{$curif}{perminute});
3383			}
3384			if( $k eq "nopercent") {
3385				$interfaces{$curif}{percent} = 0 ;
3386				# default incompact to NO if target has nopercent set
3387				$interfaces{$curif}{incompact} = 0
3388					if(($interfaces{$curif}{incompact} == 1)
3389					and($interfaces{$curif}{max} ne 100));
3390			}
3391			if( $k eq "dorelpercent") {
3392				 $interfaces{$curif}{noo} = 1;
3393				 $interfaces{$curif}{dorelpercent} = 1;
3394				 $interfaces{$curif}{fixunits} = 1;
3395				 $interfaces{$curif}{percent} = 0;
3396				 $interfaces{$curif}{bytes} = 1;
3397				 $interfaces{$curif}{bits} = 0;
3398				 $interfaces{$curif}{total} = 0;
3399				 $interfaces{$curif}{percentile} = 0;
3400				 $interfaces{$curif}{perminute} = 0;
3401				 $interfaces{$curif}{perhour} = 0;
3402				 $interfaces{$curif}{withtotal} = 0;
3403				 $interfaces{$curif}{noabsmax} = 1;
3404				 $interfaces{$curif}{nomax} = 0;
3405				 $interfaces{$curif}{mblegend} = 'Equality';
3406				 $interfaces{$curif}{unit} = '%';
3407				 $interfaces{$curif}{totunit} = '';
3408				 $interfaces{$curif}{ylegend} = 'percentage';
3409				 $interfaces{$curif}{mode} = 'relpercent';
3410			}
3411			$interfaces{$curif}{integer} = 1 if( $k eq "integer");
3412			$interfaces{$curif}{logscale} = 1 if( $k eq "logscale");
3413		} } # if defined options
3414		if ( defined $interfaces{$curif}{cgioptions} ) {
3415		  foreach $k ( split /[\s,]+/,$interfaces{$curif}{cgioptions} ) {
3416			if( $k eq "default") {
3417				$routers{$router}{defif} = $curif;
3418				$interfaces{$curif}{default} = 1 ;
3419				next;
3420			}
3421			$interfaces{$curif}{logscale} = 1 if( $k eq "logscale");
3422			$interfaces{$curif}{withfoot} = 1 if( $k eq "withpagefoot");
3423			$interfaces{$curif}{withtop} = 1 if( $k eq "withpagetop");
3424			$interfaces{$curif}{active} = 1 if( $k eq "active");
3425			$interfaces{$curif}{active} = 1 if( $k eq "activeonly");
3426			$interfaces{$curif}{cf} = 'MAX' if( $k eq "maximum");
3427			$interfaces{$curif}{cf} = 'MAX' if( $k eq "maxvalue");
3428			$interfaces{$curif}{cf} = 'MIN' if( $k eq "minimum");
3429#			$interfaces{$curif}{cf} = 'LAST' if( $k eq "last");
3430			$interfaces{$curif}{available} = 1 if( $k eq "available");
3431			$interfaces{$curif}{available} = 0 if( $k eq "noavailable");
3432			$interfaces{$curif}{noo} = 1 if( $k eq "noo");
3433			$interfaces{$curif}{noi} = 1 if( $k eq "noi");
3434			$interfaces{$curif}{noo} = 0 if( $k eq "o");
3435			$interfaces{$curif}{noi} = 0 if( $k eq "i");
3436			$interfaces{$curif}{c2fi} = 1 if( $k eq "c2fi");
3437			$interfaces{$curif}{c2fo} = 1 if( $k eq "c2fo");
3438#			$interfaces{$curif}{mult} = 8 if( $k eq "bits");
3439#			$interfaces{$curif}{mult} = 1 if( $k eq "bytes");
3440			if( $k eq "bytes") { $interfaces{$curif}{bytes} = 1;
3441				$interfaces{$curif}{bits} = 0; next; }
3442			if( $k eq "bits") { $interfaces{$curif}{bits} = 1;
3443				$interfaces{$curif}{bytes} = 0; next;  }
3444			if( $k eq "unknaszero") { $interfaces{$curif}{unknaszero} = 1; }
3445			if( $k eq "unknasprev") { $interfaces{$curif}{unknasprev} = 1; }
3446			if( $k eq "overridelegend") { $interfaces{$curif}{overridelegend} = 1; }
3447			if( $k eq "perminute") {
3448				$interfaces{$curif}{perminute} = 1
3449					if(!defined $interfaces{$curif}{perhour}
3450						and !defined $interfaces{$curif}{perminute});
3451				next;
3452			}
3453			if( $k eq "perhour") {
3454				$interfaces{$curif}{perhour} = 1
3455					if(!defined $interfaces{$curif}{perhour}
3456						and !defined $interfaces{$curif}{perminute});
3457				next;
3458			}
3459			$interfaces{$curif}{isif} = 1 if($k eq "interface");
3460			if( $k eq "ignore") {
3461				$interfaces{$curif}{inmenu} = 0 ;
3462				$interfaces{$curif}{insummary} = 0 ;
3463				$interfaces{$curif}{inout} = 0 ;
3464				$interfaces{$curif}{incompact} = 0 ;
3465				next;
3466			}
3467			$interfaces{$curif}{unscaled} = "" if( $k eq "scaled");
3468			if( $k eq "nototal") {
3469				if($interfaces{$curif}{usergraph}) {
3470					$interfaces{$curif}{withtotal} = 0 ;
3471				} else {
3472					$interfaces{$curif}{total} = 0 ;
3473				}
3474				next;
3475			}
3476			$interfaces{$curif}{percentile} = 0 if( $k eq "nopercentile");
3477			$interfaces{$curif}{percentile} = 1 if( $k eq "percentile");
3478			if( $k eq "summary" ) {
3479				$interfaces{$curif}{summary} = 1;
3480				$interfaces{$curif}{compact} = 0;
3481				$interfaces{$curif}{withtotal} = 0;
3482				$interfaces{$curif}{withaverage} = 0;
3483				$interfaces{$curif}{insummary} = 0 ;
3484				$interfaces{$curif}{incompact} = 0 ;
3485				next;
3486			}
3487			if( $k eq "compact" ) {
3488				$interfaces{$curif}{summary} = 0;
3489				$interfaces{$curif}{compact} = 1;
3490				$interfaces{$curif}{withtotal} = 0;
3491				$interfaces{$curif}{withaverage} = 0;
3492				$interfaces{$curif}{insummary} = 0;
3493				$interfaces{$curif}{incompact} = 0;
3494				next;
3495			}
3496			if( $k eq "total") {
3497				if($interfaces{$curif}{usergraph}) {
3498					$interfaces{$curif}{withtotal} = 1 ;
3499				} else {
3500					$interfaces{$curif}{total} = 1 ;
3501				}
3502				next;
3503			}
3504			if( $k eq "aspercent") {
3505				 $interfaces{$curif}{aspercent} = 1;
3506				 $interfaces{$curif}{fixunits} = 1;
3507				 $interfaces{$curif}{percent} = 0;
3508				 $interfaces{$curif}{bytes} = 1;
3509				 $interfaces{$curif}{bits} = 0;
3510				 $interfaces{$curif}{total} = 0;
3511				 $interfaces{$curif}{percentile} = 0;
3512				 $interfaces{$curif}{perminute} = 0;
3513				 $interfaces{$curif}{perhour} = 0;
3514				 $interfaces{$curif}{withtotal} = 0;
3515				 $interfaces{$curif}{noabsmax} = 1;
3516				 $interfaces{$curif}{mblegend} = '';
3517				 $interfaces{$curif}{unit} = '%';
3518				 $interfaces{$curif}{totunit} = '';
3519				 $interfaces{$curif}{ylegend} = 'percentage';
3520				 $interfaces{$curif}{mode} = 'percent';
3521				next;
3522			}
3523			$interfaces{$curif}{withaverage} = 1 if( $k eq "average");
3524			$interfaces{$curif}{nolegend} = 1 if( $k eq "nolegend");
3525			$interfaces{$curif}{nodetails} = 1 if( $k eq "nodetails");
3526			$interfaces{$curif}{nodetails} = 1 if( $k eq "nodetail");
3527			$interfaces{$curif}{nodesc} = 1 if( $k eq "nodesc");
3528			$interfaces{$curif}{nogroup} = 1
3529				if( $k eq "nogroup" or $k eq "nogroups");
3530			$interfaces{$curif}{nogroup} = 0 if( $k eq "group" );
3531			$interfaces{$curif}{nolines} = 1 if( $k eq "nolines");
3532			if( $k eq "nomax") {
3533				$interfaces{$curif}{nomax} = 1;
3534				$interfaces{$curif}{percent} = 0;
3535				# percent doesnt make sense if you dont have a maximum
3536				$interfaces{$curif}{incompact} = 0
3537					if($interfaces{$curif}{incompact} == 1);
3538			}
3539			$interfaces{$curif}{noabsmax} = 1 if( $k eq "noabsmax");
3540			$interfaces{$curif}{percent} = 0 if( $k eq "nopercent");
3541			$interfaces{$curif}{integer} = 1 if( $k eq "integer");
3542			$interfaces{$curif}{'reverse'} = 1 if( $k eq "reverse");
3543			$interfaces{$curif}{rigid} = 1 if( $k eq "rigid");
3544			if( $k =~ /^#[\da-fA-F]{6}$/ ) {
3545				$interfaces{$curif}{colours} = []
3546					if(!defined $interfaces{$curif}{colours});
3547				push @{$interfaces{$curif}{colours}}, $k;
3548				next;
3549			}
3550			$interfaces{$curif}{fixunits} = 1
3551				if( $k =~ /^fixunits?/i or $k =~ /^nounits?/i );
3552			$interfaces{$curif}{altscale} = 1 if( $k eq "altscale");
3553			$interfaces{$curif}{altscale} = 0 if( $k eq "noaltscale");
3554			$interfaces{$curif}{nothresholds} = 1 if( $k eq "nothresholds");
3555		  }
3556		}
3557		# fix the mult
3558		if($interfaces{$curif}{bytes}) {
3559			$interfaces{$curif}{mult} = 1;
3560		} elsif($interfaces{$curif}{bits} ) {
3561			$interfaces{$curif}{mult} = 8;
3562		}
3563		if($interfaces{$curif}{perminute}) {
3564			$interfaces{$curif}{mult}=1 if(!$interfaces{$curif}{mult});
3565			$interfaces{$curif}{mult} *= 60;
3566		} elsif($interfaces{$curif}{perhour}) {
3567			$interfaces{$curif}{mult}=1 if(!$interfaces{$curif}{mult});
3568			$interfaces{$curif}{mult} *= 3600;
3569		}
3570		# sanity check
3571		if( $interfaces{$curif}{incompact} and
3572			(!$interfaces{$curif}{maxbytes} or $interfaces{$curif}{nomax})){
3573			$interfaces{$curif}{incompact} = 0;
3574		}
3575		if( $interfaces{$curif}{cf} and $interfaces{$curif}{cf} eq 'MAX'){
3576			# cant have WithPeak if you have cf=MAX set
3577			$interfaces{$curif}{withpeak} = "n";
3578		}
3579
3580		# calculate RRD filename
3581		if(!$interfaces{$curif}{usergraph}) {
3582			$rrd = $workdir;
3583			$rrd .= $pathsep.$interfaces{$curif}{directory}
3584				if($interfaces{$curif}{directory});
3585			$rrd .= $pathsep.lc($interfaces{$curif}{target}).".rrd";
3586			$interfaces{$curif}{rrd} = $rrd;
3587		}
3588	}
3589
3590	# now read the corresponding .ok file, if it exists
3591	$cfgfile =~ s/\.(conf|cfg)$/.ok/;
3592	if( open OK, "<$cfgfile" )  {
3593		my( %ifdesc ) = ();
3594		my( %ifip ) = ();
3595		while( <OK> ) {
3596			if( /\tDescr\t(.+)\t(\d+)/ ) {
3597				$ifdesc{$2} = $1; $ifdesc{$1} = $2;
3598			}
3599			if( /\tIp\t(.+)\t(\d+)/ ) {
3600				$ifip{$2} = $1; $ifip{$1} = $2;
3601			}
3602		}
3603		close OK;
3604
3605		foreach $curif ( @myifs ) {
3606		if(!defined $interfaces{$curif}{ifno}) {
3607			$interfaces{$curif}{ifno} = $ifdesc{$interfaces{$curif}{ifdesc}}
3608			if(defined $interfaces{$curif}{ifdesc}
3609				and defined $ifdesc{$interfaces{$curif}{ifdesc}});
3610			$interfaces{$curif}{ifno} = $ifip{$interfaces{$curif}{ipaddress}}
3611			if(defined $interfaces{$curif}{ipaddress}
3612				and defined $ifip{$interfaces{$curif}{ipaddress}});
3613		}
3614		if(defined $interfaces{$curif}{ifno}) {
3615			$key = $interfaces{$curif}{ifno};
3616			$interfaces{$curif}{ifdesc} = $ifdesc{$key}
3617			if(defined $ifdesc{$key} and !defined $interfaces{$curif}{ifdesc});
3618			$interfaces{$curif}{ipaddress} = $ifip{$key}
3619			if(defined $ifip{$key} and !defined $interfaces{$curif}{ipaddress});
3620		}
3621		}
3622	} # ok file exists
3623
3624	# Creation of special interfaces moved to read_cfg
3625}
3626
3627sub read_cfg()
3628{
3629	my($cfgfile) = $_[0];
3630	my($l,$key,$k);
3631	my($ifcnt,$curif,@ifarr);
3632
3633	$cfgfile = $routers{$router}{file}
3634		if(!$cfgfile and $router and defined $routers{$router});
3635	$cfgfile = $config{'routers.cgi-confpath'}.$pathsep.$router
3636		if(!$cfgfile and $router);
3637	return if (!$cfgfile);
3638
3639	# now, have we done $cfgfile before?
3640	if( $CACHE and defined $ifstore{$cfgfile}
3641		and !$routers{$router}{nocache} and (-M $cfgfile >= 0 )) {
3642		# yes!
3643		%interfaces = %{$ifstore{$cfgfile}};
3644		$routers{$router}{extensions} = [@{$ifstore{"R:$cfgfile"}}]
3645			if(defined $ifstore{"R:$cfgfile"});
3646		$debugmessage .= "fromcache($cfgfile)\n";
3647		return;
3648	}
3649	if( -M $cfgfile < 0 ) {
3650		undef $ifstore{$cfgfile};
3651		undef $ifstore{"R:$cfgfile"};
3652		$debugmessage .= "refresh($cfgfile)\n";
3653	}
3654
3655	$debugmessage .= "Reading: ";
3656
3657	%interfaces = ( '_'=>{x=>0}, '^'=>{x=>0}, '$'=>{x=>0} );
3658	$interval = 5;
3659	$workdir = $config{'routers.cgi-dbpath'};
3660
3661	# Clear extension list ready to re-load it
3662	$routers{$router}{extensions} = [] if(defined $routers{$router});
3663	# recursively read the .cfg file and any includes
3664	read_cfg_file($cfgfile,1);
3665
3666	# zap defaults
3667	delete $interfaces{'_'};
3668	delete $interfaces{'$'};
3669	delete $interfaces{'^'};
3670	delete $interfaces{''} if(defined $interfaces{''});
3671
3672	# now set up userdefined graphs for Incoming and Outgoing, if it is
3673	# necessary.
3674	$ifcnt = 0; @ifarr = (); $curif="";
3675	foreach ( keys %interfaces ) {
3676		$curif = $_ if(!$curif and $interfaces{$_}{community}
3677				and $interfaces{$_}{hostname} );
3678		if($interfaces{$_}{inout}) {
3679			$ifcnt++;
3680			push @ifarr, $_;
3681		}
3682	}
3683	$debugmessage .= "ifcnt=$ifcnt\n";
3684	if($ifcnt) {
3685		my($t);
3686		$t = "";
3687		$t = $routers{$router}{shdesc}.": "
3688			if($router and defined $routers{$router}
3689				and defined $routers{$router}{shdesc});
3690		if( defined $interfaces{'_incoming'} ) {
3691			push @{$interfaces{'_incoming'}{targets}},@ifarr
3692				if( $interfaces{'_incoming'}{mode} =~ /_AUTO/ );
3693		} else {
3694			$interfaces{'_incoming'} = {
3695			usergraph=>1, insummary=>0, inmenu=>1, inout=>0, incompact=>0,
3696			shdesc=>langmsg(2405,"Incoming"),  targets=>[@ifarr], noo=>1, mult=>8,
3697			icon=>"incoming-sm.gif", mode=>"\177_AUTO",
3698			desc=>$t.langmsg(2414,"Incoming traffic"),
3699			withtotal=>0, withaverage=>0, issummary=>0,
3700			graphstyle=>'lines'
3701			};
3702			$interfaces{'_incoming'}{active} = 1
3703				if($routers{$router}{activeinout});
3704			if(defined $config{'routers.cgi-showtotal'}
3705				and $config{'routers.cgi-showtotal'}=~ /y/i ) {
3706				$interfaces{'_incoming'}{withtotal} = 1;
3707			}
3708		}
3709		if( defined $interfaces{'_outgoing'}  ) {
3710			push @{$interfaces{'_outgoing'}{targets}},@ifarr
3711				if( $interfaces{'_outgoing'}{mode} =~ /_AUTO/ );
3712		} else {
3713			$interfaces{'_outgoing'} = {
3714			usergraph=>1, insummary=>0, inmenu=>1, inout=>0, incompact=>0,
3715			shdesc=>langmsg(2406,"Outgoing"),  targets=>[@ifarr], noi=>1, mult=>8,
3716			icon=>"outgoing-sm.gif", mode=>"\177_AUTO",
3717			desc=>$t.langmsg(2415,"Outgoing traffic"),
3718			withtotal=>0, withaverage=>0, issummary=>0,
3719			graphstyle=>'lines'
3720			};
3721			$interfaces{'_outgoing'}{active} = 1
3722				if($routers{$router}{activeinout});
3723			if(defined $config{'routers.cgi-showtotal'}
3724				and $config{'routers.cgi-showtotal'}=~ /[1y]/i ) {
3725				$interfaces{'_outgoing'}{withtotal} = 1;
3726			}
3727		}
3728	}
3729
3730	# Now set up default userdefined summary, if anything is insummary
3731	@ifarr = ();
3732	foreach ( keys %interfaces )  {
3733		push @ifarr, $_ if($interfaces{$_}{insummary});
3734		# first pass for interfaces
3735		identify $_ if(!$interfaces{$_}{usergraph});
3736	}
3737	if(@ifarr) {
3738		if( defined $interfaces{'_summary_'} ) {
3739			push @{$interfaces{'_summary_'}{targets}},@ifarr
3740				if( $interfaces{'_summary_'}{mode} =~ /_AUTOSUMMARY/ );
3741		} else {
3742			$interfaces{'_summary_'} = {
3743				usergraph=>1, insummary=>0, inmenu=>1, inout=>0, incompact=>0,
3744				shdesc=>langmsg(2416,"Summary"),
3745				targets=>[@ifarr], noo=>1, mult=>8,
3746				icon=>"summary-sm.gif", mode=>"\177_AUTOSUMMARY",
3747				withtotal=>0, withaverage=>0, issummary=>1
3748			};
3749			$interfaces{'_summary_'}{active} = 1
3750				if($routers{$router}{activesummary});
3751			$interfaces{'_summary_'}{active} = 1
3752				if($routers{$router}{summaryoptions} and $routers{$router}{summaryoptions} =~ /active/);
3753			$interfaces{'_summary_'}{nodetails} = 1
3754				if($routers{$router}{summaryoptions} and $routers{$router}{summaryoptions} =~ /nodetail/);
3755		}
3756	}
3757
3758	# Can we call out to the routingtable.cgi program?
3759	if( defined $config{'routers.cgi-routingtableurl'} and $curif
3760		and ( !defined $routers{$router}{routingtable}
3761			or $routers{$router}{routingtable} =~ /[1y]/i )) {
3762		$routers{$router}{extensions} = []
3763			if( !defined $routers{$router}{extensions} );
3764		push @{$routers{$router}{extensions}}, {
3765			url=>$config{'routers.cgi-routingtableurl'},
3766			desc=>langmsg(2417,"Routing Table"), icon=>"router-sm.gif",
3767			community=>$interfaces{$curif}{community},
3768			hostname=>$interfaces{$curif}{hostname},
3769			level=>0, insecure=>1
3770		};
3771	}
3772
3773	# second pass for user graphs
3774	foreach $key ( keys %interfaces ) {
3775		if($interfaces{$key}{usergraph}) {
3776			$k = $key; $k=~ s/^_//; # chop off initial _ prefix
3777			$interfaces{$key}{shdesc} = $config{"targetnames-$k"}
3778			if(defined $config{"targetnames-$k"});
3779			$interfaces{$key}{desc} = $config{"targettitles-$k"}
3780			if(defined $config{"targettitles-$k"});
3781			$interfaces{$key}{icon} = $config{"targeticons-$k"}
3782			if(defined $config{"targeticons-$k"});
3783			# Inherit most options from first target
3784			foreach $k (keys %{$interfaces{$interfaces{$key}{targets}->[0]}}) {
3785				$interfaces{$key}{$k}
3786					= $interfaces{$interfaces{$key}{targets}->[0]}{$k}
3787					if(!defined $interfaces{$key}{$k}
3788						and ($k ne 'extensions')
3789						and ($k ne 'pagetop') and ($k ne 'pagefoot')
3790					);
3791			}
3792		} else {
3793			# Can we call out to the trend.cgi program? (undocumented)
3794			if( defined $config{'routers.cgi-trendurl'}
3795				and !$interfaces{$key}{usergraph} ) {
3796				$interfaces{$key}{extensions} = []
3797					if(!defined $interfaces{$key}{extensions});
3798				push @{$interfaces{$key}{extensions}}, {
3799					url=>$config{'routers.cgi-trendurl'},
3800					desc=>langmsg(2418,"Trend Analysis"), icon=>"graph-sm.gif",
3801					target=>"graph", level=>0, insecure=>0
3802				};
3803			}
3804		}
3805	}
3806
3807	# at this point, %interfaces is set up.
3808	if($CACHE) {
3809		# cache it
3810		$ifstore{$cfgfile} = { %interfaces };
3811		$debugmessage .= "cached[$cfgfile] ";
3812		if(defined $routers{$router}{extensions}) {
3813			$ifstore{"R:$cfgfile"} = [ @{$routers{$router}{extensions}} ];
3814			$debugmessage .= "cached[$cfgfile:X] ";
3815		}
3816		$debugmessage .= "\n";
3817		if( $archdate ) { # clean up mess before caching
3818			foreach my $tmpif ( keys %interfaces ) {
3819				$ifstore{$cfgfile}{$tmpif}{rrd}
3820					= $ifstore{$cfgfile}{$tmpif}{origrrd}
3821					if($ifstore{$cfgfile}{$tmpif}{origrrd});
3822			}
3823		}
3824#		write_cache;
3825	} else {
3826		$debugmessage .= "NOCACHE\n";
3827	}
3828}
3829
3830
3831#############################################################################
3832# reformat to look nice
3833# params -- number, fix flag, integer flag
3834sub doformat($$$)
3835{
3836	my( $sufx ) = "";
3837	my( $val, $fix, $intf ) = @_;
3838
3839	return "???" if(!defined $val or $val !~ /\d/ );
3840	return $val if( $val == 0 );
3841
3842	if(!$fix) {
3843		if( abs($val) >= $T ) {
3844			$val /= $T; $sufx = 'T';
3845		} elsif( abs($val) >= $G ) {
3846			$val /= $G; $sufx = 'G';
3847		} elsif( abs($val) >= $M  ) {
3848			$val /= $M; $sufx = 'M';
3849		} elsif( abs($val) >= $k ) {
3850			$val /= $k; $sufx = $ksym;
3851		} elsif( abs($val) < 0.001 ) {
3852			$val *= 1000000; $sufx = 'u';
3853		} elsif( abs($val) < 1 ) {
3854			$val *= 1000; $sufx = 'm';
3855		}
3856	}
3857
3858	return sprintf "%.0f %s",$val,$sufx
3859		if( $intf or ( int($val*100) == (100*int($val)) ) );
3860	return sprintf "%.2f %s",$val,$sufx;
3861}
3862# Round the number to a set no of decimal places
3863sub dp($$) {
3864	my($num,$dcp) =@_;
3865	my($rv);
3866	return '0' if(!$num);
3867	$rv = sprintf '%.'.$dcp.'f',$num;
3868	$rv =~ s/\.0+$//; # remove trailing .0
3869	return $rv;
3870}
3871
3872#################################
3873# Calculate nth percentile (bits), and total bandwidth (bits), for current rrd
3874# and for specified interval (d,w,m,y)
3875# Returns ( desc, [inpercentile,intotal,emsg], [outpercentile,outtotal,emsg] )
3876
3877sub calc_percentile($$$)
3878{
3879	my( $thisif, $pcinterval, $percentile ) = @_; # interface, dwmy, 95
3880	my( @rv, $e, @opts );
3881	my( $rrd, $ds );
3882	my( $resolution, $startpoint, $desc ); # fetch input values
3883	my( $datastart, $datastep, $dsnames, $dsdata ); # fetch return values
3884	my( $pc, $row, $totalbits, @pcarray, $idx, $pcidx );
3885
3886	return ("",["-","-","No interface"],["-","-",""])
3887		if(!$thisif); # just in case
3888
3889	$rrd = $interfaces{$thisif}{rrd};
3890	if($rrdcached and $rrdcached!~/^unix:/) {
3891		my($pth) = $config{'routers.cgi-dbpath'};
3892		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
3893		$rrd =~ s/^$pth\/*//;
3894	}
3895	foreach ( $pcinterval ) {
3896		/y/ and do { $resolution = 3600; $startpoint = "-1y";
3897			$desc = langmsg(2420,"rolling last year"); last; };
3898		/m/ and do { $resolution = 1800; $startpoint = "-1month";
3899			$desc = langmsg(2421,"rolling last month"); last; };
3900		/w/ and do { $resolution = 300; $startpoint = "-7d";
3901			$desc = langmsg(2422,"last 7 days"); last; };
3902		/6/ and do { $resolution = 60*$interfaces{$thisif}{interval};
3903			$desc = langmsg(2423,"last 6 hours");
3904			$startpoint = "-6h"; last; };
3905		$resolution = 60*$interfaces{$thisif}{interval}; # interval
3906		$startpoint = "-24h"; # 1 day
3907		$desc = langmsg(2424,"last 24 hours");
3908	}
3909	$desc =~ s/last/previous/ if($pcinterval =~ /-/);
3910	$resolution = 300 if(!$resolution);
3911	push @rv, $desc;
3912
3913	# fetch the data
3914	eval { require RRDs; };
3915	if( $@ ) {
3916		return ("", ["-","-","No RRDs.pm"],["-","-",""]) ;
3917	}
3918	if($basetime) {
3919		@opts = ( $rrd,"AVERAGE","-e",$basetime,"-s","end$startpoint" );
3920	} elsif( $pcinterval =~ /-/ ) {
3921		@opts = ( $rrd,"AVERAGE","-e","now$startpoint","-s","end$startpoint" );
3922	} elsif( $uselastupdate > 1 and $archivetime) {
3923		@opts = ( $rrd,"AVERAGE","-e",$archivetime,"-s","end$startpoint" );
3924	} elsif( $uselastupdate ) {
3925		@opts = ( $rrd,"AVERAGE","-e",$lastupdate,"-s","end$startpoint" );
3926	} else {
3927		@opts = ( $rrd,"AVERAGE","-s",$startpoint );
3928	}
3929	( $datastart, $datastep, $dsnames, $dsdata ) = RRDs::fetch( @opts, @rrdcached );
3930	$e = RRDs::error();
3931	if ( $e ) {
3932		@rv = ("",["?","?",$e], ["?","?","fetch ".(join " ",@opts)]);
3933		return @rv;
3934	}
3935
3936	# now we do two calculations: the total traffic ( $datastep*sum(value) )
3937	# for both in and out, and the percentile (95% into sorted array )
3938	foreach $idx ( 0..1 ) {
3939		$totalbits = 0; @pcarray = ();
3940		foreach $row ( @$dsdata ) {
3941			# ???? Is this correctly skipping UNKN values?
3942			#      This needs to be checked, we should avoid UNKN in %ile
3943			next if(!defined $row->[$idx]);
3944			if( $row->[$idx] =~ /\d/ ) {
3945#			$totalbits += $row->[$idx]*$interfaces{$thisif}{mult}*$datastep;
3946# We no longer multiply by {mult} since we DO NOT want to multiple for
3947# permin/perhour totals (datastep takes care of that) and we want bits to
3948# be totalled in bytes.
3949			$totalbits += $row->[$idx]*$datastep;
3950			push @pcarray, ( $row->[$idx] * $interfaces{$thisif}{mult} );
3951			}
3952		}
3953		@pcarray = sort numerically @pcarray if($#pcarray>0);
3954		$pcidx = int($#pcarray * $percentile / 100);
3955# Now, at this point, if $thisif is a RANGE, we should do percentile and
3956# 100-percentile , ie, the opposite for the 'from'.
3957		if( $idx and $interfaces{$thisif} and $interfaces{$thisif}{graphstyle}
3958			and $interfaces{$thisif}{graphstyle} eq "range" ) {
3959			$pcidx = int($#pcarray * (100-$percentile) / 100);
3960		}
3961		$pc = $pcarray[$pcidx];
3962		# multiply by the factor : we did the mult previously
3963		$pc *= $interfaces{$thisif}{factor} if($interfaces{$thisif}{factor});
3964		$totalbits *= $interfaces{$thisif}{factor}
3965			if($interfaces{$thisif}{factor});
3966		# the c2f options are BEFORE display
3967		if(($interfaces{$thisif}{c2fi} and !$idx)
3968			or ($interfaces{$thisif}{c2fo} and $idx)) {
3969			$pc = $pc * 1.8 + 32;
3970			$totalbits = $totalbits * 1.8 + 32; # yes its stupid but consistent
3971		}
3972		push @rv, [ $pc.' ', $totalbits, '' ];
3973	}
3974
3975	return @rv;
3976}
3977
3978#################################
3979# Top menu
3980
3981sub do_head()
3982{
3983my($iconsuffix) = "";
3984my($loginbuttons) = "";
3985my($colwid) = 115;
3986my($logo);
3987
3988$iconsuffix = "-bw" if( $gstyle =~ /b/ );
3989
3990start_html_ss({ -bgcolor => $menubgcolour, -text => $menufgcolour,
3991	-class => 'header' });
3992print "<DIV class=header>";
3993if( $config{'web-auth-required'} =~ /^[yo]/i ) {
3994	if( $authuser ) {
3995		$loginbuttons = $q->td({ -align=>"LEFT", -width=>110, -valign=>"TOP",
3996			class=>'header', id=>'htlogin' },
3997			$q->a({href=>"$meurlfull?page=logout", target=>'_top', class=>'header'},
3998		$q->img({src=>"${config{'routers.cgi-iconurl'}}logout$iconsuffix.gif",
3999			alt=>langmsg(5000,"Logout"), border=>"0", width=>100, height=>20, class=>'header'}))
4000			."<div class=login>"
4001			.$q->br.langmsg(1002,"User").":&nbsp;<div class=username>$authuser</div></div>");
4002	} else {
4003		$loginbuttons = $q->td({ -align=>"LEFT", -width=>110, -valign=>"TOP", class=>'header', id=>'htlogin' },
4004			$q->a({href=>"$meurlfull?page=login", target=>'_top', class=>'header'},
4005		$q->img({src=>"${config{'routers.cgi-iconurl'}}login$iconsuffix.gif",
4006			alt=>langmsg(5001,"Login"), border=>"0", width=>100, height=>20, class=>'header'}))
4007			);
4008	}
4009} elsif( $config{'web-auth-required'} =~ /^s/i ) {
4010	if( $authuser ) {
4011		$loginbuttons = $q->td({ -align=>"LEFT", -width=>110, -valign=>"TOP",
4012			class=>'header', id=>'htlogin' },
4013			"<div class=login>"
4014			.langmsg(1002,"User").":&nbsp;<div class=username>$authuser</div>"
4015			."</div>"
4016		);
4017	} else {
4018		$loginbuttons = $q->td({ -align=>"LEFT", -width=>110, -valign=>"TOP", class=>'header', id=>'htlogin' },
4019			$q->a({href=>($config{'web-shib-login'}?$config{'web-shib-login'}:'/secure'), target=>'_top', class=>'header'},
4020		$q->img({src=>"${config{'routers.cgi-iconurl'}}login$iconsuffix.gif",
4021			alt=>langmsg(5001,"Login"), border=>"0", width=>100, height=>20, class=>'header'}))
4022			);
4023	}
4024}
4025
4026# Page top logo, may be overridden
4027if($config{'routers.cgi-logourl'}) {
4028	$logo = $q->img({ src=>$config{'routers.cgi-logourl'}, border=>0, class=>'header'});
4029} else {
4030	$logo = $q->a( { href=>$APPURL, target=>"_new", class=>'header' } ,
4031		$q->img({ src=>($config{'routers.cgi-smalliconurl'}."routers2.gif"),
4032			alt=>"Routers2.cgi", border=>0, width=>120, height=>40, class=>'header' }));
4033}
4034
4035print "\n".$q->table( { -border=>"0", -width=>"100%", cellspacing=>0, cellpadding=>1, class=>'header' },
4036  $q->Tr( { -valign=>"TOP", -width=>"100%", class=>'header' }, "\n".
4037    $q->td({ -align=>"LEFT", -width=>$colwid, -valign=>"TOP", class=>'header', id=>'htleft' },
4038	($config{'web-backurl'}?( "<DIV nowrap><nobr>".
4039      $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}nothing-sm.gif",
4040	border=>0, width=>15, height=>15, class=>'header'})."&nbsp;".
4041      $q->a({ href=>$config{'web-backurl'}, target=>"_top", class=>'header'},
4042      $q->img({ src=>"${config{'routers.cgi-iconurl'}}mainmenu$iconsuffix.gif", alt=>langmsg(5002,"Main Menu"), border=>0,
4043		width=>100, height=>20, class=>'header' }))."</nobr></DIV>"."\n"
4044	):"")."<DIV nowrap><nobr>"
4045      .$q->img({ src=>"${config{'routers.cgi-smalliconurl'}}nothing-sm.gif",
4046	border=>0, width=>15, height=>15, class=>'header'})."&nbsp;"
4047	.$q->a({href=>"javascript:parent.graph.location.reload(true)", class=>'header'},
4048		$q->img({src=>"${config{'routers.cgi-iconurl'}}refresh$iconsuffix.gif",alt=>langmsg(5003,"Refresh"), border=>"0",
4049		width=>100, height=>20, class=>'header'}))."</nobr></div>"
4050    )."\n"
4051	.$loginbuttons
4052    .$q->td({ -align=>"CENTER", -valign=>"TOP", class=>'header', id=>'htmiddle' }, $toptitle)."\n"
4053    .$q->td({ -align=>"RIGHT", -width=>1, -valign=>"TOP", class=>'header', id=>'htright' }, $logo)."\n"
4054  )
4055),"\n";
4056print "</DIV>";
4057# Finish off the page
4058print $q->end_html();
4059}
4060
4061###########################
4062# Side menu
4063
4064# $mtype specified 'routers' (list routers) or 'options' (list options)
4065
4066
4067sub do_menu()
4068{
4069my ($iflabel);
4070my ($target) = "graph";
4071my ($rtrdesc,$gs,$adesc);
4072my ($iconsuffix) = "";
4073my ($groupdesc, $lastgroup, $thisgroup);
4074#my ($hassummary) = 0;
4075my ($hascompact) = 0;
4076my ($explore) = "y";
4077my (@archive) = ();
4078my ($archivepat);
4079my ($timeframe);
4080my ($lurl); # link URL
4081my ($menulevel) = 0;
4082my ($multilevel) = 0;
4083my ($gs) = ':';
4084my ($pfx);
4085
4086# explore will contain either y, n, or i
4087$explore = $config{'routers.cgi-allowexplore'}
4088	if( defined $config{'routers.cgi-allowexplore'} );
4089$mtype = "options" if( $explore !~ /y/i );
4090
4091$iconsuffix = "-bw" if( $gstyle =~ /b/ );
4092$target = "_top" if( $gstyle =~ /p/ );
4093
4094# Start it off
4095start_html_ss({ -bgcolor => $menubgcolour, -text => $menufgcolour,
4096	nowrap => "yes", -class => 'sidemenu' });
4097
4098print "<DIV NOWRAP class=sidemenu>\n";
4099
4100# top link for other stuff
4101#if( $mtype eq "options" or !$router or $router eq "none"
4102#	or $router eq "__none" or $interface eq "__none" ) {
4103#	print $q->a({name=>"top"},"");
4104#}
4105print "<FONT size=".$config{'routers.cgi-menufontsize'}.">\n"
4106	if( defined $config{'routers.cgi-menufontsize'} );
4107
4108# Main stuff and links
4109if ( $mtype eq "options" ) {
4110	# check for inout graphs
4111	foreach ( keys %interfaces ) {
4112#		if( $interfaces{$_}{insummary} ) { $hassummary = 1; }
4113		if( $interfaces{$_}{incompact} ) { $hascompact = 1; }
4114	}
4115	# check for archive
4116	if( defined $config{'routers.cgi-archive'}
4117		and $config{'routers.cgi-archive'} !~ /^n/i ) {
4118		$archivepat = $router; $archivepat =~ s/[\?#\\\/]//g;
4119		$archivepat = $config{'routers.cgi-graphpath'}.$pathsep
4120			.$archivepat.$pathsep.$interface.$pathsep."*.*";
4121		# do this in an eval because some Perl implementations treat a null
4122		# glob as an error (why??)
4123		eval { @archive = glob($archivepat); };
4124	}
4125
4126	# now show it all
4127	if( !$twinmenu ) {
4128	print "<nobr>"
4129    	.$q->img({ src=>"${config{'routers.cgi-smalliconurl'}}nothing-sm.gif",
4130			border=>0, width=>15, height=>15, class=>'sidemenu'})."&nbsp;"
4131		.$q->a({ href=>"$meurlfull?".optionstring(
4132		{ page=>"menu",xmtype=>"routers" }),class=>'sidemenu', target=>"_self",
4133		onMouseOver=>"if(devices){devices.src='${config{'routers.cgi-iconurl'}}devices-dn-w.gif'; window.status='Show list of routers';}",
4134		onmouseout=>"if(devices){devices.src='${config{'routers.cgi-iconurl'}}devices-dn$iconsuffix.gif'; window.status='';}" },
4135		$q->img({ src=>"${config{'routers.cgi-iconurl'}}devices-dn$iconsuffix.gif",
4136		alt=>langmsg(5004,"Devices"), border=>0 , name=>"devices",
4137		class => 'sidemenu',
4138		width=>100, height=>20}))."</nobr>\n".$q->br."\n"
4139		if( $explore =~ /y/i );
4140	}
4141	# list options
4142	if( $explore !~ /n/i and $router ne "none") {
4143		print "<nobr>";
4144      	print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}nothing-sm.gif",
4145			border=>0, width=>15, height=>15,class=>'sidemenu'})."&nbsp;"
4146	  .$q->img({ src=>"${config{'routers.cgi-iconurl'}}targets$iconsuffix.gif",
4147			alt=>langmsg(5005,"Targets"),width=>100, height=>20,class=>'sidemenu' })
4148		."</nobr>".$q->br."\n";
4149	foreach ( sort byifdesc keys( %interfaces ) ) {
4150		next if(!$_); # avoid the '#' interface...
4151		next if(!$interfaces{$_}{inmenu}); # if not in menu...
4152		$iflabel = $interfaces{$_}{shdesc} if(defined $interfaces{$_}{shdesc});
4153		$iflabel = "#$_" unless ( $iflabel );
4154		$iflabel =~ s/ /\&nbsp;/g; # get rid of spaces...
4155		print "<NOBR>";
4156		if( $_ eq $interface ) {
4157			my(@k) = (keys %interfaces);
4158			print $q->a({name=>"top"},"") if($#k>25); }
4159		if( $interfaces{$_}{icon} ) {
4160			print $q->img({
4161				src=>($config{'routers.cgi-smalliconurl'}.$interfaces{$_}{icon}),
4162				width=>15, height=>15, alt=>$interfaces{$_}{desc},class=>'sidemenu' }),"&nbsp;";
4163		} elsif( $interfaces{$_}{isif} ) {
4164			print $q->img({
4165				src=>($config{'routers.cgi-smalliconurl'}."interface-sm.gif"),
4166				width=>15, height=>15, alt=>$interfaces{$_}{desc},class=>'sidemenu' }),"&nbsp;";
4167		} else {
4168			print $q->img({
4169				src=>($config{'routers.cgi-smalliconurl'}."target-sm.gif"),
4170				width=>15, height=>15, alt=>$interfaces{$_}{desc},class=>'sidemenu' }),"&nbsp;";
4171		}
4172		if ( $interface eq $_ ) {
4173			print $q->b($iflabel);
4174		} else {
4175			if( $gstyle =~ /p/ ) {
4176				print $q->a({ href=>"$meurlfull?".optionstring(
4177	{ page=>"main", if=>"$_" }), target=>"_top",class=>'sidemenu' }, $iflabel );
4178			} else {
4179				print $q->a({ href=>"$meurlfull?".optionstring(
4180	{ if=>"$_" }), target=>"graph",class=>'sidemenu' }, $iflabel );
4181			}
4182		}
4183		print "</NOBR>".$q->br."\n";
4184
4185	} #  special targets - summary, compact, info, userdefined
4186	if( $router ne "none" and $router ne "__none" ) {
4187		if($hascompact) {
4188		if( $config{'routers.cgi-stylesheet'}
4189			or ! defined $config{'routers.cgi-compact'}
4190			or $config{'routers.cgi-compact'} !~ /n/i ) {
4191		print "<NOBR>";
4192		print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}compact-sm.gif",
4193			width=>15, height=>15,class=>'sidemenu'  }),"&nbsp;";
4194		if( $interface eq "__compact" ) {
4195			print $q->b(langhtml(2000,"Compact summary"));
4196		} else {
4197			if( $gstyle =~ /p/ ) {
4198			print $q->a({ href=>"$meurlfull?".optionstring(
4199	{ page=>"main", if=>"__compact" }), target=>"_top",class=>'sidemenu' },
4200	langhtml(2000,"Compact summary"));
4201			} else {
4202			print $q->a({ href=>"$meurlfull?".optionstring(
4203	{ if=>"__compact" }), target=>"graph",class=>'sidemenu' },
4204	langhtml(2000,"Compact summary"));
4205			}
4206		}
4207		print "</NOBR>".$q->br."\n";
4208		} # compact option
4209		} # hascompact
4210		if( $router !~ /^#/ ) {
4211		print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}menu-sm.gif",
4212			width=>15, height=>15,class=>'sidemenu'  }),"&nbsp;";
4213		if( $interface eq "__info" ) {
4214			print $q->b(langhtml(2001,"Information")),$q->br,"\n";
4215		} else {
4216			if( $gstyle =~ /p/ ) {
4217			print $q->a({ href=>"$meurlfull?".optionstring(
4218	{ page=>"main",if=>"__info"}), target=>"_top",class=>'sidemenu'},
4219	langhtml(2001,"Information")),$q->br,"\n";
4220			} else {
4221			print $q->a({ href=>"$meurlfull?".optionstring(
4222	{ if=>"__info" }), target=>"graph",class=>'sidemenu' },
4223	langhtml(2001,"Information")),$q->br,"\n";
4224			}
4225		}
4226		} # not system special #SERVER#
4227	# any userdefined's for this router?
4228	if ( defined $routers{$router}{extensions} ) {
4229		my( $u, $ext, $targ );
4230		foreach $ext ( @{$routers{$router}{extensions}} ) {
4231			if($seclevel<$ext->{level}) {
4232#				print $ext->{desc}." (".$ext->{level}.")".$q->br."\n";
4233				next;
4234			}
4235			$targ = "graph";
4236			$targ = $ext->{target} if( defined $ext->{target} );
4237			$u = $ext->{url};
4238			if(!$ext->{noopts}) {
4239			$u .= "?x=1" if( $u !~ /\?/ );
4240			$u .= "&fi=".$q->escape($router)
4241				."&url=".$q->escape($q->url());
4242			$u .= "&t=".$q->escape($targ);
4243			$u .= "&L=".$seclevel;
4244			$u .= "&r=".$q->escape($ext->{hostname})
4245			."&h=".$q->escape($ext->{hostname}) if(defined $ext->{hostname});
4246			$u .= "&c=".$q->escape($ext->{community})
4247				if(defined $ext->{community} and $ext->{insecure});
4248			$u .= "&b=".$q->escape("javascript:history.back();history.back()")
4249				."&conf=".$q->escape($conffile);
4250			$u .= "&ad=$archdate&arch=$archdate" if($archdate);
4251			} elsif( $ext->{noopts} == 2 ) { # special for Link[]
4252				$u .= "&L=$seclevel&xgtype=$gtype&xgstyle=$gstyle";
4253				$u .= "&ad=$archdate&arch=$archdate" if($archdate);
4254			}
4255			print "<NOBR>".$q->img({ src=>(${config{'routers.cgi-smalliconurl'}}
4256				.$ext->{icon}), width=>15, height=>15,class=>'sidemenu'  }),"&nbsp;";
4257			print $q->a({ href=>$u, target=>$targ,class=>'sidemenu' },
4258				expandvars($ext->{desc}) )."</NOBR>".$q->br."\n";
4259		}
4260	} # extensions defined
4261	} # not 'none' router
4262	print $q->br;
4263	} # explore
4264
4265	print "\n<DIV class=sidemenuoptions>";
4266	if( !$archive and $interface ne "__none" and $interface ne "__info" ) {
4267		print "<nobr>";
4268      	print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}nothing-sm.gif",
4269	border=>0, width=>15, height=>15,class=>'sidemenu'})."&nbsp;";
4270	print $q->img({ src=>"${config{'routers.cgi-iconurl'}}graphs$iconsuffix.gif", alt=>langmsg(5006,"Graphs"),
4271		width=>100, height=>20,class=>'sidemenu' })."</nobr>". $q->br."\n";
4272	# Here, if the option is enabled, use the calendar tool
4273	if( $config{'routers.cgi-extendedtime'} and $config{'routers.cgi-extendedtime'}=~/f/i ) {
4274		my($mindate) = "";
4275		my($rrdinfo);
4276		my($e);
4277		my($rranum) = 0;
4278		my($gwindow) = 400;
4279		my($basedate) = "";
4280		my($rrdfilename);
4281		my($datestr,$dformat) = ('Live Data','%Y-%m-%d');
4282		my($mday,$mon,$year);
4283		if(defined $interfaces{$interface}{origrrd}) {
4284			$rrdfilename = $interfaces{$interface}{origrrd};
4285		} else {
4286			$rrdfilename = $interfaces{$interface}{rrd};
4287		}
4288		# convert this into a param that can be used by Javascript Date()
4289		if( $q->param('arch') ) {
4290			if( $q->param('arch') =~ /(\d\d\d\d)-(\d\d)-(\d\d)/ ) {
4291				$basedate = "$1,".($2-1).",$3";
4292				($mday,$mon,$year)=($3,$2-1,$1-1900);
4293				$dformat = $config{'web-dateonlyformat'}
4294					if(defined $config{'web-dateonlyformat'});
4295				$dformat =~ s/&nbsp;/ /g;
4296				$datestr = POSIX::strftime($dformat,0,0,0,$mday,$mon,$year);
4297			} else {
4298				$datestr = $q->param('arch');
4299			}
4300		}
4301		if( $gtype =~ /w/ ) {
4302			$gwindow = 333; # weekly graphs are shorter time window
4303			$rranum = 1;
4304		} elsif( $gtype =~ /m/ ) {
4305			$rranum = 2;
4306		} elsif( $gtype =~ /y/ ) {
4307			$rranum = 3;
4308		}
4309		if($rrdcached and $rrdcached!~/^unix:/) {
4310			my($pth) = $config{'routers.cgi-dbpath'};
4311			$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
4312			$rrdfilename =~ s/^$pth\/*//;
4313		}
4314		eval { require RRDs; };
4315		if($@) {
4316			$e = $@;
4317		} else {
4318			$rrdinfo  = RRDs::info($rrdfilename,@rrdcached);
4319			$e = RRDs::error();
4320		}
4321		if($e) {
4322			print "<!-- RRD error: $e -->\n";
4323			print "<!-- RRD file: $rrdfilename -->\n";
4324			print "<!-- RRDcached option: $rrdcached -->\n";
4325			print "<!-- RRDcached setting: ".(join(" ",@rrdcached))." -->\n";
4326		} else {
4327			print "<!-- RRD rra=$rranum rows=".$rrdinfo->{"rra[${rranum}].rows"}." -->\n";
4328		}
4329		if(defined $rrdinfo and !$e and $rrdinfo->{"rra[${rranum}].rows"} ) {
4330			$mindate = 1000 * (time() - ($rrdinfo->{step} * $rrdinfo->{"rra[${rranum}].pdp_per_row"} * ($rrdinfo->{"rra[${rranum}].rows"}-$gwindow)));
4331		}
4332		print "<TABLE><TR><TD>";
4333		print "<FORM name=dateform method=GET action=$meurlfull target=graph class=sidemenu>";
4334		print "<span id=\"calendar-trigger\">".$q->img({ src=>"${config{'routers.cgi-smalliconurl'}}calendar-sm.gif",
4335			width=>15, height=>15, class=>'sidemenuform', id=>'dateanchor'  }),"&nbsp;"; # spacer
4336		print "<button id=\"calendar-trigger-button\">$datestr</button></span><br>\n";
4337		print $q->hidden(-id=>"calendar-field", -name=>"arch", -override=>1, -default=>($q->param('arch')));
4338		print $q->hidden(-name=>'rtr', -default=>"$router", -override=>1);
4339		print $q->hidden(-name=>'if', -default=>"$interface", -override=>1);
4340		print $q->hidden(-name=>'page', -default=>'graph', -override=>1);
4341		print $q->hidden(-name=>'xpage', -default=>'graph', -override=>1); # grr
4342		print $q->hidden(-name=>'xgtype', -default=>"$gtype", -override=>1);
4343		print $q->hidden(-name=>'xgstyle', -default=>"$gstyle", -override=>1);
4344		print $q->hidden(-name=>'xgopts', -default=>"$gopts", -override=>1);
4345		print $q->hidden(-name=>'bars', -default=>"$baropts", -override=>1);
4346		print $q->hidden(-name=>'extra', -default=>"$extra", -override=>1);
4347		print $q->hidden(-name=>'uopts', -default=>"$uopts", -override=>1);
4348		print "</FORM>";
4349		print "</TD></TR></TABLE>\n";
4350		print "<SCRIPT>\n
4351// JSCal2 Calendar control from http://www.dynarch.com/projects/calendar/
4352function getDateInfo(date, wantsClassName) {
4353	var idate = Calendar.dateToInt(date);
4354	if (String(idate).indexOf(\"0821\") == 4) {
4355		return { klass: \"birthday\", tooltip: \"Steve's Birthday!\" };
4356	}
4357};
4358var cal = Calendar.setup({
4359	inputField : \"calendar-field\",
4360	trigger    : \"calendar-trigger\",
4361	anchor     : \"dateanchor\",
4362	animation  : false,
4363	opacity    : 1,
4364	align      : \"BC/ /l/b/\",
4365	dateFormat : \"\%Y-\%m-\%d\",
4366	selection  : Calendar.dateToInt(new Date(${basedate})),
4367	max        : Calendar.dateToInt(new Date()),
4368	min        : Calendar.dateToInt(new Date(${mindate})),
4369	dateInfo   : getDateInfo,
4370	onSelect   : function() {
4371		this.hide();
4372		if( Calendar.printDate(Calendar.intToDate(this.selection.get()),\"\%Y-\%m-\%d\") != \"".$q->param('arch')."\" ) {
4373			dateform.submit();
4374		}
4375	}
4376});
4377</SCRIPT>\n";
4378	} else {
4379	# First we list all the archived RRD files, if available.
4380	my($archroot) = '';
4381	if($interface and defined $interfaces{$interface}) {
4382		if($interfaces{$interface}{origrrd}) {
4383			$archroot = dirname($interfaces{$interface}{origrrd})
4384				.$pathsep.'archive';
4385		} elsif($interfaces{$interface}{rrd}) {
4386			$archroot = dirname($interfaces{$interface}{rrd})
4387				.$pathsep.'archive';
4388		}
4389	}
4390	if( -d $archroot ) {
4391		# An archive exists!
4392		my($rrdfilename);
4393		if(defined $interfaces{$interface}{origrrd}) {
4394			$rrdfilename = basename($interfaces{$interface}{origrrd});
4395		} else {
4396			$rrdfilename = basename($interfaces{$interface}{rrd});
4397		}
4398		my(@days) = ( '0' );
4399		my(%descs);
4400		my($dmyfmt);
4401		if( defined $config{'web-dateonlyformat'} ) {
4402			$dmyfmt = $config{'web-dateonlyformat'};
4403		} else { $dmyfmt = "\%d/\%m/\%y" } # could use %x here?
4404		$debugmessage .= "Dateformat used: $dmyfmt\n";
4405		$descs{0} = langmsg(5007,'Live data');
4406		# caching code for speedycgi people
4407		if( -M $archroot < 0 ) {
4408			# invalidate archive cache, as a new one has been added.
4409			%cachedays = ();
4410			$^T = time; # set 'script init time' to first read of cfg files
4411			# we also need to clear all other caches since they are tied
4412			# to the script init time?
4413			# try without since if they have changed the previous checks will
4414			# already have picked it up and refreshed them
4415			#%ifstore = ();      # clean out all cached info
4416			#%routerscache = (); # clean out all cached info
4417			#$readinrouters = 0;
4418		}
4419		if( defined $cachedays{$rrdfilename} ) {
4420			@days = @{$cachedays{$rrdfilename}};
4421			# If we get the list from the cache, we still need to build descs
4422			# This is because people may have different date formats...
4423			foreach ( @days ) {
4424				if( /(\d\d)(\d\d)-(\d\d)-(\d\d)/ ) {
4425					if($dmyfmt) {
4426						$descs{$_} =
4427				POSIX::strftime($dmyfmt,0,0,0,$4,($3-1),(($1>19)?($2+100):$2));
4428					} else { $descs{$_} =  "$4/$3/$2"; } #DMY
4429				}
4430			}
4431			$debugmessage .= "fromcache(dates:$rrdfilename)\n";
4432		} else {
4433			# Maybe find a better way to do this -- glob is SLOW
4434			$|=1; # print out what we've done so far
4435			foreach ( sort rev findarch( $archroot,$rrdfilename ) ) {
4436				if( /(\d\d)(\d\d)-(\d\d)-(\d\d)/ ) {
4437					push @days, "$1$2-$3-$4";
4438					if($dmyfmt) {
4439						$descs{"$1$2-$3-$4"} =
4440				POSIX::strftime($dmyfmt,0,0,0,$4,($3-1),(($1>19)?($2+100):$2));
4441					} else { $descs{"$1$2-$3-$4"} =  "$4/$3/$2"; } #DMY
4442				}
4443			}
4444			$cachedays{$rrdfilename} = [ @days ]; # Cache for later
4445			$debugmessage .= "cached[dates:$rrdfilename]\n";
4446		}
4447		if( $#days > 0 ) {
4448		print "<nobr><TABLE cellspacing=0 cellpadding=0 border=0 class=sidemenu><TR class=sidemenu><TD class=sidemenu>";
4449		print "<FORM name=archform method=GET action=$meurlfull target=graph class=sidemenu>";
4450		print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}calendar-sm.gif",
4451			width=>15, height=>15, class=>'sidemenuform'  }),"&nbsp;"; # spacer
4452		my($curd) = $q->param('arch');
4453		$curd = $opt_a if($opt_a);
4454		$curd = '0' if(!$curd);
4455		print $q->popup_menu( -name=>"arch", -values=>\@days,
4456			-default=>$curd, -labels=>\%descs,
4457			-onChange=>'archform.submit();', class=>'sidemenuform');
4458		print $q->hidden(-name=>'rtr', -default=>"$router", -override=>1);
4459		print $q->hidden(-name=>'if', -default=>"$interface", -override=>1);
4460		print $q->hidden(-name=>'page', -default=>'graph', -override=>1);
4461		print $q->hidden(-name=>'xpage', -default=>'graph', -override=>1); # grr
4462		print $q->hidden(-name=>'xgtype', -default=>"$gtype", -override=>1);
4463		print $q->hidden(-name=>'xgstyle', -default=>"$gstyle", -override=>1);
4464		print $q->hidden(-name=>'xgopts', -default=>"$gopts", -override=>1);
4465		print $q->hidden(-name=>'bars', -default=>"$baropts", -override=>1);
4466		print $q->hidden(-name=>'extra', -default=>"$extra", -override=>1);
4467		print $q->hidden(-name=>'uopts', -default=>"$uopts", -override=>1);
4468		print "</FORM>\n";
4469		print "</TD></TR></TABLE></nobr>";
4470		} else {
4471			print "<!-- no archive dates -->";
4472		}
4473	} else {
4474		print "<!-- $archroot does not exist -->\n";
4475	}
4476	} # new archive method
4477	# Now all the different daily/weekly/etc graph types
4478	foreach ( @gorder ) {
4479		if( defined $interfaces{$interface}
4480			and defined $interfaces{$interface}{suppress} ) {
4481			$timeframe = $_; $timeframe =~ s/-//g;
4482			next if( $interfaces{$interface}{suppress} =~ /$timeframe/ );
4483		}
4484		print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}clock-sm.gif",
4485			width=>15, height=>15, class=>'sidemenu'  }),"&nbsp;";
4486		if($gtype eq $_) {
4487			print $q->b($gtypes{$_}),$q->br,"\n";
4488		} elsif((($interface eq "__compact")
4489			and (length > 2 ))
4490			or ( $router eq "none" )) {
4491			print $gtypes{$_},$q->br,"\n";
4492		} else {
4493			if( $gstyle =~ /p/ ) {
4494			print $q->a({ href=>"$meurlfull?".optionstring(
4495				{ page=>"main", xgtype=>"$_" }),
4496				target=>"_top", class=>'sidemenu' }, $gtypes{$_} ), $q->br,"\n";
4497			} else {
4498			print $q->a({ href=>"$meurlfull?".optionstring(
4499	{ xgtype=>"$_" }), target=>"graph", class=>'sidemenu' }, $gtypes{$_} ),$q->br,"\n";
4500			}
4501		}
4502	}
4503		print $q->br;
4504	} # ! viewing archive
4505	print "\n";
4506	if( @archive ) {
4507		print "<nobr>";
4508      	print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}nothing-sm.gif",
4509	border=>0, width=>15, height=>15, class=>'sidemenu'})."&nbsp;";
4510		print  $q->img({
4511			src=>"${config{'routers.cgi-iconurl'}}archive-h$iconsuffix.gif",
4512			alt=>langmsg(5008,"Archive"), width=>100, height=>20, class=>'sidemenu' }),"</nobr>".$q->br."\n";
4513		if($archive) {
4514			print "<NOBR>";
4515			print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}graph-sm.gif",
4516					width=>15, height=>15, class=>'sidemenu'  }),"&nbsp;";
4517			$adesc = langhtml(5007,"Live graph");
4518			if( $gstyle=~/p/ ) {
4519				print $q->a({ href=>"$meurlfull?".optionstring( { page=>"main" }),
4520					target=>"_top", class=>'sidemenu' }, $adesc );
4521			} else {
4522				print $q->a({ href=>"$meurlfull?".optionstring( { page=>"graph" }),
4523					target=>"graph", class=>'sidemenu' }, $adesc );
4524			}
4525			print "</NOBR>".$q->br."\n";
4526		}
4527		foreach ( sort @archive ) {
4528			if(/(\d+)-(\d+)-(\d+)-(\d+)-(\d+)-(\S+)\.(gif|png)$/) {
4529				# try to get local formatting
4530#				$adesc = "$4:$5&nbsp;$3/$2/$1&nbsp;(".$gtypes{$6}.")";
4531				my( $dformat ) = "%c";
4532				$dformat = $config{'web-shortdateformat'}
4533					if(defined $config{'web-shortdateformat'});
4534				if(!$dformat) {
4535					$adesc = "$4:$5&nbsp;$3/$2/$1&nbsp;(".$gtypes{$6}.")";
4536				} else {
4537					$adesc = POSIX::strftime($dformat,
4538						0,$5,$4,$3,($2-1),($1-1900))." (".$gtypes{$6}.")";
4539					$adesc =~ s/ /\&nbsp;/g;
4540				}
4541				print "<NOBR>";
4542		print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}graph-sm.gif",
4543				width=>15, height=>15, class=>'sidemenu'  }),"&nbsp;";
4544				if( $gstyle=~/p/ ) {
4545					print $q->a({ href=>"$meurlfull?".optionstring( { page=>"main",
4546						archive=>(basename $_), xgtype=>"$6"}),
4547						target=>"_top", class=>'sidemenu' }, $adesc );
4548				} else {
4549					print $q->a({ href=>"$meurlfull?".optionstring( {
4550						page=>"graph",
4551						archive=>(basename $_), xgtype=>"$6"}),
4552						target=>"graph", class=>'sidemenu' }, $adesc );
4553				}
4554				print "</NOBR>".$q->br."\n";
4555			} else {
4556				print "<!-- Error in archive [$_] -->\n";
4557			}
4558		}
4559		print $q->br."\n";
4560	}
4561
4562	if( !$archive and $interface ne "__none" and $interface ne "__info"  ) {
4563		print "<nobr>";
4564      	print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}nothing-sm.gif",
4565	border=>0, width=>15, height=>15, class=>'sidemenu'})."&nbsp;";
4566	print  $q->img({
4567		src=>"${config{'routers.cgi-iconurl'}}styles$iconsuffix.gif",
4568		alt=>langmsg(5009,"Styles"), width=>100, height=>20, class=>'sidemenu' })."</nobr>".$q->br."\n";
4569	foreach ( @sorder ) {
4570		next if (!defined $gstyles{$_});
4571		print "<NOBR>";
4572		print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}pbrush-sm.gif",
4573			width=>15, height=>15, class=>'sidemenu'  }),"&nbsp;";
4574		$gs = $gstyles{$_};
4575		$gs =~ s/ /\&nbsp;/g;
4576		if($gstyle eq $_) {
4577			print $q->b($gs);
4578		} elsif( $router eq "none" ) {
4579			print $gs;
4580		} else {
4581			# PDAs cant be relied on to have javascript support
4582			if( /p/ ) {
4583			print $q->a({ href=>"$meurlfull?".optionstring(
4584	{ page=>"main", xgstyle=>"$_"}), target=>"_top", class=>'sidemenu' }, $gs );
4585			} else {
4586			print $q->a({ href=>"$meurlfull?".optionstring(
4587	{ xgstyle=>"$_"}), target=>"graph", class=>'sidemenu' }, $gs );
4588			}
4589		}
4590		print "</NOBR>".$q->br."\n";
4591	}
4592		print $q->br;
4593	} # ! archive viewing
4594		print "<nobr>";
4595      	print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}nothing-sm.gif",
4596	border=>0, width=>15, height=>15, class=>'sidemenu'})."&nbsp;";
4597	print  $q->img({ src=>"${config{'routers.cgi-iconurl'}}otherstuff$iconsuffix.gif", alt=>langmsg(5010,"Other Stuff"),
4598		width=>100, height=>20, class=>'sidemenu' })."</nobr>". $q->br."\n";
4599	print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}prefs-sm.gif",
4600			width=>15, height=>15, class=>'sidemenu'  }),"&nbsp;";
4601	print $q->a({href=>"$meurlfull?".optionstring(
4602	{ page=>"config" }) , target=>"graph", class=>'sidemenu'},
4603		langmsg(5011,"Preferences")),$q->br,"\n";
4604	print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}info-sm.gif", class=>'sidemenu' }),"&nbsp;";
4605	print $q->a({href=>"$meurlfull?".optionstring({page=>"help"}), target=>"graph", class=>'sidemenu'},
4606		langmsg(5012,"Information")),$q->br,"\n";
4607#	print $q->img({ src=>"${config{'routers.cgi-iconurl'}}error-sm.gif" }),"&nbsp;";
4608#	print $q->a({href=>("$meurl?page=verify&rtr="
4609#		.$q->escape($router)),target=>"_new"},"Configuration&nbsp;check")
4610#		.$q->br."\n";
4611	# twin menu
4612	print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}menu-sm.gif", class=>'sidemenu' }),
4613		"&nbsp;";
4614	if( $twinmenu ) {
4615		$uopts=~ s/[tT]//g; $uopts .= "T";
4616		print $q->a({ href=>"$meurlfull?".optionstring({ page=>"main"}),
4617			target=>"_top", class=>'sidemenu' },langhtml(5013,"Close second menu") )
4618	} else {
4619		$uopts=~ s/[tT]//g; $uopts .= "t";
4620		print $q->a({ href=>"$meurlfull?".optionstring({page=>"main"}),
4621			target=>"_top", class=>'sidemenu' }, langhtml(5014,"Twin menu view") )
4622	}
4623	print $q->br."\n";
4624	print "</DIV>"; # sidemenuoptions
4625} else {
4626	# Devices (Routers) menu list
4627	#
4628	if( ! $twinmenu ) {
4629      	print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}nothing-sm.gif",
4630	border=>0, width=>15, height=>15, class=>'sidemenu'})."&nbsp;";
4631		print $q->a({ href=>"$meurlfull?".optionstring(
4632			{ page=>"menu", xmtype=>"options" }), target=>"_self" ,
4633		onMouseOver=>"if(options){options.src='${config{'routers.cgi-iconurl'}}options-dn-w.gif'; window.status='Show display options';}",
4634		onmouseout=>"if(options){options.src='${config{'routers.cgi-iconurl'}}options-dn$iconsuffix.gif'; window.status='';}", class=>'sidemenu' },
4635		$q->img({ src=>"${config{'routers.cgi-iconurl'}}options-dn$iconsuffix.gif", alt=>langmsg(5015,"Options"), border=>0, name=>"options", class=>'sidemenu',
4636			height=>20, width=>100 }))."\n".$q->br."\n";
4637	}
4638	# list  devices
4639      	print $q->img({ src=>"${config{'routers.cgi-smalliconurl'}}nothing-sm.gif",
4640	border=>0, width=>15, height=>15, class=>'sidemenu'})."&nbsp;";
4641	print  $q->img({ src=>"${config{'routers.cgi-iconurl'}}devices$iconsuffix.gif", alt=>langmsg(5004,"Devices"),
4642			height=>20, width=>100, class=>'sidemenu' }), $q->br,"\n";
4643	# The 'Find' box
4644	print "<DIV class=sidemenuoptions>";
4645	if( !defined $config{'routers.cgi-showfindbox'}
4646		or $config{'routers.cgi-showfindbox'} =~ /[Yy1]/ ) {
4647		print "<NOBR><TABLE align=left cellspacing=0 cellpadding=0 border=0 class=sidemenu><TR class=sidemenu><TD nowrap class=sidemenu><FORM method=GET action=$meurlfull target=graph class=sidemenuform>";
4648      	print $q->img({src=>"${config{'routers.cgi-smalliconurl'}}search-sm.gif", border=>0, width=>15, height=>15, class=>'sidemenu'})."&nbsp;";
4649		print $q->textfield({-name=>'searchhost',
4650			-value=>langmsg(5004,"Device"), -size=>9, class=>'sidemenuform'});
4651		print $q->hidden(-name=>'page', -default=>"graph", -override=>1);
4652		print $q->hidden(-name=>'xgtype', -default=>"$gtype", -override=>1);
4653		print $q->hidden(-name=>'xgstyle', -default=>"$gstyle", -override=>1);
4654		print $q->hidden(-name=>'xgopts', -default=>"$gopts", -override=>1);
4655		print $q->hidden(-name=>'bars', -default=>"$baropts", -override=>1);
4656		print $q->hidden(-name=>'extra', -default=>"$extra", -override=>1);
4657		print $q->hidden(-name=>'uopts', -default=>"$uopts", -override=>1);
4658		print $q->submit({ name=>"search", value=>"?", class=>'sidemenuform' });
4659		print "</FORM></TD></TR></TABLE></NOBR><br clear=both>\n";
4660	}
4661	print "</DIV>";
4662	# grouping
4663	my($lastgroupdesc,$activegroupdesc);
4664	$grouping = $multilevel = 0;
4665	$grouping = 1 if( defined $config{'routers.cgi-group'}
4666		and $config{'routers.cgi-group'} =~ /[Yy1]/ );
4667	if($grouping) {
4668		$group=$lastgroup="";
4669		$group=$routers{$router}{group} if(defined $routers{$router});
4670		$gs = ':';
4671		$gs = $config{'routers.cgi-groupsep'}
4672			if(defined $config{'routers.cgi-groupsep'});
4673		$multilevel = 1 if( defined $config{'routers.cgi-multilevel'}
4674			and $config{'routers.cgi-multilevel'}=~/[y1]/i );
4675		# Prefix to cut off for group names
4676		$pfx = $config{'routers.cgi-confpath'}.$pathsep;
4677		# Can't add escapes for some reason
4678#		$pfx =~ s/\//\\\//g;
4679		$pfx =~ s/\\/\\\\/g;
4680
4681		if($multilevel) {
4682			if( defined $config{"targetnames-$group"} ) {
4683				$activegroupdesc = $config{"targetnames-$group"};
4684			} elsif( defined $config{("targetnames-".(lc $group))} ) {
4685				$activegroupdesc = $config{("targetnames-".(lc $group))};
4686			} elsif($group) {
4687				$activegroupdesc = $group;
4688				$activegroupdesc =~ s/^$pfx//; # Chop off confpath
4689				$activegroupdesc = basename( $group,'' ).$pathsep
4690					if(!$activegroupdesc);
4691			} else {
4692				$activegroupdesc = "None";
4693			}
4694		}
4695	}
4696	foreach ( sort byshdesc keys(%routers) ) {
4697		next if(!$routers{$_}{inmenu});
4698		if( $grouping ) {
4699			$thisgroup =  $routers{$_}{group};
4700			if( $thisgroup ne $lastgroup ) {
4701				my(@grps);
4702				if( defined $config{"targetnames-$thisgroup"} ) {
4703					$groupdesc = $config{"targetnames-$thisgroup"};
4704				} elsif( defined $config{("targetnames-".(lc $thisgroup))} ) {
4705					$groupdesc = $config{("targetnames-".(lc $thisgroup))};
4706				} else {
4707					$groupdesc = $thisgroup;
4708					$groupdesc =~ s/^$pfx//; # Chop off confpath
4709					$groupdesc = basename( $thisgroup,'' ).$pathsep if(!$groupdesc);
4710				}
4711				if($multilevel) {
4712					@grps = getgroups($activegroupdesc,$groupdesc,$lastgroupdesc);
4713				} else {
4714					@grps = ( [ $groupdesc,1,(($thisgroup eq $group)?1:0) ] );
4715				}
4716				foreach my $gg ( @grps ) {
4717					print "<NOBR>";
4718					$menulevel = $gg->[1];
4719					print "&nbsp;&nbsp;" x $menulevel if($menulevel);
4720					if( $gg->[2] ) {
4721						print $q->img({
4722						src=>"${config{'routers.cgi-smalliconurl'}}g-sm.gif",
4723						width=>15, height=>15, alt=>$gg->[0], class=>'sidemenu' }),"&nbsp;";
4724						print $q->b($gg->[0]);
4725					} else {
4726						$lurl = $meurlfull;
4727						$lurl = $routers{$_}{redirect}
4728							if(defined $routers{$_}{redirect});
4729						if( $gstyle =~ /p/ or defined $routers{$_}{redirect}) {
4730						print $q->img({
4731						src=>"${config{'routers.cgi-smalliconurl'}}plus-sm.gif",
4732						width=>15, height=>15, alt=>$gg->[0], class=>'sidemenu',
4733						border=>0 }),"&nbsp;";
4734							print $q->a({href=>"$lurl?"
4735				 				.optionstring({page=>"main",'if'=>"",rtr=>"$_"}),
4736								target=>"_top", class=>'sidemenu' },$q->b($gg->[0]) );
4737						} else {
4738						print $q->a({ href=>"$lurl?"
4739							.optionstring({ rtr=>"$_", 'if'=>"" }),
4740							target=>"graph", class=>'sidemenu' }, $q->img({
4741						src=>"${config{'routers.cgi-smalliconurl'}}plus-sm.gif",
4742						width=>15, height=>15, alt=>$gg->[0], class=>'sidemenu',
4743						border=>0 }))."&nbsp;";
4744							print $q->a({ href=>"$lurl?"
4745								.optionstring({ rtr=>"$_", 'if'=>"" }),
4746								target=>"graph", class=>'sidemenu' },$q->b($gg->[0]) );
4747						}
4748					}
4749					print "</NOBR>".$q->br."\n";
4750				} # foreach
4751				$lastgroup = $thisgroup;
4752				$lastgroupdesc = $groupdesc;
4753			} # if in new group
4754			if( $multilevel ) {
4755				next if(( $thisgroup ne $group )
4756					and ( $activegroupdesc !~ /^$groupdesc$gs/ ));
4757#				if(( $thisgroup ne $group )
4758#					and ( $activegroupdesc !~ /^$groupdesc$gs/ )) { print "[$activegroupdesc][^$groupdesc$gs]"; }
4759			} else {
4760				next if( $thisgroup ne $group ); # only show active group
4761			}
4762		} # if grouping
4763		$rtrdesc = $routers{$_}{shdesc};
4764		$rtrdesc = $_ if(! $rtrdesc );
4765		$rtrdesc =~ s/ /\&nbsp\;/g; # stop breaking of line on spaces
4766
4767		print "<NOBR>";
4768		if($grouping) { print ( "&nbsp;&nbsp;" x ($menulevel+1)); }
4769		if( $_ eq $router ) { print $q->a({name=>"top"},""); }
4770		print $q->img({ src=>($config{'routers.cgi-smalliconurl'}.$routers{$_}{icon}),
4771			width=>15, height=>15, class=>'sidemenu',
4772			alt=>( $routers{$_}{shdesc}?$routers{$_}{shdesc}:$_ ) }),"&nbsp;";
4773		if( $_ eq $router ) {
4774			print $q->b($rtrdesc);
4775		} else {
4776			$lurl = $meurlfull;
4777			$lurl = $routers{$_}{redirect}
4778				if(defined $routers{$_}{redirect});
4779			if( $gstyle =~ /p/ or defined $routers{$_}{redirect}) {
4780			print $q->a({href=>"$lurl?".optionstring({page=>"main", 'if'=>"",
4781				rtr=>"$_"}), target=>"_top", class=>'sidemenu' },$rtrdesc );
4782			} else {
4783			print $q->a({href=>"$lurl?".optionstring({ rtr=>"$_", 'if'=>"" }),
4784				target=>"graph", class=>'sidemenu' },$rtrdesc );
4785			}
4786		}
4787		print "</NOBR>".$q->br."\n";
4788	}
4789	# Now add any  site links
4790	my($mkey,$marg,$mdesc,$micon,$murl,$targ,$level,$insec,$noop);
4791#	my($itemx) = 1;
4792#	while ( defined $config{"menu-item$itemx"} ) {
4793#		$marg = $config{"menu-item$itemx"};
4794#		$mkey = "Item $itemx";
4795#		$itemx += 1;
4796## This way is slower, but more user-friendly
4797    foreach ( sort keys %config ) {
4798	  if( /^menu-(\S+)/i ) {
4799		$mkey = $1;
4800		$marg = $config{$_};
4801
4802		( $mdesc, $murl, $micon, $targ, $level, $insec, $noop ) =
4803			parse_ext($marg);
4804		if($seclevel >= $level ) { # Are we high enough security level?
4805			if( !$micon and $mdesc =~ /\.gif$/ ) {
4806				$micon = $mdesc; $mdesc = $mkey;
4807			}
4808			$mdesc = $mkey if(!$mdesc); #default
4809			$micon = "cog-sm.gif" if(!$micon); #default
4810			if(!$noop and $murl !~ /\.html?$/ ) {
4811				if( $murl =~ /\?/ ) { $murl .= '&'; } else { $murl .= '?'; }
4812				$murl .= "fi=".$q->escape($router)
4813					."&url=".$q->escape($q->url())
4814					."&t=".$q->escape($targ)."&L=".$seclevel;
4815			}
4816			print "<NOBR>";
4817			print $q->img({ src=>($config{'routers.cgi-smalliconurl'}.$micon),
4818				width=>15, height=>15, alt=>"$mdesc", class=>'sidemenu' }),"&nbsp;";
4819			print $q->a({href=>$murl, target=>$targ, class=>'sidemenu' },$mdesc );
4820			print "</NOBR>".$q->br."\n";
4821		} # security level
4822	  } # if
4823	} # foreach
4824}
4825
4826# Finish off the page
4827print "</FONT>\n" if( defined $config{'routers.cgi-menufontsize'} );
4828print "</DIV>\n<!-- Version $VERSION -->\n";
4829print "<!-- R:[$router] I:[$interface] A:[$archive] U:[$authuser] -->\n";
4830print "<!--\n$debugmessage\n-->\n" if($debugmessage);
4831print $q->end_html();
4832}
4833
4834############################
4835# Main frame set
4836
4837sub do_main()
4838{
4839	my( $javascript, $framethree );
4840	my( $urla, $urlb, $urlc, $urlh );
4841	my( $menuwidth ) = 150;
4842	my( $frameopts ) = " marginwidth=2 marginheight=2 bgcolor=$menubgcolour ";
4843	my( $borderwidth ) = 1;
4844
4845	$gtype = "" if(!defined $gtype);
4846	$mtype = "" if(!defined $mtype);
4847	$gstyle = "" if(!defined $gstyle);
4848	$gopts = "" if(!defined $gopts);
4849	$baropts = "cam" if(!defined $baropts);
4850
4851	$borderwidth = $config{'routers.cgi-borderwidth'}
4852		if( defined $config{'routers.cgi-borderwidth'} );
4853
4854	$menuwidth = $config{'routers.cgi-menuwidth'}
4855		if( defined $config{'routers.cgi-menuwidth'} );
4856	$menuwidth = 150 if ( $menuwidth < 100 or $menuwidth > 500
4857		or $menuwidth !~ /^\d+$/ );
4858
4859# Javasciript funtion to reload the page with a specified set of params.
4860	$javascript = "
4861	function makebookmark(rtr,rtrif,xgtype,xgstyle,xgopts,bars,extra,arch) {
4862		var newurl;
4863		newurl = '$meurlfull?rtr='+escape(rtr)+'&if='+escape(rtrif);
4864		if ( xgtype != '' ) { newurl = newurl + '&xgtype='+xgtype; }
4865		if ( xgstyle != '' ) { newurl = newurl + '&xgstyle='+xgstyle; }
4866		if ( xgopts  != '' ) { newurl = newurl + '&xgopts='+xgopts ; }
4867		if ( extra != '' ) { newurl = newurl + '&extra='+escape(extra) ; }
4868		if ( arch != '' ) { newurl = newurl + '&arch='+escape(arch) ; }
4869		if ( bars  != '' && rtrif == '__compact' ) { newurl = newurl + '&bars='+bars ; }
4870		window.location = newurl;
4871	}
4872	function makearchmark(rtr,rtrif,extra,arch) {
4873		var newurl;
4874		newurl = '$meurlfull?rtr='+escape(rtr)+'&if='+escape(rtrif)
4875			+'&archive='+arch;
4876		if ( extra != '' ) { newurl = newurl + '&extra='+escape(extra) ; }
4877		window.location = newurl;
4878	}
4879	var lastaurl;
4880	var lastburl;
4881	function setlocationa(url) {
4882		if( lastaurl != url ) {
4883			self.menu.location = url;
4884			lastaurl = url;
4885		}
4886		return 0;
4887	}
4888	function setlocationb(url) {
4889		if( self.menub ) {
4890			if( lastburl != url ) {
4891				self.menub.location = url;
4892				lastburl = url;
4893			}
4894		}
4895		return 0;
4896	}
4897";
4898
4899	$urlb = $meurlfull."?".optionstring({ page=>"graph", nomenu=>1 });
4900
4901	if( $twinmenu ) {
4902		$urla = $meurlfull."?".optionstring({ page=>"menu", xmtype=>"routers"
4903			  }) ."#top";
4904		$urlc = $meurlfull."?".optionstring({ page=>"menub", xmtype=>"options"
4905			 }) ."#top";
4906		$framethree = "<FRAMESET border=$borderwidth  $frameopts
4907	cols=$menuwidth,*,$menuwidth class=main>
4908  <FRAME name=menu src=$urla scrolling=auto nowrap $frameopts class=main id=leftframe>
4909  <FRAME name=graph src=$urlb scrolling=auto $frameopts class=main id=graphframe>
4910  <FRAME name=menub src=$urlc scrolling=auto nowrap $frameopts class=main id=rightframe>
4911 </FRAMESET>\n";
4912	} else {
4913		$urla = $meurlfull."?".optionstring({ page=>"menu", nomenu=>1 })."#top";
4914		$framethree = "<FRAMESET border=$borderwidth  $frameopts
4915cols=$menuwidth,* >
4916  <FRAME name=menu src=$urla scrolling=auto nowrap $frameopts class=main id=leftframe>
4917  <FRAME name=graph src=$urlb scrolling=auto $frameopts class=main id=graphframe>
4918 </FRAMESET>\n";
4919	}
4920
4921	$urlh = $meurlfull."?".optionstring({ page=>"head" });
4922
4923	if($q->cookie('auth')) {
4924		print "<!-- ".$q->cookie('auth')." -->\n";
4925	}
4926
4927	print "<HTML><HEAD>\n<!-- $pagetype -->\n";
4928	print "<LINK rel=\"stylesheet\" type=\"text/css\" href=\""
4929		.$config{"routers.cgi-stylesheet"}."\" />\n"
4930		if($config{"routers.cgi-stylesheet"});
4931	print "<TITLE>$windowtitle</TITLE></HEAD><SCRIPT language=JavaScript><!--\n$javascript\n//--></SCRIPT>\n";
4932	if(! $q->param('noheader') ) {
4933		print "<FRAMESET border=$borderwidth $frameopts rows=50,* bgcolor=$menubgcolour class=main>\n";
4934		print "<FRAME name=head src=$urlh resize scrolling=no $frameopts class=main id=topframe>\n";
4935	}
4936  	print "$framethree\n";
4937	if(! $q->param('nohead') ) { print "</FRAMESET>\n"; }
4938	print <<EOT
4939<NOFRAMES>
4940 <BODY>
4941  Sorry, routers.cgi does not support non-frames browsers.
4942  Upgrade to Netscape 4.x or later, or MSIE 4.x or later.
4943 </BODY>
4944</NOFRAMES>
4945<!-- Language $language -->
4946<!-- User $authuser -->
4947<!-- Version $VERSION -->
4948<!-- $debugmessage -->
4949<!-- NOTE:
4950     You should not normally run routers.cgi from the command line.  It is
4951     intended to be used as a CGI script, called by your Web Server.  When
4952     installed in this way, you should be able to view the output in your
4953     web browser by calling the CGI script through your web server.
4954     You may want to call it from the command line with the -A parameter
4955     in order to manually create Archived graphs.  In this case, use -D and
4956     -T to specify Device and Target, and -s, -t for Style and Type.
4957     Similarly, the -C option will export CSV data to standard output.
4958     You can use the -U option to specify an authenticated username if required.
4959  -->
4960</HTML>
4961EOT
4962;
4963# now clean up the verify stuff if it's there
4964# we cant do this in the do_verify subroutine because the file is required
4965# by a future connection.
4966unlink ($config{'routers.cgi-graphpath'}.$pathsep."redsquare.png")
4967	if( -f $config{'routers.cgi-graphpath'}.$pathsep."redsquare.png" );
4968
4969}
4970
4971########################
4972# Is this target 'active'?
4973# return 0 (inactive), 1 (active), error message
4974sub isactive($) {
4975	my($curif) = $_[0];
4976	my($start,$end,$interval,$rrd,$data,$names);
4977	my($e,$line,$val);
4978	my(@params)=('MAX'); # Should we use MAX?  Might be confused with -ve data
4979#	my(@params)=('AVG');
4980	my($dwmy,$lastupdate);
4981
4982	# Userdefined!
4983	return "Summaries are always active!"
4984		 if( $interfaces{$curif}{issummary} ); # should never happen
4985	if( $interfaces{$curif}{usergraph} ) {
4986		my ( @ctgt, $t, $r );
4987		foreach $t ( @{$interfaces{$curif}{targets}} ) {
4988			next if( $interfaces{$t}{usergraph} ); # prevent looping
4989			return 1 if( isactive($t) ); # optimise if possible
4990		}
4991		return 0;
4992	}
4993
4994	# If this is an archive, then uselastupdate=2 and rrd is already changed
4995	$rrd = $interfaces{$curif}{rrd};
4996	if($rrdcached and $rrdcached!~/^unix:/) {
4997		my($pth) = $config{'routers.cgi-dbpath'};
4998		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
4999		$rrd =~ s/^$pth\/*//;
5000	}
5001	$dwmy = $gtype;
5002
5003	$end = 'now';
5004	if($uselastupdate) {
5005		$lastupdate = RRDs::last($rrd,@rrdcached);
5006		if($lastupdate) { $end = $lastupdate; }
5007		$end = $archivetime
5008			if($uselastupdate > 1 and $archivetime);
5009		$end = $basetime if($basetime);
5010	}
5011	if( $dwmy =~ /-/ ) {
5012		if ( $dwmy =~ /6/ ) { push @params, "-e", "$end-6h"; }
5013		elsif ( $dwmy =~ /d/ ) { push @params, "-e", "$end-24h";}
5014		elsif ( $dwmy =~ /w/ ) { push @params, "-e", "$end-7d"; }
5015		elsif ( $dwmy =~ /m/ ) { push @params, "-e", "$end-30d";}
5016		elsif ( $dwmy =~ /y/ )  { push @params, "-e", "$end-365d";}
5017	} else {
5018		push @params, '-e', $end;
5019	}
5020	if ( $dwmy =~ /6/ ) { $interval = "60"; }
5021	elsif ( $dwmy =~ /d/ ) { $interval = "300"; }
5022	elsif ( $dwmy =~ /w/ ) { $interval = "1800"; }
5023	elsif ( $dwmy =~ /m/ ) { $interval = "7200"; }
5024	elsif ( $dwmy =~ /y/ ) { $interval = "86400"; }
5025
5026	push @params,'-r',86400; # always use daily max RRA
5027	push @params,'-s',"end-".($interval*400);# just back to start of this graph
5028
5029	($start,$interval,$names,$data) = RRDs::fetch($rrd,@params,@rrdcached);
5030	$e = RRDs::error();
5031	return "Error: $e" if($e); # so erroring targets display by default
5032	foreach $line ( @$data ) {
5033		foreach $val ( @$line ) { return 1 if($val); }
5034	}
5035	return 0;  # not active: no values other than 0 or UNKN were found
5036}
5037
5038##########################
5039# Graph panel
5040
5041sub sinout {
5042	my($interface);
5043	my($sin,$sout,$sext);
5044	my($ssin,$ssout,$ssext);
5045	my($l,$escunit,$escunit2);
5046	my($alt);
5047
5048	($interface,$alt,$l) = @_;
5049
5050	$escunit = $interfaces{$interface}{unit};
5051	$escunit =~ s/%/%%/g;
5052	$escunit =~ s/:/\\:/g;
5053	$escunit =~ s/&nbsp;/ /g;
5054	$escunit2 = $interfaces{$interface}{unit2};
5055	$escunit2 =~ s/%/%%/g;
5056	$escunit2 =~ s/:/\\:/g;
5057	$escunit2 =~ s/&nbsp;/ /g;
5058
5059	$sin=langmsg(6403,"In: "); $sout=langmsg(6404,"Out:"); $sext = "Ext:";
5060	$ssext = $ssin = $ssout = "";
5061	$sin = $interfaces{$interface}{legendi}
5062		if( defined $interfaces{$interface}{legendi} );
5063	$sout= $interfaces{$interface}{legendo}
5064		if( defined $interfaces{$interface}{legendo} );
5065	$sext = $interfaces{$interface}{legendx}
5066		if( defined $interfaces{$interface}{legendx} );
5067
5068	if( $alt and $interfaces{$alt}{overridelegend}
5069		and $interfaces{$interface}{shdesc}
5070		and ( $interfaces{$interface}{noo} or $interfaces{$interface}{noi}
5071		or  $interfaces{$alt}{noo} or $interfaces{$alt}{noi} )
5072	) {
5073		$sin = $sout = $interfaces{$interface}{shdesc}.':';
5074	}
5075
5076	if(!$l) {
5077		$l = length $sin; $l = length $sout if($l < length $sout);
5078	}
5079	$sin = substr($sin.'                ',0,$l);
5080	$sout= substr($sout.'                ',0,$l);
5081	$sin =~ s/:/\\:/g; $sout =~ s/:/\\:/g;
5082	$sin =~ s/%/%%/g; $sout =~ s/%/%%/g;
5083	if( $interfaces{$interface}{integer} ) {
5084		$ssin = "%5.0lf"; $ssout = "%5.0lf"; $ssext = "%5.0lf";
5085	} elsif( $interfaces{$interface}{fixunits}
5086		and !$interfaces{$interface}{exponent} ) {
5087		$ssin = "%7.2lf "; $ssout = "%7.2lf "; $ssext = "%7.2lf";
5088	} else {
5089		$ssin = "%6.2lf %s"; $ssout = "%6.2lf %s"; $ssext = "%6.2lf %s";
5090	}
5091	if( defined $config{'routers.cgi-legendunits'}
5092		and $config{'routers.cgi-legendunits'} =~ /y/i ) {
5093		$ssin .= $escunit; $ssout .= $escunit2;
5094	}
5095	$sin .= $ssin; $sout .= $ssout;
5096	if( $interfaces{$interface}{mode} eq "SERVER"
5097		and $interface eq "CPU" ) {
5098		$sin = "usr\\:%6.2lf%%"; $sout = "sys\\:%6.2lf%%";
5099		$sext = "wa\\: %6.2lf%%";
5100		$ssin = $ssout = $ssext = "%6.2lf%%";
5101	}
5102
5103	return ( $sin,$sout,$sext, $ssin,$ssout,$ssext );
5104}
5105
5106sub usr_params(@)
5107{
5108	my($ds0,$ds1,$mds0,$mds1);
5109	my($lin, $lout);
5110	my($dwmy,$interface) = @_;
5111	my($ssin, $ssout, $sin, $sout, $sext, $ssext);
5112	my($l,$defrrd, $curif);
5113	my($legendi,$legendo);
5114	my(@clr,$ifcnt, $c, $escunit);
5115	my($totindef,$totoutdef,$incnt, $outcnt);
5116	my($totin,$totout) = ("totin","totout");
5117	my($stacking) = 0;
5118	my($mirroring) = 0;
5119	my($max1, $max2);
5120	my($greydef) = "0"; # extra RPN is added if necessary
5121	my($havepeaks) = 0;
5122	my($workday) = 0;
5123#	my($timezone) = 0; # use the global
5124	my(@wdparams) = ();
5125	my($maxlbl,$avglbl,$curlbl,$lastlbl) = ('Max','Avg','Cur','Last');
5126	my($gmaxlbl,$gavglbl,$gcurlbl,$glastlbl);
5127	my(@extraparams) = ();
5128	my($titlemaxlen) = 128;
5129	my($daemonsuffix) = "";
5130	my(@sorted);
5131	my($leglen) = 0; # length of legends
5132
5133	if($rrdcached) {
5134		$daemonsuffix = "daemon=$rrdcached";
5135		$daemonsuffix =~ s/:/\\:/g;
5136		$daemonsuffix = ":$daemonsuffix";
5137	}
5138
5139	$titlemaxlen = $config{'routers.cgi-maxtitle'}?$config{'routers.cgi-maxtitle'}:128;
5140
5141	$maxlbl = langmsg(2200,$maxlbl); $avglbl = langmsg(2201,$avglbl);
5142	$curlbl = langmsg(2202,$curlbl); $lastlbl = langmsg(2203,$lastlbl);
5143	$gmaxlbl = langmsg(6200,$maxlbl); $gavglbl = langmsg(6201,$avglbl);
5144	$gcurlbl = langmsg(6202,$curlbl); $glastlbl = langmsg(6203,$lastlbl);
5145
5146	if( defined $config{'routers.cgi-daystart'}
5147		and defined $config{'routers.cgi-dayend'}
5148		and $config{'routers.cgi-daystart'}<$config{'routers.cgi-dayend'}
5149		and $dwmy !~ /y/ ){
5150		$workday = 1;
5151	}
5152
5153	# stacking?
5154	if( defined $interfaces{$interface}{graphstyle}
5155		and $interfaces{$interface}{graphstyle} =~ /stack/i ) {
5156		$stacking = 1; # first is AREA, then STACK
5157	}
5158	if( defined $interfaces{$interface}{graphstyle}
5159		and $interfaces{$interface}{graphstyle} =~ /mirror/i ) {
5160		$mirroring = 1;
5161	}
5162	# identify colours
5163	if( defined $interfaces{$interface}{colours} ) {
5164		@clr = @{$interfaces{$interface}{colours}};
5165	}
5166	if(! @clr ) {
5167		if( $gstyle =~ /b/ ) {
5168		@clr = ( "#000000","#888888","#cccccc","#dddddd","#666666","#444444",
5169		"#222222", "#aaaaaa", "#eeeeee", "#bbbbbb", "#555555", "#333333" );
5170		} else {
5171		@clr = ( "#0000ff","#00ff00","#ff0000","#00cccc","#cccc00","#cc00cc",
5172		"#8800ff", "#88ff00", "#ff8800", "#0088ff", "#ff0088", "#00ff88" );
5173		}
5174	}
5175	$ifcnt = $#{$interfaces{$interface}{targets}};
5176
5177# Now the workday highlights, if required
5178	if( $workday ) {
5179		# note we must have a DS in there even if it is not used
5180		push @wdparams, "CDEF:wdtest=in1,POP,"
5181			."TIME,3600,/,$timezone,+,DUP,24,/,7,%,DUP,4,LT,EXC,2,GE,+,2,LT,"
5182			."EXC,24,%,DUP,"
5183			.trim($config{'routers.cgi-daystart'}).",GE,EXC,"
5184			.trim($config{'routers.cgi-dayend'}).",LT,+,2,EQ,1,"
5185			."0,IF,0,IF"; # Set to 1 if in working day
5186		# mark the working day background, if not in b&w mode
5187		if( $gstyle !~ /b/ ) {
5188			push @wdparams, "CDEF:wd=wdtest,INF,0,IF", "AREA:wd#ffffcc";
5189			push @wdparams, "CDEF:mwd=wd,-1,*", "AREA:mwd#ffffcc" ;
5190#				if($mirroring);
5191		}
5192	}
5193
5194	while( $#clr < $ifcnt ) { push @clr, @clr; }
5195
5196	$totindef = "CDEF:$totin=0"; $totoutdef = "CDEF:$totout=0";
5197	$ifcnt = 0; $incnt = $outcnt = 0;
5198
5199	if( $interfaces{$interface}{sortby} ) {
5200		@sorted = sorttargets($interface,$dwmy,$interfaces{$interface}{sortby});
5201	} else {
5202		@sorted = @{$interfaces{$interface}{targets}};
5203	}
5204
5205	foreach $curif ( @sorted ) {
5206		if(!$interfaces{$interface}{noo} and !$interfaces{$curif}{noo}) {
5207			my $olen = length $interfaces{$curif}{legendo};
5208			$leglen = $olen if($olen > $leglen);
5209		}
5210		if(!$interfaces{$interface}{noi} and !$interfaces{$curif}{noi}) {
5211			my $ilen = length $interfaces{$curif}{legendi};
5212			$leglen = $ilen if($ilen > $leglen);
5213		}
5214	}
5215	$leglen = 20 if($leglen > 20); # sanity check
5216
5217	###################################################
5218	# MAIN LOOP THROUGH COMPONENT TARGETS STARTS HERE #
5219	###################################################
5220	foreach $curif ( @sorted ) {
5221		# loop through all interfaces
5222
5223		if($interfaces{$interface}{active}) {
5224			next if(!isactive($curif));
5225		}
5226		$ifcnt++;
5227
5228	$defrrd = $interfaces{$curif}{rrd};
5229	$defrrd =~ s/:/\\:/g;
5230	if($rrdcached and $rrdcached!~/^unix:/) {
5231		my($pth) = $config{'routers.cgi-dbpath'};
5232		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
5233		$defrrd =~ s/^$pth\/*//;
5234	}
5235
5236#	$debugmessage .= "RRD: $defrrd\n";
5237
5238	($sin,$sout,$sext ,$ssin,$ssout,$ssext) = sinout($curif,$interface,$leglen);
5239
5240	if ( $dwmy =~ /s/ ) {
5241		$lin=""; $lout="";
5242	} else {
5243		$lin = langmsg(6405,"Inbound"); $lout = langmsg(6406,"Outbound");
5244		$lin = $interfaces{$curif}{legend1}
5245			if( defined $interfaces{$curif}{legend1} );
5246		$lout = $interfaces{$curif}{legend2}
5247			if( defined $interfaces{$curif}{legend2} );
5248		if( $interfaces{$interface}{noo} or $interfaces{$interface}{noi} ) {
5249			$lin = $interfaces{$curif}{desc}." ($lin)"
5250				if($lin ne $interfaces{$curif}{desc});
5251			$lout= $interfaces{$curif}{desc}." ($lout)"
5252				if($lout ne $interfaces{$curif}{desc});
5253		}
5254		$lin =~ s/:/\\:/g; $lout=~ s/:/\\:/g;
5255		$lin = ':'.$lin; $lout = ':'.$lout;
5256		if($interfaces{$interface}{noo} or $interfaces{$curif}{noo}) {
5257 			$lin .= "\\l"
5258		} else { $lout .= "\\l"; }
5259	}
5260	$lin = substr( $lin."                                ",0,30 )
5261		if($lin and !$interfaces{$interface}{noo} and !$interfaces{$curif}{noo});
5262
5263	if( $interfaces{$interface}{nolegend} or
5264		$interfaces{$interface}{nodetails} ) {
5265		$lin = $lout = "";
5266	}
5267
5268	($ds0, $ds1) = ("ds0", "ds1");
5269	push @params,
5270		"DEF:in$ifcnt=".$defrrd.":$ds0:"
5271		.($interfaces{$interface}{cf}?$interfaces{$interface}{cf}:"AVERAGE")
5272		.$daemonsuffix,
5273		"DEF:out$ifcnt=".$defrrd.":$ds1:"
5274		.($interfaces{$interface}{cf}?$interfaces{$interface}{cf}:"AVERAGE")
5275		.$daemonsuffix;
5276	($ds0, $ds1) = ("in$ifcnt", "out$ifcnt");
5277
5278	# Now for unknasprev
5279	if( $interfaces{$curif}{unknasprev}
5280		or $interfaces{$interface}{unknasprev} ) {
5281		if($RRDs::VERSION >= 1.00039 ) {
5282			push @params,
5283				"CDEF:unpin$ifcnt=$ds0,UN,PREV,$ds0,IF",
5284				"CDEF:unpout$ifcnt=$ds1,UN,PREV,$ds1,IF";
5285			($ds0, $ds1) = ("unpin$ifcnt", "unpout$ifcnt");
5286		}
5287	}
5288	# Now for unknaszero
5289	elsif( $interfaces{$curif}{unknaszero}
5290		or  $interfaces{$interface}{unknaszero} ) {
5291		push @params,
5292			"CDEF:unin$ifcnt=$ds0,UN,0,$ds0,IF",
5293			"CDEF:unout$ifcnt=$ds1,UN,0,$ds1,IF";
5294		($ds0, $ds1) = ("unin$ifcnt", "unout$ifcnt");
5295	} else {
5296		if($RRDs::VERSION >= 1.00039 ) {
5297			my($step) = $routers{$router}{interval};
5298			if($step) { $step *= 60; } else { $step = 300; }
5299			push @params,
5300				"CDEF:unxin$ifcnt=NOW,TIME,-,$step,LT,$ds0,UN,+,2,EQ,PREV,$ds0,IF",
5301				"CDEF:unxout$ifcnt=NOW,TIME,-,$step,LT,$ds1,UN,+,2,EQ,PREV,$ds1,IF";
5302			($ds0, $ds1) = ("unxin$ifcnt", "unxout$ifcnt");
5303		}
5304	}
5305
5306	# Needs to be here because ds1 must be defined
5307	push @params, @wdparams if($workday and ($ifcnt == 1));
5308
5309### do this if we are using BITS
5310	if( $interfaces{$curif}{mult} and ($interfaces{$curif}{mult} != 1) ) {
5311		push @params, "CDEF:fin$ifcnt=$ds0,".$interfaces{$curif}{mult}.",*",
5312			"CDEF:fout$ifcnt=$ds1,".$interfaces{$curif}{mult}.",*";
5313		($ds0, $ds1) = ("fin$ifcnt", "fout$ifcnt");
5314	}
5315	if( $interfaces{$curif}{factor} and $interfaces{$curif}{factor}!=1) {
5316		push @params, "CDEF:ffin$ifcnt=$ds0,".$interfaces{$curif}{factor}.",*",
5317			"CDEF:ffout$ifcnt=$ds1,".$interfaces{$curif}{factor}.",*";
5318		($ds0, $ds1) = ("ffin$ifcnt", "ffout$ifcnt");
5319	}
5320	if( $interfaces{$interface}{factor}
5321		and $interfaces{$interface}{factor}!=1) {
5322		push @params, "CDEF:ffinx$ifcnt=$ds0,".$interfaces{$interface}{factor}.",*",
5323			"CDEF:ffoutx$ifcnt=$ds1,".$interfaces{$interface}{factor}.",*";
5324		($ds0, $ds1) = ("ffinx$ifcnt", "ffoutx$ifcnt");
5325	}
5326	if( $interfaces{$curif}{c2fi} ) {
5327		push @params, "CDEF:c2fin$ifcnt=$ds0,1.8,*,32,+";
5328		$ds0 = "c2fin$ifcnt";
5329	}
5330	if( $interfaces{$curif}{c2fo} ) {
5331		push @params, "CDEF:c2fout$ifcnt=$ds1,1.8,*,32,+";
5332		$ds1 = "c2fout$ifcnt";
5333	}
5334
5335	# For later referral by userdefined calculations
5336	$interfaces{$curif}{ds0} = $ds0;
5337	$interfaces{$curif}{ds1} = $ds1;
5338
5339	if(!$interfaces{$curif}{noi} ) {
5340		if($RRDs::VERSION < 1.00039 ) {
5341			$totindef .= ",$ds0,UN,0,$ds0,IF,+";
5342		} else {
5343#			$totindef .= ",$ds0,DUP,UN,EXC,PREV($ds0),DUP,UN,EXC,0,EXC,IF,EXC,IF,+";
5344			$totindef .= ",NOW,TIME,-,300,LT,$ds0,UN,+,2,EQ,PREV($ds0),DUP,UN,EXC,0,EXC,IF,$ds0,IF,+";
5345		}
5346		$incnt++;
5347		if( !$interfaces{$curif}{unknasprev}
5348			and !$interfaces{$interface}{unknasprev}
5349			and !$interfaces{$curif}{unknaszero} ) {
5350			$greydef .= ",in$ifcnt,UN,+";
5351		}
5352	}
5353	if(!$interfaces{$curif}{noo} ) {
5354		if($RRDs::VERSION < 1.00039 ) {
5355			$totoutdef .= ",$ds1,UN,0,$ds1,IF,+";
5356		} else {
5357#			$totoutdef.= ",$ds1,DUP,UN,EXC,PREV($ds1),DUP,UN,EXC,0,EXC,IF,EXC,IF,+";
5358			$totoutdef .= ",NOW,TIME,-,300,LT,$ds1,UN,+,2,EQ,PREV($ds1),DUP,UN,EXC,0,EXC,IF,$ds1,IF,+";
5359		}
5360		$outcnt++;
5361		if( !$interfaces{$curif}{unknasprev}
5362			and !$interfaces{$interface}{unknasprev}
5363			and !$interfaces{$curif}{unknaszero} ) {
5364			$greydef .= ",out$ifcnt,UN,+";
5365		}
5366	}
5367#	now for the peaks stuff
5368	($mds0, $mds1) = ("ds0", "ds1");
5369	push @params,
5370		"DEF:min$ifcnt=".$defrrd.":$mds0:MAX".$daemonsuffix
5371			.(($RRDs::VERSION >= 1.4)?":reduce=MAX":""),
5372		"DEF:mout$ifcnt=".$defrrd.":$mds1:MAX".$daemonsuffix
5373			.(($RRDs::VERSION >= 1.4)?":reduce=MAX":"");
5374	($mds0, $mds1) = ("min$ifcnt", "mout$ifcnt");
5375### Do this if we are using BITS
5376	if( $interfaces{$curif}{mult} ne 1 ) {
5377		push @params, "CDEF:fmin$ifcnt=$mds0,".$interfaces{$curif}{mult}.",*",
5378			"CDEF:fmout$ifcnt=$mds1,".$interfaces{$curif}{mult}.",*";
5379		($mds0, $mds1) = ("fmin$ifcnt", "fmout$ifcnt");
5380	}
5381	if( $interfaces{$curif}{factor} and $interfaces{$curif}{factor}!=1) {
5382		push @params,"CDEF:ffmin$ifcnt=$mds0,"
5383				.$interfaces{$curif}{factor}.",*",
5384			"CDEF:ffmout$ifcnt=$mds1,".$interfaces{$curif}{factor}.",*";
5385		($mds0, $mds1) = ("ffmin$ifcnt", "ffmout$ifcnt");
5386	}
5387	if( $interfaces{$interface}{factor} and $interfaces{$interface}{factor}!=1 ) {
5388		push @params,"CDEF:ffminx$ifcnt=$mds0,"
5389				.$interfaces{$interface}{factor}.",*",
5390			"CDEF:ffmoutx$ifcnt=$mds1,".$interfaces{$interface}{factor}.",*";
5391		($mds0, $mds1) = ("ffminx$ifcnt", "ffmoutx$ifcnt");
5392	}
5393	if( $interfaces{$curif}{c2fi} ) {
5394		push @params, "CDEF:mc2fin$ifcnt=$mds0,1.8,*,32,+";
5395		$mds0 = "mc2fin$ifcnt";
5396	}
5397	if( $interfaces{$curif}{c2fo} ) {
5398		push @params, "CDEF:mc2fout$ifcnt=$mds1,1.8,*,32,+";
5399		$mds1 = "mc2fout$ifcnt";
5400	}
5401
5402	# For later referral by userdefined calculations
5403	$interfaces{$curif}{mds0} = $mds0;
5404	$interfaces{$curif}{mds1} = $mds1;
5405###
5406# And the percentages
5407	$max1 = $max2 = $interfaces{$curif}{max};
5408	$max1 = $interfaces{$curif}{max1} if(defined $interfaces{$curif}{max1});
5409	$max2 = $interfaces{$curif}{max2} if(defined $interfaces{$curif}{max2});
5410	if( $max1 && $dwmy !~ /s/ ) {
5411		push @params,
5412			"CDEF:pcin$ifcnt=$ds0,100,*,".$max1.",/",
5413			"CDEF:mpcin$ifcnt=$mds0,100,*,".$max1.",/";
5414	}
5415	if( $max2 && $dwmy !~ /s/ ) {
5416		push @params,
5417			"CDEF:pcout$ifcnt=$ds1,100,*,".$max2.",/",
5418			"CDEF:mpcout$ifcnt=$mds1,100,*,".$max2.",/";
5419	}
5420
5421	# For scaleshift
5422	if( defined $interfaces{$interface}{scaleshift}
5423		and ($RRDs::VERSION >= 1.3) ) {
5424		if(!$interfaces{$interface}{altscale} or $interfaces{$curif}{altscale}){
5425			push @params,
5426				"CDEF:x$ds1=$ds1,"
5427					.$interfaces{$interface}{shift}.",-,"
5428					.$interfaces{$interface}{scale}.",/";
5429#				"CDEF:x$mds1=$mds1,".$interfaces{$interface}{scale}.",/,"
5430#					.$interfaces{$interface}{shift}.",-";
5431		} else {
5432			push @params, "CDEF:x$ds1=$ds1";
5433#				, "CDEF:x$mds1=$mds1";
5434		}
5435		if($interfaces{$interface}{altscale} and $interfaces{$curif}{altscale}){
5436			push @params,
5437				"CDEF:x$ds0=$ds0,"
5438					.$interfaces{$interface}{shift}.",-,"
5439					.$interfaces{$interface}{scale}.",/";
5440#				"CDEF:x$mds0=$mds0,".$interfaces{$interface}{scale}.",/,"
5441#					.$interfaces{$interface}{shift}.",-";
5442		} else {
5443			push @params, "CDEF:x$ds0=$ds0";
5444#				, "CDEF:x$mds0=$mds0";
5445		}
5446	} else {
5447		push @params, "CDEF:x$ds1=$ds1";
5448#			, "CDEF:x$mds1=$mds1";
5449		push @params, "CDEF:x$ds0=$ds0";
5450#			, "CDEF:x$mds0=$mds0";
5451	}
5452
5453	if($mirroring and $lin and $lout ) {
5454		$lout = "";
5455		$lin = $interfaces{$curif}{desc};
5456		$lin = substr($lin,0,$titlemaxlen) if(length($lin)>$titlemaxlen);
5457		$lin =~ s/:/\\:/g;
5458		$lin = ":$lin\\l";
5459	} else {
5460		if( !$interfaces{$interface}{nolegend} and
5461			!$interfaces{$interface}{nodetails} and
5462			!$interfaces{$interface}{nodesc} and
5463			$dwmy !~ /s/ and
5464			!$interfaces{$interface}{noi} and
5465			!$interfaces{$interface}{noo}) {
5466				my($tmpt) = $interfaces{$curif}{desc};
5467				$tmpt = substr($tmpt,0,$titlemaxlen)
5468					if(length($tmpt)>$titlemaxlen);
5469				push @params, "COMMENT:".decolon("$tmpt:\\l");
5470		}
5471	}
5472	if(! $interfaces{$interface}{nolines} ) {
5473	$c="";
5474	if(!$interfaces{$interface}{noi} and !$interfaces{$curif}{noi}) {
5475		$c = shift @clr; push @clr, $c;
5476		if( !$stacking ) {
5477			push @params, "LINE$linewidth:x$ds0$c$lin" ;
5478		} elsif( $stacking > 1 ) {
5479			push @params, "STACK:$ds0$c$lin" ;
5480		} else {
5481			push @params, "AREA:$ds0$c$lin" ;
5482			$stacking = 2;
5483		}
5484	}
5485	if(!$interfaces{$interface}{noo} and !$interfaces{$curif}{noo}) {
5486		my($tmpds) = $ds1;
5487		$c = "" if( $c and !$mirroring );
5488		if(!$c) { $c = shift @clr; push @clr, $c; }
5489		if($mirroring) {
5490			push @params, "CDEF:mirror$ifcnt=$ds1,-1,*";
5491			$tmpds = "mirror$ifcnt";
5492		} elsif(!$stacking) { $tmpds = "x$ds1"; }
5493		if( !$stacking ) {
5494			push @params, "LINE$linewidth:$tmpds$c$lout" ;
5495		} elsif($mirroring) {
5496			if(@extraparams) {
5497				push @extraparams, "STACK:$tmpds$c$lout";
5498			} else {
5499				push @extraparams, "AREA:$tmpds$c$lout";
5500			}
5501		} elsif( $stacking > 1 ) {
5502			push @params, "STACK:$tmpds$c$lout";
5503		} else {
5504			push @params, "AREA:$tmpds$c$lout";
5505			$stacking = 2;
5506		}
5507	}
5508	} # nolines
5509
5510#	now for the labels at the bottom
5511	if( !$interfaces{$interface}{nolegend} and
5512		!$interfaces{$interface}{nodetails} ) {
5513	if( $dwmy !~ /s/ ) {
5514		if( $max1 ) {
5515			if(!$interfaces{$interface}{noi}
5516				and !$interfaces{$curif}{noi}) {
5517				push @params, "GPRINT:$mds0:MAX:$gmaxlbl $sin\\g" ;
5518				push @params ,"GPRINT:mpcin$ifcnt:MAX: (%2.0lf%%)\\g"
5519					if($interfaces{$curif}{percent});
5520				push @params,"GPRINT:$ds0:AVERAGE:  $gavglbl $sin\\g" ;
5521				push @params ,"GPRINT:pcin$ifcnt:AVERAGE: (%2.0lf%%)\\g"
5522					if($interfaces{$curif}{percent});
5523				push @params,"GPRINT:$ds0:LAST:  $gcurlbl $sin\\g" ;
5524				push @params ,"GPRINT:pcin$ifcnt:LAST: (%2.0lf%%)\\g"
5525					if($interfaces{$curif}{percent});
5526				push @params, "COMMENT:\\l" ;
5527			}
5528			if(!$interfaces{$interface}{noo}
5529				and !$interfaces{$curif}{noo}) {
5530				push @params, "GPRINT:$mds1:MAX:$gmaxlbl $sout\\g" ;
5531				push @params ,"GPRINT:mpcout$ifcnt:MAX: (%2.0lf%%)\\g"
5532					if($interfaces{$curif}{percent});
5533				push @params,"GPRINT:$ds1:AVERAGE:  $gavglbl $sout\\g" ;
5534				push @params ,"GPRINT:pcout$ifcnt:AVERAGE: (%2.0lf%%)\\g"
5535					if($interfaces{$curif}{percent});
5536				push @params,"GPRINT:$ds1:LAST:  $gcurlbl $sout\\g" ;
5537				push @params ,"GPRINT:pcout$ifcnt:LAST: (%2.0lf%%)\\g"
5538					if($interfaces{$curif}{percent});
5539				push @params, "COMMENT:\\l" ;
5540			}
5541		} else {
5542			push @params,
5543			"GPRINT:$mds0:MAX:$gmaxlbl $sin\\g",
5544			"GPRINT:$ds0:AVERAGE:  $gavglbl $sin\\g",
5545			"GPRINT:$ds0:LAST:  $gcurlbl $sin\\l"
5546					if(!$interfaces{$interface}{noi}
5547						and !$interfaces{$curif}{noi});
5548			push @params,
5549			"GPRINT:$mds1:MAX:$gmaxlbl $sout\\g",
5550			"GPRINT:$ds1:AVERAGE:  $gavglbl $sout\\g",
5551			"GPRINT:$ds1:LAST:  $gcurlbl $sout\\l"
5552					if(!$interfaces{$interface}{noo}
5553						and !$interfaces{$curif}{noo});
5554		}
5555	} else {
5556		($legendi,$legendo)=(langmsg(2204,"IN:"),langmsg(2205,"OUT:"));
5557		$legendi = $interfaces{$curif}{legendi} if(defined $interfaces{$curif}{legendi});
5558		$legendo = $interfaces{$curif}{legendo} if(defined $interfaces{$curif}{legendo});
5559		if( $interfaces{$interface}{overridelegend}
5560			and $interfaces{$curif}{shdesc}
5561			and ( $interfaces{$interface}{noo} or $interfaces{$interface}{noi}
5562			or  $interfaces{$curif}{noo} or $interfaces{$curif}{noi} )
5563		) {
5564			$legendi = $legendo = $interfaces{$curif}{shdesc}.':';
5565		}
5566		$legendi =~ s/:/\\:/g; $legendo =~ s/:/\\:/g;
5567		$legendi =~ s/%/%%/g; $legendo =~ s/%/%%/g;
5568
5569#		my $meurlfullesc = $meurlfull;
5570#		$meurlfullesc =~ s/:/\\:/g;
5571		push @params,
5572#			"PRINT:$mds0:MAX:".$q->a({href=>"$meurlfullesc?"
5573#					.optionstring({if=>$curif})},
5574#				$q->b($legendi))." $maxlbl $ssin, ",
5575			"PRINT:$mds0:MAX:".$q->b($legendi)." $maxlbl $ssin, ",
5576			"PRINT:$ds0:AVERAGE:$avglbl $ssin, ",
5577			"PRINT:$ds0:LAST:$lastlbl $ssin ".$q->br
5578					if(!$interfaces{$interface}{noi}
5579						and !$interfaces{$curif}{noi});
5580		push @params,
5581#			"PRINT:$mds1:MAX:".$q->a({href=>"$meurlfullesc?"
5582#					.optionstring({if=>$curif})},
5583#				$q->b($legendo))." $maxlbl $ssout, ",
5584			"PRINT:$mds1:MAX:".$q->b($legendo)." $maxlbl $ssout, ",
5585			"PRINT:$ds1:AVERAGE:$avglbl $ssout, ",
5586			"PRINT:$ds1:LAST:$lastlbl $ssout ".$q->br
5587					if(!$interfaces{$interface}{noo}
5588						and !$interfaces{$curif}{noo});
5589	} # s mode
5590	} # not nolegend mode
5591	} # end of loop through interfaces
5592
5593	# Add onto the end extra interface stuff (for mirroring mainly)
5594	push @params, @extraparams;
5595
5596	# add total line(s) if necessary
5597	if($interfaces{$interface}{withtotal}
5598		or $interfaces{$interface}{withaverage} ) {
5599		push @params, $totindef if(!$interfaces{$interface}{noi} and $incnt);
5600		push @params, $totoutdef if(!$interfaces{$interface}{noo} and $outcnt);
5601		if($interfaces{$interface}{nogroup} and $incnt and $outcnt) {
5602			push @params,"CDEF:totinout=$totin,$totout,+";
5603			$incnt += $outcnt;
5604			$outcnt = 0;
5605			($totin,$totout) = ("totinout","");
5606		}
5607		if(!$interfaces{$interface}{noo} and $outcnt) {
5608			if($interfaces{$interface}{scaleshift}
5609				and !$interfaces{$interface}{altscale}) {
5610				push @params,
5611					"CDEF:x$totout=$totout,"
5612					.$interfaces{$interface}{shift}.",-,"
5613					.$interfaces{$interface}{scale}.",/";
5614			} else {
5615				push @params,"CDEF:x$totout=$totout" ;
5616			}
5617		}
5618		($sin,$sout,$sext ,$ssin,$ssout,$ssext) = sinout($interface,0);
5619		$lin = langmsg(6100,"Total")." ".$interfaces{$interface}{legend1};
5620		$lin = $interfaces{$interface}{legendti}
5621			if($interfaces{$interface}{legendti});
5622		$lin = substr($lin.'                          ',0,30);
5623		if($interfaces{$interface}{noo} or !$outcnt) { $lin .= "\\l"; }
5624		$lout = langmsg(6100,"Total")." ".$interfaces{$interface}{legend2}."\\l";
5625		$lout = $interfaces{$interface}{legendto}."\\l"
5626			if($interfaces{$interface}{legendto});
5627		$lin =~ s/:/\\:/g; $lout=~ s/:/\\:/g;
5628		$lin = ':'.$lin if($lin); $lout = ':'.$lout if($lout);
5629		if($interfaces{$interface}{withtotal} ) {
5630			if($interfaces{$interface}{nolegend} or $dwmy =~ /s/ ) {
5631				$lin = $lout = "";
5632			} elsif($mirroring) {
5633				$lout = "";
5634				$lin = langmsg(6101,"Total values"); $lin =~ s/:/\\:/g;
5635				$lin = ":$lin\\l";
5636			} else {
5637				push @params, "COMMENT:"
5638					.decolon(langmsg(6101,"Total values").":\\l")
5639					if(!$interfaces{$interface}{noi}
5640						and !$interfaces{$interface}{noo}
5641						and !$interfaces{$interface}{nodesc}
5642						and !$interfaces{$interface}{nodetails});
5643			}
5644			$c = "";
5645			if(!$interfaces{$interface}{noi} and $incnt ) {
5646				$c = shift @clr; push @clr, $c;
5647				push @params, "LINE$linewidth:$totin$c$lin";
5648			}
5649			if(!$interfaces{$interface}{noo} and $outcnt ) {
5650				$c = "" if( $c and !$mirroring );
5651				if(!$c) { $c = shift @clr; push @clr, $c;}
5652				if($mirroring) {
5653					push @params, "CDEF:mtotout=$totout,-1,*";
5654					push @params, "LINE$linewidth:mtotout$c$lout";
5655				} else {
5656					push @params, "LINE$linewidth:x$totout$c$lout";
5657				}
5658			}
5659			if( $dwmy !~ /s/ ) {
5660				if(!$interfaces{$interface}{nolegend} ) {
5661				push @params,
5662				"GPRINT:$totin:MAX:$gmaxlbl $sin\\g",
5663				"GPRINT:$totin:AVERAGE:  $gavglbl $sin\\g",
5664				"GPRINT:$totin:LAST:  $gcurlbl $sin\\l"
5665					if(!$interfaces{$interface}{noi} and $incnt);
5666				push @params,
5667				"GPRINT:$totout:MAX:$gmaxlbl $sout\\g",
5668				"GPRINT:$totout:AVERAGE:  $gavglbl $sout\\g",
5669				"GPRINT:$totout:LAST:  $gcurlbl $sout\\l"
5670					if(!$interfaces{$interface}{noo} and $outcnt);
5671				}
5672			} else {
5673				($legendi,$legendo)=(langmsg(2204,"IN:"),langmsg(2205,"OUT:"));
5674				$legendi = $interfaces{$interface}{legendi}
5675					if(defined $interfaces{$interface}{legendi});
5676				$legendo = $interfaces{$interface}{legendo}
5677					if(defined $interfaces{$interface}{legendo});
5678
5679				$legendi =~ s/:/\\:/g;
5680				$legendo =~ s/:/\\:/g;
5681				push @params,
5682					"PRINT:$totin:MAX:".$q->b(langmsg(2100,"Total")."\\:")." $maxlbl $ssin, ",
5683					"PRINT:$totin:AVERAGE:$avglbl $ssin, ",
5684					"PRINT:$totin:LAST:$lastlbl $ssin ".$q->br
5685							if(!$interfaces{$interface}{noi} and $incnt);
5686				push @params,
5687					"PRINT:$totout:MAX:".$q->b(langmsg(2100,"Total")."\\:")." $maxlbl $ssout, ",
5688					"PRINT:$totout:AVERAGE:$avglbl $ssout, ",
5689					"PRINT:$totout:LAST:$lastlbl $ssout ".$q->br
5690							if(!$interfaces{$interface}{noo} and $outcnt);
5691			}
5692		}
5693	}
5694
5695	# add average line if necessary
5696	if($interfaces{$interface}{withaverage} ) {
5697		# set avg to UNKN if we're in greyout, IE we have no data.
5698		push @params,"CDEF:avgin=$greydef,$incnt,$outcnt,+,EQ,UNKN,$totin,$incnt,/,IF"
5699			if(!$interfaces{$interface}{noi} and $incnt);
5700		if(!$interfaces{$interface}{noo} and $outcnt) {
5701			push @params,
5702				"CDEF:avgout=$greydef,$incnt,$outcnt,+,EQ,UNKN,$totout,$outcnt,/,IF";
5703			if($interfaces{$interface}{scaleshift}
5704				and !$interfaces{$interface}{altscale}) {
5705				push @params,
5706					"CDEF:xavgout=avgout,"
5707					.$interfaces{$interface}{shift}.",-,"
5708					.$interfaces{$interface}{scale}.",/";
5709			} else {
5710				push @params,"CDEF:xavgout=avgout" ;
5711			}
5712		}
5713		$lin = "Average ".$interfaces{$interface}{legend1};
5714		$lin = $interfaces{$interface}{legendai}
5715			if($interfaces{$interface}{legendai});
5716		$lin = substr($lin.'                          ',0,30);
5717		$lout= "Average ".$interfaces{$interface}{legend2}."\\l";
5718		if($interfaces{$interface}{noo} or !$outcnt){ $lin .= "\\l"; }
5719		$lout = $interfaces{$interface}{legendao}."\\l"
5720			if($interfaces{$interface}{legendao});
5721		$lin =~ s/:/\\:/g; $lout=~ s/:/\\:/g;
5722		$lin = ':'.$lin if($lin); $lout = ':'.$lout if($lout);
5723		if($interfaces{$interface}{nolegend} or $dwmy=~ /s/ ) {
5724			$lin = $lout = "";
5725		} elsif($mirroring) {
5726			$lout = "";
5727			$lin = langmsg(6901,"Average values"); $lin =~ s/:/\\:/g;
5728			$lin = ":$lin\\l";
5729		} else {
5730			push @params, "COMMENT:"
5731				.decolon(langmsg(6901,"Average values").":\\l")
5732				if(!$interfaces{$interface}{noi}
5733					and !$interfaces{$interface}{noo}
5734					and !$interfaces{$interface}{nodesc}
5735					and !$interfaces{$interface}{nodetails});
5736		}
5737		$c = "";
5738		if(!$interfaces{$interface}{noi} and $incnt) {
5739			$c = shift @clr; push @clr, $c;
5740			push @params, "LINE$linewidth:avgin$c$lin";
5741		}
5742		if(!$interfaces{$interface}{noo} and $outcnt) {
5743			$c = "" if( $c and !$mirroring );
5744			if(!$c) { $c = shift @clr; push @clr, $c;}
5745			if($mirroring) {
5746				push @params, "CDEF:mavgout=avgout,-1,*";
5747				push @params, "LINE$linewidth:mavgout$c$lout";
5748			} else {
5749				push @params, "LINE$linewidth:xavgout$c$lout";
5750			}
5751		}
5752		if( $dwmy !~ /s/ ) {
5753			if(!$interfaces{$interface}{nolegend} ) {
5754				push @params,
5755				"GPRINT:avgin:MAX:$gmaxlbl $sin\\g",
5756				"GPRINT:avgin:AVERAGE:  $gavglbl $sin\\g",
5757				"GPRINT:avgin:LAST:  $gcurlbl $sin\\l"
5758					if(!$interfaces{$interface}{noi} and $incnt);
5759				push @params,
5760				"GPRINT:avgout:MAX:$gmaxlbl $sout\\g",
5761				"GPRINT:avgout:AVERAGE:  $gavglbl $sout\\g",
5762				"GPRINT:avgout:LAST:  $gcurlbl $sout\\l"
5763					if(!$interfaces{$interface}{noo} and $outcnt);
5764			}
5765		} else {
5766			($legendi,$legendo)=(langmsg(2204,"IN:"),langmsg(2205,"OUT:"));
5767			$legendi = $interfaces{$interface}{legendi}
5768				if(defined $interfaces{$interface}{legendi});
5769			$legendo = $interfaces{$interface}{legendo}
5770				if(defined $interfaces{$interface}{legendo});
5771			$legendi =~ s/:/\\:/g;
5772			$legendo =~ s/:/\\:/g;
5773			push @params,
5774				"PRINT:avgin:MAX:".$q->b("$avglbl\\:")." $maxlbl $ssin, ",
5775				"PRINT:avgin:AVERAGE:$avglbl $ssin, ",
5776				"PRINT:avgin:LAST:$lastlbl $ssin ".$q->br
5777						if(!$interfaces{$interface}{noi} and $incnt);
5778			push @params,
5779				"PRINT:avgout:MAX:".$q->b("$avglbl\\:")." $maxlbl $ssout, ",
5780				"PRINT:avgout:AVERAGE:$avglbl $ssout, ",
5781				"PRINT:avgout:LAST:$lastlbl $ssout ".$q->br
5782						if(!$interfaces{$interface}{noo} and $outcnt);
5783		} # small graph
5784	} # with average line
5785
5786	# if there were no lines AT ALL, we need to add a dummy one else
5787	# RRDtool gets unhappy
5788	if(!$ifcnt or (!$incnt and !$outcnt)) {
5789		my($t) = $interfaces{$interface}{targets}[0];
5790		$greydef = "x,x,-"; # this is 'positive' but zero to trigger next sec
5791		$defrrd = $interfaces{$t}{rrd};
5792		$defrrd =~ s/:/\\:/g;
5793		if($daemonsuffix) {
5794			my($pth) = $config{'routers.cgi-dbpath'};
5795			$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
5796			$defrrd =~ s/$pth\/*//;
5797		}
5798		push @params, "DEF:x=$defrrd:ds0:AVERAGE".$daemonsuffix;
5799		$ifcnt = $incnt = $outcnt = 0; # just in case
5800#		$debugmessage .= "Dummy target = $t\nDummy RRD = $defrrd\n";
5801	}
5802
5803	# Greyout if no data at all.
5804	if($greydef) {
5805		$greydef = "CDEF:greyout=$greydef,$incnt,$outcnt,+,EQ,INF,0,IF";
5806		push @params, $greydef, "AREA:greyout#d0d0d0";
5807		if( !$interfaces{$interface}{unknasprev}
5808		    and !$interfaces{$interface}{unknazero}) {
5809			$greydef = "CDEF:mgreyout=greyout,-1,*";
5810			push @params, $greydef, "AREA:mgreyout#d0d0d0";
5811			push @params, "HRULE:0#000000"; # redraw axis
5812		}
5813	}
5814
5815} # usr_params
5816
5817sub rtr_params(@)
5818{
5819	my($ds0,$ds1,$ds2,$mds0,$mds1, $mds2)=("","","","","","");
5820	my($lin, $lout, $mlin, $mlout, $lextra);
5821	my($dwmy,$interface) = @_;
5822	my($ssin, $ssout, $sin, $sout, $ssext, $sext);
5823	my($l,$defrrd);
5824	my($workday) = 0;
5825	my($legendi,$legendo, $legendx);
5826	my(@clr, $escunit);
5827	my($max1, $max2);
5828	my($havepeaks) = 0;
5829	my($graphstyle) = "";
5830	my($maxlbl,$avglbl,$curlbl,$lastlbl) = ('Max','Avg','Cur','Last');
5831	my($gmaxlbl,$gavglbl,$gcurlbl,$glastlbl);
5832	my($cf) = "AVERAGE";
5833	my($daemonsuffix) = "";
5834
5835	if($rrdcached) {
5836		$daemonsuffix = "daemon=$rrdcached";
5837		$daemonsuffix =~ s/:/\\:/g;
5838		$daemonsuffix = ":$daemonsuffix";
5839	}
5840
5841	$maxlbl = langmsg(2200,$maxlbl); $avglbl = langmsg(2201,$avglbl);
5842	$curlbl = langmsg(2202,$curlbl); $lastlbl = langmsg(2203,$lastlbl);
5843	$gmaxlbl = langmsg(6200,$maxlbl); $gavglbl = langmsg(6201,$avglbl);
5844	$gcurlbl = langmsg(6202,$curlbl); $glastlbl = langmsg(6203,$lastlbl);
5845
5846	$graphstyle = lc $interfaces{$interface}{graphstyle}
5847		if( $interfaces{$interface}{graphstyle} );
5848	# are we going to add peak lines on this graph?
5849	if($graphstyle !~ /stack/ ) {
5850		if(!defined $config{'routers.cgi-withpeak'}
5851			or $config{'routers.cgi-withpeak'} =~ /y/i ) {
5852			if( $dwmy =~ /[wmy]/ or ( $dwmy =~ /d/ and $usesixhour )) {
5853				my($pat) = '';
5854				if( defined $interfaces{$interface}{withpeak} ) {
5855					$pat = '[a'.$interfaces{$interface}{withpeak}.']';
5856					$havepeaks = 1 if( $dwmy =~ /$pat/i );
5857				} else { $havepeaks = 1; }
5858			}
5859		}
5860	}
5861
5862	# are we going to work out the 'working day' averages as well?
5863	if( defined $config{'routers.cgi-daystart'}
5864		and defined $config{'routers.cgi-dayend'}
5865		and $config{'routers.cgi-daystart'}<$config{'routers.cgi-dayend'}
5866		and $dwmy !~ /y/ ){
5867		$workday = 1;
5868	}
5869
5870	# identify colours
5871	if( defined $interfaces{$interface}{colours} ) {
5872		@clr = @{$interfaces{$interface}{colours}};
5873	}
5874	if(! @clr ) {
5875		if( $gstyle =~ /b/ ) {
5876			@clr =  ("#888888", "#000000", "#cccccc","#444444", "#222222");
5877		} else {
5878			@clr = ("#00cc00", "#0000ff","#006600", "#ff00ff", "#ff0000" );
5879		}
5880	}
5881
5882	$defrrd = $interfaces{$interface}{rrd};
5883	$defrrd =~ s/:/\\:/g;
5884	if($rrdcached and $rrdcached!~/^unix:/) {
5885		my($pth) = $config{'routers.cgi-dbpath'};
5886		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
5887		$defrrd =~ s/^$pth\/*//;
5888	}
5889
5890	$debugmessage .= "RRD: $defrrd\n";
5891
5892	$escunit = $interfaces{$interface}{unit};
5893	$escunit =~ s/%/%%/g;
5894	$escunit =~ s/:/\\:/g;
5895	$escunit =~ s/&nbsp;/ /g;
5896
5897	($sin,$sout,$sext,$ssin,$ssout,$ssext) = sinout($interface,0);
5898
5899	if ( $dwmy =~ /s/ ) {
5900		$lin=""; $lout=""; $lextra="";
5901		$mlin=""; $mlout="";
5902	} else {
5903		$lin = langmsg(6405,"Inbound"); $lout = langmsg(6406,"Outbound");
5904		$mlin = langmsg(6407,"Peak Inbound");
5905		$mlout = langmsg(6408,"Peak Outbound");
5906		$lin = $interfaces{$interface}{legend1}
5907			if( defined $interfaces{$interface}{legend1} );
5908		$lout = $interfaces{$interface}{legend2}
5909			if( defined $interfaces{$interface}{legend2} );
5910		$mlin = $interfaces{$interface}{legend3}
5911			if( defined $interfaces{$interface}{legend3} );
5912		$mlout = $interfaces{$interface}{legend4}
5913			if( defined $interfaces{$interface}{legend4} );
5914		if($interfaces{$interface}{noo} or $havepeaks
5915			or ( $graphstyle =~ /range/i )) {
5916				$lin .= "\\l";
5917		}
5918		$lextra = "Other\\l";
5919		$lextra = $interfaces{$interface}{legend5}."\\l"
5920			if( defined $interfaces{$interface}{legend5} );
5921		$lin =~ s/:/\\:/g; $mlin =~ s/:/\\:/g;
5922		$lout =~ s/:/\\:/g; $mlout =~ s/:/\\:/g;
5923		$lin = ':'.$lin; $lout = ':'.$lout;
5924		$mlin = ':'.$mlin; $mlout = ':'.$mlout;
5925		$lextra = ':'.$lextra;
5926	}
5927	$lout .= "\\l" if($lout);
5928	$lin = substr( $lin."                                ",0,30 )
5929		if($lin and !$interfaces{$interface}{noo}
5930			and $lin !~ /\\l$/ );
5931	$mlout = substr( $mlout."                                ",0,30 )
5932		if ($mlout);
5933	$mlin = substr( $mlin."                                ",0,30 )
5934		if ($mlin);
5935
5936	if( $interfaces{$interface}{nolegend} ) { $mlin = $lin = $mlout = $lout = ""; }
5937
5938	($ds0, $ds1) = ("ds0", "ds1");
5939	if( $interfaces{$interface}{mode} eq "SERVER" ) {
5940		($ds0, $ds1, $ds2) = ("user", "system", "wait") if($interface eq "CPU");
5941		($ds0, $ds1) = ("page", "page") if($interface eq "Page");
5942		($ds0, $ds1) = ("usercount", "usercount") if($interface eq "Users");
5943	}
5944	push @params,
5945		"DEF:in=".$defrrd.":$ds0:"
5946		.($interfaces{$interface}{cf}?$interfaces{$interface}{cf}:"AVERAGE")
5947		.$daemonsuffix,
5948		"DEF:out=".$defrrd.":$ds1:"
5949		.($interfaces{$interface}{cf}?$interfaces{$interface}{cf}:"AVERAGE")
5950		.$daemonsuffix;
5951	push @params,
5952		"DEF:extra=".$defrrd.":$ds2:"
5953		.($interfaces{$interface}{cf}?$interfaces{$interface}{cf}:"AVERAGE")
5954		.$daemonsuffix
5955			if($ds2);
5956	($ds0, $ds1) = ("in", "out");
5957	$ds2 = "extra" if($ds2);
5958# Try to get around the race condition... This also hides the first UNK point
5959#	if($RRDs::VERSION >= 1.00039 ) {
5960#		push @params,
5961#			"CDEF:racein=$ds0,UN,PREV($ds0),$ds0,IF",
5962#			"CDEF:raceout=$ds1,UN,PREV($ds1),$ds1,IF";
5963#		($ds0, $ds1) = ("racein", "raceout");
5964#	}
5965# Now for unknasprev
5966	if( $interfaces{$interface}{unknasprev} ) {
5967		if($RRDs::VERSION >= 1.00039 ) {
5968			push @params,
5969				"CDEF:unpin=$ds0,UN,PREV,$ds0,IF",
5970				"CDEF:unpout=$ds1,UN,PREV,$ds1,IF";
5971			($ds0, $ds1) = ("unpin", "unpout");
5972		}
5973	} elsif( $interfaces{$interface}{unknaszero} ) {
5974# Now for unknaszero
5975		push @params,
5976			"CDEF:unin=$ds0,UN,0,$ds0,IF",
5977			"CDEF:unout=$ds1,UN,0,$ds1,IF";
5978		($ds0, $ds1) = ("unin", "unout");
5979	} else {
5980		if($RRDs::VERSION >= 1.00039 ) {
5981			my($step) = $routers{$router}{interval};
5982			if($step) { $step *= 60; } else { $step = 300; }
5983			push @params,
5984				"CDEF:unxin=NOW,TIME,-,$step,LT,$ds0,UN,+,2,EQ,PREV,$ds0,IF",
5985				"CDEF:unxout=NOW,TIME,-,$step,LT,$ds1,UN,+,2,EQ,PREV,$ds1,IF";
5986			($ds0, $ds1) = ("unxin", "unxout");
5987		}
5988	}
5989	if( $interfaces{$interface}{c2fi} ) {
5990		push @params, "CDEF:c2fin=$ds0,1.8,*,32,+";
5991		$ds0 = "c2fin";
5992	}
5993	if( $interfaces{$interface}{c2fo} ) {
5994		push @params, "CDEF:c2fout=$ds1,1.8,*,32,+";
5995		$ds1 = "c2fout";
5996	}
5997### do this if we are using BITS
5998	if( $interfaces{$interface}{mult} and ($interfaces{$interface}{mult}!=1) ) {
5999		push @params, "CDEF:fin=$ds0,".$interfaces{$interface}{mult}.",*",
6000			"CDEF:fout=$ds1,".$interfaces{$interface}{mult}.",*";
6001		($ds0, $ds1) = ("fin", "fout");
6002	}
6003###
6004	if( defined $interfaces{$interface}{factor} and $interfaces{$interface}{factor}!=1 ) {
6005		push @params, "CDEF:ffin=$ds0,".$interfaces{$interface}{factor}.",*",
6006			"CDEF:ffout=$ds1,".$interfaces{$interface}{factor}.",*";
6007		($ds0, $ds1) = ("ffin", "ffout");
6008	}
6009#	now for the peaks stuff
6010	($mds0, $mds1) = ("ds0", "ds1");
6011	if( $interfaces{$interface}{mode} eq "SERVER" ) {
6012		($mds0,$mds1,$mds2) = ("user","system","wait") if($interface eq "CPU");
6013		($mds0,$mds1) = ("page", "page") if($interface eq "Page");
6014		($mds0,$mds1) = ("usercount", "usercount") if($interface eq "Users");
6015	}
6016	push @params,
6017		"DEF:min=".$defrrd.":$mds0:MAX".$daemonsuffix
6018			.(($RRDs::VERSION >= 1.4)?":reduce=MAX":""),
6019		"DEF:mout=".$defrrd.":$mds1:MAX".$daemonsuffix
6020			.(($RRDs::VERSION >= 1.4)?":reduce=MAX":"");
6021	($mds0, $mds1) = ("min", "mout");
6022	if( $interfaces{$interface}{mode} eq "SERVER" and $mds2 ) {
6023		push @params, "DEF:mx=".$defrrd.":$mds2:MAX".$daemonsuffix
6024			.(($RRDs::VERSION >= 1.4)?":reduce=MAX":"");
6025		$mds2 = "mx";
6026	}
6027### Do this if we are using BITS
6028	if( $interfaces{$interface}{mult} and ($interfaces{$interface}{mult}!=1)) {
6029		push @params, "CDEF:fmin=$mds0,".$interfaces{$interface}{mult}.",*",
6030			"CDEF:fmout=$mds1,".$interfaces{$interface}{mult}.",*";
6031		($mds0, $mds1) = ("fmin", "fmout");
6032	}
6033###
6034	if( defined $interfaces{$interface}{factor} and $interfaces{$interface}{factor}!=1 ) {
6035		push @params, "CDEF:ffmin=$mds0,".$interfaces{$interface}{factor}.",*",
6036			"CDEF:ffmout=$mds1,".$interfaces{$interface}{factor}.",*";
6037		($mds0, $mds1) = ("ffmin", "ffmout");
6038	}
6039	if( $interfaces{$interface}{c2fi} ) {
6040		push @params, "CDEF:mc2fin=$mds0,1.8,*,32,+";
6041		$mds0 = "mc2fin";
6042	}
6043	if( $interfaces{$interface}{c2fo} ) {
6044		push @params, "CDEF:mc2fout=$mds1,1.8,*,32,+";
6045		$mds1 = "mc2fout";
6046	}
6047
6048# Do the maxima
6049	$max1 = $max2 = $interfaces{$interface}{max};
6050	$max1 = $interfaces{$interface}{max1}
6051		if(defined $interfaces{$interface}{max1});
6052	$max2 = $interfaces{$interface}{max2}
6053		if(defined $interfaces{$interface}{max2});
6054# Reverse calculations
6055	if($interfaces{$interface}{'reverse'}) {
6056		push @params,
6057			"CDEF:rin=$max1,$ds0,-",
6058			"CDEF:mrin=$max1,$mds0,-",
6059			"CDEF:rout=$max2,$ds1,-",
6060			"CDEF:mrout=$max2,$mds1,-";
6061		($ds0, $ds1) = ("rin", "rout");
6062		($mds0, $mds1) = ("mrin", "mrout");
6063	}
6064# And the percentages
6065	if($interfaces{$interface}{aspercent}) {
6066		push @params,
6067			"CDEF:pcin=$ds0,100,*,$max1,/",
6068			"CDEF:mpcin=$mds0,100,*,$max1,/",
6069			"CDEF:pcout=$ds1,100,*,$max2,/",
6070			"CDEF:mpcout=$mds1,100,*,$max2,/";
6071		($mds0, $mds1) = ("mpcin", "mpcout");
6072		($ds0, $ds1) = ("pcin", "pcout");
6073	} elsif($interfaces{$interface}{dorelpercent}) {
6074		# what if ds1=0? No way to avoid potential /0
6075		push @params,
6076			"CDEF:pcin=$ds0,100,*,$ds1,/",
6077			"CDEF:mpcin=$mds0,100,*,$mds1,/";
6078		$mds0 = "mpcin"; # note we don't care about OUT as this implies NOO
6079		$ds0 = "pcin";
6080	} else {
6081		if( $max1 && $dwmy !~ /s/ ) {
6082			push @params,
6083				"CDEF:pcin=$ds0,100,*,$max1,/",
6084				"CDEF:mpcin=$mds0,100,*,$max1,/";
6085		}
6086		if( $max2 && $dwmy !~ /s/ ) {
6087			push @params,
6088				"CDEF:pcout=$ds1,100,*,$max2,/",
6089				"CDEF:mpcout=$mds1,100,*,$max2,/";
6090		}
6091	}
6092
6093# Now the workday averages, if required
6094	if( $workday ) {
6095		# note we must have a DS in there even if it is not used
6096		push @params, "CDEF:wdtest=$ds0,POP,"
6097			."TIME,3600,/,$timezone,+,DUP,24,/,7,%,DUP,4,LT,EXC,2,GE,+,2,LT,"
6098			."EXC,24,%,DUP,"
6099			.trim($config{'routers.cgi-daystart'}).",GE,EXC,"
6100			.trim($config{'routers.cgi-dayend'}).",LT,+,2,EQ,1,"
6101			."0,IF,0,IF"; # Set to 1 if in working day
6102		push @params, "CDEF:wdin=wdtest,$ds0,UNKN,IF",
6103			"CDEF:wdout=wdtest,$ds1,UNKN,IF";
6104		push @params, "CDEF:wdx=wdtest,$ds2,UNKN,IF" if($ds2);
6105		# mark the working day background, if not in b&w mode
6106		if( $gstyle !~ /b/ ) {
6107			push @params, "CDEF:wd=wdtest,INF,0,IF", "AREA:wd#ffffcc";
6108#			if($graphstyle=~/mirror/) {
6109				push @params, "CDEF:mwd=wd,-1,*", "AREA:mwd#ffffcc";
6110#			}
6111		}
6112	}
6113
6114	if( $interfaces{$interface}{available} ) {
6115		# availability percentage
6116		push @params, "CDEF:apc=in,UN,out,UN,+,2,EQ,0,100,IF";
6117		# Now, the average of apc is the percentage availability!
6118	}
6119
6120	# For the scaleshift
6121	if( defined $interfaces{$interface}{scaleshift}
6122		and ($RRDs::VERSION >= 1.3) ) {
6123		push @params,
6124			"CDEF:x$ds1=$ds1,"
6125				.$interfaces{$interface}{shift}.",-,"
6126				.$interfaces{$interface}{scale}.",/",
6127			"CDEF:x$mds1=$mds1,"
6128				.$interfaces{$interface}{shift}.",-,"
6129				.$interfaces{$interface}{scale}.",/";
6130	} else {
6131		push @params, "CDEF:x$ds1=$ds1", "CDEF:x$mds1=$mds1";
6132	}
6133
6134	if( $interfaces{$interface}{mode} eq "SERVER" and $ds2 ) {
6135		push @params, "AREA:$ds0".$clr[0].$lin,
6136			"STACK:$ds1".$clr[1].$lout,
6137			"STACK:$ds2".$clr[4].$lextra;
6138	} else {
6139#	now for the actual lines : put the peaklines for d only if we have a 6 hr
6140#	dont forget to use more friendly colours if this is black and white mode
6141		push @params, "LINE$linewidth:$mds0".$clr[2].$mlin
6142			if($havepeaks and !$interfaces{$interface}{noi});
6143			# outbound is done later...
6144		if(!$interfaces{$interface}{noi}) {
6145			if( $graphstyle =~ /lines/i ) {
6146				push @params, "LINE$linewidth:$ds0".$clr[0].$lin;
6147			} else {
6148				push @params, "AREA:$ds0".$clr[0].$lin;
6149			}
6150		}
6151		if(!$interfaces{$interface}{noo}) {
6152			if( $graphstyle =~ /stack/i ) {
6153				push @params, "STACK:$ds1".$clr[1].$lout;
6154			} elsif( $graphstyle =~ /range/i ) {
6155				push @params, "AREA:$ds1#ffffff"; # erase lower part
6156				# if workingday active, put HIGHLIGHTED lower in
6157				if( $workday and $gstyle !~ /b/) {
6158					push @params, "CDEF:lwday=wdin,UN,0,$ds1,IF",
6159						"AREA:lwday#ffffcc";
6160				}
6161				push @params, "LINE$linewidth:$ds1".$clr[0]; # replace last pixel
6162			} elsif( $graphstyle =~ /mirror/i ) {
6163				if($havepeaks) {
6164					push @params, "CDEF:mmirror=$mds1,-1,*";
6165					push @params, "LINE$linewidth:mmirror".$clr[3].$mlout;
6166				}
6167				push @params, "CDEF:mirror=$ds1,-1,*";
6168				push @params, "AREA:mirror".$clr[1].$lout;
6169			} else {
6170				# we do it here so it isnt overwritten by the incoming area
6171				if($havepeaks) {
6172					push @params, "LINE$linewidth:x$mds1".$clr[3].$mlout;
6173				} # with peaks
6174				push @params, "LINE$linewidth:x$ds1".$clr[1].$lout;
6175			}
6176		}
6177	} # server mode
6178
6179# data unavailable
6180	if(!$interfaces{$interface}{unknaszero}
6181		and !$interfaces{$interface}{unknasprev}) {
6182		push @params,
6183		"CDEF:down=in,UN,out,UN,+,2,EQ,INF,0,IF","AREA:down#d0d0d0";
6184#		if($graphstyle=~/mirror/i) {
6185		push @params, "CDEF:mdown=down,-1,*","AREA:mdown#d0d0d0";
6186		push @params, "HRULE:0#000000";
6187#		}
6188	}
6189# thresholds
6190	if( $dwmy !~ /s/ and !$interfaces{$interface}{nothresholds} ) {
6191	my($tdone) = 0; my( $tlab ) = "";
6192	my($tlabbit);
6193	foreach ( qw/i o/ ) {
6194		$tlabbit = "";
6195		if(defined $interfaces{$interface}{"threshmin$_"}) {
6196			$tlabbit = doformat($interfaces{$interface}{"threshmin$_"},
6197					$interfaces{$interface}{fixunits},0)
6198				.$interfaces{$interface}{unit};
6199		}
6200		if(defined $interfaces{$interface}{"threshmax$_"}) {
6201			$tlabbit .= ", " if($tlabbit);
6202			$tlabbit .= doformat($interfaces{$interface}{"threshmax$_"},
6203					$interfaces{$interface}{fixunits},0)
6204				.$interfaces{$interface}{unit};
6205		}
6206		if($tlabbit) {
6207			$tlab .= " (".$interfaces{$interface}{"legend$_"}." ".$tlabbit.")";
6208		}
6209	}
6210	$tlab =~ s/:/\\:/g;
6211	foreach my $thresh ( qw/maxi maxo mini mino/ ) {
6212		if(defined $interfaces{$interface}{"thresh$thresh"} ) {
6213			my($tval) = $interfaces{$interface}{"thresh$thresh"};
6214			if( $graphstyle =~ /mirror/ and $thresh =~ /o$/ ) {
6215				$tval = -$tval;
6216			}
6217			if($tdone) {
6218				push @params, "HRULE:".$tval."#ffa0a0";
6219			} else {
6220				push @params, "HRULE:".$tval."#ffa0a0:"
6221					.langmsg(6105,"Thresholds")."$tlab\\l";
6222				$tdone = 1;
6223			}
6224		}
6225	} # foreach
6226	} # dwmy != s
6227# the max line
6228	if($interfaces{$interface}{aspercent}
6229		or $interfaces{$interface}{dorelpercent}) {
6230		$interfaces{$interface}{max} = 100;
6231		$interfaces{$interface}{max1} = 100;
6232		$interfaces{$interface}{max2} = 100;
6233	}
6234	if( $interfaces{$interface}{max}
6235		and ! ( defined $config{'routers.cgi-maxima'}
6236			and  $config{'routers.cgi-maxima'} =~ /n/i )
6237		and !$interfaces{$interface}{nomax}
6238	) {
6239		my( $lmax ) = "";
6240		my( $lamax ) = "";
6241		my( $lcol ) = "#ff0000";
6242		$lcol = "#cccccc" if( $gstyle =~ /b/ );
6243		if( $dwmy !~ /s/ ) {
6244			if( defined $interfaces{$interface}{mblegend} ) {
6245				$lmax = $interfaces{$interface}{mblegend};
6246				$lmax =~ s/:/\\:/g; $lmax = ':'.$lmax;
6247			} elsif( $interfaces{$interface}{isif} ) {
6248				$lmax =":100% ".langmsg(6103,"Bandwidth");
6249			} else { $lmax =":".langmsg(6102,"Maximum"); }
6250			if( $max1 and $max2 and ($max1 != $max2) ) {
6251			$lmax .= " (".doformat($max1,$interfaces{$interface}{fixunits},0)
6252				.$interfaces{$interface}{unit}.","
6253				.doformat($max2,$interfaces{$interface}{fixunits},0)
6254				.$interfaces{$interface}{unit}.")\\l";
6255			} else {
6256			$lmax .= " (".doformat($interfaces{$interface}{max},
6257					$interfaces{$interface}{fixunits},0)
6258				.$interfaces{$interface}{unit}.")\\l";
6259			}
6260			if( defined $interfaces{$interface}{absmax} ) {
6261				if( defined $interfaces{$interface}{amlegend} ) {
6262					$lamax = ":".$interfaces{$interface}{amlegend};
6263				} else { $lamax =":".langmsg(6104,"Hard Maximum"); }
6264				$lamax .= " (".doformat($interfaces{$interface}{absmax},
6265					$interfaces{$interface}{fixunits},1)
6266					.$interfaces{$interface}{unit}.")\\l";
6267			}
6268			if($interfaces{$interface}{aspercent}
6269				or $interfaces{$interface}{aspercent}) { $lmax=""; }
6270		}
6271		if( $graphstyle =~ /mirror/ ) {
6272			$max1 = $interfaces{$interface}{max} if(!$max1);
6273			$max2 = -$interfaces{$interface}{max} if(!$max2);
6274			$max2 = -$max2 if($max2>0); # put it below the axis!
6275		}
6276		if( $max1 and $max2 and ($max1 != $max2)) {
6277			push @params, "HRULE:".$max1.$lcol.$lmax;
6278			push @params, "HRULE:".$max2.$lcol;
6279		} else {
6280			push @params, "HRULE:".$interfaces{$interface}{max}.$lcol.$lmax;
6281		}
6282		if( defined $interfaces{$interface}{absmax}
6283			and !$interfaces{$interface}{noabsmax} ) {
6284			if( $gstyle =~ /b/ ) {
6285				push @params, "HRULE:".$interfaces{$interface}{absmax}
6286					."#aaaaaa$lamax";
6287			} else {
6288				push @params, "HRULE:".$interfaces{$interface}{absmax}
6289					."#ff0080$lamax";
6290			}
6291			if( $graphstyle =~ /mirror/ ) {
6292				if( $gstyle =~ /b/ ) {
6293					push @params, "HRULE:-".$interfaces{$interface}{absmax}
6294						."#aaaaaa";
6295				} else {
6296					push @params, "HRULE:-".$interfaces{$interface}{absmax}
6297						."#ff0080";
6298				}
6299			}
6300		}
6301	}
6302#	now for the labels at the bottom
6303	if( $dwmy !~ /s/
6304		and !$interfaces{$interface}{nodetails}
6305		and !$interfaces{$interface}{nolegend}
6306	) {
6307		if( $max1 ) {
6308			if(!$interfaces{$interface}{noi}) {
6309				push @params, "GPRINT:$mds0:MAX:$gmaxlbl $sin\\g" ;
6310				push @params ,"GPRINT:mpcin:MAX: (%2.0lf%%)\\g"
6311					if($interfaces{$interface}{percent});
6312				push @params,"GPRINT:$ds0:AVERAGE:  $gavglbl $sin\\g" ;
6313				push @params ,"GPRINT:pcin:AVERAGE: (%2.0lf%%)\\g"
6314					if($interfaces{$interface}{percent});
6315				push @params,"GPRINT:$ds0:LAST:  $gcurlbl $sin\\g" ;
6316				push @params ,"GPRINT:pcin:LAST: (%2.0lf%%)\\g"
6317					if($interfaces{$interface}{percent});
6318				push @params, "COMMENT:\\l" ;
6319			}
6320			if(!$interfaces{$interface}{noo}) {
6321				push @params, "GPRINT:$mds1:MAX:$gmaxlbl $sout\\g" ;
6322				push @params ,"GPRINT:mpcout:MAX: (%2.0lf%%)\\g"
6323					if($interfaces{$interface}{percent});
6324				push @params,"GPRINT:$ds1:AVERAGE:  $gavglbl $sout\\g" ;
6325				push @params ,"GPRINT:pcout:AVERAGE: (%2.0lf%%)\\g"
6326					if($interfaces{$interface}{percent});
6327				push @params,"GPRINT:$ds1:LAST:  $gcurlbl $sout\\g" ;
6328				push @params ,"GPRINT:pcout:LAST: (%2.0lf%%)\\g"
6329					if($interfaces{$interface}{percent});
6330				push @params, "COMMENT:\\l" ;
6331			}
6332			if($ds2) {
6333				push @params, "GPRINT:$mds2:MAX:$gmaxlbl $sext\\g" ;
6334				push @params,"GPRINT:$ds2:AVERAGE:  $gavglbl $sext\\g" ;
6335				push @params,"GPRINT:$ds2:LAST:  $gcurlbl $sext\\g" ;
6336				push @params, "COMMENT:\\l" ;
6337			}
6338			if($workday) {
6339				push @params, "COMMENT:".decolon(langmsg(6106,"Working day averages")."\\g");
6340				push @params,"GPRINT:wdin:AVERAGE: $sin\\g"
6341					if(!$interfaces{$interface}{noi});
6342				push @params,"GPRINT:wdout:AVERAGE: $sout\\g"
6343					if(!$interfaces{$interface}{noo});
6344				push @params,"GPRINT:wdx:AVERAGE: $sext\\g"
6345					if($ds2);
6346				push @params, "COMMENT:\\l";
6347			}
6348			if( defined $config{'routers.cgi-maxima'}
6349				and $config{'routers.cgi-maxima'} =~ /n/i
6350				and !$interfaces{$interface}{nomax} ) {
6351				my( $comment );
6352				if(defined $interfaces{$interface}{mblegend}) {
6353					$comment = $interfaces{$interface}{mblegend};
6354					$comment = "COMMENT:".decolon($comment);
6355				} elsif($interfaces{$interface}{isif}) {
6356					$comment = "COMMENT:100% ".decolon(langmsg(6103,"Bandwidth"));
6357				} else {
6358					$comment = "COMMENT:".decolon(langmsg(6102,"Maximum value"));
6359				}
6360				$comment .= decolon(" ".doformat($interfaces{$interface}{max},
6361						$interfaces{$interface}{fixunits},0)
6362					.$escunit."\\l");
6363				push @params, $comment;
6364 		 	}
6365		} else {
6366			push @params,
6367				"GPRINT:$mds0:MAX:$gmaxlbl $sin\\g",
6368				"GPRINT:$ds0:AVERAGE:  $gavglbl $sin\\g",
6369				"GPRINT:$ds0:LAST:  $gcurlbl $sin\\l"
6370					if(!$interfaces{$interface}{noi});
6371			push @params,
6372				"GPRINT:$mds1:MAX:$gmaxlbl $sout\\g",
6373				"GPRINT:$ds1:AVERAGE:  $gavglbl $sout\\g",
6374				"GPRINT:$ds1:LAST:  $gcurlbl $sout\\l"
6375					if(!$interfaces{$interface}{noo});
6376			push @params,
6377				"GPRINT:$mds2:MAX:$gmaxlbl $sext\\g",
6378				"GPRINT:$ds2:AVERAGE:  $gavglbl $sext\\g",
6379				"GPRINT:$ds2:LAST:  $gcurlbl $sext\\l"
6380					if($ds2);
6381			if($workday) {
6382				push @params, "COMMENT:".decolon(langmsg(6106,"Working day averages")."\\g");
6383				push @params,"GPRINT:wdin:AVERAGE: $sin\\g"
6384					if(!$interfaces{$interface}{noi});
6385				push @params,"GPRINT:wdout:AVERAGE: $sout\\g"
6386					if(!$interfaces{$interface}{noo});
6387				push @params,"GPRINT:wdx:AVERAGE: $sext\\g"
6388					if($ds2);
6389				push @params, "COMMENT:\\l";
6390			}
6391		}
6392		if( $interfaces{$interface}{available} ) {
6393			push @params, "GPRINT:apc:AVERAGE:".langmsg(6107,"Data availability")."\\: %.2lf%%\\l";
6394		}
6395	} else {
6396		($legendi,$legendo,$legendx)
6397			= (langmsg(2204,"IN:"),langmsg(2205,"OUT:"),"");
6398		$legendi = $interfaces{$interface}{legendi}
6399			if(defined $interfaces{$interface}{legendi});
6400		$legendo = $interfaces{$interface}{legendo}
6401			if(defined $interfaces{$interface}{legendo});
6402		$legendx = $interfaces{$interface}{legendx}
6403			if(defined $interfaces{$interface}{legendx});
6404		$legendi =~ s/:/\\:/g; $legendo =~ s/:/\\:/g; $legendx=~s/:/\\:/g;
6405		$legendi =~ s/%/%%/g; $legendo =~ s/%/%%/g; $legendx=~s/%/%%/g;
6406
6407		push @params,
6408			"PRINT:$mds0:MAX:".$q->b($legendi)." $maxlbl $ssin, ",
6409			"PRINT:$ds0:AVERAGE:$avglbl $ssin, ",
6410			"PRINT:$ds0:LAST:$lastlbl $ssin ".$q->br
6411					if(!$interfaces{$interface}{noi});
6412		push @params,
6413			"PRINT:$mds1:MAX:".$q->b($legendo)." $maxlbl $ssout, ",
6414			"PRINT:$ds1:AVERAGE:$avglbl $ssout, ",
6415			"PRINT:$ds1:LAST:$lastlbl $ssout ".$q->br
6416					if(!$interfaces{$interface}{noo});
6417		push @params,
6418			"PRINT:$mds2:MAX:".$q->b($legendx)." $maxlbl $ssext, ",
6419			"PRINT:$ds2:AVERAGE:$avglbl $ssext, ",
6420			"PRINT:$ds2:LAST:$lastlbl $ssext ".$q->br
6421					if($legendx and $ds2);
6422
6423		if($workday) {
6424			my($pfx) = "<TR><TD>".langmsg(3201,"Working day average")."\\:</TD>";
6425			my($sfx) = "";
6426			if(!$interfaces{$interface}{noi}) {
6427				$sfx = "</TR>" if($interfaces{$interface}{noo});
6428				push @params,
6429					"PRINT:wdin:AVERAGE:$pfx<TD align=right>$ssin"
6430					."</TD>$sfx";
6431				$pfx = "";
6432			}
6433			push @params,
6434				"PRINT:wdout:AVERAGE:$pfx<TD align=right>$ssout"
6435					."</TD>$sfx"
6436				if(!$interfaces{$interface}{noo});
6437			push @params,
6438				"PRINT:wdx:AVERAGE:$pfx<TD align=right>$ssext"
6439					."</TD>$sfx"
6440				if($ds2);
6441		}
6442	}
6443}
6444
6445sub jscript_actuals($$$$@) {
6446	my($interface,$dwmy,$starttime,$endtime,@p) = @_;
6447	my($idx) = 0;
6448	my($js) = "";
6449	my( $start, $step, $names, $values, $e );
6450	my($t,$i,$dp,$factor,$incr);
6451	my($rrd);
6452	my($max1,$max2);
6453	my($intf);
6454
6455	# if we're in a summary
6456	return if($dwmy =~/s/);
6457	# Here, we can add the javascript to define the actual arrays for the
6458	# popup, if necessary.
6459	$factor = 1;
6460	$factor *= $interfaces{$interface}{mult} if($interfaces{$interface}{mult});
6461	$factor *= $interfaces{$interface}{factor} if($interfaces{$interface}{factor});
6462	$dp = 2; $dp = 0 if($interfaces{$interface}{integer});
6463	if($dwmy=~/d/) { $idx=1; }
6464	elsif($dwmy=~/w/) { $idx=2; }
6465	elsif($dwmy=~/m/) { $idx=3; }
6466	elsif($dwmy=~/y/) { $idx=4; }
6467	$rrd = $interfaces{$interface}{rrd};
6468	if($rrdcached and $rrdcached!~/^unix:/) {
6469		my($pth) = $config{'routers.cgi-dbpath'};
6470		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
6471		$rrd =~ s/^$pth\/*//;
6472	}
6473	if( $config{'web-debug'} ) {
6474		print "\n<!-- Extraction params: $rrd ".(join " ",@p)." -->\n";
6475	}
6476	( $start, $step, $names, $values ) = RRDs::fetch($rrd,"AVERAGE",@p,@rrdcached);
6477	$e = RRDs::error();
6478	if($e) {
6479		print "<!-- Error fetching: $e -->\n";
6480		return;
6481	}
6482	if( $config{'web-debug'} ) {
6483		print "<!-- Asked for: $starttime to $endtime, 400 values-->\n";
6484		print "<!-- Asked for: ".longdate($starttime)." to ".longdate($endtime)." -->\n";
6485		print "<!-- Retrieved: $start to ".($start+$step*$#$values).", ".$#$values." values -->\n";
6486		print "<!-- Retrieved: ".longdate($start)." to ".longdate($start+$step*$#$values)." -->\n";
6487#		print "<!-- Step: asked for ".$p[5]." retrieved $step -->\n";
6488	}
6489
6490	$js = "xactual[$idx]=1;\nactual[$idx]=new Array(400);\n";
6491	$i = 0; $t = $start;
6492	$incr = ($endtime-$starttime)/400;
6493	$max1 = $max2 = $interfaces{$interface}{max};
6494	$max1 = $interfaces{$interface}{max1}
6495		if(defined $interfaces{$interface}{max1});
6496	$max2 = $interfaces{$interface}{max2}
6497		if(defined $interfaces{$interface}{max2});
6498	$intf = 0;
6499	$intf = $interfaces{$interface}{integer}
6500		if(defined $interfaces{$interface}{integer});
6501	foreach my $row ( @$values ) {
6502		$i = int(($t-$starttime)/$incr);
6503		if(!defined $row->[0]) { $js .= "actual[$idx][$i] = \"\"\n"; }
6504		else {
6505			$js .= "actual[$idx][$i] = \"";
6506			if($interfaces{$interface}{dorelpercent}) {
6507				$js .= doformat(($row->[0]/$row->[1]*100.0),1,$intf)."\%"
6508					if($row->[1]);
6509			} elsif($interfaces{$interface}{aspercent}) {
6510			$js .= doformat($row->[0]/$interfaces{$interface}{maxbytes}*100.0,
6511				1,$intf)."\%" unless($interfaces{$interface}{noi});
6512			$js .= ",<BR>" unless($interfaces{$interface}{noi}
6513				or $interfaces{$interface}{noo});
6514			$js .= doformat($row->[1]/$interfaces{$interface}{maxbytes}*100.0,
6515				1,$intf)."\%" unless($interfaces{$interface}{noo});
6516			} elsif($interfaces{$interface}{'reverse'}) {
6517				$js .= doformat(($max1-$row->[0])*$factor,
6518					$interfaces{$interface}{fixunits},$intf)
6519					.$interfaces{$interface}{unit}
6520					unless($interfaces{$interface}{noi});
6521				$js .= ",<BR>" unless($interfaces{$interface}{noi}
6522					or $interfaces{$interface}{noo});
6523				$js .= doformat(($max2-$row->[1])*$factor,
6524					$interfaces{$interface}{fixunits},$intf)
6525					.$interfaces{$interface}{unit2}
6526					unless($interfaces{$interface}{noo});
6527			} else {
6528				$js .= doformat(($interfaces{$interface}{c2fi}?
6529					(($row->[0]*$factor*1.8)+32):$row->[0]*$factor),
6530					$interfaces{$interface}{fixunits},$intf)
6531					.$interfaces{$interface}{unit}
6532					unless($interfaces{$interface}{noi});
6533				$js .= ",<BR>" unless($interfaces{$interface}{noi}
6534					or $interfaces{$interface}{noo});
6535				$js .= doformat(($interfaces{$interface}{c2fo}?
6536					(($row->[1]*$factor*1.8)+32):$row->[1]*$factor),
6537					$interfaces{$interface}{fixunits},$intf)
6538					.$interfaces{$interface}{unit2}
6539					unless($interfaces{$interface}{noo});
6540			}
6541			$js .= "\";\n";
6542		}
6543		$t += $step;
6544	}
6545
6546	# and output
6547	print "\n<SCRIPT type=\"text/javascript\">//<![CDATA[\n$js\n//]></SCRIPT>\n";
6548}
6549########################################################################
6550# Actually create the necessary graph, and output the IMG tag.
6551
6552sub make_graph(@)
6553{
6554	my($e, $thisgraph, $thisurl, $s, $autoscale);
6555	my($tstr, $gheight, $width, $gwidth, $gtitle, $col);
6556	my($titlemaxlen);
6557	my($maxwidth) = 30;
6558	my($endtime, $starttime, @tparams, $interval, $end, $start);
6559	my($inhtml,$dwmy,$graphif) = @_;
6560	my($optsuffix) = "";
6561	my(@ctgt) = ();
6562	my($js) = "";
6563
6564	$debugmessage .= "Graph: $graphif\n";
6565
6566# Verify that the rrd file exists
6567	if(!$rrdcached) {
6568	if( $interfaces{$graphif}{usergraph} ) {
6569		# several to check
6570		@ctgt =  @{$interfaces{$graphif}{targets}};
6571	} else {
6572		@ctgt = ( $graphif );
6573	}
6574	foreach (@ctgt) {
6575		if(!-r $interfaces{$_}{rrd}) {
6576			if ( $pagetype =~ /image/ ) {
6577				if($opt_I) {
6578					print "Interface: $graphif($_)\nDevice: $router\nError: RRD does not exist\nRRD: ".$interfaces{$_}{rrd}."\n";
6579				} else {
6580					print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
6581				}
6582			} else {
6583				print $q->h1(langmsg(3003,"RRD database file not found"))."\n";
6584				print "The file ".$interfaces{$_}{rrd}
6585					." does not exist, or is unreadable.  This file is created by MRTG when it first runs successfully on the "
6586					.$routers{$router}{file}." file.\n".$q->br
6587					."Please check that you have collected data via MRTG and stored it into the RRD database without errors.".$q->br."\n";
6588			}
6589			return;
6590		}
6591	}
6592	} # rrdcached
6593
6594# Shall we scale it, etc
6595	$autoscale = 1;
6596	$s = $dwmy; $s =~ s/[^dwmy6]//g; # get rid of excess stuff
6597	if( $interfaces{$graphif}{unscaled} ) {
6598		$autoscale = 0 if ($interfaces{$graphif}{unscaled} =~ /$s/i);
6599	}
6600
6601	$tstr = "6-hour" if( $dwmy =~ /6/ ) ;
6602	$tstr = "Daily" if( $dwmy =~ /d/ ) ;
6603	$tstr = "Weekly" if( $dwmy =~ /w/ ) ;
6604	$tstr = "Monthly" if( $dwmy =~ /m/ ) ;
6605	$tstr = "Yearly" if( $dwmy =~ /y/ ) ;
6606
6607	$gtitle = $interfaces{$graphif}{desc};
6608	if( ($dwmy.$gstyle)=~/s/ ) {
6609		if($gstyle=~/y/) { $maxwidth = 60; }
6610		elsif($gstyle=~/x/) { $maxwidth = 50; }
6611		elsif($gstyle=~/l/) { $maxwidth = 40; }
6612		else { $maxwidth = 30; }
6613	}
6614	if(!$gtitle or ((length($gtitle)>$maxwidth)and(($dwmy.$gstyle) =~ /s/))) {
6615		$gtitle = "";
6616		$gtitle .= $routers{$router}{shdesc}.": "
6617				if( defined $routers{$router}{shdesc});
6618		$gtitle .= $interfaces{$graphif}{shdesc};
6619	}
6620	$gtitle = $q->unescape($gtitle);
6621	$gtitle =~ s/&nbsp;/ /g; $gtitle =~ s/&amp;/&/g;
6622
6623	@params = ();
6624	$optsuffix = "r1" if($uopts =~ /r/ );
6625	$optsuffix = "r2" if($uopts =~ /R/ );
6626	$optsuffix = "-$optsuffix" if($optsuffix);
6627	$thisgraph = "${router}-${graphif}-${dwmy}-${gstyle}${optsuffix}.${graphsuffix}";
6628	$thisgraph = "${archdate}-${thisgraph}" if($archdate);
6629	$thisgraph = "${language}-${thisgraph}" if($language);
6630	$thisgraph =~ s/[\?#\/\\]//g;
6631	$thisurl   = $config{'routers.cgi-graphurl'}."/".$q->escape($thisgraph);
6632	$thisgraph = $config{'routers.cgi-graphpath'}.$pathsep.$thisgraph;
6633
6634	# width is the data unit width (400 max). gwidth is the pixel width of
6635	# the actual graph.  Thus, if gwidth > width, it is stretched.
6636	# Short: for PDAs, unstretched, shorter data window
6637	# Stretch: normal graph size, short data window (for easier viewing)
6638	# Long: normal data width, slightly bigger graph (for 800/600 screens)
6639	# Xlong: normal data width, double graph size (for 1024/768 screens)
6640	# v and w are thumbnail sizes, with half/quarter data width intended to
6641	# be used with the 'g' graph-only option.
6642	# gheight is the height of the graphic.
6643	# The 1st char is the width indicator s,t,n,l,x,y,v,w
6644	# then optional height indicator -,0,2,3
6645	# Then opional b (monochrome), g (graph only), p (no javascript)
6646	# Also D,H,Q for double/half/quarter data width ( t == nH )
6647	# A == w-g, B == v0g (thumbnails)
6648	# Note that the graph TYPE (dwmy) can have a trailing s to indicate
6649	# summary, which will reduce the size and data width and suppress the
6650	# legend.
6651	if ( $gstyle =~ /^s/ ) { $width = 200; $gwidth = 200; } #short
6652	elsif ( $gstyle =~ /^t/ ) { $width = 200; $gwidth = 400; } #stretch
6653	elsif ( $gstyle =~ /^l/ ) { $width = 400; $gwidth = 530; } #long
6654	elsif ( $gstyle =~ /^x/ ) { $width = 400; $gwidth = 800; } #xlong
6655	elsif ( $gstyle =~ /^y/ ) { $width = 400; $gwidth = 1000; } #supersize
6656	elsif ( $gstyle =~ /^[wA]/i ) { $width = 100; $gwidth = 50; } #thumbnail
6657	elsif ( $gstyle =~ /^[vB]/i ) { $width = 200; $gwidth = 100; } #thumbnail
6658	else { $width = 400; $gwidth = 400; } # default (normal)
6659	if ( $gstyle =~ /2/ ) { $gheight = 200; } # double height
6660	elsif ( $gstyle =~ /3/ ) { $gheight = 300; } # triple height
6661	elsif ( $gstyle =~ /[-A]/ ) { $gheight = 30; } # thumbnail
6662	elsif ( $gstyle =~ /[0B]/ ) { $gheight = 50; } # half height
6663	else { $gheight = 100; } # normal height
6664	if    ( $gstyle =~ /D/ ) { $width *= 2; } # double data width, so n=tD
6665	elsif ( $gstyle =~ /H/ ) { $width /= 2; } # half data width, so t=nH
6666	elsif ( $gstyle =~ /Q/ ) { $width /= 2; } # quarter data width
6667	elsif ( $gstyle =~ /T/ ) { $width *= 3; } # triple data width
6668	# now, if $dwmy contains an s, this is a summary graph, and should be
6669	# half of the expected data width and half the expected screen width.
6670	# We also force the graph to be half height, or 100 (whichever is greater).
6671	# The magic 120 in the graph width is the width of the axis, as gwidth is
6672	# the width of the AXIS, not the width of the graphic.
6673	if ( $dwmy =~ /s/ ) {
6674		my $ratio = 0.5;
6675		if( $interfaces{$interface}{nodetails} ) { $ratio = 0.5; }
6676		elsif($gwidth>800) { $ratio = 0.75; } # y
6677		elsif($gwidth>400) { $ratio = 0.65; } # x,l
6678		elsif($gwidth>200) { $ratio = 0.5; } # n,s
6679		$width *= $ratio; $gwidth = ($gwidth+120)*$ratio - 120;
6680		$gheight/=2; $gheight = 100 if($gheight<100);
6681	}
6682
6683	push @params,"--only-graph" if($gstyle=~/[gAB]/);
6684	push @params, $thisgraph;
6685	if( $graphsuffix eq "png" ) {
6686		push @params, '--imgformat',uc $graphsuffix;
6687	}
6688	if($interfaces{$graphif}{kilo}) {
6689		push @params,"--base", $interfaces{$graphif}{kilo};
6690	} else {
6691		push @params,"--base", $k;
6692	}
6693	push @params,"--lazy" if($dwmy !~ /s/ and $RRDs::VERSION != 1.3
6694		and (!defined $config{'routers.cgi-lazy'}
6695			or $config{'routers.cgi-lazy'}=~/[y1]/i));
6696		# only if we dont need PRINT, and avoid RRD v1.3.0 bug
6697	push @params, "--interlaced"; # -l 0 removed
6698	if($interfaces{$graphif}{fixunits} and $RRDs::VERSION >= 1.00030 ) {
6699		if($interfaces{$graphif}{exponent}) {
6700			push @params,"--units-exponent",$interfaces{$graphif}{exponent};
6701		} else {
6702			push @params,"--units-exponent",0;
6703		}
6704	}
6705
6706	push @params,"--force-rules-legend" if($RRDs::VERSION >= 1.00047);
6707	push @params,"--slope-mode" if(($RRDs::VERSION >= 1.2 )
6708		and defined $config{'routers.cgi-slope'}
6709		and ($config{'routers.cgi-slope'}=~/[y1]/i) );
6710
6711	# time window: save these, we may need them again
6712	@tparams = ();
6713	$end = 'now'; $endtime = time;
6714#	$debugmessage .= "Endtime = $endtime\n";
6715	if($basetime) {
6716		$end = $endtime = $basetime;
6717	} elsif($uselastupdate > 1  and $archivetime) {
6718		$end = $endtime = $archivetime;
6719	} elsif($lastupdate and $uselastupdate) {
6720		$end = $endtime = $lastupdate;
6721	} elsif( $interval ) {
6722		# Cannot be done because interval not yet set!
6723		$end = $endtime = $interval*int($endtime/$interval); # boundary
6724	} elsif( $dwmy =~ /6/ ) {
6725		$end = $endtime = 60*int($endtime/60);  # 1min boundary
6726	} else {
6727		$end = $endtime = 300*int($endtime/300);  # 5min boundary
6728	}
6729#	$debugmessage .= "Endtime = $endtime\n";
6730	if( $dwmy =~ /-/ ) {
6731		if ( $dwmy =~ /6/ ) {
6732			push @tparams, "-e", "$end-6h"; $endtime -= (6*3600); }
6733		if ( $dwmy =~ /d/ ) {
6734			push @tparams, "-e", "$end-24h"; $endtime -= (24*3600); }
6735		if ( $dwmy =~ /w/ ) {
6736			push @tparams, "-e", "$end-7d"; $endtime -= (7*24*3600); }
6737		if ( $dwmy =~ /m/ ) {
6738			push @tparams, "-e", "$end-30d"; $endtime -= (30*24*3600); }
6739		if ( $dwmy =~ /y/ )  {
6740			push @tparams, "-e", "$end-365d"; $endtime -= (365*24*3600); }
6741	} else {
6742		push @tparams, "-e", $end;
6743	}
6744	if ( $dwmy =~ /6/ ) {
6745		$interval = 60;
6746		$starttime = $endtime - $interval*$width;
6747		push @tparams, "-s", "end".(-1 * $width)."m"  ;
6748	} elsif ( $dwmy =~ /d/ ) {
6749		$interval = 300;
6750		$starttime = $endtime - $interval*$width;
6751		push @tparams, "-s", "end".(-5 * $width)."m" ;
6752	} elsif ( $dwmy =~ /w/ ) {
6753		$interval = 1800;
6754		$starttime = $endtime - 1500*$width; # dont use $interval
6755		push @tparams, "-s", "end".(-25 * $width)."m" ; # dont set to 30
6756	} elsif ( $dwmy =~ /m/ ) {
6757		$interval = 7200;
6758		$starttime = $endtime - $interval*$width;
6759		push @tparams, "-s", "end".(-2 * $width)."h"  ;
6760	} elsif ( $dwmy =~ /y/ ) {
6761		$interval = 86400;
6762		$starttime = $endtime - $interval*$width;
6763		push @tparams, "-s", "end".(-1 * $width)."d"   ;
6764	}
6765
6766	push @params, @tparams;
6767
6768	# only force the minimum upper-bound of graph if we have a max,
6769	# and we dont have maxima=n, and we dont have unscaled=n
6770	if( $uopts =~ /r/i ) {
6771		# force upper limit to be 2xMax(avgs) if r, and Max(avgs) if R
6772		my($ulim) = 0;
6773		my($llim) = 0;
6774		my($ai,$ao, $e, $start, $names, $data);
6775		my(@t) = ($graphif);
6776		my($thistarg, $thislim,$lookback);
6777		# multiple targets?
6778		@t = @{$interfaces{$graphif}{targets}}
6779			if($interfaces{$graphif}{usergraph});
6780		# find out average value
6781		$e = int($lastupdate/$interval)*$interval;
6782		$lookback = 10;
6783		$lookback = 200 if($uopts =~ /r/); # look back further
6784		# this _should_ return only one line of values...
6785		foreach $thistarg ( @t ) {
6786			my($trrd) = $interfaces{$thistarg}{rrd};
6787			if($rrdcached and $rrdcached!~/^unix:/) {
6788				my($pth) = $config{'routers.cgi-dbpath'};
6789		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
6790				$trrd =~ s/^$pth\/*//;
6791			}
6792			($start,$interval,$names,$data) =
6793				RRDs::fetch($trrd, "AVERAGE",
6794				"-r", $interval, "-s", "end-".($lookback*$interval), "-e", $e,
6795				@rrdcached);
6796			($ai,$ao) = get_avg($data);
6797			if( defined $interfaces{$interface}{graphstyle}
6798				and $interfaces{$interface}{graphstyle} =~ /mirror/i ) {
6799				if(!$interfaces{$thistarg}{noo}) {
6800					if( $interfaces{$graphif}{withtotal}
6801						and $interfaces{$graphif}{usergraph} ) {
6802						$ulim += $ao;
6803					} else {
6804						$ulim = $ao if($ao > $ulim);
6805					}
6806				}
6807				if(!$interfaces{$thistarg}{noi}) {
6808					if( $interfaces{$graphif}{withtotal}
6809						and $interfaces{$graphif}{usergraph} ) {
6810						$llim += $ai;
6811					} else {
6812						$llim = $ai if($ai > $llim);
6813					}
6814				}
6815			} else {
6816				if($ao > $ai) { $thislim = $ao; } else { $thislim = $ai; }
6817				$thislim = $ao if($interfaces{$thistarg}{noi});
6818				$thislim = $ai if($interfaces{$thistarg}{noo});
6819				if( $interfaces{$graphif}{withtotal}
6820					and $interfaces{$graphif}{usergraph} ) {
6821					$ulim += $thislim;
6822				} else {
6823					$ulim = $thislim if($thislim > $ulim);
6824				}
6825			}
6826		}
6827		$ulim *= 1.1; # just give a little more space
6828		# now we need to multiply, if appropriate
6829		$ulim *= $interfaces{$graphif}{mult}
6830			if($interfaces{$graphif}{mult});
6831		$ulim *= $interfaces{$graphif}{factor}
6832			if(defined $interfaces{$graphif}{factor});
6833		$ulim = int(2.0 * $ulim + 0.5) if($uopts =~ /r/);
6834		push @params, '-r', '-u', $ulim if($ulim > 0);
6835		if( defined $interfaces{$interface}{graphstyle}
6836			and $interfaces{$interface}{graphstyle} =~ /mirror/i ) {
6837			$llim *= -1.1; # just give a little more space
6838			$llim *= $interfaces{$graphif}{mult}
6839				if($interfaces{$graphif}{mult});
6840			$llim *= $interfaces{$graphif}{factor}
6841				if(defined $interfaces{$graphif}{factor});
6842			$llim = int(2.0 * $llim + 0.5) if($uopts =~ /r/);
6843			push @params, '-l', $llim if($llim < 0);
6844		}
6845	} else {
6846		if($interfaces{$graphif}{upperlimit}) {
6847			push @params, '-u', $interfaces{$graphif}{upperlimit};
6848		} elsif( ! $autoscale ) {
6849			if( $interfaces{$graphif}{max} and (
6850				!defined $config{'routers.cgi-maxima'}
6851				or $config{'routers.cgi-maxima'} !~ /n/i
6852			) ) {
6853				push @params, '-u', $interfaces{$graphif}{max} ;
6854			} else {
6855				push @params, '-u', 0.1; # For sanity
6856			}
6857		} else {
6858			push @params, '-u', 0.1; # For sanity
6859		}
6860		# could have added a "-r" there to enforce the upper limit rigidly
6861		push @params, '--rigid' if($interfaces{$graphif}{rigid});
6862		if($interfaces{$graphif}{lowerlimit}) {
6863			push @params, '--lower-limit', $interfaces{$graphif}{lowerlimit};
6864		}
6865	}
6866	push @params, "-w", $gwidth, "-h", $gheight;
6867
6868	push @params,'--alt-y-grid'
6869		if($RRDs::VERSION>=1.2 and defined $config{'routers.cgi-altygrid'}
6870		and $config{'routers.cgi-altygrid'}=~/[y1]/i);
6871
6872	push @params,"--x-grid","MINUTE:15:HOUR:1:HOUR:1:0:$dailylabel"
6873		if ( $dwmy =~ /6/ );
6874	push @params,"--x-grid","HOUR:1:HOUR:24:HOUR:2:0:$dailylabel"
6875		if ( $dwmy =~ /d/ );
6876	push @params,"--x-grid","HOUR:6:DAY:1:DAY:1:86400:%a"
6877		if ( $dwmy =~ /w/ );
6878	push @params,"--x-grid","DAY:1:WEEK:1:WEEK:1:604800:Week"
6879			.(($NT and $RRDs::VERSION < 1.00039)?"_":" ").$monthlylabel
6880		if ( $dwmy =~ /m/ and $RRDs::VERSION >= 1.00029  );
6881	$titlemaxlen = $config{'routers.cgi-maxtitle'}?$config{'routers.cgi-maxtitle'}:128;
6882	$gtitle = substr($gtitle,0,$titlemaxlen) if(length($gtitle)>$titlemaxlen);
6883	push @params,"--title", $gtitle;
6884
6885	if ( defined $interfaces{$graphif}{ylegend} ) {
6886		push @params, "--vertical-label", $interfaces{$graphif}{ylegend};
6887#		push @params, "-U", $interfaces{$graphif}{unit}
6888#			if($interfaces{$graphif}{unit});
6889	} else {
6890		push @params, "--vertical-label", $interfaces{$graphif}{unit};
6891	}
6892
6893	# Horizontal rules
6894	if( defined $interfaces{$graphif}{hrule} and $dwmy!~/s/ ) {
6895		$col = 4;
6896		foreach ( @{$interfaces{$graphif}{hrule}} ) {
6897			push @params, "HRULE:".$_->{value}."#"
6898				.($_->{colour}?$_->{colour}:((sprintf "%x",$col) x 6))
6899				.":".$_->{desc}." ( "
6900				.doformat($_->{value},$interfaces{$graphif}{fixunits},0)
6901				.$interfaces{$graphif}{unit} .")\\l";
6902			$col += 1;
6903		}
6904	}
6905
6906	# Scale modes and secondary axis
6907	push @params, "--logarithmic", "--units=si"
6908		if($interfaces{$graphif}{logscale});
6909	push @params, "--right-axis-label", $interfaces{$graphif}{ylegend2}
6910		if($interfaces{$graphif}{ylegend2} and ($RRDs::VERSION >= 1.3));
6911	push @params, "--right-axis",
6912		$interfaces{$graphif}{scale}.':'.$interfaces{$graphif}{shift}
6913		if($interfaces{$graphif}{scaleshift} and ($RRDs::VERSION >= 1.3));
6914	push @params, "-P" if(defined $config{'routers.cgi-pango'}
6915		and $config{'routers.cgi-pango'}=~/[y1]/i);
6916
6917	push @params, "--watermark", "Generated by routers2.cgi Version $VERSION"
6918		if($RRDs::VERSION>=1.3004 and $dwmy !~ /s/);
6919
6920	push @params, "HRULE:0#000000"; # redraw zero axis
6921
6922	if( $interfaces{$graphif}{usergraph} ) {
6923		usr_params($dwmy,$graphif);
6924	} else {
6925		rtr_params($dwmy,$graphif);
6926	}
6927
6928	if( defined $interfaces{$graphif}{comment} ) {
6929		foreach ( @{$interfaces{$graphif}{comment}} ) {
6930			push @params, "COMMENT:".decolon(expandvars($_))."\\l";
6931		}
6932	}
6933
6934	if ( defined $config{'routers.cgi-withdate'}
6935		and $config{'routers.cgi-withdate'}=~/[1y]/ ) {
6936		push @params, "COMMENT:".decolon(shortdate($endtime))."\\r";
6937	}
6938
6939	( $rrdoutput, $rrdxsize, $rrdysize ) = RRDs::graph(@params);
6940	$e = RRDs::error();
6941	if ( $pagetype =~ /image/ ) {
6942		if($e or ! -f $thisgraph) {
6943			if($opt_I) {
6944				print "Device: $router\nTarget: $graphif\n";
6945				print "Error: $e\n";
6946			} else {
6947		print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
6948			}
6949		} else {
6950			# output the graphic directly from disk
6951			open GRAPH, "<$thisgraph";
6952			binmode GRAPH;
6953			binmode STDOUT;
6954			print $q->header({ -type=>"image/$graphsuffix", -expires=>"now",
6955				'-Content-Disposition'=>"filename=\"image.$graphsuffix\"" })
6956				if(!$opt_I);
6957			while( <GRAPH> ) { print; }
6958			close GRAPH;
6959		}
6960		return;
6961	}
6962	if ( $e ) {
6963		if( $inhtml ) {
6964			if($config{'web-paranoia'}
6965				and $config{'web-paranoia'}=~/[yY1]/) {
6966				print $q->p("RRD Error!"),"\n";
6967			} else {
6968				print $q->p("RRD Error: $e"),"\n";
6969				print $q->p("You can visit the configuration verification page "
6970					.$q->a({href=>("$meurlfull?page=verify&rtr="
6971						.$q->escape($router)),target=>"_new"},"here."));
6972				print $q->p("RRD: ".$interfaces{$graphif}{rrd}.$q->br.
6973					"Device: [$router] ".$routers{$router}{desc}.$q->br.
6974					"Interface: $graphif".$q->br.
6975						"Interfaces: ".(join ",",keys(%interfaces))
6976					);
6977				print "Params: ".(join " ",@params).$q->br;
6978			}
6979		} else {
6980			print "Error generating graph:\n$e\n";
6981		}
6982	} elsif( ! -f $thisgraph ) {
6983		if( $inhtml ) {
6984			print $q->h2("Graph was not created!");
6985			print $q->p("Probably, no data is available for the requested time period.");
6986			print $q->p("RRD: ".$interfaces{$graphif}{rrd}.$q->br.
6987				"Device: [$router] ".$routers{$router}{desc}.$q->br.
6988				"Interface: $graphif"
6989			);
6990		} else {
6991			print "Error generating graph: Probably no data available for that time period.\n";
6992		}
6993	} else {
6994		print "<!-- RRD: ".$interfaces{$graphif}{rrd}." -->\n"
6995			."<!-- OrigRRD: ".$interfaces{$graphif}{origrrd}." -->\n"
6996			."<!-- ArchiveDate: $archdate -->\n"
6997			if( $config{'web-debug'} );
6998		if($inhtml) {
6999			my($element) = "igraph$dwmy";
7000			my($tzoffset) = ($timezone*3600); # default to server's timezone
7001			if($interfaces{$graphif}{timezone}) {
7002				my($savetz) = $ENV{TZ};
7003				$ENV{TZ}=$interfaces{$graphif}{timezone};
7004				POSIX::tzset();
7005				$tzoffset = (localtime(86400))[2]; # -0
7006				$tzoffset -= 24 if( (localtime(86400))[3] != 2 );
7007				$tzoffset *= 3600;
7008				$ENV{TZ}=$savetz;
7009				POSIX::tzset();
7010				print "<!-- Timezone: ".$interfaces{$graphif}{timezone}
7011					." = $tzoffset -->\n";
7012			}
7013			# If we're able, get the actuals data
7014			# only if enabled, a simple graph, and not summary
7015			if(! $interfaces{$graphif}{usergraph}
7016				and ! $interfaces{$graphif}{issummary}
7017				and defined $config{'routers.cgi-actuals'}
7018				and $config{'routers.cgi-actuals'}=~/[y1]/i
7019				and (!defined $config{'routers.cgi-javascript'}
7020					or $config{'routers.cgi-javascript'}=~/[y1]/i)
7021				and $dwmy !~ /s/
7022			) {
7023				jscript_actuals($graphif,$dwmy,$starttime,$endtime,
7024					@tparams,'-r',$interval);
7025			}
7026			# Print out the actual image tag
7027			if($rrdxsize and $rrdysize and $rrdxsize < 10000 and $rrdysize < 10000 ) {
7028			print $q->img({src=>$thisurl,alt => $gtitle,border => 0,
7029				width => $rrdxsize, height => $rrdysize, name => $element,
7030				onMouseOver => "timepopup(this,'$element',$gwidth,$gheight,$interval,$endtime,$width,$tzoffset)",
7031				onMouseMove => "mousemove(event)",
7032				onMouseOut => "clearpopup()" });
7033			} else { # avoid problems with RRD v1.3.0
7034			print $q->img({src=>$thisurl,alt => $gtitle,border => 0,
7035				name => $element,
7036				onMouseOver => "timepopup(this,'$element',$gwidth,$gheight,$interval,$endtime,$width,$tzoffset)",
7037				onMouseMove => "mousemove(event)",
7038				onMouseOut => "clearpopup()" });
7039			}
7040
7041		}
7042		if( $archiveme ) {
7043			# copy this graph into the archive dir,
7044			# graphdir/file/target/ymdhm-siz.ext
7045			my( $arch ) = "";
7046			my( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time);
7047			$year += 2000 if($year < 100);
7048			$year += 1900 if($year < 1000);
7049			$arch = $router; $arch =~ s/[\?#\/\\]//g;
7050			$arch = $config{'routers.cgi-graphpath'}.$pathsep.$arch;
7051			mkdir $arch,0755 if(! -d $arch);
7052			$arch .= $pathsep.$graphif;
7053			mkdir $arch,0755 if(! -d $arch);
7054			$min = '0'.$min if($min < 10);
7055			$mday = '0'.$mday if($mday < 10);
7056			$mon += 1; $mon = '0'.$mon if($mon < 10);
7057			$arch .= $pathsep.$year.'-'.$mon.'-'
7058				.$mday.'-'.$hour.'-'.$min.'-'.$dwmy.'.'.$graphsuffix;
7059			print "<!-- Archiving $thisgraph\ninto $arch -->\n"
7060				if( $config{'web-debug'} );
7061			if( open ARCH, '>'.$arch ) {
7062				binmode ARCH;
7063				if( open GRAPH, '<'.$thisgraph ) {
7064					binmode GRAPH;
7065					while ( <GRAPH> ) { print ARCH; }
7066					if($inhtml) {
7067					print $q->br.$q->b(langmsg(9001,"Archived OK")).$q->br."\n";
7068					} else { print langmsg(9001,"Graph archive OK.")."\n"; }
7069					close GRAPH;
7070				} else {
7071					if($inhtml) {
7072					print $q->br.$q->b(langmsg(8001,"Archiving FAILED")." (cannot read?!)");
7073					} else { print "Graph archive FAILED (cannot read?!).\n"; }
7074				}
7075				close ARCH;
7076			} else {
7077				if($inhtml) {
7078					print $q->br.$q->b(langmsg(8001,"Archiving FAILED")." (cannot write)");
7079				} else { print "Graph archive FAILED (cannot write).\n"; }
7080			}
7081		}
7082	}
7083	if($js and $inhtml) {
7084		# Now, load the values into the array
7085		print "<script type=\"text/javascript\">//<![CDATA[\n"
7086			.$js."\n//]]></script>\n";
7087	}
7088	if( $config{'web-debug'} ) {
7089		print "\n<!-- Start comment -->\n<!-- \nrrdtool graph ";
7090		print (join "\n  ",@params); # For some browsers, this creates a
7091		                          # line too long and makes an error
7092		print "\n-->\n<!-- end comment -->\n";
7093	}
7094}
7095
7096###############
7097# Calculations of average and max from fetched data
7098sub get_max($)
7099{
7100	my($rows) = $_[0];
7101	my($maxin, $maxout) = (0,0);
7102
7103	foreach ( @$rows ) {
7104		$maxin = $$_[0] if($$_[0]>$maxin);
7105		$maxout = $$_[1] if($$_[1]>$maxout);
7106	}
7107	return ($maxin, $maxout);
7108}
7109sub get_avg($)
7110{
7111	my($rows) = $_[0];
7112	my($avgin, $avgout) = (0,0);
7113	my($numrows) = $#$rows;
7114
7115	return (0,0) if($numrows < 1);
7116	foreach ( @$rows ) {
7117		$avgin += $$_[0];
7118		$avgout += $$_[1];
7119	}
7120	$avgin /= ($numrows+1);
7121	$avgout /= ($numrows+1);
7122
7123	return ($avgin,$avgout);
7124}
7125#######################################################
7126# For the compact summary.  This will call the bar function a lot!
7127# bar images are: $meurl?page=bar&IN=xx&OUT=yy for percentages xx yy
7128# images are 400x15 pixels
7129sub do_compact($)
7130{
7131my ($csvmode) = $_[0];
7132my ($javascript);
7133my ($curif);
7134my ($e, $interval, $resolution, $rrd, $seconds);
7135my ($curin, $curout, $avgin, $avgout, $maxin, $maxout );
7136my ($curinpc, $curoutpc, $avginpc, $avgoutpc, $maxinpc, $maxoutpc );
7137my ($perinpc, $peroutpc, $perin, $perout);
7138my ($start, $from, $step, $names, $values);
7139my ($c,$a,$m,$p,$io, $heading);
7140my ($d, $inarr, $outarr,$barlen);
7141my (@iforder);
7142my ($legendi,$legendo,$fix,$intf);
7143my ($unit) = "";
7144my ($max1, $max2);
7145
7146if(!$csvmode) {
7147	$javascript = make_javascript({});
7148	start_html_ss({ -expires => "+5s",  -script => $javascript,
7149		-onload => "LoadMenu()", -class=>'compact' });
7150	print "<DIV class=pagetop>";
7151	print expandvars($config{'routers.cgi-pagetop'}),"\n"
7152		if( defined $config{'routers.cgi-pagetop'} );
7153	print "</DIV>";
7154} else {
7155	$comma = substr( $config{'web-comma'},0,1 )
7156		if(defined $config{'web-comma'});
7157	$comma = ',' if(!$comma);
7158	print "Target".$comma."Description".$comma."Type".$comma
7159		."Metric 1".$comma."Metric 2\n";
7160}
7161#
7162# Now for the RRD stuff
7163eval { require RRDs; };
7164if( $@ ) {
7165	if($csvmode) { print "".langmsg(8999,"Error").$comma
7166		."Cannot find RRDs.pm: $@\n";
7167		return;
7168	}
7169	if($config{'web-paranoia'}
7170		and $config{'web-paranoia'}=~/[yY1]/) {
7171		print $q->h1(langmsg(8999,"Error"))."<CODE>Cannot find RRDs.pm</CODE>\n";
7172	} else {
7173		print $q->h1(langmsg(8999,"Error"))."<CODE>Cannot find RRDs.pm in ".(join " ",@INC )."</CODE>\n";
7174		print $q->p("You can visit the configuration verification page "
7175			.$q->a({href=>("$meurlfull?page=verify&rtr=".$q->escape($router)),
7176			target=>"_new"},"here."));
7177	}
7178	do_footer();
7179	return;
7180}
7181
7182# First, the header to select which are visible:
7183($c,$a,$m,$p,$io) = ("","","","","i");
7184$c = $1 if( $baropts =~ /(c)/i ); # this preserves the case
7185$a = $1 if( $baropts =~ /(a)/i );
7186$m = $1 if( $baropts =~ /(m)/i );
7187$p = $1 if( $baropts =~ /(p)/i );
7188if( $baropts =~ /o/i ) { $io = "o"; } else { $io = "i"; }
7189if(!$csvmode) {
7190print "<DIV class=icons>";
7191print "<TABLE width=100% border=0 cellspacing=0 cellpadding=0 class=compactmenu><TR>\n";
7192print "<TD><SMALL>".langmsg(2302,"Last:")." "
7193	.$q->a({href=>"$meurlfull?".optionstring({bars=>"Ci".(lc "$a$m$p")})},
7194		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}sort-g-vsm.gif",
7195			border=>0,height=>10,width=>10,alt=>"Sort by current incoming"})
7196	).$q->a({href=>"$meurlfull?".optionstring({bars=>"Co".(lc "$a$m$p")})},
7197		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}sort-b-vsm.gif",
7198			border=>0,height=>10,width=>10,alt=>"Sort by current outgoing"})
7199	);
7200if( $c ) {
7201	print $q->a({href=>"$meurlfull?".optionstring({bars=>"$a$m$p$io"})},
7202		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}tick-vsm.gif",
7203			border=>0,height=>10,width=>10,alt=>"Remove current bar"})
7204	);
7205} else {
7206	print $q->a({href=>"$meurlfull?".optionstring({bars=>"c$a$m$p$io"})},
7207		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}cross-vsm.gif",
7208			border=>0,height=>10,width=>10,alt=>"Add Current bar"})
7209	);
7210}
7211print "</SMALL></TD>\n";
7212print "<TD><SMALL>".langmsg(2303,"Average:")." "
7213	.$q->a({href=>"$meurlfull?".optionstring({bars=>"Ai".(lc "$c$m$p")})},
7214		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}sort-g-vsm.gif",
7215			border=>0,height=>10,width=>10,alt=>"Sort by average incoming"})
7216	).$q->a({href=>"$meurlfull?".optionstring({bars=>"Ao".(lc "$c$m$p")})},
7217		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}sort-b-vsm.gif",
7218			border=>0,height=>10,width=>10,alt=>"Sort by average outgoing"})
7219	);
7220if( $a ) {
7221	print $q->a({href=>"$meurlfull?".optionstring({bars=>"$c$m$p$io"})},
7222		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}tick-vsm.gif",
7223			border=>0,height=>10,width=>10,alt=>"Remove Average bar"})
7224	);
7225} else {
7226	print $q->a({href=>"$meurlfull?".optionstring({bars=>"a$c$m$p$io"})},
7227		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}cross-vsm.gif",
7228			border=>0,height=>10,width=>10,alt=>"Add Average bar"}));
7229}
7230print "</SMALL></TD>\n";
7231print "<TD><SMALL>".langmsg(2304,"Maximum:")." "
7232	.$q->a({href=>"$meurlfull?".optionstring({bars=>"Mi".(lc "$c$a$p")})},
7233		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}sort-g-vsm.gif",
7234			border=>0,height=>10,width=>10,alt=>"Sort by Maximum incoming"})
7235	).$q->a({href=>"$meurlfull?".optionstring({bars=>"Mo".(lc "$c$a$p")})},
7236		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}sort-b-vsm.gif",
7237			border=>0,height=>10,width=>10,alt=>"Sort by Maximum outgoing"})
7238	);
7239if( $m ) {
7240	print $q->a({href=>"$meurlfull?".optionstring({bars=>"$a$c$p$io"})},
7241		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}tick-vsm.gif",
7242			border=>0,height=>10,width=>10,alt=>"Remove Maximum bar"}));
7243} else {
7244	print $q->a({href=>"$meurlfull?".optionstring({bars=>"m$a$c$p$io"})},
7245		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}cross-vsm.gif",
7246			border=>0,height=>10,width=>10,alt=>"Add Maximum bar"}));
7247}
7248print "</SMALL></TD>\n";
7249if( defined $config{'routers.cgi-percentile'}
7250	and $config{'routers.cgi-percentile'} =~ /y/i ) {
7251	print "<TD><SMALL>".langmsg(2305,"$PERCENT<SUP>th</SUP> Percentile:")." "
7252		.$q->a({href=>"$meurlfull?".optionstring({bars=>"Pi".(lc "$c$a$m")})},
7253			$q->img({src=>"${config{'routers.cgi-smalliconurl'}}sort-g-vsm.gif",
7254			border=>0,height=>10,width=>10,alt=>"Sort by Incoming ${PERCENT}th percentile"})
7255		).$q->a({href=>"$meurlfull?".optionstring({bars=>"Po".(lc "$c$a$m")})},
7256			$q->img({src=>"${config{'routers.cgi-smalliconurl'}}sort-b-vsm.gif",
7257			border=>0,height=>10,width=>10,alt=>"Sort by Outgoing ${PERCENT}th percentile"})
7258		);
7259	if( $p ) {
7260		print $q->a({href=>"$meurlfull?".optionstring({bars=>"$a$m$c$io"})},
7261		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}tick-vsm.gif",
7262			border=>0,height=>10,width=>10,alt=>"Remove ${PERCENT}th percentile bar"}));
7263	} else {
7264		print $q->a({href=>"$meurlfull?".optionstring({bars=>"p$a$m$c$io"})},
7265		$q->img({src=>"${config{'routers.cgi-smalliconurl'}}cross-vsm.gif",
7266			border=>0,height=>10,width=>10,alt=>"Add ${PERCENT}th percentile bar"}));
7267	}
7268	print "</SMALL></TD>\n";
7269}
7270print "</TR></TABLE></DIV>\n";
7271} # end if csvmode
7272
7273# Now, we set up the necessary resolution variables to use in the fetch:
7274$resolution = 60; $interval = "6h"; $seconds = 6*3600;
7275$heading = langmsg(2310,"Six hourly calculations");
7276if ( $gtype =~ /d/ ) { $resolution=300; $interval="24h"; $seconds=86400;
7277	$heading = langmsg(2311,"Daily calculations"); }
7278elsif ($gtype =~ /w/){ $resolution=1800; $interval="7d"; $seconds=7*86400;
7279	$heading = langmsg(2312,"Weekly calculations"); }
7280elsif ($gtype =~ /m/){ $resolution=7200; $interval="1month"; $seconds=30*86400;
7281	$heading = langmsg(2313,"Monthly calculations"); }
7282elsif ($gtype =~ /y/){ $resolution=86400; $interval="1y"; $seconds=365*86400;
7283	$heading = langmsg(2314,"Yearly calculations"); }
7284
7285if(!$csvmode) {
7286print $q->center($q->h2({class=>'compact'},$routers{$router}{desc}))."\n"
7287	if($routers{$router}{desc});
7288print $q->h3({class=>'compact'},$heading);
7289}
7290
7291# we now process each interface with incompact=>1 in turn.
7292foreach $curif ( keys(%interfaces) ) {
7293	next if(!$curif); # avoid rogue records
7294	next if(!$interfaces{$curif}{incompact});
7295	next if(!$interfaces{$curif}{max});
7296	next if($interfaces{$curif}{nomax});
7297
7298	$interfaces{$curif}{errors} = "";
7299
7300	# now we fetch the necessary information from the RRD
7301	$curin = $maxin = $avgin = -1; # error
7302	$curout= $maxout= $avgout= -1; # error
7303	$from = "now"; $e = 0;
7304	$rrd = $interfaces{$curif}{rrd};
7305	if($rrdcached and $rrdcached!~/^unix:/) {
7306		my($pth) = $config{'routers.cgi-dbpath'};
7307		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
7308		$rrd =~ s/^$pth\/*//;
7309	}
7310	if($basetime) {
7311		$from = $basetime;
7312	} elsif( $gtype =~ /-/ ) {
7313		$from = "now-$interval";
7314	} elsif($uselastupdate > 1 and $archivetime) {
7315		$from = $archivetime;
7316	} elsif($uselastupdate) {
7317		$from = RRDs::last($rrd,@rrdcached);
7318		$e = RRDs::error();
7319		if($e) {
7320			$from = "now";
7321			$interfaces{$curif}{errors}.= $q->br.$q->small(langmsg(8999,"Error").": $e")."\n";
7322		}
7323	} else {
7324		$from = "now-5min";
7325	}
7326	$max1 = $max2 = $interfaces{$curif}{max};
7327	$max1 = $interfaces{$curif}{max1} if(defined $interfaces{$curif}{max1});
7328	$max2 = $interfaces{$curif}{max2} if(defined $interfaces{$curif}{max2});
7329	$lastupdate = $from;
7330	if( $c ) {
7331	( $start, $step, $names, $values ) =
7332		RRDs::fetch($rrd,"AVERAGE","-s","$from-$resolution",
7333			"-e",$from,"-r",$resolution,@rrdcached);
7334	$e = RRDs::error();
7335	if($e) {
7336		$interfaces{$curif}{errors} .= $q->br.$q->small(langmsg(8999,"Error").": $e");
7337	} else {
7338		( $curin, $curout ) = @{$values->[0]};
7339		$curin *= $interfaces{$curif}{mult};
7340		$curout *= $interfaces{$curif}{mult};
7341		$curin *= $interfaces{$curif}{factor} if($interfaces{$curif}{factor});
7342		$curout *= $interfaces{$curif}{factor} if($interfaces{$curif}{factor});
7343		$curin = 0 if($interfaces{$curif}{noi});
7344		$curout= 0 if($interfaces{$curif}{noo} and !$interfaces{$curif}{dorelpercent});
7345	}
7346	if( $interfaces{$curif}{dorelpercent} ) {
7347		if(defined $curin and $curout) {
7348			$curinpc = 100.0 * $curin / $curout;
7349			$curin = $curinpc;
7350		} else {
7351			$curinpc = 0; $curin = -1;
7352		}
7353		$curoutpc = 0;
7354		$curout = -1;
7355	} else {
7356		if(defined $curin) { $curinpc = $curin*100.0/$max1; }
7357		else { $curin = -1; $curinpc = 0; }
7358		if(defined $curout) { $curoutpc = $curout*100.0/$max2; }
7359		else { $curout = -1; $curoutpc = 0; }
7360	}
7361	$interfaces{$curif}{barcurin}    = $curin;
7362	$interfaces{$curif}{barcurinpc}  = $curinpc;
7363	$interfaces{$curif}{barcurout}   = $curout;
7364	$interfaces{$curif}{barcuroutpc} = $curoutpc;
7365	} # c
7366	if( $a ) {
7367	( $start, $step, $names, $values ) =
7368		RRDs::fetch($rrd,"AVERAGE","-s","$from-$interval",
7369			"-e",$from,"-r",$seconds,@rrdcached);
7370	$e = RRDs::error();
7371	if($e) {
7372		$interfaces{$curif}{errors} .= $q->br.$q->small(langmsg(8999,"Error").": $e");
7373	} else {
7374		($avgin, $avgout) = get_avg($values);
7375		$avgin *= $interfaces{$curif}{mult};
7376		$avgout *= $interfaces{$curif}{mult};
7377		$avgin *= $interfaces{$curif}{factor} if($interfaces{$curif}{factor});
7378		$avgout *= $interfaces{$curif}{factor} if($interfaces{$curif}{factor});
7379		$avgin = 0 if($interfaces{$curif}{noi});
7380		$avgout= 0 if($interfaces{$curif}{noo} and !$interfaces{$curif}{dorelpercent});
7381	}
7382	if( $interfaces{$curif}{dorelpercent} ) {
7383		if(defined $avgin and $avgout) {
7384			$avginpc = 100.0 * $avgin / $avgout;
7385			$avgin = $avginpc;
7386		} else {
7387			$avginpc = 0; $avgin = -1;
7388		}
7389		$avgoutpc = 0;
7390		$avgout = -1;
7391	} else {
7392		if(defined $avgin) { $avginpc = $avgin*100.0/$max1; }
7393		else { $avgin = -1; $avginpc = 0; }
7394		if(defined $avgout) { $avgoutpc = $avgout*100.0/$max2; }
7395		else { $avgout = -1; $avgoutpc = 0; }
7396	}
7397	$interfaces{$curif}{baravgin}    = $avgin;
7398	$interfaces{$curif}{baravgout}   = $avgout;
7399	$interfaces{$curif}{baravginpc}  = $avginpc;
7400	$interfaces{$curif}{baravgoutpc} = $avgoutpc;
7401	} # a
7402	if( $m ) {
7403	( $start, $step, $names, $values ) =
7404		RRDs::fetch($rrd,"MAX","-s","$from-$interval",
7405			"-e",$from,"-r",$seconds,@rrdcached);
7406	$e = RRDs::error();
7407	if($e) {
7408		$interfaces{$curif}{errors} .= $q->br.$q->small(langmsg(8999,"Error").": $e");
7409	} else {
7410		($maxin, $maxout) = get_max($values);
7411		$maxin *= $interfaces{$curif}{mult};
7412		$maxout *= $interfaces{$curif}{mult};
7413		$maxin *= $interfaces{$curif}{factor} if($interfaces{$curif}{factor});
7414		$maxout *= $interfaces{$curif}{factor} if($interfaces{$curif}{factor});
7415		$maxin = 0 if($interfaces{$curif}{noi});
7416		$maxout= 0 if($interfaces{$curif}{noo} and !$interfaces{$curif}{dorelpercent});
7417	}
7418	if( $interfaces{$curif}{dorelpercent} ) {
7419		if(defined $maxin and $maxout) {
7420			$maxinpc = 100.0 * $maxin / $maxout;
7421			$maxin = $maxinpc;
7422		} else {
7423			$maxinpc = 0; $maxin = -1;
7424		}
7425		$maxoutpc = 0;
7426		$maxout = -1;
7427	} else {
7428		if(defined $maxin) { $maxinpc = $maxin*100.0/$max1; }
7429		else { $maxin = -1; $maxinpc = 0; }
7430		if(defined $maxout) { $maxoutpc = $maxout*100.0/$max2; }
7431		else { $maxout = -1; $maxoutpc = 0; }
7432	}
7433	$interfaces{$curif}{barmaxin}    = $maxin;
7434	$interfaces{$curif}{barmaxout}   = $maxout;
7435	$interfaces{$curif}{barmaxinpc}  = $maxinpc;
7436	$interfaces{$curif}{barmaxoutpc} = $maxoutpc;
7437	} # m
7438	if( $p ) {
7439		($d,$inarr,$outarr) = calc_percentile($curif,$gtype,$PERCENT);
7440		$perin = ${$inarr}[0];
7441		$perout= ${$outarr}[0];
7442		if( $interfaces{$curif}{dorelpercent} ) {
7443			if(defined $perin and $perout) {
7444				$perinpc = 100.0 * $perin / $perout;
7445				$perin = $perinpc;
7446			} else {
7447				$perinpc = 0; $perin = -1;
7448			}
7449			$peroutpc = 0;
7450			$perout = -1;
7451		} else {
7452			$perin = 0 if($interfaces{$curif}{noi});
7453			$perout= 0 if($interfaces{$curif}{noo});
7454			if(defined $perin) { $perinpc = $perin*100.0/$max1; }
7455			else { $perin = -1; $perinpc = -1; }
7456			if(defined $perout) { $peroutpc = $perout*100.0/$max2; }
7457			else { $perout = -1; $peroutpc = -1; }
7458		}
7459		$interfaces{$curif}{barperin}    = $perin;
7460		$interfaces{$curif}{barperout}   = $perout;
7461		$interfaces{$curif}{barperinpc}  = $perinpc;
7462		$interfaces{$curif}{barperoutpc} = $peroutpc;
7463		if(!$d) {
7464			$interfaces{$curif}{errors} .= $q->br.$q->small($$inarr[2])
7465				.$q->br.$q->small($$outarr[2]);
7466		}
7467	} # p
7468} # end of data collection
7469
7470# Work out the order of the interfaces
7471$traffic = "";
7472if ( $c eq "C" ) {
7473	$traffic = "cur";
7474} elsif( $a eq "A" ) {
7475	$traffic = "avg";
7476} elsif( $m eq "M" ) {
7477	$traffic = "max";
7478} elsif( $p eq "P" and defined $config{'routers.cgi-percentile'}
7479  and $config{'routers.cgi-percentile'} =~ /y/i ) {
7480	$traffic = "per";
7481}
7482if($traffic) {
7483	$traffic .= 'in' if( $io eq "i" );
7484	$traffic .= 'out' if( $io eq "o" );
7485	$traffic = 'bar'.$traffic.'pc';
7486	@iforder = sort bytraffic keys(%interfaces);
7487} else {
7488	@iforder = sort byifdesc keys(%interfaces);
7489}
7490
7491# we now print the bars.
7492$barlen = 400;                            # 800x600
7493$barlen = 600 if ( $gstyle =~ /x/i );     # 1024x768
7494$barlen = 280 if ( $gstyle =~ /[nts]/i ); # 640x480 and pda
7495print "<TABLE border=0 cellpadding=0 cellspacing=0 nowrap class=compact>\n"
7496	if(!$csvmode);
7497foreach $curif ( @iforder ) {
7498	next if(!$curif); # avoid rogue records
7499	next if(!$interfaces{$curif}{incompact});
7500
7501	# the unit string, if any
7502	$unit = "";
7503	$unit = $interfaces{$curif}{unit}
7504		if(!defined $config{'routers.cgi-legendunits'}
7505			or $config{'routers.cgi-legendunits'} =~ /y/i );
7506	$fix = $interfaces{$curif}{fixunits};
7507	$fix = 0 if(!defined $fix);
7508	$intf = $interfaces{$curif}{integer};
7509	$intf = 0 if(!defined $intf);
7510
7511	# the legends
7512	($legendi,$legendo)=(langmsg(2204,"IN"),langmsg(2205,"OUT"));
7513	$legendi = $interfaces{$curif}{legendi} if(defined $interfaces{$curif}{legendi});
7514	$legendo = $interfaces{$curif}{legendo} if(defined $interfaces{$curif}{legendo});
7515	$legendi = "" if($interfaces{$curif}{noi});
7516	$legendo = "" if($interfaces{$curif}{noo});
7517
7518	if(!$csvmode) {
7519	print "<TR class=compact><TD align=left colspan=2 width=$barlen class=compact>\n";
7520	print $q->a({href=>"$meurlfull?".optionstring({if=>$curif})},
7521		$q->small($interfaces{$curif}{desc}
7522		.(($interfaces{$curif}{desc} ne $interfaces{$curif}{shdesc})?
7523			(" (".$interfaces{$curif}{shdesc}.")"):"")
7524		))."\n";
7525	print $interfaces{$curif}{errors};
7526	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";
7527	} # csvmode
7528
7529	# now print the bar graphs up
7530	if( $c ) {
7531	$curin =   $interfaces{$curif}{barcurin};
7532	$curout=   $interfaces{$curif}{barcurout};
7533	$curinpc = $interfaces{$curif}{barcurinpc};
7534	$curoutpc= $interfaces{$curif}{barcuroutpc};
7535	if($csvmode) {
7536		print $curif.$comma.'"'.$interfaces{$curif}{desc}.'"'.$comma
7537			.'"'.langmsg(2203,"Last").'"'.$comma
7538			.($legendi?doformat($curin,$fix,$intf):"").$comma
7539			.($legendo?doformat($curout,$fix,$intf):"").$comma
7540			."\n";
7541	} else {
7542	print "<TR><TD align=left><SMALL>".langmsg(2203,"Last")
7543		."</SMALL></TD>";
7544	do_bar_html($barlen,dp($curinpc,1),dp($curoutpc,1),$legendi,$legendo);
7545	print "<TD align=right nowrap>";
7546	print $q->small("&nbsp;&nbsp;<FONT color=#00d000>"
7547		.doformat($curin,$fix,$intf)."$unit</FONT>")
7548		if($curin>=0 and $legendi);
7549	print $q->small(" <FONT color=#00d000>(".doformat($curinpc,1,0)."%)</FONT>")
7550		if($curinpc>=0 and $legendi and $interfaces{$curif}{percent});
7551	print "</TD><TD align=right nowrap>";
7552	print $q->small("&nbsp;&nbsp;<FONT color=#0000ff>"
7553		.doformat($curout,$fix,$intf)."$unit</FONT>")
7554		if($curout>=0 and $legendo);
7555	print $q->small(" <FONT color=#0000ff>(".doformat($curoutpc,1,0)."%)</FONT>")
7556		if($curoutpc>=0 and $legendo and $interfaces{$curif}{percent});
7557	print "</TD></TR>\n";
7558	} # csvmode
7559	} # c
7560	if( $a ) {
7561	$avgin =   $interfaces{$curif}{baravgin};
7562	$avgout=   $interfaces{$curif}{baravgout};
7563	$avginpc = $interfaces{$curif}{baravginpc};
7564	$avgoutpc= $interfaces{$curif}{baravgoutpc};
7565	if($csvmode) {
7566		print $curif.$comma.'"'.$interfaces{$curif}{desc}.'"'.$comma
7567			.'"'.langmsg(2201,"Avg").'"'.$comma
7568			.($legendi?doformat($avgin,$fix,$intf):"").$comma
7569			.($legendo?doformat($avgout,$fix,$intf):"").$comma
7570			."\n";
7571	} else {
7572	print "<TR><TD align=left><SMALL>".langmsg(2201,"Avg")
7573		."</SMALL></TD>";
7574	do_bar_html($barlen,dp($avginpc,1),dp($avgoutpc,1),$legendi,$legendo);
7575	print "<TD align=right nowrap>";
7576	print $q->small("&nbsp;&nbsp;<FONT color=#00d000>".doformat($avgin,$fix,$intf)."$unit</FONT>")
7577		if($avgin>=0 and $legendi);
7578	print $q->small(" <FONT color=#00d000>(".doformat($avginpc,1,0)."%)</FONT>")
7579		if($avginpc>=0 and $legendi and $interfaces{$curif}{percent});
7580	print "</TD><TD align=right nowrap>";
7581	print $q->small("&nbsp;&nbsp;<FONT color=#0000ff>".doformat($avgout,$fix,$intf)."$unit</FONT>")
7582		if($avgout>=0 and $legendo);
7583	print $q->small(" <FONT color=#0000ff>(".doformat($avgoutpc,1,0)."%)</FONT>")
7584		if($avgoutpc>=0 and $legendo and $interfaces{$curif}{percent});
7585	print "</TD></TR>\n";
7586	} # csvmode
7587	} # a
7588	if( $m ) {
7589	$maxin =   $interfaces{$curif}{barmaxin};
7590	$maxout=   $interfaces{$curif}{barmaxout};
7591	$maxinpc = $interfaces{$curif}{barmaxinpc};
7592	$maxoutpc= $interfaces{$curif}{barmaxoutpc};
7593	if($csvmode) {
7594		print $curif.$comma.'"'.$interfaces{$curif}{desc}.'"'.$comma
7595			.'"'.langmsg(2200,"Max").'"'.$comma
7596			.($legendi?doformat($maxin,$fix,$intf):"").$comma
7597			.($legendo?doformat($maxout,$fix,$intf):"").$comma
7598			."\n";
7599	} else {
7600	print "<TR><TD align=left><SMALL>"
7601		.langmsg(2200,"Max")."</SMALL></TD>";
7602	do_bar_html($barlen,dp($maxinpc,1),dp($maxoutpc,1),$legendi,$legendo);
7603	print "<TD align=right nowrap>";
7604	print $q->small("&nbsp;&nbsp;<FONT color=#00d000>".doformat($maxin,$fix,$intf)."$unit</FONT>")
7605		if($maxin>=0 and $legendi);
7606	print $q->small(" <FONT color=#00d000>(".doformat($maxinpc,1,0)."%)</FONT>")
7607		if($maxinpc>=0 and $legendi and $interfaces{$curif}{percent});
7608	print "</TD><TD align=right nowrap>";
7609	print $q->small("&nbsp;&nbsp;<FONT color=#0000ff>".doformat($maxout,$fix,$intf)."$unit</FONT>")
7610		if($maxout>=0 and $legendo);
7611	print $q->small(" <FONT color=#0000ff>(".doformat($maxoutpc,1,0)."%)</FONT>")
7612		if($maxoutpc>=0 and $legendo and $interfaces{$curif}{percent});
7613	print "</TD></TR>\n";
7614	} # csvmode
7615	} # m
7616	if( $p ) {
7617	$perin =   $interfaces{$curif}{barperin};
7618	$perout=   $interfaces{$curif}{barperout};
7619	$perinpc = $interfaces{$curif}{barperinpc};
7620	$peroutpc= $interfaces{$curif}{barperoutpc};
7621	if($csvmode) {
7622		print $curif.$comma.'"'.$interfaces{$curif}{desc}.'"'.$comma
7623			.'"'.langmsg(2206,$PERCENT."th").'"'.$comma
7624			.($legendi?doformat($perin,$fix,$intf):"").$comma
7625			.($legendo?doformat($perout,$fix,$intf):"").$comma
7626			."\n";
7627	} else {
7628	print "<TR><TD align=left><SMALL>".langmsg(2206,"$PERCENT<sup>th</sup>")
7629		."</SMALL></TD>";
7630	do_bar_html($barlen,dp($perinpc,1),dp($peroutpc,1),$legendi,$legendo);
7631	print "<TD align=right nowrap>";
7632	print $q->small("&nbsp;&nbsp;<FONT color=#00d000>".doformat($perin,$fix,$intf)."$unit</FONT>")
7633		if($perin>=0 and $legendi);
7634	print $q->small(" <FONT color=#00d000>(".doformat($perinpc,1,0)."%)</FONT>")
7635		if($perinpc>=0 and $legendi and $interfaces{$curif}{percent});
7636	print "</TD><TD align=right nowrap>";
7637	print $q->small("&nbsp;&nbsp;<FONT color=#0000ff>".doformat($perout,$fix,$intf)."$unit</FONT>")
7638		if($perout>=0 and $legendo);
7639	print $q->small(" <FONT color=#0000ff>(".doformat($peroutpc,1,0)."%)</FONT>")
7640		if($peroutpc>=0 and $legendo and $interfaces{$curif}{percent});
7641	print "</TD></TR>\n";
7642	} # csvmode
7643	} # p
7644} # foreach interface
7645print "</TABLE>\n" if(!$csvmode);
7646
7647# Page foot
7648if(!$csvmode) {
7649print "<DIV class=pagefoot>";
7650print expandvars($config{'routers.cgi-pagefoot'}),"\n"
7651	if( defined $config{'routers.cgi-pagefoot'} );
7652print "</DIV>";
7653if( $gstyle !~ /p/ ) {
7654	my( $ngti, $ngto ) = ("","");
7655	print "<DIV class=icons>".$q->hr;
7656	print "\n",$q->a({href=>"javascript:location.reload(true)"},
7657		$q->img({src=>"${config{'routers.cgi-iconurl'}}refresh.gif",
7658		alt=>langmsg(5003,"Refresh"),border=>"0",width=>100,height=>20})),"&nbsp;\n"
7659		if(!$archdate);
7660#	print $q->a({href=>"javascript:parent.makebookmark('"
7661#		.$q->escape($router)."','__compact','$gtype','$gstyle','$gopts','$baropts','".$q->escape($extra)."')"},
7662#		$q->img({src=>"${config{'routers.cgi-iconurl'}}bookmark.gif",
7663#		alt=>"Bookmark",border=>"0",width=>100,height=>20})),"&nbsp;\n";
7664	print $q->a({href=>"$meurlfull?".optionstring({page=>"", xmtype=>"",
7665		if=>"__compact", xgstyle=>""}), target=>"_top" },
7666		$q->img({src=>"${config{'routers.cgi-iconurl'}}bookmark.gif",
7667		alt=>langmsg(5016,"Bookmark"),border=>"0",width=>100,height=>20})),"&nbsp;\n";
7668	print $q->a({href=>"$meurlfull?".optionstring({page=>"compactcsv"}), target=>"graph"},
7669		$q->img({src=>"${config{'routers.cgi-iconurl'}}csv.gif",
7670		alt=>langmsg(5019,"CSV Download"),border=>"0",width=>100,height=>20})),"\n";
7671	if( $gtype eq "6" ) { $ngto = "d"; }
7672	elsif( $gtype eq "d" ) { $ngto = "w"; $ngti = "6" if($usesixhour); }
7673	elsif( $gtype eq "w" ) { $ngti = "d"; $ngto = "m"; }
7674	elsif( $gtype eq "m" ) { $ngti = "w"; $ngto = "y"; }
7675	elsif( $gtype eq "y" ) { $ngti = "m"; }
7676	if( $ngti ) {
7677		print $q->a({href=>"$meurlfull?".optionstring({xgtype=>"$ngti"}), target=>"graph"},
7678			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomin.gif",
7679			alt=>langmsg(5017,"Zoom In"),border=>"0",width=>100,height=>20})),"&nbsp;\n";
7680	}
7681	if( $ngto ) {
7682		print $q->a({href=>"$meurlfull?".optionstring({xgtype=>"$ngto"}), target=>"graph"},
7683			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomout.gif",
7684			alt=>langmsg(5018,"Zoom Out"),border=>"0",width=>100,height=>20})),"&nbsp;\n";
7685	}
7686	print "</DIV>";
7687	print $q->br,"\n";
7688	} # csvmode
7689}
7690
7691if(!$csvmode){
7692	print "<!-- CAMPIO=[$c][$a][$m][$p][$io] gtype=$gtype baropts=$baropts -->\n";
7693	do_footer();
7694} # csvmode
7695}
7696
7697#######################################################
7698# This is for the summary of interfaces view
7699sub do_summary()
7700{
7701# Start off.  We use onload() and Javascript to force reload the
7702# lefthand (menu) panel.
7703my ($javascript, $e);
7704my ($rrd, $curif);
7705my ($m, $a, $l );
7706my ($start,$step, $names, $data);
7707my ($savetz) = "";
7708my ($legendi, $legendo, $legendx);
7709my ($donehead) = 0;
7710my ($withdetails) = 1;
7711my ($doneone) = 0;
7712my ($inhtml) = 1;
7713my (@sorted);
7714my ($gheight) = 100;
7715
7716calctimezone();
7717
7718$javascript = make_javascript({}).graphpopupscript();
7719
7720$withdetails = 0 if($interfaces{$interface}{nodetails});
7721
7722if ( $gstyle =~ /2/ ) { $gheight = 200; } # double height
7723elsif ( $gstyle =~ /3/ ) { $gheight = 300; } # triple height
7724else { $gheight = 100; } # normal height
7725
7726start_html_ss({  -expires => "+5s",  -script => $javascript,
7727	-onload => "LoadMenu()", -class=>'summary' },
7728	$interfaces{$interface}{xbackground}?$interfaces{$interface}{xbackground}:"");
7729
7730print $q->center($q->h2($routers{$router}{desc}))."\n"
7731	if($routers{$router}{desc});
7732
7733print "<DIV class=pagetop>";
7734print expandvars($config{'routers.cgi-pagetop'}),"\n"
7735	if( defined $config{'routers.cgi-pagetop'} );
7736if( defined $config{'routers.cgi-mrtgpagetop'}
7737	and $config{'routers.cgi-mrtgpagetop'} =~ /y/i
7738	and $interfaces{$interface}{pagetop}) {
7739	print expandvars($interfaces{$interface}{pagetop}),"\n";
7740}
7741print "</DIV>";
7742#
7743# Now for the RRD stuff
7744eval { require RRDs; };
7745if( $@ ) {
7746	if($config{'web-paranoia'}
7747		and $config{'web-paranoia'}=~/[yY1]/) {
7748		print $q->h1(langmsg(8999,"Error"))."<CODE>Cannot find RRDs.pm</CODE>\n";
7749	} else {
7750	print $q->h1(langmsg(8999,"Error"))."<CODE>Cannot find RRDs.pm in ".(join " ",@INC )."</CODE>\n";
7751		print $q->p("You can visit the configuration verification page "
7752			.$q->a({href=>("$meurlfull?page=verify&rtr=".$q->escape($router)),
7753			target=>"_new"},"here."));
7754	}
7755	do_footer();
7756	return;
7757}
7758
7759if( $interfaces{$interface}{sortby} ) {
7760	@sorted = sorttargets($interface,$gtype,$interfaces{$interface}{sortby});
7761} else {
7762	# for historical compatibility
7763	@sorted = sort byifdesc @{$interfaces{$interface}{targets}};
7764}
7765
7766print "<TABLE border=0 width=100% align=center class=summary>\n";
7767
7768$savetz = $ENV{TZ};
7769$doneone = 0;
7770foreach $curif ( @sorted ) {
7771	next if(!$curif); # avoid rogue records
7772
7773	if($interfaces{$interface}{active}) {
7774		next if(!isactive($curif));
7775	}
7776
7777	($legendi,$legendo,$legendx)=(langmsg(2204,"IN:"),langmsg(2205,"OUT:"),"");
7778	$legendi = $interfaces{$curif}{legendi}
7779		if(defined $interfaces{$curif}{legendi});
7780	$legendo = $interfaces{$curif}{legendo}
7781		if(defined $interfaces{$curif}{legendo});
7782	$legendx = $interfaces{$curif}{legendx}
7783		if(defined $interfaces{$curif}{legendx});
7784
7785	if($interfaces{$interface}{overridelegend} and $interfaces{$curif}{shdesc}
7786		and ( $interfaces{$interface}{noo} or $interfaces{$interface}{noi}
7787		or  $interfaces{$curif}{noo} or $interfaces{$curif}{noi} )
7788	){
7789		$legendi = $legendo = $interfaces{$curif}{shdesc}.':';
7790	}
7791
7792	# timezone information
7793	if($interfaces{$curif}{timezone}) {
7794		$ENV{TZ} = $interfaces{$curif}{timezone} ;
7795		POSIX::tzset();
7796	}
7797
7798	print "<TR WIDTH=100% VALIGN=TOP>" if($withdetails or !$doneone);
7799	print "<TD VALIGN=TOP>";
7800
7801	if( $interfaces{$curif}{usergraph} ) {
7802		$rrd = $interfaces{$interfaces{$interface}{targets}->[0]}{rrd};
7803	} elsif( defined $interfaces{$curif}{rrd} ) {
7804		$rrd = $interfaces{$curif}{rrd};
7805	} else {
7806		$rrd = "";
7807	}
7808	if($rrdcached and $rrd and $rrdcached!~/^unix:/) {
7809		my($pth) = $config{'routers.cgi-dbpath'};
7810		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
7811		$rrd =~ s/^$pth\/*//;
7812	}
7813	if( $interfaces{$curif}{usergraph} ) {
7814		$lastupdate = RRDs::last($rrd,@rrdcached);
7815		$e = RRDs::error();
7816	} elsif( defined $interfaces{$curif}{rrd} ) {
7817		# Last update stuff.
7818		$lastupdate = RRDs::last($rrd,@rrdcached);
7819		$e = RRDs::error();
7820	} else {
7821		$e = langmsg(8002,"No RRD file defined for interface")." '$curif'";
7822	}
7823	if( $e ) {
7824		print $q->p($q->b(langmsg(8003,"Error reading RRD database")." $rrd")
7825			.$q->br."<I>$e</I>".$q->br
7826			."Check that MRTG has run successfully on this device, and has created the RRD file.")."\n";
7827		print $q->p("Check that rrdcached is running correctly on $rrdcached")
7828			if($rrdcached and ($e=~/No such file/));
7829		if(!$withdetails) {
7830			print "</TD>";
7831			if($doneone) { print "</TR>\n" ; $doneone = 0; }
7832			else { $doneone = 1; }
7833		} else {
7834			print "</TD><TD>\n";
7835			print $q->h3($interfaces{$curif}{shdesc}),"\n";
7836			print $q->p($interfaces{$curif}{desc}),$q->br;
7837#		print $q->dump;
7838			print "</TD></TR>\n";
7839		}
7840		next;
7841	}
7842	if(!$withdetails) {
7843		if($interfaces{$interface}{withtop}) {
7844			print $q->br."\n".$interfaces{$curif}{pagetop}.$q->br
7845				if($interfaces{$curif}{pagetop});
7846		}
7847	}
7848	print "<A href=".$meurlfull."?".optionstring({if=>"$curif"},
7849		target=>"graph").">";
7850	make_graph($inhtml,$gtype."s",$curif);
7851	print "</A>";
7852	if($interfaces{$curif}{usergraph}) {
7853		print $q->br.$q->small("User Graph: ".$q->i($curif));
7854	} else {
7855	print $q->br.$q->small("Target: ".$q->i($interfaces{$curif}{target}))
7856		if($interfaces{$curif}{target});
7857	}
7858	if(!$withdetails) {
7859		if($interfaces{$interface}{withfoot}) {
7860			print $q->br."\n".$interfaces{$curif}{pagefoot}
7861				if($interfaces{$curif}{pagefoot});
7862		}
7863		print "</TD>\n";
7864		if($doneone) { print "</TR>\n" ; $doneone = 0; }
7865		else { $doneone = 1; }
7866		next;
7867	}
7868	print "</TD><TD>\n";
7869	print "<DIV class=summarydetails style=\"max-height: ${gheight}px;\" >";
7870	print $q->a({href=>"$meurlfull?".optionstring({if=>"$curif"}),
7871		target=>"graph"}, $q->b($interfaces{$curif}{desc}));
7872	if($interfaces{$interface}{withtop} and $interfaces{$curif}{pagetop}) {
7873		print $q->br.$interfaces{$curif}{pagetop}."\n";
7874	}
7875	print $q->br,langmsg(3203,"Last update").": ".longdate($lastupdate),
7876		$q->br,"\n";
7877	print langmsg(3204,"Timezone").": ".$interfaces{$curif}{timezone}.$q->br."\n"
7878		if($interfaces{$curif}{timezone});
7879
7880	if($interfaces{$curif}{usergraph}) {
7881		if($rrdoutput) {
7882			$donehead = 0;
7883			foreach ( @$rrdoutput ) {
7884				if( /^<TR>/i and !$donehead ) {
7885					$donehead = 1; next;
7886				}
7887				print if(!$donehead);
7888			}
7889		}
7890	} else {
7891		if ( $interfaces{$curif}{max}
7892			and !$interfaces{$curif}{nomax} ) {
7893				if ( defined $interfaces{$curif}{mblegend} ) {
7894					print $interfaces{$curif}{mblegend};
7895				} elsif ( $interfaces{$curif}{isif} ) { print langmsg(2103,"Bandwidth"); }
7896				else { print langmsg(2102,"Maximum"); }
7897				if(defined $interfaces{$curif}{max1}
7898					and defined $interfaces{$curif}{max2}) {
7899					print ": ".doformat( $interfaces{$curif}{max1},
7900						$interfaces{$curif}{fixunits},0)
7901						.$interfaces{$curif}{unit}."/"
7902						.doformat( $interfaces{$curif}{max2},
7903							$interfaces{$curif}{fixunits},0)
7904						.$interfaces{$curif}{unit}.$q->br,"\n";
7905				} else {
7906					print ": ".doformat( $interfaces{$curif}{max},
7907						$interfaces{$curif}{fixunits},0);
7908					print $interfaces{$curif}{unit}.$q->br,"\n";
7909				}
7910				if( defined $interfaces{$curif}{absmax}
7911					and !$interfaces{$curif}{noabsmax} ) {
7912					if ( defined $interfaces{$curif}{amlegend} ) {
7913						print $interfaces{$curif}{amlegend};
7914					} else { print langmsg(2104,"Hard Maximum"); }
7915					print ": ".doformat ($interfaces{$curif}{absmax},
7916						$interfaces{$curif}{fixunits},0)
7917						.$interfaces{$curif}{unit}.$q->br,"\n";
7918				}
7919			}
7920			print "Address: ".$interfaces{$curif}{address},$q->br,"\n"
7921				if ( $interfaces{$curif}{address} );
7922			print "Interface IP: ".$interfaces{$curif}{ipaddress},$q->br,"\n"
7923				if ( $interfaces{$curif}{ipaddress} );
7924			print "Interface # ".$interfaces{$curif}{ifno},$q->br,"\n"
7925				if(defined $interfaces{$curif}{ifno});
7926			print "Interface name: ".$interfaces{$curif}{ifdesc},$q->br,"\n"
7927				if($interfaces{$curif}{ifdesc});
7928# insert here the last/current/max values.
7929#			print @$rrdoutput if($rrdoutput);
7930		$donehead = 0;
7931		if($rrdoutput) {
7932			foreach ( @$rrdoutput ) {
7933				if( /^<TR>/i and !$donehead ) {
7934					$donehead = 1;
7935					print "<TABLE border=1 cellspacing=0 class=summarydata><TR><TD></TD>";
7936				print $q->td($q->b($legendi)) if(!$interfaces{$curif}{noi});
7937				print $q->td($q->b($legendo)) if(!$interfaces{$curif}{noo});
7938				print $q->td($q->b($legendx)) if($legendx);
7939					print "</TR>\n";
7940				}
7941				print;
7942			}
7943		}
7944# now the 95th percentile, if required
7945		if(
7946#			( defined $config{'routers.cgi-percentile'}
7947#			and $config{'routers.cgi-percentile'} =~ /y/i )
7948			 $interfaces{$curif}{total}
7949			or $interfaces{$curif}{percentile}
7950		) {
7951			my( $pcdesc, $inarr, $outarr );
7952			if(!$donehead) {
7953				print "<TABLE border=1 cellspacing=0 class=summarydata><TR><TD></TD>";
7954				print $q->td($q->b($legendi)) if(!$interfaces{$curif}{noi});
7955				print $q->td($q->b($legendo)) if(!$interfaces{$curif}{noo});
7956				print $q->td($q->b($legendx)) if($legendx);
7957				print "</TR>\n";
7958				$donehead = 1;
7959			}
7960			( $pcdesc, $inarr, $outarr ) = calc_percentile($curif,$gtype,$PERCENT);
7961			if($pcdesc) {
7962				if($interfaces{$curif}{total}) {
7963					print "<TR>".$q->td(langmsg(2301,"Total over")." $pcdesc:");
7964					print $q->td({ align=>"right"},doformat($$inarr[1],
7965$interfaces{$curif}{fixunits},$interfaces{$curif}{integer})
7966	.$interfaces{$curif}{totunit}) if(!$interfaces{$curif}{noi});
7967					print $q->td({ align=>"right"},doformat($$outarr[1],
7968$interfaces{$curif}{fixunits},$interfaces{$curif}{integer})
7969	.$interfaces{$curif}{totunit2}) if(!$interfaces{$curif}{noo});
7970					print "</TR>\n";
7971				}
7972				if($interfaces{$curif}{percentile}) {
7973					print "<TR>".$q->td(langmsg(2300,$PERCENT."th Percentile for")." $pcdesc:");
7974					print $q->td({ align=>"right"},doformat($$inarr[0],
7975$interfaces{$curif}{fixunits},0)
7976	.$interfaces{$curif}{unit}) if(!$interfaces{$curif}{noi});
7977					print $q->td({ align=>"right"},doformat($$outarr[0],
7978$interfaces{$curif}{fixunits},0)
7979	.$interfaces{$curif}{unit2}) if(!$interfaces{$curif}{noo});
7980				}
7981			} else {
7982				print "<TR>".$q->td(langmsg(8004,"Error in ${PERCENT}th percentile calcs").":")
7983					.$q->td($$inarr[2]).$q->td($$outarr[2])."\n";
7984			}
7985		}
7986		print "</TABLE>".$q->br."\n" if($donehead);
7987	} # not usergraph
7988	if($interfaces{$interface}{withfoot} and $interfaces{$curif}{pagefoot}) {
7989		print $interfaces{$curif}{pagefoot}."\n";
7990	}
7991	print "</DIV>";
7992	print "</TD></TR>\n";
7993	if($savetz){ $ENV{TZ}=$savetz; POSIX::tzset(); }
7994} # foreach
7995print "<TD></TD></TR>" if(!$withdetails and $doneone);
7996print "</TABLE>\n";
7997
7998# Page foot
7999print "<DIV class=pagefoot>";
8000if( defined $config{'routers.cgi-mrtgpagefoot'}
8001	and $config{'routers.cgi-mrtgpagefoot'} =~ /y/i
8002	and $interfaces{$interface}{pagefoot}) {
8003	print expandvars($interfaces{$interface}{pagefoot}),"\n";
8004}
8005print expandvars($config{'routers.cgi-pagefoot'}),"\n"
8006	if( defined $config{'routers.cgi-pagefoot'} );
8007print "</DIV><DIV class=icons>";
8008if( $gstyle !~ /p/ ) {
8009	my( $u, $ngti, $ngto ) = ("","","");
8010	print $q->hr;
8011	print "\n",$q->a({href=>"javascript:location.reload(true)"},
8012		$q->img({src=>"${config{'routers.cgi-iconurl'}}refresh.gif",
8013		alt=>langmsg(5003,"Refresh"),border=>"0",width=>100,height=>20})),"&nbsp;\n"
8014		if(!$archdate);
8015	print $q->a({href=>"$meurlfull?".optionstring({page=>"", bars=>"", xmtype=>"",
8016		xgstyle=>""}), target=>"_top" },
8017		$q->img({src=>"${config{'routers.cgi-iconurl'}}bookmark.gif",
8018		alt=>langmsg(5016,"Bookmark"),border=>"0",width=>100,height=>20})),"&nbsp;\n";
8019	if( $gtype eq "6" ) { $ngto = "d"; }
8020	elsif( $gtype eq "d" ) { $ngto = "w"; $ngti = '6' if($usesixhour); }
8021	elsif( $gtype eq "w" ) { $ngti = "d"; $ngto = "m"; }
8022	elsif( $gtype eq "m" ) { $ngti = "w"; $ngto = "y"; }
8023	elsif( $gtype eq "y" ) { $ngti = "m"; }
8024	if( $ngti ) {
8025		print $q->a({href=>"$meurlfull?".optionstring({xgtype=>"$ngti"}), target=>"graph"},
8026			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomin.gif",
8027			alt=>langmsg(5017,"Zoom In"),border=>"0",width=>100,height=>20})),"&nbsp;\n";
8028	}
8029	if( $ngto ) {
8030		print $q->a({href=>"$meurlfull?".optionstring({xgtype=>"$ngto"}), target=>"graph"},
8031			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomout.gif",
8032			alt=>langmsg(5018,"Zoom Out"),border=>"0",width=>100,height=>20})),"&nbsp;\n";
8033	}
8034
8035	print $q->br,"\n";
8036}
8037print "</DIV>";
8038do_footer();
8039}
8040
8041sub do_empty()
8042{
8043	my ($javascript);
8044
8045	$javascript = make_javascript({});
8046
8047	start_html_ss({ -expires => "+5s",  -script => $javascript,
8048		-onload => "LoadMenu()", -bgcolor => "#ffffff", -class=>'empty' });
8049
8050	if( $router eq "none" ) {
8051		print $q->h3(langmsg(9002,"Please select a device"));
8052	} else {
8053		print $q->h3(langmsg(9003,"Please select a target"));
8054	}
8055	do_footer();
8056}
8057
8058sub do_graph($)
8059{
8060# Start off.  We use onload() and Javascript to force reload the
8061# lefthand (menu) panel.
8062my ($javascript, $e);
8063my ($rrd, $curif);
8064my ($iconsuffix) = "";
8065my ($bgcolor,$legendi,$legendo,$legendx);
8066my ($inhtml) = $_[0]; # true if we want HTML page
8067
8068calctimezone();
8069
8070$iconsuffix = "-bw" if( $gstyle =~ /b/ );
8071
8072$javascript = make_javascript({}).graphpopupscript();
8073# We need to subsequently add the javascript for the actuals array if necessary
8074$bgcolor = $defbgcolour;
8075$bgcolor = $interfaces{$interface}{background} if($interface and defined $interfaces{$interface} and defined $interfaces{$interface}{background});
8076
8077if($inhtml) {
8078	my($class) = $interfaces{$interface}{mode}?$interfaces{$interface}{mode}:'generic';
8079	$class =~ s/^\177_//;
8080	start_html_ss({ -expires => "+5s",  -script => $javascript,
8081		-onload => "LoadMenu()", -bgcolor => $bgcolor,
8082		-class => $class },
8083	$interfaces{$interface}{xbackground}?$interfaces{$interface}{xbackground}:"");
8084}
8085
8086# Catch for if there are NO cfg files.
8087if( ! $interface or ! $router
8088    or $interface eq "none" or $interface =~ /^__/
8089	or $router eq "none" ) {
8090	if(!$inhtml) {
8091		if($opt_I) {
8092			print "Device: $router\nTarget: $interface\nError: no valid target was specified!\n";
8093		} else {
8094		print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
8095		}
8096		return;
8097	}
8098	print $q->h3(langmsg(9004,"No valid target is selected"));
8099	if( $#cfgfiles eq -1
8100		and $config{'routers.cgi-cfgfiles'} ne 'none' ) {
8101		print $q->p("You have no valid MRTG configuration files.  You should check your configuration in $conffile.".$q->br."["
8102			.$config{'routers.cgi-confpath'}.$pathsep
8103			.$config{'routers.cgi-cfgfiles'}."]"),"\n";
8104		print $q->p("NT users should check that this includes the correct drive letter.")."\n" if($config{'web-NT'});
8105		print $q->p("confpath = ".$config{'routers.cgi-confpath'});
8106		print $q->p("cfgfiles = ".$config{'routers.cgi-cfgfiles'});
8107	}
8108	do_footer();
8109	return;
8110}
8111
8112# Now for the RRD stuff
8113eval { require RRDs; };
8114if( $@ ) {
8115	if(!$inhtml) {
8116		if($opt_I) {
8117			print "Error: $@\n";
8118		} else {
8119		print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
8120		}
8121		return;
8122	}
8123	if($config{'web-paranoia'}
8124		and $config{'web-paranoia'}=~/[yY1]/) {
8125	print $q->h1(langmsg(8999,"Error")),"<CODE>cannot find RRDs.pm</CODE>\n";
8126	} else {
8127	print $q->h1(langmsg(8999,"Error")),"<CODE>cannot find RRDs.pm in ".(join " ",@INC)."</CODE>\n";
8128		print $q->p("You can visit the configuration verification page "
8129			.$q->a({href=>("$meurlfull?page=verify&rtr=".$q->escape($router)),
8130			target=>"_new"},"here."));
8131	}
8132	do_footer();
8133	return 0;
8134}
8135# Now, we have to do this differently depending on which gtype we have
8136# We do a switch for the different graphs.
8137# We have to call RRD to create them, and the IMG tag is created ready to
8138# stuff into the page!
8139$rrd = "";
8140if ( $interface =~ /^__/ ) { # compact and summary
8141	$curif = (keys(%interfaces))[0];
8142	$rrd = $interfaces{$curif}{rrd};
8143} elsif ( $interfaces{$interface}{usergraph} ) { #  user defined
8144	$rrd = $interfaces{$interfaces{$interface}{targets}->[0]}{rrd};
8145} else {
8146	$rrd = $interfaces{$interface}{rrd}
8147		if( defined $interfaces{$interface}{rrd} );
8148}
8149if($rrd and $rrdcached and $rrdcached!~/^unix:/) {
8150	my($pth) = $config{'routers.cgi-dbpath'};
8151		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
8152	$rrd =~ s/^$pth\/*//;
8153}
8154
8155# Timezone
8156if($interfaces{$interface}{timezone}) {
8157	$ENV{TZ} = $interfaces{$interface}{timezone} ;
8158	POSIX::tzset();
8159}
8160
8161# Last update stuff.
8162if( $rrd ) {
8163	$lastupdate = RRDs::last($rrd,@rrdcached);
8164	$e = RRDs::error();
8165} else {
8166	$e = langmsg(8002,"No RRD file defined for interface")." '$interface'";
8167}
8168if( $e ) {
8169	if(!$inhtml) {
8170		if($opt_I) {
8171			print "Error: $e\n";
8172		} else {
8173		print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
8174		}
8175		return;
8176	}
8177	print $q->h3("$interfaces{$interface}{shdesc}"),"\n";
8178	print $q->p("$interfaces{$interface}{desc}"),"\n";
8179	if($config{'web-paranoia'}
8180		and $config{'web-paranoia'}=~/[yY1]/) {
8181	print $q->p($q->b(langmsg(8003,"Error reading RRD database")).$q->br."Check that MRTG has run successfully on this device, and has created the RRD file.  If using rrdcached, check that this is running and available.")."\n";
8182	} else {
8183	print $q->p($q->b(langmsg(8003,"Error reading RRD database")." $rrd").$q->br.$e.$q->br."Check that MRTG has run successfully on this device, and has created the RRD file.")."\n";
8184	print $q->p("Check that rrdcached is running on $rrdcached")
8185		if($rrdcached and ($e=~/No such file/));
8186	# We may need to give a more helpful error message here if the
8187	# user is asking for a nonexistant archive date
8188	print $q->p("You can visit the configuration verification page "
8189		.$q->a({href=>("$meurlfull?page=verify&rtr=".$q->escape($router)),
8190		target=>"_new"},"here."));
8191	}
8192#	print $q->dump;
8193} else {
8194	# any defined pagetop stuff
8195	if($inhtml) {
8196		print "<DIV class=pagetop>";
8197		print expandvars($config{'routers.cgi-pagetop'}),"\n"
8198			if( defined $config{'routers.cgi-pagetop'} );
8199		if((( defined $config{'routers.cgi-mrtgpagetop'}
8200			and $config{'routers.cgi-mrtgpagetop'} =~ /y/i
8201			and !$interfaces{$interface}{usergraph})
8202			or $interfaces{$interface}{withtop} )
8203			and $interfaces{$interface}{pagetop}
8204		) {
8205			print expandvars($interfaces{$interface}{pagetop}),"\n";
8206		}
8207		print "</DIV>";
8208	}
8209	my $suffix = ( $gtype =~ /s/ ) ? "s" : "";
8210	$suffix .= "-" if( $gtype =~ /-/ );
8211	if( defined $interfaces{$interface}{suppress} ) {
8212		my $pat = "[".$interfaces{$interface}{suppress}."]";
8213		$gtype =~ s/$pat//g;
8214	}
8215	foreach my $gt ( '6','d','w','m','y' ) {
8216		next if ( $gtype !~ /$gt/ );
8217		print $q->h4($gtypes{$gt}) if((length($gtype)>1) and ($gtype!~/s/));
8218		make_graph($inhtml,"$gt$suffix",$interface) ;
8219		print $q->br,"\n" if($inhtml and (length($gtype) > 2 or $uopts=~/s/)
8220			and ($gtype!~/s/));
8221	}
8222
8223	return if(!$inhtml); # we can leave now
8224
8225	print $q->br;
8226	print "<TABLE border=0>";
8227	print "<TR><TD>".langmsg(3205,"Data archived")
8228		.":</TD><TD>$archdate</TD></TR>\n" if($archdate and !$basetime);
8229	print "<TR><TD>".langmsg(3203,"Last update").": </TD><TD>"
8230		.longdate($lastupdate)."</TD></TR>\n" unless($basetime);
8231	print "<TR><TD>".langmsg(3204,"Timezone").":</TD><TD>"
8232		.$interfaces{$interface}{timezone}."</TD></TR>\n"
8233		if($interfaces{$interface}{timezone});
8234	print "</TABLE>\n";
8235	if((
8236#		( defined $config{'routers.cgi-percentile'}
8237#		and $config{'routers.cgi-percentile'} =~ /y/i )
8238		   $interfaces{$interface}{total}
8239		or $interfaces{$interface}{percentile}
8240		) and !$interfaces{$interface}{nodetails}
8241		and !$interfaces{$interface}{nolegend}
8242		) {
8243		my( $i, $pcdesc, $inarr, $outarr, $sfx );
8244
8245		print "<TABLE border=0 >\n";
8246
8247		# Loop through interfaces, if on userdefined graph
8248		foreach $curif ( $interfaces{$interface}{usergraph}?
8249			(@{$interfaces{$interface}{targets}}):($interface) ) {
8250		# Skip this if it is not an active graph
8251		if($interfaces{$interface}{active}) { next if(!isactive($curif)); }
8252		print "<TR><TD colspan=5 align=left>"
8253			.$q->a({href=>("$meurlfull?".optionstring({
8254					'if'=>$curif, 'page'=>'graph'
8255				} ))}, $q->i($interfaces{$curif}{desc}))
8256			."</TD></TR>\n"
8257			if($interfaces{$interface}{usergraph});
8258
8259		$sfx = "";
8260		($legendi,$legendo,$legendx)=(langmsg(2204,"IN:"),langmsg(2205,"OUT:"),"");
8261		$legendi=$interfaces{$curif    }{legendi}
8262			if(defined $interfaces{$curif    }{legendi});
8263		$legendo=$interfaces{$curif    }{legendo}
8264			if(defined $interfaces{$curif    }{legendo});
8265		$legendx=$interfaces{$curif    }{legendx}
8266			if(defined $interfaces{$curif    }{legendx});
8267		$legendi =~ s/ /&nbsp;/g; $legendo =~ s/ /&nbsp;/g;
8268		$sfx = "-" if( $gtype =~ /-/ );
8269		# Loop through time periods, if on multiple graphs
8270		foreach $i  ( qw/d w m y/ ) {
8271		  next if((index $gtype, $i) < 0);
8272		  ( $pcdesc, $inarr, $outarr ) = calc_percentile($curif,$i.$sfx,$PERCENT);
8273		  if($pcdesc) {
8274#			print "<TR>".$q->td("").$q->td($q->b($legendi))
8275#				.$q->td($q->b($legendo));
8276		    if($interfaces{$interface}{total}) {
8277			print "<TR>".$q->td($q->b(langmsg(2301,"Total over")." $pcdesc:"));
8278			print $q->td($legendi).$q->td({align=>"right"},doformat($$inarr[1],
8279$interfaces{$curif    }{fixunits},$interfaces{$curif    }{integer})
8280	.$interfaces{$curif    }{totunit})
8281	.$q->td("") if(!$interfaces{$interface}{noi});
8282			print $q->td($legendo).$q->td({align=>"right"},doformat($$outarr[1],
8283$interfaces{$curif    }{fixunits},$interfaces{$curif    }{integer})
8284	.$interfaces{$curif    }{totunit2})
8285	.$q->td("")  if(!$interfaces{$interface}{noo});
8286			print "</TR>\n";
8287		    }
8288		    if($interfaces{$interface}{percentile}) {
8289			my($pclabel);
8290			print "<TR>".$q->td($q->b(langmsg(2300,$PERCENT."th Percentile for")." $pcdesc:"));
8291			if(!$interfaces{$interface}{noi} and !$interfaces{$curif}{noi}) {
8292				$pclabel = "";
8293				$pclabel = " ("
8294				  .doformat(($$inarr[0]/$interfaces{$curif}{max}*100.0),1,0)
8295				  ."%)" if($interfaces{$curif}{percent} and $interfaces{$curif}{max});
8296				print $q->td($legendi).$q->td({align=>"right"},
8297					doformat($$inarr[0], $interfaces{$curif}{fixunits},0)
8298					.$interfaces{$curif}{unit}) ;
8299				print $q->td($pclabel);
8300			  }
8301			  if(!$interfaces{$interface}{noo} and !$interfaces{$curif}{noo}) {
8302				$pclabel = "";
8303				$pclabel = " ("
8304				  .doformat(($$outarr[0]/$interfaces{$curif}{max}*100.0),1,0)
8305				  ."%)"
8306					if($interfaces{$curif}{percent}
8307						and $interfaces{$curif}{max});
8308				print $q->td($legendo).$q->td({align=>"right"},
8309					doformat($$outarr[0], $interfaces{$curif}{fixunits},0)
8310					.$interfaces{$curif}{unit2}) ;
8311				print $q->td($pclabel);
8312			  }
8313			  print "</TR>\n";
8314		    }
8315		  } else {
8316			print "<TR><TD>".langmsg(8004,"Error in ${PERCENT}th percentile")
8317			.":</TD><TD colspan=5>"
8318			."[".$$inarr[2]."]".$q->br
8319			."[".$$outarr[2]."]</TD></TR>" if($$inarr[2] or $$outarr[2]);
8320		  } # pcdesc
8321		} # foreach	timeperiod
8322		} # foreach interface
8323		print "</TABLE>\n";
8324	}
8325
8326	print $q->br."<DIV class=pagefoot>";
8327	if((( defined $config{'routers.cgi-mrtgpagefoot'}
8328		and $config{'routers.cgi-mrtgpagefoot'} =~ /y/
8329		and !$interfaces{$interface}{usergraph})
8330		or $interfaces{$interface}{withfoot})
8331		and $interfaces{$interface}{pagefoot}
8332	) {
8333		print expandvars($interfaces{$interface}{pagefoot}),"\n";
8334	}
8335	print expandvars($config{'routers.cgi-pagefoot'}),"\n"
8336		if( defined $config{'routers.cgi-pagefoot'} );
8337	print "</DIV><DIV class=extensions>";
8338
8339	# any extensions defined for this target?
8340	if( defined $interfaces{$interface}{extensions}
8341		and $uopts !~/s/ ) {
8342		my($ext, $u, $targ);
8343		print $q->hr,"\n";
8344		foreach $ext ( @{$interfaces{$interface}{extensions}} ) {
8345			if($seclevel<$ext->{level}) {
8346#				print $ext->{desc}." (".$ext->{level}.")".$q->br."\n";
8347				next;
8348			}
8349			$targ = "graph";
8350			$targ = $ext->{target} if( defined $ext->{target} );
8351			$u=$ext->{url};
8352			if(!$ext->{noopts}) {
8353			$u .= "?x=2" if( $u !~ /\?/ );
8354			$u .= "&fi=".$q->escape($router)."&ta="
8355				.$q->escape($interface)."&url=".$q->escape($q->url());
8356			$u .= "&t=".$q->escape($targ);
8357			$u .= "&L=".$seclevel;
8358			$u .= "&uopts=".$uopts if($uopts);
8359			$u .= "&h=".$q->escape($interfaces{$interface}{hostname})
8360				if(defined $interfaces{$interface}{hostname});
8361			$u .= "&c=".$q->escape($interfaces{$interface}{community})
8362				if(defined $interfaces{$interface}{community}
8363				and $ext->{insecure});
8364			$u .= "&ifno=".$interfaces{$interface}{ifno}
8365				if(defined $interfaces{$interface}{ifno});
8366			$u .= "&b=".$q->escape("javascript:history.back();history.back()")
8367				."&conf=".$q->escape($conffile);
8368				$u .= "&ad=$archdate" if($archdate);
8369			} elsif( $ext->{noopts} == 2 ) {
8370				$u .= "&L=$seclevel&xgtype=$gtype&xgstyle=$gstyle";
8371				$u .= "&arch=$archdate" if($archdate);
8372			}
8373			print $q->img( { height=>15, width=>15,
8374				src=>($config{'routers.cgi-smalliconurl'}.$ext->{icon}) })
8375				."&nbsp;";
8376#			print $q->img( { height=>15, width=>15,
8377#				src=>($config{'routers.cgi-iconurl'}."alert-sm.gif") })
8378#				."&nbsp;" if($ext->{insecure});
8379			print $q->a( { href=>$u, target=>$targ },
8380					expandvars($ext->{desc})).$q->br."\n";
8381		}
8382	}
8383
8384	print "</DIV><DIV class=icons>";
8385	# routers.cgi page footer
8386	if( $gstyle !~ /p/ ) {
8387		my( $u, $ngti, $ngto ) = ("","","");
8388	print $q->hr;
8389	print "\n",$q->a({href=>"javascript:location.reload(true)"},
8390		$q->img({src=>"${config{'routers.cgi-iconurl'}}refresh$iconsuffix.gif",alt=>langmsg(5003,"Refresh"),border=>"0",width=>100,height=>20})),"\n"
8391		if(!$archdate);
8392#	print $q->a({href=>"javascript:parent.makebookmark('"
8393#		.$q->escape($router)."','".$q->escape($interface)
8394#		."','$gtype','$gstyle','$gopts','$baropts','".$q->escape($extra)."')"},
8395	print $q->a({href=>"$meurlfull?".optionstring({page=>"", bars=>"",
8396		xmtype=>"", xgstyle=>""}), target=>"_top" },
8397		$q->img({src=>"${config{'routers.cgi-iconurl'}}bookmark$iconsuffix.gif",alt=>langmsg(5016,"Bookmark"),border=>"0",width=>100,height=>20})), "\n";
8398	if( $gtype eq "6" ) { $ngto = "d"; }
8399	elsif( $gtype eq "d" ) { $ngto = "w"; $ngti='6' if($usesixhour); }
8400	elsif( $gtype eq "w" ) { $ngti = "d"; $ngto = "m"; }
8401	elsif( $gtype eq "m" ) { $ngti = "w"; $ngto = "y"; }
8402	elsif( $gtype eq "y" ) { $ngti = "m"; }
8403	if( $ngti ) {
8404		print $q->a({href=>"$meurlfull?".optionstring({xgtype=>"$ngti"}), target=>"graph"},
8405			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomin.gif",
8406			alt=>langmsg(5017,"Zoom In"),border=>"0",width=>100,height=>20})),"\n";
8407	}
8408	if( $ngto ) {
8409		print $q->a({href=>"$meurlfull?".optionstring({xgtype=>"$ngto"}), target=>"graph"},
8410			$q->img({src=>"${config{'routers.cgi-iconurl'}}zoomout.gif",
8411			alt=>langmsg(5018,"Zoom Out"),border=>"0",width=>100,height=>20})),"\n";
8412	}
8413#	if(!$interfaces{$interface}{usergraph}) {
8414	print $q->a({href=>"$meurlfull?".optionstring({page=>"csv"}), target=>"graph"},
8415		$q->img({src=>"${config{'routers.cgi-iconurl'}}csv.gif",
8416		alt=>langmsg(5019,"CSV Download"),border=>"0",width=>100,height=>20})),"\n";
8417#	}
8418	if( defined $config{'routers.cgi-archive'}
8419		and $config{'routers.cgi-archive'} =~ /[y1]/i ) {
8420		print $q->a({href=>"$meurlfull?".optionstring({page=>"archive"}),
8421			target=>"graph"},
8422			$q->img({src=>"${config{'routers.cgi-iconurl'}}archive.gif",
8423			alt=>langmsg(5020,"Add to archive"),border=>"0",width=>100,height=>20})),"\n";
8424	}
8425	my($nuopts) = $uopts; # 3-way toggle
8426	if($nuopts =~ /r/) {
8427		$nuopts =~  s/r/R/g;
8428	} elsif($nuopts =~ /R/) {
8429		$nuopts =~  s/[rR]//g;
8430	} else {
8431		$nuopts .= 'r';
8432	}
8433	print $q->a({href=>"$meurlfull?".optionstring({uopts=>"$nuopts"}),
8434		target=>"graph"},
8435		$q->img({src=>"${config{'routers.cgi-iconurl'}}rescale.gif",
8436		alt=>langmsg(5021,"Rescale"),border=>"0",width=>100,height=>20})),"\n";
8437
8438	print $q->br,"\n";
8439
8440
8441	} # gstyle not p
8442	print "</DIV>";
8443}
8444# Finish off the page (this does the ending body and html tags)
8445do_footer();
8446}
8447
8448# Information on this router
8449sub do_info()
8450{
8451# Start off.  We use onload() and Javascript to force reload the
8452# lefthand (menu) panel.
8453my ($javascript, $ifkey,$x, $icon);
8454my ($acount,$archivepat,@archive,$archives);
8455
8456$javascript = make_javascript({});
8457
8458start_html_ss({ -expires => "+5s",  -script => $javascript,
8459	-onload => "LoadMenu()", -class=>'info' });
8460
8461# Here we build up a page of info, with lotsalinks.
8462
8463print $q->center($q->h2($routers{$router}{desc}))."\n";
8464
8465print $q->h3(langmsg(3004,"Device Information")),"\n";
8466
8467print $q->a({href=>"$meurlfull?".optionstring({page=>"graph",if=>"_summary_"}),
8468	target=>"graph"},
8469	$q->b("$router: ".$routers{$router}{shdesc}.": "
8470		.$routers{$router}{desc})),$q->br,"\n";
8471print $q->br.$q->b(langmsg(3005,"MRTG config file").": ").$routers{$router}{file}."\n";
8472print $q->br.$q->p("WorkDir: ".($routers{$router}{workdir}?$routers{$router}{workdir}:$config{'routers.cgi-dbpath'}))."\n";
8473print $q->b("Targets:").$q->br();
8474print "<UL>";
8475$ifkey = ""; # we want this later
8476foreach (sort byifdesc keys (%interfaces)) {
8477	next if(!$_); # avoid rogue records
8478	next if(/^__/);
8479	next if($interfaces{$_}{mode} =~ /^\177_AUTO/); # system created
8480	# count archived copies
8481	$archivepat = $router; $archivepat =~ s/[\?#\\\/]//g;
8482	$archivepat = $config{'routers.cgi-graphpath'}.$pathsep
8483		.$archivepat.$pathsep.$_.$pathsep."*.*";
8484	@archive = glob($archivepat);
8485	$acount = $#archive + 1;
8486	# now the data line
8487	$icon = $q->img({src=>($config{'routers.cgi-smalliconurl'}.$interfaces{$_}{icon})
8488		,width=>15,height=>15})." ";
8489	$ifkey = $_ if(!$ifkey and $interfaces{$_}{community}
8490		and $interfaces{$_}{hostname});
8491	if( $acount == 1 ) {
8492		$archives = $q->br.langmsg(3300,"This target has one archived graph.");
8493	} elsif( $acount > 1 ) {
8494		$archives = $q->br.langmsg(3301,"This target has")
8495			." $acount ".langmsg(3302,"archived graphs.");
8496	} else {
8497		$archives = "";
8498	}
8499	if( $interfaces{$_}{usergraph} ) {
8500		print $q->li( $icon.$q->a(
8501			{href=>"$meurlfull?".optionstring({if=>"$_"}),
8502			target=>"graph"},
8503			$interfaces{$_}{desc})." [$_] "
8504			.($interfaces{$_}{graphstyle}?("&lt;".$interfaces{$_}{graphstyle}."&gt;"):"")
8505			.($interfaces{$_}{default}?"[DEFAULT]":"")
8506			." \n$archives");
8507	} elsif( defined $interfaces{$_}{ifno} ) {
8508		# interface number
8509		print $q->li( $icon.$q->a(
8510			{href=>"$meurlfull?".optionstring({if=>"$_"}),
8511			target=>"graph"},
8512			"#".$interfaces{$_}{ifno}.": ".$interfaces{$_}{desc}
8513		)." [".$interfaces{$_}{target}."] ".langmsg(6200,"Max")." "
8514			.doformat($interfaces{$_}{max},$interfaces{$_}{fixunits},1)
8515			.$interfaces{$_}{unit}
8516			." {".$interfaces{$_}{mode}."} "
8517			.($interfaces{$_}{default}?"[DEFAULT]":"")
8518			."\n$archives"),"\n";
8519	} elsif( defined $interfaces{$_}{ifdesc} ) {
8520		# interface description
8521		print $q->li( $icon.$q->a(
8522			{href=>"$meurlfull?".optionstring({if=>"$_"}),
8523			target=>"graph"},
8524			$interfaces{$_}{shdesc}.": ".$interfaces{$_}{desc}
8525		)." [".$interfaces{$_}{target}."] ".langmsg(6200,"Max")." "
8526			.doformat($interfaces{$_}{max},$interfaces{$_}{fixunits},1)
8527			.$interfaces{$_}{unit}
8528			." {".$interfaces{$_}{mode}."} "
8529			.($interfaces{$_}{default}?"[DEFAULT]":"")
8530			."\n$archives"),"\n";
8531	} elsif( defined $interfaces{$_}{ipaddress} ) {
8532		# IP address
8533		print $q->li( $icon.$q->a(
8534			{href=>"$meurlfull?".optionstring({if=>"$_"}),
8535			target=>"graph"},
8536			$interfaces{$_}{ipaddress}.": ".$interfaces{$_}{desc}
8537		)." [".$interfaces{$_}{target}."] "
8538				.langmsg(6200,"Max")." "
8539			.doformat($interfaces{$_}{max},$interfaces{$_}{fixunits},1)
8540				.$interfaces{$_}{unit}
8541			." {".$interfaces{$_}{mode}."} "
8542			.($interfaces{$_}{default}?"[DEFAULT]":"")
8543			."\n$archives"),"\n";
8544	} else {
8545		# userdefined and unknown
8546		print $q->li( $icon.$q->a(
8547			{href=>"$meurlfull?".optionstring({if=>"$_"}),
8548			target=>"graph"},
8549			$interfaces{$_}{desc})." [".$interfaces{$_}{target}."] "
8550				.langmsg(6200,"Max")." "
8551				.doformat($interfaces{$_}{max},$interfaces{$_}{fixunits},1)
8552				.$interfaces{$_}{unit}
8553#				."(f=".$interfaces{$_}{factor}.",m=".$interfaces{$_}{mult}.")"
8554				." {".$interfaces{$_}{mode}."}"
8555				.($interfaces{$_}{graphstyle}?("&lt;".$interfaces{$_}{graphstyle}."&gt;"):"")
8556				.($interfaces{$_}{default}?"[DEFAULT]":"")
8557				."\n$archives"
8558			),"\n";
8559	}
8560}
8561print "</UL>\n";
8562
8563# Can we call out to the routingtable.cgi program?
8564if( defined $config{'routers.cgi-routingtableurl'}
8565	and ( !defined $routers{$router}{routingtable}
8566		or $routers{$router}{routingtable} eq "y" )) {
8567	if($ifkey) {
8568	print $q->a({target=>"_self",
8569		href=>($config{'routers.cgi-routingtableurl'}
8570		."?r=".$q->escape($interfaces{$ifkey}{hostname})
8571		."&h=".$q->escape($interfaces{$ifkey}{hostname})
8572		."&c=".$q->escape($interfaces{$ifkey}{community})
8573		."&url=".$q->escape($q->url())
8574		."&t=graph&b=javascript:".$q->escape("history.back();history.back()")
8575		."&conf=".$q->escape($conffile))},
8576		langmsg(3303,"Show routing table for this device"))." (may take some time)",
8577			$q->br,$q->br,"\n";
8578	} else {
8579		print langmsg(3304,"Routing table information not available."),$q->br,
8580			$q->br,"\n";
8581	}
8582}
8583
8584# Finish off the page (this does the ending body and html tags)
8585do_footer();
8586}
8587
8588############################################################################
8589# Export of data to CSV format -- single RRD
8590sub do_export()
8591{
8592	my( $start, $step, $names, $data, $line);
8593	my( $mstart, $mstep, $mnames, $maxdata, $mline );
8594	my( $rrd, @opts, $e, $d, $t, $i, $r, @dat );
8595	my( $thisif, $startpoint, $endpoint, $resolution );
8596
8597	my( @allifs );
8598
8599	$comma = substr( $config{'web-comma'},0,1 )
8600		if(defined $config{'web-comma'});
8601	$comma = ',' if(!$comma);
8602
8603	eval { require RRDs; };
8604	if( $@ ) {
8605 		print "ERROR".$comma."Cannot find RRDs.pm!".$comma.$@;
8606		return;
8607	}
8608	if( !$interface ) {
8609		print langmsg(9004,"No interface selected!");
8610		return;
8611	}
8612
8613	# If this is a normal one, then just one interface.  If it is a
8614	# userdefined, then we wil have a list of targets to process.
8615	@allifs = ( $interface );
8616	@allifs = @{$interfaces{$interface}{targets}}
8617		if( $interfaces{$interface}{targets} );
8618
8619	foreach $thisif ( @allifs ) {
8620
8621	# Header line
8622	print "\"Hostname\"$comma\"Target\"$comma\"Sample Date YMD\"$comma\"Sample Time HHMM\"$comma\"Count in seconds\"";
8623	if( $interfaces{$thisif}{aspercent}) {
8624		print "$comma\"Raw data 1\""
8625		if($interfaces{$thisif}{legend1} and !$interfaces{$thisif}{noi});
8626		print "$comma\"Raw data 2\""
8627		if($interfaces{$thisif}{legend2} and !$interfaces{$thisif}{noo});
8628	} elsif( $interfaces{$thisif}{dorelpercent} ) {
8629		print "$comma\"Raw data 1\"";
8630		print "$comma\"Raw data 2\"";
8631	}
8632	print "$comma\"".$interfaces{$thisif}{legend1}.($interfaces{$thisif}{unit}?
8633		(' in '.$interfaces{$thisif}{unit}):'').'"'
8634		if($interfaces{$thisif}{legend1} and !$interfaces{$thisif}{noi});
8635	print "$comma\"".$interfaces{$thisif}{legend2}.($interfaces{$thisif}{unit}?
8636		(' in '.$interfaces{$thisif}{unit}):'').'"'
8637		if($interfaces{$thisif}{legend2} and !$interfaces{$thisif}{noo});
8638	if( $gtype !~ /6/ ) {
8639	if( $interfaces{$thisif}{aspercent} ) {
8640		print "$comma\"Raw max data 1\""
8641		if($interfaces{$thisif}{legend1} and !$interfaces{$thisif}{noi});
8642		print "$comma\"Raw max data 2\""
8643		if($interfaces{$thisif}{legend2} and !$interfaces{$thisif}{noo});
8644	} elsif( $interfaces{$thisif}{dorelpercent} ) {
8645		print "$comma\"Raw max data 1\"";
8646		print "$comma\"Raw max data 2\"";
8647	}
8648	print "$comma\"".$interfaces{$thisif}{legend3}.($interfaces{$thisif}{unit}?
8649		(' in '.$interfaces{$thisif}{unit}):'').'"'
8650		if($interfaces{$thisif}{legend3} and !$interfaces{$thisif}{noi});
8651	print "$comma\"".$interfaces{$thisif}{legend4}.($interfaces{$thisif}{unit}?
8652		(' in '.$interfaces{$thisif}{unit}):'').'"'
8653		if($interfaces{$thisif}{legend4} and !$interfaces{$thisif}{noo});
8654	}
8655	print "\r\n";
8656	$i = $interfaces{$thisif}{shdesc};
8657	$r = $routers{$router}{desc};
8658	$r = $interfaces{$thisif}{hostname} if(!$r);
8659	$r = $router if(!$r);
8660	$r = "Unknown" if(!$r);
8661
8662	$rrd = $interfaces{$thisif}{rrd};
8663	if($rrd and $rrdcached and $rrdcached!~/^unix:/) {
8664		my($pth) = $config{'routers.cgi-dbpath'};
8665		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
8666		$rrd =~ s/^$pth\/*//;
8667	}
8668	foreach ( $gtype ) {
8669		/y/ and do { $resolution = 3600; $startpoint = "-1y";
8670			last; };
8671		/m/ and do { $resolution = 1800; $startpoint = "-1month";
8672			last; };
8673		/w/ and do { $resolution = 300; $startpoint = "-7d";
8674			last; };
8675		/6/ and do { $resolution = 60*$interfaces{$thisif}{interval};
8676			$startpoint = "-6h"; last; };
8677		$resolution = 60*$interfaces{$thisif}{interval}; # interval
8678		$startpoint = "-24h"; # 1 day
8679	}
8680	$resolution = 300 if(!$resolution);
8681
8682	if($basetime) {
8683		@opts = ( $rrd, "AVERAGE", "-e", $basetime,
8684			"-s", "end".$startpoint );
8685	} elsif( $gtype =~ /-/ ) {
8686		@opts = ( $rrd, "AVERAGE", "-e", "now".$startpoint,
8687			"-s", "end".$startpoint );
8688	} elsif( $uselastupdate ) {
8689		$lastupdate = RRDs::last($rrd,@rrdcached);
8690		$e = RRDs::error();
8691		if(!$lastupdate) {
8692			print "Error reading rrd:\n$e\n";
8693			return;
8694		}
8695		if($archivetime and $uselastupdate > 1 ) {
8696		@opts = ( $rrd, "AVERAGE", "-e", $archivetime, "-s", "end".$startpoint );
8697		} else {
8698		@opts = ( $rrd, "AVERAGE", "-e", $lastupdate, "-s", "end".$startpoint );
8699		}
8700	} else {
8701		@opts = ( $rrd, "AVERAGE", "-s", $startpoint );
8702	}
8703
8704	# Fetch data
8705	( $start, $step, $names, $data ) = RRDs::fetch( @opts,@rrdcached );
8706	if( !$start or !$data ) {
8707		$e = RRDs::error();
8708		print "Error retrieving data - do you have enough stored?\n";
8709		print "Check that you have enough real data gathered to be able to export.\n";
8710		print "$e\n";
8711		return;
8712	}
8713	if( $gtype !~ /6/ ) {
8714		$opts[1] = 'MAX';
8715		( $mstart, $mstep, $mnames, $maxdata ) = RRDs::fetch( @opts,@rrdcached );
8716		# maxdata may now be null, if we dont have a MAX RRA available.
8717	} else {
8718		$maxdata = 0; # 6-hour graphs never have MAX available.
8719	}
8720
8721	# Print data
8722	foreach $line ( @$data ) {
8723		@dat = localtime $start;
8724		$d = sprintf "%04d/%02d/%02d",($dat[5]+1900),($dat[4]+1),$dat[3];
8725		$t = sprintf "%02d:%02d",$dat[2],$dat[1]; # hh:mm
8726		print "\"$r\"$comma\"$i\"$comma$d$comma$t$comma$start";
8727		if($interfaces{$thisif}{aspercent} ) {
8728			printf "$comma%12.4f", ($$line[0]*$interfaces{$thisif}{mult})
8729				if(!$interfaces{$thisif}{noi});
8730			printf "$comma%12.4f", ($$line[1]*$interfaces{$thisif}{mult})
8731				if(!$interfaces{$thisif}{noo});
8732			printf "$comma%12.4f", 100.0*($$line[0]/$interfaces{$thisif}{max})
8733				if(!$interfaces{$thisif}{noi});
8734			printf "$comma%12.4f", 100.0*($$line[1]/$interfaces{$thisif}{max})
8735				if(!$interfaces{$thisif}{noo});
8736		} elsif( $interfaces{$thisif}{dorelpercent}) {
8737			printf "$comma%12.4f", ($$line[0]*$interfaces{$thisif}{mult});
8738			printf "$comma%12.4f", ($$line[1]*$interfaces{$thisif}{mult});
8739			printf "$comma%12.4f", 100.0*($$line[0]/$$line[1]);
8740		} else {
8741			printf "$comma%12.4f", ($$line[0]*$interfaces{$thisif}{mult}*$interfaces{$thisif}{factor})
8742				if(!$interfaces{$thisif}{noi});
8743			printf "$comma%12.4f", ($$line[1]*$interfaces{$thisif}{mult}*$interfaces{$thisif}{factor})
8744				if(!$interfaces{$thisif}{noo});
8745		}
8746		if($gtype !~ /6/) {
8747		  if($maxdata) {
8748			$mline = shift @$maxdata;
8749			$mline = [ 0,0 ] if(!$mline); # in case data runs out
8750			if($interfaces{$thisif}{aspercent} ) {
8751			printf "$comma%12.4f", ($$mline[0]*$interfaces{$thisif}{mult})
8752				if(!$interfaces{$thisif}{noi});
8753			printf "$comma%12.4f", ($$mline[1]*$interfaces{$thisif}{mult})
8754				if(!$interfaces{$thisif}{noo});
8755			printf "$comma%12.4f", 100.0*($$mline[0]/$interfaces{$thisif}{max})
8756				if(!$interfaces{$thisif}{noi});
8757			printf "$comma%12.4f", 100.0*($$mline[1]/$interfaces{$thisif}{max})
8758				if(!$interfaces{$thisif}{noo});
8759			} elsif( $interfaces{$thisif}{dorelpercent}) {
8760				printf "$comma%12.4f", ($$mline[0]*$interfaces{$thisif}{mult});
8761				printf "$comma%12.4f", ($$mline[1]*$interfaces{$thisif}{mult});
8762				printf "$comma%12.4f", 100.0*($$mline[0]/$$mline[1]);
8763			} else {
8764				printf "$comma%12.4f", ($$mline[0]*$interfaces{$thisif}{mult}*$interfaces{$thisif}{factor})
8765					if(!$interfaces{$thisif}{noi});
8766				printf "$comma%12.4f", ($$mline[1]*$interfaces{$thisif}{mult}*$interfaces{$thisif}{factor})
8767					if(!$interfaces{$thisif}{noo});
8768			}
8769		  } else {
8770			printf "$comma%12.4f", ($$line[0]*$interfaces{$thisif}{mult}*$interfaces{$thisif}{factor})
8771				if(!$interfaces{$thisif}{noi});
8772			printf "$comma%12.4f", ($$line[1]*$interfaces{$thisif}{mult}*$interfaces{$thisif}{factor})
8773				if(!$interfaces{$thisif}{noo});
8774			if($interfaces{$thisif}{aspercent}) {
8775				printf "$comma%12.4f", 100.0*($$line[0]/$interfaces{$thisif}{max})
8776					if(!$interfaces{$thisif}{noi});
8777				printf "$comma%12.4f", 100.0*($$line[1]/$interfaces{$thisif}{max})
8778					if(!$interfaces{$thisif}{noo});
8779			} # aspercent
8780		  } # maxdata exists
8781		} # not 6
8782		printf "\r\n";
8783		$start += $step;
8784	} # foreachline
8785
8786	} # next interface in list
8787
8788}
8789############################################################################
8790# Help page
8791
8792sub do_help()
8793{
8794	my($vurl,$iurl);
8795	my($javascript);
8796
8797	$javascript = make_javascript({if=>"__none",rtr=>"none"});
8798
8799	start_html_ss({-script => $javascript, -onload => "LoadMenu()",
8800		-class=>'help' });
8801
8802	$vurl = "$meurlfull?page=verify&rtr=".$q->escape($router);
8803	$iurl = $config{'routers.cgi-smalliconurl'};
8804
8805	print $q->h1(langmsg(3006,"Information and Help"));
8806
8807	print <<EOT
8808<h2>Updates and support</h2>
8809Updates to the routers.cgi script may be obtained from
8810<a href=$APPURL>$APPURL</a>. During development phases there may be daily
8811updates, so check every so often.  Support is available via the
8812<a href=$FURL>support forum</a>,
8813<a href=$MLURL>mailing list</a> and
8814directly - check <a href=$APPURL>this link</a> for more details.
8815<HR>
8816<h2>Publications</h2>
8817The new MRTG/RRD/Routers2 book,
8818<a href=$BURL target=_top>Using MRTG with RRDtool and Routers2</a>, can be
8819obtained in dead-tree format from <A HREF=$BURL target=_top>here</a>.
8820This should be able to help you to make the most of your MRTG installation,
8821and also help with any installation and configuration problems!
8822<hr>
8823<h2>Online help</h2>
8824<UL>
8825<li>Diagnose configuration problems
8826<a target=_new href=$vurl>here</a> (opens new window)</li>
8827<li>Show available link icons
8828<a target=_new href=$iurl>here</a> (opens new window)</li>
8829</UL>
8830<hr>
8831<h2>Credits</h2>
8832Thanks to the following people for supporting the development of
8833this software by <a target=_new href=$WLURL >
8834sending me a gift</a> on my Wishlist!
8835All listed in no particular order, in case you were wondering.
8836<UL>
8837<LI>Pall Wiberg Joensen, Faroese Telecom, Faroe Islands</li>
8838<li>Ben Higgins, Dovetail Internet, USA</li>
8839<li>Mike Bernhardt, Arsin, USA</li>
8840<li>EDS Europe</li>
8841<li>Ruedi Kehl, Manor AG, Switzerland (twice!)</li>
8842<li>Allied Domecq, UK</li>
8843<li>Rob</li>
8844<li>Peter Cohen, Telia, USA</li>
8845<li>Jay Christopherson</li>
8846<li>David Hares, Network One</li>
8847<li>Reuben Farrelly, Netfilter, Australia</li>
8848<li>Network Operations, Roche Diagnostics GmbH, Germany</li>
8849<li>Keith Johnson, UK</li>
8850<li>J Herrera, Brown Publishing</LI>
8851<li>Kristin Gorman, New York, USA</li>
8852<li>Inigo T Storm, ASV AG, Hamburg, Germany</li>
8853<li>M Williams, London, UK</li>
8854<li>Joseph Truong, USA</li>
8855<LI>Babul Mukherjee, The Montopolis Group, San Antonio, USA</li>
8856<li>Matevz Turk, Slovenia</li>
8857<li>Barry Basselgia; the most generous contributor so far</li>
8858<li>Gary Higgs</li>
8859<li>Scott Monk, USA</li>
8860<li>Robert Gibson, Texas, USA</li>
8861<li>Andrew McClure, Santa Barbara, USA</li>
8862<li>Innokentiy Georgeievskiy, Moscow, Russia (Twice!)</li>
8863<li>Kirsten Johnson</li>
8864<li>Matti Wiersmuller, Switzerland</li>
8865<li>University of Auckland, New Zealand</li>
8866<li>Steven Hay, Alberta, Canada.</li>
8867<LI>Dan Lowry, Scituate, USA</li>
8868<LI>Alan Dean, Prospect, USA</li>
8869<LI>Thomas Thong, Alameda, USA</li>
8870<LI>Steve McDonald, Indiana, USA</li>
8871<LI>Harry Edmondson, USA</li>
8872<LI>Saul Herbert/Hugh David, ADV Films, UK and Australia</li>
8873<li>Francesco Duranti, Kuwait Petroleum Italia</li>
8874<li>Herman Poon, Ontario, Canada</li>
8875<li>Peter Hall, Texas, USA</li>
8876<li>Casey Scott, F5 Networks, USA</li>
8877<li>Steve Litchfield, Georgia, USA</li>
8878<li>Rodrigo Schneider</li>
8879<li>Christopher Noyes, CT, USA</li>
8880<li>GroundWork Open Systems, USA</li>
8881<li>Ask.com, USA</li>
8882<li>Andrew Lewis</li>
8883<li>Yuriy Vlasov</li>
8884<li>Scott Neader</li>
8885<LI>Dave Diamond, USA</LI>
8886<LI>Timothy Graham</li>
8887<LI>Matthew Elmore, AL, USA</LI>
8888<li>Plus various generous but anonymous people</li>
8889
8890</ul>
8891V2.0 Beta testers:
8892<UL>
8893<li>Garry Cook, MacTec Inc.</li>
8894<li>Ed Stalnaker, Rollins Corp, USA</li>
8895<li>Francesco Duranti, Kuwait Petroleum Italia</li>
8896<li>Neil Pike, Protech Computing</li>
8897<li>Brian Wilson, North Carolina State University</li>
8898<li>Martijn Koopsen, Energis NL</li>
8899</UL>
8900Contributors:
8901<UL>
8902<li>Ed Stalnaker (modified cfgmaker script)</li>
8903<li>Brian Wilson, Garry Cook, Aid Arslanagic, Andy Jezierski, Leo Artnts, James Keane, Todd Wiese, Jim Harbin (alternative icon sets)</li>
8904<li>Many other people for suggestions and bug reports.</li>
8905</UL>
8906Additional thanks to all the other people who have assisted by sending in
8907bug reports and suggestions for improvement.  Also, major thanks to
8908Tobi Oetiker, the author of <a href=http://www.mrtg.org/ target=_new>MRTG</a>
8909and <a href=http://www.rrdtool.org/ target=_new>RRDTool</a>, without whom
8910this interface would never have been created.
8911<hr>
8912<h2>Legal Jargon</h2>
8913This software is available under the GNU GPL.  More information is available
8914in the text files accompanying this software, or on the web site.  Please note
8915that this software is provided without any warranty, or guarantee, and you
8916use it at your own risk.  In no event shall myself, my employers, or the
8917owner of any
8918web site distributing this software, be held liable for any loss or damage
8919caused as a result of the use or misuse of this software or the instructions
8920that accompany it.
8921<p>
8922EOT
8923;
8924	do_footer();
8925}
8926
8927# set cookies etc. for defaults.
8928# the way we do this is by refreshing ourself with extra parameters.
8929# The existence of the extra parameters causes the cookie to be set.
8930sub do_config()
8931{
8932	my ( $javascript, %routerdesc, $k );
8933	my (%langs,$langfile,$langdir,$cc);
8934	my ($explore);
8935
8936	$javascript = make_javascript({if=>"__none",rtr=>"none"});
8937
8938	start_html_ss({-script => $javascript, -onload => "LoadMenu()",
8939		-class=>'config' });
8940	print $q->h2(langmsg(3007,"Personal Preferences")),"\n";
8941
8942	$explore = 'y';
8943	$explore = $config{'routers.cgi-allowexplore'}
8944		if( defined $config{'routers.cgi-allowexplore'} );
8945
8946	if( $q->param('xset') ) {
8947		print $q->p($q->b(langmsg(9005,"Options have been saved."))),"\n";
8948	}
8949
8950	# Load language definitions
8951	%langs = ();
8952	$langs{''} = langmsg(3008,"No Preference");
8953	if(defined $config{'web-langdir'}) { $langdir = $config{'web-langdir'} ; }
8954	else { $langdir = dirname($conffile); }
8955	foreach $langfile ( glob( $langdir.$pathsep."lang_*.conf" ) ) {
8956		if( -r $langfile and $langfile =~ /lang_(.+)\.conf/ ) {
8957			$cc = $1;
8958			open LANG,"<$langfile";
8959			while ( <LANG> ) {
8960				chomp;
8961				if( /^\s*description\s*=\s*(.*)/ ) { $langs{$cc} = $1; last; }
8962			}
8963			close LANG;
8964		}
8965	}
8966
8967	# Load routers definitions
8968	foreach ( keys %routers ) { $routerdesc{$_} = $routers{$_}{desc}; }
8969	$routerdesc{''} = langmsg(3008,"No preference");
8970
8971	if($config{'routers.cgi-6hour'} =~ /y/i ) {
8972		@gorder = ( '6', @gorder ) if($gorder[0] ne "6");
8973	}
8974
8975	print $q->p(langmsg(3107,"Options set here will persist over future invocations of this script.  Note that this uses cookies, so you must have them enabled."));
8976
8977	print $q->hr;
8978	print "<FORM METHOD=GET ACTION=$meurlfull>\n";
8979
8980# now a couple of hidden fields to preserve mtype and page
8981	print $q->hidden({ name=>"page", value=>"config", -override=>1 }),"\n",
8982		$q->hidden({ name=>"xmtype", value=>$mtype, -override=>1 }) ,"\n",
8983		$q->hidden({ name=>"xset", value=>"yes" }) ,"\n";
8984
8985# Now the main fields, defrouter and defgtype.  Dropdown lists.  In a table.
8986
8987	$defgstyle = $q->cookie('gstyle');
8988	$defgstyle = 'n' if(!$defgstyle);
8989
8990	print $q->table( { -border=>0 },
8991		(( $explore =~ /[1y]/i )?
8992		$q->Tr( { -border=>"0", align=>"left" } ,
8993			$q->td(langmsg(3100,"Default device:") )."\n", $q->td(
8994				$q->popup_menu( {name=>"defrouter",
8995					values=>["",sort bydesc keys(%routers)],
8996					labels=>{%routerdesc}, default=>$q->cookie('router')})
8997			)."\n"
8998		):""),
8999		(( $explore =~ /[1yi]/i )?
9000		$q->Tr( { -border=>"0", align=>"left" } ,
9001			$q->td(langmsg(3101,"Default target/interface:") )."\n", $q->td(
9002				$q->popup_menu({ name=>"defif", values=>["",
9003					"__first",
9004					"__interface","__cpu","__memory","__summary",
9005					"__compact", "__incoming","__outgoing","__info",
9006					"__userdef" ],
9007					labels=>{__first=>langmsg(3012,"First target"),
9008						__summary=>langmsg(3013,"Summary page"),
9009						__info=>langmsg(3021,"Info Page"),
9010						__cpu=>langmsg(3016,"CPU performance"),
9011						__memory=>langmsg(3017,"Memory Usage"),
9012						__userdef=>langmsg(3018,"First user graph"),
9013						__interface=>langmsg(3019,"First Interface target"),
9014						__incoming=>langmsg(3014,"Incoming Graph"),
9015						__outgoing=>langmsg(3015,"Outgoing graph"),
9016						__compact=>langmsg(3020,"Compact Summary"),
9017						""=>langmsg(3008,"No preference") },
9018					default=>$q->cookie('if') })
9019			)."\n"
9020		):""),
9021		$q->Tr( { -border=>"0", align=>"left" } ,
9022			$q->td(langmsg(3102,"Default graph type:") )."\n", $q->td(
9023				$q->popup_menu({ name=>"defgtype", values=>[@gorder],
9024					labels=>{%gtypes}, default=>$q->cookie('gtype') })
9025			)."\n"
9026		),
9027		$q->Tr( { -border=>"0", align=>"left" } ,
9028			$q->td(langmsg(3103,"Default graph style:") )."\n", $q->td(
9029				$q->popup_menu({ name=>"defgstyle", values=>[@sorder],
9030					labels=>{%gstyles}, default=>"$defgstyle" })
9031			)."\n"
9032		),
9033		$q->Tr( { -border=>"0", align=>"left" } ,
9034			$q->td(langmsg(3106,"Default language:") )."\n", $q->td(
9035				$q->popup_menu({ name=>"deflang", values=>[sort keys %langs],
9036					labels=>{%langs}, default=>"$language" })
9037			)."\n"
9038		),
9039		$q->Tr( { align=>"left" },
9040			$q->td(""),$q->td(
9041				$q->submit({ name=>"Submit", value=>langmsg(3104,"Set Defaults") })
9042			)."\n"
9043		)
9044	),"\n";
9045
9046	print "</FORM>";
9047
9048	print $q->br({clear=>"BOTH"}),"\n";
9049
9050	print $q->center($q->b($q->a({target=>"_top",href=>$meurlfull},
9051		langmsg(3105,"Go to the current default page")))).$q->br,"\n";
9052
9053	do_footer();
9054}
9055
9056###########################
9057# Show an archive graph.
9058
9059sub do_archive($)
9060{
9061	my( $javascript, $thisgraph, $thisgraphurl );
9062	my( $inhtml ) = $_[0];
9063
9064	$javascript = make_javascript({archive=>$archive});
9065
9066	if($inhtml) {
9067		start_html_ss({ -script => $javascript, -onload => "LoadMenu()" ,
9068#			-class=>($interfaces{$interface}{mode}?$interfaces{$interface}{mode}:'archive')
9069			-class=>'archive'
9070		}, $interfaces{$interface}{xbackground}?$interfaces{$interface}{xbackground}:"");
9071	}
9072
9073	$thisgraphurl = $router; $thisgraphurl =~ s/[\?#\\\/]//g;
9074	$thisgraph = $thisgraphurl;
9075	$thisgraph = $config{'routers.cgi-graphpath'}.$pathsep.$thisgraph
9076		.$pathsep.$interface.$pathsep.$archive;
9077	$thisgraphurl = $config{'routers.cgi-graphurl'}.'/'.$thisgraphurl
9078		.'/'.$interface.'/'.$archive;
9079
9080	if($inhtml) {
9081	print $q->h2({class=>'archive'},langmsg(3009,"Archive graph"));
9082	# any defined pagetop stuff
9083	print "<DIV class=pagetop>";
9084	print expandvars($config{'routers.cgi-pagetop'}),"\n"
9085		if( defined $config{'routers.cgi-pagetop'} );
9086	if( defined $config{'routers.cgi-mrtgpagetop'}
9087		and $config{'routers.cgi-mrtgpagetop'} =~ /y/i
9088		and $interfaces{$interface}{pagetop}
9089		and !$interfaces{$interface}{usergraph} ) {
9090		print expandvars($interfaces{$interface}{pagetop}),"\n";
9091	}
9092	print "</DIV>";
9093	}
9094
9095	if( -f $thisgraph ) {
9096		if($inhtml) {
9097			print $q->img({ src=>$thisgraphurl, alt=>$archive }).$q->br."\n";
9098		} else {
9099			#output the graph in binmode XXX
9100		}
9101	} else {
9102		if($inhtml) {
9103			print $q->p($q->b(langmsg(3010,"This graph has been deleted.")))."\n";
9104		} else {
9105			# redirect to error
9106			if($opt_I) {
9107				print "Error: This graph has been deleted.\n";
9108			} else {
9109			print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
9110			}
9111			return;
9112		}
9113	}
9114
9115	if( $inhtml and $archive =~ /(\d+)-(\d+)-(\d+)-(\d+)-(\d+)-([dwmys6]+)\./ ) {
9116		# try to get local formatting
9117		my( $dformat ) = "%c";
9118		$dformat = $config{'web-dateonlyformat'}
9119			if(defined $config{'web-dateonlyformat'});
9120		$dformat = $config{'web-shortdateformat'}
9121			if(defined $config{'web-shortdateformat'});
9122		if(!$dformat) {
9123			print $q->br, $q->p(langmsg(3200,"Archive time").": $4:$5 $3/$2/$1 ("
9124				.$gtypes{$6}.")");
9125		} else {
9126			print $q->br, $q->p(langmsg(3200,"Archive time").": "
9127				.POSIX::strftime($dformat,0,$5,$4,$3,($2-1),($1-1900))
9128				." (".$gtypes{$6}.")");
9129		}
9130	}
9131	if($inhtml) {
9132	print $q->br."<DIV class=pagefoot>";
9133	if( defined $config{'routers.cgi-mrtgpagefoot'}
9134		and $config{'routers.cgi-mrtgpagefoot'} =~ /y/
9135		and $interfaces{$interface}{pagefoot}
9136		and !$interfaces{$interface}{usergraph}  ) {
9137		print expandvars($interfaces{$interface}{pagefoot}),"\n";
9138	}
9139	print expandvars($config{'routers.cgi-pagefoot'}),"\n"
9140		if( defined $config{'routers.cgi-pagefoot'} );
9141	print "</DIV>";
9142
9143	print "<DIV class=icons>";
9144	print $q->hr."\n";
9145#	print $q->a({href=>"javascript:parent.makearchmark('"
9146#		.$q->escape($router)."','".$q->escape($interface)
9147#		."','".$q->escape($extra)."','$archive')"},
9148	print $q->a({href=>"$meurlfull?".optionstring({page=>"", bars=>"", xmtype=>"",
9149		archive=>"$archive", xgtype=>"", xgstyle=>""}), target=>"_top"},
9150		$q->img({src=>"${config{'routers.cgi-iconurl'}}bookmark.gif",
9151		alt=>langmsg(5016,"Bookmark"),border=>"0",width=>100,height=>20})),"\n";
9152
9153	# only for Yes, not for Read
9154	if( $config{'routers.cgi-archive'} =~ /y/i ) {
9155	print $q->a( { href=>$meurlfull.'?'.optionstring({archive=>$archive,
9156		page=>'graph',delete=>1}) },
9157		$q->img({ border=>0, alt=>langmsg(5022,"Delete this graph"), width=>100, height=>20,
9158			src=>$config{'routers.cgi-iconurl'}."delete.gif" })).$q->br;
9159	}
9160	print "</DIV>";
9161	do_footer();
9162	} # inhtml
9163}
9164
9165###########################
9166# Verification of everything.
9167# This is more a debug utility, really.  We display all the routers and
9168# interfaces, also the available icons and check the sanity of the
9169# routers.conf, and the graph directory.
9170
9171sub yesno($)
9172{
9173	if(!$_[0]) { print $q->td({bgcolor=>"#ff0000",align=>"center",class=>"no"},"No"); }
9174	else { print $q->td({bgcolor=>"#00ff00",align=>"center",class=>"yes"},"Yes"); }
9175}
9176sub do_verify()
9177{
9178	my($server,$iconpath, $ipath, $confpath, $iconurl,$graphpath, $graphurl);
9179	my($curif, $key, $rtr);
9180	my($testfile, $okfile);
9181	my($username) = "";
9182	my($e,$rrdok, $rrdinfo);
9183	my($archroot,@days,$rrdfilename);
9184	my($s)="";
9185
9186	$server = "localhost";
9187	$server = $2 if($meurl =~ /http(s?):\/\/([\w\.\-]+)\//);
9188	$s = "s" if($1);
9189	$confpath = $config{'routers.cgi-confpath'};
9190	$graphpath = $config{'routers.cgi-graphpath'};
9191	$graphurl = $config{'routers.cgi-graphurl'};
9192	$iconurl = $config{'routers.cgi-smalliconurl'};
9193	$ipath = $iconurl; $ipath =~ s#/#\\#g if($NT);
9194	$iconpath = $graphpath.$pathsep."..".$ipath;
9195	$iconpath = $graphpath.$pathsep."..".$pathsep."..".$ipath
9196		if(!-d $iconpath);
9197	$iconpath = "" if(!-d $iconpath);
9198	$username = $q->remote_user if($q->remote_user);
9199
9200	start_html_ss({-title=>langmsg(3011,"Configuration Verification"),
9201		-class=>'verify'});
9202
9203	print $q->h1(langmsg(3011,"Configuration Verification"));
9204	print $q->ul(
9205		$q->li($q->a({href=>"#conf"},"Check routers.conf")),
9206		$q->li($q->a({href=>"#files"},"Check MRTG files")),
9207		$q->li($q->a({href=>"#targets"},"Check MRTG targets")),
9208		$q->li($q->a({href=>"#icons"},"Check available icons")),
9209		$q->li($q->a({href=>"#settings"},"Configuration settings"))
9210	).$q->hr."\n";
9211
9212	print $q->a({name=>"conf"},$q->h2("routers.conf check"))."\n";
9213	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";
9214	print "<TABLE align=center border=1 class=verify>\n";
9215	print "<TR><TD>Script name</TD><TD>$myname  (Version $VERSION)</TD></TR>\n";
9216	print "<TR><TD>Configuration file<br>$conffile</TD>\n";
9217	if( -r $conffile ) { print "<TD>Exists and is readble</TD></TR>\n"; }
9218	else { print "<TD background=#ff0000>Unable to read file</TD></TR>\n"; }
9219	print "<TR><TD>Authenticated username</TD><TD>$username</TD></TR>\n"
9220		if($username);
9221	print "<TR><TD>Graphs path<br>$graphpath</TD>\n";
9222	if( -d $graphpath ) {
9223		$testfile = $graphpath.$pathsep
9224			."verylongfilename-------------testfile.png";
9225		if( open TEST, ">$testfile"  ) {
9226			print "<TD>Directory exists and is writeable</TD></TR>\n";
9227			close TEST;
9228			unlink $testfile;
9229		} else {
9230			print "<TD background=#ff0000>Unable to create files in directory!</TD></TR>\n";
9231		}
9232	} else {
9233		print "<TD background=#ff0000>Directory does not exist!</TD></TR>\n";
9234	}
9235	print "<TR><TD>Graph URL<br>$graphurl</TD>\n";
9236	$testfile = $graphpath.$pathsep."redsquare.png";
9237	unlink $testfile if( -f $testfile );
9238	if( open GRAPH, ">$testfile" ) {
9239		binmode GRAPH;
9240		# this generates a PNG of a red square.
9241		print GRAPH
9242"\211PNG\r\n\032\n\0\0\0\rIHDR\0\0\0\017\0\0\0\017\001\003\0\0\0\001\030"
9243."\a\t\0\0\0\003PLTE\377\0\0\031\342\t7\0\0\0\fIDATx\234c` \001\0\0\0-\0"
9244."\001\305\327\300\206\0\0\0\0IEND\256B`\202";
9245		close GRAPH;
9246		print "<TD>This should show a red square --&gt;"
9247			.$q->img({src=>$graphurl."/redsquare.png",alt=>"Red Square",
9248				width=>15,height=>15})
9249			."&lt;--<br>\n";
9250		print "If it doesn't, then your graphurl does not match your graphpath.</TD></TR>\n";
9251	} else {
9252		print "<TD background=#ff0000>Unable to create test file!<br>Check your graphpath setting above.</TD></TR>\n";
9253	}
9254
9255	print "<TR><TD>Icon URL<br>$iconurl</TD><TD>\n";
9256	print "This should show a target --&gt;"
9257		.$q->img({src=>$iconurl."target-sm.gif",width=>15, height=>15})
9258		."&lt;--<br>\n"
9259  		."If it doesn't, then there is a problem.</td></tr>\n";
9260	print "<TR><TD>MRTG files<br>Path: ".$confpath
9261		.$q->br."Files: ".$config{'routers.cgi-cfgfiles'}."</TD>\n";
9262	if( @cfgfiles ) {
9263		print "<TD>".($#cfgfiles + 1)." files detected OK.";
9264	} else {
9265		if(!-d $confpath) {
9266			print "<TD gcolor=#ff0000>Directory does not exist or is not readable!";
9267		} else {
9268			print "<TD gcolor=#ff0000>No files found that match this pattern!";
9269		}
9270	}
9271	print "</TD></TR>\n";
9272	print "<TR><TD>Perl libraries<br>RRDs, GD</TD><TD>\n";
9273	eval { require RRDs; };
9274	if($@) {
9275		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;
9276		print $@.$q->br;
9277		$rrdok = 0;
9278	} else {
9279		my($v);
9280		# RRDTool v1.0.x reported version as 1.000xx for 1.0.xx
9281		# RRDTool v1.{2,3,4}.x report version as 1.abbb for 1.a.bbb
9282		$RRDs::VERSION =~ /(\d+)\.(\d)(\d+)/ ;
9283		$v = "$1.".($2 + 0).".".($3 + 0);
9284		print "RRDs library found OK (Version $v)<br>";
9285		print "You should upgrade to at least v1.0.36 to avoid problems.<BR>"
9286			if($RRDs::VERSION < 1.00036);
9287		$rrdok = 1
9288			if($RRDs::VERSION < 1.00036);
9289	}
9290	if( $config{'routers.cgi-stylesheet'}  ) {
9291		print "GD library not required as operating in StyleSheet mode<BR>\n";
9292	} elsif( $config{'routers.cgi-compact'} =~ /n/i ) {
9293		print "GD library not required as compact is disabled in routers.conf<BR>\n";
9294	} else {
9295		eval { require GD; };
9296		if($@) {
9297			print $q->b("GD library NOT FOUND.")." This would not be a problem if you had compact=no in the routers.conf.".$q->br;
9298			print $@;
9299		} else {
9300			print "GD library found OK";
9301			my $gd = new GD::Image(1,1);
9302			eval { print ": Ver ".$GD::VERSION."<BR>"; };
9303			eval { # must eval because old versions dont have 'can' or VERSION
9304				if( $gd->can('png') ) { print "- PNG Supported<BR>"; }
9305				else { print "- PNG NOT supported<BR>"; }
9306				if( $gd->can('gif') ) { print "- GIF Supported<BR>"; }
9307				else { print "- GIF NOT supported<BR>"; }
9308				if( $config{'web-png'} and !$gd->can('png')) {
9309					print "WARNING: You have PNG enabled in the routers2.conf but your GD does not support it!<BR>";
9310				}
9311				if( !$config{'web-png'} and !$gd->can('gif')) {
9312					print "WARNING: You do not have PNG enabled in the routers2.conf but your GD does not support GIFs!<BR>";
9313				}
9314			};
9315		}
9316	}
9317	if( $config{'web-rrdcached'} or $ENV{RRDCACHED_ADDRESS} ) {
9318		print "Config file sets rrdcached options to ".$config{'web-rrdcached'}."<BR>" if($config{'web-rrdcached'});
9319		print "Environment sets rrdcached options to ".$ENV{RRDCACHED_ADDRESS}."<BR>" if($ENV{RRDCACHED_ADDRESS});
9320		if( $RRDs::VERSION < 1.4 ) {
9321			print "You cannot use rrdcached with this version of the RRD library!<BR>\n";
9322		} elsif( $RRDs::VERSION < 1.4999 ) {
9323			print "You cannot ONLY use rrdcached with UNIX sockets with this version of the RRD library!<BR>\n";
9324		}
9325
9326	}
9327	print "</TD></TR><TR><TD>Routingtable extensions</TD><TD>";
9328	if(defined $config{'routers.cgi-routingtableurl'}) {
9329		eval { require Net::SNMP; };
9330		if($@) {
9331			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;
9332			print $@;
9333		} else {
9334			print "Net::SNMP library found OK and extensions are enabled.";
9335		}
9336	} else {
9337		print "Routing table extensions are not enabled.";
9338	}
9339	print "</TD></TR></TABLE>\n";
9340
9341	print $q->hr.$q->a({name=>"files"},$q->h2("MRTG files check"))."\n";
9342	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.");
9343	print "confpath = ".$q->code($confpath).$q->br."\n";
9344	print "cfgfiles = ".$q->code($config{'routers.cgi-cfgfiles'}).$q->br."\n";
9345
9346	print $q->br."<TABLE align=center border=1 class=verify>\n";
9347	print "<TR><TD>MRTG file name</td><td>Description</td><td>Visible</td><td>Valid</td><td>Notes</td></tr>\n";
9348	foreach $rtr ( keys %routers ) {
9349		print "<TR><TD>";
9350		print $q->img({src=>$iconurl.$routers{$rtr}{icon},width=>15, height=>15})." " if(defined $routers{$rtr}{icon});
9351		print $q->a({href=>("$meurlfull?page=verify&rtr=".$q->escape($rtr))},$rtr);
9352
9353		if( $rtr !~ /^#/ ) {
9354		$okfile = $confpath.$pathsep.$rtr;
9355		$okfile =~ s/\.conf$/.ok/; $okfile =~ s/\.cfg$/.ok/;
9356		print "<BR><B><font color=#ff0000>No .ok file found</font></b><br>\n"
9357			."Have you successfully run MRTG on this file yet?"
9358				if(!-f $okfile);
9359		}
9360		print "</TD><TD>".$routers{$rtr}{shdesc}."</TD>";
9361		yesno $routers{$rtr}{inmenu};
9362		yesno $routers{$rtr}{hastarget};
9363		print "<TD><TABLE border=0>";
9364		print "<TR><TD>Group:</TD><TD>".$routers{$rtr}{group}."</TD></TR>"
9365			if($routers{$rtr}{group});
9366		print "<TR><TD>Server:</TD><TD>".$routers{$rtr}{server}."</TD></TR>"
9367			if($routers{$rtr}{server});
9368		print "<TR><TD>Hostname:</TD><TD>".$routers{$rtr}{hostname}."</TD></TR>"
9369			if($routers{$rtr}{hostname});
9370		print "</TABLE></TD></TR>\n";
9371	}
9372	print "</TABLE>";
9373
9374	print $q->hr.$q->a({name=>"targets"},$q->h2("MRTG targets check"))."\n";
9375	print "Current device: ".$q->b($router)." (".$routers{$router}{desc}.")".$q->br."\n";
9376	print "MRTG file: ".$q->code($routers{$router}{file}).$q->br."\n"
9377		if($routers{$router}{file});
9378	print $q->p("These targets are read from the MRTG file, and then displayed according to how they are interpreted.");
9379	print "<BR><TABLE border=1 align=center>\n";
9380	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>Archives</TD><TD>Notes</TD></TR>\n";
9381	foreach $curif ( keys %interfaces ) {
9382		next if($interfaces{$curif}{usergraph});
9383		print "<TR><TD>";
9384		print $q->img({src=>$iconurl.$interfaces{$curif}{icon},width=>15, height=>15})." " if(defined $interfaces{$curif}{icon});
9385		print "$curif<br>".$interfaces{$curif}{rrd};
9386		if(!$rrdcached and !-r $interfaces{$curif}{rrd}) {
9387		print "<BR><B><font color=#ff0000>Unable to read RRD file!</font></B>"
9388		}
9389		print "</TD><TD>".$interfaces{$curif}{mode}."</TD>";
9390		yesno $interfaces{$curif}{inmenu};
9391		yesno $interfaces{$curif}{insummary};
9392		yesno $interfaces{$curif}{inout};
9393		yesno $interfaces{$curif}{incompact};
9394		print "<TD>";
9395		@days = ();
9396		if(defined $interfaces{$curif}{origrrd}) {
9397			$rrdfilename = $interfaces{$curif}{origrrd};
9398		} else {
9399			$rrdfilename = $interfaces{$curif}{rrd};
9400		}
9401		if($rrdfilename) {
9402			$archroot  = dirname($rrdfilename).$pathsep.'archive';
9403			$rrdfilename = basename($rrdfilename);
9404			if( defined $cachedays{$rrdfilename} ) {
9405				@days = @{$cachedays{$rrdfilename}};
9406				$debugmessage .= "fromcache(dates:$rrdfilename)\n";
9407			}  else {
9408				foreach ( sort rev findarch( $archroot,$rrdfilename ) ) {
9409					if( /(\d\d)(\d\d)-(\d\d)-(\d\d)/ ) {
9410						push @days, "$1$2-$3-$4"; }
9411				}
9412				$cachedays{$rrdfilename} = [ @days ]; # Cache for later
9413				$debugmessage .= "cached[dates:$rrdfilename]\n";
9414			}
9415			print ( $#days + 1 );
9416			print " from ".$days[$#days] if($#days > -1);
9417		} else {
9418			print "N/A";
9419		}
9420		print "</TD><TD>";
9421		if($rrdok and -r $interfaces{$curif}{rrd}) {
9422			$rrdinfo = RRDs::info($interfaces{$curif}{rrd},@rrdcached);
9423			$e = RRDs::error();
9424			if(defined $rrdinfo and !$e) {
9425				print "RRD file format is legal.";
9426				print "<BR>Interval ".($rrdinfo->{step}/60)
9427					." minute(s)" if($rrdinfo->{step} != 300);
9428				print "<BR><B>Not in MRTG format!</B>"
9429					if(!defined $rrdinfo->{"ds[ds0].type"});
9430				print "<BR>Extended timeframe"
9431					if($rrdinfo->{"rra[0].rows"} > 799);
9432			} else {
9433				print $q->b("Error reading rrd:").$q->br.$e;
9434			}
9435		} else { print "N/A"; }
9436		print "</TD>\n";
9437	}
9438	print "</TABLE>\n";
9439
9440	print $q->hr.$q->a({name=>"icons"},$q->h2("Available Icons"))."\n";
9441	print "The available icons should be located in the <b>rrdicons</b> directory, currently defined to be:".$q->br."\n";
9442	print "URL: ".$q->code("http$s://$server".$config{'routers.cgi-smalliconurl'}).$q->br;
9443	print "If the menu page is installed, you can get to it "
9444		.$q->a({href=>$config{'routers.cgi-smalliconurl'}},"here").".".$q->br."\n";
9445	if($iconpath and -d $iconpath ) {
9446		# show available icons in here
9447		my( $c ) = 0; my($f,$b);
9448		print $q->br."<TABLE border=1 align=center>\n<TR>";
9449		foreach $f ( glob( $iconpath.$pathsep."*-sm.gif" ) ) {
9450			$b = basename $f;
9451			$c++;
9452			if($c eq 5) { $c = 1; print "</TR>\n<TR>"; }
9453			if( -r $f ) {
9454			print "<TD>".$q->img({src=>($iconurl.$b), width=>15, height=>15});
9455			print " ".$b."</TD>";
9456			} else {
9457				print "<TD bgcolor=#ff0000>Unable to read file $b</TD>";
9458			}
9459		}
9460		print "</TR></TABLE>";
9461
9462		# verify
9463		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.");
9464	} else {
9465		print "Checked directory $iconpath<br>\n";
9466		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.");
9467	}
9468	print "This should show a target --&gt;"
9469		.$q->img({src=>$iconurl."target-sm.gif",width=>15, height=>15});
9470	print "&lt;--.  If it does not, correct your <b>iconurl</b> setting."
9471		.$q->br."\n";
9472
9473	print $q->hr.$q->a({name=>"settings"},
9474		$q->h2("Active Configuration Settings"))."\n";
9475	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 ('$authuser').")."\n";
9476	print "<UL>\n";
9477	foreach ( sort keys %config ) {
9478		if( $_ eq 'web-auth-key' ) {
9479		print $q->li($q->b($_)." = \"<I>not displayed</I>\"")."\n";
9480		} else {
9481		print $q->li($q->b($_)." = \"".$config{$_}."\"")."\n";
9482		}
9483	}
9484	print "</UL>".$q->br;
9485	do_footer();
9486}
9487
9488###########################
9489# If we get a bad page request
9490
9491sub do_bad($)
9492{
9493	start_html_ss({-title=>"routers.cgi Error",-bgcolor=>"#ffd0d0",
9494		-class=>'error'});
9495	print $q->h1(langmsg(8005,"Bad page request"));
9496	print $q->p("Error message was [".$_[0]."]")."\n";
9497	print $q->p(langmsg(8007,"Check the format of the URL parameters for the page you are requesting."))."\n";
9498	if(!$config{'web-paranoia'}
9499		or $config{'web-paranoia'}=~/[nN0]/) {
9500		eval { print $q->dump; };
9501	}
9502	print $q->hr.$q->small("Error message generated by routers2.cgi")."\n";
9503	print $q->end_html();
9504}
9505
9506########################################################################
9507# MAIN CODE STARTS HERE
9508########################################################################
9509# Initialise parameters
9510
9511$bn = lc basename $q->url(-absolute=>1);
9512$myname = $bn if($bn);
9513
9514$opt_D = $opt_r = $opt_T = $opt_i = $opt_U = $opt_s = $opt_t = $opt_A = "";
9515$opt_I = $opt_C = $opt_a = "";
9516getopts('GAICD:T:r:i:s:t:a:U:');
9517$opt_D = $opt_r if($opt_r); $opt_T = $opt_i if($opt_i); # override
9518
9519# Avoid IIS pathinfo bug
9520if( $^O !~ /Win/ or $q->server_software()!~/IIS|Microsoft/i ) {
9521	@pathinfo = split '/',$q->path_info() if($q->path_info());
9522}
9523
9524$pagetype="";
9525$pagetype=$q->param('page') if( defined $q->param('page') );
9526$pagetype=$q->param('xpage')if( defined $q->param('xpage'));# stupid persistence
9527$pagetype='image' if(! defined $q->param('page')
9528	and $q->param('xgstyle') and ($q->param('xgstyle')=~/[AB]/));
9529if($myname =~ /thumbnail\.(cgi|pl)/) { $pagetype = 'image'; $defgstyle = 'A'; }
9530$pagetype="graphCOMMAND" if($opt_A or $opt_D); # command line archive or generate
9531$pagetype="imageCOMMAND" if($opt_I or $opt_G); # command line image
9532$pagetype="csvCOMMAND" if($opt_C); # command line CSV extract
9533#$pagetype="graph" if(defined $q->param('searchhost'));
9534$pagetype="main" if(!$pagetype);
9535$archive = "";
9536if( $q->param('archive') ){
9537	$archive = $q->param('archive');
9538}
9539# Deal with Authentication requests FIRST, before reading conf.
9540if( $pagetype eq 'login' ) {
9541	# generate login page
9542	login_page;
9543	print "<!--- login page requested --->\n";
9544	exit 0;
9545}
9546if( $pagetype eq 'logout' ) {
9547	# generate logout page
9548	logout_page;
9549	exit 0;
9550}
9551if( $q->param('username') ) {
9552	# someone is trying to log in
9553	if( user_verify( $q->param('username'), $q->param('password') ) ) {
9554		# OK
9555		$authuser = $q->param('username');
9556	} else {
9557		# bad login: force it again
9558		force_login(langmsg(1005,"Invalid username/password combination"));
9559		exit 0;
9560	}
9561} elsif($opt_U) {
9562	$authuser = $opt_U; # only via command line
9563} else {
9564	# get username from other sources
9565	$authuser = verify_id;
9566}
9567
9568# get these sections from the conf file.
9569$extra = lc $q->param('extra') if($q->param('extra'));
9570readconf( 'routers.cgi','web','routerdesc','targetnames','targettitles',
9571	'targeticons', 'servers', 'menu' );
9572initlang(undef); # initialise the language module, if defined
9573
9574# Paranoia
9575$pagetype="main" if($pagetype eq "verify" and $config{'web-paranoia'}
9576	and $config{'web-paranoia'}=~/[yY1]/);
9577
9578if(defined $config{'routers.cgi-percent'}
9579	and $config{'routers.cgi-percent'}=~/(\d\d?\d?)/ ) {
9580	$PERCENT = $1;
9581}
9582
9583# Generate archived graphs
9584if($pagetype =~ /archive/) {
9585	$pagetype = "graph";
9586	$archiveme = 1 if($config{'routers.cgi-archive'}=~/[y1]/i);
9587}
9588
9589# Allow override for broken web servers
9590$meurlfull = $config{'routers.cgi-myurl'}
9591	if( defined $config{'routers.cgi-myurl'} );
9592
9593# Now, if we have forced security, and no authuser, then force the
9594# login page regardless.
9595if( defined $config{'web-auth-required'}
9596	and $config{'web-auth-required'} =~ /^[1y]/i  and !$authuser ) {
9597	force_login(langmsg(1006,"Authorisation is required to view these pages"));
9598	exit 0;
9599}
9600# otherwise, if we have an authuser, set the cookie.
9601if($authuser) {
9602	push @cookies, generate_cookie;
9603	$headeropts{-cookie} = [@cookies];
9604}
9605
9606# Find out our security level
9607$seclevel = $config{'routers.cgi-level'}
9608	if( defined $config{'routers.cgi-level'} );
9609
9610# background colour (for the americans)
9611if ( defined $config{'routers.cgi-bgcolor'}
9612	and $config{'routers.cgi-bgcolor'} =~ /(#[\da-fA-F]{6})/i ) {
9613	$defbgcolour = $1;
9614}
9615if ( defined $config{'routers.cgi-fgcolor'}
9616	and $config{'routers.cgi-fgcolor'} =~ /(#[\da-fA-F]{6})/i ) {
9617	$deffgcolour = $1;
9618}
9619if ( defined $config{'routers.cgi-menufgcolor'}
9620	and $config{'routers.cgi-menufgcolor'} =~ /(#[\da-fA-F]{6})/i ) {
9621	$menufgcolour = $1;
9622}
9623if ( defined $config{'routers.cgi-menubgcolor'}
9624	and $config{'routers.cgi-menubgcolor'} =~ /(#[\da-fA-F]{6})/i ) {
9625	$menubgcolour = $1;
9626}
9627if ( defined $config{'routers.cgi-authfgcolor'}
9628	and $config{'routers.cgi-authfgcolor'} =~ /(#[\da-fA-F]{6})/i ) {
9629	$authfgcolour = $1;
9630}
9631if ( defined $config{'routers.cgi-authbgcolor'}
9632	and $config{'routers.cgi-authbgcolor'} =~ /(#[\da-fA-F]{6})/i ) {
9633	$authbgcolour = $1;
9634}
9635if ( defined $config{'routers.cgi-linkcolor'}
9636	and $config{'routers.cgi-linkcolor'} =~ /(#[\da-fA-F]{6})/i ) {
9637	$linkcolour = $1;
9638}
9639# background colour (for the british)
9640if ( defined $config{'routers.cgi-bgcolour'}
9641	and $config{'routers.cgi-bgcolour'} =~ /(#[\da-fA-F]{6})/i ) {
9642	$defbgcolour = $1;
9643}
9644if ( defined $config{'routers.cgi-fgcolour'}
9645	and $config{'routers.cgi-fgcolour'} =~ /(#[\da-fA-F]{6})/i ) {
9646	$deffgcolour = $1;
9647}
9648if ( defined $config{'routers.cgi-menubgcolour'}
9649	and $config{'routers.cgi-menubgcolour'} =~ /(#[\da-fA-F]{6})/i ) {
9650	$menubgcolour = $1;
9651}
9652if ( defined $config{'routers.cgi-menufgcolour'}
9653	and $config{'routers.cgi-menufgcolour'} =~ /(#[\da-fA-F]{6})/i ) {
9654	$menufgcolour = $1;
9655}
9656if ( defined $config{'routers.cgi-authbgcolour'}
9657	and $config{'routers.cgi-authbgcolour'} =~ /(#[\da-fA-F]{6})/i ) {
9658	$authbgcolour = $1;
9659}
9660if ( defined $config{'routers.cgi-authfgcolour'}
9661	and $config{'routers.cgi-authfgcolour'} =~ /(#[\da-fA-F]{6})/i ) {
9662	$authfgcolour = $1;
9663}
9664if ( defined $config{'routers.cgi-linkcolour'}
9665	and $config{'routers.cgi-linkcolour'} =~ /(#[\da-fA-F]{6})/i ) {
9666	$linkcolour = $1;
9667}
9668
9669if( defined $config{'web-png'} and $config{'web-png'}=~/[1y]/i ) {
9670	$graphsuffix = "png";
9671}
9672if( defined $config{'routers.cgi-bytes'}
9673	and $config{'routers.cgi-bytes'}=~/y/i ) {
9674	$bits = "!bytes";
9675	$factor = 1;
9676}
9677
9678# Anyone giving us a cookie?
9679$defgstyle = $q->cookie('gstyle') if($q->cookie('gstyle'));
9680if( ! $defgstyle ) {
9681	if( $config{'routers.cgi-graphstyle'} ) {
9682		my( $w ); # match against all the possibilities
9683		if( defined $gstyles{$config{'routers.cgi-graphstyle'}} ) {
9684			$defgstyle = $config{'routers.cgi-graphstyle'};
9685		} else {
9686			foreach ( keys %gstyles ) {
9687				$gstyles{$_} =~ /^\s*(\w+)/;
9688				$w = lc $1;
9689				if( $w eq lc $config{'routers.cgi-graphstyle'}
9690					or $w eq $_ ) {
9691					$defgstyle = $_;
9692					last;
9693				}
9694			}
9695		}
9696	}
9697	$defgstyle = 'n' if(!$defgstyle);
9698}
9699$defbaropts = "Cami";
9700if(defined $config{'routers.cgi-bars'}) {
9701	$defbaropts = $config{'routers.cgi-bars'};
9702}
9703$defgopts = $q->cookie('gopts');
9704$defgopts = "" if(!defined $defgopts);
9705$defgtype = $q->cookie('gtype');
9706if( ! $defgtype ) {
9707	if( $config{'routers.cgi-graphtype'} ) {
9708		foreach ( @gorder ) {
9709			if( $_ eq $config{'routers.cgi-graphtype'} ) {
9710				$defgtype = $_;
9711				last;
9712			}
9713		}
9714	}
9715}
9716$defgtype = $gorder[0] if(! $defgtype);
9717
9718# identify menu type
9719$mtype = "routers";
9720$mtype  = $q->param('xmtype')  if( defined $q->param('xmtype') );
9721if( defined $config{'routers.cgi-allowexplore'} and $mtype ne "options" ) {
9722	$mtype = "options"
9723		if($config{'routers.cgi-allowexplore'} !~ /y/ );
9724}
9725
9726# set the current device(router) and interface...
9727$router = "";
9728$router = $defrouter = $q->cookie('router') if($q->cookie('router'));
9729$router = $pathinfo[1] if($pathinfo[1]);
9730$router = $opt_D if($opt_D); # command line
9731$router = $q->param('rtr') if( $q->param('rtr') );
9732#$router = "" if(!defined $router or $router eq "none");
9733$router = "" if(!defined $router);
9734# Only read in the routers table if (1) we need it, or (2) we are caching
9735if(($pagetype =~ /config/)
9736	or ($pagetype =~ /menu/ and ($mtype eq "routers" or !$router))
9737  or(!$router and $pagetype and $pagetype !~ /help|main|head|bar/ )
9738  or($pagetype =~ /graph/
9739	and -r $config{'routers.cgi-confpath'}.$pathsep.$router )
9740  or ($pagetype =~ /verify/)
9741  or ($q->param('searchhost'))
9742  or $CACHE ) {
9743	read_routers();
9744	if ((! $router or !defined $routers{$router} ) and $router ne "none") {
9745		if($config{'routers.cgi-defaultrouter'}
9746			and ( defined $routers{$config{'routers.cgi-defaultrouter'}}
9747				or $config{'routers.cgi-defaultrouter'} eq 'none' )) {
9748			$router = $defrouter = $config{'routers.cgi-defaultrouter'};
9749		} else {
9750			$router = $defrouter = (sort bydesc keys(%routers))[0] ;
9751		}
9752	}
9753}
9754
9755# Searching?
9756if( $q->param('searchhost') ) {
9757	my($sh) = $q->param('searchhost');
9758	$router = 'none'; # If not found
9759	foreach ( keys %routers ) {
9760		if( $_ =~ /^(.*[\\\/])?$sh\.[^\.\\\/]+$/i ) { $router = $_; last; }
9761	}
9762	if($router eq 'none') {
9763		foreach ( keys %routers ) {
9764			if( $_ =~ /$sh/i ) { $router = $_; last; }
9765			if( $routers{$_}{shdesc} =~ /$sh/i ) { $router = $_; last; }
9766		}
9767	}
9768}
9769
9770# Do we need to redirect?
9771if( defined $routers{$router} and $routers{$router}{redirect} ) {
9772	if($pagetype =~ /graph/ or $q->param('searchhost')) {
9773		# coming from search box, or wanting graph page
9774		# Ugly stuff to avoid XSS problems - must reload entire frameset
9775		my($js)="function doredirect() { parent.location = \""
9776			.$routers{$router}{redirect}.'?'
9777        	.optionstring({page=>"main",rtr=>$router})
9778			."\"; } ";
9779		print $q->header();
9780		print $q->start_html({-expires=>"+1s",-script=>$js,-onload=>"doredirect()"});
9781		print "Please wait: handing over to other cluster member";
9782		print $q->end_html;
9783		exit(0);
9784	}
9785	print $q->redirect($routers{$router}{redirect}.'?'.
9786		optionstring({page=>$pagetype,rtr=>$router}) );
9787	exit(0);
9788}
9789
9790# Get interface information, if we need it
9791$defif = $q->cookie('if');
9792$defif = $config{'routers.cgi-defaultinterface'}
9793	if(!$defif and defined $config{'routers.cgi-defaultinterface'});
9794$defif = $pathinfo[2] if($pathinfo[2]);
9795$interface = ($q->param('if'))?$q->param('if'):$defif ;
9796$interface = $opt_T if($opt_T); # command line
9797$interface = '_summary_' if($interface eq '__summary'); # backwards compatible
9798$interface = 'none' if($router eq 'none');
9799$interface = "" if(! defined $interface );
9800if( ( ($pagetype =~ /menu/ and $mtype ne "routers" )
9801	  or $pagetype =~ /csv|graph|summary|info|compact|verify|image/ )
9802	and $router ne "none" ) {
9803	if($router =~ /^#SERVER#/ ) {
9804		set_svr_ifs();
9805	} else {
9806		read_cfg();
9807	}
9808	$donecfg = 1; # set flag to show we have read in interfaces data
9809	if ( !$interface or $interface eq "__first"
9810		or $interface eq "__interface" or $interface eq "__memory"
9811		or $interface eq "__cpu" or $interface eq "__userdef"
9812		or ( $interface !~ /^__/ and !defined $interfaces{$interface} )
9813	) {
9814		if( $routers{$router}{defif}
9815			and defined $interfaces{$routers{$router}{defif}}) {
9816			$defif = $routers{$router}{defif};
9817		} else {
9818			my( @ifs );
9819			@ifs = sort byifdesc keys(%interfaces);
9820			$defif = 'none';
9821			foreach ( @ifs ) {
9822				next if(!$interfaces{$_}{inmenu});
9823				if( $interfaces{$_}{default} ) { $defif=$_; last; }
9824				$defif = $_ if($defif eq 'none');
9825				if($interface eq "__interface"
9826					and $interfaces{$_}{mode} eq "interface")
9827				{ $defif = $_; last;  }
9828				if($interface eq "__memory"
9829					and $interfaces{$_}{mode} eq "memory")
9830				{ $defif = $_; last; }
9831				if($interface eq "__cpu"
9832					and $interfaces{$_}{mode} eq "cpu")
9833				{ $defif = $_; last; }
9834				if($interface eq "__userdef" and !$interfaces{$_}{issummary}
9835					and $interfaces{$_}{usergraph} )
9836				{ $defif = $_; last; }
9837				if($interface eq "__usersummary" and $interfaces{$_}{issummary}
9838					and $interfaces{$_}{usergraph} )
9839				{ $defif = $_; last; }
9840			}
9841		} # default specified
9842		$interface = $defif;
9843	}
9844}
9845
9846# Archive deletion
9847if( $q->param('delete') and $archive ) {
9848	# zap the requested archive
9849	my( $arch );
9850	$arch = $router; $arch =~ s/[\?#\/\\]//g;
9851	$arch = $config{'routers.cgi-graphpath'}.$pathsep.$arch.$pathsep
9852		.$interface.$pathsep.$archive;
9853	unlink $arch;
9854	$archive = "";
9855}
9856
9857$gtype = $defgtype;
9858$gstyle = $defgstyle;
9859$gopts = $defgopts;
9860$baropts = $defbaropts;
9861$gtype  = $q->param('xgtype')  if( defined $q->param('xgtype') );
9862$gtype  = $opt_t if($opt_t);
9863$gstyle = $q->param('xgstyle') if( defined $q->param('xgstyle'));
9864$gstyle = $opt_s if($opt_s);
9865$gopts  = $q->param('xgopts')  if( defined $q->param('xgopts') );
9866$uopts  = $q->param('uopts')   if( defined $q->param('uopts')  );
9867$baropts= $q->param('bars')    if( defined $q->param('bars')   );
9868$gtype = "d" if(!$gtype);
9869
9870# the graph time options
9871# Allow 6-hour if every RRD involved is able to do it also.
9872if(	defined $config{'routers.cgi-6hour'}
9873	and $config{'routers.cgi-6hour'} =~ /y/i ) {
9874	# 6-hour mode is available.
9875	my($thisif);
9876	if($donecfg) { # have we read in the cfg files?
9877		if( $interface eq "__compact" ) {
9878			$usesixhour = 1;
9879			foreach $thisif ( keys %interfaces ) {
9880				next if(!$interfaces{$thisif}{incompact});
9881				if($interfaces{$thisif}{interval} > 4) {$usesixhour = 0; last;}
9882			}
9883		} elsif ( $interface and defined $interfaces{$interface}
9884			and $interfaces{$interface}{usergraph} ) {
9885			# Userdefined - all member interfaces MUST be <5
9886			$usesixhour = 1;
9887			foreach $thisif ( @{$interfaces{$interface}{targets}} ) {
9888				if($interfaces{$thisif}{interval} > 4) {$usesixhour = 0; last;}
9889			}
9890		} elsif( $interface and defined $interfaces{$interface}
9891			and $interfaces{$interface}{interval} < 5 ) {
9892			$usesixhour = 1;
9893		}
9894		$usesixhour = 1 if($config{'routers.cgi-6hour'} =~ /a/i ); # for 'always'
9895		@gorder = ( "6", @gorder ) # add it to the beginning of the list
9896			if($usesixhour);
9897	} else { # donecfg
9898		@gorder = ( "6", @gorder ); # Assume it's OK, fix it later
9899	}
9900}
9901
9902# rrdcached support
9903# If we're using UNIX sockets, then we just need to force a flush of the
9904# relevant RRD files.  If we're using TCP sockets, then all the commands need
9905# to use them.
9906$rrdcached = "";
9907$rrdcached = $ENV{RRDCACHED_ADDRESS} if($ENV{RRDCACHED_ADDRESS});
9908$rrdcached = $config{'web-rrdcached'} if($config{'web-rrdcached'});
9909$rrdcached = $routers{$router}{rrdcached}
9910	if($router and defined $routers{$router} and $routers{$router}{rrdcached});
9911if($rrdcached) {
9912	$debugmessage .= "RRDCached = $rrdcached, testing version...\n";
9913	eval{
9914		require RRDs;
9915		if( $RRDs::VERSION < 1.4 ) {
9916			$rrdcached = ""; # no support for rrdcached in this version
9917		} elsif( ($rrdcached !~ /^unix:/) and ($RRDs::VERSION<1.4999) ) {
9918			$rrdcached = ""; # no support for rrdcached/TCP in this version
9919		}
9920	};
9921	$rrdcached = "" if($@); # if RRDs problem
9922	$debugmessage .= "RRDCached mode cancelled.\n" if(!$rrdcached);
9923}
9924# For tcp, 'fetch' and 'graph' will flush the cache; however 'last' doesnt
9925# Therefore we need to flush for all sockets.  For unix domain, we go
9926# direct for graph, fetch and last so we MUST flush the cache.
9927#if( $rrdcached =~ /^unix:/ ) {
9928if( $rrdcached ) {	 # flush for TCP domain as well as unix domain
9929	# we know RRDs will be loaded by now
9930	if( $router and defined $routers{$router} and $interface
9931		and $interfaces{$interface} ) {
9932		my(@ifs) = ();
9933		my($pth) = $config{'routers.cgi-dbpath'};
9934		$pth = $routers{$router}{workdir} if($routers{$router}{workdir});
9935		$debugmessage .= "Flushing RRD files\n";
9936		if( defined $interfaces{$interface}{targets} ) {
9937			foreach ( $interfaces{$interface}{targets} ) {
9938				push @ifs, $interfaces{$_}{rrd};
9939			}
9940		} else { push @ifs, $interfaces{$interface}{rrd}; }
9941		eval {
9942			foreach ( @ifs ) {
9943				next if(!$_);
9944				RRDs::flushcached('--daemon',$rrdcached,$_);
9945			};
9946		};
9947	}
9948	# no longer needed as all will be done directly
9949	#$rrdcached = "" if( $rrdcached =~ /^unix:/ );
9950}
9951@rrdcached = ();
9952@rrdcached = ( '--daemon',$rrdcached ) if($rrdcached);
9953
9954# Should we verify that the RRA has enough data?  This would take a bit of
9955# extra time to do, but would prevent glitches.  However we could say that
9956# anyone who switches this option on is taking the responsibility for making
9957# sure that the data is valid!
9958# Note that, if extendedtime = full, then we dont add these as we will instead
9959# test the RRD and add the appropriate dates into the calendar.
9960if( defined $config{'routers.cgi-extendedtime'}
9961	and $config{'routers.cgi-extendedtime'} =~ /y/i
9962) {
9963	push @gorder, "d-","w-","m-","y-";
9964} elsif ( defined $config{'routers.cgi-extendedtime'}
9965	and $config{'routers.cgi-extendedtime'} =~ /t/i
9966	and $interface and defined $interfaces{$interface}
9967	and $interfaces{$interface}{rrd}
9968) {
9969	# see if we have more data available...
9970	eval { require RRDs; };
9971	if( !$@ ) {
9972		my( $infop ) = RRDs::info($interfaces{$interface}{rrd},@rrdcached);
9973		push @gorder, "d-" if( ${$infop}{"rra[0].rows"} > 799 );
9974		push @gorder, "w-" if( ${$infop}{"rra[1].rows"} > 799 );
9975		push @gorder, "m-" if( ${$infop}{"rra[2].rows"} > 799 );
9976		push @gorder, "y-" if( ${$infop}{"rra[3].rows"} > 799 );
9977	}
9978}
9979
9980# sanity check
9981#if( $gtype eq "6" and $interface !~ /^__/ and ( !$usesixhour
9982#	or ($interface and defined $interfaces{$interface}
9983#		and $interfaces{$interface}{interval} >= 5 ))) {
9984#	 $gtype = $gorder[0];
9985#}
9986if( $gtype eq "6" and $interface !~ /^_/ and !$usesixhour ) {
9987	 $gtype = $gorder[0];
9988}
9989if( defined $interfaces{$interface}
9990	and defined $interfaces{$interface}{suppress} ) {
9991	my($pat) = '['.$interfaces{$interface}{suppress}.']';
9992	$gtype = 'dwmy' if($gtype =~ /$pat/);
9993}
9994if ( ! (defined $gtypes{$gtype}) or
9995	( ($interface eq "__compact"
9996		or (defined $interfaces{$interface} and $interfaces{$interface}{issummary}))
9997		 and (length ($gtype) > 2) )) {
9998	$gtype = $gorder[0];
9999}
10000if( defined $config{'routers.cgi-uselastupdate'}
10001	and $config{'routers.cgi-uselastupdate'} =~ /y/i ) {
10002	$uselastupdate = 1; # set the flag for later.
10003} else { $uselastupdate = 0; }
10004# How big is a K ? Some people prefer 1024, some prefer 1000
10005if( $interfaces{$interface}{kilo} ) {
10006	$k = $interfaces{$interface}{kilo};
10007	$M = $k * $k;
10008	$G = $M * $k;
10009	$T = $G * $k;
10010	if($k == 1000) { $ksym = 'k'; } else { $ksym = 'K'; }
10011} else {
10012  if( defined $config{'routers.cgi-usebigk'} ) {
10013	if( $config{'routers.cgi-usebigk'} =~ /y/i )      # yes
10014		{ $k = 1024; $M = $k * 1024; $G = $M * 1024; $T=$G*1024; $ksym = "K"; }
10015	elsif( $config{'routers.cgi-usebigk'} =~ /n/i )   # no
10016		{ $k = 1000; $M = 1000000; $G = $M * 1000; $T=$G*1000;$ksym = "k"; }
10017	elsif( $config{'routers.cgi-usebigk'} =~ /m/i )   # mixed
10018		{ $k = 1024; $M = 1024000; $G = $M * 1000; $T=$G*1000;$ksym = "K"; }
10019	else
10020		{ $k = 1024; $M = 1024000; $G=$M*1000;$T=$G*1000;$ksym="K"; } # default
10021  } else {
10022	$k = 1024; $M=1024000; $G=$M*1000;$T=$G*1000;$ksym="K"; # default (mixed)
10023  }
10024}
10025# Here, we should consider supporting Kmg to set ksym
10026# Define page title and so on.
10027$windowtitle = $config{'routers.cgi-windowtitle'}
10028	if ( defined $config{'routers.cgi-windowtitle'} );
10029$toptitle = $config{'routers.cgi-pagetitle'}
10030	if ( defined $config{'routers.cgi-pagetitle'} );
10031$toptitle = "<FONT size=+3>".$q->b($windowtitle)."</FONT>" if(!$toptitle);
10032
10033# Date format labels
10034$monthlylabel=$config{'web-weeknumber'}
10035	if( defined $config{'web-weeknumber'}
10036	and $config{'web-weeknumber'} =~ /%[UVW]/ );
10037$dailylabel=$config{'web-hournumber'}
10038	if( defined $config{'web-hournumber'}
10039	and $config{'web-hournumber'} =~ /%[a-zA-Z]/ );
10040
10041# Line widths
10042$linewidth = $config{'routers.cgi-linewidth'}
10043	if( defined $config{'routers.cgi-linewidth'}
10044		and ($config{'routers.cgi-linewidth'}>0)
10045		and ($config{'routers.cgi-linewidth'}<5));
10046
10047# Menu format
10048if( (defined $config{'routers.cgi-twinmenu'}
10049	and $config{'routers.cgi-twinmenu'} =~ /y/i and $uopts !~ /T/ )
10050	or $uopts =~ /t/ ) {
10051	$twinmenu = 1;
10052}
10053
10054# Archived data
10055# first, clean up cache if polluted
10056if(defined $interfaces{$interface} and $interfaces{$interface}{origrrd}) {
10057	$interfaces{$interface}{rrd} = $interfaces{$interface}{origrrd};
10058}
10059$archdate = '';
10060$archdate = $q->param('arch') if(defined $q->param('arch'));
10061$archdate = $opt_a if($opt_a);
10062$archdate = '' if($archdate eq POSIX::strftime('%Y-%m-%d',localtime()));
10063$basetime = 0;
10064if($config{'routers.cgi-extendedtime'} and $config{'routers.cgi-extendedtime'}=~/f/i and $archdate) {
10065	if($archdate=~/^(\d\d\d\d)-(\d\d)-(\d\d)/) {
10066		eval {
10067			$basetime = timelocal_nocheck(59,59,23,$3,$2-1,$1-1900);
10068		};
10069		if($@) {
10070			$debugmessage .= "Error in time conversion: $@\n";
10071		}
10072	}
10073	$basetime = time() if($basetime > time());
10074	$debugmessage .= "Setting base time to $basetime ($archdate)\n";
10075} elsif($archdate and $donecfg) {
10076	# archive date, and read in cfg file, and not extendedtime=full mode
10077	if($archdate=~/^(\d\d\d\d)-(\d\d)-(\d\d)/) {
10078		eval {
10079			$archivetime = timelocal_nocheck(59,59,23,$3,$2-1,$1-1900);
10080		};
10081	}
10082	if( !$interface or !$interfaces{$interface}{rrd}){
10083		$debugmessage .= "Invalid target $interface!\n";
10084		$archdate = '';  # This interface is not valid
10085	} elsif( $config{'routers.cgi-extendedtime'} and $config{'routers.cgi-extendedtime'}=~/f/i ) {
10086		# using extendedtime with calendar.
10087	} elsif( ! -d
10088		(dirname($interfaces{$interface}{rrd}).$pathsep.'archive'
10089			.(($config{'routers.cgi-archive-mode'} and
10090				$config{'routers.cgi-archive-mode'}=~/hash/i )?""
10091				:($pathsep.$archdate)
10092			)
10093		)
10094	) {
10095		$debugmessage .= "Invalid date $archdate for target $interface!\n";
10096		$archdate =  ''; # this date archive is not avaiable
10097	} else {
10098		# CHANGE THE DEFINED RRD FILE(s) IF WE ARE NOT ON MENU
10099		if($pagetype=~/graph|csv|image|summary|compact/ ) {
10100			my($thisif,$dn,$bn);
10101			my(@candidates) = ( $interface );
10102#			push @candidates, @{$interfaces{$interface}{targets}}
10103#				if($interfaces{$interface}{usergraph}
10104#					or $interfaces{$interface}{issummary});
10105			@candidates = (keys %interfaces)
10106				if($interface =~ /^__/ or $interfaces{$interface}{usergraph});
10107			foreach $thisif ( @candidates ) {
10108				next if($thisif =~ /^_/); # skip userdefineds
10109				if(!$interfaces{$thisif}{origrrd}) {
10110					$interfaces{$thisif}{origrrd} = $interfaces{$thisif}{rrd};
10111				} else {
10112					$interfaces{$thisif}{rrd} = $interfaces{$thisif}{origrrd};
10113				}
10114				next if(!$interfaces{$thisif}{rrd});
10115				$dn = dirname($interfaces{$thisif}{rrd});
10116				$bn = basename($interfaces{$thisif}{rrd});
10117				$interfaces{$thisif}{rrd} = $dn.$pathsep.'archive'.$pathsep
10118					.(($config{'routers.cgi-archive-mode'} and
10119						$config{'routers.cgi-archive-mode'}=~/hash/i )?(
10120						makehash($bn).$pathsep.$bn.".d"
10121						.$pathsep.$archdate.".rrd"
10122					):(
10123						$archdate.$pathsep.$bn
10124					));
10125				if( ! -f $interfaces{$thisif}{rrd} ) {
10126					# if the archive doesnt exist
10127					$interfaces{$thisif}{rrd} = $interfaces{$thisif}{origrrd};
10128#					$archdate = '';
10129					$debugmessage .= "No archive for target $thisif on $archdate\n";
10130#				} else {
10131#					# is this a good idea?  Maybe should uselastupdate instead
10132#					my($a) = (stat $interfaces{$thisif}{rrd})[9];
10133#					$archivetime = $a if(!$archivetime) or ($a > $archivetime));
10134				}
10135			}
10136		}
10137		$uselastupdate = 2; # since we are now basing from old .rrd file
10138	}
10139#	$debugmessage .= "Archivetime: $archivetime\nArchdate: $archdate\n";
10140} elsif(defined $interfaces{$interface}) {
10141	if($pagetype =~ /graph|csv|summary|compact/ ) {
10142		my($thisif);
10143		my(@candidates) = ( $interface );
10144		push @candidates, @{$interfaces{$interface}{targets}}
10145			if($interfaces{$interface}{usergraph});
10146		@candidates = (keys %interfaces) if($interface =~ /^__/);
10147		foreach $thisif ( @candidates ) {
10148			$interfaces{$thisif}{rrd} = $interfaces{$thisif}{origrrd}
10149				if($interfaces{$thisif}{origrrd});
10150		}
10151	}
10152}
10153
10154if( $opt_A ) {
10155	$pagetype = 'COMMAND'; $archiveme = 1; # override
10156	$|=1;
10157	print "Creating Graph...\n";
10158	if($opt_T) {
10159		# target was set
10160		# Archive this graph
10161		if( !$interface or !defined $interfaces{$interface}
10162			or $interface=~/^__/ or $interfaces{$interface}{issummary} ) {
10163			print "This target is not appropriate to archive.\n";
10164			print "Device/Target = [$router]/[$interface]\n";
10165			print "Unknown Target\n" if(!defined $interfaces{$interface});
10166			print "Illegal Target\n" if($interface=~/^__/);
10167			print "Summary Target\n" if($interfaces{$interface}{issummary});
10168			print "Targets:\n".(join ",",(keys %interfaces))."\n";
10169			print "Devices:\n".(join ",",(keys %routers))."\n";
10170			exit(1);
10171		}
10172		do_graph(0);
10173	} else {
10174		# Do them all, for this device
10175		foreach $interface ( keys %interfaces ) {
10176			next if($interface=~/^__/ or $interfaces{$interface}{issummary}
10177				or !$interfaces{$interface}{inmenu} );
10178			print "$interface... ";
10179			do_graph(0);
10180		}
10181	}
10182	exit(0);
10183}
10184
10185# Start the page off
10186if( $pagetype =~ /graph/ and !$archive and !$archdate ) {
10187	my($rtime) = 1800;
10188	$rtime =900 if($gtype =~ /w/);
10189	$rtime =300 if($gtype =~ /d/);
10190	$rtime = 60 if($gtype =~ /6/);
10191	$rtime = $config{'routers.cgi-minrefreshtime'}
10192		if( defined $config{'routers.cgi-minrefreshtime'}
10193			and $config{'routers.cgi-minrefreshtime'} > $rtime );
10194	$headeropts{-expires} = "+5s";
10195	$headeropts{-Refresh} = $rtime;
10196	$headeropts{-Refresh} .= "; URL=$meurlfull?".optionstring({}) if($archiveme);
10197	$headeropts{-head} = [] if(!$headeropts{-head});
10198	push @{$headeropts{-head}}, $q->meta({-http_equiv=>'Refresh',-content=>$headeropts{-Refresh}});
10199}
10200$headeropts{-target} = $pagetype if($pagetype =~ /head|menub?|graph/ );
10201$headeropts{-target} = "graph"
10202	if( $pagetype =~ /compact|summary|help|info|config/ );
10203$headeropts{-target} = "_top" if ( !$pagetype );
10204
10205if ( $pagetype =~ /config/ and $q->param('xset')) {
10206	push @cookies, $q->cookie( -name=>'gstyle', -value=>$q->param('defgstyle'),
10207		-path=>$q->url(-absolute=>1), -expires=>"+10y" )
10208			if( defined $q->param('defgstyle'));
10209	push @cookies, $q->cookie( -name=>'gtype', -value=>$q->param('defgtype'),
10210		-path=>$q->url(-absolute=>1), -expires=>"+10y" )
10211			if( defined $q->param('defgtype') );
10212	push @cookies, $q->cookie( -name=>'router', -value=>$q->param('defrouter'),
10213		-path=>$q->url(-absolute=>1), -expires=>"+10y" )
10214			if( defined $q->param('defrouter') );
10215	push @cookies, $q->cookie( -name=>'if', -value=>$q->param('defif'),
10216		-path=>$q->url(-absolute=>1), -expires=>"+10y" )
10217			if( defined $q->param('defif') );
10218	if( defined $q->param('deflang') ) {
10219		initlang($q->param('deflang'));
10220		if($q->param('deflang')) {
10221			push @cookies, $q->cookie( -name=>'lang', -value=>$language,
10222				-path=>$q->url(-absolute=>1), -expires=>"+10y" ) ;
10223		} else {
10224			push @cookies, $q->cookie( -name=>'lang', -value=>'',
10225				-path=>$q->url(-absolute=>1), -expires=>"now" ) ;
10226		}
10227	}
10228}
10229# Character sets
10230if(defined $config{'routers.cgi-charset'}) {
10231	$charset = $config{'routers.cgi-charset'};
10232}elsif(defined $config{'web-charset'}) {
10233	$charset = $config{'web-charset'};
10234}
10235if($charset) {
10236	$headeropts{-charset} = $charset;
10237
10238	$headeropts{-head} = [] if(!$headeropts{-head});
10239	push @{$headeropts{-head}}, $q->meta({-http_equiv => 'Content-Type',
10240		-content => "text/html; charset=$charset"});
10241}
10242# Are we exporting CSV?
10243if( $pagetype =~ /csv/ ) {
10244	my($fn) = "export.csv";
10245	$csvmime=$config{'web-csvmimetype'} if(defined $config{'web-csvmimetype'});
10246	$fn = $config{'web-csvmimefilename'}
10247		if(defined $config{'web-csvmimefilename'}) ;
10248	$csvmime .= "; filename=\"".$fn."\"";
10249	$headeropts{"-Content-Disposition"} = "filename=\"".$fn."\"";
10250	$headeropts{-type} = $csvmime ;
10251}
10252
10253# The bar and image functions have to do their own headers as they may need
10254# to redirect.
10255$headeropts{-cookie} = [@cookies] if(@cookies);
10256print $q->header({ %headeropts }) if($pagetype !~ /bar|image|COMMAND/);
10257
10258#
10259# Now, we check the passed parameters to find out what sort of page to
10260# serve up.  If we can't work out which one to do, then we just serve the
10261# index page
10262if($pagetype) {
10263	for($pagetype) {
10264		/head/ and do {	do_head(); last; };
10265		/menu/ and do { do_menu(); last; }; # matches menu and menub
10266		/compactcsv/ and do { do_compact(1); last; };
10267		/csv/ and do {
10268			if($interface eq "__compact") { do_compact(1);	last; }
10269			last if( $interface =~ /^__/ ); # oops, this shouldnt happen
10270			do_export();
10271			last;
10272		};
10273		/image/ and do {
10274			if( $interface !~ /^__/ and defined $interfaces{$interface}) {
10275				if( $archive ) {
10276					do_archive(0);
10277				} else {
10278					do_graph(0);
10279				}
10280			} else {
10281				if($opt_I) {
10282					print "Interface: $interface\nError: Not defined\n";
10283				} else {
10284		print $q->redirect($config{'routers.cgi-iconurl'}."error-lg.gif");
10285				}
10286			}
10287			last;
10288		};
10289		/graph|archive/ and do {
10290			if ( $interface eq "__info" ) {
10291				do_info();
10292			} elsif ( $interface eq "__compact" ) {
10293				do_compact(0);
10294			} elsif ( $interface eq "__none" ) {
10295				do_empty();
10296			} elsif ( $interface =~ /^__/ ) {
10297				do_bad("Bad target: $interface");
10298			} elsif ( $interfaces{$interface}{usergraph}
10299				and $interfaces{$interface}{issummary} ) {
10300				do_summary();
10301			} else {
10302				if( $archive ) {
10303					do_archive(1);
10304				} else {
10305					do_graph(1);
10306				}
10307			}
10308			last;
10309		};
10310		/help/ and do { do_help(); last; };
10311		/main/ and do { do_main(); last; };
10312		/info/ and do { do_info(); last; };
10313		/summary/ and do { do_summary(); last; };
10314		/compact/ and do { do_compact(0); last; };
10315		/config/ and do { do_config(); last; };
10316		/bar/ and do { do_bar(); last; };
10317		/verify/ and do {
10318			if($config{'web-paranoia'}
10319				and $config{'web-paranoia'}=~/[yY1]/) {
10320				do_bad(langmsg(8006,"You do not have authority to view the configuration"));
10321			last;
10322			}
10323			if( !defined $config{'routers.cgi-allowexplore'}
10324				or $config{'routers.cgi-allowexplore'} =~ /[1y]/i ) {
10325				do_verify(); last;
10326			}
10327			do_bad(langmsg(8006,"You do not have authority to view the configuration"));
10328			last;
10329		};
10330		do_bad("Bad pagetype: $pagetype");
10331	}
10332} else { do_main() }
10333
10334# Clean up
10335if($CACHE and $archdate) {
10336	if(defined $interfaces{$interface}
10337	and defined $interfaces{$interface}{origrrd}) {
10338		$interfaces{$interface}{rrd} = $interfaces{$interface}{origrrd};
10339	}
10340}
10341exit(0);
10342