#! /usr/bin/perl
# -*- mode: Perl -*-
BEGIN{
$main::OS = 'OS2';
#$main::OS = 'UNIX';
#$main::OS = 'NT';
#$main::OS = 'VMS';
##################################################################
# MRTG 2.8.8  Multi Router Traffic Grapher
##################################################################
# Created by Tobias Oetiker <oetiker@ee.ethz.ch>
#            and Dave Rand <dlr@bungi.com>
#
# Code Strictification by Richard Bullington <rbulling@obscure.org>
#
#################################################################
#
# Distributed under the GNU copyleft
#
###################################################################
   # The path separator is a slash, backslash or semicolon, depending
   # on the platform.
   $main::SL = {
     UNIX=>'/',
     WINDOWS=>'\\',
     NT=>'\\',
     OS2=>'\\',
     VMS=>''
     }->{$main::OS};

   # The search path separator is a colon or semicolon depending on the
   # operating system.
   $main::PS = {
     UNIX=>':',
     WINDOWS=>';',
     NT=>';',
     OS2=>';',
     VMS=>':'
     }->{$main::OS};

  # We need to find the place where mrtg is installed, and
  # then take the .pm and rateup programms from there.
  if ( $main::OS eq 'OS2' ) {
     $main::binpath =".";
  } else {
     $main::binpath ="";
  }
  if ($0 =~ /^(.+\Q${main::SL}\E)/) {
    $main::binpath="$1";
  } else {
    foreach $pathname ( split ${main::PS}, $ENV{'PATH'}) {
      if ((($main::OS eq 'NT' || $main::OS eq 'OS2'  ) &&
           (-e "$pathname${main::SL}$0")) ||
           (-x "$pathname${main::SL}$0")) {
	$main::binpath=$pathname;
  	last;
      }
    }
  }
  die "ERROR: Can\'t find location of mrtg executable\n" 
    unless $main::binpath; 
  unshift (@INC,$main::binpath);
}

###
# Finally, SNMPGet fully written in PERL5. 
# Thanks to Simon Leinen <simon@switch.ch>
# More on: http://www.switch.ch/misc/leinen/snmp/perl/
####

# There older perls tend to behave peculiar with
# large integers ... 
require 5.003;

if ($main::OS eq 'UNIX' || $main::OS eq 'NT' || $main::OS eq 'OS2' ) {
#######################################################################
#    use lib "path to a rrd module as instructed by RRDtool distro";
#    use RRDs;
#######################################################################
    use SNMP_Session "0.71";
    use BER "0.66";
    use SNMP_util "0.71";
    use locales_mrtg "0.01";
    use Config;    
    $main::SNMPDEBUG =0;
}

use strict;

if($main::OS eq 'UNIX')
{
    my($i) = 0;
    my($name);

    foreach $name (split(/ /, $Config{sig_name}))
    {
	$main::signo{$name} = $i;
	$main::signame[$i++] = $name;
    }
}

$main::DEBUG=0;


sub END {
	local($?, $!);
	unlink ${main::Cleanfile} if($main::Cleanfile);
}

sub main {
  
  my ($router, $target);
  
  # unbuffer stdout to see everything immediately
  $|=1 if $main::DEBUG;   
  
  # read in the config file
  my ($routers, $cfg, $rcfg, $cfgfile) = readcfg();
  $target = cfgcheck($routers, $cfg, $rcfg);
  
  # Check the config and create the target object
  # lets make sure that there are not two mrtgs running in parallel.
  # so we lock on the cfg file. Nothing fancy, just a lockfile
  #
  my $lockfile = $cfgfile."_l";
  my $templock = $cfgfile."_l_" . $$ ;
  if ($main::OS eq 'VMS' || $main::OS eq 'NT' || $main::OS eq 'OS2' ) {
  # too sad OS2 and NT and VMS can't do links we'll do the diletants lock
    if (-e $lockfile && not unlink $lockfile){
      my($lockage) = time()-(stat($lockfile))[9];
      die ("ERROR: I guess another mrtg is running. A lockfile ($lockfile)
       aged $lockage seconds is hanging around and I can't remove 
       it because another process is still using it.");
    }
    	
    open (LOCK, ">$lockfile") or die "ERROR: Can't create lockfile $lockfile\n";
    print LOCK "$$\n";
    close LOCK;
    open (LOCK, "<$lockfile") or die "ERROR: Can't open lockfile $lockfile for owner check\n";
    my($read)=<LOCK>;
    chomp($read);
    die "ERROR: Someone else just got the lockfile $lockfile\n" 
	unless  $$ == $read;
  } else {
    # now, lets do it the UNIX way ... Daves work ...
    open(LOCK,">$templock") || die "Can't create templock $templock";
    $main::Cleanfile = $templock;
    if (!link($templock,$lockfile)) {  # Lock file exists - deal with it.
      my($nlink,$lockage) = (stat($lockfile))[3,9]; 
      $lockage = time() - $lockage;
      if ($nlink < 2 || $lockage > 30*60) { #lockfile is alone and old
	unlink($lockfile) 
	  || do{ unlink $templock; 
		 die "ERROR: Can't unlink stale lockfile ($lockfile). Permissions?\n"};
	
	link($templock,$lockfile) 
	  || do{ unlink $templock; 
		 die "ERROR: Can't create lockfile ($lockfile).\n".
		   "Permission problem or another mrtg locking succesfully?\n"};
      }
      else {
	unlink $templock;
	die ("ERROR: I guess another mrtg is running. A lockfile ($lockfile) aged\n".
	     "$lockage seconds is hanging around. If you are sure that no other mrtg\n".
	     "is running you can remove the lockfile\n");
	
      }
      
    }
  }
  # OK we are in business ... lets read the cfg file ... 

  # removed this ... it just breaks too much ...   
  #chdir ($cfg{'workdir'});
  
  # Use SNMP to populate the target object
  readtargets($target, $cfg, $rcfg,$cfgfile);
  
  foreach $router (@$routers) {
    my($savetz) = $ENV{'TZ'};

    if ($$rcfg{'timezone'}{$router} ne '') {
      $ENV{'TZ'} = $$rcfg{'timezone'}{$router}
    }  

    my ($inlast, $outlast, $uptime, $name, $time) = 
      getcurrent($target, $router, $rcfg);
    
    print "inlast $inlast outlast $outlast uptime $uptime".
      " name $name time $time\n"  if $main::DEBUG;
    #abort, if the router is not responding.
    next if ($inlast == -1);
    
    my ($maxin, $maxout, $maxpercent, $avin, $avout, $avpercent,
		$cuin, $cuout, $cupercent);
    if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
      ($maxin, $maxout, $maxpercent, $avin, $avout, $avpercent,
		$cuin, $cuout, $cupercent) =  
        writegraphics($router, $cfg, $rcfg, $inlast, $outlast, $time);
    }
    else {
      ($maxin, $maxout ,$avin, $avout, $cuin, $cuout) =  
        writegraphics($router, $cfg, $rcfg, $inlast, $outlast, $time);
    }
    
    # threshold checking ... by Tom Muggli
    my (@threshinexec, @threshoutexec, $threshinval, 
	$threshoutval, $threshfile, @threshtmp);
    @threshinexec = ();
    @threshoutexec = ();
    $threshinval = 0 + $$cuin{'d'}{$router};
    $threshoutval = 0 + $$cuout{'d'}{$router};
    $threshfile = "$$cfg{'threshdir'}${main::SL}";
 
    @threshtmp = split(/\Q$main::SL\E/, $cfgfile);
    $threshfile .= "$threshtmp[$#threshtmp].$router";
 
    if ($$rcfg{'threshmini'}{$router} && 
	$$rcfg{'threshmini'}{$router} > $threshinval) {
      @threshinexec = ("$$rcfg{'threshprogi'}{$router}", 
		       "$router", "$$rcfg{'threshmini'}{$router}", 
		       "$threshinval");
    }
    if ($$rcfg{'threshmaxi'}{$router} && 
	$$rcfg{'threshmaxi'}{$router} < $threshinval) {
      @threshinexec = ("$$rcfg{'threshprogi'}{$router}", 
		       "$router", "$$rcfg{'threshmaxi'}{$router}", 
		       "$threshinval");
    }
    if (scalar(@threshinexec) > 0) {
      print "THRESH IN: ",(join " ", @threshinexec),"\n" if $main::DEBUG;
      if ($$cfg{'threshdir'} && 
	  $$rcfg{'threshprogoki'}{$router} && -d $$cfg{'threshdir'}) {
        # Create a file to indicate a threshold problem for the next running.
        open (THRESHTOUCH, ">$threshfile.I");
        close (THRESHTOUCH);
      }  
      if ($main::OS eq 'VMS' || $main::OS eq 'NT' ) {
        open (THRESHIN, join (" ", @threshinexec)."|");
      } else {
        open (THRESHIN, "-|") || exec @threshinexec;
      }  
      close (THRESHIN);
    } else {
      if ($$cfg{'threshdir'} && 
	  $$rcfg{'threshprogoki'}{$router} && -e "$threshfile.I") {
        # If a previous running broke a threshold, but now we're inside.
        @threshinexec = ("$$rcfg{'threshprogoki'}{$router}", 
			 "$router", "$threshinval");
        print "THRESH IN OK: ",(join " ", @threshinexec),"\n" if $main::DEBUG;
        if ($main::OS eq 'VMS' || $main::OS eq 'NT') {
          open (THRESHIN, join (" ", @threshinexec)."|");
        } else { 
          open (THRESHIN, "-|") || exec @threshinexec;
        }
        close (THRESHIN);
        unlink("$threshfile.I");
      }  
    }  

    if ($$rcfg{'threshmino'}{$router} && 
	$$rcfg{'threshmino'}{$router} > $threshoutval) {
      @threshoutexec = ("$$rcfg{'threshprogo'}{$router}", 
			"$router", "$$rcfg{'threshmino'}{$router}", 
			"$threshoutval");
    }
    if ($$rcfg{'threshmaxo'}{$router} && 
	$$rcfg{'threshmaxo'}{$router} < $threshoutval) {
      @threshoutexec = ("$$rcfg{'threshprogo'}{$router}", 
			"$router", "$$rcfg{'threshmaxo'}{$router}", 
			"$threshoutval");
    }
    if (scalar(@threshoutexec) > 0) {
      print "THRESH OUT: ",(join " ", @threshoutexec),"\n" if $main::DEBUG;
      if ($$cfg{'threshdir'} && 
	  $$rcfg{'threshprogoko'}{$router} && -d $$cfg{'threshdir'}) {
        # Create a file to indicate a threshold problem for the next running.
        open (THRESHTOUCH, ">$threshfile.O");
        close (THRESHTOUCH);
      }  
      if ($main::OS eq 'VMS' || $main::OS eq 'NT') {
        open (THRESHOUT, join (" ", @threshoutexec)."|");
      } else {
        open (THRESHOUT, "-|") || exec @threshoutexec;
      }  
      close (THRESHOUT);
    } else {
      if ($$cfg{'threshdir'} && 
	  $$rcfg{'threshprogoko'}{$router} && -e "$threshfile.O") {
        # If a previous running broke a threshold, but now we're inside.
        @threshoutexec = ("$$rcfg{'threshprogoko'}{$router}", 
			  "$router", "$threshoutval");
        print "THRESH OUT OK: ",(join " ", @threshoutexec),"\n" 
	  if $main::DEBUG;
        if ($main::OS eq 'VMS' || $main::OS eq 'NT') {
          open (THRESHIN, join (" ", @threshoutexec)."|");
        } else {
          open (THRESHIN, "-|") || exec @threshoutexec;
        }
        close (THRESHIN);
        unlink("$threshfile.O");
      }  
    }  
    #  end of threshold checking ... ****************************************
    if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
    print "maxin $maxin maxout $maxout maxpercent $maxpercent avin $avin ",
    "avout $avout avpercent $avpercent cuin $cuin cuout $cuout ", 
    "cupercent $cupercent\n"
      if $main::DEBUG >2;
    }
    else {
    print "maxin $maxin maxout $maxout avin $avin ",
    "avout $avout cuin $cuin cuout $cuout\n" 
      if $main::DEBUG >2;
    }
    
    # set the locale
    my($LOC);
    if( $$cfg{'language'} && defined($lang2tran::LOCALE{"\L$$cfg{'language'}\E"}))
    {
      $LOC=$lang2tran::LOCALE{"\L$$cfg{'language'}\E"};
    }
    else
    {
      $LOC=$lang2tran::LOCALE{'default'};
    };

    writehtml($router, $cfg, $rcfg, 
	         $maxin, $maxout, $maxpercent, $avin, $avout, $avpercent,
	         $cuin, $cuout, $cupercent, $uptime, $name, $LOC)
	if (!$$cfg{userrdtool});
    
    #put TZ things back in shape ... 
    if ($savetz) {$ENV{'TZ'} =  $savetz;} else
    {delete $ENV{'TZ'}};
    
  }
  # OK we are done, remove the lock files ... 
  close LOCK; unlink ($templock, $lockfile);
}

