#!/usr/bin/perl

################################################################################
#
# v1.2
#
# Updates v1.1:
# Updated 04/16/04 to remove readlines and replace with <>
#		   apparently this is the cause of the problem
#		   with older versions of Perl.
#
# Updates v1.2:
# Updated 10/15/04 found a problem where NetView Windows will names
#                  devices differently. Changing the key for everything
#                  to use the symbol id instead
#
# The object of this script is to accept the output from ovmapdump -v and
# to create a location.conf file. We simply feed it the name(and path) of
# the file we want to run against. 
#
# This is not a IBM Tivoli NetView supported tool. Please use at your own
# risk. Do NOT call IBM for support as they will have no clue what you are
# talking about. No warranty is given or implied.
#
# Here is a quick breakdown of the important variables and what they are 
# used for:
#   $submap{} - this hash stores the symbol id of the device as the key
#		and stores the submapid and parent_submapid in an 
#               array
#
#   $location{} - this hash stores the submapid as the key and stores
#                 the name, symbol type and parent_submapid in an array
#
#   @{$router{}} - this is an array of a hash(the hash is used as the
#                  varible name) is built for each submap. All router
#                  names that are parented by that submap are stored
#                  in this array.(this is also true for @{$network{}})
#
#   @toplevel - this is an array that stores the submapid of all
#               locations parented by IP Internet
#
#   @{$parent{}} - this is an array of a hash, the hash key is the submapid
#                  and it stores an array each child submapid
#                
#
################################################################################

if (! defined($ARGV[0])) {
   print "No target file defined.\n";
   print "Usage: $0 <path to ovmapdump -v output>\n";
   exit 255;
   }


open (MAPDUMP, "$ARGV[0]") || die "Unable to open: $ARGV[0]\n";

$date = `date`;
chomp $date;
print "# location.conf file was autogenerated on $date.\n\n";

while (<MAPDUMP>) {
  if ( $_ =~ /^Submap ID/ ) {

     # Here we need to capture the submapid and parent_submapid and
	 # store it in a hash with the Name as the key
     
     ($submapid) = /^Submap ID\: (.*)/;

     # Apparently in perl there is no way to move the file pointer by
     # line, we will just skip the lines we know we dont care about
    
     skip_line(\*MAPDUMP,1);
     $name = get_var(\*MAPDUMP);

     # We need to store ip internet and use it as our starting point
     
     if ( $name =~ /^IP Internet\b/ ) {
        $ipmapid = $submapid;
        }
     skip_line(\*MAPDUMP,3);
     $pobjid = get_var(\*MAPDUMP); 
     $psubid = get_var(\*MAPDUMP); 
     $submap{$pobjid} = [($submapid,$psubid)];
  
     skip_line(\*MAPDUMP,16);
     }
  elsif ( $_ =~ /^Symbol ID/ ) {

     # Here we grab the label, Symbol type and store it with its parent id 
     # for each location. Each router and network is stored simply with 
     # its parent id
     
     skip_line(\*MAPDUMP,1);
     $label = get_var(\*MAPDUMP); 
     $objid = get_var(\*MAPDUMP);
     $symid = get_var(\*MAPDUMP); # used only to store routers and networks
                                  # as there are multiple symbols for each 
                                  # router and subnet
     skip_line(\*MAPDUMP,1);
     $symtype = get_var(\*MAPDUMP); 
     skip_line(\*MAPDUMP,14);      
     if ($symtype =~ /Router|Cisco|Connector/ ) {

        # store hopefully all layer3 capable devices(i guess we should add 
        # bay, lucent whatever) into a hash of an array with the parent submap
        # id as the key of the hash. The array contains all routers that are
        # a child of that submap

           push(@{$router{$symid}},$label);
        }
     elsif ($symtype =~ /Location/) {
        if (! $location{$submap{$objid}[0]}) {

          # store name, symbol type, submap id(hash key), and submap parent id
          # also create a new hash array(parent) that stores the parent submap
          # id along with each of its children in the array. We will walk this
          # array recursively to create the location.conf file. We also store
          # all the locations that appear on ip internet
        
          (undef,$hold) = split(/\:/, $symtype);
          $symtype = $hold;

          @location{$submap{$objid}[0]}=[($label,$symtype,$submap{$objid}[1])];

          if ( $submap{$objid}[1] == $ipmapid ) {
             push (@toplevel, $submap{$objid}[0]);
             }

          if ( $submap{$objid}[1] > 0 ) { 
             push (@{$parent{$submap{$objid}[1]}},$submap{$objid}[0]);
             }
          }
        }
     elsif ($symtype =~ /Network/ ) {
        
        # store all networks with their parent id and label
        # if they do not already exist

        if ( ! grep { /\b$label\b/ } @{$network{$symid}} ) {
           push(@{$network{$symid}},$label);
           }
        }
     }
  }

