############################################################################### # Net::Whois::RIPE - implementation of RIPE Whois. # Copyright (C) 2005 Paul Gampe, Kevin Baker # vim:tw=78:ts=4 ############################################################################### package Net::Whois::RIPE::Object; use strict; use Carp; my $errstr = ''; sub errstr { $errstr } use vars qw($VERSION $AUTOLOAD); $VERSION = do { my @r = ( q$Revision: 1.3 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; # values not permitted to be added my @NO_ADD = qw( content methods attributes warning error success debug parse size _ok _err _wrn ); my %NO_ADD = map { $_ => 1 } @NO_ADD; my @Free_Form = qw(descr remarks person address role trouble); my %Free_Form = map { $_ => 1 } @Free_Form; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $handle = shift; my $persistance = shift || 0; unless ( $handle and ref($handle) ) { $errstr = 'expected handle not found'; carp "expecting a handle"; return undef; } $errstr = ''; my $self = bless { _methods => {} , # storage for parsed attributes values, lookup by attribute _order => [], # order attributes are saved in _content => [], # untampered text from whois server _debug => 0, # off by default _warn => [], _error => [], }, $class; return $self->parse( $handle, $persistance ) ? $self : undef; } sub parse { my $self = shift; my $handle = shift; my $persistance = shift; my $found_record = 0; my $precedent_attribute; local $/ = "\n"; local $_; my $line_cnt = 0; while ( $_ = <$handle> ) { # walk through the response $line_cnt++; push @{ $self->{_content} }, $_; # save the entire response if ( $self->debug ) { my $received = $_; chomp $received; carp "received ->", $received; } /^The object shown below is NOT in the/ and $self->_err($_); /^\% No entries found\./ and $self->_err('No entries found'); /^\%ERROR:(.*)/ and $self->_err($1), next; /^%/ and next; # skip server comments /^\n$/ and $found_record and last; /^\n$/ and $persistance and last; /^\n$/ and next; chomp; # search for errors, failures and warnings /^(?:New|Delete|Update) FAILED/ and next; # followed by ERROR /^(?:New|Update|Delete) OK:(.*)/ and $self->_ok($1), next; /^\*ERROR\*:\s+(.*)/ and $self->_err($1), next; /^WARNING:\s+(.*)/ and $self->_wrn($1), next; # ok, now try to match attribute value pairs if (my ($value2) = /^\+?\s+(.+)$/ and $precedent_attribute){ $value2 =~ s/#.*$// unless exists $Free_Form{$precedent_attribute}; $value2 =~ s/\s+$//; $self->add($precedent_attribute, $value2); } elsif (my ($attribute, $value) = /^([\w\-]+|\*\w\w):\s+(.*)$/) { # strip end of line comments and trailing white space $value =~ s/#.*$// unless exists $Free_Form{$attribute}; $value =~ s/\s+$//; $self->add( $attribute, $value ); $precedent_attribute = $attribute; $found_record = 1; } else { $self->_err("unparseable line: '$_'"); } } if ( $line_cnt == 0 ) { carp "parse: no lines read from handle" if $self->debug; $errstr = "no lines read from handle"; return 0; } if ( @{ $self->{_content} } == 0 ) { # this should be caught by $line_cnt carp "parse: no content read from handle" if $self->debug; $errstr = "no content read from handle"; return 0; } if ( scalar $self->content =~ /^\s*$/ ) { carp "parse: content is all whitespace" if $self->debug; $errstr = "content is all whitespace"; return 0; } return 1; } sub size { # will only work in the ascii world my $self = shift; return length scalar $self->content; } sub add { my ( $self, $attr, $value ) = @_; unless ( ref($self) and $attr and $value ) { carp "add: expecting an ATTRIBUTE and a VALUE" if $self->debug; return undef; } # don't clobber our method names if ( defined $NO_ADD{$attr} ) { carp "attribute [$attr] is a reserved attribute" if $self->debug; return undef; } carp "adding attribute [$attr] with value [$value]" if $self->debug; # preserve order in which the attributes are registered. # if this ATTRIBUTE has been saved before then do not # place it on the order list again. push @{ $self->{_order} }, $attr unless exists $self->{_methods}->{$attr}; # save the VALUE on the list for that ATTRIBUTE push @{ $self->{_methods}->{$attr} }, $value; } sub content { my $self = shift; return wantarray ? @{ $self->{_content} } : join( '', @{ $self->{_content} } ); } sub methods { return $_[0]->attributes } sub attributes { my $self = shift; return @{ $self->{_order} }; } sub warning { my $self = shift; # local $^W=0; return wantarray ? @{ $self->{_warn} } : join( "\n", @{ $self->{_warn} } ); } sub error { my $self = shift; # local $^W=0; return wantarray ? @{ $self->{_error} } : join( "\n", @{ $self->{_error} } ); } sub success { my $self = shift; return defined @{ $self->{_error} } > 0 ? 0 : 1; } sub debug { my $self = shift; return @_ ? $self->{_debug} = shift: $self->{_debug}; } sub AUTOLOAD { my $self = shift; my $type = ref($self) or croak "$self is not an object"; my $name = $AUTOLOAD; $name =~ s/^.*://; # strip fully-qualified portion $name =~ s/_/-/g; # change _ to - in method name: same as 'add' unless ( exists $self->{_methods}->{$name} ) { carp "I don't know about method `$name' in class $type" if $self->debug; return undef; } # all the attribute values are stored in arrays return wantarray ? @{ $self->{_methods}->{$name} } : $self->{_methods}->{$name}->[0]; } sub DESTROY { } ############################################################################### ## P R I V A T E M E T H O D S ############################################################################### sub _err { my $self = shift; (@_) and push @{ $self->{_error} }, shift } sub push_warn { shift->_wrn(@_) } sub _wrn { my $self = shift; (@_) and push @{ $self->{_warn} }, shift } sub _ok { my ( $self, $text ) = @_; unless ($text) { carp "_ok: can't find TEXT" if $self->debug; return undef; } # New and Update return the nic hdl of the created/updated object # tear out the nic-hdl from the text. example text below. #New OK: [person] KB1-TEST (Kevin Baker) #Update OK: [person] KB1-TEST (Kevin Baker) # I made this a separate routine in case there turn out to be other # cases to match. For instance, a route object. if ( $text =~ /\[person\]\s+([^\s]+)\s+\((.+)\)/ ) { $self->add( 'nic-hdl', $1 ); $self->add( 'person', $2 ); } } 1; __END__