main;
exit(0);

sub quickcheck {
  my ($first,$second,$arg,$line) = @_;
  my %rules =
    (# General CFG
     'workdir' => 
     ['$arg && (-d $arg)','"Directory $arg does not exist"'],
     
     'refresh' => 
     ['int($arg) >= 300', '"$arg should be 300 seconds or more"'],
     
     'interval' => 
     ['int($arg) >= 5','"$arg should be more than 5 Minutes"'], 
     
     'writeexpires' =>  
     ['1','"Internal Error"'],
     
     'icondir' =>
     ['$arg','"Directory argument missing"'],
     
     'language' =>
     ['1','"Mrtg not localized for $arg - defaulting to english"'],

     'loadmibs' =>
     ['$arg','"No MIB Files specified"'],

     'userrdtool' =>
     ['1','"Internal Error"'],

     # Per Router CFG
     'target[]' => 
     ['1','"Internal Error"'],  #will test this later
     
     'routeruptime[]' => 
     ['1','"Internal Error"'],  #will test this later
     
     'maxbytes[]' => 
     ['(($arg =~ /^[0-9]+$/) && ($arg <= (2**31)-1))',
	'"$arg must be a Number smaller than maxint"'],

     'maxbytes1[]' =>
     ['(($arg =~ /^[0-9]+$/) && ($arg < (2**31)-1))',
	'"$arg must be a Number smaller than maxint"'],

     'maxbytes2[]' =>
     ['(($arg =~ /^[0-9]+$/) && ($arg < (2**31)-1))',
	'"$arg must be a Number smaller than maxint"'],

     'absmax[]' => 
     ['($arg =~ /^[0-9]+$/)','"$arg must be a Number"'],
     
     'title[]' => 
     ['1','"Internal Error"'], #what ever the user chooses.
     
     'directory[]' => 
     ['1','"Internal Error"'], #what ever the user chooses.
     
     'pagetop[]' => 
     ['1','"Internal Error"'], #what ever the user chooses.

     'pagefoot[]' => 
     ['1','"Internal Error"'], #what ever the user chooses.

     'addhead[]' => 
     ['1','"Internal Error"'], #what ever the user chooses.
     
     'unscaled[]' => 
     ['$arg =~ /[dwmy]+/i','"Must be a string of [d]ay, [w]eek, [m]onth, [y]ear"'],
     
     'weekformat[]' => 
     ['$arg =~ /[UVW]/','"Must be either W, V, or U"'],
     
     'withpeak[]' =>
     ['$arg =~ /[dwmy]+/i','"Must be a string of [d]ay, [w]eek, [m]onth, [y]ear"'],
     
     'suppress[]' =>
     ['$arg =~ /[dwmy]+/i','"Must be a string of [d]ay, [w]eek, [m]onth, [y]ear"'],
     
     'xsize[]' =>
     ['((int($arg) >= 30) && (int($arg) <= 600))','"$arg must be between 30 and 600 pixels"'],
     
     'ysize[]' =>
     ['(int($arg) >= 30)','"Must be >= 30 pixels"'],

     'ytics[]' =>
     ['(int($arg) >= 1) ','"Must be >= 1"'],

     'yticsfactor[]' =>
     ['$arg =~ /[-+0-9.efg]+/','"Should be a numerical value"'],

     'step[]'  =>
     ['(int($arg) >= 0)','"$arg must be > 0"'],

     'timezone[]' =>
     ['1','"Internal Error"'],

     'options[]' =>
     ['1','"Internal Error"'],
     
     'colours[]' =>
     ['1','"Internal Error"'],


     'background[]' =>
     ['1','"Internal Error"'],
     
     'kilo[]' => 
     ['($arg =~ /^[0-9]+$/)','"$arg must be a Integer Number"'],
			#define whatever k should be (1000, 1024, ???)
     
     'kmg[]' =>
     ['1','"Internal Error"'],
     
     'ylegend[]' =>
     ['1','"Internal Error"'],

     'shortlegend[]' =>
     ['1','"Internal Error"'],

     'legend1[]' =>
     ['1','"Internal Error"'],

     'legend2[]' =>
     ['1','"Internal Error"'],

     'legend3[]' =>
     ['1','"Internal Error"'],

     'legend4[]' =>
     ['1','"Internal Error"'],

     'legend5[]' =>
     ['1','"Internal Error"'],

     'legendi[]' =>
     ['1','"Internal Error"'],

     'legendo[]' =>
     ['1','"Internal Error"'],

     'xzoom[]' =>
     ['($arg =~ /^[0-9]+(?:\.[0-9]+)?$/)',
      '"$arg must be a Number xxx.xxx"'],

     'yzoom[]' =>
     ['($arg =~ /^[0-9]+(?:\.[0-9]+)?$/)',
      '"$arg must be a Number xxx.xxx"'],

     'xscale[]' =>
     ['($arg =~ /^[0-9]+(?:\.[0-9]+)?$/)',
      '"$arg must be a Number xxx.xxx"'],

     'yscale[]' =>
     ['($arg =~ /^[0-9]+(?:\.[0-9]+)?$/)',
      '"$arg must be a Number xxx.xxx"'],

     'threshdir' =>
     ['$arg && (-d $arg)','"Threshold directory $arg does not exist"'],

     'threshmini[]' =>
     ['1','"Internal Threshold Config Error"'],

     'threshmino[]' =>
     ['1','"Internal Threshold Config Error"'],

     'threshmaxi[]' =>
     ['1','"Internal Threshold Config Error"'],

     'threshmaxo[]' =>
     ['1','"Internal Threshold Config Error"'],

     'threshprogi[]' =>
     ['$arg && (-x $arg)','"Threshold program $arg cannot be executed"'],

     'threshprogo[]' =>
     ['$arg && (-x $arg)','"Threshold program $arg cannot be executed"'],

     'threshprogoki[]' =>
     ['$arg && (-x $arg)','"Threshold program $arg cannot be executed"'],

     'threshprogoko[]' =>
     ['$arg && (-x $arg)','"Threshold program $arg cannot be executed"']

    );
 
  my $braces = $second ? '[]':'';
  if (exists $rules{$first.$braces}) {
    if (eval($rules{$first.$braces}[0])) {
      return 1;
    } else {
      if ($second) {
	die "\nCFG Error in \"$first\[$second\]\", line $line: ".
	  eval($rules{$first.$braces}[1])."\n\n"; 
      } else {
	die "\nCFG Error in \"$first\", line $line: ".
	  eval($rules{$first.$braces}[1])."\n\n"; 
      } 
    }
  }
  die "\nCFG Error: Unknown Option \"$first\" on line $line or above.\n".
    "           Check readme.html for Help\n\n";
}

sub readcfg {
  my ($first,$second,$key);
  my (%seen);
  my (@routers);
  my (%rcfg,%cfg,%pre,%post,%deflt,%defaulted);
  my ($cfgfile) = pop(@ARGV);
  open (CFG, $cfgfile) || do { print "ERROR: unable to open config file: $cfgfile\n\n"; &printusage };
  while (<CFG>) {
    s/\s+$//g; #remove whitespace at the end of the line
    s/\s/ /g;  #replace whitespace by space
    next if /^\s*\#/; #ignore comment lines
    next if /^\s*$/;  #ignore empty lines
    # oops spelling error
    s/^supress/suppress/gi;
    # append mode
    if ($first && /^\s+(.*\S)\s*$/) {
      if ($second eq '^') {
	$pre{$first} .= " $1";
	next;
      }
      if ($second eq '$' ) {
	$post{$first} .= " $1";
	next;
      }
      if ($second eq '_') {
	$deflt{$first} .= " $1";
	next;
      }

      if ($second) {
	$rcfg{$first}{$second} .= " $1";
      } else {
	$cfg{$first} .= " $1";
      }
      next;
    }
    
    if ($first && $second && $post{$first} && ($second !~ /^[\$^_]$/)) {
      if ($defaulted{$first}{$second}) {
        $rcfg{$first}{$second} = $post{$first};
        delete $defaulted{$first}{$second};
      } else {
        $rcfg{$first}{$second} .= " $post{$first}"
      }
    }

    if ($first && exists $deflt{$first} && ($second eq '_')) {
      &quickcheck($first,$second,$deflt{$first},$.)
    } elsif ($first && $second && ($second !~ /^[\$^_]$/)) {
      &quickcheck($first,$second,$rcfg{$first}{$second},$.)
    } elsif ($first && ($second !~ /^[\$^_]$/)) {
      &quickcheck($first,0,$cfg{$first},$.)
    }

    if (/^([A-Za-z0-9]+)\[(\S+)\]\s*:\s*(.*\S?)\s*$/) {
      print "readcfg: rcfg $1 $2  = $3\n" if $main::DEBUG > 1; 
      $first = lc($1);
      $second = lc($2);
      if ($second eq '^')
        { if ($3 ne '') {$pre{$first}=$3} else {delete $pre{$first}}; next; }
      if ($second eq '$')
        { if ($3 ne '') {$post{$first}=$3} else {delete $post{$first}}; next; }
      if ($second eq '_')
        { if ($3 ne '') {$deflt{$first}=$3} else {delete $deflt{$first}}; next; }

      push (@routers, $second) unless grep (/^$second$/, @routers); 
      
      # make sure that default tags spring into existance upon first 
      # call of a router

      foreach $key (keys %deflt) {
	if (! exists $rcfg{$key}{$second}) {
	  $rcfg{$key}{$second} = $deflt{$key};
	  $defaulted{$key}{$second} = 1;
	}
      }

      # make sure that prefix-only tags spring into existance upon first 
      # call of a router

      foreach $key (keys %pre) {
	if (! exists $rcfg{$key}{$second}) {
          delete $defaulted{$key}{$second} if $defaulted{$key}{$second};
	  $rcfg{$key}{$second} = "$pre{$key} ";
	}
      }

      if ($seen{$first}{$second}) {
	die ("\nLine $. in CFG file contains a duplicate definition for\n".
	     "$first\[$second]. First definition is on line $seen{$first}{$second}\n")
      } else {
	$seen{$first}{$second} = $.;
      }

      if ($defaulted{$first}{$second}) {
        $rcfg{$first}{$second} = '';
        delete $defaulted{$first}{$second};
      }
      $rcfg{$first}{$second} .= $3;

      next;

    }
    if (/^(\S+):\s*(.*\S)\s*$/) {
      $first = lc($1);	
      $cfg{$first} = $2;
      $second = '';
      next;
    }
    die ( "\nLine $. in CFG file does not make sense\n" );
  }

  # append $ stuff to the very last tag in cfg file if necessary 
  if ($first && $second && $post{$first} && ($second !~ /^[\$^_]$/)) {
    if ($defaulted{$first}{$second}) {
      $rcfg{$first}{$second} = $post{$first};
      delete $defaulted{$first}{$second};
    } else {
      $rcfg{$first}{$second} .= " $post{$first}"
    }
  }
  
  #check the last input line
  if ($first && exists $deflt{$first} && ($second eq '_')) {
    &quickcheck($first,$second,$deflt{$first},$.)
  } elsif ($first && $second) {
    &quickcheck($first,$second,$rcfg{$first}{$second},$.)
  } elsif ($first) {
    &quickcheck($first,0,$cfg{$first},$.)
  }

  close (CFG);
  (\@routers, \%cfg, \%rcfg, $cfgfile);
}

