summaryrefslogtreecommitdiff
path: root/httemplate/misc/xmlhttp-mib-browse.html
blob: f3084ff6fe4bd65c1357227de96d7766b298ee49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
%#<% Data::Format::HTML->new->format($index{by_path}) %>
% my $json = "JSON"->new->canonical;
<% $json->encode($result) %>
<%init>
#<%once>  #enable me in production
use SNMP;
SNMP::initMib();
my $mib = \%SNMP::MIB;

# make an index of the leaf nodes
my %index = (
  by_objectID => {}, # {.1.3.6.1.2.1.1.1}
  by_fullname => {}, # {iso.org.dod.internet.mgmt.mib-2.system.sysDescr}
  by_path     => {}, # {iso}{org}{dod}{internet}{mgmt}{mib-2}{system}{sysDescr}
  module  => {}, #{SNMPv2-MIB}{by_path}{iso}{org}...
                 #{SNMPv2-MIB}{by_fullname}{iso.org...}
);

my %name_of_oid = (); # '.1.3.6.1' => 'iso.org.dod.internet'

# build up path names
my $fullname;
$fullname = sub {
  my $oid = shift;
  return $name_of_oid{$oid} if exists $name_of_oid{$oid};

  my $object = $mib->{$oid};
  my $myname = '.' . $object->{label};
  # cut off the last element and recurse
  $oid =~ /^(\.[\d\.]+)?(\.\d+)$/;
  if ( length($1) ) {
    $myname = $fullname->($1) . $myname;
  }
  return $name_of_oid{$oid} = $myname
};

my @oids = keys(%$mib); # dotted numeric OIDs
foreach my $oid (@oids) {
  my $object = {};
  %$object = %{ $mib->{$oid} }; # untie it
  # and remove references
  delete $object->{parent};
  delete $object->{children};
  delete $object->{nextNode};
  $index{by_objectID}{$oid} = $object;
  my $myname = $fullname->($oid);
  $object->{fullname} = $myname;
  $index{by_fullname}{$myname} = $object;
  my $moduleID = $object->{moduleID};
  $index{module}{$moduleID} ||= { by_fullname => {}, by_path => {} };
  $index{module}{$moduleID}{by_fullname}{$myname} = $object;
}
my @names = sort {$a cmp $b} keys %{ $index{by_fullname} };
foreach my $myname (@names) {
  my $obj = $index{by_fullname}{$myname};
  my $moduleID = $obj->{moduleID};
  my @parts = split('\.', $myname);
  shift @parts; # always starts with an empty string
  for ($index{by_path}, $index{module}{$moduleID}{by_path}) {
    my $subindex = $_;
    for my $this_part (@parts) {
      $subindex = $subindex->{$this_part} ||= {};
    }
    # $subindex now = $index{by_path}{foo}{bar}{baz}.
    # set {''} = the object with that name.
    # and set object $index{by_path}{foo}{bar}{baz}{''} = 
    # the object named .foo.bar.baz
    $subindex->{''} = $obj;
  }
}

#</%once>
#<%init>
# no ACL for this
my $sub = $cgi->param('sub');
my $result = {};
if ( $sub eq 'search' ) {
  warn "search: ".$cgi->param('arg')."\n";
  my ($module, $string) = split(':', $cgi->param('arg'), 2);
  my $idx; # the branch of the index to use for this search
  if ( $module eq 'ANY' ) {
    $idx = \%index;
  } elsif (exists($index{module}{$module}) ) {
    $idx = $index{module}{$module};
  } else {
    warn "unknown MIB moduleID: $module\n";
    $idx = {}; # will return nothing, because you've somehow sent a bad moduleID
  }
  if ( exists($index{by_fullname}{$string}) ) {
    warn "exact match\n";
    # don't make this module-selective--if the path matches an existing 
    # object, return that object
    %$result = %{ $index{by_fullname}{$string} }; # put the object info in $result
    #warn Dumper $result;
  }
  my @choices; # menu options to return
  if ( $string =~ /^[\.\d]+$/ ) {
    # then this is a numeric path
    # ignore the module filter, and return everything starting with $string
    if ( $string =~ /^\./ ) {
      @choices = grep /^\Q$string\E/, keys %{$index{by_objectID}};
    } else {
      # or everything containing it
      @choices = grep /\Q$string\E/, keys %{$index{by_objectID}};
    }
    @choices = map { $index{by_objectID}{$_}->{fullname} } @choices;
  } elsif ( $string eq '' or $string =~ /^\./ ) {
    # then this is an absolute path
    my @parts = split('\.', $string);
    shift @parts;
    my $subindex = $idx->{by_path};
    my $path = '';
    @choices = keys %$subindex;
    # walk all the specified path parts
    foreach my $this_part (@parts) {
      # stop before walking off the map
      last if !exists($subindex->{$this_part});
      $subindex = $subindex->{$this_part};
      $path .= '.' . $this_part;
      @choices = grep {$_} keys %$subindex;
    }
    # skip uninteresting nodes: those that aren't accessible nodes (have no
    # data type), and have only one path forward
    while ( scalar(@choices) == 1
            and (!exists $subindex->{''} or $subindex->{''}->{type} eq '') ) {

      $subindex = $subindex->{ $choices[0] };
      $path .= '.' . $choices[0];
      @choices = grep {$_} keys %$subindex;

    }

    # if we are on an existing node, and the entered path didn't exactly
    # match another node, return the current node as the result
    if (!keys %$result and exists($subindex->{''})) {
      %$result = %{ $subindex->{''} };
    }
    # prepend the path up to this point
    foreach (@choices) {
      $_ = $path.'.'.$_;
      # also label accessible nodes for the UI
      if ( exists($subindex->{$_}{''}) and $subindex->{$_}{''}{'type'} ) {
        $_ .= '-';
      }
    }
    # also include one level above the originally requested path, 
    # for tree-like navigation
    if ( $string =~ /^(.+)\.[^\.]+/ ) {
      unshift @choices, $1;
    }
  } else {
    # then this is a full-text search
    warn "/$string/\n";
    @choices = grep /\Q$string\E/i, keys(%{ $idx->{by_fullname} });
  }
  @choices = sort @choices;
  $result->{choices} = \@choices;
} elsif ( $sub eq 'get_module_list' ) {
  $result = { modules => [ sort keys(%{ $index{module} }) ] };
}
</%init>