package UPC; use strict; use warnings; use WWW::Mechanize; use HTML::TokeParser; use Date::Parse; use POSIX; use File::Basename qw(dirname); use File::Path qw(make_path); use UPC::Config; sub new { my $type = shift; my %opts = @_; my $self = {}; $opts{ipaddr} ||= '192.168.1.1'; $opts{username} ||= ''; # default password is blank, so this probably works $opts{password} ||= ''; my $ua = new WWW::Mechanize( env_proxy => 0, timeout => 10 ); $ua->credentials( $opts{ipaddr} . ':80', 'Cisco', $opts{username}, $opts{password} ); $self->{ua} = $ua; $self->{ipaddr} = $opts{ipaddr}; $self->{username} = $opts{username}; $self->{password} = $opts{password}; return bless $self, $type; } =pod reset() - reset the modem. returns 0 on failure, 1 on success. =cut sub reset { my $self = shift; my $c = $self->_getpage( 'restart.asp' ); if ( $c ) { my $res = $self->{ua}->submit(); if ( $res->is_success()) { return 1; } } return 0; } sub bootpages { # these pages are only available when booting return [ 'emta', 'signal', 'status', 'log' ] } sub backup { my $self = shift; my $backupfile = shift; my $rawconfig = $self->_getconfig(); my $backupfilename = strftime($backupfile, gmtime()); my $backuppath = dirname($backupfilename); make_path($backuppath, {mode => 0755}); if (open(my $BACKUP, '>', $backupfilename)) { print $BACKUP $rawconfig; return $backupfilename; } return; } sub _getconfig { my $self = shift; my $c = $self->_getpage( 'filename.gwc' ); if ( $c ) { $self->{_config} = new UPC::Config(); $self->{_config}->parsetext( $c ); } return $c; } sub _system { my $self = shift; my $data = { Date => scalar( gmtime( time )) }; my $c = $self->_getpage( 'system.asp' ); if ( $c ) { my $p = new HTML::TokeParser( \$c ); my $label = ""; while( my $t = $p->get_token( "td" )) { my $text = $p->get_trimmed_text( "/td" ); if ( $text !~ /^[[:print:]]/ ) { $text =~ s/^.\s*//; $data->{$label} = $text; # cheap hack last if $label eq "Software Revision"; } else { $text =~ s/^.*\. //; $label = $text; } } } else { $data->{'Cable Modem Status'} = 'Admin Interface not responding'; } $data; } sub _network { my $self = shift; my $c = $self->_getpage( 'RgSetup.asp' ); my $data = { Date => scalar( gmtime( time )) }; if ( $c ) { my $p = new HTML::TokeParser( \$c ); while ( my $t = $p->get_tag( "input" )) { if ( $t->[1]{name} ) { $data->{$t->[1]{name}} = $t->[1]{value}; } } # reset parser, and pull the plain text $p = new HTML::TokeParser( \$c ); while ( my $t = $p->get_tag( "tr" )) { my ( $key, $value ) = ( undef, "" ); my $col = 0; while ( my $t1 = $p->get_tag( "td", "/tr" )) { last if $t1->[0] eq "/tr"; $col++; next if $col == 1; my $text = $p->get_trimmed_text( "/td" ); if ( $col == 2 ) { if ( $text !~ /^[[:print:]]/ ) { $text = 'IPv4 DNS Servers'; $value = $data->{$text}; } $key = $text; } else { if ( $value ) { $value = join( ", ", $value, $text ); } else { $value = $text; } } } next unless defined($key) and defined($value); $key =~ s/:$//; $data->{$key} = $value; } } # data fiddling my $leaselength = $data->{Duration}; my $leaseexpires = $data->{Expires}; $data->{LeaseTime} = time; if ( $leaselength and $leaseexpires ) { my $exp = str2time( $leaseexpires ); my %len = split( /:?\s+/, $leaselength ); # now backtrack, not wholly accurate if ( $exp ) { $data->{LeaseTime} = $exp - $len{S} - ( 60 * $len{M} ) - ( 60 * 60 * $len{H} ) - ( 24 * 60 * 60 * $len{D} ); } } $data; } sub _ip_mgmt { my $self = shift; my $c = $self->_getpage('RgDhcp.asp' ); my @leases; my $p =new HTML::TokeParser(\$c); my $t = $p->get_tag('select'); if (($t->[1]{name}||'') eq 'LeaseToFree' ) { while ( $t = $p->get_tag('option', '/select')) { last if $t->[0] eq '/select'; my $row = $p->get_text('/option'); chomp($row); my @data = split(/\xa0+/, $row); $data[0] = uc($data[0]); $data[0] =~ s/(..)(?=.)/$1:/g; my %data = ( macaddr => $data[0], ipaddr => $data[1], netmask => $data[2], duration => $data[3], expires => $data[4], ); push @leases, \%data; } } \@leases; } sub _getpage { my $self = shift; my $page = shift; my $res = $self->{ua}->get( 'http://' . $self->{ipaddr} . '/' . $page ); my $c; if ( $res->is_success()) { $c = $self->{ua}->content(); } else { $c = ""; } return $c; } 1;