File Coverage

blib/lib/Net/Telnet/Cisco.pm
Criterion Covered Total %
statement 15 350 4.2
branch 0 236 0.0
condition 0 20 0.0
subroutine 5 33 15.1
pod 18 21 85.7
total 38 660 5.7


line stmt bran cond sub pod time code
1             package Net::Telnet::Cisco;
2              
3             #-----------------------------------------------------------------
4             # Net::Telnet::Cisco - interact with a Cisco router
5             #
6             # $Id: Cisco.pm,v 1.52 2002/06/18 17:17:03 jkeroes Exp $
7             #
8             # Todo: Add error and access logging.
9             #
10             # POD documentation at end of file.
11             #
12             #-----------------------------------------------------------------
13              
14             require 5.005;
15              
16 1     1   213536 use strict;
  1         3  
  1         29  
17 1     1   1417 use Net::Telnet 3.02;
  1         51786  
  1         62  
18 1     1   10 use AutoLoader;
  1         7  
  1         12  
19 1     1   56 use Carp;
  1         2  
  1         69  
20              
21 1     1   6 use vars qw($AUTOLOAD @ISA $VERSION $DEBUG);
  1         3  
  1         6190  
22              
23             @ISA = qw(Net::Telnet);
24             $VERSION = '1.10';
25             $^W = 1;
26             $DEBUG = 0;
27             $|++;
28              
29             #------------------------------
30             # Public Methods
31             #------------------------------
32              
33             sub new {
34 0     0 1   my $class = shift;
35              
36 0           my ($self, $host, %args);
37              
38             # Add default prompt to args if none present.
39 0 0         push @_, (-Prompt =>
40             '/(?m:^[\w.-]+\s?(?:\(config[^\)]*\))?\s?[\$#>]\s?(?:\(enable\))?\s*$)/')
41             unless grep /^-?prompt$/i, @_;
42              
43             # There's a new cmd_prompt in town.
44 0 0         $self = $class->SUPER::new(@_) or return;
45              
46 0           *$self->{net_telnet_cisco} = {
47             last_prompt => '',
48             last_cmd => '',
49              
50             always_waitfor_prompt => 1,
51             waitfor_pause => 0.1,
52              
53             autopage => 1,
54              
55             more_prompt => '/(?m:^\s*--More--)/',
56              
57             normalize_cmd => 1,
58              
59             send_wakeup => 0,
60              
61             ignore_warnings => 0,
62             warnings => '/(?mx:^% Unknown VPN
63             |^%IP routing table VRF.* does not exist. Create first$
64             |^%No CEF interface information
65             |^%No matching route to delete$
66             |^%Not all config may be removed and may reappear after reactivating/
67             )/',
68             };
69              
70             ## Parse the args.
71 0 0         if (@_ == 2) { # one positional arg given
    0          
72 0           $host = $_[1];
73             } elsif (@_ > 2) { # named args
74             ## Get the named args.
75 0           %args = @_;
76              
77             ## Parse the errmode named arg first.
78 0           foreach (keys %args) {
79 0 0         $self->errmode($args{$_})
80             if /^-?errmode$/i;
81             }
82              
83             ## Parse all other named args.
84 0           foreach (keys %args) {
85 0 0         if (/^-?always_waitfor_prompt$/i) {
    0          
    0          
    0          
    0          
    0          
86 0           $self->always_waitfor_prompt($args{$_});
87             }
88             elsif (/^-?waitfor_pause$/i) {
89 0           $self->waitfor_pause($args{$_});
90             }
91             elsif (/^-?more_prompt$/i) {
92 0           $self->more_prompt($args{$_});
93             }
94             elsif (/^-?autopage$/i) {
95 0           $self->autopage($args{$_});
96             }
97             elsif (/^-?normalize_cmd$/i) {
98 0           $self->normalize_cmd($args{$_});
99             }
100             elsif (/^-?send_wakeup$/i) {
101 0           $self->send_wakeup($args{$_});
102             }
103             }
104             }
105              
106 0           $self;
107             } # end sub new
108              
109              
110             # The new prompt() stores the last matched prompt for later
111             # fun 'n amusement. You can access this string via $self->last_prompt.
112             #
113             # It also parses out any router errors and stores them in the
114             # correct place, where they can be acccessed/handled by the
115             # Net::Telnet error methods.
116             #
117             # No POD docs for prompt(); these changes should be transparent to
118             # the end-user.
119             sub prompt {
120 0     0 1   my( $self, $prompt ) = @_;
121 0           my( $prev, $stream );
122              
123 0           $stream = $ {*$self}{net_telnet_cisco};
  0            
124 0           $prev = $self->SUPER::prompt;
125              
126             ## Parse args.
127 0 0         if ( @_ == 2 ) {
    0          
128 0 0         defined $prompt or $prompt = '';
129 0           $self->_match_check($prompt);
130 0           $self->SUPER::prompt($prompt);
131             } elsif (@_ > 2) {
132 0           return $self->error('usage: $obj->prompt($match_op)');
133             }
134              
135 0           return $prev;
136             } # end sub prompt
137              
138             # cmd() now parses errors and sticks 'em where they belong.
139             #
140             # This is a routerish error:
141             # routereast#show asdf
142             # ^
143             # % Invalid input detected at '^' marker.
144             #
145             # "show async" is valid, so the "d" of "asdf" raised an error.
146             #
147             # If an error message is found, the following error message
148             # is sent to Net::Telnet's error()-handler:
149             #
150             # Last command and router error:
151             #
152             #
153             sub cmd {
154 0     0 1   my $self = shift;
155 0           my $ok = 1;
156              
157 0           my $normalize = $self->normalize_cmd;
158              
159             # Parse args
160 0 0         if (@_ == 1) {
    0          
161 0           $ {*$self}{net_telnet_cisco}{last_cmd} = $_[0];
  0            
162             } elsif ( @_ >= 2 ) {
163 0           my @args = @_;
164 0           while (my ($k, $v) = splice @args, 0, 2) {
165 0 0         $ {*$self}{net_telnet_cisco}{last_cmd} = $v if $k =~ /^-?[Ss]tring$/;
  0            
166 0 0         $normalize = $v if $k =~ /^-?[Nn]ormalize_cmd$/;
167             }
168             }
169              
170 0           my $cmd = $ {*$self}{net_telnet_cisco}{last_cmd};
  0            
171 0           my $old_ors = $self->output_record_separator;
172 0           my $need_more = 0;
173 0           my @out;
174              
175 0           while(1) {
176             # Send a space (with no newline) whenever we see a "More" prompt.
177 0 0         if ($need_more) {
178 0           $self->output_record_separator('');
179              
180             # We saw a more prompt, so put it in the command output.
181 0           my @tmp = $self->last_prompt;
182              
183             # Send the , taking care not to
184             # discard the top line.
185 0           push @tmp, $self->SUPER::cmd(String => " ", Cmd_remove_mode => 0);
186              
187 0 0         if ($self->normalize_cmd) {
188 0           push @out, _normalize(@tmp);
189             } else {
190 0           push @out, @tmp;
191             }
192             } else {
193 0           $self->output_record_separator($old_ors);
194 0           push @out, $self->SUPER::cmd(@_);
195             }
196              
197             # Look for errors in output
198 0           for ( my ($i, $lastline) = (0, '');
199             $i <= $#out;
200             $lastline = $out[$i++] ) {
201              
202             # This may have to be a pattern match instead.
203 0 0         if ( ( substr $out[$i], 0, 1 ) eq '%' ) {
204 0 0         if ( $out[$i] =~ /'\^' marker/ ) { # Typo & bad arg errors
205 0           chomp $lastline;
206 0           $self->error( join "\n",
207             "Last command and router error: ",
208             ( $self->last_prompt . $cmd ),
209             $lastline,
210             $out[$i],
211             );
212 0           splice @out, $i - 1, 3;
213             } else { # All other errors.
214 0           chomp $out[$i];
215 0           $self->error( join "\n",
216             "Last command and router error: ",
217             ( $self->last_prompt . $cmd ),
218             $out[$i],
219             );
220 0           splice @out, $i, 2;
221             }
222 0           $ok = 0;
223 0           last;
224             }
225             }
226              
227             # Restore old settings
228 0           $self->output_record_separator($old_ors);
229              
230             # redo the while loop if we saw a More prompt.
231 0           my $more_re = $self->re_sans_delims($self->more_prompt);
232 0 0 0       if ($self->autopage && $self->last_prompt =~ /$more_re/) {
233 0           $need_more = 1;
234             } else {
235 0           last;
236             }
237             }
238              
239 0 0         return wantarray ? @out : $ok;
240             }
241              
242              
243             # waitfor now stores prompts to $obj->last_prompt()
244             sub waitfor {
245 0     0 1   my $self = shift;
246              
247 0 0         return unless @_;
248              
249             # $all_prompts will be built into a regex that matches all currently
250             # valid prompts.
251             #
252             # -Match args will be added to this regex. The current prompt will
253             # be appended when all -Matches have been exhausted.
254 0           my $all_prompts = '';
255              
256             # Literal string matches, passed in with -String.
257 0           my @literals = ();
258              
259             # Parse the -Match => '/prompt \$' type options
260             # waitfor can accept more than one -Match argument, so we can't just
261             # hashify the args.
262 0 0         if (@_ >= 2) {
    0          
263 0           my @args = @_;
264 0           while ( my ($k, $v) = splice @args, 0, 2 ) {
265 0 0         if ($k =~ /^-?[Ss]tring$/) {
    0          
266 0           push @literals, $v;
267             } elsif ($k =~ /^-?[Mm]atch$/) {
268 0           $all_prompts = $self->prompt_append($all_prompts, $v);
269             }
270             }
271             } elsif (@_ == 1) {
272             # A single argument is always a -match.
273 0           $all_prompts = $self->prompt_append($all_prompts, $_[0]);
274             }
275              
276 0           my $all_re = $self->re_sans_delims($all_prompts);
277 0           my $prompt_re = $self->re_sans_delims($self->prompt);
278 0           my $more_re = $self->re_sans_delims($self->more_prompt);
279              
280              
281             # Add the current prompt if it's not already there. You can turn this behavior
282             # off by setting always_waitfor_prompt to a false value.
283 0 0 0       if ($self->always_waitfor_prompt && index($all_re, $prompt_re) == -1) {
284 0 0         unshift @_, "-Match" if @_ == 1;
285 0           push @_, (-Match => $self->prompt);
286              
287 0           $all_prompts = $self->prompt_append($all_prompts, $self->prompt);
288 0           $all_re = $self->re_sans_delims($all_prompts);
289             }
290              
291             # Add the more prompt if it's not present. See the autopage() docs
292             # to turn this behaviour off.
293 0 0 0       if ($self->autopage && index($all_re, $more_re) == -1) {
294 0 0         unshift @_, "-Match" if @_ == 1;
295 0           push @_, (-Match => $self->more_prompt);
296              
297 0           $all_prompts = $self->prompt_append($all_prompts, $self->more_prompt);
298 0           $all_re = $self->re_sans_delims($all_prompts);
299             }
300              
301 0 0 0       return $self->error("Godot ain't home - waitfor() isn't waiting for anything.")
302             unless $all_prompts || @literals;
303              
304             # There's a timing issue that I can't quite figure out.
305             # Adding a small pause here seems to make it go away.
306 0           select undef, undef, undef, $self->waitfor_pause;
307              
308 0           my ($prematch, $match) = $self->SUPER::waitfor(@_);
309              
310             # If waitfor saw a prompt then store it.
311 0 0         if ($match) {
312 0           for (@literals) {
313 0 0         if (index $match, $_) {
314 0 0         return wantarray ? ($prematch, $match) : 1;
315             }
316             }
317              
318 0 0         if ($match =~ /($all_re)/m ) {
319 0           $ {*$self}{net_telnet_cisco}{last_prompt} = $1;
  0            
320 0 0         return wantarray ? ($prematch, $match) : 1;
321             }
322             }
323 0 0         return wantarray ? ( $prematch, $match ) : 1;
324             }
325              
326              
327             sub login {
328 0     0 1   my($self) = @_;
329             my(
330 0           $cmd_prompt,
331             $endtime,
332             $error,
333             $lastline,
334             $match,
335             $orig_errmode,
336             $orig_timeout,
337             $prematch,
338             $reset,
339             $timeout,
340             $usage,
341             $sent_wakeup,
342             );
343 0           my ($username, $password, $tacpass, $passcode ) = ('','','','');
344 0           my (%args, %seen);
345              
346 0           local $_;
347              
348             ## Init vars.
349 0           $timeout = $self->timeout;
350 0           $self->timed_out('');
351 0 0         return if $self->eof;
352 0           $cmd_prompt = $self->prompt;
353 0           $sent_wakeup = 0;
354              
355 0 0         print "login:\t[orig: $cmd_prompt]\n" if $DEBUG;
356              
357 0           $usage = 'usage: $obj->login([Name => $name,] [Password => $password,] '
358             . '[Passcode => $passcode,] [Prompt => $matchop,] [Timeout => $secs,])';
359              
360 0 0         if (@_ == 3) { # just username and passwd given
361 0           ($username, $password) = (@_[1,2]);
362             }
363             else { # named args given
364             ## Get the named args.
365 0           (undef, %args) = @_;
366              
367             ## Parse the named args.
368 0           foreach (keys %args) {
369 0 0         if (/^-?name$/i) {
    0          
    0          
    0          
    0          
370 0           $username = $args{$_};
371             } elsif (/^-?passw/i) {
372 0           $password = $args{$_};
373             } elsif (/^-?passcode/i) {
374 0           $passcode = $args{$_};
375             } elsif (/^-?prompt$/i) {
376             # login() always looks for a cmd_prompt. This is not
377             # controllable via always_waitfor_prompt().
378 0           $cmd_prompt = $self->prompt_append($cmd_prompt, $args{$_});
379             } elsif (/^-?timeout$/i) {
380 0           $timeout = _parse_timeout($args{$_});
381             } else {
382 0           return $self->error($usage);
383             }
384             }
385             }
386              
387 0 0         print "login:\t[after args: $cmd_prompt]\n" if $DEBUG;
388              
389             ## Override these user set-able values.
390 0           $endtime = _endtime($timeout);
391 0           $orig_timeout = $self->timeout($endtime);
392 0           $orig_errmode = $self->errmode;
393              
394             ## Create a subroutine to reset to original values.
395             $reset
396             = sub {
397 0     0     $self->errmode($orig_errmode);
398 0           $self->timeout($orig_timeout);
399 0           1;
400 0           };
401              
402             ## Create a subroutine to generate an error for user.
403             $error
404             = sub {
405 0     0     my($errmsg) = @_;
406              
407 0           &$reset;
408 0 0         if ($self->timed_out) {
    0          
409 0           return $self->error($errmsg);
410             } elsif ($self->eof) {
411 0           ($lastline = $self->lastline) =~ s/\n+//;
412 0           return $self->error($errmsg, ": ", $lastline);
413             } else {
414 0           return $self->error($self->errmsg);
415             }
416 0           };
417              
418              
419             # Send a newline as the wakeup-call
420 0 0         if ($self->send_wakeup eq 'connect') {
421              
422 0           $sent_wakeup = 1;
423              
424 0           my $old_sep = $self->output_record_separator;
425              
426 0           $self->output_record_separator("\n");
427 0           $self->print('');
428 0           $self->output_record_separator($old_sep);
429             }
430              
431              
432 0           while (1) {
433 0           (undef, $_) = $self->waitfor(
434             -match => '/(?:[Ll]ogin|[Uu]sername|[Pp]assw(?:or)?d)[:\s]*$/',
435             -match => '/(?i:Passcode)[:\s]*$/',
436             -match => $cmd_prompt,
437             );
438              
439 0 0         unless ($_) {
440 0 0         return &$error("read eof waiting for login or password prompt")
441             if $self->eof;
442              
443             # We timed-out. Send a newline as the wakeup-call.
444 0 0 0       if ($sent_wakeup == 0 && $self->send_wakeup eq 'timeout') {
445              
446 0           $sent_wakeup = 1;
447              
448 0           my $old_sep = $self->output_record_separator;
449              
450 0           $self->output_record_separator("\n");
451 0           $self->print('');
452 0           $self->output_record_separator($old_sep);
453              
454 0           next;
455             }
456              
457 0           return &$error("timed-out during login process");
458             }
459              
460 0           my $cmd_prompt_re = $self->re_sans_delims($cmd_prompt);
461              
462 0 0         if (not defined) {
    0          
    0          
    0          
    0          
463 0           return $self->error("login failed: access denied or bad name, passwd, etc");
464             } elsif (/sername|ogin/) {
465 0 0         $self->print($username) or return &$error("login disconnected");
466 0 0         $seen{login}++ && $self->error("login failed: access denied or bad username");
467             } elsif (/[Pp]assw/) {
468 0 0         $self->print($password) or return &$error("login disconnected");
469 0 0         $seen{passwd}++ && $self->error("login failed: access denied or bad password");
470             } elsif (/(?i:Passcode)/) {
471 0 0         $self->print($passcode) or return &$error("login disconnected");
472 0 0         $seen{passcode}++ && $self->error("login failed: access denied or bad passcode");
473             } elsif (/($cmd_prompt_re)/) {
474 0           &$reset; # Success. Reset obj to default vals before continuing.
475 0           last;
476             } else {
477 0           $self->error("login received unexpected prompt. Aborting.");
478             }
479             }
480              
481 0           1;
482             } # end sub login
483              
484              
485             # Overridden to support ignore_warnings()
486             sub error {
487 0     0 1   my $self = shift;
488              
489             # Ignore warnings
490 0 0         if ($self->ignore_warnings) {
491 0           my $errmsg = join '', @_;
492 0           my $warnings_re = $self->re_sans_delims($self->warnings);
493 0 0         return if $errmsg =~ /$warnings_re/;
494             }
495              
496 0           return $self->SUPER::error(@_);
497             }
498              
499              
500             # Tries to enter enabled mode with the password arg.
501             sub enable {
502 0     0 1   my $self = shift;
503 0           my $usage = 'usage: $obj->enable([Name => $name,] [Password => $password,] '
504             . '[Passcode => $passcode,] [Level => $level] )';
505 0           my ($en_username, $en_password, $en_passcode, $en_level) = ('','','','');
506 0           my ($error, $lastline, $orig_errmode, $reset, %args, %seen);
507              
508 0 0         if (@_ == 1) { # just passwd given
509 0           ($en_password) = shift;
510             } else { # named args given
511 0           %args = @_;
512              
513 0           foreach (keys %args) {
514 0 0         if (/^-?name$|^-?login$|^-?user/i) {
    0          
    0          
    0          
515 0           $en_username = $args{$_};
516             } elsif (/^-?passw/i) {
517 0           $en_password = $args{$_};
518             } elsif (/^-?passc/i) {
519 0           $en_passcode = $args{$_};
520             } elsif (/^-?level$/i) {
521 0           $en_level = $args{$_};
522             } else {
523 0           return $self->error($usage);
524             }
525             }
526             }
527              
528             ## Create a subroutine to generate an error for user.
529             $error = sub {
530 0     0     my($errmsg) = @_;
531              
532 0 0         if ($self->timed_out) {
    0          
533 0           return $self->error($errmsg);
534             } elsif ($self->eof) {
535 0           ($lastline = $self->lastline) =~ s/\n+//;
536 0           return $self->error($errmsg, ": ", $lastline);
537             } else {
538 0           return $self->error($errmsg);
539             }
540 0           };
541              
542             # Store the old prompt without the //s around it.
543 0           my ($old_prompt) = $self->re_sans_delims($self->prompt);
544              
545             # We need to expect either a Password prompt or a
546             # typical prompt. If the user doesn't have enough
547             # access to run the 'enable' command, the device
548             # won't even query for a password, it will just
549             # ignore the command and display another [boring] prompt.
550 0           $self->print("enable $en_level");
551              
552             {
553 0           my ($prematch, $match) = $self->waitfor(
554             -match => '/[Ll]ogin[:\s]*$/',
555             -match => '/[Uu]sername[:\s]*$/',
556             -match => '/[Pp]assw(?:or)?d[:\s]*$/',
557             -match => '/(?i:Passcode)[:\s]*$/',
558             -match => "/$old_prompt/",
559 0 0         ) or do {
560 0 0         return &$error("read eof waiting for enable login or password prompt")
561             if $self->eof;
562 0           return &$error("timed-out waiting for enable login or password prompt");
563             };
564              
565 0 0         if (not defined $match) {
    0          
    0          
    0          
    0          
566 0           return &$error("enable failed: access denied or bad name, passwd, etc");
567             } elsif ($match =~ /sername|ogin/) {
568 0 0         $self->print($en_username) or return &$error("enable failed");
569 0 0         $seen{login}++
570             && return &$error("enable failed: access denied or bad username");
571 0           redo;
572             } elsif ($match =~ /[Pp]assw/ ) {
573 0 0         $self->print($en_password) or return &$error("enable failed");
574 0 0         $seen{passwd}++
575             && return &$error("enable failed: access denied or bad password");
576 0           redo;
577             } elsif ($match =~ /(?i:Passcode)/ ) {
578 0 0         $self->print($en_passcode) or return &$error("enable failed");
579 0 0         $seen{passcode}++
580             && return &$error("enable failed: access denied or bad passcode");
581 0           redo;
582             } elsif ($match =~ /$old_prompt/) {
583             ## Success! Exit the block.
584 0           last;
585             } else {
586 0           return &$error("enable received unexpected prompt. Aborting.");
587             }
588             }
589              
590 0 0 0       if (not defined $en_level or $en_level =~ /^[1-9]/) {
591             # Prompts and levels over 1 give a #/(enable) prompt.
592 0 0         return $self->is_enabled ? 1 : &$error('Failed to enter enable mode');
593             } else {
594             # Assume success
595 0           return 1;
596             }
597             }
598              
599             # Leave enabled mode.
600             sub disable {
601 0     0 1   my $self = shift;
602 0           $self->cmd('disable');
603 0 0         return $self->is_enabled ? $self->error('Failed to exit enabled mode') : 1;
604             }
605              
606             # Send control-^ (without newline)
607             sub ios_break {
608 0     0 1   my $self = shift;
609              
610 0           my $old_ors = $self->output_record_separator;
611 0           $self->output_record_separator('');
612 0           my $ret = $self->print("\c^");
613 0           $self->output_record_separator($old_ors);
614              
615 0           return $ret;
616             }
617              
618             # Displays the last prompt.
619             sub last_prompt {
620 0     0 1   my $self = shift;
621 0           my $stream = $ {*$self}{net_telnet_cisco};
  0            
622 0 0         exists $stream->{last_prompt} ? $stream->{last_prompt} : undef;
623             }
624              
625             # Displays the last command.
626             sub last_cmd {
627 0     0 0   my $self = shift;
628 0           my $stream = $ {*$self}{net_telnet_cisco};
  0            
629 0 0         exists $stream->{last_cmd} ? $stream->{last_cmd} : undef;
630             }
631              
632             # Examines the last prompt to determine the current mode.
633             # Some prompts may be hard set to #, so this won't always return a valid answer.
634             # Call 'show priv' instead.
635             # 1 => enabled.
636             # undef => not enabled.
637 0 0   0 1   sub is_enabled { $_[0]->last_prompt =~ /\#|enable|config/ ? 1 : undef }
638              
639             # Typical get/set method.
640             sub always_waitfor_prompt {
641 0     0 1   my ($self, $arg) = @_;
642 0           my $stream = $ {*$self}{net_telnet_cisco};
  0            
643 0 0         $stream->{always_waitfor_prompt} = $arg if defined $arg;
644 0           return $stream->{always_waitfor_prompt};
645             }
646              
647             # Typical get/set method.
648             sub waitfor_pause {
649 0     0 1   my ($self, $arg) = @_;
650 0           my $stream = $ {*$self}{net_telnet_cisco};
  0            
651 0 0         $stream->{waitfor_pause} = $arg if defined $arg;
652 0           return $stream->{waitfor_pause};
653             }
654              
655             # Typical get/set method.
656             sub autopage {
657 0     0 1   my ($self, $arg) = @_;
658 0           my $stream = $ {*$self}{net_telnet_cisco};
  0            
659 0 0         $stream->{autopage} = $arg if defined $arg;
660 0           return $stream->{autopage};
661             }
662              
663             # Typical get/set method.
664             sub normalize_cmd {
665 0     0 1   my ($self, $arg) = @_;
666 0           my $stream = $ {*$self}{net_telnet_cisco};
  0            
667 0 0         $stream->{normalize_cmd} = $arg if defined $arg;
668 0           return $stream->{normalize_cmd};
669             }
670              
671             # Typical get/set method.
672             sub send_wakeup {
673 0     0 1   my ($self, $arg) = @_;
674 0           my $stream = $ {*$self}{net_telnet_cisco};
  0            
675 0 0         $stream->{send_wakeup} = $arg if defined $arg;
676 0           return $stream->{send_wakeup};
677             }
678              
679             # Typical get/set method.
680             sub ignore_warnings {
681 0     0 1   my ($self, $arg) = @_;
682 0           my $stream = $ {*$self}{net_telnet_cisco};
  0            
683 0 0         $stream->{ignore_warnings} = $arg if defined $arg;
684 0           return $stream->{ignore_warnings};
685             }
686              
687             # Get/set the More prompt
688             sub more_prompt {
689 0     0 1   my ($self, $arg) = @_;
690 0           my $stream = $ {*$self}{net_telnet_cisco};
  0            
691 0 0         if (defined $arg) {
692 0           $self->_match_check($arg);
693 0           $stream->{more_prompt} = $arg;
694             }
695 0           return $stream->{more_prompt};
696             }
697              
698             # Join two or more regexen into one on "|".
699             sub prompt_append {
700 0     0 0   my $self = shift;
701 0   0       my $orig = shift || '';
702 0 0         return $self->error("usage: \$obj->prompt_append(orig, new, [new...])")
703             unless @_;
704              
705 0 0         print "prompt_append:\t[original: $orig]\n" if $DEBUG;
706              
707 0 0         if ($orig) {
708 0 0         if ($self->_match_check($orig)) {
709 0           $orig = $self->re_sans_delims($orig);
710 0 0         return $self->error("Can't parse prompt: '$orig'") unless $orig;
711             }
712             }
713              
714 0           for (@_) {
715 0 0         print "prompt_append:\t[append: $_]\n" if $DEBUG;
716 0 0         if ($self->_match_check($_)) {
717 0           my $re = $self->re_sans_delims($_);
718              
719 0 0         unless ($re) {
720 0           $self->error("Can't parse prompt: '$_'");
721 0           next;
722             }
723              
724 0 0         $orig .= $orig ? "|$re" : $re;
725             }
726             }
727              
728 0 0         print "prompt_append:\t[return: /$orig/]\n\n" if $DEBUG;
729 0           return "/$orig/";
730             }
731              
732             # Return a Net::Telnet regular expression without the delimiters.
733             sub re_sans_delims {
734 0     0 0   my ($self, $str) = @_;
735              
736 0 0         return $self->error("usage: \$obj->re_sans_delims(\$matchop)")
737             unless $str;
738              
739 0           $self->_match_check($str);
740 0           my ($delim, $re) = $str =~ /^\s*m?\s*(\W)(.*)\1\s*$/;
741 0           return $re;
742             }
743              
744             #------------------------------
745             # Private methods
746             #------------------------------
747              
748             # strip backspaces, deletes, kills, and the character they
749             # pertain to, from an array.
750             sub _normalize {
751 0     0     $_ = join "", @_;
752              
753 0           1 while s/[^\cH\c?][\cH\c?]//mg; # ^H ^?
754 0           s/^.*\cU//mg; # ^U
755              
756 0 0         return wantarray ? split /$/mg, $_ : $_; # ORS instead?
757             }
758              
759             # Lifted from Net::Telnet en toto
760             sub _match_check {
761 0     0     my ($self, $code) = @_;
762 0 0         return unless $code;
763              
764 0           my $error;
765 0           my @warns = ();
766              
767 0 0         print "_match_check:\t[Checking: $code]\n" if $DEBUG;
768              
769             ## Use eval to check for syntax errors or warnings.
770             {
771 0           local $SIG{'__DIE__'} = 'DEFAULT';
  0            
772 0     0     local $SIG{'__WARN__'} = sub { push @warns, @_ };
  0            
773 0           local $^W = 1;
774 0           local $_ = '';
775 0           eval "\$_ =~ $code;";
776             }
777 0 0         if ($@) {
    0          
778             ## Remove useless lines numbers from message.
779 0           ($error = $@) =~ s/ at \(eval \d+\) line \d+.?//;
780 0           chomp $error;
781 0           return $self->error("bad match operator: $error");
782             }
783             elsif (@warns) {
784             ## Remove useless lines numbers from message.
785 0           ($error = shift @warns) =~ s/ at \(eval \d+\) line \d+.?//;
786 0           $error =~ s/ while "strict subs" in use//;
787 0           chomp $error;
788 0           return $self->error("bad match operator: $error");
789             }
790              
791 0           1;
792             } # end sub _match_check
793              
794             #------------------------------
795             # Class methods
796             #------------------------------
797              
798             # Look for subroutines in Net::Telnet if we can't find them here.
799             sub AUTOLOAD {
800 0     0     my ($self) = @_;
801 0 0         croak "$self is an [unexpected] object, aborting" if ref $self;
802 0           $AUTOLOAD =~ s/.*::/Net::Telnet::/;
803 0           goto &$AUTOLOAD;
804             }
805              
806             1;
807              
808             __END__