1 %#<% Data::Format::HTML->new->format($index{by_path}) %>
2 % my $json = "JSON"->new->canonical;
3 <% $json->encode($result) %>
5 #<%once> #enable me in production
10 # make an index of the leaf nodes
12 by_objectID => {}, # {.1.3.6.1.2.1.1.1}
13 by_fullname => {}, # {iso.org.dod.internet.mgmt.mib-2.system.sysDescr}
14 by_path => {}, # {iso}{org}{dod}{internet}{mgmt}{mib-2}{system}{sysDescr}
15 module => {}, #{SNMPv2-MIB}{by_path}{iso}{org}...
16 #{SNMPv2-MIB}{by_fullname}{iso.org...}
19 my %name_of_oid = (); # '.1.3.6.1' => 'iso.org.dod.internet'
25 return $name_of_oid{$oid} if exists $name_of_oid{$oid};
27 my $object = $mib->{$oid};
28 my $myname = '.' . $object->{label};
29 # cut off the last element and recurse
30 $oid =~ /^(\.[\d\.]+)?(\.\d+)$/;
32 $myname = $fullname->($1) . $myname;
34 return $name_of_oid{$oid} = $myname
37 my @oids = keys(%$mib); # dotted numeric OIDs
38 foreach my $oid (@oids) {
40 %$object = %{ $mib->{$oid} }; # untie it
41 # and remove references
42 delete $object->{parent};
43 delete $object->{children};
44 delete $object->{nextNode};
45 $index{by_objectID}{$oid} = $object;
46 my $myname = $fullname->($oid);
47 $object->{fullname} = $myname;
48 $index{by_fullname}{$myname} = $object;
49 my $moduleID = $object->{moduleID};
50 $index{module}{$moduleID} ||= { by_fullname => {}, by_path => {} };
51 $index{module}{$moduleID}{by_fullname}{$myname} = $object;
53 my @names = sort {$a cmp $b} keys %{ $index{by_fullname} };
54 foreach my $myname (@names) {
55 my $obj = $index{by_fullname}{$myname};
56 my $moduleID = $obj->{moduleID};
57 my @parts = split('\.', $myname);
58 shift @parts; # always starts with an empty string
59 for ($index{by_path}, $index{module}{$moduleID}{by_path}) {
61 for my $this_part (@parts) {
62 $subindex = $subindex->{$this_part} ||= {};
64 # $subindex now = $index{by_path}{foo}{bar}{baz}.
65 # set {''} = the object with that name.
66 # and set object $index{by_path}{foo}{bar}{baz}{''} =
67 # the object named .foo.bar.baz
68 $subindex->{''} = $obj;
75 my $sub = $cgi->param('sub');
77 if ( $sub eq 'search' ) {
78 warn "search: ".$cgi->param('arg')."\n";
79 my ($module, $string) = split(':', $cgi->param('arg'), 2);
80 my $idx; # the branch of the index to use for this search
81 if ( $module eq 'ANY' ) {
83 } elsif (exists($index{module}{$module}) ) {
84 $idx = $index{module}{$module};
86 warn "unknown MIB moduleID: $module\n";
87 $idx = {}; # will return nothing, because you've somehow sent a bad moduleID
89 if ( exists($index{by_fullname}{$string}) ) {
91 # don't make this module-selective--if the path matches an existing
92 # object, return that object
93 %$result = %{ $index{by_fullname}{$string} }; # put the object info in $result
96 my @choices; # menu options to return
97 if ( $string =~ /^[\.\d]+$/ ) {
98 # then this is a numeric path
99 # ignore the module filter, and return everything starting with $string
100 if ( $string =~ /^\./ ) {
101 @choices = grep /^\Q$string\E/, keys %{$index{by_objectID}};
103 # or everything containing it
104 @choices = grep /\Q$string\E/, keys %{$index{by_objectID}};
106 @choices = map { $index{by_objectID}{$_}->{fullname} } @choices;
107 } elsif ( $string eq '' or $string =~ /^\./ ) {
108 # then this is an absolute path
109 my @parts = split('\.', $string);
111 my $subindex = $idx->{by_path};
113 @choices = keys %$subindex;
114 # walk all the specified path parts
115 foreach my $this_part (@parts) {
116 # stop before walking off the map
117 last if !exists($subindex->{$this_part});
118 $subindex = $subindex->{$this_part};
119 $path .= '.' . $this_part;
120 @choices = grep {$_} keys %$subindex;
122 # skip uninteresting nodes: those that aren't accessible nodes (have no
123 # data type), and have only one path forward
124 while ( scalar(@choices) == 1
125 and (!exists $subindex->{''} or $subindex->{''}->{type} eq '') ) {
127 $subindex = $subindex->{ $choices[0] };
128 $path .= '.' . $choices[0];
129 @choices = grep {$_} keys %$subindex;
133 # if we are on an existing node, and the entered path didn't exactly
134 # match another node, return the current node as the result
135 if (!keys %$result and exists($subindex->{''})) {
136 %$result = %{ $subindex->{''} };
138 # prepend the path up to this point
141 # also label accessible nodes for the UI
142 if ( exists($subindex->{$_}{''}) and $subindex->{$_}{''}{'type'} ) {
146 # also include one level above the originally requested path,
147 # for tree-like navigation
148 if ( $string =~ /^(.+)\.[^\.]+/ ) {
149 unshift @choices, $1;
152 # then this is a full-text search
154 @choices = grep /\Q$string\E/i, keys(%{ $idx->{by_fullname} });
156 @choices = sort @choices;
157 $result->{choices} = \@choices;
158 } elsif ( $sub eq 'get_module_list' ) {
159 $result = { modules => [ sort keys(%{ $index{module} }) ] };