# Close filehandle

close(MAPDUMP);

# We will start with our toplevel array, this contains the mapid of each of
# ip internets locations. We will start there, once this loop completes the
# script is complete


foreach $submap (@toplevel) {

   # First we must create our 0 level icon
   # Name 0 Symboltype
 
   create_toplevel_entry($submap);

   # After we print the toplevel entry, we will add all routers
   # and then all networks before moving to its children locations
 
   walk_routers($submap);
   walk_networks($submap);

   # Now we begin the recursive loop through the locations

   walk_children($submap);

   # print a blank line at the end

   print "\n";

   }

# print ending message

$date = `date`;
chomp $date;
print "# Script completed processing on $date\n";

# FIN script completed

# This subroutine will recursively call itself until it reaches the end
# of all children of the submap passed.

sub walk_children {
   foreach $child (@{$parent{$_[0]}}) {

      # First we create the upper level entry for this child, then
      # print routers and or networks before again calling this
      # routine for its children.
  
      create_zero_entry($child,$location{$_[0]}[0]);
      walk_routers($child);
      walk_networks($child);
      walk_children($child);
      }
   }

sub create_zero_entry {

   # We need to check if the name of this object or its parent
   # name contains spaces, if so we need to quote them.
   
   $child_name = check_spaces($location{$_[0]}[0]);
   $type = check_spaces($location{$_[0]}[1]);
   $parent_name = check_spaces($_[1]);

   if ( length($child_name) < 8 ) {
      printf "%s\t\t255\t%s\t%s\n",$child_name,$type,$parent_name;
      } else {
      printf "%s\t255\t%s\t%s\n",$child_name,$type,$parent_name;
      }

   }
   
sub create_toplevel_entry {
  
   # This routine simply prints the 0 level entry for the toplevel
   # icons

   $name = check_spaces($location{$_[0]}[0]);
   $type = check_spaces($location{$_[0]}[1]);

   if ( length($name) < 8 ) {
      printf "%s\t\t255\t%s\n",$name, $type;
      } else {
      printf "%s\t255\t%s\n",$name, $type;
      }

   }

sub walk_routers {

   # Each router of a parent submap is stored in an array. We walk
   # the array passed and print the output.

   foreach $router (sort(@{$router{$_[0]}})) {

      $name = check_spaces($location{$_[0]}[0]);
      if (length($name) < 8 ) {
         printf "%s\t\t%s\n",$name, $router;
         } else {
         printf "%s\t%s\n",$name, $router;
         }
      }
   print "\n";

   }

sub walk_networks {

   # Each network of a parent submap is stored in an array. We walk
   # the array passed and print the output.

   foreach $network (sort(@{$network{$_[0]}})) {
       
      $name = check_spaces($location{$_[0]}[0]);
      $type = check_spaces($location{$_[0]}[1]);
        
      if ( length($network) < 8 && length($name) < 8 ) {
         printf "%s\t\t%s\t\t%s\n",$name, $network, $type;
         } elsif (length($network) < 8 ) {
         printf "%s\t%s\t\t%s\n",$name, $network, $type;
         } elsif (length($name) < 8 ) {
         printf "%s\t\t%s\t%s\n",$name, $network, $type;
         } else {
         printf "%s\t%s\t%s\n",$name, $network, $type;
         }
      }
   print "\n";
   }

# Stupid readline hack to work around perls inability to move the
# file pointer by line.

sub skip_line {
  for ($i=1;$i<=$_[1];$i++) {

     # $test = readline($_[0]);   REMOVED 4/16/04

     <MAPDUMP>;
     }
  }

# Got tired of writing this over and over so I made it a function
# it simply pulls the necessary information(ie after the ":")

sub get_var {

   # $test = readline($_[0]);   REMOVED 4/16/04

   $hold = <MAPDUMP>;
   $hold =~ /^S.*\: (.*)/;
   return $1;
   }

# In some of the names of locations and some of the Location Symbol
# types contain spaces, if need be we will quote them before printing
# this checks for and returns a quoted string if necessary

sub check_spaces {
   if ($_[0] =~ / /) {
      $return = "\"$_[0]\"";
      } else {
      $return = $_[0];
      }

   return($return);
   }