sub cfgcheck {
  my ($routers, $cfg, $rcfg) = @_;
  my ($rou, $confname, $one_option);
  my %target;
  my $error="no";
  my(@known_options) = qw(growright bits noinfo absolute gauge nopercent integer perhour perminute transparent dorelpercent unknaszero transparent);
  if (! $$cfg{workdir}) {
      warn ("\nERROR: \"WorkDir\" not specified\n");
      $error = "yes";
  }
  $SNMP_util::CacheFile = "$$cfg{'workdir'}${main::SL}oid-mib-cache.txt";
  
  if (defined $$cfg{loadmibs}) {
    my($mibFile);
    foreach $mibFile (split /[,\s]+/, $$cfg{loadmibs}) {
      &snmpQueue_MIB_File($mibFile);
    }
  }

  foreach $rou (@$routers) {
    # and now for the testing
    if (! $$rcfg{"title"}{$rou}) {
      warn ("\nERROR: \"Title[$rou]\" not specified\n");
      $error = "yes";
    }
	if ($$rcfg{'directory'}{$rou})
	{
		# They specified a directory for this router.  Append the
		# pathname seperator to it (so that it can either be present or
		# absent, and the rules for including it are the same).
		$$rcfg{'directory'}{$rou} .= ${main::SL};
		# remove any stray spaces ...
		$$rcfg{'directory'}{$rou} =~ s/\s//g;
	}
    if (! $$rcfg{"pagetop"}{$rou}) {
      warn ("\nERROR: \"PageTop[$rou]\" is not specified.\n");
      $error = "yes";
    } else {
      # allow for linebreaks
      $$rcfg{"pagetop"}{$rou} =~ s/\\n/\n/g;
    }
  if (exists $$rcfg{"pagefoot"}{$rou}) {
    # allow for linebreaks
    $$rcfg{"pagefoot"}{$rou} =~ s/\\n/\n/g;
  }
 
    $$rcfg{"maxbytes1"}{$rou} = $$rcfg{"maxbytes"}{$rou} unless $$rcfg{"maxbytes1"}{$rou};
    $$rcfg{"maxbytes2"}{$rou} = $$rcfg{"maxbytes"}{$rou} unless $$rcfg{"maxbytes2"}{$rou};

    if ($$rcfg{"maxbytes1"}{$rou} eq '') {
      warn ("\nERROR: \"MaxBytes1[$rou]\" not specified\n");
      $error = "yes";
    }
    if ($$rcfg{"maxbytes2"}{$rou} eq '') {
      warn ("\nERROR: \"MaxBytes2[$rou]\" not specified\n");
      $error = "yes";
    }

    # set default size 
    if (! exists $$rcfg{"xsize"}{$rou}) {
      $$rcfg{"xsize"}{$rou}=400;
    } 
    if (! exists $$rcfg{"ysize"}{$rou}) {
      $$rcfg{"ysize"}{$rou}=100;
    }
    if (! exists $$rcfg{"ytics"}{$rou}) {
      $$rcfg{"ytics"}{$rou}=4;
    }
    if (! exists $$rcfg{"yticsfactor"}{$rou}) {
      $$rcfg{"yticsfactor"}{$rou}=1;
    }
    
    my $opttemp = lc($$rcfg{"options"}{$rou});
    if (exists $$rcfg{"options"}{$rou}) {      
      my $opttemp = lc($$rcfg{"options"}{$rou});      	
      delete $$rcfg{"options"}{$rou};
      foreach $one_option (split /[,\s]+/, $opttemp) {
	if (grep {$one_option eq $_} @known_options) {
	  $$rcfg{'options'}{$one_option}{$rou} = 1;
	} else {
	  warn ("\nERROR: Option[$rou]: \"$one_option\" is unknown\n");
	  $error="yes";
	}
      }
    }
    #
    # Check out routeruptime definition
    #    
    if ($$rcfg{"routeruptime"}{$rou}) {
      ($$rcfg{"community"}{$rou},$$rcfg{"router"}{$rou}) =
        split(/@/,$$rcfg{"routeruptime"}{$rou});
    }
    #
    # Check out target definition
    #    
    if ($$rcfg{"target"}{$rou}) {
      print "TARGSTART: '".$$rcfg{"target"}{$rou}."'\n" if $main::DEBUG > 1;
	    
      my ($pr) = "\$\$target\{'";
      my ($po) = "'\}\{\$mode\}";
      $$rcfg{targorig}{$rou} = $$rcfg{target}{$rou};
      $$rcfg{target}{$rou}  =~ s/,/ \+ /g;
      
      while ($$rcfg{target}{$rou}  =~ 
            s/(-?)([a-z0-9\.&\/]+):([^\s]+)\@([-a-z0-9_\.]+(:[0-9.]*)*)(?=[\s\+\/\*]|$)/$pr$&$po/i)
	{
	my $targ=$&;       
	my($oid1, $oid2) = ("","");
	my $index = undef;
	print "TARGNEW:   '".$$rcfg{"target"}{$rou}."'\n" if $main::DEBUG > 1;
	print "TARGMATCH: '".$targ."'\n" if $main::DEBUG > 1;
	$$rcfg{targtest}{$rou} .= "($pr$&$po == -1) || ";
	$$rcfg{targcount}{$rou}++;
	# my($host) = $4;
	$target{$targ}{'ioswap'} = $1;
	my($port) = $2;
	$target{$targ}{'community'} = $3;
	$target{$targ}{'router'} = $4;

	if ($port =~ /^\d+$/) {   # By default get the input/output octets
	  $oid1 = "ifInOctets.$port";
	  $oid2 = "ifOutOctets.$port";
	} else {
	    ($oid1, $oid2) = split(/\&/, $port,2) if ($port =~ /\&/);
	}

	printf " oid1: %s oid2: %s\n",$oid1,$oid2 if $main::DEBUG > 1;

	if ($oid1 =~ /(^.+)\/(.+$)/) {
	   if (!$target{$targ}{'ifindex'}{$2}) {
printf "Requesting: oid: %s\n","ipAdEntIfIndex.$2" if $main::DEBUG > 1;
	  	($target{$targ}{'ifindex'}{$2}) =
		&snmpget($target{$targ}{'community'}."@".$target{$targ}{'router'},
	     		"ipAdEntIfIndex.$2");
printf "Response: oid: %s\n","ipAdEntIfIndex.$target{$targ}{'ifindex'}{$2}" if $main::DEBUG > 1;
	   }
	   $oid1 = "$1.$target{$targ}{'ifindex'}{$2}";
	}

	if ($oid2 =~ /(^.+)\/(.+$)/) {
	   if (!$target{$targ}{'ifindex'}{$2}) {
printf "Requesting: oid: %s\n","ipAdEntIfIndex.$2" if $main::DEBUG > 1;
	  	($target{$targ}{'ifindex'}{$2}) =
		&snmpget($target{$targ}{'community'}."@".$target{$targ}{'router'},
	     		"ipAdEntIfIndex.$2");
printf "Response: oid: %s\n","ipAdEntIfIndex.$target{$targ}{'ifindex'}{$2}" if $main::DEBUG > 1;
	   }
	   $oid2 = "$1.$target{$targ}{'ifindex'}{$2}";
	}
	
     	if (!$oid1 && !$oid2 && $port) {
	   $port =~ s/\///;
	   if (!$target{$targ}{'ifindex'}{$port}) {
printf "Requesting: oid: %s\n","ipAdEntIfIndex.$port" if $main::DEBUG > 1;
	  	($target{$targ}{'ifindex'}{$port}) =
		&snmpget($target{$targ}{'community'}."@".$target{$targ}{'router'},
	     		"ipAdEntIfIndex.$port");
printf "Response: oid: %s\n","ipAdEntIfIndex.$target{$targ}{'ifindex'}{$port}" if $main::DEBUG > 1;
	   }
	   $oid1 = "ifInOctets.$target{$targ}{'ifindex'}{$port}";
           $oid2 = "ifOutOctets.$target{$targ}{'ifindex'}{$port}";
	}
	printf "Result oid1: %s oid2: %s\n",$oid1,$oid2 if $main::DEBUG > 1;

	  if (!$oid1 || !$oid2) {
	    warn ("\nERROR: If specifying the full OID, you must specify\n".
		  "2 full OID's separated by '&'. Error found with\n".
		  "\"$&\" in \"Target[$rou]\"\n");
	    $error = "yes";
	  }
	  $target{$targ}{'oid1'} = $oid1;
	  $target{$targ}{'oid2'} = $oid2;
      }
      
      while ($$rcfg{"target"}{$rou} =~ /\`([^\`]+)\`(?=[\s\+\/\*]|$)/) {
	my $cmd = $1;
	my $targ = my $tq = $&;
	$tq =~ s/['\\]/\\$&/g;
	$$rcfg{"target"}{$rou} =~ s/\`([^\`]+)\`(?=[\s\+\/\*]|$)/$pr$tq$po/;
	$$rcfg{targtest}{$rou} .= "($pr$tq$po == -1) || ";
	$$rcfg{targcount}{$rou}++;

	print "TARGSUBST:".$$rcfg{"target"}{$rou}."\n" if $main::DEBUG > 1;;
	$target{$targ}{'command'} = $cmd;
      }
    } else {
      warn ("\nERROR: I can't find a \"target[$rou]\" definition\n");
      $error = "yes";
    }
    
    # colors format: name#hexcol,
    if ($$rcfg{"colours"}{$rou}) {
#warn ("\nINFO: \"colours\[$rou\]\" \n$$rcfg{'colours'}{$rou} \n");
     if ($$rcfg{'options'}{'dorelpercent'}{$rou}) {
      if ($$rcfg{"colours"}{$rou} =~  
	  /^([^\#]+)(\#[0-9a-f]{6})\s*,\s*
		([^\#]+)(\#[0-9a-f]{6})\s*,\s*
		([^\#]+)(\#[0-9a-f]{6})\s*,\s*
		([^\#]+)(\#[0-9a-f]{6})\s*,\s*
		([^\#]+)(\#[0-9a-f]{6})/ix) {
	($$rcfg{'col1'}{$rou}, $$rcfg{'rgb1'}{$rou},
	 $$rcfg{'col2'}{$rou}, $$rcfg{'rgb2'}{$rou},
	 $$rcfg{'col3'}{$rou}, $$rcfg{'rgb3'}{$rou},
	 $$rcfg{'col4'}{$rou}, $$rcfg{'rgb4'}{$rou},
	 $$rcfg{'col5'}{$rou}, $$rcfg{'rgb5'}{$rou}) = 
	   ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
#	warn ("\nINFO:\n\
#	 $$rcfg{'col1'}{$rou}, $$rcfg{'rgb1'}{$rou},\n\
#	 $$rcfg{'col2'}{$rou}, $$rcfg{'rgb2'}{$rou},\n\
#	 $$rcfg{'col3'}{$rou}, $$rcfg{'rgb3'}{$rou},\n\
#	 $$rcfg{'col4'}{$rou}, $$rcfg{'rgb4'}{$rou},\n\
#	 $$rcfg{'col5'}{$rou}, $$rcfg{'rgb5'}{$rou}");

      } else {
	warn ("\nERROR: \"colours[$rou]\" for colour definition\n".
	      "       use the format: Name#hexcolour, Name#Hexcolour,...\n",
	      "       note, that dorelpercent requires 5 colours");
	$error="yes";
      }
     } else {            
#warn ("\nINFO: NO \"colours\[$rou\]\"\n$$rcfg{'colours'}{$rou}\n");
      if ($$rcfg{"colours"}{$rou} =~  
	  /^([^\#]+)(\#[0-9a-f]{6})\s*,\s*
		([^\#]+)(\#[0-9a-f]{6})\s*,\s*
		([^\#]+)(\#[0-9a-f]{6})\s*,\s*
		([^\#]+)(\#[0-9a-f]{6})/ix) {
	($$rcfg{'col1'}{$rou}, $$rcfg{'rgb1'}{$rou},
	 $$rcfg{'col2'}{$rou}, $$rcfg{'rgb2'}{$rou},
	 $$rcfg{'col3'}{$rou}, $$rcfg{'rgb3'}{$rou},
	 $$rcfg{'col4'}{$rou}, $$rcfg{'rgb4'}{$rou}) =
	   ($1, $2, $3, $4, $5, $6, $7, $8);
#	warn ("\nINFO:\n\
#	 $$rcfg{'col1'}{$rou}, $$rcfg{'rgb1'}{$rou},\n\
#	 $$rcfg{'col2'}{$rou}, $$rcfg{'rgb2'}{$rou},\n\
#	 $$rcfg{'col3'}{$rou}, $$rcfg{'rgb3'}{$rou},\n\
#	 $$rcfg{'col4'}{$rou}, $$rcfg{'rgb4'}{$rou}");
      } else {
	warn ("\nERROR: \"colours[$rou]\" for colour definition\n".
	      "       use the format: Name#hexcolour, Name#Hexcolour,...\n");
	$error="yes";
      }
     }
    } else {            
     if ($$rcfg{'options'}{'dorelpercent'}{$rou}) {
      ($$rcfg{'col1'}{$rou}, $$rcfg{'rgb1'}{$rou},
       $$rcfg{'col2'}{$rou}, $$rcfg{'rgb2'}{$rou},
       $$rcfg{'col3'}{$rou}, $$rcfg{'rgb3'}{$rou},
       $$rcfg{'col4'}{$rou}, $$rcfg{'rgb4'}{$rou},
       $$rcfg{'col5'}{$rou}, $$rcfg{'rgb5'}{$rou}) = 
	 ("GREEN","#00cc00",
	  "BLUE","#0000ff",
	  "DARK GREEN","#006600",
	  "MAGENTA","#ff00ff",
	  "AMBER","#ef9f4f");
     } else {            
      ($$rcfg{'col1'}{$rou}, $$rcfg{'rgb1'}{$rou},
       $$rcfg{'col2'}{$rou}, $$rcfg{'rgb2'}{$rou},
       $$rcfg{'col3'}{$rou}, $$rcfg{'rgb3'}{$rou},
       $$rcfg{'col4'}{$rou}, $$rcfg{'rgb4'}{$rou}) =
	 ("GREEN","#00cc00",
	  "BLUE","#0000ff",
	  "DARK GREEN","#006600",
	  "MAGENTA","#ff00ff");
     }
    }

    # Background color, format: #rrggbb
    if ($$rcfg{'background'}{$rou}) {
      if ($$rcfg{'background'}{$rou} =~ /^(\#[0-9a-f]{6})/i) {
	$$rcfg{'backgc'}{$rou} = "BGCOLOR=\"$1\"";
      } else {
	warn ("\nERROR: \"background[$rou]: ".
	      "$$rcfg{'background'}{$rou}\" for colour definition\n".
	      "       use the format: #rrggbb\n");
	$error="yes";
      }
    } else {
      $$rcfg{'backgc'}{$rou} = "BGCOLOR=\"#ffffff\"";
    }
    
    if (! $$rcfg{'kilo'}{$rou}) { $$rcfg{'kilo'}{$rou} = 1000 }
    if ($$rcfg{'kmg'}{$rou}) { $$rcfg{'kmg'}{$rou} =~ s/\s+//g; }

    if (! $$rcfg{'xzoom'}{$rou}) { $$rcfg{'xzoom'}{$rou} = 1.0 }
    if (! $$rcfg{'yzoom'}{$rou}) { $$rcfg{'yzoom'}{$rou} = 1.0 }
    if (! $$rcfg{'xscale'}{$rou}) { $$rcfg{'xscale'}{$rou} = 1.0 }
    if (! $$rcfg{'yscale'}{$rou}) { $$rcfg{'yscale'}{$rou} = 1.0 }
    
    if ($error eq "yes") {
      die ("\n\nABORT: Please fix the error(s) in your config file\n\n");
    }
  }
  \%target;
}



	
sub getcurrent {
  my ($target, $rou, $rcfg) = @_;

  if ($main::DEBUG > 1) {
    print "getcurrent: dumping rcfg keys\n";
    my $key;
    foreach $key (keys %$rcfg) {
      print "getcurrent: rcfg $key $$rcfg{$key}\n";
    }
  }
  
  
  my $inlast=0;
  my $outlast=0;
  my $uptime;
  my $name;
  my $strg;
  my $time;
  my $count=0;


  print "getcurrent: rcfg target router $rou = $$rcfg{'target'}{$rou}\n"
    if $main::DEBUG;

  my $mode='in';
	
 if ( eval("(" . $$rcfg{targtest}{$rou}."0 )")) {
    $inlast = -1;
  } else {
  # we must get a plain value
    $inlast = sprintf("%.0f",eval($$rcfg{target}{$rou}));
    die "* Problem with '$$rcfg{targorig}{$rou}':\n  $@\n" if $@;
  }

  $mode='out';
  if ( eval("(" . $$rcfg{targtest}{$rou}."0 )")) {
    $outlast = -1;
  } else {
    $outlast = sprintf("%.0f",eval($$rcfg{target}{$rou}));
    die "* Problem with '$$rcfg{targorig}{$rou}':\n  $@\n" if $@;
  }

  if ($$rcfg{targcount}{$rou} == 1) {
    $uptime = $$target{$$rcfg{targorig}{$rou}}{'uptime'};
    $name = $$target{$$rcfg{targorig}{$rou}}{'name'};
    $time = $$target{$$rcfg{targorig}{$rou}}{'time'};
  }
  #make sure we have a time set ...
  $time = time unless defined $time;

  if ($$rcfg{routeruptime}{$rou} ne '') {
    ($uptime,$name) = &snmpget(
	$$rcfg{"community"}{$rou}."@".$$rcfg{"router"}{$rou},
	     'sysUptime',
	     'sysName');
  }

  ($inlast, $outlast, $uptime, $name, $time);
}


sub writegraphics {
  my($router, $cfg, $rcfg, $inlast, $outlast, $time) = @_;
  
  my($absmax,$maxv, $maxvi, $maxvo, $i, $period, $res);
  my(@exec, @mxvls, @metas);
  my(%maxin, %maxout, %maxpercent, %avin, %avout, %avpercent, %cuin, %cuout, %cupercent);

  @metas = ();
  $maxvi = $$rcfg{'maxbytes1'}{$router};
  $maxvo = $$rcfg{'maxbytes2'}{$router};
  if ($maxvi > $maxvo) {
    $maxv = $maxvi;
  } else {
    $maxv = $maxvo;
  }
  $absmax = $$rcfg{'absmax'}{$router};
  $absmax = $maxv unless $absmax;

  
  print "writegraphics: inlast $inlast outlast $outlast\n" if $main::DEBUG;

  # select whether the datasource gives relative or absolte return values.
  my $up_abs="u";
  $up_abs='a' if $$rcfg{'options'}{'absolute'}{$router};
  $up_abs='g' if $$rcfg{'options'}{'gauge'}{$router};
  $up_abs='h' if $$rcfg{'options'}{'perhour'}{$router};
  $up_abs='m' if $$rcfg{'options'}{'perminute'}{$router};

  if ($$cfg{userrdtool}) {
    # protect us from early evaluation 
    my %dstype = qw/u COUNTER a ABSOLUTE g GAUGE h COUNTER m COUNTER/;
    $up_abs = $dstype{$up_abs};
    # update the database.
    my $rrd = "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${main::SL}$router.rrd";
    if (! -e $rrd) {
    	  # create the rrd if it doesn't exist
    	  my $now = time;
    	  $now = ($now / 300) * 300;
    	  RRDs::create($rrd, '-b', $now, '-s', 300,
    		  "DS:ds0:$up_abs:600:U:U",
    		  "DS:ds1:$up_abs:600:U:U",
    		  "RRA:AVERAGE:0.5:1:600",
    		  "RRA:AVERAGE:0.5:6:600",
    		  "RRA:AVERAGE:0.5:24:600",
    		  "RRA:AVERAGE:0.5:288:732",
    		  "RRA:MAX:0.5:1:600",
    		  "RRA:MAX:0.5:6:600",
    		  "RRA:MAX:0.5:24:600",
    		  "RRA:MAX:0.5:288:732");
    	  my $e = $RRDs::error;
    	  die "Cannot create logfile: $e\n" if $e;
    }
    # update the rrd
    RRDs::update("$rrd", "$time:$inlast:$outlast");
    my $e = $RRDs::error;
    die "Cannot update logfile: $e" if ($e);

    # the html pages and the graphics are created at "call time" so that's it!
    # (the returned hashes are empty, it's just to minimize the changes to mrtg)
    if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
      return (\%maxin, \%maxout, \%maxpercent, \%avin, \%avout, \%avpercent, \%cuin, \%cuout, \%cupercent);
    }
    else {
      return (\%maxin, \%maxout, \%avin, \%avout, \%cuin, \%cuout);
    }
  } # if ($$cfg{userrdtool})
  
  ((($main::OS eq 'NT' || $main::OS eq 'OS2' ) && (-e "$main::binpath${main::SL}rateup.exe")) ||
    (-x "$main::binpath${main::SL}rateup")) || 
    die "Can't Execute '$main::binpath${main::SL}rateup'\n";
	
# 
if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
  @exec = ("$main::binpath${main::SL}rateup", 
	   "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}","$router", 
	   $time, $$rcfg{'options'}{'unknaszero'}{$router} ? '-z':'-Z',
           "$up_abs"."p", $inlast, $outlast, $absmax,
	   "C", $$rcfg{'rgb1'}{$router},$$rcfg{'rgb2'}{$router},
		$$rcfg{'rgb3'}{$router},$$rcfg{'rgb4'}{$router},
		$$rcfg{'rgb5'}{$router});
}
else { 
  @exec = ("$main::binpath${main::SL}rateup", 
	   "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}","$router", 
	   $time, $$rcfg{'options'}{'unknaszero'}{$router} ? '-z':'-Z',
           "$up_abs", $inlast, $outlast, $absmax,
	   "c", $$rcfg{'rgb1'}{$router},$$rcfg{'rgb2'}{$router},
		$$rcfg{'rgb3'}{$router},$$rcfg{'rgb4'}{$router});
}
  # VMS: I dont think this is really needed
  #  if ($main::OS eq 'VMS') {
  #    @exec = ("\$verify = \'f\$verify(0)\'\n",
  #	     "\$set default $main::binpath\n",
  #	     "\$rateup = \"\$$cfg{'workdir'}rateup\"\n",
  #	     "\$rateup $router", 
  #	     "u", $inlast, $outlast, $absmax) }

  push (@exec, '-t') if defined $$rcfg{'options'}{'transparent'}{$router};

  my $maxx = $$rcfg{'xsize'}{$router}; 
  my $maxy = $$rcfg{'ysize'}{$router};
  my $xscale = $$rcfg{'xscale'}{$router}; 
  my $yscale = $$rcfg{'yscale'}{$router}; 
  my $growright = 0+$$rcfg{'options'}{'growright'}{$router};
  my $bits = 0+$$rcfg{'options'}{'bits'}{$router};
  my $integer = 0+$$rcfg{'options'}{'integer'}{$router};
  my $step = 5*60; 
  my $rop;
  my $ytics = $$rcfg{'ytics'}{$router};
  my $yticsf= $$rcfg{'yticsfactor'}{$router};

  if ($$rcfg{'ylegend'}{$router}) {
	push (@exec, "l", "[$$rcfg{'ylegend'}{$router}]");
  }
  my $sign = ($$rcfg{'unscaled'}{$router} =~ /d/) ? 1 : -1;
  
  if ($$rcfg{'kilo'}{$router}) {
      push (@exec, "k", $$rcfg{'kilo'}{$router});
  }
  if ($$rcfg{'kmg'}{$router}) { 
      push (@exec, "K", $$rcfg{'kmg'}{$router});
  }
  if ($$rcfg{'weekformat'}{$router}){
      push (@exec, "W", $$rcfg{'weekformat'}{$router});
  }

  if ($$rcfg{'suppress'}{$router} !~/d/){
    # VMS: should work for both now
    push (@exec, "i", "${router}-day.gif", 
	  $sign*$maxvi, $sign*$maxvo, $maxx, $maxy, ,$xscale, $yscale, $growright, $step, $bits, $ytics, $yticsf);
    @mxvls = ("d");
    push (@metas, "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${router}-day.gif", 
	  $$cfg{'interval'} ? $$cfg{'interval'} : 5);
  }
  
  if (((not -e "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${router}-week.gif") ||
       (-M "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${router}-week.gif" >= 0.5/24)) &&
      ($$rcfg{'suppress'}{$router} !~/w/)
     ) {
    $step=30*60;
    $sign = ($$rcfg{'unscaled'}{$router} =~ /w/) ? 1 : -1;
    push (@mxvls , "w");
    $rop =($$rcfg{'withpeak'}{$router} =~ /w/) ? "p" : "i"; 
    push (@exec, $rop ,"${router}-week.gif", 
	  $sign*$maxvi, $sign*$maxvo,  $maxx, $maxy, $xscale, $yscale, $growright, $step, $bits, $ytics, $yticsf);
    push (@metas, "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${router}-week.gif", 30);
  }
  
  if (((not -e "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${router}-month.gif") || 
       ( -M "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${router}-month.gif" >= 2/24))  &&
      ($$rcfg{'suppress'}{$router} !~/m/)) {
    $step=2*60*60;
    $sign = ($$rcfg{'unscaled'}{$router} =~ /m/) ? 1 : -1;
    push (@mxvls , "m");
    $rop =($$rcfg{'withpeak'}{$router} =~ /m/) ? "p" : "i"; 
    push (@exec, $rop ,"${router}-month.gif", 
	  $sign*$maxvi, $sign*$maxvo, $maxx, $maxy, $xscale, $yscale, $growright, $step, $bits, $ytics, $yticsf);
    push (@metas, "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${router}-month.gif", 120);
  }
  
  if (((not -e "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${router}-year.gif") || 
       ( -M "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${router}-year.gif" >= 1)) &&
      ($$rcfg{'suppress'}{$router} !~/y/)) {
    $step=24*60*60;
    $sign = ($$rcfg{'unscaled'}{$router} =~ /y/) ? 1 : -1;
    push (@mxvls , "y");
    $rop =($$rcfg{'withpeak'}{$router} =~ /y/) ? "p" : "i"; 
    push (@exec, $rop, "${router}-year.gif", 
	  $sign*$maxvi, $sign*$maxvo, $maxx, $maxy, $xscale, $yscale, $growright, $step, $bits, $ytics, $yticsf) ;
    push (@metas, "$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}${router}-year.gif", 1440);
  }    
  
  print "EXEC: ",(join " ", @exec),"\n" if $main::DEBUG;
  
  # VMS: this might work now ... or does VMS NOT know about pipes?
  # NT doesn't have fork() so an open(xxx,"-|") won't work
  
  if ($main::OS eq 'VMS' || $main::OS eq 'NT') {
    open (RATEUP, join (" ", @exec)."|");
  } else {
    open (RATEUP,"-|") ||  exec @exec;
  }
  
  # Original VMS Patch ... ends up with rateup output in a
  # array ... 
  #    open (COMMAND, ">mrtg-temp.com") ||
  #              die ("Can't open command file\n");
  #   print COMMAND "@exec";
  #   close COMMAND;
  #   @rateup = `\@mrtg-temp.com`
  
  if (open (HTML,"<$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}$router.html")) {
    for ($i=0 ; $i<40 ; $i++) {
      $_=<HTML>;
      if (/<!-- maxin ([dwmy]) (\d*)/) {
	$maxin{$1}{$router}=0+$2;
      };
      if (/<!-- maxout ([dwmy]) (\d*)/) {
	$maxout{$1}{$router}=0+$2;
      };
      if (/<!-- maxpercent ([dwmy]) (\d*)/) {
	$maxpercent{$1}{$router}=0+$2;
      };
      if (/<!-- avin ([dwmy]) (\d*)/) {
	$avin{$1}{$router}=0+$2;
      };
      if (/<!-- avout ([dwmy]) (\d*)/) {
	$avout{$1}{$router}=0+$2;
      };
      if (/<!-- avpercent ([dwmy]) (\d*)/) {
	$avpercent{$1}{$router}=0+$2;
      };
      if (/<!-- cuin ([dwmy]) (\d*)/) {
	$cuin{$1}{$router}=0+$2;
      };
      if (/<!-- cuout ([dwmy]) (\d+)/) {
	$cuout{$1}{$router}=0+$2;
      };
      if (/<!-- cupercent ([dwmy]) (\d+)/) {
	$cupercent{$1}{$router}=0+$2;
      };
    }
    close HTML;
  };
  
  
  foreach $period (@mxvls) {
    chomp($res = <RATEUP>); 
    print "$period: maxin \"$res\"\n" if $main::DEBUG >2;
    $maxin{$period}{$router}=sprintf("%.0f",0+$res);
    chomp($res = <RATEUP>); 
    print "$period: maxout \"$res\"\n" if $main::DEBUG >2;
    $maxout{$period}{$router}=sprintf("%.0f",0+$res);
    if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
       chomp($res = <RATEUP>); 
       print "$period: maxpercent \"$res\"\n" if $main::DEBUG >2;
       $maxpercent{$period}{$router}=sprintf("%.0f",0+$res);
    }
    chomp($res = <RATEUP>); 
    print "$period: avin \"$res\"\n" if $main::DEBUG >2;
    $avin{$period}{$router}=sprintf("%.0f",0+$res);
    chomp($res = <RATEUP>); 
    print "$period: avout \"$res\"\n" if $main::DEBUG >2;
    $avout{$period}{$router}=sprintf("%.0f",0+$res);
    if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
       chomp($res = <RATEUP>); 
       print "$period: avpercent \"$res\"\n" if $main::DEBUG >2;
       $avpercent{$period}{$router}=sprintf("%.0f",0+$res);
    }
    chomp($res = <RATEUP>); 
    print "$period: cuin \"$res\"\n" if $main::DEBUG >2;
    $cuin{$period}{$router}=sprintf("%.0f",0+$res);
    chomp($res = <RATEUP>); 
    print "$period: cuout \"$res\"\n" if $main::DEBUG >2;
    $cuout{$period}{$router}=sprintf("%.0f",0+$res);
    if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
       chomp($res = <RATEUP>); 
       print "$period: cupercent \"$res\"\n" if $main::DEBUG >2;
       $cupercent{$period}{$router}=sprintf("%.0f",0+$res);
    }
  }
  close(RATEUP);
  if ($?) {
      my $value = $?;
	my $signal =  $? & 127; #ignore the most significant bit 
				#as it is always one when it is a returning
				#child says dave ...
	if(($main::OS != 'UNIX') || ($signal != 127))
	{
	my $exitval = $? >> 8;
	warn "\nPROBLEM: rateup died from Signal $signal\n".
	" with Exit Value $exitval when doing router '$router'\n".
	" code was $value, retcode was $!.".
	" If this happens all the time,\n".
	" you should probably investigate the cause. :-)\n\n";
  }
    }
  if( $$cfg{'writeexpires'} =~ /^y/i ) {
    my($fil,$exp);
    while( $fil = shift(@metas) ) {
      $exp = &expistr(shift(@metas));
      open(META, ">$fil.meta");
      print META "Expires: $exp\n";
      close(META);
    }
  }

  if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
    (\%maxin, \%maxout, \%maxpercent, \%avin, \%avout, \%avpercent, \%cuin, \%cuout, \%cupercent);
  }
  else {
    (\%maxin, \%maxout, \%avin, \%avout, \%cuin, \%cuout);
  }
}

#format 10*$kilo to 10 kB/s
sub fmi {
  my($number, $maxbytes, $router, @foo) = @_;
  my($rcfg,$LOC)=@foo;
  my(@short,$mul);
  if ($$rcfg{'kmg'}{$router}) {
    my($i);
    if ($$rcfg{'options'}{'bits'}{$router} == 1) {
      @short = ();
      foreach $i (split(/,/, $$rcfg{'kmg'}{$router})) {
         if ($$rcfg{'options'}{'perminute'}{$router}) {
           $short[$#short+1] = "$i".&$LOC("b/min");
         } elsif ($$rcfg{'options'}{'perhour'}{$router}) {
           $short[$#short+1] = "$i".&$LOC("b/h");
         } else {
           $short[$#short+1] = "$i".&$LOC("b/s");
         }
      }
      $mul= 8;
    } else {
      @short = ();
      foreach $i (split(/,/, $$rcfg{'kmg'}{$router})) {
         if ($$rcfg{'options'}{'perminute'}{$router}) {
           $short[$#short+1] = "$i".&$LOC ("B/min");
         } elsif ($$rcfg{'options'}{'perhour'}{$router}) {
           $short[$#short+1] = "$i".&$LOC("B/h");
         } else {
           $short[$#short+1] = "$i".&$LOC("B/s");
         }
      }
      $mul= 1;
    }
    if ($$rcfg{'shortlegend'}{$router}) {
      @short = ();
      foreach $i (split(/,/, $$rcfg{'kmg'}{$router})) {
         $short[$#short+1] = "$i"."$$rcfg{'shortlegend'}{$router}";
      }
    }
  } else {
    if ($$rcfg{'options'}{'bits'}{$router} == 1) {
      if ($$rcfg{'options'}{'perminute'}{$router}) {
        @short = (&$LOC("b/min"),&$LOC("kb/min"),&$LOC("Mb/min"),&$LOC("Gb/min"));
      } elsif ($$rcfg{'options'}{'perhour'}{$router}) {
        @short = (&$LOC("b/h"),&$LOC("kb/h"),&$LOC("Mb/h"),&$LOC("Gb/h"));
      } else {
        @short = (&$LOC("b/s"),&$LOC("kb/s"),&$LOC("Mb/s"),&$LOC("Gb/s"));
      }
      $mul= 8;
    } else {
      if ($$rcfg{'options'}{'perminute'}{$router}) {
        @short = (&$LOC("B/min"),&$LOC("kB/min"),&$LOC("MB/min"),&$LOC("GB/min"));
      } elsif ($$rcfg{'options'}{'perhour'}{$router}) {
        @short = (&$LOC("B/h"),&$LOC("kB/h"),&$LOC("MB/h"),&$LOC("GB/h"));
      } else {
        @short = (&$LOC("B/s"),&$LOC("kB/s"),&$LOC("MB/s"),&$LOC("GB/s"));
      }
      $mul= 1;
    }
    if ($$rcfg{'shortlegend'}{$router}) {
	@short = ("$$rcfg{'shortlegend'}{$router}",
		  "k$$rcfg{'shortlegend'}{$router}",
		  "M$$rcfg{'shortlegend'}{$router}",
		  "G$$rcfg{'shortlegend'}{$router}");
    }
  }
  my $digits=length("".$number*$mul);
  my $divm=0;
#
#  while ($digits-$divm*3 > 4) { $divm++; }
#  my $divnum = $number*$mul/10**($divm*3);
  my $divnum=$number*$mul;
#  while ($divnum/$$rcfg{'kilo'}{$router} >= 10*$$rcfg{'kilo'}{$router} && $divnum<$#short) {
  while ($divnum >= 10*$$rcfg{'kilo'}{$router} && $divm<$#short) {
     $divm++;
     $divnum /= $$rcfg{'kilo'}{$router};
  }
  my $perc;
  if ($number == 0 || $maxbytes == 0) {
    $perc = 0;
  } else {
    $perc = 100/$maxbytes*$number;
  }
  if ($$rcfg{'options'}{'integer'}{$router} == 1) {
    if ($$rcfg{'options'}{'nopercent'}{$router}) {
      return sprintf("%0.f ",$number*$mul);
    } else {
      return sprintf("%0.f (%2.1f%%)",$number*$mul,$perc);
    }
  } else {
    if ($$rcfg{'options'}{'nopercent'}{$router}) {
      return sprintf("%1.1f %s",$divnum,$short[$divm]);  # Added: FvW
    } else {
      return sprintf("%1.1f %s (%2.1f%%)",$divnum,$short[$divm],$perc);
    }
   return sprintf("%1.1f %s (%2.1f%%)",$divnum,$short[$divm],$perc);
  }
}

sub datestr {
  my ($time) = shift(@_) || return 0;
  my ($wday) = ('Sunday','Monday','Tuesday','Wednesday',
		'Thursday','Friday','Saturday')[(localtime($time))[6]];
  my ($month) = ('January','February' ,'March' ,'April' ,
		 'May' , 'June' , 'July' , 'August' , 'September' , 
		 'October' ,
		 'November' , 'December' )[(localtime($time))[4]];
  my ($mday,$year,$hour,$min) = (localtime($time))[3,5,2,1];
  if ($min<10) {$min = "0$min";}
  return "$wday, $mday $month ".($year+1900)." at $hour:$min";
}

sub expistr {
  my ($time) = time+$_[0]*60+5;
  my ($wday) = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[(gmtime($time))[6]];
  my ($month) = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep', 
		 'Oct','Nov','Dec')[(gmtime($time))[4]];
  my ($mday,$year,$hour,$min,$sec) = (gmtime($time))[3,5,2,1,0];
  if ($mday<10) {$mday = "0$mday"};
  if ($hour<10) {$hour = "0$hour"};
  if ($min<10) {$min = "0$min";}
  if ($sec<10) {$sec = "0$sec";}
  return "$wday, $mday $month ".($year+1900)." $hour:$min:$sec GMT";
}

sub writehtml {
  my($router, $cfg, $rcfg, $maxin, $maxout, $maxpercent,
     $avin, $avout, $avpercent, $cuin, $cuout, $cupercent, $uptime, $name, $LOC) = @_;
  
  my($VERSION,$Today,$peri);
  
  my($persec);

  if ($$rcfg{'options'}{'bits'}{$router} == 1) {
     $persec = &$LOC("Bits");
  } else {
     $persec = &$LOC("Bytes");
  }

#  Work out the Colour legend
  my($leg1, $leg2, $leg3, $leg4, $leg5);
  if ($$rcfg{'legend1'}{$router}) {
	$leg1 = $$rcfg{'legend1'}{$router};
  } else {
	$leg1 = &$LOC("Incoming Traffic in $persec per Second");
  }
  if ($$rcfg{'legend2'}{$router}) {
	$leg2 = $$rcfg{'legend2'}{$router};
  } else {
	$leg2 = &$LOC("Outgoing Traffic in $persec per Second");
  }
  if ($$rcfg{'legend3'}{$router}) {
	$leg3 = $$rcfg{'legend3'}{$router};
  } else {
	$leg3 = &$LOC("Maximal 5 Minute Incoming Traffic");
  }
  if ($$rcfg{'legend4'}{$router}) {
	$leg4 = $$rcfg{'legend4'}{$router};
  } else {
	$leg4 = &$LOC("Maximal 5 Minute Outgoing Traffic");
  }
  if ($$rcfg{'legend5'}{$router}) {
	$leg5 = $$rcfg{'legend5'}{$router};
  } else {
	$leg5 = "(($leg1)/($leg2))*100";
  }
# Translate the color names
$$rcfg{'col1'}{$router}=&$LOC($$rcfg{'col1'}{$router});
$$rcfg{'col2'}{$router}=&$LOC($$rcfg{'col2'}{$router});
$$rcfg{'col3'}{$router}=&$LOC($$rcfg{'col3'}{$router});
$$rcfg{'col4'}{$router}=&$LOC($$rcfg{'col4'}{$router});
$$rcfg{'col5'}{$router}=&$LOC($$rcfg{'col5'}{$router});

  $Today=&$LOC(datestr(time));
  $VERSION = "2.8.8";
  open (HTML,">$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}$router.html") || 
    warn ("\nCan not write $router.html");
  print HTML '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">' . "\n";
  print HTML "<HTML>\n";
  my $interval =$$cfg{'interval'} ? $$cfg{'interval'} : 5;
  my $expiration = &expistr($interval);
  my $refresh =  $$cfg{'refresh'} ? $$cfg{'refresh'} : 300;
  my $namestring = &$LOC("the device");  
  print HTML <<"TEXT";    
<HEAD>
<TITLE>$$rcfg{'title'}{$router}</TITLE>
<META HTTP-EQUIV="Refresh" CONTENT="$refresh">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="$expiration">
TEXT

  print HTML 
'<META HTTP-EQUIV="Content-Type" CONTENT="text/html; '.&$LOC('charset=iso-8859-1')."\">\n";

  foreach $peri (qw(d w m y)) {
    print HTML <<"TEXT";
<!-- maxin $peri $$maxin{$peri}{$router} -->
<!-- maxout $peri $$maxout{$peri}{$router} -->
TEXT
if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
    print HTML <<"TEXT";
<!-- maxpercent $peri $$maxpercent{$peri}{$router} -->
TEXT
}
    print HTML <<"TEXT";
<!-- avin $peri $$avin{$peri}{$router} -->
<!-- avout $peri $$avout{$peri}{$router} -->
TEXT
if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
    print HTML <<"TEXT";
<!-- avpercent $peri $$avpercent{$peri}{$router} -->
TEXT
}
    print HTML <<"TEXT";
<!-- cuin $peri $$cuin{$peri}{$router} -->
<!-- cuout $peri $$cuout{$peri}{$router} -->
TEXT
if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
    print HTML <<"TEXT";
<!-- cupercent $peri $$cupercent{$peri}{$router} -->
TEXT
}
  }
  if ($name ne '') {$namestring = "<B>'$name'</B>"};
  # allow for \n in addhead
  $$rcfg{addhead}{$router} =~ s/\\n/\n/g;
print HTML <<"TEXT";    
$$rcfg{'addhead'}{$router}
</HEAD>
<BODY $$rcfg{'backgc'}{$router}>
$$rcfg{'pagetop'}{$router}<BR>
<HR>
TEXT
print HTML     
&$LOC("The statistics were last updated <B>$Today $$rcfg{'timezone'}{$router}</B>");


if ($uptime && ! $$rcfg{options}{noinfo}{$router}) {
print HTML
",<BR>
".&$LOC("at which time $namestring had been up for <B>$uptime</B>.")."
";
  }

  my %sample= ('d' => "`Daily' Graph (".$interval.' Minute',
	       'w' => "`Weekly' Graph (30 Minute",
	       'm' => "`Monthly' Graph (2 Hour",
	       'y' => "`Yearly' Graph (1 Day");
  
  my %full = ('d' => 'day',
	      'w' => 'week',
	      'm' => 'month',
	      'y' => 'year');
  
  my $InCo;
  if (exists $$rcfg{'legendi'}{$router}) {
    if ($$rcfg{'legendi'}{$router} ne "") {
      $InCo="<FONT COLOR=\"$$rcfg{'rgb1'}{$router}\">".
	"$$rcfg{'legendi'}{$router}</FONT>" }
  } else {
    $InCo="<FONT COLOR=\"$$rcfg{'rgb1'}{$router}\">".
      &$LOC("&nbsp;In:</FONT>") }
  my $OutCo;
  if (exists $$rcfg{'legendo'}{$router}) {
    if ($$rcfg{'legendo'}{$router} ne "") {
      $OutCo="<FONT COLOR=\"$$rcfg{'rgb2'}{$router}\">".
	"$$rcfg{'legendo'}{$router}</FONT>" }
  } else {
    $OutCo="<FONT COLOR=\"$$rcfg{'rgb2'}{$router}\">".
      &$LOC("&nbsp;Out:</FONT>") }
  my $PercentCo;
  if (exists $$rcfg{'legend5'}{$router}) {
    if ($$rcfg{'legend5'}{$router} ne "") {
      $PercentCo="<FONT COLOR=\"$$rcfg{'rgb5'}{$router}\">".
	"$$rcfg{'legend5'}{$router}</FONT>" }
  } else {
    $PercentCo="<FONT COLOR=\"$$rcfg{'rgb5'}{$router}\">".
      &$LOC("&nbsp;Percentage</FONT>") }
  
  foreach $peri (qw(d w m y)){
    next if $$rcfg{'suppress'}{$router} =~/$peri/;
    my $gifw;
    if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
       $gifw=sprintf("%.0f",($$rcfg{'xsize'}{$router}*$$rcfg{'xscale'}{$router}+
		+100+30) *$$rcfg{'xzoom'}{$router});
    }
    else {
      $gifw=sprintf("%.0f",($$rcfg{'xsize'}{$router}*$$rcfg{'xscale'}{$router}
		+100) *$$rcfg{'xzoom'}{$router});
    }
    my $gifh=sprintf("%.0f",($$rcfg{'ysize'}{$router}*$$rcfg{'yscale'}{$router}+35)
		 *$$rcfg{'yzoom'}{$router});
		 
  
    print HTML "
<HR>
".&$LOC("<B>$sample{$peri}").&$LOC(" Average)</B><BR>")."
<IMG VSPACE=10 WIDTH=$gifw HEIGHT=$gifh ALIGN=TOP 
     SRC=\"$router-$full{$peri}.gif\" ALT=\"$full{$peri}\">
 <TABLE CELLPADDING=0 CELLSPACING=0>
";
    my(@foo)=($rcfg,$LOC);
    print HTML "<TR>
  ".&$LOC("<TD ALIGN=right><SMALL>Max $InCo</SMALL></TD>")."
  <TD ALIGN=right><SMALL>".&fmi($$maxin{$peri}{$router}, $$rcfg{'maxbytes1'}{$router}, $router, @foo)."
   </SMALL></TD>
  <TD WIDTH=5></TD>
  ".&$LOC("<TD ALIGN=right><SMALL>Average $InCo</SMALL></TD>")."
  <TD ALIGN=right><SMALL>".&fmi($$avin{$peri}{$router}, $$rcfg{'maxbytes1'}{$router}, $router, @foo)."
  </SMALL></TD>
  <TD WIDTH=5></TD>
  ".&$LOC("<TD ALIGN=right><SMALL>Current $InCo</SMALL></TD>")."
  <TD ALIGN=right><SMALL>".&fmi($$cuin{$peri}{$router}, $$rcfg{'maxbytes1'}{$router}, $router, @foo)."
  </SMALL></TD>
 </TR>
" if $InCo;
print HTML "
 <TR>
  ".&$LOC("<TD ALIGN=right><SMALL>Max $OutCo</SMALL></TD>")."
  <TD ALIGN=right><SMALL>".&fmi($$maxout{$peri}{$router}, $$rcfg{'maxbytes2'}{$router}, $router, @foo)."
  </SMALL></TD>
  <TD WIDTH=5></TD>
  ".&$LOC("<TD ALIGN=right><SMALL>Average $OutCo</SMALL></TD>")."
  <TD ALIGN=right><SMALL>".&fmi($$avout{$peri}{$router}, $$rcfg{'maxbytes2'}{$router}, $router, @foo)."
  </SMALL></TD>
  <TD WIDTH=5></TD>
  ".&$LOC("<TD ALIGN=right><SMALL>Current $OutCo</SMALL></TD>")."
  <TD ALIGN=right><SMALL>".&fmi($$cuout{$peri}{$router}, $$rcfg{'maxbytes2'}{$router}, $router, @foo)."
 </SMALL></TD>
 </TR> " if $OutCo;
print HTML "
 <TR>
  ".&$LOC("<TD ALIGN=right><SMALL>Max $PercentCo</SMALL></TD>")."
  <TD ALIGN=right><SMALL>".sprintf("%0.1f %%",$$maxpercent{$peri}{$router})."
  </SMALL></TD>
  <TD WIDTH=5></TD>
  ".&$LOC("<TD ALIGN=right><SMALL>Average $PercentCo</SMALL></TD>")."
  <TD ALIGN=right><SMALL>".sprintf("%0.1f %%",$$avpercent{$peri}{$router})."
  </SMALL></TD>
  <TD WIDTH=5></TD>
  ".&$LOC("<TD ALIGN=right><SMALL>Current $PercentCo</SMALL></TD>")."
  <TD ALIGN=right><SMALL>".sprintf("%0.1f %%",$$cupercent{$peri}{$router})."
 </SMALL></TD>
 </TR> " if ($$rcfg{'options'}{'dorelpercent'}{$router} && $PercentCo);
    print HTML "
</TABLE>\n";
  }
  print HTML "
  <HR><BR>
  <TABLE WIDTH=500 BORDER=0 CELLPADDING=4 CELLSPACING=0>";
  print HTML "
   <TR><TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=\"$$rcfg{'rgb1'}{$router}\">
      <B>$$rcfg{'col1'}{$router} ###</B></FONT></TD>
      <TD><FONT SIZE=-1>$leg1</FONT></TD></TR> " if $InCo;
  print HTML "
   <TR><TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=\"$$rcfg{'rgb2'}{$router}\">
      <B>$$rcfg{'col2'}{$router} ###</B></FONT></TD>
      <TD><FONT SIZE=-1>$leg2</FONT></TD></TR> " if $OutCo;
  
  if ($$rcfg{'withpeak'}{$router}) {
    print HTML "
   <TR><TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=\"$$rcfg{'rgb3'}{$router}\">
			<B>$$rcfg{'col3'}{$router}###</B></FONT></TD>
       <TD><FONT SIZE=-1>$leg3</FONT></TD></TR> " if $InCo;
  print HTML "
   <TR><TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=\"$$rcfg{'rgb4'}{$router}\">
			<B>$$rcfg{'col4'}{$router}###</B></FONT></TD>
       <TD><FONT SIZE=-1>$leg4</FONT></TD></TR> "if $OutCo;
     }

  if ($$rcfg{'options'}{'dorelpercent'}{$router}) {
    print HTML "
   <TR><TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=\"$$rcfg{'rgb5'}{$router}\">
			<B>$$rcfg{'col5'}{$router}###</B></FONT></TD>
       <TD><FONT SIZE=-1>$leg5</FONT></TD></TR> ";
     }

#	warn ("\nINFO: \$router = $router\n\
#	 $$rcfg{'col1'}{$router}, $$rcfg{'rgb1'}{$router},\n\
#	 $$rcfg{'col2'}{$router}, $$rcfg{'rgb2'}{$router},\n\
#	 $$rcfg{'col3'}{$router}, $$rcfg{'rgb3'}{$router},\n\
#	 $$rcfg{'col4'}{$router}, $$rcfg{'rgb4'}{$router},\n\
#	 $$rcfg{'col5'}{$router}, $$rcfg{'rgb5'}{$router}");

  # If they're using the "directory" option, we have to adjust the
  # path to the gifs.
  my $gifPath = "../" x ($$rcfg{'directory'}{$router} =~ tr|/|/|);
  if (defined $$cfg{icondir}) {
	$gifPath = $$cfg{icondir};
	#lets make sure there is a trailing path separator
        $gifPath =~ s|/*$|/|; 
  }

  print HTML<<TEXT;
</TABLE><BR><HR><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0>
  <TR>
    <TD WIDTH=63><A
    HREF="http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html"><IMG
    BORDER=0 SRC="${gifPath}mrtg-l.gif" WIDTH=63 HEIGHT=25 ALT="MRTG"></A></TD>
    <TD WIDTH=25><A
    HREF="http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html"><IMG
    BORDER=0 SRC="${gifPath}mrtg-m.gif" WIDTH=25 HEIGHT=25 ALT=""></A></TD>
    <TD WIDTH=388><A
    HREF="http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html"><IMG
    BORDER=0 SRC="${gifPath}mrtg-r.gif" WIDTH=388 HEIGHT=25
    ALT="Multi Router Traffic Grapher"></A></TD>
  </TR>
</TABLE>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0>
  <TR VALIGN=top>
  <TD WIDTH=88 ALIGN=RIGHT><FONT FACE="Arial,Helvetica" SIZE=2>
TEXT

print HTML &$LOC("version")." $VERSION</FONT></TD>\n";
  print HTML<<TEXT;
  <TD WIDTH=388 ALIGN=RIGHT><FONT FACE="Arial,Helvetica" SIZE=2>
  <A HREF="http://ee-staff.ethz.ch/~oetiker/">Tobias Oetiker</A>
  <A HREF="mailto:oetiker\@ee.ethz.ch">&lt;oetiker\@ee.ethz.ch&gt;</A> 
TEXT
  print HTML &$LOC("and");
  print HTML<<TEXT;
  &nbsp;
  <A HREF="http://www.bungi.com/">Dave&nbsp;Rand</A>&nbsp;
  <A HREF="mailto:dlr\@bungi.com">&lt;dlr\@bungi.com&gt;</A></FONT>
  </TD>
</TR>
</TABLE>
TEXT

  # We don't need this any more.
  undef $gifPath;

  if ($main::OS eq 'VMS') {
    print HTML 
" <HR NOSHADE>
".&$LOC("Ported to OpenVMS Alpha by").".
  <NOBR><A HREF=\"http://www.cerberus.ch/\">Werner Berger</A>
  <A href=\"mailto:werner.berger\@cch.cerberus.ch\">
  &lt;werner.berger\@cch.cerberus.ch&gt;</A></NOBR>
";

  }
  if ($main::OS eq 'NT') {
    print HTML 
"  <HR NOSHADE>
  ".&$LOC("Ported to WindowsNT by")."
  <NOBR><A HREF=\"http://www.testlab.orst.edu/\">Stuart Schneider</A>
  <A HREF=\"mailto:schneis\@testlab.orst.edu\">
  &lt;schneis\@testlab.orst.edu&gt;</A></NOBR>
";
  }
  if ($main::OS eq 'OS2') {
    print HTML 
" <HR NOSHADE>
".&$LOC("Ported to OS/2 by").".
  <NOBR><A HREF=\"http://www.ee.tku.edu.tw/~rexchen/\">Rex Chen</A>
  <A href=\"mailto:rexchen\@ug.ee.tku.edu.tw\">
  &lt;rexchen\@ug.ee.tku.edu.tw&gt;</A></NOBR>
";

  }
  if( 
     $$cfg{'language'} && 
     defined($lang2tran::LOCALE{"\L$$cfg{'language'}\E"}) &&
     ($LOC != $lang2tran::LOCALE{"default"})
    )
  {
    if(defined($credits::LOCALE{"\L$$cfg{'language'}\E"}))
      {
	print HTML $credits::LOCALE{"\L$$cfg{'language'}\E"};
      }
    else
      {
	print HTML $credits::LOCALE{'default'};
      };
  }

  print HTML $$rcfg{'pagefoot'}{$router} if defined $$rcfg{'pagefoot'}{$router};
  print HTML <<TEXT;
</BODY>
</HTML>
TEXT
  close HTML;

  if ($$cfg{'writeexpires'} =~ /^y/i)
  {
    open(HTMLG, ">$$cfg{'workdir'}${main::SL}$$rcfg{'directory'}{$router}$router.html.meta");
    print HTMLG "Expires: $expiration\n";
    close(HTMLG);
  }
}

sub printusage {
    print <<USAGEDESC;
Usage: mrtg <config-file>

mrtg: Multi Router Traffic Grapher.

If you want to know more about this tool, you might want
to read the docs. They came together with mrtg! 

Home: http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html

USAGEDESC
    exit(1);
}


sub readtargets {
  my ($target, $cfg, $rcfg, $cfgfile) = @_;
  
  my($in,$out,$uptime,$name,$targ,$now,$i,$okfile,$cfgorig);

  # get a list of known ifDescrs, in order to cross check the
  # the values returned by querying the various targets ...

  my(%oldifDescrs,%newifDescrs);
  # remove any trailing . something from the cfg file name.
  $cfgorig=$cfgfile;
  $cfgfile =~ s/\.[^\.\/]+$//g;  
  if(open (CFGOK,"<$cfgfile.ok")) {
    print STDERR "Reading ifDescs from $cfgfile.ok ...\n" if $main::DEBUG;
    while (<CFGOK>) {
      chomp;
       my($targ,$desc) = split (' = ', $_, 2);
      # ignore empty ifDescs ...
      $oldifDescrs{$targ}=$desc if $desc;
    }
    close CFGOK;
  } else {
    print STDERR "Could not read ifDescs from $cfgfile.ok ...\n" if $main::DEBUG;
  }

  open SR, ">>$$cfg{'workdir'}${main::SL}mrtg.dbg" if $main::SNMPDEBUG;
  print SR time," -- ", (join " | ", keys %$target), "\n" if $main::SNMPDEBUG;
  foreach $targ (sort keys %$target) {
    print "getting SNMP variables for target: $targ\n" 
      if $main::DEBUG;
    if (exists $$target{$targ}{'command'}) {
      print "external snmpget: executing $$target{$targ}{'command'}\n" 
	if $main::DEBUG;

      open (EXTERNAL , $$target{$targ}{'command'}."|")
	|| warn "Can't fork to start \'".$$target{$targ}{'command'}."\': $!\n";
     
      warn "Could not get any data from external command ".
	  "'".$$target{$targ}{'command'}.
	    "'\nMaybe the external command did not even start. ($!)\n\n" if eof EXTERNAL;
      
      chomp( $$target{$targ}{'in'}=<EXTERNAL>) unless eof EXTERNAL;
      chomp( $$target{$targ}{'out'}=<EXTERNAL>) unless eof EXTERNAL;
      chomp( $$target{$targ}{'uptime'}=<EXTERNAL>) unless eof EXTERNAL;
      chomp( $$target{$targ}{'name'}=<EXTERNAL>) unless eof EXTERNAL;

      close EXTERNAL;
      print "External Command returned: in '$$target{$targ}{'in'}'\n".
      "                          out '$$target{$targ}{'out'}'\n".
      "                       uptime '$$target{$targ}{'uptime'}'\n".
      "                         name '$$target{$targ}{'name'}'\n" if $main::DEBUG >2;
	
      # if there is no data set it to -1 so that the graph is 
      # not generated
      if (! exists $$target{$targ}{'in'}) {
	$$target{$targ}{'in'}=-1;
	$$target{$targ}{'out'}=-1;
      } else {

        $$target{$targ}{'in'} =~ s/^\s*//;
        $$target{$targ}{'in'} =~ s/\s*$//;
        $$target{$targ}{'out'} =~ s/^\s*//;
        $$target{$targ}{'out'} =~ s/\s*$//;
        $$target{$targ}{'uptime'} =~ s/^\s*//;
        $$target{$targ}{'uptime'} =~ s/\s*$//;
        $$target{$targ}{'name'} =~ s/^\s*//;
        $$target{$targ}{'name'} =~ s/\s*$//;

	# do we have numbers in the external programs answer ?
	if ( $$target{$targ}{'in'} !~ /^\d+$/ ) {
	  warn "Problem with Externale get '$targ':\n".
	    "   Expected an INTEGER for 'in' but got '$$target{$targ}{'in'}'\n\n";
	  $$target{$targ}{'in'} = int($$target{$targ}{'in'});
	}	
	if ( $$target{$targ}{'out'} !~ /^\d+$/ ) {
	  warn "Problem with Externale get '$targ':\n".
	    "    Expected an INTEGER for 'out' but got '$$target{$targ}{'out'}'\n\n";
	  $$target{$targ}{'out'} = int($$target{$targ}{'out'});
	}	
      }
      
      if ($main::SNMPDEBUG) {
	$now=time;
	print SR "$now -- $targ ".
	  "in: \"$$target{$targ}{'in'}\"  ".
	    "out: \"$$target{$targ}{'out'}\"\n";
      }
    } else {
      if ($main::OS eq 'VMS') {
	die "FATAL ERROR: The VMS Port only supports 'external snmpget'\n";
      }
      
      print "snmpget: $$target{$targ}{oid1} $$target{$targ}{oid2} ".
	"$$target{$targ}{router} ".
	"$$target{$targ}{community}\n" if $main::DEBUG;
#      for ($i=0;$i<2;$i++) {
	if (($$target{$targ}{'oid1'} =~ /^if.+\.(\d+)$/) ||
	    ($$target{$targ}{'oid1'} =~ 
	     /^1\.3\.6\.1\.2\.1\.2\.2\.1\.\d+\.(\d+)$/)){
	  # we ll do the interface check only if 
	  # the request is to an if OID. Otherwhise this does not make
	  # sense.
print STDOUT "1.2.1\n" if ($main::DEBUG > 100);
	  ($in,$out,$uptime,$name,$newifDescrs{$targ}) = 
	    &snmpget($$target{$targ}{'community'}."@".$$target{$targ}{'router'},
		     $$target{$targ}{'oid1'},
		     $$target{$targ}{'oid2'},
		     'sysUptime',
		     'sysName',
		     "ifDescr.$1");
	   chomp($newifDescrs{$targ}); #some ifDescrs end with \n ... aargh
	} elsif (($$target{$targ}{'oid1'} =~ /^cache.+$/) ||
	    ($$target{$targ}{'oid1'} =~ 
	     /^1\.3\.6\.1\.4\.1\.3495\.1\.\d+(\.\d+)+$/)){
print STDOUT "1.4.1\n" if ($main::DEBUG > 100);
	  ($in,$out) = 
	    &snmpget($$target{$targ}{'community'}."@".$$target{$targ}{'router'},
		     $$target{$targ}{'oid1'},
		     $$target{$targ}{'oid2'});
	} else {
print STDOUT "neither 1.2.1 nor 1.4.1: $$target{$targ}{'oid1'}\n" if ($main::DEBUG > 100);
	  ($in,$out,$uptime,$name) = 
	    &snmpget($$target{$targ}{'community'}."@".$$target{$targ}{'router'},
		     $$target{$targ}{'oid1'},
		     $$target{$targ}{'oid2'},
		     'sysUptime',
		     'sysName');
	}

	if (($in >= 0) && (($$target{$targ}{'oid1'} =~ /ifOperHack/) || 
	    ($$target{$targ}{'oid1'} =~ /ifAdminHack/))) {
	  $in = 0 unless $in == 1;
	  print SR "SNMPGET: if*Hack in action: targ - '$targ' in - '$in'\n" 
	    if $main::SNMPDEBUG;
	}
	if (($$target{$targ}{'oid2'} =~ /ifOperHack/) || 
	    ($$target{$targ}{'oid2'} =~ /ifAdminHack/)) {
	  $out = 0 unless $out == 1;
	  print SR "SNMPGET: if*Hack in action: targ - '$targ' out - '$out'\n"
	    if $main::SNMPDEBUG;
	  
	}

#	if ($in != -1) {
#	  last;
#	}

#	print "CANT GET $targ PROBLEM in:'$in' out:'$out'\n " if $main::DEBUG;
#	sleep(1); # try again in 1 seconds ...
 #     }
      if ( not defined $in or not defined $out ) {
	print STDERR "SNMPGET: Failed to reach target: \"$targ\". I tried multiple times!\n";
	$in=-1; $out=-1;
      } else {
	# we only get here if there was data returned 
	print "$targ --> in: $in  out: $out  name: $name\n" if $main::DEBUG;
	
	
	if (($oldifDescrs{$targ} ne '') &&
	    ($newifDescrs{$targ} ne '') &&
	    ($oldifDescrs{$targ} ne $newifDescrs{$targ})){
	  $in=-1,$out=-1;	
	  print STDERR <<WARN;
Warning: There is something wrong with Target '$targ'
  
* Its ifDescr used to be '$oldifDescrs{$targ}'
* Now it is '$newifDescrs{$targ}'

I will not update this graph for the moment. Maybe your Router has
changed the port to interface mapping. This can happen when new
Interfaces are added to the router or when it is rebooted.

You should alter your '$cfgfile' file to fix the mapping and then
remove the offending lines from your '$cfgfile.ok' file. Mrtg will
then assume that everything is OK and create new entries representing 
the new matching. 
---------------------------------------------------------------------
WARN
  ;
	  
	}
	# Build the new ok files
	if ($oldifDescrs{$targ} ne '') {
	  $okfile .= "$targ = $oldifDescrs{$targ}\n";
	} elsif ($newifDescrs{$targ} ne '') {
	  $okfile .= "$targ = $newifDescrs{$targ}\n";
	}
      }
      #
      
      # sometimes we can only observe the router on the wrong side 
      # of the fence ...
      
      if ($$target{$targ}{'ioswap'} eq '-') {
	$$target{$targ}{'in'}=$out;
	$$target{$targ}{'out'}=$in;
      } else {
	$$target{$targ}{'in'}=$in;
	$$target{$targ}{'out'}=$out;
      }
      
      $$target{$targ}{'uptime'}=$uptime;
      $$target{$targ}{'name'}=$name;
      
      if ($main::SNMPDEBUG) {
	$now=time;
	print SR "$now -- $$target{$targ}{'router'} ".
	  " in: \"$in\"  out: \"$out\"\n";
	}
    }
    # now that the data is gatherd we take a time stamp ...
    # for simple targets we will pass this along to rateup and be happy
    $$target{$targ}{'time'}=time;
  }  

  close SR if $main::SNMPDEBUG;
  #
  # store the new ifDescr File
  if(open CFGOK,">$cfgfile.ok") {
    print STDERR "Writing ifDescs to $cfgfile.ok ...\n" if $main::DEBUG;
    print CFGOK $okfile;
    close CFGOK;
  } else {
    print STDERR "Problem: Could not write ifDescs to $cfgfile.ok ...\n";
  }  
  #
}
