http://www.usr.com/support/gpl/USR9107_release1.1.tar.gz
[bcm963xx.git] / userapps / opensource / net-snmp / local / tkmib
1 #!/usr/bin/perl
2 #!/usr/bin/perl -w
3
4 require 5;
5
6 # attempt to determine if they have the proper modules installed.
7
8 # SNMP
9 my $havesnmp = eval {require SNMP;};
10
11 # the Tk packages
12
13 my $havetk = eval {require Tk;
14                    require Tk::Table;
15                    require Tk::HList;
16                    require Tk::FileSelect;
17                    require Tk::Dialog;};
18 if (!$havesnmp) {
19     print "
20 ERROR:  You don't have the SNMP perl module installed.  Please obtain this by
21 getting the latest source release of the net-snmp toolkit from
22 http://www.net-snmp.org/download/ .  The perl module is contained in
23 the perl/SNMP directory.  See the INSTALL file there for
24 instructions.
25 ";
26 }
27
28 if (!$havetk) {
29     print "
30 ERROR:  You don't have the Tk module installed.  You should be able to
31 install this by running (as root):
32
33     perl -MCPAN -e 'install Tk'
34 ";
35 }
36
37 if (!$havetk || !$havesnmp) {
38     print "\n";
39     exit;
40 }
41
42 if ($havetk) {
43   # Tk doesn't seem to like require so we force use here.
44     eval {import Tk;
45           import Tk::Table;
46           import Tk::HList;
47           import Tk::FileSelect;
48           import Tk::Dialog;
49           import SNMP;};
50 }
51
52 use Getopt::Std;
53 use Data::Dumper;
54
55 $host = 'localhost';
56 $OID = '.1.3.6.1';
57 $opts{'C'}=$ENV{'HOME'} . "/.snmp/tkmibrc";
58
59 # default session options
60 if (test_version(1,5,0,0)) {
61     print "setting opts\n";
62     %opts = (
63              'c'          => "public",
64              'p'   => 161,
65              't'      => 5000000,
66              'r'      => 5,
67              'v'      => 1,
68              'a'    => 'MD5',
69              'x'    => 'DES',
70              'A'     => '',
71              'X'     => '',
72              'n'      => '',
73              'u'      => 'initial',
74              'l'     => 'authNoPriv',
75              );
76 }
77
78 getopts("hp:v:a:A:x:X:n:u:l:r:t:o:c:C", \%opts);
79
80 sub usage {
81     print "
82 tkmib [-C] [-o OID] [SNMPCMD arguments] [host]
83   -C CONFIG_FILE  load CONFIG_FILE after starting up. (default: ~/.snmp/tkmibrc)
84                   (use -C /dev/null to not read one).
85
86   See the snmpcmd manual page for related SNMPCMD arguments.  (Not all
87   options are currently supported.)
88 ";
89     exit();
90 }
91
92 usage() if ($opts{'h'});
93
94 # initialize defaults, may be overridden by config file below
95 @displayInfo=qw(type access status units hint moduleID enums indexes);
96 @saveoptions = ('displayoidas', 'writecolor', 'graphtime', 'graphdelta');
97 $displayoidas='full';
98 $writecolor = "blue";
99 $graphtime=5;
100 $graphdelta=1;
101 foreach $i (@displayInfo) {
102     $displayInfoStates{$i} = 1;
103 }
104
105
106 # source config file
107 do $opts{'C'} if ($opts{'C'} && -f $opts{'C'});
108
109 $session_opts{'UseLongNames'} => 1;
110 $session_opts{'RemotePort'} = $opts{'p'} if ($opts{'p'});
111 $session_opts{'Community'} = $opts{'c'} if ($opts{'c'});
112 $session_opts{'Version'} = $opts{'v'} if ($opts{'v'});
113 $session_opts{'AuthProto'} = $opts{'a'} if ($opts{'a'});
114 $session_opts{'AuthPass'} = $opts{'A'} if ($opts{'A'});
115 $session_opts{'PrivProto'} = $opts{'x'} if ($opts{'x'});
116 $session_opts{'PrivPass'} = $opts{'X'} if ($opts{'X'});
117 $session_opts{'Context'} = $opts{'n'} if ($opts{'n'});
118 $session_opts{'SecName'} = $opts{'u'} if ($opts{'u'});
119 $session_opts{'SecLevel'} = $opts{'l'} if ($opts{'l'});
120 $session_opts{'Retries'} = $opts{'r'} if ($opts{'r'});
121 $session_opts{'Timeout'} = $opts{'t'} if ($opts{'t'});
122
123 $host = shift if ($#ARGV > -1);
124 $session_opts{'Community'} = shift if ($#ARGV > -1);
125
126 @graphcolors=qw(blue red green yellow purple);
127
128 # initialize SNMP module
129 $SNMP::save_descriptions=1;
130 $SNMP::use_long_names=1;
131 $SNMP::use_enums=1;
132 $SNMP::verbose = 1;
133 my $tmpbd = 1;
134
135 $top = MainWindow->new();
136 $top->title("tkmib");
137
138 #Menus
139 $MenuFrame = $top->Frame(-relief => "raised",-borderwidth => 2);
140 $MenuFrame->pack(-fill => "x",-expand => 1);
141 $FileMenuBut = $MenuFrame->Menubutton(-pady => $tmpbd, -padx => $tmpbd, -text => "File",
142                                       -menuitems =>
143       [
144 #       [Button => "Save Output", -command => [\&saveOutput]],
145        [Button => "Quit",        -command => [\&exit]]
146        ]);
147 $FileMenuBut->pack(-side => 'left');
148
149 $MibMenuBut = $MenuFrame->Menubutton(-pady => $tmpbd, -padx => $tmpbd, -text => "Mib",
150                                       -menuitems =>
151       [[Button => "Find a mib node", 
152         -command => sub { my $var;
153                           entryBox("Find a Mib Node", 
154                                    "Enter a mib node name to search for:",
155                                    \$var, \&findANode );}],
156        [Button => "Load a New Mib File", -command => [\&loadNewMibFile]],
157        [Button => "Load a New Mib Module", 
158         -command => sub { my $var;
159                           entryBox("Load a Module", 
160                                    "Enter a SNMP MIB module name to load:",
161                                    \$var, \&loadIt);}]
162        ]);
163 $MibMenuBut->pack(-side => 'left');
164
165 $OptMenuBut = $MenuFrame->Menubutton(-pady => $tmpbd, -padx => $tmpbd, -text => "Options",
166                                      -menuitems =>
167       [[Cascade => "~Display", -menuitems =>
168         [
169          [Cascade => "~MIB Information"],
170          [Cascade => "~OID Display", -menuitems =>
171           [
172            [Radiobutton => 'full', -variable => \$displayoidas],
173            [Radiobutton => 'numeric', -variable => \$displayoidas],
174            [Radiobutton => 'short', -variable => \$displayoidas],
175            [Radiobutton => 'module', -variable => \$displayoidas]
176            ]
177           ],
178          [Button => "Writable Color", 
179           -command => [\&entryBox,"Writable Color",
180                        "Color for writable objects:",
181                        \$writecolor]]
182          ]],
183        [Cascade => "Use SNMP Version", -menuitems =>
184         [
185          [Radiobutton => '1', -variable => \$session_opts{'Version'}],
186          [Radiobutton => '2c', -variable => \$session_opts{'Version'}],
187          [Radiobutton => '3', -variable => \$session_opts{'Version'}]
188         ]
189        ], # ends version number specification
190        [Cascade => "SNMPv1/2c options", -menuitems =>
191         [
192          [Button => "Community Name", 
193           -command => [\&entryBox,"Community Name", "Community name to use:", 
194                        \$session_opts{'Community'}]]
195         ]
196        ],
197        [Cascade => "SNMP3 options", -menuitems =>
198         [
199          [Button => "Security Name", 
200           -command => [\&entryBox,"Security Name", "Security Name to use:", 
201                        \$session_opts{'SecName'}]],
202          [Cascade => "Security Level", -menuitems =>
203           [
204            [Radiobutton => 'noAuthNoPriv',
205             -variable => \$session_opts{'SecLevel'}],
206            [Radiobutton => 'authNoPriv', 
207             -variable => \$session_opts{'SecLevel'}],
208            [Radiobutton => 'authPriv', 
209             -variable => \$session_opts{'SecLevel'}]
210           ]
211          ],
212          [Button => "Authentication Passphrase", 
213           -command => [\&entryBox,"Authentication Passphrase", 
214                        "Authentication Passphrase to use:", 
215                        \$session_opts{'AuthPass'}]],
216          [Cascade => "Authentication Type", -menuitems =>
217           [
218            [Radiobutton => 'MD5',
219             -variable => \$session_opts{'AuthProto'}],
220            [Radiobutton => 'SHA',
221             -variable => \$session_opts{'AuthProto'}],
222           ]
223          ],
224          [Button => "Privacy Passphrase", 
225           -command => [\&entryBox,"Privacy Passphrase", 
226                        "Privacy Passphrase to use:", 
227                        \$session_opts{'PrivPass'}]],
228          [Cascade => "Privacy Type", -menuitems =>
229           [
230            [Radiobutton => 'DES',
231             -variable => \$session_opts{'PrivProto'}],
232           ]
233          ],
234         ]
235        ],
236        [Button => "Time between graph polls", 
237         -command => sub { entryBox("graph polls", "Time between graph polls:", 
238                                     \$graphtime);}],
239        [Button => "Port number", 
240         -command => sub { entryBox("Port Number", "SNMP Port number to use:", 
241                                     \$session_opts{'RemotePort'});}],
242        [Button => "TimeOut", 
243         -command => sub { entryBox("Time Out", "Timeout for SNMP requests:", 
244                                     \$session_opts{'Timeout'});}],
245        [Button => "Retries", 
246         -command => sub { entryBox("Retries", 
247                                    "Number of Times to Retransmit Requests:", 
248                                     \$session_opts{'Retries'});}],
249        [Button => "Save Options",
250         -command => \&save_options]
251        ])->pack(-side => 'left');
252         
253 $tmp = $OptMenuBut->cget(-menu);
254 $OptMenuWidgets = $tmp->entrycget("Display", -menu);
255 $OptMenuWidgets = $OptMenuWidgets->entrycget("MIB Information", -menu);
256
257 $hlist=$top->Scrolled(qw(HList -itemtype imagetext -browsecmd main::showInfo
258                          -command main::showChildren -width 80 -height 15));
259 $hlist->pack(-side => 'top', -expand => 1, -fill => 'both');
260 my $sFrame = $top->Frame(-relief => 'raised', -borderwidth => $tmpbd);
261 $sFrame->pack(-side => 'top', -fill => 'x');
262 $sFrame->Label(-pady => $tmpbd, -padx => $tmpbd, -text => 'OID: ', -relief => 'raised', -borderwidth => $tmpbd)
263     ->pack(-side => 'left');
264 $mibOID = $sFrame->Entry(-textvariable => \$OID, -relief => 'flat', -width => 40);
265 $mibOID->pack(-side => 'left');
266 $mibTextOID = $sFrame->Label(-pady => $tmpbd, -padx => $tmpbd, -text => '');
267 $mibTextOID->pack(-side => 'right');
268
269 $dispFrame=$top->Frame(-relief => 'raised', -borderwidth => $tmpbd);
270 $dispFrame->pack(-side => 'top', -fill =>'x');
271 for($i=0;$i<= $#displayInfo;$i++) {
272     createRow($i) if ($displayInfoStates{$displayInfo[$i]});
273     optionalWidget($i,$OptMenuWidgets, \$displayInfoStates{$displayInfo[$i]});
274 }
275     
276 $descrFrame=$top->Frame(-relief => 'raised', -borderwidth => $tmpbd);
277 $descrFrame->pack(-side => 'top', -fill =>'x');
278 $descrFrame->Label(-pady => $tmpbd, -padx => $tmpbd, -text => 'Description:', -anchor => 'w')->pack(-side => 'top',
279                                                                 -fill => 'x');
280 $descr = $descrFrame->Scrolled(qw(Text -width 80 -height 4));
281 $descr->pack(-side => 'top', -fill => 'x');
282
283 $bFrame = $top->Frame(-relief => 'raised', -borderwidth => $tmpbd);
284 $bFrame->pack(-side => 'top', -fill => 'x');
285 $hostEntry = $bFrame->Entry(-textvariable => \$host, -width => 12);
286 $hostEntry->pack(-side => 'left');
287 $bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'graph', -command => \&snmpgraph)->pack(-side => 'right');
288 $tablebutton = $bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'table', -command => \&snmptable);
289 $tablebutton->pack(-side => 'right');
290 $bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'walk', -command => \&snmpwalk)->pack(-side => 'right');
291 $bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'getnext', -command => \&snmpgetnext)->pack(-side => 'right');
292 $bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'get', -command => \&snmpget)->pack(-side => 'right');
293 $bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'set', -command => [\&snmpsetbegin, 'OID'])->pack(-side => 'right');
294 $stopBut = $bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'stop', -command => sub { stop(1) },
295                            -state => 'disabled');
296 $stopBut->pack(-side => 'right');
297 $oFrame = $top->Frame(-borderwidth => $tmpbd, -relief => 'raised');
298 $oFrame->pack(-side => 'top', -fill => 'both');
299 $output = $oFrame->Scrolled(qw(Text -width 80 -height 14));
300 $output->pack(-side => 'top', -fill => 'both', -expand => 1);
301
302 $tmpFrame = $top->Frame(-relief => 'raised', -borderwidth => $tmpbd);
303 $tmpFrame->pack(-side => 'top', -fill => 'x');
304 $tmpFrame->Label(-pady => $tmpbd, -padx => $tmpbd, -text => "Status:  ", -anchor => 'w')
305 #                -relief => 'raised', -borderwidth => $tmpbd)
306     ->pack(-side => 'left');
307 $status = $tmpFrame->Label(-pady => $tmpbd, -padx => $tmpbd, -anchor => 'w');
308 $status->pack(-side => 'left', -fill => 'x');
309
310 # initialize the browser
311 foreach $i (qw(.1 .1.3 .1.3.6 .1.3.6.1)) {
312     addMibOID($i);
313 }
314 showChildren("$OID");
315 if (defined($opts{'o'})) {
316     findANode($opts{'o'});
317 }
318
319 MainLoop();
320
321 sub insertresult {
322     my $oid = shift;
323     my $val = shift;
324     $oid = $OID if ($oid eq "OID");
325     $output->insert('end', $oid, "oid:$oid");
326     $output->tagBind("oid:$oid", '<1>', [sub{shift; 
327                                              my $oid = shift;
328                                              findANode($oid);
329                                              my $tag = SNMP::translateObj($oid);
330                                              showInfo($tag);},$oid]);
331     $output->insert('end', " = ");
332     my $mib = $SNMP::MIB{format_oid("$oid",'numeric')};
333     $output->insert('end', $val, "value:$oid");
334     if ($mib->{'access'} =~ /(Write|Create)/) {
335         $output->tagConfigure("value:$oid", -foreground => $writecolor);
336         $output->tagBind("value:$oid", '<1>', [sub{shift; 
337                                                    my $oid = shift;
338                                                    my $value = shift;
339                                                    snmpsetmaybebegin($oid, $value);
340                                                    findANode($oid);
341                                                    my $tag = SNMP::translateObj($oid);
342                                                    showInfo($tag);},format_oid($oid,'full'), $val]);
343     }
344     $output->insert('end', "\n");
345 }
346
347 sub insertvar {
348     my $var = shift;
349     my $name = get_oid($var);
350
351     insertresult($name,"$var->[$SNMP::Varbind::val_f]");
352 }
353
354 sub snmpsetup {
355     my $oid = $OID;
356     my $tag = SNMP::translateObj($oid);
357     my $sess = new SNMP::Session(DestHost => $host, %session_opts);
358     my $var = new SNMP::Varbind([$oid]);
359     if (!defined($var)) {
360         print "ack:  $@ $SNMP::ErrorStr $!\n";
361     }
362     stop(0);
363     initText();
364     $oid = "." . $oid if ($oid !~ /^\./);
365     return ($oid, $sess, $var);
366 }
367
368 sub initText {
369     if (ref($output) eq "Tk::Frame" && defined($$output{'_#text'})) {
370         $output->delete('0.0','end');
371     } else {
372         $output->destroy();
373         $output = $oFrame->Scrolled(qw(Text -width 80 -height 14));
374         $output->pack(-side => 'top', -fill => 'both', -expand => 1);
375     }
376 }
377
378 sub initTable {
379     $output->destroy();
380     $oFrame->packPropagate(0);
381     $output = $oFrame->Table(-columns => shift, -width => 80, -height => 14,
382                              -fixedrows => 2, -fixedcolumns => 1);
383     $output->pack(-side => 'top', -fill => 'both', -expand => 1);
384 }
385
386 sub initCanvas {
387     $output->destroy();
388     $oFrame->packPropagate(0);
389     $output = $oFrame->Scrolled(qw(Canvas -width 80c -height 14c));
390     $output->pack(-side => 'top', -fill => 'both', -expand => 1);
391 }
392
393 sub snmpget {
394     (my $oid, my $sess, my $var) = snmpsetup();
395     $status->configure(-text => "getting:  $host $community $oid");
396     $top->update();
397     my $val = $sess->get($var);
398     if ($sess->{ErrorStr}) {
399         $status->configure(-text => $sess->{ErrorStr});
400     } else {
401         insertvar($var);
402         $status->configure(-text => "");
403     }
404 }
405
406 sub snmpsetbegin {
407     my $startoid = shift;
408     my $startval = shift;
409     my $setwin = MainWindow->new();
410     $setwin->title("SNMP set");
411     my $varswin = $setwin->Frame(-relief => "raised",-borderwidth => $tmpbd);
412     my $vars = new SNMP::VarList;
413     $varswin->pack(-side => 'top');
414     my $buttons = $setwin->Frame(-relief => "raised")->pack(-side => 'top', -fill => "x",-expand => 1);
415     $buttons->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'Add a varbind', -command => [\&snmpsetbegin_addvar, $vars, $varswin, 'OID'])->pack(-side => 'left', -fill => "x",-expand => 1);
416     $buttons->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'perform set', -command => [\&snmpsetbegin_ok, $vars, $setwin, $varswin])->pack(-side => 'left');
417     $buttons->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'Cancel', -command => [sub { my $widget = shift; $varswin = shift; if ($setmain == $varswin) { $setmain = undef; } $widget->destroy();}, $setwin, $varswin])->pack(-side => 'right');
418     if ($startoid ne "") {
419         snmpsetbegin_addvar($vars, $varswin, $startoid, $startval);
420     }
421     if (!$setmain) {
422         $setmain = $varswin;
423         $setvars = $vars;
424     }
425 }
426
427 sub make_enum_button {
428     my $win = shift;
429     my $var = shift;
430     my @objs;
431     foreach my $i (@_) {
432         push @objs,[Radiobutton => $i, -variable => $var];
433     }
434     return $win->Menubutton(-pady => $tmpbd, -padx => $tmpbd, -textvariable => $var,
435                             -relief => raised,
436                             -menuitems => \@objs);
437 }
438
439 sub snmpsetmaybebegin {
440     my ($oid, $val) = @_;
441     if ($setmain) {
442         snmpsetbegin_addvar($setvars, $setmain, $oid, $val);
443     } else {
444         snmpsetbegin($oid, $val);
445     }
446 }
447
448
449 sub snmpsetbegin_addvar {
450     my ($vars, $place, $oid, $val) = @_;
451     $oid = $OID if ($oid eq "OID");
452     my $mib = $SNMP::MIB{format_oid("$oid",'numeric')};
453     my $var = new SNMP::Varbind([$oid, '', $val, $mib->{'type'} || 'INTEGER']);
454     push @$vars,$var;
455     my $frame = $place->Frame();
456     $frame->Entry(-textvariable => \$var->[0], -width => 20)->pack(-side => 'left');
457     make_enum_button($frame, \$var->[3], qw(OBJECTID OCTETSTR INTEGER NETADDR IPADDR COUNTER COUNTER64 GAUGE UINTEGER TICKS OPAQUE NULL))->pack(-side => 'left');
458     if (ref($mib->{'enums'}) eq HASH && scalar(keys(%{$mib->{'enums'}})) > 0) {
459         make_enum_button($frame, \$var->[2], keys(%{$mib->{'enums'}}))->pack(-side => 'left');
460     } else {
461         $frame->Entry(-textvariable => \$var->[2])->pack(-side => 'left');
462     }
463     $frame->pack(-expand => 1, -fill => 'x');
464 }
465
466 sub snmpsetbegin_ok {
467     my ($vars, $win, $frame) = @_;
468     snmpset($vars);
469     $setmain = undef if ($setmain == $frame);
470     $win->destroy();
471 }
472
473 sub snmpset {
474     my $vars = shift;
475     (my $oid, my $sess, my $var) = snmpsetup();
476     $status->configure(-text => "setting:  $host -> " . Dumper($vars) . "\n");
477     $top->update();
478     my $val = $sess->set($vars);
479     if ($sess->{ErrorStr}) {
480         $output->insert('end', "Set failed.\nReason:  $sess->{ErrorStr}");
481         $status->configure(-text => $sess->{ErrorStr});
482     } else {
483         foreach my $i (@$vars) {
484             insertvar($i);
485         }
486         $status->configure(-text => "");
487     }
488 }
489
490 sub snmpgetnext {
491     (my $oid, my $sess, my $var) = snmpsetup();
492     $status->configure(-text => "get next:  $host $community $oid");
493     $top->update();
494     my $val = $sess->getnext($var);
495     if ($sess->{ErrorStr}) {
496         $status->configure(-text => $sess->{ErrorStr});
497     } else {
498         insertvar($var);
499         $status->configure(-text => "");
500     }
501 }
502
503 sub snmpwalk {
504     (my $oid, my $sess, my $var) = snmpsetup();
505     $status->configure(-text => "walking:  $host $community $oid");
506     $top->update();
507     while (!$sess->{ErrorStr} && !$stopit) {
508         my $val = $sess->getnext($var);
509         last if (!defined($var->tag) ||
510                  $sess->{ErrorStr} ||
511                  $val eq "ENDOFMIBVIEW" ||
512                  !is_in_subtree($oid, $var->tag . "." . $var->iid));
513         insertvar($var);
514         $top->update();
515     }
516     if ($sess->{ErrorStr}) {
517         $status->configure(-text => $sess->{ErrorStr});
518         $output->insert('end',"$sess->{ErrorStr} ($sess->{ErrorNum})\n");
519     } else {
520         $status->configure(-text => "");
521     }
522     stop(1);
523 }
524
525 sub snmptable {
526     (my $oid, my $sess, my $var) = snmpsetup();
527     $status->configure(-text => "collecting data:  $host $community $oid");
528     $top->update();
529     my (%tb, @tags, @index, %tboids);
530     while (!$sess->{ErrorStr} && !$stopit) {
531         my $val = $sess->getnext($var);
532         last if (!defined($var->tag) ||
533                  $sess->{ErrorStr} ||
534                  $val eq "ENDOFMIBVIEW" ||
535                  !is_in_subtree($oid, $var->tag . "." . $var->iid));
536         $newoid = "$var->[$SNMP::Varbind::tag_f].$var->[$SNMP::Varbind::iid_f]";
537         insertvar($var);
538         $top->update();
539         $newoid =~ /([^\.]+)\.([0-9\.]+)$/;
540         if (!grep(/$1/,@tags)) {
541             push @tags,$1;
542         }
543         if (!grep(/$2/,@index)) {
544             push @index,$2;
545         }
546         $tb{$2}{$1} = $var->val;
547 #       $tboids{$2}{$1} = $var->tag;
548         $tboids{$2}{$1} = $newoid;
549     }
550     initTable($#tags+1);
551     for(my $k=0;$k <= $#tags;$k++) {
552         $output->put(1,$k+2,$tags[$k]);
553     }
554     $output->put(1,1,"Index");
555     for(my $i=0;$i <= $#index;$i++) {
556         $output->put($i+2,1,$index[$i]);
557     }
558     for(my $i=0;$i <= $#index; $i++) {
559         for(my $k=0;$k <= $#tags;$k++) {
560             my $mib = $SNMP::MIB{format_oid("$tboids{$index[$i]}{$tags[$k]}",'numeric')};
561             if ($mib->{'access'} =~ /(Write|Create)/) {
562                 $output->put($i+2,$k+2,$output->Button(-fg => $writecolor, -pady => $tmpbd, -padx => $tmpbd, -text => $tb{$index[$i]}{$tags[$k]}, -command => [\&snmpsetmaybebegin, $tboids{$index[$i]}{$tags[$k]}, $tb{$index[$i]}{$tags[$k]}], -padx => 0, -pady => 0));
563             } else {
564                 $output->put($i+2,$k+2,$tb{$index[$i]}{$tags[$k]});
565             }
566         }
567     }
568     $status->configure(-text => "");
569     stop(1);
570 }
571
572 sub snmpgraph {
573     ($graphoid, $graphsess, my $graphvar) = snmpsetup();
574     $top->update();
575     %graphtb = ();
576     @graphvars = ();
577     initCanvas();
578     $gcount=0;
579     $max=-1;
580     $min=2**32-1;
581     updateGraph();
582     $output->repeat($graphtime*1000, \&updateGraph);
583 }
584
585 sub updateGraph() {
586     $status->configure(-text => "collecting data:  $host $community $graphoid");
587     my $oid = $graphoid;
588     my $tag = SNMP::translateObj($graphoid,0);
589     my $var = new SNMP::Varbind([$oid]);
590     $graphsess->{ErrorStr} = "";    
591     while (!$graphsess->{ErrorStr} && !$stopit) {
592         my $val = $graphsess->getnext($var);
593         if ($#graphvars == -1 && SNMP::translateObj($var->tag) !~ /^$oid/) {
594             # if an exact oid, do a get instead.
595             $var = new SNMP::Varbind([$oid]);
596             $val = $graphsess->get($var);
597         }
598         if ($graphsess->{ErrorStr} ||
599             !defined($var->tag) ||
600             SNMP::translateObj($var->tag) !~ /^$oid/) {
601             last;
602         }
603         my $newoid = SNMP::translateObj("$var->[$SNMP::Varbind::tag_f].$var->[$SNMP::Varbind::iid_f]");
604         $top->update();
605         $newoid =~ /$oid\.([0-9\.]+)$/;
606         if (defined($1)) {
607             if (!grep(/$1/,@graphvars)) {
608                 push @graphvars,$1;
609             }
610             if ($graphdelta) {
611                 if ($gcount > 0) {
612                     $graphtb{$1}[$gcount-1] = $var->val - $prev{$1};
613                 }
614                 $prev{$1} = $var->val;
615             } else {
616                 $graphtb{$1}[$gcount] = $var->val;
617             }
618             $max = $graphtb{$1}[$#{$graphtb{$1}}] 
619                 if ($#{$graphtb{$1}} >= 0 &&
620                     $graphtb{$1}[$#{$graphtb{$1}}] > $max);
621             $min = $graphtb{$1}[$#{$graphtb{$1}}] 
622                 if ($#{$graphtb{$1}} >= 0 &&
623                     $graphtb{$1}[$#{$graphtb{$1}}] < $min);
624         }
625     }
626     if ($gcount > 1) {
627         $output->delete('all');
628         my $canvas = $$output{'SubWidget'}{'canvas'};
629         my $h=$canvas->cget(-height);
630         foreach $i (@graphvars) {
631             my @a = ();
632             for(my $j=0; $j <= $#{$graphtb{$i}}; $j++) {
633                 $a[$j*2] = $j;
634                 $a[$j*2+1] = $h-(($h-3)*($graphtb{$i}[$j]-$min))/($max-$min)-3;
635             }
636             $output->createLine(@a, -fill => $graphcolors[$i%$#graphcolors]);
637         }
638         $output->create('text',5, $h-3, -text => "$max");
639         $output->create('text',5, 3, -text => "$min");
640     }
641     $gcount++;
642     $status->configure(-text => "sleeping for $graphtime seconds");
643 }
644
645 sub addMibOID {
646     my $i = shift;
647     $i = ".$i" if ($i !~ /^\./);
648     my $name = SNMP::translateObj($i,1);
649     if (defined($name)) {
650         $name =~ s/.*\.([^.]+)$/$1/;
651     } else {
652         return;
653     }
654     $i =~ s/^\.//;
655     $hlist->add($i, -text => $name);
656 }
657
658 sub showInfo {
659     my $full = shift;
660     $full = ".$full" if ($full !~ /^\./);
661     my $oid = $full;
662     my $tag = $oid;
663
664     if ($tag =~ /^[.0-9]+$/) {
665         # strip off index in case there is one
666         $tag = SNMP::translateObj("$oid");
667         $tag = ".iso.org.dod.internet.private.$tag" if $tag =~ /^enterprises/;
668     } else {
669         $full = SNMP::translateObj("$oid");
670     }
671
672     $tag =~ s/[.0-9]+$//;
673     $oid = SNMP::translateObj($tag);
674         
675     if (!defined($last) || "$last" ne $oid) {
676         updateInfo($oid);
677     }
678     $OID = $full;
679     $mibOID->configure(-textvariable => \$OID);
680     $mibOID->update();
681     $last = $oid;
682 }
683         
684 sub showAllChildren {
685     my $id = shift;
686     $id =~ s/^\.//;
687     my @pieces = split(/\./,$id);
688     my ($i, $lastvalid);
689     for($i = 0; $i <= $#pieces; $i++) {
690         my $a = join(".", @pieces[0..$i]);
691         if ($hlist->infoExists($a) && !($hlist->infoChildren($a))) {
692             showChildren(join(".", $a));
693         }
694         if ($hlist->infoExists($a)) {
695             $lastvalid = $a;
696         } else {
697             last;
698         }
699     }
700     $hlist->see($lastvalid);
701     $hlist->selectionClear($hlist->selectionGet);
702     $hlist->selectionSet($lastvalid);
703 }
704
705 sub showChildren {
706     $OID = shift;
707     $OID =~ s/^\.//;
708     my $oid = $OID;
709     $mibOID->configure(-textvariable => \$OID);
710     if ($hlist->infoChildren($oid)) {
711         my @a = $hlist->infoChildren($oid);
712         my $i;
713         foreach $i (@a) {
714             $hlist->deleteEntry($i);
715         }
716     } else {
717         $oid = ".$oid";
718         my $mib = $SNMP::MIB{format_oid($oid,'full')};
719         if (defined($mib)) {
720             my $children = $$mib{'children'}; 
721             if (ref($children) eq "ARRAY") {
722                 foreach $i (sort {$$a{'subID'} <=> $$b{'subID'}} @{$children}) {
723                     addMibOID($$i{'objectID'});
724                 }
725             } else {
726                 $status->configure(-text => SNMP::translateObj($oid,1) . 
727                                    " has no children");
728                 return;
729             }
730         }
731     }
732     $status->configure(-text => "");
733 }
734
735 sub updateInfo {
736     $OID = shift;
737     my $oid = $OID;
738     my $mib = $SNMP::MIB{format_oid("$oid",'numeric')};
739     if (!defined($mib->{'description'}) || $mib->{'description'} eq "") {
740         $oid =~ s/[.0-9]+$//;
741         $mib = $SNMP::MIB{format_oid("$oid",'numeric')};
742     }
743     if (defined($mib)) {
744         if ($mib->{'label'} =~ /Table$/) {
745             $tablebutton->configure(-state => 'normal');
746         } else {
747             $tablebutton->configure(-state => 'disabled');
748         }
749         $mibOID->configure(-text => $mib->{'objectID'});
750         $mibTextOID->configure(-text => 
751                              SNMP::translateObj($mib->{'objectID'},1));
752         $descr->delete('0.0','end');
753         if (defined($mib->{'description'}) && 
754             $mib->{'description'} ne "") {
755             my $desc = $mib->{'description'};
756             $desc =~ s/\n[ \t]+/\n/g;
757             $desc =~ s/^\n//;
758             $descr->insert('end',$desc);
759         }
760         for($i=0; $i<= $#displayInfo;$i++) {
761             $dpyInfo[$i] = $mib->{$displayInfo[$i]};
762             if (ref($dpyInfo[$i]) eq HASH) {
763                 my %hash = %{$dpyInfo[$i]};
764                 $dpyInfo[$i] = "";
765                 foreach $j (sort { $hash{$a} <=> $hash{$b} } keys(%hash)) {
766                     $dpyInfo[$i] .= "$j = $hash{$j},";
767                 }
768             } elsif (ref($dpyInfo[$i]) eq ARRAY) {
769                 $dpyInfo[$i] = join(", ", @{$dpyInfo[$i]});
770             }
771         }
772     }
773 }
774
775 sub optionalWidget {
776     my $num = shift;
777     my $menu = shift;
778     my $var = shift;
779     $menu->checkbutton(-label => $displayInfo[$num], 
780                        -variable => $var,
781                        -command => [\&toggleWidgetShown, $num, $var]);
782 }
783
784 sub createRow {
785     my $i = shift;
786     if (!$displayLabels[$i]) {
787         $displayLabels[$i] = $dispFrame->Label(-pady => $tmpbd, -padx => $tmpbd,
788                                                -text => $displayInfo[$i], 
789                                                -anchor => 'w',
790                                                -borderwidth => $tmpbd);
791     }
792     if (!$displayEntries[$i]) {
793         $displayEntries[$i] = $dispFrame->Entry(-textvariable => \$dpyInfo[$i],
794                                                 -width => 40, -relief => 'flat',
795                                                 -borderwidth => $tmpbd);
796     }
797     $displayLabels[$i]->grid(-ipady => $tmpbd, -ipadx => $tmpbd,
798                              -column => ($i%2)*2, -row => int($i/2),
799                              -sticky => 'w');
800     $dpyInfo[$i] = "" if (!defined($dpyInfo[$i]));
801     $displayEntries[$i]->grid(-ipady => $tmpbd, -ipadx => $tmpbd, -column => ($i%2)*2 + 1, -row => int($i/2), -sticky => 'w');
802 }
803
804 sub toggleWidgetShown {
805     my ($num, $var) = @_;
806     if ($$var) {
807         createRow($num);
808     } else {
809         $displayLabels[$num]->gridForget();
810         $displayEntries[$num]->gridForget()
811     }
812 #    my @widgets = $dispFrame->gridSlaves(-row => $num);
813 }
814
815 sub loadNewMibFile {
816     my $sel = $top->FileSelect();
817     my $file = $sel->Show();
818     if (defined($file)) {
819       SNMP::addMibFiles($file);
820         showChildren("1.3.6.1");
821         showChildren("1.3.6.1");
822     }
823 }
824
825 sub loadNewMibModule {
826     my $tmptop = MainWindow->new();
827     my $var = "";
828     $tmptop->Label(-pady => $tmpbd, -padx => $tmpbd, -text => "Enter a SNMP MIB module name")
829         ->pack(-side => 'top');
830     my $e = $tmptop->Entry(-textvariable => \$var);
831     $e->pack(-side => 'top');
832     $e->bind('<Return>',[\&loadIt,\$var,$tmptop]);
833     my $f = $tmptop->Frame();
834     $f->pack(-side => 'top');
835     $f->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'Ok', -command => [\&loadIt,"",\$var,$tmptop])
836         ->pack(-side => 'left');
837     $f->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'Cancel', -command => [sub { my $wid = shift;
838                                                      $wid->destroy(); },
839                                                $tmptop])
840         ->pack(-side => 'left');
841 }
842
843 sub loadIt {
844     my $var = shift;
845     if ($var ne "") {
846         my $ret = SNMP::loadModules($var);
847         if ($ret) {
848             showChildren("1.3.6.1");
849             showChildren("1.3.6.1");
850             return 1;
851         } else {
852             $status->configure(-text => "Failed reading module $var");
853             return 0;
854         }
855     }
856     return 0;
857 }
858
859 sub stop {
860     $stopit = shift;
861     if ($stopit) {
862         $stopBut->configure(-state => 'disabled');
863     } else {
864         $stopBut->configure(-state => 'normal');
865     }
866 }
867
868 sub entryBox {
869     my $title = shift;
870     my $text = shift;
871     my $var = shift;
872     my $callback = shift;
873     my $top = MainWindow->new();
874     my $newvar = $$var if defined($var);
875     $top->title($title);
876     my $f = $top->Frame();
877     $f->pack(-side => 'top');
878     $f->Label(-pady => $tmpbd, -padx => $tmpbd,
879               -text => $text)->pack(-side => 'left');
880     my $e = $f->Entry(-textvariable => \$newvar);
881     $e->pack(-side => 'left');
882     $f = $top->Frame();
883     $f->pack(-side => 'bottom');
884     my $b = $f->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'Ok', 
885                        -command => [sub { my $w = shift;
886                                           my $v1 = shift;
887                                           my $v2 = shift;
888                                           my $call = shift;
889                                           my $ret = 1;
890                                           $$v1 = $$v2 if defined($v1);
891                                           $ret = $call->($$v2) 
892                                               if defined($call);
893                                           $w->destroy() if ($ret);}, $top, $var,
894                                     \$newvar, $callback]);
895     $b->pack(-side => 'left');
896     $e->bind('<Return>',[$b,'invoke']);
897     $b = $f->Button(-pady => $tmpbd, -padx => $tmpbd, 
898                     -text => 'Cancel', -command => [sub { my $w = shift;
899                                                           $w->destroy();}, $top
900                                                     ]);
901     $b->pack(-side => 'right');
902     $e->bind('<Escape>',[$b,'invoke']);
903     
904 }
905
906 sub findANode {     
907     my $val = shift;
908     my $tag = SNMP::translateObj($val);
909     if ($tag) {
910         showAllChildren($tag);
911         return 1;
912     } else {
913         $top->Dialog(-text => "$val not found")->Show();
914         return 0;
915     }
916 }
917
918 sub test_version {
919     my ($gt, $major, $minor, $sub) = @_;
920     $SNMP::VERSION =~ /(\d)\.(\d).(\d)/;
921     if ($gt) {
922         if ($1 > $major || ($1 == $major && $2 > $minor) || 
923             ($1 == $major && $2 == $minor && $3 >= $sub)) {
924             return 1;
925         }
926     } else {
927         if ($1 < $major || ($1 == $major && $2 < $minor) || ($1 == $major && $2 == $minor && $3 < $sub)) {
928             return 1;
929         }
930     }
931     return 0;
932 }
933
934 sub save_options {
935     my $umask = umask();
936     umask 0077; # make sure its not readable by the world by default.
937     if (!open(O,">$opts{C}")) {
938         warn "can't save to $opts{C}\n";
939         umask $umask;
940         return;
941     }
942     umask $umask;
943     print O Data::Dumper->Dump([\%session_opts], [qw(*session_opts)]);
944     print O Data::Dumper->Dump([\%displayInfoStates], [qw(*displayInfoStates)]);
945     foreach my $var (@saveoptions) {
946         print O Data::Dumper->Dump([$$var], [$var]);
947     }
948     close(O);
949     $status->configure(-text => "saved options to $opts{C}");
950 }
951
952 # returns 1 if $oid2 is below $oid1 in the hierarchy
953 sub is_in_subtree {
954     my ($oid1, $oid2) = @_;
955     # get pure numeric
956     $oid1 = SNMP::translateObj($oid1) if ($oid1 !~ /^[\d\.]*$/);
957     $oid2 = SNMP::translateObj($oid2) if ($oid2 !~ /^[\d\.]*$/);
958
959     # has more on it or is exactly the same
960     return 1 if ($oid2 =~ /^$oid1\./ || $oid2 =~ /^$oid1$/);
961     return 0;
962 }
963
964 sub format_oid {
965     my ($oid, $type) = @_;
966     $oid =~ s/\.$//;
967     $type = $displayoidas if ($type eq "");
968
969     if ($type eq 'numeric') {
970         return SNMP::translateObj($oid) if ($oid !~ /^[\d\.]*$/);
971         return $oid;
972     } elsif ($type eq 'full') {
973         return SNMP::translateObj($oid, 1) if ($oid =~ /^[\d\.]*$/);
974         return SNMP::translateObj(SNMP::translateObj($oid), 1) if ($oid !~ /^\./);
975         return $oid;
976     } elsif ($type eq 'short' || $type eq 'module') {
977         $oid = SNMP::translateObj($oid) if ($oid =~ /^[\d\.]*$/);
978         $oid =~ s/.*\.([a-zA-Z]\w+)\.(.*)/$1.$2/;
979         if ($type eq 'module') {
980             $oid = $SNMP::MIB{format_oid($oid,'numeric')}->{'moduleID'} . "::" . $oid;
981         }
982         return $oid;
983     } elsif ($type eq 'module') {
984         $oid = SNMP::translateObj($oid) if ($oid =~ /^[\d\.]*$/);
985         $oid =~ s/.*\.([a-zA-Z]\w+)\.(.*)/$1.$2/;
986         return $oid;
987     } else {
988         warn 'unknown oid translation type: $type';
989         return $oid;
990     }
991 }
992
993 sub get_oid {
994     my ($var, $type) = @_;
995     return format_oid($var->tag . "." . $var->iid, $type);
996 }