PaxHeader/Net-EPP-0.28000755 777777 777777 00000000102 14777665203 020310 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792195.741554638 Net-EPP-0.28/000755 €JªDI€GÖP;00000000000 14777665203 017145 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/PaxHeader/tidy.sh000755 777777 777777 00000000254 14760316103 021662 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1740741699.542249916 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/tidy.sh000755 €JªDI€GÖP;00000000275 14760316103 020441 0ustar00gavin.brownICANN\Domain Users000000 000000 #!/bin/sh # this runs perltidy for every script and then cleans up after itself DIR="$(dirname "$0")" find "$DIR" -iname '*.p[lm]' | xargs perltidy -b find "$DIR" -iname '*.bak' -delete Net-EPP-0.28/PaxHeader/Changes000644 777777 777777 00000000571 14777665154 021674 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792172.456542117 51 LIBARCHIVE.xattr.com.macromates.visibleIndex=MA 46 SCHILY.xattr.com.macromates.visibleIndex=0 57 LIBARCHIVE.xattr.com.macromates.selectionRange=NTo4NQ 51 SCHILY.xattr.com.macromates.selectionRange=5:85 57 LIBARCHIVE.xattr.com.apple.provenance=AQAAeoKLzynV3q0 49 SCHILY.xattr.com.apple.provenance=z‚‹Ï)ÕÞ­ Net-EPP-0.28/Changes000644 €JªDI€GÖP;00000000250 14777665154 020442 0ustar00gavin.brownICANN\Domain Users000000 000000 Revision history for perl module Net::EPP: 0.28 - 2025-04-16 - added this file. - fixed the XML namespace URI of the RGP extension in Net::EPP::Frame::ObjectSpec. Net-EPP-0.28/PaxHeader/MANIFEST000644 777777 777777 00000000102 14777665203 021513 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792195.822495579 Net-EPP-0.28/MANIFEST000644 €JªDI€GÖP;00000003332 14777665203 020277 0ustar00gavin.brownICANN\Domain Users000000 000000 .perltidyrc Changes lib/Net/EPP.pm lib/Net/EPP/Client.pm lib/Net/EPP/Frame.pm lib/Net/EPP/Frame/Command.pm lib/Net/EPP/Frame/Command/Check.pm lib/Net/EPP/Frame/Command/Check/Contact.pm lib/Net/EPP/Frame/Command/Check/Domain.pm lib/Net/EPP/Frame/Command/Check/Host.pm lib/Net/EPP/Frame/Command/Create.pm lib/Net/EPP/Frame/Command/Create/Contact.pm lib/Net/EPP/Frame/Command/Create/Domain.pm lib/Net/EPP/Frame/Command/Create/Host.pm lib/Net/EPP/Frame/Command/Delete.pm lib/Net/EPP/Frame/Command/Delete/Contact.pm lib/Net/EPP/Frame/Command/Delete/Domain.pm lib/Net/EPP/Frame/Command/Delete/Host.pm lib/Net/EPP/Frame/Command/Info.pm lib/Net/EPP/Frame/Command/Info/Contact.pm lib/Net/EPP/Frame/Command/Info/Domain.pm lib/Net/EPP/Frame/Command/Info/Host.pm lib/Net/EPP/Frame/Command/Login.pm lib/Net/EPP/Frame/Command/Logout.pm lib/Net/EPP/Frame/Command/Poll.pm lib/Net/EPP/Frame/Command/Poll/Ack.pm lib/Net/EPP/Frame/Command/Poll/Req.pm lib/Net/EPP/Frame/Command/Renew.pm lib/Net/EPP/Frame/Command/Renew/Domain.pm lib/Net/EPP/Frame/Command/Transfer.pm lib/Net/EPP/Frame/Command/Transfer/Contact.pm lib/Net/EPP/Frame/Command/Transfer/Domain.pm lib/Net/EPP/Frame/Command/Update.pm lib/Net/EPP/Frame/Command/Update/Contact.pm lib/Net/EPP/Frame/Command/Update/Domain.pm lib/Net/EPP/Frame/Command/Update/Host.pm lib/Net/EPP/Frame/Greeting.pm lib/Net/EPP/Frame/Hello.pm lib/Net/EPP/Frame/ObjectSpec.pm lib/Net/EPP/Frame/Response.pm lib/Net/EPP/Parser.pm lib/Net/EPP/Protocol.pm lib/Net/EPP/ResponseCodes.pm lib/Net/EPP/Simple.pm Makefile.PL MANIFEST This list of files README.md t/use.t tidy.sh META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Net-EPP-0.28/PaxHeader/t000755 777777 777777 00000000102 14777665202 020552 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.485388851 Net-EPP-0.28/t/000755 €JªDI€GÖP;00000000000 14777665202 017407 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/PaxHeader/README.md000644 777777 777777 00000000254 14760316103 021631 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1740741699.533643864 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/README.md000644 €JªDI€GÖP;00000003717 14760316103 020414 0ustar00gavin.brownICANN\Domain Users000000 000000 # NAME Net::EPP - a Perl library for the Extensible Provisioning Protocol (EPP). # DESCRIPTION EPP is the Extensible Provisioning Protocol. EPP (defined in [STD 69](https://www.rfc-editor.org/info/std69)) is an application-layer client-server protocol for the provisioning and management of objects stored in a shared central repository. Specified in XML, the protocol defines generic object management operations and an extensible framework that maps protocol operations to objects. As of writing, its only well-developed application is the provisioning of domain names, hosts, and related contact details. This package offers a number of Perl modules which implement various EPP- related functions: - a low-level protocol implementation ([Net::EPP::Protocol](https://metacpan.org/pod/Net%3A%3AEPP%3A%3AProtocol)); - a low-level client ([Net::EPP::Client](https://metacpan.org/pod/Net%3A%3AEPP%3A%3AClient)); - a high(er)-level client ([Net::EPP::Simple](https://metacpan.org/pod/Net%3A%3AEPP%3A%3ASimple)); - an EPP frame builder ([Net::EPP::Frame](https://metacpan.org/pod/Net%3A%3AEPP%3A%3AFrame)); - a utility library to export EPP response codes ([Net::EPP::ResponseCodes](https://metacpan.org/pod/Net%3A%3AEPP%3A%3AResponseCodes)). # SEE ALSO - [Net::EPP::Server](https://metacpan.org/pod/Net%3A%3AEPP%3A%3AServer) - an EPP server implementation. - [App::pepper](https://metacpan.org/pod/App%3A%3Apepper) - a command-line EPP client. # AUTHORS This module is maintained by [Gavin Brown](https://metacpan.org/author/GBROWN), with the assistance of other contributors around the world, including (but not limited to): - Rick Jansen - Mike Kefeder - Sage Weil - Eberhard Lisse - Yulya Shtyryakova - Ilya Chesnokov - Simon Cozens - Patrick Mevzek - Alexander Biehl - Christian Maile - Tony Finch # COPYRIGHT This module is (c) 2008 - 2023 CentralNic Ltd and 2024 Gavin Brown. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Net-EPP-0.28/PaxHeader/META.yml000644 777777 777777 00000000102 14777665202 021632 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.920934564 Net-EPP-0.28/META.yml000644 €JªDI€GÖP;00000001462 14777665202 020420 0ustar00gavin.brownICANN\Domain Users000000 000000 --- abstract: 'a Perl library for the Extensible Provisioning Protocol (EPP).' author: - 'Gavin Brown ' build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Net-EPP no_index: directory: - t - inc requires: Digest::SHA: '0' IO::Socket::IP: '0' IO::Socket::SSL: '0' List::Util: '0' Time::HiRes: '0' XML::LibXML: '0' resources: bugtracker: https://github.com/gbxyz/perl-net-epp/issues repository: https://github.com/gbxyz/perl-net-epp.git version: '0.28' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Net-EPP-0.28/PaxHeader/lib000755 777777 777777 00000000102 14777665202 021055 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.474399982 Net-EPP-0.28/lib/000755 €JªDI€GÖP;00000000000 14777665202 017712 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/PaxHeader/Makefile.PL000755 777777 777777 00000000216 14760316103 022325 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/Makefile.PL000755 €JªDI€GÖP;00000001655 14760316103 021111 0ustar00gavin.brownICANN\Domain Users000000 000000 #!perl use ExtUtils::MakeMaker; use strict; WriteMakefile( 'NAME' => 'Net::EPP', 'VERSION_FROM' => 'lib/Net/EPP.pm', 'ABSTRACT_FROM' => 'lib/Net/EPP.pm', 'AUTHOR' => ['Gavin Brown '], 'LICENSE' => 'perl', 'PREREQ_PM' => { 'Digest::SHA' => 0, 'IO::Socket::SSL' => 0, 'IO::Socket::IP' => 0, 'List::Util' => 0, 'Time::HiRes' => 0, 'XML::LibXML' => 0, }, 'META_MERGE' => { 'meta-spec' => {'version' => 2}, 'resources' => { 'repository' => { 'type' => 'git', 'url' => 'https://github.com/gbxyz/perl-net-epp.git', 'web' => 'https://github.com/gbxyz/perl-net-epp', }, 'bugtracker' => { 'web' => 'https://github.com/gbxyz/perl-net-epp/issues', }, }, }, ); Net-EPP-0.28/PaxHeader/.perltidyrc000644 777777 777777 00000000254 14760316103 022534 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1740741699.533255288 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/.perltidyrc000644 €JªDI€GÖP;00000000140 14760316103 021302 0ustar00gavin.brownICANN\Domain Users000000 000000 -l=4096 -i=4 -ci=4 -ce -nsbl --weld-nested-containers -sot -sct -pt=2 -sbt=2 -bt=2 -bbt=0 -nolq Net-EPP-0.28/PaxHeader/META.json000644 777777 777777 00000000102 14777665203 022003 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792195.735383511 Net-EPP-0.28/META.json000644 €JªDI€GÖP;00000002630 14777665203 020567 0ustar00gavin.brownICANN\Domain Users000000 000000 { "abstract" : "a Perl library for the Extensible Provisioning Protocol (EPP).", "author" : [ "Gavin Brown " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Net-EPP", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Digest::SHA" : "0", "IO::Socket::IP" : "0", "IO::Socket::SSL" : "0", "List::Util" : "0", "Time::HiRes" : "0", "XML::LibXML" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/gbxyz/perl-net-epp/issues" }, "repository" : { "type" : "git", "url" : "https://github.com/gbxyz/perl-net-epp.git", "web" : "https://github.com/gbxyz/perl-net-epp" } }, "version" : "0.28", "x_serialization_backend" : "JSON::PP version 4.16" } Net-EPP-0.28/lib/PaxHeader/Net000755 777777 777777 00000000102 14777665202 021603 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.488059327 Net-EPP-0.28/lib/Net/000755 €JªDI€GÖP;00000000000 14777665202 020440 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/PaxHeader/EPP.pm000644 777777 777777 00000000535 14777664661 022661 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 51 LIBARCHIVE.xattr.com.macromates.visibleIndex=MA 46 SCHILY.xattr.com.macromates.visibleIndex=0 58 LIBARCHIVE.xattr.com.macromates.selectionRange=MTA6MjE 52 SCHILY.xattr.com.macromates.selectionRange=10:21 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP.pm000644 €JªDI€GÖP;00000004015 14777664661 021432 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP; use vars qw($VERSION); use Net::EPP::Client; use Net::EPP::Frame; use Net::EPP::Protocol; use Net::EPP::ResponseCodes; use Net::EPP::Simple; use strict; our $VERSION = '0.28'; 1; __END__ =pod =head1 NAME Net::EPP - a Perl library for the Extensible Provisioning Protocol (EPP). =head1 DESCRIPTION EPP is the Extensible Provisioning Protocol. EPP (defined in L) is an application-layer client-server protocol for the provisioning and management of objects stored in a shared central repository. Specified in XML, the protocol defines generic object management operations and an extensible framework that maps protocol operations to objects. As of writing, its only well-developed application is the provisioning of domain names, hosts, and related contact details. This package offers a number of Perl modules which implement various EPP- related functions: =over =item * a low-level protocol implementation (L); =item * a low-level client (L); =item * a high(er)-level client (L); =item * an EPP frame builder (L); =item * a utility library to export EPP response codes (L). =back =head1 SEE ALSO =over =item * L - an EPP server implementation. =item * L - a command-line EPP client. =back =head1 AUTHORS This module is maintained by L, with the assistance of other contributors around the world, including (but not limited to): =over =item * Rick Jansen =item * Mike Kefeder =item * Sage Weil =item * Eberhard Lisse =item * Yulya Shtyryakova =item * Ilya Chesnokov =item * Simon Cozens =item * Patrick Mevzek =item * Alexander Biehl =item * Christian Maile =item * Tony Finch =back =head1 COPYRIGHT This module is (c) 2008 - 2023 CentralNic Ltd and 2024 Gavin Brown. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Net-EPP-0.28/lib/Net/PaxHeader/EPP000755 777777 777777 00000000102 14777665202 022227 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.492762069 Net-EPP-0.28/lib/Net/EPP/000755 €JªDI€GÖP;00000000000 14777665202 021064 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/PaxHeader/Protocol.pm000644 777777 777777 00000000216 14760316103 024427 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Protocol.pm000644 €JªDI€GÖP;00000007301 14760316103 023205 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Protocol; use bytes; use Carp; use vars qw($THRESHOLD); use strict; =pod =head1 NAME Net::EPP::Protocol - Low-level functions useful for both EPP clients and servers. =head1 SYNOPSIS #!/usr/bin/perl use Net::EPP::Protocol; use strict; # send a frame down a socket: Net::EPP::Protocol->send_frame($socket, $xml); # get a frame from a socket: my $xml = Net::EPP::Protocol->get_frame($socket); =head1 DESCRIPTION This module implements functions that are common to both EPP clients and servers that implement the TCP/TLS transport of the L as defined in L. The only user of this module is L, but it may be useful if you want to write an EPP server. =head1 VARIABLES =head2 $Net::EPP::Protocol::THRESHOLD At least one EPP server implementation sends an unframed plain text error message when a client connects from an unauthorised address. As a result, when the first four bytes of the message are unpacked, the client tries to read and allocate a very large amount of memory. If the apparent frame length received from a server exceeds the value of C<$Net::EPP::Protocol::THRESHOLD>, the C method will croak. The default value is 1GB. =cut BEGIN { our $THRESHOLD = 1000000000; } =pod =head1 METHODS my $xml = Net::EPP::Protocol->get_frame($socket); This method reads a frame from the socket and returns a scalar containing the XML. C<$socket> must be an L or one of its subclasses (ie C). If the transmission fails for whatever reason, this method will C, so be sure to enclose it in an C. =cut sub get_frame { my ($class, $fh) = @_; my $hdr; if (!defined($fh->read($hdr, 4))) { croak("Got a bad frame length from peer - connection closed?"); } else { my $length = (unpack('N', $hdr) - 4); if ($length < 0) { croak("Got a bad frame length from peer - connection closed?"); } elsif (0 == $length) { croak('Frame length is zero'); } elsif ($length > $THRESHOLD) { croak("Frame length is $length which exceeds $THRESHOLD"); } else { my $xml = ''; my $buffer; while (length($xml) < $length) { $buffer = ''; $fh->read($buffer, ($length - length($xml))); last if (length($buffer) == 0); # in case the socket has closed $xml .= $buffer; } return $xml; } } } =pod Net::EPP::Protocol->send_frame($socket, $xml); This method prepares an RFC 5734 compliant EPP frame and transmits it to the remote peer. C<$socket> must be an L or one of its subclasses (ie C). If the transmission fails for whatever reason, this method will C, so be sure to enclose it in an C. Otherwise, it will return a true value. =cut sub send_frame { my ($class, $fh, $xml) = @_; $fh->print($class->prep_frame($xml)); $fh->flush; return 1; } =pod my $frame = Net::EPP::Protocol->prep_frame($xml); This method returns the XML frame in "wire format" with the protocol header prepended to it. The return value can be printed directly to an open socket, for example: print STDOUT Net::EPP::Protocol->prep_frame($frame->toString); =cut sub prep_frame { my ($class, $xml) = @_; return pack('N', length($xml) + 4) . $xml; } 1; =pod =head1 COPYRIGHT This module is (c) 2008 - 2023 CentralNic Ltd and 2024 Gavin Brown. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Net-EPP-0.28/lib/Net/EPP/PaxHeader/Client.pm000755 777777 777777 00000000216 14760316103 024047 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Client.pm000755 €JªDI€GÖP;00000021765 14760316103 022637 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Client; use Carp; use IO::Socket::IP; use IO::Socket::SSL; use Net::EPP::Parser; use Net::EPP::Frame::Response; use Net::EPP::Protocol; use bytes; use strict; use warnings; =pod =head1 NAME Net::EPP::Client - a client library for the L of the L. =head1 SYNOPSIS #!/usr/bin/perl use Net::EPP::Client; use strict; my $epp = Net::EPP::Client->new('host' => 'epp.nic.tld'); my $greeting = $epp->connect; $epp->send_frame('login.xml'); my $answer = $epp->get_frame; my $answer = $epp->request(''); =head1 DESCRIPTION L defines a TCP- (and TLS-) based transport model for EPP, and this module implements a client for that model. You can establish and manage EPP connections and send and receive responses over this connection. C is a low-level EPP client. If you are writing applications, you should use L instead. =head1 CONSTRUCTOR my $epp = Net::EPP::Client->new(%PARAMS); The constructor method creates a new EPP client object. It accepts a number of parameters: =over =item * C MANDATORY. Specifies the computer to connect to. This may be a DNS hostname or an IP address. If a hostname is provided, IPv6 will be used if available. =item * C OPTIONAL. Specifies the TCP port to connect to. This defaults to C<700>. =item * C OPTIONAL. If the value of this parameter is false, then a plaintext connection will be created. Otherwise, L will be used to provide an encrypted connection. =item * C DEPRECATED. If the value of this parameter is false, then the C and C methods (see below) will return strings instead of C objects. =back =cut sub new { my ($package, %params) = @_; my $self; # # this is an undocumented and unsupported feature that allows clients to # connect to a local Unix socket instead of a TCP service. IIRC the only # use case for this was the old Net::EPP::Proxy module which went away ð‘› # decades ago, and it will be removed in a future release. # if (defined($params{'sock'})) { $self = { 'sock' => $params{'sock'}, 'ssl' => 0, }; } else { croak("missing hostname") if (!defined($params{'host'})); $self = { 'host' => $params{'host'}, 'port' => $params{'port'} || 700, # # since v0.27, TLS is enabled by default and must be explicitly # disabled. # 'ssl' => (exists($params{'ssl'}) && !$params{'ssl'} ? 0 : 1), }; } # # this option will also be removed in a future release. # $self->{'frames'} = (exists($params{'frames'}) && !$params{'frames'} ? 0 : 1); return bless($self, $package); } =pod =head1 METHODS =head2 CONNECTING TO A SERVER my $greeting = $epp->connect(%PARAMS); This method establishes the TCP connection. You can use the C<%PARAMS> hash to specify arguments that will be passed on to the constructors for L (such as a timeout) or L (such as certificate information). Which of these modules will be used is determined by the C parameter that was provided when instantiating the object. See the relevant manpage for examples. This method will C if connection fails, so be sure to use C if you want to catch the error. By default, the return value for C will be the EPP EgreetingE frame returned by the server. Please note that the same caveat about blocking applies to this method as to C (see below). If you want to get the greeting yourself, set C<$params{no_greeting}> to C<1>. If TLS is enabled, then you can use C<%params> to configure a client certificate and/or server certificate validation behaviour. =cut sub connect { my ($self, %params) = @_; croak('already connected') if ($self->connected); if (defined($self->{'sock'})) { $self->_connect_unix(%params); } else { $self->_connect_tcp(%params); } return ($params{'no_greeting'} ? 1 : $self->get_frame); } sub _connect_tcp { my ($self, %params) = @_; my $class = ($self->{'ssl'} == 1 ? 'IO::Socket::SSL' : 'IO::Socket::IP'); $self->{'connection'} = $class->new( 'PeerAddr' => $self->{'host'}, 'PeerPort' => $self->{'port'}, 'Proto' => 'tcp', 'Type' => SOCK_STREAM, %params ); if (!defined($self->{'connection'}) || ($@ && $@ ne '')) { chomp($@); $@ =~ s/^$class:? ?//; croak("Connection to $self->{'host'}:$self->{'port'} failed: $@"); } return 1; } sub _connect_unix { my ($self, %params) = @_; $self->{'connection'} = IO::Socket::UNIX->new( 'Peer' => $self->{'sock'}, 'Type' => SOCK_STREAM, %params ); if (!defined($self->{'connection'}) || ($@ && $@ ne '')) { croak("Connection to $self->{'host'}:$self->{'port'} failed: $@"); } return 1; } =pod =head2 COMMUNICATING WITH THE SERVER my $answer = $epp->request($question); This is a simple wrapper around C and C (see below). This method accepts a "question" frame as an argument, sends it to the server, and then returns the next frame the server sends back. =cut sub request { my ($self, $frame) = @_; return $self->get_frame if ($self->send_frame($frame)); } =pod =head2 GETTING A FRAME FROM THE SERVER my $frame = $epp->get_frame; This method returns an EPP response frame from the server. This will be a L object unless the C argument to the constructor was false, in which case it will be a string containing a blob of XML. B: this method will block your program until it receives the full frame from the server. That could be a bad thing for your program, so you might want to consider using the C function to apply a timeout, like so: my $timeout = 10; # ten seconds eval { local $SIG{ALRM} = sub { die "alarm\n" }; alarm($timeout); my $frame = $epp->get_frame; alarm(0); }; if ($@ ne '') { alarm(0); print "timed out\n"; } If the connection to the server closes before the response can be received, or the server returned a mal-formed frame, this method will C. =cut sub get_frame { my $self = shift; return $self->parse_response(Net::EPP::Protocol->get_frame($self->connection)); } sub parse_response { my ($self, $xml) = @_; my $doc; eval { $doc = $self->parser->parse_string($xml) }; if (!defined($doc) || $@ ne '') { chomp($@); croak(sprintf("Frame from server wasn't well formed: %s\n\nThe XML looks like this:\n\n%s\n\n", $@, $xml)); } else { return bless($doc, 'Net::EPP::Frame::Response'); } } =pod =head2 SENDING A FRAME TO THE SERVER $epp->send_frame($frame); This sends a request frame to the server. C<$frame> may be one of: =over =item * a scalar containing XML =item * a scalar containing a filename =item * an L object (or an instance of a subclass) =item * an L object (or an instance of a subclass) =back =cut sub send_frame { my ($self, $frame) = @_; my $xml; if ($frame->isa('XML::DOM::Document') || $frame->isa('XML::LibXML::Document')) { $xml = $frame->toString; } elsif ($frame !~ /); close(FRAME); } } else { $xml = $frame; } return Net::EPP::Protocol->send_frame($self->connection, $xml); } =pod =head2 DISCONNECTING FROM THE SERVER $epp->disconnect; This closes the connection. An EPP server should always close a connection after a ElogoutE frame has been received and acknowledged; this method is provided to allow you to clean up on the client side, or close the connection out of sync with the server. =cut sub disconnect { my $self = shift; if ($self->connected) { $self->connection->close; delete($self->{'connection'}); } return 1; } sub parser { my $self = shift; $self->{'parser'} = Net::EPP::Parser->new if (!$self->{'parser'}); return $self->{'parser'}; } =pod $connected = $epp->connected; Returns a boolean if C has a connection to the server. Note that this connection might have dropped, use C to test it. =cut sub connected { defined(shift->connection) } =pod $socket = $epp->connection; Returns the underlying socket. =cut sub connection { shift->{'connection'} } 1; =pod =head1 COPYRIGHT This module is (c) 2008 - 2023 CentralNic Ltd and 2024 Gavin Brown. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Net-EPP-0.28/lib/Net/EPP/PaxHeader/Frame000755 777777 777777 00000000101 14777665202 023260 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 29 mtime=1744792194.49125885 Net-EPP-0.28/lib/Net/EPP/Frame/000755 €JªDI€GÖP;00000000000 14777665202 022116 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/PaxHeader/Parser.pm000644 777777 777777 00000000216 14760316103 024062 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Parser.pm000644 €JªDI€GÖP;00000001035 14760316103 022636 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Parser; use base qw(XML::LibXML); use strict; use warnings; =pod =head1 NAME Net::EPP::Parser - a wrapper around the LibXML parser. =head1 DESCRIPTION Nothing to see here, move along. =cut sub new { my $package = shift; my $self = bless($package->SUPER::new(@_), $package); return $self; } 1; =pod =head1 COPYRIGHT This module is (c) 2008 - 2023 CentralNic Ltd and 2024 Gavin Brown. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Net-EPP-0.28/lib/Net/EPP/PaxHeader/ResponseCodes.pm000644 777777 777777 00000000216 14760316103 025402 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/ResponseCodes.pm000644 €JªDI€GÖP;00000012410 14760316103 024155 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::ResponseCodes; use base qw(Exporter); use vars qw(@EXPORT); use strict; =head1 NAME Net::EPP::ResponseCodes - a module to export some constants that correspond to EPP response codes. =head1 SYNOPSIS use Net::EPP::ResponseCodes; use Net::EPP::Simple; use strict; my $epp = Net::EPP::Simple->new( host => 'epp.nic.tld', user => 'my-id', pass => 'my-password', ); my $result = $epp->domain_transfer_request('example.tld', 'foobar', 1); if ($result) { print "Transfer initiated OK\n"; } else { if ($Net::EPP::Simple::Code == OBJECT_PENDING_TRANSFER) { print "Error: domain is already pending transfer\n"; } elsif ($Net::EPP::Simple::Code == INVALID_AUTH_INFO) { print "Error: invalid authcode provided\n"; } elsif ($Net::EPP::Simple::Code == OBJECT_DOES_NOT_EXIST) { print "Error: domain not found\n"; } elsif ($Net::EPP::Simple::Code == STATUS_PROHIBITS_OP) { print "Error: domain cannot be transferred\n"; } else { print "Error code $Net::EPP::Simple::Code\n"; } } =head1 DESCRIPTION Every response sent to the client by an EPP server contains at least one CresultE> element that has a C attribute. This is a four-digit numeric code that describes the result of the request. This module exports a set of constants that provide handy mnemonics for each of the defined codes. =head1 EXPORTS C exports the following constants. The number in brackets is the integer value associated with the constant. =head2 Successful command completion responses (1nnn) =over =item OK (1000) =item OK_PENDING (1001) =item OK_NO_MESSAGES (1300) =item OK_MESSAGES (1301) =item OK_BYE (1500) =back =head2 Command error responses (2nnn) =head3 Protocol Syntax =over =item UNKNOWN_COMMAND (2000) =item SYNTAX_ERROR (2001) =item USE_ERROR (2002) =item MISSING_PARAM (2003) =item PARAM_RANGE_ERROR (2004) =item PARAM_SYNTAX_ERROR (2005) =back =head3 Implementation-specific Rules =over =item UNIMPLEMENTED_VERSION (2100) =item UNIMPLEMENTED_COMMAND (2101) =item UNIMPLEMENTED_OPTION (2102) =item UNIMPLEMENTED_EXTENSION (2103) =item BILLING_FAILURE (2104) =item NOT_RENEWABLE (2105) =item NOT_TRANSFERRABLE (2106) =back =head3 Security (22nn) =over =item AUTHENTICATION_ERROR (2200) =item AUTHORISATION_ERROR (2201) =item AUTHORIZATION_ERROR (2201) =item INVALID_AUTH_INFO (2202) =back =head3 Data Management (23nn) =over =item OBJECT_PENDING_TRANSFER (2300) =item OBJECT_NOT_PENDING_TRANSFER (2301) =item OBJECT_EXISTS (2302) =item OBJECT_DOES_NOT_EXIST (2303) =item STATUS_PROHIBITS_OP (2304) =item ASSOC_PROHIBITS_OP (2305) =item PARAM_POLICY_ERROR (2306) =item UNIMPLEMENTED_OBJECT_SERVICE (2307) =item DATA_MGMT_POLICY_VIOLATION (2308) =back =head3 Server System (24nn) =over =item COMMAND_FAILED (2400) =back =head3 Connection Management (25nn) =over =item COMMAND_FAILED_BYE (2500) =item AUTH_FAILED_BYE (2501) =item SESSION_LIMIT_EXCEEDED_BYE (2502) =back =head1 COPYRIGHT This module is (c) 2008 - 2023 CentralNic Ltd and 2024 Gavin Brown. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut # # Successful command completion responses: # use constant OK => 1000; use constant OK_PENDING => 1001; use constant OK_NO_MESSAGES => 1300; use constant OK_MESSAGES => 1301; use constant OK_BYE => 1500; # # Command error responses: # # Protocol Syntax: use constant UNKNOWN_COMMAND => 2000; use constant SYNTAX_ERROR => 2001; use constant USE_ERROR => 2002; use constant MISSING_PARAM => 2003; use constant PARAM_RANGE_ERROR => 2004; use constant PARAM_SYNTAX_ERROR => 2005; # Implementation-specific Rules: use constant UNIMPLEMENTED_VERSION => 2100; use constant UNIMPLEMENTED_COMMAND => 2101; use constant UNIMPLEMENTED_OPTION => 2102; use constant UNIMPLEMENTED_EXTENSION => 2103; use constant BILLING_FAILURE => 2104; use constant NOT_RENEWABLE => 2105; use constant NOT_TRANSFERRABLE => 2106; # Security: use constant AUTHENTICATION_ERROR => 2200; use constant AUTHORISATION_ERROR => 2201; use constant AUTHORIZATION_ERROR => 2201; use constant INVALID_AUTH_INFO => 2202; # Data Management: use constant OBJECT_PENDING_TRANSFER => 2300; use constant OBJECT_NOT_PENDING_TRANSFER => 2301; use constant OBJECT_EXISTS => 2302; use constant OBJECT_DOES_NOT_EXIST => 2303; use constant STATUS_PROHIBITS_OP => 2304; use constant ASSOC_PROHIBITS_OP => 2305; use constant PARAM_POLICY_ERROR => 2306; use constant UNIMPLEMENTED_OBJECT_SERVICE => 2307; use constant DATA_MGMT_POLICY_VIOLATION => 2308; # Server System: use constant COMMAND_FAILED => 2400; # Connection Management: use constant COMMAND_FAILED_BYE => 2500; use constant AUTH_FAILED_BYE => 2501; use constant SESSION_LIMIT_EXCEEDED_BYE => 2502; our @EXPORT; my $package = __PACKAGE__; foreach my $constant (keys(%constant::declared)) { if ($constant =~ /^$package/) { $constant =~ s/^$package\:\://; push(@EXPORT, $constant); } } 1; Net-EPP-0.28/lib/Net/EPP/PaxHeader/Frame.pm000755 777777 777777 00000000216 14760316103 023663 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame.pm000755 €JªDI€GÖP;00000016726 14760316103 022454 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame; use Carp; use Net::EPP::Frame::Command; use Net::EPP::Frame::Greeting; use Net::EPP::Frame::Hello; use Net::EPP::Frame::ObjectSpec; use Net::EPP::Frame::Response; use POSIX qw(strftime); use XML::LibXML; use base qw(XML::LibXML::Document); use vars qw($EPP_URN); use strict; our $EPP_URN = 'urn:ietf:params:xml:ns:epp-1.0'; =pod =head1 NAME Net::EPP::Frame - An EPP XML frame system built on top of L. =head1 SYNOPSIS #!/usr/bin/perl use Net::EPP::Client; use Net::EPP::Frame; use Net::EPP::ObjectSpec; use Digest::MD5 qw(md5_hex); use Time::HiRes qw(time); use strict; # # establish a connection to an EPP server: # my $epp = Net::EPP::Client->new( host => 'epp.registry.tld', port => 700, ssl => 1, dom => 1, ); my $greeting = $epp->connect; # # log in: # my $login = Net::EPP::Frame::Command::Login->new; $login->clID->appendText($userid); $login->pw->appendText($passwd); # # set the client transaction ID: # $login->clTRID->appendText(md5_hex(Time::HiRes::time().$$)); # # check the response from the log in: # my $answer = $epp->request($login); my $result = ($answer->getElementsByTagName('result'))[0]; if ($result->getAttribute('code') != 1000) { die("Login failed!"); } # # OK, let's do a domain name check: # my $check = Net::EPP::Frame::Command::Check->new; # # get the spec from L: # my @spec = Net::EPP::Frame::ObjectSpec->spec('domain'); # # create a domain object using the spec: # my $domain = $check->addObject(@spec); # # set the domain name we want to check: # my $name = $check->createElement('domain:name'); $name->appendText('example.tld'); # # set the client transaction ID: # $check->clTRID->appendText(md5_hex(time().$$)); # # assemble the frame: # $domain->addChild($name); # # send the request: # my $answer = $epp->request($check); # and so on... =head1 DESCRIPTION The L uses XML documents called "frames" send data to and from clients and servers. This module implements a subclass of the L module that simplifies the process of creation of these frames. It is designed to be used alongside the L and L modules, but could also be used on the server side. =head1 OBJECT HIERARCHY L +----L +----L =head1 USAGE As a rule, you will not need to create C objects directly. Instead, you should use one of the subclasses included with the distribution. The subclasses all inherit from C. C is itself a subclass of L so all the methods available from that class are also available to instances of C. The available subclasses of C exist to add any additional elements required by the EPP specification. For example, the EloginE frame must contain the EclIDE and EpwE frames, so when you create a new L object, you get these already defined. These classes also have convenience methods, so for the above example, you can call the C<$login-EclID> and C<$login-Epw> methods to get the L objects correesponding to those elements. =head2 RATIONALE You could just as easily construct your EPP frames from templates or just lots of C calls. But using a programmatic approach such as this strongly couples the validity of your XML to the validity of your program. If the process by which your XML is built is broken, I. This has to be a win. =cut sub new { my ($package, $type) = @_; if (!$type) { my @parts = split(/::/, $package); $type = lc(pop(@parts)); } if ($type !~ /^(hello|greeting|command|response)$/) { croak("'type' parameter to Net::EPP::Frame::new() must be one of: hello, greeting, command, response ('$type' given)."); return undef; } my $self = $package->SUPER::new('1.0', 'UTF-8'); bless($self, $package); my $epp = $self->createElementNS($EPP_URN, 'epp'); $self->addChild($epp); my $el = $self->createElement($type); $epp->addChild($el); $self->_addExtraElements; return $self; } sub _addExtraElements { } =pod =head1 ADDITIONAL METHODS my $str = $frame->formatTimeStamp($timestamp); This method returns a scalar in the required format (defined in RFC 3339). This is a convenience method. =cut sub formatTimeStamp { my ($self, $stamp) = @_; return strftime('%Y-%m-%dT%H:%M:%S.0Z', gmtime($stamp)); } =pod my $node = $frame->getNode($id); my $node = $frame->getNode($ns, $id); This is another convenience method. It uses C<$id> with the I method to get a list of nodes with that element name, and simply returns the first L from the list. If C<$ns> is provided, then I is used. =cut sub getNode { my ($self, @args) = @_; if (scalar(@args) == 2) { return ($self->getElementsByTagNameNS(@args))[0]; } elsif (scalar(@args) == 1) { return ($self->getElementsByTagName($args[0]))[0]; } else { croak('Invalid number of arguments to getNode()'); } } =pod my $binary = $frame->header; Returns a scalar containing the frame length packed into binary. This is only useful for low-level protocol stuff. =cut sub header { my $self = shift; return pack('N', length($self->toString) + 4); } =pod my $data = $frame->frame; Returns a scalar containing the frame header (see the I method above) concatenated with the XML frame itself. This is only useful for low-level protocol stuff. =cut sub frame { my $self = shift; return $self->header . $self->toString; } =pod =head1 AVAILABLE SUBCLASSES =over =item * L, the base class =item * L, for EPP client command frames =item * L, for EPP EcheckE client commands =item * L, for EPP EcreateE client commands =item * L, for EPP EdeleteE client commands =item * L, for EPP EinfoE client commands =item * L, for EPP EloginE client commands =item * L, for EPP ElogoutE client commands =item * L, for EPP EpollE client commands =item * L, for EPP ErenewE client commands =item * L, for EPP EtransferE client commands =item * L, for EupdateE client commands =item * L, for EPP server greetings =item * L, for EPP client greetings =item * L, for EPP server response frames =back Each subclass has its own subclasses for various objects, for example L creates a CcheckE> frame for domain names. Coverage for all combinations of command and object type is not complete, but work is ongoing. =head1 COPYRIGHT This module is (c) 2008 - 2023 CentralNic Ltd and 2024 Gavin Brown. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Net-EPP-0.28/lib/Net/EPP/PaxHeader/Simple.pm000644 777777 777777 00000000562 14760316103 024063 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 56 LIBARCHIVE.xattr.com.macromates.visibleIndex=MjY2MDc 50 SCHILY.xattr.com.macromates.visibleIndex=26607 65 LIBARCHIVE.xattr.com.macromates.selectionRange=ODEyLTgxMjoyOA 57 SCHILY.xattr.com.macromates.selectionRange=812-812:28 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Simple.pm000644 €JªDI€GÖP;00000177426 14760316103 022655 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Simple; use Carp; use Config; use Digest::SHA qw(sha1_hex); use List::Util qw(any); use Net::EPP; use Net::EPP::Frame; use Net::EPP::ResponseCodes; use Time::HiRes qw(time); use base qw(Net::EPP::Client); use constant EPP_XMLNS => 'urn:ietf:params:xml:ns:epp-1.0'; use vars qw($Error $Code $Message @Log); use strict; use warnings; our $Error = ''; our $Code = OK; our $Message = ''; our @Log = (); =pod =head1 NAME Net::EPP::Simple - a simple EPP client interface for the most common jobs. =head1 SYNOPSIS #!/usr/bin/perl use Net::EPP::Simple; use strict; my $epp = Net::EPP::Simple->new( host => 'epp.nic.tld', user => 'my-id', pass => 'my-password', ); my $domain = 'example.tld'; if ($epp->check_domain($domain) == 1) { print "Domain is available\n" ; } else { my $info = $epp->domain_info($domain); printf("Domain was registered on %s by %s\n", $info->{crDate}, $info->{crID}); } =head1 DESCRIPTION This module provides a high level interface to EPP. It hides all the boilerplate of connecting, logging in, building request frames and parsing response frames behind a simple, Perlish interface. It is based on the L module and uses L to build request frames. =head1 CONSTRUCTOR my $epp = Net::EPP::Simple->new(%PARAMS); The constructor accepts the following arguments: =over =item * C identifies the EPP server to connect to. =item * C specifies the port, which defaults to C<700>. =item * C and C parameters specify authentication information. =item * C specifies a new password that is set during login. =item * The C parameter can be used to force the use of the Login Security Extension (see L). C will automatically use this extension if the server supports it, but clients may wish to force this behaviour to prevent downgrade attacks. =item * The C parameter can be used to specify the value of the CappE> element in the Login Security extension (if used). Unless specified, the name and current version of C will be used. =item * The C parameter controls how long the client waits for a response from the server before returning an error. =item * if C is set, C will output verbose debugging information on C, including all frames sent to and received from the server. =item * C can be used to disable automatic reconnection (it is enabled by default). Before sending a frame to the server, C will send a ChelloE> to check that the connection is up, if not, it will try to reconnect, aborting after the Ith time, where I is the value of C (the default is 3). =item * C can be used to disable automatic logins. If you set it to C<0>, you can manually log in using the C<$epp-E_login()> method. =item * C is a reference to an array of the EPP object namespace URIs that the client requires. =item * C is a flag saying the client only requires the standard EPP C, C, and C namespaces. =item * If neither C nor C is specified then the client will echo the server's object namespace list. =item * C is a reference to an array of the EPP extension namespace URIs that the client requires. =item * C is a flag saying the client only requires the standard EPP C DNSSEC extension namespace. =item * If neither C nor C is specified then the client will echo the server's extension namespace list. =item * The C parameter can be used to specify the language. The default is "C". =back The constructor will establish a connection to the server and retrieve the greeting (which is available via C<$epp-Egreeting>) and then send a CloginE> request. If the login fails, the constructor will return C and set C<$Net::EPP::Simple::Error> and C<$Net::EPP::Simple::Code>. =head2 CLIENT AND SERVER SSL OPTIONS RFC 5730 requires that all EPP instances must be protected using "mutual, strong client-server authentication". In practice, this means that both client and server must present an SSL certificate, and that they must both verify the certificate of their peer. =head3 SERVER CERTIFICATE VERIFICATION C will verify the certificate presented by a server if the C, and either C or C are passed to the constructor: my $epp = Net::EPP::Simple->new( host => 'epp.nic.tld', user => 'my-id', pass => 'my-password', verify => 1, ca_file => '/etc/pki/tls/certs/ca-bundle.crt', ca_path => '/etc/pki/tls/certs', ); C will fail to connect to the server if the certificate is not valid. You can disable SSL certificate verification by omitting the C argument or setting it to C. This is strongly discouraged, particularly in production environments. You may wish to use L to provide a value for the C parameter. =head3 SSL CIPHER SELECTION You can restrict the ciphers that you will use to connect to the server by passing a C parameter to the constructor. This is a colon- separated list of cipher names and aliases. See L for further details. As an example, the following cipher list is suggested for clients who wish to ensure high-security connections to servers: HIGH:!ADH:!MEDIUM:!LOW:!SSLv2:!EXP =head3 CLIENT CERTIFICATES If you are connecting to an EPP server which requires a client certificate, you can configure C to use one as follows: my $epp = Net::EPP::Simple->new( host => 'epp.nic.tld', user => 'my-id', pass => 'my-password', key => '/path/to/my.key', cert => '/path/to/my.crt', passphrase => 'foobar123', ); C is the filename of the private key, C is the filename of the certificate. If the private key is encrypted, the C parameter will be used to decrypt it. =cut sub new { my ($package, %params) = @_; $params{dom} = 1; my $load_config; if (exists($params{load_config})) { confess('the load_config parameter is deprecated and may be removed in a future version'); $load_config = $params{load_config}; $package->_load_config(\%params) if ($load_config); } $params{port} = (defined($params{port}) && int($params{port}) > 0 ? $params{port} : 700); $params{ssl} = ($params{no_ssl} ? undef : 1); my $self = $package->SUPER::new(%params); $self->{user} = $params{user}; $self->{pass} = $params{pass}; $self->{newPW} = $params{newPW}; $self->{debug} = (defined($params{debug}) ? int($params{debug}) : undef); $self->{timeout} = (defined($params{timeout}) && int($params{timeout}) > 0 ? $params{timeout} : 5); $self->{reconnect} = (defined($params{reconnect}) ? int($params{reconnect}) : 3); $self->{'authenticated'} = undef; $self->{connect} = (exists($params{connect}) ? $params{connect} : 1); $self->{login} = (exists($params{login}) ? $params{login} : 1); $self->{key} = $params{key}; $self->{cert} = $params{cert}; $self->{passphrase} = $params{passphrase}; $self->{verify} = $params{verify}; $self->{ca_file} = $params{ca_file}; $self->{ca_path} = $params{ca_path}; $self->{ciphers} = $params{ciphers}; $self->{objects} = $params{objects}; $self->{stdobj} = $params{stdobj}; $self->{extensions} = $params{extensions}; $self->{stdext} = $params{stdext}; $self->{lang} = $params{lang} || 'en'; $self->{login_security} = $params{login_security}; $self->{appname} = $params{appname}; bless($self, $package); if ($self->{connect}) { return ($self->_connect($self->{login}) ? $self : undef); } else { return $self; } } # # this functionality is now DEPRECATED # sub _load_config { my ($package, $params_ref) = @_; eval 'use Config::Simple'; if (!$@) { # we have Config::Simple, so let's try to parse the RC file: my $rcfile = $ENV{'HOME'} . '/.net-epp-simple-rc'; if (-e $rcfile) { my $config = Config::Simple->new($rcfile); # if no host was defined in the constructor, use the default (if specified): if (!defined($params_ref->{'host'}) && $config->param('default.default')) { $params_ref->{'host'} = $config->param('default.default'); } # if no debug level was defined in the constructor, use the default (if specified): if (!defined($params_ref->{'debug'}) && $config->param('default.debug')) { $params_ref->{'debug'} = $config->param('default.debug'); } # grep through the file's values for settings for the selected host: my %vars = $config->vars; foreach my $key (grep { /^$params_ref->{'host'}\./ } keys(%vars)) { my $value = $vars{$key}; $key =~ s/^$params_ref->{'host'}\.//; $params_ref->{$key} = $value unless (defined($params_ref->{$key})); } } } } sub _connect { my ($self, $login) = @_; my %params; $params{SSL_cipher_list} = $self->{ciphers} if (defined($self->{ssl}) && defined($self->{ciphers})); if (defined($self->{key}) && defined($self->{cert}) && defined($self->{ssl})) { $self->debug('configuring client certificate parameters'); $params{SSL_key_file} = $self->{key}; $params{SSL_cert_file} = $self->{cert}; $params{SSL_passwd_cb} = sub { $self->{passphrase} }; } if (defined($self->{ssl}) && defined($self->{verify})) { $self->debug('configuring server verification'); $params{SSL_verify_mode} = 1; $params{SSL_ca_file} = $self->{ca_file}; $params{SSL_ca_path} = $self->{ca_path}; } elsif (defined($self->{ssl})) { $params{SSL_verify_mode} = 0; } $self->debug(sprintf('Attempting to connect to %s:%d', $self->{host}, $self->{port})); eval { $params{no_greeting} = 1; $self->connect(%params); }; if ($@ ne '') { chomp($@); $@ =~ s/ at .+ line .+$//; $self->debug($@); $Code = COMMAND_FAILED; $Error = $Message = "Error connecting: " . $@; return undef; } else { $self->debug('Connected OK, retrieving greeting frame'); $self->{greeting} = $self->get_frame; if (ref($self->{greeting}) ne 'Net::EPP::Frame::Response') { $Code = COMMAND_FAILED; $Error = $Message = "Error retrieving greeting: " . $@; return undef; } else { $self->debug('greeting frame retrieved OK'); } } map { $self->debug('S: ' . $_) } split(/\n/, $self->{greeting}->toString(1)); if ($login) { $self->debug('attempting login'); return $self->_login; } else { return 1; } } sub _login { my $self = shift; $self->debug(sprintf("Attempting to login as client ID '%s'", $self->{user})); my $response = $self->request($self->_prepare_login_frame()); if (!$response) { $Error = $Message = "Error getting response to login request: " . $Error; return undef; } else { $Code = $self->_get_response_code($response); $Message = $self->_get_message($response); $self->debug(sprintf('%04d: %s', $Code, $Message)); if ($Code > 1999) { $Error = "Error logging in (response code $Code, message $Message)"; return undef; } else { $self->{'authenticated'} = 1; return 1; } } } sub _get_uris_from_greeting { my $self = shift; my $tag = shift; my $list = []; my $elems = $self->{greeting}->getElementsByTagNameNS(EPP_XMLNS, $tag); while (my $elem = $elems->shift) { push @$list, $elem->firstChild->data; } return $list; } sub _prepare_login_frame { my $self = shift; $self->debug('preparing login frame'); my $login = Net::EPP::Frame::Command::Login->new; my @extensions; if ($self->{'stdext'}) { push(@extensions, Net::EPP::Frame::ObjectSpec->xmlns('secDNS')); } elsif ($self->{'extensions'}) { @extensions = @{$self->{'extensions'}}; } else { @extensions = @{$self->_get_uris_from_greeting('extURI')}; } $login->clID->appendText($self->{'user'}); my $loginSecXMLNS = Net::EPP::Frame::ObjectSpec->xmlns('loginSec'); if ($self->{'login_security'} || $self->server_has_extension($loginSecXMLNS)) { push(@extensions, $loginSecXMLNS) unless (any { $loginSecXMLNS eq $_ } @extensions); $login->pw->appendText('[LOGIN-SECURITY]'); my $loginSec = $login->createElementNS($loginSecXMLNS, 'loginSec'); my $userAgent = $login->createElement('userAgent'); $loginSec->appendChild($userAgent); my $app = $login->createElement('app'); $app->appendText($self->{'appname'} || sprintf('%s %s', __PACKAGE__, $Net::EPP::VERSION)); $userAgent->appendChild($app); my $tech = $login->createElement('tech'); $tech->appendText(sprintf('Perl %s', $Config{'version'})); $userAgent->appendChild($tech); my $os = $login->createElement('os'); $os->appendText(sprintf('%s %s', ucfirst($Config{'osname'}), $Config{'osvers'})); $userAgent->appendChild($os); my $pw = $login->createElement('pw'); $pw->appendText($self->{'pass'}); $loginSec->appendChild($pw); if ($self->{'newPW'}) { my $newPW = $login->createElement('newPW'); $newPW->appendText('[LOGIN-SECURITY]'); $login->getNode('login')->insertAfter($newPW, $login->pw); $newPW = $login->createElement('newPW'); $newPW->appendText($self->{'newPW'}); $loginSec->appendChild($newPW); } $login->extension->appendChild($loginSec); } else { $login->pw->appendText($self->{pass}); if ($self->{newPW}) { my $newPW = $login->createElement('newPW'); $newPW->appendText($self->{newPW}); $login->getNode('login')->insertAfter($newPW, $login->pw); } } $login->version->appendText($self->{greeting}->getElementsByTagNameNS(EPP_XMLNS, 'version')->shift->firstChild->data); $login->lang->appendText($self->{lang}); my $objects = $self->{objects}; $objects = [map { Net::EPP::Frame::ObjectSpec->xmlns($_) } qw(contact domain host)] if $self->{stdobj}; $objects = $self->_get_uris_from_greeting('objURI') if not $objects; $login->svcs->appendTextChild('objURI', $_) for @$objects; if (scalar(@extensions) > 0) { my $svcext = $login->createElement('svcExtension'); $login->svcs->appendChild($svcext); $svcext->appendTextChild('extURI', $_) for @extensions; } return $login; } =pod =head1 AVAILABILITY CHECKS You can do a simple CcheckE> request for an object like so: my $result = $epp->check_domain($domain); my $result = $epp->check_host($host); my $result = $epp->check_contact($contact); Each of these methods has the same profile. They will return one of the following: =over =item * C in the case of an error (check C<$Net::EPP::Simple::Error> and C<$Net::EPP::Simple::Code>). =item * C<0> if the object is already provisioned. =item * C<1> if the object is available. =back =cut sub check_domain { my ($self, $domain) = @_; return $self->_check('domain', $domain); } sub check_host { my ($self, $host) = @_; return $self->_check('host', $host); } sub check_contact { my ($self, $contact) = @_; return $self->_check('contact', $contact); } sub _check { my ($self, $type, $identifier) = @_; my $frame; if ($type eq 'domain') { $frame = Net::EPP::Frame::Command::Check::Domain->new; $frame->addDomain($identifier); } elsif ($type eq 'contact') { $frame = Net::EPP::Frame::Command::Check::Contact->new; $frame->addContact($identifier); } elsif ($type eq 'host') { $frame = Net::EPP::Frame::Command::Check::Host->new; $frame->addHost($identifier); } else { $Error = "Unknown object type '$type'"; return undef; } my $response = $self->_request($frame); if (!$response) { return undef; } else { $Code = $self->_get_response_code($response); $Message = $self->_get_message($response); if ($Code > 1999) { $Error = $self->_get_error_message($response); return undef; } else { my $xmlns = Net::EPP::Frame::ObjectSpec->xmlns($type); my $key; if ($type eq 'domain' || $type eq 'host') { $key = 'name'; } elsif ($type eq 'contact') { $key = 'id'; } return $response->getNode($xmlns, $key)->getAttribute('avail'); } } } =pod =head1 RETRIEVING OBJECT INFORMATION =head2 DOMAIN OBJECTS my $info = $epp->domain_info($domain, $authInfo, $follow); This method constructs an CinfoE> frame and sends it to the server, then parses the response into a simple hash ref. If there is an error, this method will return C, and you can then check C<$Net::EPP::Simple::Error> and C<$Net::EPP::Simple::Code>. If C<$authInfo> is defined, it will be sent to the server as per RFC 5731, Section 3.1.2. If the C<$follow> parameter is true, then C will also retrieve the relevant host and contact details for a domain: instead of returning an object name or ID for the domain's registrant, contact associations, DNS servers or subordinate hosts, the values will be replaced with the return value from the appropriate C or C command (unless there was an error, in which case the original object ID will be used instead). =cut sub domain_info { my ($self, $domain, $authInfo, $follow, $hosts) = @_; $hosts = $hosts || 'all'; my $result = $self->_info('domain', $domain, $authInfo, $hosts); return $result if (ref($result) ne 'HASH' || !$follow); if (defined($result->{'ns'}) && ref($result->{'ns'}) eq 'ARRAY') { for (my $i = 0 ; $i < scalar(@{$result->{'ns'}}) ; $i++) { my $info = $self->host_info($result->{'ns'}->[$i]); $result->{'ns'}->[$i] = $info if (ref($info) eq 'HASH'); } } if (defined($result->{'hosts'}) && ref($result->{'hosts'}) eq 'ARRAY') { for (my $i = 0 ; $i < scalar(@{$result->{'hosts'}}) ; $i++) { my $info = $self->host_info($result->{'hosts'}->[$i]); $result->{'hosts'}->[$i] = $info if (ref($info) eq 'HASH'); } } my $info = $self->contact_info($result->{'registrant'}); $result->{'registrant'} = $info if (ref($info) eq 'HASH'); foreach my $type (keys(%{$result->{'contacts'}})) { my $info = $self->contact_info($result->{'contacts'}->{$type}); $result->{'contacts'}->{$type} = $info if (ref($info) eq 'HASH'); } return $result; } =pod =head2 HOST OBJECTS my $info = $epp->host_info($host); This method constructs an CinfoE> frame and sends it to the server, then parses the response into a simple hash ref. If there is an error, this method will return C, and you can then check C<$Net::EPP::Simple::Error> and C<$Net::EPP::Simple::Code>. =cut sub host_info { my ($self, $host) = @_; return $self->_info('host', $host); } =pod =head2 CONTACT OBJECTS my $info = $epp->contact_info($contact, $authInfo, $roid); This method constructs an CinfoE> frame and sends it to the server, then parses the response into a simple hash ref. If there is an error, this method will return C, and you can then check C<$Net::EPP::Simple::Error> and C<$Net::EPP::Simple::Code>. If C<$authInfo> is defined, it will be sent to the server as per RFC RFC 5733, Section 3.1.2. If the C<$roid> parameter to C is set, then the C attribute will be set on the CauthInfoE> element. =cut sub contact_info { my ($self, $contact, $authInfo, $roid) = @_; return $self->_info('contact', $contact, $authInfo, $roid); } sub _info { # $opt is the "hosts" attribute value for domains or the "roid" # attribute for contacts my ($self, $type, $identifier, $authInfo, $opt) = @_; my $frame; if ($type eq 'domain') { $frame = Net::EPP::Frame::Command::Info::Domain->new; $frame->setDomain($identifier, $opt || 'all'); } elsif ($type eq 'contact') { $frame = Net::EPP::Frame::Command::Info::Contact->new; $frame->setContact($identifier); } elsif ($type eq 'host') { $frame = Net::EPP::Frame::Command::Info::Host->new; $frame->setHost($identifier); } else { $Error = "Unknown object type '$type'"; return undef; } if (defined($authInfo) && $authInfo ne '') { $self->debug('adding authInfo element to request frame'); my $el = $frame->createElementNS(Net::EPP::Frame::ObjectSpec->xmlns($type), 'authInfo'); my $pw = $frame->createElementNS(Net::EPP::Frame::ObjectSpec->xmlns($type), 'pw'); $pw->appendChild($frame->createTextNode($authInfo)); $pw->setAttribute('roid', $opt) if ($type eq 'contact' && $opt); $el->appendChild($pw); $frame->getNode(Net::EPP::Frame::ObjectSpec->xmlns($type), 'info')->appendChild($el); } my $response = $self->_request($frame); if (!$response) { return undef; } else { $Code = $self->_get_response_code($response); $Message = $self->_get_message($response); if ($Code > 1999) { $Error = $self->_get_error_message($response); return undef; } else { return $self->parse_object_info($type, $response); } } } # An easy-to-subclass method for parsing object info sub parse_object_info { my ($self, $type, $response) = @_; my $infData = $response->getNode(Net::EPP::Frame::ObjectSpec->xmlns($type), 'infData'); if ($type eq 'domain') { # secDNS extension only applies to domain objects my $secinfo = $response->getNode(Net::EPP::Frame::ObjectSpec->xmlns('secDNS'), 'infData'); return $self->_domain_infData_to_hash($infData, $secinfo); } elsif ($type eq 'contact') { return $self->_contact_infData_to_hash($infData); } elsif ($type eq 'host') { return $self->_host_infData_to_hash($infData); } else { $Error = "Unknown object type '$type'"; return undef; } } sub _get_common_properties_from_infData { my ($self, $infData, @extra) = @_; my $hash = {}; my @default = qw(roid clID crID crDate upID upDate trDate); foreach my $name (@default, @extra) { my $els = $infData->getElementsByLocalName($name); $hash->{$name} = $els->shift->textContent if ($els->size > 0); } my $codes = $infData->getElementsByLocalName('status'); while (my $code = $codes->shift) { push(@{$hash->{status}}, $code->getAttribute('s')); } return $hash; } =pod =head2 DOMAIN INFORMATION The hash ref returned by C will usually look something like this: { 'contacts' => { 'admin' => 'contact-id' 'tech' => 'contact-id' 'billing' => 'contact-id' }, 'registrant' => 'contact-id', 'clID' => 'registrar-id', 'roid' => 'tld-12345', 'status' => ['ok'], 'authInfo' => 'abc-12345', 'name' => 'example.tld', 'trDate' => '2011-01-18T11:08:03.0Z', 'ns' => ['ns0.example.com', 'ns1.example.com',], 'crDate' => '2011-02-16T12:06:31.0Z', 'exDate' => '2011-02-16T12:06:31.0Z', 'crID' => 'registrar-id', 'upDate' => '2011-08-29T04:02:12.0Z', hosts => ['ns0.example.tld', 'ns1.example.tld',], } Members of the C hash ref may be strings or, if there are multiple associations of the same type, an anonymous array of strings. If the server uses the Host Attribute model instead of the Host Object model, then the C member will look like this: [ { name => 'ns0.example.com', addrs => [ version => 'v4', addr => '10.0.0.1', ], }, { name => 'ns1.example.com', addrs => [ version => 'v4', addr => '10.0.0.2', ], }, ] Note that there may be multiple members in the C section and that the C attribute is optional. =cut sub _domain_infData_to_hash { my ($self, $infData, $secinfo) = @_; my $hash = $self->_get_common_properties_from_infData($infData, 'registrant', 'name', 'exDate'); my $contacts = $infData->getElementsByLocalName('contact'); while (my $contact = $contacts->shift) { my $type = $contact->getAttribute('type'); my $id = $contact->textContent; if (ref($hash->{contacts}->{$type}) eq 'STRING') { $hash->{contacts}->{$type} = [$hash->{contacts}->{$type}, $id]; } elsif (ref($hash->{contacts}->{$type}) eq 'ARRAY') { push(@{$hash->{contacts}->{$type}}, $id); } else { $hash->{contacts}->{$type} = $id; } } my $ns = $infData->getElementsByLocalName('ns'); if ($ns->size == 1) { my $el = $ns->shift; my $hostObjs = $el->getElementsByLocalName('hostObj'); while (my $hostObj = $hostObjs->shift) { push(@{$hash->{ns}}, $hostObj->textContent); } my $hostAttrs = $el->getElementsByLocalName('hostAttr'); while (my $hostAttr = $hostAttrs->shift) { my $host = {}; $host->{name} = $hostAttr->getElementsByLocalName('hostName')->shift->textContent; my $addrs = $hostAttr->getElementsByLocalName('hostAddr'); while (my $addr = $addrs->shift) { push(@{$host->{addrs}}, {version => $addr->getAttribute('ip'), addr => $addr->textContent}); } push(@{$hash->{ns}}, $host); } } my $hosts = $infData->getElementsByLocalName('host'); while (my $host = $hosts->shift) { push(@{$hash->{hosts}}, $host->textContent); } my $auths = $infData->getElementsByLocalName('authInfo'); if ($auths->size == 1) { my $authInfo = $auths->shift; my $pw = $authInfo->getElementsByLocalName('pw'); $hash->{authInfo} = $pw->shift->textContent if ($pw->size == 1); } if (defined $secinfo) { if (my $maxSigLife = $secinfo->getElementsByLocalName('maxSigLife')) { $hash->{maxSigLife} = $maxSigLife->shift->textContent; } my $dslist = $secinfo->getElementsByTagName('secDNS:dsData'); while (my $ds = $dslist->shift) { my @ds = map { $ds->getElementsByLocalName($_)->string_value() } qw(keyTag alg digestType digest); push @{$hash->{DS}}, "@ds"; } my $keylist = $secinfo->getElementsByLocalName('keyData'); while (my $key = $keylist->shift) { my @key = map { $key->getElementsByLocalName($_)->string_value() } qw(flags protocol alg pubKey); push @{$hash->{DNSKEY}}, "@key"; } } return $hash; } =pod =head2 HOST INFORMATION The hash ref returned by C will usually look something like this: { 'crDate' => '2011-09-17T15:38:56.0Z', 'clID' => 'registrar-id', 'crID' => 'registrar-id', 'roid' => 'tld-12345', 'status' => ['linked', 'serverDeleteProhibited',], 'name' => 'ns0.example.tld', 'addrs' => [ { 'version' => 'v4', 'addr' => '10.0.0.1' } ] } Note that hosts may have multiple addresses, and that C is optional. =cut sub _host_infData_to_hash { my ($self, $infData) = @_; my $hash = $self->_get_common_properties_from_infData($infData, 'name'); my $addrs = $infData->getElementsByLocalName('addr'); while (my $addr = $addrs->shift) { push(@{$hash->{addrs}}, {version => $addr->getAttribute('ip'), addr => $addr->textContent}); } return $hash; } =pod =head2 CONTACT INFORMATION The hash ref returned by C will usually look something like this: { 'id' => 'contact-id', 'postalInfo' => { 'int' => { 'name' => 'John Doe', 'org' => 'Example Inc.', 'addr' => { 'street' => ['123 Example Dr.', 'Suite 100'], 'city' => 'Dulles', 'sp' => 'VA', 'pc' => '20116-6503', 'cc' => 'US', }} }, 'clID' => 'registrar-id', 'roid' => 'CNIC-HA321983', 'status' => ['linked', 'serverDeleteProhibited'], 'voice' => '+1.7035555555x1234', 'fax' => '+1.7035555556', 'email' => 'jdoe@example.com', 'crDate' => '2011-09-23T03:51:29.0Z', 'upDate' => '1999-11-30T00:00:00.0Z' } There may be up to two members of the C hash, corresponding to the C and C internationalised and localised types. =cut sub _contact_infData_to_hash { my ($self, $infData) = @_; my $hash = $self->_get_common_properties_from_infData($infData, 'email', 'id'); # remove this as it gets in the way: my $els = $infData->getElementsByLocalName('disclose'); if ($els->size > 0) { while (my $el = $els->shift) { $el->parentNode->removeChild($el); } } foreach my $name ('voice', 'fax') { my $els = $infData->getElementsByLocalName($name); if (defined($els) && $els->size == 1) { my $el = $els->shift; if (defined($el)) { $hash->{$name} = $el->textContent; $hash->{$name} .= 'x' . $el->getAttribute('x') if (defined($el->getAttribute('x')) && $el->getAttribute('x') ne ''); } } } my $postalInfo = $infData->getElementsByLocalName('postalInfo'); while (my $info = $postalInfo->shift) { my $ref = {}; foreach my $name (qw(name org)) { my $els = $info->getElementsByLocalName($name); $ref->{$name} = $els->shift->textContent if ($els->size == 1); } my $addrs = $info->getElementsByLocalName('addr'); if ($addrs->size == 1) { my $addr = $addrs->shift; foreach my $child ($addr->childNodes) { next if (XML::LibXML::XML_ELEMENT_NODE != $child->nodeType); if ($child->localName eq 'street') { push(@{$ref->{addr}->{$child->localName}}, $child->textContent); } else { $ref->{addr}->{$child->localName} = $child->textContent; } } } $hash->{postalInfo}->{$info->getAttribute('type')} = $ref; } my $auths = $infData->getElementsByLocalName('authInfo'); if ($auths->size == 1) { my $authInfo = $auths->shift; my $pw = $authInfo->getElementsByLocalName('pw'); $hash->{authInfo} = $pw->shift->textContent if ($pw->size == 1); } return $hash; } =pod =head1 OBJECT TRANSFERS The EPP CtransferE> command suppots five different operations: query, request, cancel, approve, and reject. C makes these available using the following methods: # For domain objects: $epp->domain_transfer_query($domain); $epp->domain_transfer_cancel($domain); $epp->domain_transfer_request($domain, $authInfo, $period); $epp->domain_transfer_approve($domain); $epp->domain_transfer_reject($domain); # For contact objects: $epp->contact_transfer_query($contact); $epp->contact_transfer_cancel($contact); $epp->contact_transfer_request($contact, $authInfo); $epp->contact_transfer_approve($contact); $epp->contact_transfer_reject($contact); Most of these methods will just set the value of C<$Net::EPP::Simple::Code> and return either true or false. However, the C, C, C and C methods will return a hash ref that looks like this: { 'name' => 'example.tld', 'reID' => 'losing-registrar', 'acDate' => '2011-12-04T12:24:53.0Z', 'acID' => 'gaining-registrar', 'reDate' => '2011-11-29T12:24:53.0Z', 'trStatus' => 'pending' } =cut sub _transfer_request { my ($self, $op, $type, $identifier, $authInfo, $period) = @_; my $class = sprintf('Net::EPP::Frame::Command::Transfer::%s', ucfirst(lc($type))); my $frame; eval("\$frame = $class->new"); if ($@ || ref($frame) ne $class) { $Error = "Error building request frame: $@"; $Code = COMMAND_FAILED; return undef; } else { $frame->setOp($op); if ($type eq 'domain') { $frame->setDomain($identifier); $frame->setPeriod(int($period)) if ($op eq 'request'); } elsif ($type eq 'contact') { $frame->setContact($identifier); } if ($op eq 'request' || $op eq 'query') { $frame->setAuthInfo($authInfo) if ($authInfo ne ''); } } my $response = $self->_request($frame); if (!$response) { return undef; } else { $Code = $self->_get_response_code($response); $Message = $self->_get_message($response); if ($Code > 1999) { $Error = $response->msg; return undef; } elsif ($op eq 'query' || $op eq 'request') { my $trnData = $response->getElementsByLocalName('trnData')->shift; my $hash = {}; foreach my $child ($trnData->childNodes) { $hash->{$child->localName} = $child->textContent; } return $hash; } else { return 1; } } } sub domain_transfer_query { return $_[0]->_transfer_request('query', 'domain', $_[1]); } sub domain_transfer_cancel { return $_[0]->_transfer_request('cancel', 'domain', $_[1]); } sub domain_transfer_request { return $_[0]->_transfer_request('request', 'domain', $_[1], $_[2], $_[3]); } sub domain_transfer_approve { return $_[0]->_transfer_request('approve', 'domain', $_[1]); } sub domain_transfer_reject { return $_[0]->_transfer_request('reject', 'domain', $_[1]); } sub contact_transfer_query { return $_[0]->_transfer_request('query', 'contact', $_[1]); } sub contact_transfer_cancel { return $_[0]->_transfer_request('cancel', 'contact', $_[1]); } sub contact_transfer_request { return $_[0]->_transfer_request('request', 'contact', $_[1], $_[2]); } sub contact_transfer_approve { return $_[0]->_transfer_request('approve', 'contact', $_[1]); } sub contact_transfer_reject { return $_[0]->_transfer_request('reject', 'contact', $_[1]); } =pod =head1 CREATING OBJECTS The following methods can be used to create a new object at the server: $epp->create_domain($domain); $epp->create_host($host); $epp->create_contact($contact); The argument for these methods is a hash ref of the same format as that returned by the info methods above. As a result, cloning an existing object is as simple as the following: my $info = $epp->contact_info($contact); # set a new contact ID to avoid clashing with the existing object $info->{id} = $new_contact; # randomize authInfo: $info->{authInfo} = $random_string; $epp->create_contact($info); C will ignore object properties that it does not recognise, and those properties (such as server-managed status codes) that clients are not permitted to set. =head2 CREATING NEW DOMAINS When creating a new domain object, you may also specify a C key, like so: $epp->create_domain({ 'name' => 'example.tld', 'period' => 2, 'registrant' => 'contact-id', 'contacts' => { 'tech' => 'contact-id', 'admin' => 'contact-id', 'billing' => 'contact-id', }, 'status' => ['clientTransferProhibited',], 'ns' => {'ns0.example.com', 'ns1.example.com',}, # this will be ignored if the server does not support the TTL extension 'ttl' => {'NS' => 3600, 'DS' => 60}, }); The C key is assumed to be in years rather than months. C assumes the registry uses the host object model rather than the host attribute model. =cut sub create_domain { my ($self, $domain) = @_; return $self->_get_response_result($self->_request($self->_prepare_create_domain_frame($domain))); } sub _prepare_create_domain_frame { my ($self, $domain) = @_; my $frame = Net::EPP::Frame::Command::Create::Domain->new; $frame->setDomain($domain->{'name'}); $frame->setPeriod($domain->{'period'}) if (defined($domain->{period}) && $domain->{period} > 0); $frame->setNS(@{$domain->{'ns'}}) if $domain->{'ns'} and @{$domain->{'ns'}}; $frame->setRegistrant($domain->{'registrant'}) if (defined($domain->{registrant}) && $domain->{registrant} ne ''); $frame->setContacts($domain->{'contacts'}); $frame->setAuthInfo($domain->{authInfo}) if (defined($domain->{authInfo}) && $domain->{authInfo} ne ''); if ($domain->{'ttl'} && $self->server_has_extension(Net::EPP::Frame::ObjectSpec->xmlns('ttl'))) { $frame->setTTLs($domain->{'ttl'}); } return $frame; } =head2 CREATING HOSTS $epp->create_host({ name => 'ns1.example.tld', addrs => [ {ip => '192.0.2.1', version => 'v4'}, {ip => '192.0.2.2', version => 'v4'}, ], # this will be ignored if the server does not support the TTL extension 'ttl' => { 'A' => 3600, 'AAAA' => 900, } }); =cut sub create_host { my ($self, $host) = @_; return $self->_get_response_result($self->_request($self->_prepare_create_host_frame($host))); } sub _prepare_create_host_frame { my ($self, $host) = @_; my $frame = Net::EPP::Frame::Command::Create::Host->new; $frame->setHost($host->{name}); $frame->setAddr(@{$host->{addrs}}); if ($host->{'ttl'} && $self->server_has_extension(Net::EPP::Frame::ObjectSpec->xmlns('ttl'))) { $frame->setTTLs($host->{'ttl'}); } return $frame; } sub create_contact { my ($self, $contact) = @_; return $self->_get_response_result($self->_request($self->_prepare_create_contact_frame($contact))); } sub _prepare_create_contact_frame { my ($self, $contact) = @_; my $frame = Net::EPP::Frame::Command::Create::Contact->new; $frame->setContact($contact->{id}); if (ref($contact->{postalInfo}) eq 'HASH') { foreach my $type (keys(%{$contact->{postalInfo}})) { $frame->addPostalInfo($type, $contact->{postalInfo}->{$type}->{name}, $contact->{postalInfo}->{$type}->{org}, $contact->{postalInfo}->{$type}->{addr}); } } $frame->setVoice($contact->{voice}) if (defined($contact->{voice}) && $contact->{voice} ne ''); $frame->setFax($contact->{fax}) if (defined($contact->{fax}) && $contact->{fax} ne ''); $frame->setEmail($contact->{email}); $frame->setAuthInfo($contact->{authInfo}) if (defined($contact->{authInfo}) && $contact->{authInfo} ne ''); if (ref($contact->{status}) eq 'ARRAY') { foreach my $status (grep { /^client/ } @{$contact->{status}}) { $frame->appendStatus($status); } } return $frame; } # Process response code and return result sub _get_response_result { my ($self, $response) = @_; return undef if !$response; # If there was a response... $Code = $self->_get_response_code($response); $Message = $self->_get_message($response); if ($Code > 1999) { $Error = $response->msg; return undef; } return 1; } =head1 UPDATING OBJECTS The following methods can be used to update an object at the server: $epp->update_domain($domain); $epp->update_host($host); $epp->update_contact($contact); Each of these methods has the same profile. They will return one of the following: =over =item * undef in the case of an error (check C<$Net::EPP::Simple::Error> and C<$Net::EPP::Simple::Code>). =item * 1 if the update request was accepted. =back You may wish to check the value of $Net::EPP::Simple::Code to determine whether the response code was 1000 (OK) or 1001 (action pending). =cut =head2 UPDATING DOMAINS Use C method to update a domain name. The C<$info> argument should look like this: { name => $domain, chg => { registrant => $new_registrant_id, authInfo => $new_domain_password, # this will be ignored if the server does not support the TTL extension ttl => {'NS' => 3600, 'DS' => 60}, }, add => { ns => [qw/ns1.example.com ns2.example.com/], contacts => { tech => 'contact-id', billing => 'contact-id', admin => 'contact-id', }, # Status info, simple form: status => [qw/ clientUpdateProhibited clientHold /], # Status info may be in more detailed form: # status => { # clientUpdateProbhibited => 'Avoid accidental change', # clientHold => 'This domain is not delegated', # }, }, rem => { ns => [...], contacts => { tech => 'old_tech_id', billing => 'old_billing_id', admin => 'old_admin_id', }, status => [qw/ clientTransferProhibited ... /], }, } All fields except C are optional. =cut sub update_domain { my ($self, $domain) = @_; return $self->_update('domain', $domain); } =head2 UPDATING CONTACTS Use C method to update a contact object. The C<$info> argument should look like this: { id => $contact_id, add => { status => [qw/ clientDeleteProhibited /], # OR # status => { # clientDeleteProhibited => 'Avoid accidental removal', # }, }, rem => { status => [qw/ clientUpdateProhibited /], }, chg => { postalInfo => { int => { name => 'John Doe', org => 'Example Inc.', addr => { street => ['123 Example Dr.', 'Suite 100'], city => 'Dulles', sp => 'VA', pc => '20116-6503', cc => 'US', }, }, }, voice => '+1.7035555555x1234', fax => '+1.7035555556', email => 'jdoe@example.com', authInfo => 'new-contact-password', }, } All fields except C are optional. =cut sub update_contact { my ($self, $contact) = @_; return $self->_update('contact', $contact); } =head2 UPDATING HOSTS Use C method to update a host object. The C<$info> argument should look like this: { name => 'ns1.example.com', add => { status => [qw/ clientDeleteProhibited /], # OR # status => { # clientDeleteProhibited => 'Avoid accidental removal', # }, addrs => [{ip => '123.45.67.89', version => 'v4'}, {ip => '98.76.54.32', version => 'v4'},], }, rem => { status => [qw/ clientUpdateProhibited /], addrs => [{ip => '1.2.3.4', version => 'v4'}, {ip => '5.6.7.8', version => 'v4'},], }, chg => { name => 'ns2.example.com', # this will be ignored if the server does not support the TTL extension ttl => {NS => 3600, DS => 60}, }, } All fields except C are optional. =cut sub update_host { my ($self, $host) = @_; return $self->_update('host', $host); } # Update domain/contact/host information sub _update { my ($self, $type, $info) = @_; my %frame_generator = ( 'domain' => \&_generate_update_domain_frame, 'contact' => \&_generate_update_contact_frame, 'host' => \&_generate_update_host_frame, ); if (!exists $frame_generator{$type}) { $Error = "Unknown object type: '$type'"; return undef; } my $generator = $frame_generator{$type}; my $frame = $self->$generator($info); return $self->_get_response_result($self->request($frame)); } sub _generate_update_domain_frame { my ($self, $info) = @_; my $frame = Net::EPP::Frame::Command::Update::Domain->new; $frame->setDomain($info->{name}); # 'add' element if (exists $info->{add} && ref $info->{add} eq 'HASH') { my $add = $info->{add}; # Add DNS if (exists $add->{ns} && ref $add->{ns} eq 'ARRAY') { $frame->addNS(@{$add->{ns}}); } # Add contacts if (exists $add->{contacts} && ref $add->{contacts} eq 'HASH') { my $contacts = $add->{contacts}; foreach my $type (keys %{$contacts}) { $frame->addContact($type, $contacts->{$type}); } } # Add status info if (exists $add->{status} && ref $add->{status}) { if (ref $add->{status} eq 'HASH') { while (my ($type, $info) = each %{$add->{status}}) { $frame->addStatus($type, $info); } } elsif (ref $add->{status} eq 'ARRAY') { $frame->addStatus($_) for @{$add->{status}}; } } } # 'rem' element if (exists $info->{rem} && ref $info->{rem} eq 'HASH') { my $rem = $info->{rem}; # DNS if (exists $rem->{ns} && ref $rem->{ns} eq 'ARRAY') { $frame->remNS(@{$rem->{ns}}); } # Contacts if (exists $rem->{contacts} && ref $rem->{contacts} eq 'HASH') { my $contacts = $rem->{contacts}; foreach my $type (keys %{$contacts}) { $frame->remContact($type, $contacts->{$type}); } } # Status info if (exists $rem->{status} && ref $rem->{status} eq 'ARRAY') { $frame->remStatus($_) for @{$rem->{status}}; } } # 'chg' element if (exists $info->{chg} && ref $info->{chg} eq 'HASH') { my $chg = $info->{chg}; if (defined $chg->{registrant}) { $frame->chgRegistrant($chg->{registrant}); } if (defined $chg->{authInfo}) { $frame->chgAuthInfo($chg->{authInfo}); } if (defined $chg->{ttl} && $self->server_has_extension(Net::EPP::Frame::ObjectSpec->xmlns('ttl'))) { $frame->chgTTLs($chg->{ttl}); } } return $frame; } sub _generate_update_contact_frame { my ($self, $info) = @_; my $frame = Net::EPP::Frame::Command::Update::Contact->new; $frame->setContact($info->{id}); # Add if (exists $info->{add} && ref $info->{add} eq 'HASH') { my $add = $info->{add}; if (exists $add->{status} && ref $add->{status}) { if (ref $add->{status} eq 'HASH') { while (my ($type, $info) = each %{$add->{status}}) { $frame->addStatus($type, $info); } } elsif (ref $add->{status} eq 'ARRAY') { $frame->addStatus($_) for @{$add->{status}}; } } } # Remove if (exists $info->{rem} && ref $info->{rem} eq 'HASH') { my $rem = $info->{rem}; if (exists $rem->{status} && ref $rem->{status} eq 'ARRAY') { $frame->remStatus($_) for @{$rem->{status}}; } } # Change if (exists $info->{chg} && ref $info->{chg} eq 'HASH') { my $chg = $info->{chg}; # Change postal info if (ref $chg->{postalInfo} eq 'HASH') { foreach my $type (keys %{$chg->{postalInfo}}) { $frame->chgPostalInfo($type, $chg->{postalInfo}->{$type}->{name}, $chg->{postalInfo}->{$type}->{org}, $chg->{postalInfo}->{$type}->{addr}); } } # Change voice / fax / email for my $contact_type (qw/ voice fax email /) { if (defined $chg->{$contact_type}) { my $el = $frame->createElement("contact:$contact_type"); $el->appendText($chg->{$contact_type}); $frame->chg->appendChild($el); } } # Change auth info if ($chg->{authInfo}) { $frame->chgAuthInfo($chg->{authInfo}); } # 'disclose' option is still unimplemented } return $frame; } sub _generate_update_host_frame { my ($self, $info) = @_; my $frame = Net::EPP::Frame::Command::Update::Host->new; $frame->setHost($info->{name}); if (exists $info->{add} && ref $info->{add} eq 'HASH') { my $add = $info->{add}; # Process addresses if (exists $add->{addrs} && ref $add->{addrs} eq 'ARRAY') { $frame->addAddr(@{$add->{addrs}}); } # Process statuses if (exists $add->{status} && ref $add->{status}) { if (ref $add->{status} eq 'HASH') { while (my ($type, $info) = each %{$add->{status}}) { $frame->addStatus($type, $info); } } elsif (ref $add->{status} eq 'ARRAY') { $frame->addStatus($_) for @{$add->{status}}; } } } if (exists $info->{rem} && ref $info->{rem} eq 'HASH') { my $rem = $info->{rem}; # Process addresses if (exists $rem->{addrs} && ref $rem->{addrs} eq 'ARRAY') { $frame->remAddr(@{$rem->{addrs}}); } # Process statuses if (exists $rem->{status} && ref $rem->{status}) { if (ref $rem->{status} eq 'HASH') { while (my ($type, $info) = each %{$rem->{status}}) { $frame->remStatus($type, $info); } } elsif (ref $rem->{status} eq 'ARRAY') { $frame->remStatus($_) for @{$rem->{status}}; } } } if (exists $info->{chg} && ref $info->{chg} eq 'HASH') { if ($info->{chg}->{name}) { $frame->chgName($info->{chg}->{name}); } } if (exists $info->{chg} && ref $info->{chg} eq 'HASH') { if ($info->{chg}->{name}) { $frame->chgName($info->{chg}->{name}); } if (defined $info->{chg}->{ttl} && $self->server_has_extension(Net::EPP::Frame::ObjectSpec->xmlns('ttl'))) { $frame->chgTTLs($info->{chg}->{ttl}); } } return $frame; } =pod =head1 DELETING OBJECTS The following methods can be used to delete an object at the server: $epp->delete_domain($domain); $epp->delete_host($host); $epp->delete_contact($contact); Each of these methods has the same profile. They will return one of the following: =over =item * undef in the case of an error (check C<$Net::EPP::Simple::Error> and C<$Net::EPP::Simple::Code>). =item * 1 if the deletion request was accepted. =back You may wish to check the value of $Net::EPP::Simple::Code to determine whether the response code was 1000 (OK) or 1001 (action pending). =cut sub delete_domain { my ($self, $domain) = @_; return $self->_delete('domain', $domain); } sub delete_host { my ($self, $host) = @_; return $self->_delete('host', $host); } sub delete_contact { my ($self, $contact) = @_; return $self->_delete('contact', $contact); } sub _delete { my ($self, $type, $identifier) = @_; my $frame; if ($type eq 'domain') { $frame = Net::EPP::Frame::Command::Delete::Domain->new; $frame->setDomain($identifier); } elsif ($type eq 'contact') { $frame = Net::EPP::Frame::Command::Delete::Contact->new; $frame->setContact($identifier); } elsif ($type eq 'host') { $frame = Net::EPP::Frame::Command::Delete::Host->new; $frame->setHost($identifier); } else { $Error = "Unknown object type '$type'"; return undef; } my $response = $self->_request($frame); if (!$response) { return undef; } else { $Code = $self->_get_response_code($response); $Message = $self->_get_message($response); if ($Code > 1999) { $Error = $self->_get_error_message($response); return undef; } else { return 1; } } } =head1 DOMAIN RENEWAL You can extend the validity period of the domain object by issuing a renew_domain() command. my $result = $epp->renew_domain({ name => 'example.com', cur_exp_date => '2011-02-05', # current expiration date period => 2, # prolongation period in years }); Return value is C<1> on success and C on error. In the case of error C<$Net::EPP::Simple::Error> contains the appropriate error message. =cut sub renew_domain { my ($self, $info) = @_; return $self->_get_response_result($self->request($self->_generate_renew_domain_frame($info))); } sub _generate_renew_domain_frame { my ($self, $info) = @_; my $frame = Net::EPP::Frame::Command::Renew::Domain->new; $frame->setDomain($info->{name}); $frame->setCurExpDate($info->{cur_exp_date}); $frame->setPeriod($info->{period}) if $info->{period}; return $frame; } =pod =head1 MISCELLANEOUS METHODS =cut sub error { $Error } sub code { $Code } sub message { $Message } =pod my $greeting = $epp->greeting; Returns the a L object representing the greeting returned by the server. =cut sub greeting { my $self = shift; return $self->{'greeting'}; } =pod $epp->ping; Checks that the connection is up by sending a ChelloE> to the server. Returns false if no response is received. =cut sub ping { my $self = shift; my $hello = Net::EPP::Frame::Hello->new; my $response = $self->request($hello); if (UNIVERSAL::isa($response, 'XML::LibXML::Document')) { $Code = 1000; $Message = 'Command completed successfully.'; return 1; } else { $Code = 2400; $Message = 'Error getting greeting from server.'; return undef; } } sub _request { my ($self, $frame) = @_; if ($self->{reconnect} > 0) { $self->debug("reconnect is $self->{reconnect}, pinging"); if (!$self->ping) { $self->debug('connection seems dead, trying to reconnect'); for (1 .. $self->{reconnect}) { $self->debug("attempt #$_"); if ($self->_connect) { $self->debug("attempt #$_ succeeded"); return $self->request($frame); } else { $self->debug("attempt #$_ failed, sleeping"); sleep($self->{timeout}); } } $self->debug('unable to reconnect!'); return undef; } else { $self->debug("Connection is up, sending frame"); return $self->request($frame); } } else { return $self->request($frame); } } =pod =head1 OVERRIDDEN METHODS FROM L C overrides some methods inherited from L. These are described below: =head2 C C overrides this method so it can automatically populate the CclTRIDE> element with a unique string. It then passes the frame back up to L. =cut sub request { my ($self, $frame) = @_; # Make sure we start with blank variables $Code = undef; $Error = ''; $Message = ''; if (!$self->connected) { $Code = COMMAND_FAILED; $Error = $Message = 'Not connected'; $self->debug('cannot send frame if not connected'); return undef; } elsif (!$frame) { $Code = COMMAND_FAILED; $Error = $Message = 'Invalid frame'; $self->debug($Message); return undef; } else { $frame->clTRID->appendText(sha1_hex(ref($self) . time() . $$)) if (UNIVERSAL::isa($frame, 'Net::EPP::Frame::Command')); my $type = ref($frame); if ($frame =~ /^\//) { $type = 'file'; } else { $type = 'string'; } $self->debug(sprintf('sending a %s to the server', $type)); if (UNIVERSAL::isa($frame, 'XML::LibXML::Document')) { map { $self->debug('C: ' . $_) } split(/\n/, $frame->toString(2)); } else { map { $self->debug('C: ' . $_) } split(/\n/, $frame); } my $response = $self->SUPER::request($frame); map { $self->debug('S: ' . $_) } split(/\n/, $response->toString(2)) if (UNIVERSAL::isa($response, 'XML::LibXML::Document')); return $response; } } =pod =head2 C C overrides this method so it can catch timeouts and network errors. If such an error occurs it will return C. =cut sub get_frame { my $self = shift; if (!$self->connected) { $self->debug('cannot get frame if not connected'); $Code = COMMAND_FAILED; $Error = $Message = 'Not connected'; return undef; } else { my $frame; $self->debug(sprintf('reading frame, waiting %d seconds before timeout', $self->{timeout})); eval { local $SIG{ALRM} = sub { die 'timeout' }; $self->debug('setting timeout alarm for receiving frame'); alarm($self->{timeout}); $frame = $self->SUPER::get_frame(); $self->debug('unsetting timeout alarm after successful receive'); alarm(0); }; if ($@ ne '') { chomp($@); $@ =~ s/ at .+ line .+$//; $self->debug("unsetting timeout alarm after alarm was triggered ($@)"); alarm(0); $Code = COMMAND_FAILED; if ($@ =~ /^timeout/) { $Error = $Message = "get_frame() timed out after $self->{timeout} seconds"; } else { $Error = $Message = "get_frame() received an error: $@"; } return undef; } else { return bless($frame, 'Net::EPP::Frame::Response'); } } } sub send_frame { my ($self, $frame, $wfcheck) = @_; if (!$self->connected) { $self->debug('cannot send frame if not connected'); $Code = 2400; $Message = 'Not connected'; return undef; } else { return $self->SUPER::send_frame($frame, $wfcheck); } } # Get details error description including code, message and reason sub _get_error_message { my ($self, $doc) = @_; my $code = $self->_get_response_code($doc); my $error = "Error $code"; my $message = $self->_get_message($doc); if ($message) { $error .= ": $message"; } my $reason = $self->_get_reason($doc); if ($reason) { $error .= " ($reason)"; } return $error; } sub _get_response_code { my ($self, $doc) = @_; if ($doc->isa('XML::DOM::Document') || $doc->isa('Net::EPP::Frame::Response')) { my $els = $doc->getElementsByTagNameNS(EPP_XMLNS, 'result'); if (defined($els)) { my $el = $els->shift; return $el->getAttribute('code') if (defined($el)); } } return 2400; } sub _get_message { my ($self, $doc) = @_; if ($doc->isa('XML::DOM::Document') || $doc->isa('Net::EPP::Frame::Response')) { my $msgs = $doc->getElementsByTagNameNS(EPP_XMLNS, 'msg'); if (defined($msgs)) { my $msg = $msgs->shift; return $msg->textContent if (defined($msg)); } } return ''; } sub _get_reason { my ($self, $doc) = @_; if ($doc->isa('XML::DOM::Document') || $doc->isa('Net::EPP::Frame::Response')) { my $reasons = $doc->getElementsByTagNameNS(EPP_XMLNS, 'reason'); if (defined($reasons)) { my $reason = $reasons->shift; if (defined($reason)) { return $reason->textContent; } } } return ''; } sub logout { my $self = shift; if ($self->authenticated) { $self->debug('logging out'); my $response = $self->request(Net::EPP::Frame::Command::Logout->new); undef($self->{'authenticated'}); if (!$response) { $Code = COMMAND_FAILED; $Message = $Error = 'unknown error'; return undef; } else { $Code = $self->_get_response_code($response); $Message = $self->_get_message($response); } } $self->debug('disconnecting from server'); $self->disconnect; return 1; } sub DESTROY { my $self = shift; $self->debug('DESTROY() method called'); $self->logout if ($self->connected); } sub debug { my ($self, $msg) = @_; my $log = sprintf("%s (%d): %s", scalar(localtime()), $$, $msg); push(@Log, $log); print STDERR $log . "\n" if (defined($self->{debug}) && $self->{debug} == 1); } =pod $bool = $epp->server_has_object($xmlns); $bool = $epp->server_has_extension($xmlns); These methods both return a true value if the object/extension identified by C<$xmlns> was present in the server's greeting. =cut sub server_has_object { my ($self, $xmlns) = @_; if (!$self->greeting) { carp('not connected'); return undef; } foreach my $objURI ($self->greeting->getElementsByTagName('objURI')) { return 1 if ($objURI->textContent eq $xmlns); } return undef; } sub server_has_extension { my ($self, $xmlns) = @_; if (!$self->greeting) { carp('not connected'); return undef; } foreach my $extURI ($self->greeting->getElementsByTagName('extURI')) { return 1 if ($extURI->textContent eq $xmlns); } return undef; } =pod $authenticated = $epp->authenticated; Returns a boolean if C has successfully authenticated with the server. =cut sub authenticated { my $self = shift; return defined($self->{'authenticated'}); } 1; =pod =head1 PACKAGE VARIABLES =head2 $Net::EPP::Simple::Error This variable contains an english text message explaining the last error to occur. This is may be due to invalid parameters being passed to a method, a network error, or an error response being returned by the server. =head2 $Net::EPP::Simple::Message This variable contains the contains the text content of the CmsgE> element in the response frame for the last transaction. =head2 $Net::EPP::Simple::Code This variable contains the integer result code returned by the server for the last transaction. A successful transaction will always return an error code of 1999 or lower, for an unsuccessful transaction it will be 2011 or more. If there is an internal client error (due to invalid parameters being passed to a method, or a network error) then this will be set to 2400 (C). See L for more information about thes codes. =head1 COPYRIGHT This module is (c) 2008 - 2023 CentralNic Ltd and 2024 Gavin Brown. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Net-EPP-0.28/lib/Net/EPP/Frame/PaxHeader/ObjectSpec.pm000755 777777 777777 00000000537 14777472745 025741 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 51 LIBARCHIVE.xattr.com.macromates.visibleIndex=MA 46 SCHILY.xattr.com.macromates.visibleIndex=0 59 LIBARCHIVE.xattr.com.macromates.selectionRange=MTA6MTEz 53 SCHILY.xattr.com.macromates.selectionRange=10:113 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/ObjectSpec.pm000755 €JªDI€GÖP;00000011622 14777472745 024512 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::ObjectSpec; use vars qw($SPEC); use strict; our $SPEC = { 'domain' => ['urn:ietf:params:xml:ns:domain-1.0', 'urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd'], 'contact' => ['urn:ietf:params:xml:ns:contact-1.0', 'urn:ietf:params:xml:ns:contact-1.0 contact-1.0.xsd'], 'host' => ['urn:ietf:params:xml:ns:host-1.0', 'urn:ietf:params:xml:ns:host-1.0 host-1.0.xsd'], 'secDNS' => ['urn:ietf:params:xml:ns:secDNS-1.1', 'urn:ietf:params:xml:ns:secDNS-1.1 secDNS-1.1.xsd'], 'rgp' => ['urn:ietf:params:xml:ns:rgp-1.0', 'urn:ietf:params:xml:ns:rgp-1.0 rgp-1.0.xsd'], 'maintenance' => ['urn:ietf:params:xml:ns:epp:maintenance-1.0'], 'secure-authinfo-transfer' => ['urn:ietf:params:xml:ns:epp:secure-authinfo-transfer-1.0'], 'b-dn' => ['urn:ietf:params:xml:ns:epp:b-dn'], 'unhandled-namespaces' => ['urn:ietf:params:xml:ns:epp:unhandled-namespaces-1.0'], 'loginSec' => ['urn:ietf:params:xml:ns:epp:loginSec-1.0'], 'fee' => ['urn:ietf:params:xml:ns:epp:fee-1.0'], 'changePoll' => ['urn:ietf:params:xml:ns:changePoll-1.0'], 'orgext' => ['urn:ietf:params:xml:ns:epp:orgext-1.0'], 'org' => ['urn:ietf:params:xml:ns:epp:org-1.0'], 'allocationToken' => ['urn:ietf:params:xml:ns:allocationToken-1.0'], 'launch' => ['urn:ietf:params:xml:ns:launch-1.0'], 'keyrelay' => ['urn:ietf:params:xml:ns:keyrelay-1.0'], 'ttl' => ['urn:ietf:params:xml:ns:epp:ttl-1.0'], }; sub spec { my ($package, $type) = @_; return (!defined($SPEC->{$type}) ? undef : ($type, @{$SPEC->{$type}})); } sub xmlns { my ($package, $type) = @_; return $SPEC->{$type}->[0]; } =pod =head1 NAME Net::EPP::Frame::ObjectSpec - metadata about EPP objects and extensions. =head1 SYNOPSIS use Net::EPP::Frame; use strict; # create an EPP frame: my $check = Net::EPP::Frame::Command::Check->new; # get the spec: my @spec = Net::EPP::Frame::ObjectSpec->spec('domain'); # create an object: my $domain = $check->addObject(@spec); # set the attributes: my $name = $check->createElement('domain:name'); $name->addText('example.tld'); # assemble the frame: $domain->appendChild($name); $check->getCommandNode->appendChild($domain); print $check->toString; =head1 DESCRIPTION C is a simple module designed to provide easy access to metadata for the objects and extensions defined in EPP and various extensions. =head1 METHODS =head2 C my $xmlns = Net::EPP::Frame::ObjectSpec->xmlns($type); Returns a string containing the XML namespace URI of the thing identified by C<$type>, or C if C<$type> is unknown. See below for possible values of C<$type>. =head2 C my @spec = Net::EPP::Frame::ObjectSpec->spec($type); This function returns an array containing metadata for the given object type. If no metadata is registered then the function returns C. The returned array contains three members: @spec = ( $type, $xmlns, $schemaLocation, # (deprecated) ); C<$type> is the same as the supplied argument, while C<$xmlns> is the XML namespace URI for the given type. The third argument is suitable for inclusion in a C attribute, but is now deprecated and will be C for any value of C<$type> other than C, C C, C and C. =head1 THE C<$type> ARGUMENT The C<$type> argument to C and C identifies the object or extension desired. Possible values are: =head2 OBJECT MAPPINGS =over =item * C, for domain names; =item * C, for host objects; =item * C, for contact objects; =item * C, for organization object. =back =head2 EXTENSIONS =over =item * C, for the DNSSEC extension; =item * C, for Registry Grace Period extension; =item * C, for the TTL extension; =item * C, for the Maintenance extension; =item * C, for the Secure authInfo extension; =item * C, for the bundled domain names extension; =item * C, for the unhandled namespaces extension; =item * C, for the Login Security extension; =item * C, for the Fee extension; =item * C, for the Change Poll extension; =item * C, for the Organization extension; =item * C, for the Allocation Token extension; =item * C, for the Launch extension; =item * C, for the Key Relay extension; =item * C, for the TTL extension. =back =head1 COPYRIGHT This module is (c) 2008 - 2023 CentralNic Ltd and 2024 Gavin Brown. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/PaxHeader/Hello.pm000755 777777 777777 00000000216 14760316103 024726 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Hello.pm000755 €JªDI€GÖP;00000001712 14760316103 023504 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Hello; use base qw(Net::EPP::Frame); =pod =head1 NAME Net::EPP::Frame::Hello - an instance of L for client greetings =head1 DESCRIPTION This module is a subclass of L that represents EPP client greetings. Clients can send a greeting to an EPP server at any time during a session. According to the EPP RFC, the server must transmit an EPP greeting frame to the client upon connection, and in response to an EPP ChelloE> command. The CgreetingE> frame provides information about the server, including the server time, access control rules, and a list of the object types that are provisioned by the server. =head1 OBJECT HIERARCHY L +----L +----L +----L =head1 METHODS This module does not define any methods in addition to those it inherits from its ancestors. =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/PaxHeader/Command.pm000755 777777 777777 00000000216 14760316103 025241 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command.pm000755 €JªDI€GÖP;00000010451 14760316103 024017 0ustar00gavin.brownICANN\Domain Users000000 000000 # Copyright (c) 2016 CentralNic Ltd. All rights reserved. This program is # free software; you can redistribute it and/or modify it under the same # terms as Perl itself. # # $Id: Command.pm,v 1.4 2011/12/03 11:44:51 gavin Exp $ package Net::EPP::Frame::Command; use Net::EPP::Frame::Command::Check; use Net::EPP::Frame::Command::Create; use Net::EPP::Frame::Command::Delete; use Net::EPP::Frame::Command::Info; use Net::EPP::Frame::Command::Login; use Net::EPP::Frame::Command::Logout; use Net::EPP::Frame::Command::Poll; use Net::EPP::Frame::Command::Renew; use Net::EPP::Frame::Command::Transfer; use Net::EPP::Frame::Command::Update; use base qw(Net::EPP::Frame); use strict; =pod =head1 NAME Net::EPP::Frame::Command - an instance of L for client commands =head1 DESCRIPTION This module is a base class for the Net::EPP::Frame::* subclasses, you should never need to access it directly. =head1 OBJECT HIERARCHY L +----L +----L +----L =cut sub new { my $package = shift; my $self = $package->SUPER::new('command'); return bless($self, $package); } sub addObject() { my ($self, $object, $ns, $schema) = @_; my $obj = $self->createElement($self->getCommandType); $obj->setNamespace($ns, $object); $self->getNode($self->getCommandType)->addChild($obj); return $obj; } sub _addExtraElements { my $self = shift; $self->command->addChild($self->createElement($self->getCommandType)) if ($self->getCommandType ne ''); $self->command->addChild($self->createElement('clTRID')); $self->_addCommandElements; return 1; } sub _addCommandElements { } =pod =head1 METHODS my $object = $frame->addObject(@spec); This method creates and returns a new element corresponding to the data in C<@spec>, and appends it to the "command" element (as returned by the C method below). The L module can be used to quickly retrieve EPP object specifications. my $type = $frame->getCommandType; This method returns a scalar containing the command type (eg L<'create'>). my $type = $frame->getCommandNode; This method returns the L object corresponding to the command in question, eg the CcreateE> element (for a L object). It is within this element that EPP objects are placed. my $node = $frame->command; This method returns the L object corresponding to the CcommandE> element. my $node = $frame->clTRID; This method returns the L object corresponding to the CclTRIDE> element. =cut sub getCommandType { my $self = shift; my $type = ref($self); my $me = __PACKAGE__; $type =~ s/^$me\:+//; $type =~ s/\:{2}.+//; return lc($type); } sub getCommandNode { my $self = shift; return $self->getNode($self->getCommandType); } sub command { $_[0]->getNode('command') } sub clTRID { $_[0]->getNode('clTRID') } =pod my $extension = $frame->extension; This method returns the L object corresponding to the CextensionE> element. If one does not exist, it will be created and inserted at the correct position. =cut sub extension { my $self = shift; my $extension = $self->getNode('extension'); $extension = $self->getCommandNode->parentNode->insertAfter($self->createElement('extension'), $self->getCommandNode) if (!$extension); return $extension; } =pod my $element = $frame->createExtensionElementFor($xmlns); This methods creates a new element in the CextensionE> element for the EPP extension specified by C<$xmlns> which can be obtained from L. The element's tag name will correspond to the command name (C, C etc). Example usage: my $frame = Net::EPP::Frame::Command::Info::Domain->new; my $element = $frame->createExtensionElementFor( Net::EPP::Frame::ObjectSpec->xmlns('foobar') ); // prints print $element->toString(); =cut sub createExtensionElementFor { my ($self, $xmlns) = @_; return $self->extension->appendChild($self->createElementNS($xmlns, $self->getCommandType)); } 1; Net-EPP-0.28/lib/Net/EPP/Frame/PaxHeader/Greeting.pm000755 777777 777777 00000000216 14760316103 025427 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Greeting.pm000755 €JªDI€GÖP;00000003717 14760316103 024214 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Greeting; use base qw(Net::EPP::Frame); 1; __END__ =pod =head1 NAME Net::EPP::Frame::Greeting - an instance of L for server greetings =head1 DESCRIPTION This module is a subclass of L that represents EPP server greetings. According to the EPP RFC, the server must transmit an EPP greeting frame to the client upon connection, and in response to an EPP ChelloE> command. The CgreetingE> frame provides information about the server, including the server time, access control rules, and a list of the object types that are provisioned by the server. =head1 OBJECT HIERARCHY L +----L +----L +----L =cut sub _addExtraElements { my $self = shift; $self->greeting->addChild($self->createElement('svID')); $self->greeting->addChild($self->createElement('svDate')); $self->greeting->addChild($self->createElement('svcMenu')); $self->greeting->addChild($self->createElement('dcp')); return 1; } =pod =head1 METHODS my $node = $frame->greeting; This method returns the L object corresponding to the CgreetingE> element. my $node = $frame->svID; This method returns the L object corresponding to the CsvIDE> element. my $node = $frame->svDate; This method returns the L object corresponding to the CsvDateE> element. my $node = $frame->svcMenu; This method returns the L object corresponding to the CsvcMenuE> element. my $node = $frame->dcp; This method returns the L object corresponding to the CdcpE> element. =cut sub greeting { $_[0]->getNode('greeting') } sub svID { $_[0]->getNode('svID') } sub svDate { $_[0]->getNode('svDate') } sub svcMenu { $_[0]->getNode('svcMenu') } sub dcp { $_[0]->getNode('dcp') } =cut Net-EPP-0.28/lib/Net/EPP/Frame/PaxHeader/Response.pm000755 777777 777777 00000000216 14760316103 025461 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Response.pm000755 €JªDI€GÖP;00000005464 14760316103 024247 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Response; use Net::EPP::ResponseCodes; use base qw(Net::EPP::Frame); =pod =head1 NAME Net::EPP::Frame::Response - an instance of L for server responses =head1 DESCRIPTION This module is a subclass of L that represents EPP server responses. Responses are sent back to clients when the server receives a CcommandE> frame. =head1 OBJECT HIERARCHY L +----L +----L +----L =cut sub new { my $package = shift; my $self = $package->SUPER::new('response'); return bless($self, $package); } sub _addExtraElements { my $self = shift; my $result = $self->createElement('result'); $result->appendChild($self->createElement('msg')); $self->response->addChild($result); $self->result->setAttribute('code' => COMMAND_FAILED); $self->response->addChild($self->createElement('resData')); my $trID = $self->createElement('trID'); $trID->addChild($self->createElement('clTRID')); $trID->addChild($self->createElement('svTRID')); $self->response->addChild($trID); return 1; } =pod =head1 METHODS my $node = $frame->response; This method returns the L object corresponding to the CcommandE> element. my $node = $frame->result; This method returns the L object corresponding to the CresultE> element. my $node = $frame->resData; This method returns the L object corresponding to the CresDataE> element. my $node = $frame->trID; This method returns the L object corresponding to the CtrIDE> element. my $node = $frame->clTRID; This method returns the L object corresponding to the CclTRIDE> element. my $node = $frame->svTRID; This method returns the L object corresponding to the CsvTRIDE> element. =cut sub response { $_[0]->getNode('response') } sub result { $_[0]->getNode('result') } sub resData { $_[0]->getNode('resData') } sub trID { $_[0]->getNode('trID') } sub clTRID { $_[0]->getNode('clTRID') } sub svTRID { $_[0]->getNode('svTRID') } =pod my $msg = $frame->code; This method returns the code attribute of the CresultE> element. =cut sub code { my $self = shift; my $result = $self->result; if ($result) { return $result->getAttribute('code'); } return COMMAND_FAILED; } =pod my $msg = $frame->msg; This method returns a string containing the text content of the CmsgE> element. =cut sub msg { my $self = shift; my $msgs = $self->getElementsByLocalName('msg'); return $msgs->shift->textContent if ($msgs->size == 1); } 1; Net-EPP-0.28/lib/Net/EPP/Frame/PaxHeader/Command000755 777777 777777 00000000102 14777665202 024637 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.493888993 Net-EPP-0.28/lib/Net/EPP/Frame/Command/000755 €JªDI€GÖP;00000000000 14777665202 023474 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Logout.pm000755 777777 777777 00000000216 14760316103 026512 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Logout.pm000755 €JªDI€GÖP;00000001073 14760316103 025270 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Logout; use base qw(Net::EPP::Frame::Command); use strict; =pod =head1 NAME Net::EPP::Frame::Command::Logout - an instance of L for the EPP ClogoutE> command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =head1 METHODS This module does not define any methods in addition to those it inherits from its ancestors. =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Update.pm000755 777777 777777 00000000216 14760316103 026463 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Update.pm000755 €JªDI€GÖP;00000002765 14760316103 025252 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Update; use Net::EPP::Frame::Command::Update::Contact; use Net::EPP::Frame::Command::Update::Domain; use Net::EPP::Frame::Command::Update::Host; use base qw(Net::EPP::Frame::Command); use strict; =pod =head1 NAME Net::EPP::Frame::Command::Update - an instance of L for the EPP CupdateE> command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =head1 METHODS =cut sub add { my $self = shift; foreach my $el ($self->getNode('update')->getChildNodes->shift->getChildNodes) { my (undef, $name) = split(/:/, $el->localName, 2); return $el if ($name eq 'add'); } } sub rem { my $self = shift; foreach my $el ($self->getNode('update')->getChildNodes->shift->getChildNodes) { my (undef, $name) = split(/:/, $el->localName, 2); return $el if ($name eq 'rem'); } } sub chg { my $self = shift; foreach my $el ($self->getNode('update')->getChildNodes->shift->getChildNodes) { my (undef, $name) = split(/:/, $el->localName, 2); return $el if ($name eq 'chg'); } } =pod my $el = $frame->add; my $el = $frame->rem; my $el = $frame->chg; These methods return the elements that should be used to contain the changes to be made to the object (ie C, C, C). =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Delete.pm000755 777777 777777 00000000216 14760316103 026443 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Delete.pm000755 €JªDI€GÖP;00000001304 14760316103 025216 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Delete; use base qw(Net::EPP::Frame::Command); use Net::EPP::Frame::Command::Delete::Contact; use Net::EPP::Frame::Command::Delete::Domain; use Net::EPP::Frame::Command::Delete::Host; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Delete - an instance of L for the EPP CdeleteE> command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =head1 METHODS This module does not define any methods in addition to those it inherits from its ancestors. =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Renew.pm000755 777777 777777 00000000216 14760316103 026321 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Renew.pm000755 €JªDI€GÖP;00000001144 14760316103 025076 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Renew; use Net::EPP::Frame::Command::Renew::Domain; use base qw(Net::EPP::Frame::Command); use strict; =pod =head1 NAME Net::EPP::Frame::Command::Renew - an instance of L for the EPP CrenewE> command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =head1 METHODS This module does not define any methods in addition to those it inherits from its ancestors. =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Renew000755 777777 777777 00000000102 14777665202 025717 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.487403573 Net-EPP-0.28/lib/Net/EPP/Frame/Command/Renew/000755 €JªDI€GÖP;00000000000 14777665202 024554 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Create.pm000755 777777 777777 00000000216 14760316103 026444 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Create.pm000755 €JªDI€GÖP;00000001304 14760316103 025217 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Create; use base qw(Net::EPP::Frame::Command); use Net::EPP::Frame::Command::Create::Domain; use Net::EPP::Frame::Command::Create::Host; use Net::EPP::Frame::Command::Create::Contact; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Create - an instance of L for the EPP CcreateE> command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =head1 METHODS This module does not define any methods in addition to those it inherits from its ancestors. =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Update000755 777777 777777 00000000102 14777665202 026061 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.494225287 Net-EPP-0.28/lib/Net/EPP/Frame/Command/Update/000755 €JªDI€GÖP;00000000000 14777665202 024716 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Check.pm000755 777777 777777 00000000216 14760316103 026256 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Check.pm000755 €JªDI€GÖP;00000001275 14760316103 025040 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Check; use base qw(Net::EPP::Frame::Command); use Net::EPP::Frame::Command::Check::Domain; use Net::EPP::Frame::Command::Check::Contact; use Net::EPP::Frame::Command::Check::Host; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Check - an instance of L for the EPP CcheckE> command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =head1 METHODS This module does not define any methods in addition to those it inherits from its ancestors. =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Delete000755 777777 777777 00000000102 14777665202 026041 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.481851951 Net-EPP-0.28/lib/Net/EPP/Frame/Command/Delete/000755 €JªDI€GÖP;00000000000 14777665202 024676 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Transfer000755 777777 777777 00000000102 14777665202 026423 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.483486087 Net-EPP-0.28/lib/Net/EPP/Frame/Command/Transfer/000755 €JªDI€GÖP;00000000000 14777665202 025260 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Info000755 777777 777777 00000000102 14777665202 025532 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.493213739 Net-EPP-0.28/lib/Net/EPP/Frame/Command/Info/000755 €JªDI€GÖP;00000000000 14777665202 024367 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Transfer.pm000755 777777 777777 00000000216 14760316103 027025 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Transfer.pm000755 €JªDI€GÖP;00000001412 14760316103 025600 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Transfer; use Net::EPP::Frame::Command::Transfer::Contact; use Net::EPP::Frame::Command::Transfer::Domain; use base qw(Net::EPP::Frame::Command); use strict; =pod =head1 NAME Net::EPP::Frame::Command::Transfer - an instance of L for the EPP CtransferE> command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =head1 METHODS $frame->setOp($op); Sets the op of the frame (i.e. C, C, C or C). =cut sub setOp { my ($self, $op) = @_; $self->getCommandNode->setAttribute('op', $op); } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Info.pm000755 777777 777777 00000000216 14760316103 026134 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Info.pm000755 €JªDI€GÖP;00000001266 14760316103 024716 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Info; use Net::EPP::Frame::Command::Info::Contact; use Net::EPP::Frame::Command::Info::Domain; use Net::EPP::Frame::Command::Info::Host; use base qw(Net::EPP::Frame::Command); use strict; =pod =head1 NAME Net::EPP::Frame::Command::Info - an instance of L for the EPP CinfoE> command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =head1 METHODS This module does not define any methods in addition to those it inherits from its ancestors. =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Login.pm000755 777777 777777 00000000216 14760316103 026311 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Login.pm000755 €JªDI€GÖP;00000004166 14760316103 025075 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Login; use base qw(Net::EPP::Frame::Command); use strict; =pod =head1 NAME Net::EPP::Frame::Command::Login - an instance of L for the EPP CloginE> command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =cut sub _addCommandElements { my $self = shift; $self->getNode('login')->addChild($self->createElement('clID')); $self->getNode('login')->addChild($self->createElement('pw')); $self->getNode('login')->addChild($self->createElement('options')); $self->getNode('options')->addChild($self->createElement('version')); $self->getNode('options')->addChild($self->createElement('lang')); $self->getNode('login')->addChild($self->createElement('svcs')); } =pod =head1 METHODS my $node = $frame->clID; This method returns the L object corresponding to the CclIDE> element. my $node = $frame->pw; This method returns the L object corresponding to the CpwE> element. my $node = $frame->newPW; This method returns the L object corresponding to the CnewPWE> element. my $node = $frame->svcs; This method returns the L object corresponding to the CsvcsE> element. my $node = $frame->options; This method returns the L object corresponding to the CoptionsE> element. my $node = $frame->version; This method returns the L object corresponding to the CversionE> element. my $node = $frame->lang; This method returns the L object corresponding to the ClangE> element. =cut sub clID { $_[0]->getNode('clID') } sub pw { $_[0]->getNode('pw') } sub newPW { $_[0]->getNode('newPW') } sub svcs { $_[0]->getNode('svcs') } sub options { $_[0]->getNode('options') } sub version { $_[0]->getNode('version') } sub lang { $_[0]->getNode('lang') } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Poll.pm000755 777777 777777 00000000216 14760316103 026147 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Poll.pm000755 €JªDI€GÖP;00000001205 14760316103 024722 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Poll; use Net::EPP::Frame::Command::Poll::Req; use Net::EPP::Frame::Command::Poll::Ack; use base qw(Net::EPP::Frame::Command); use strict; =pod =head1 NAME Net::EPP::Frame::Command::Poll - an instance of L for the EPP CPollE> command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =head1 METHODS This module does not define any methods in addition to those it inherits from its ancestors. =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Create000755 777777 777777 00000000102 14777665202 026042 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.486111189 Net-EPP-0.28/lib/Net/EPP/Frame/Command/Create/000755 €JªDI€GÖP;00000000000 14777665202 024677 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Check000755 777777 777777 00000000102 14777665202 025654 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 30 mtime=1744792194.491663228 Net-EPP-0.28/lib/Net/EPP/Frame/Command/Check/000755 €JªDI€GÖP;00000000000 14777665202 024511 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/Frame/Command/PaxHeader/Poll000755 777777 777777 00000000101 14777665202 025544 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 29 mtime=1744792194.48012698 Net-EPP-0.28/lib/Net/EPP/Frame/Command/Poll/000755 €JªDI€GÖP;00000000000 14777665202 024402 5ustar00gavin.brownICANN\Domain Users000000 000000 Net-EPP-0.28/lib/Net/EPP/Frame/Command/Poll/PaxHeader/Ack.pm000644 777777 777777 00000000216 14760316103 026642 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Poll/Ack.pm000644 €JªDI€GÖP;00000001676 14760316103 025431 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Poll::Ack; use base qw(Net::EPP::Frame::Command::Poll); use strict; =pod =head1 NAME Net::EPP::Frame::Command::Poll::Ack - an instance of L for the EPP CPollE> acknowledge command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('poll'), $package); $self->getCommandNode->setAttribute('op' => 'ack'); return $self; } =pod =head1 METHODS $frame->setMsgID($id); This method sets the C attribute on the CpollE> element that is used to specify the message ID being acknowleged. =cut sub setMsgID { my ($self, $id) = @_; $self->getCommandNode->setAttribute('msgID' => $id); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Poll/PaxHeader/Req.pm000644 777777 777777 00000000216 14760316103 026673 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Poll/Req.pm000644 €JªDI€GÖP;00000001402 14760316103 025445 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Poll::Req; use base qw(Net::EPP::Frame::Command::Poll); use strict; =pod =head1 NAME Net::EPP::Frame::Command::Poll::Req - an instance of L for the EPP CPollE> request command. =head1 OBJECT HIERARCHY L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('poll'), $package); $self->getCommandNode->setAttribute('op' => 'req'); return $self; } =head1 METHODS This module does not define any methods in addition to those it inherits from its ancestors. =cut 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Check/PaxHeader/Domain.pm000644 777777 777777 00000000216 14760316103 027462 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Check/Domain.pm000644 €JªDI€GÖP;00000004151 14760316103 026240 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Check::Domain; use base qw(Net::EPP::Frame::Command::Check); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Check::Domain - an instance of L for domain names. =head1 SYNOPSIS use Net::EPP::Frame::Command::Check::Domain; use strict; my $check = Net::EPP::Frame::Command::Check::Domain->new; $check->addDomain('example-1.tld'); $check->addDomain('example-2.tld'); $check->addDomain('example-2.tld'); print $check->toString(1); This results in an XML document like this: example-1.tldE/domain:name> example-2.tldE/domain:name> example-3.tldE/domain:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('check'), $package); $self->addObject(Net::EPP::Frame::ObjectSpec->spec('domain')); return $self; } =pod =head1 METHODS $frame->addDomain($domain_name); This adds a domain name to the list of domains to be checked. =cut sub addDomain { my ($self, $domain) = @_; my $name = $self->createElement('domain:name'); $name->appendText($domain); $self->getNode('check')->getChildNodes->shift->appendChild($name); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Check/PaxHeader/Host.pm000644 777777 777777 00000000216 14760316103 027170 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Check/Host.pm000644 €JªDI€GÖP;00000004072 14760316103 025750 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Check::Host; use base qw(Net::EPP::Frame::Command::Check); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Check::Host - an instance of L for host objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Check::Host; use strict; my $check = Net::EPP::Frame::Command::Check::Host->new; $check->addHost('example-1.tld'); $check->addHost('example-2.tld'); $check->addHost('example-2.tld'); print $check->toString(1); This results in an XML document like this: ns0.example-1.tldE/host:name> ns1.example-2.tldE/host:name> ns2.example-3.tldE/host:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('check'), $package); $self->addObject(Net::EPP::Frame::ObjectSpec->spec('host')); return $self; } =pod =head1 METHODS $frame->addHost($host_name); This adds a hostname to the list of hosts to be checked. =cut sub addHost { my ($self, $host) = @_; my $name = $self->createElement('host:name'); $name->appendText($host); $self->getNode('check')->getChildNodes->shift->appendChild($name); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Check/PaxHeader/Contact.pm000644 777777 777777 00000000216 14760316103 027646 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Check/Contact.pm000644 €JªDI€GÖP;00000004167 14760316103 026433 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Check::Contact; use base qw(Net::EPP::Frame::Command::Check); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Check::Contact - an instance of L for contact objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Check::Contact; use strict; my $check = Net::EPP::Frame::Command::Check::Contact->new; $check->addContact('contact-id-01'); $check->addContact('contact-id-02'); $check->addContact('contact-id-03'); print $check->toString(1); This results in an XML document like this: contact-id-01E/contact:id> contact-id-02E/contact:id> contact-id-03E/contact:id> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('check'), $package); $self->addObject(Net::EPP::Frame::ObjectSpec->spec('contact')); return $self; } =pod =head1 METHODS $frame->addContact($contact_id); This adds a contact ID to the list of contacts to be checked. =cut sub addContact { my ($self, $contact) = @_; my $name = $self->createElement('contact:id'); $name->appendText($contact); $self->getNode('check')->getChildNodes->shift->appendChild($name); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Create/PaxHeader/Domain.pm000644 777777 777777 00000000216 14760316103 027650 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Create/Domain.pm000644 €JªDI€GÖP;00000014605 14760316103 026433 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Create::Domain; use List::Util qw(any); use base qw(Net::EPP::Frame::Command::Create); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Create::Domain - an instance of L for domain objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Create::Domain; use strict; my $create = Net::EPP::Frame::Command::Create::Domain->new; $create->setDomain('example.uk.com); print $create->toString(1); This results in an XML document like this: example-1.tldE/domain:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('create'), $package); $self->addObject(Net::EPP::Frame::ObjectSpec->spec('domain')); return $self; } =pod =head1 METHODS my $element = $frame->setDomain($domain_name); This sets the name of the object to be created. Returns the Cdomain:nameE> element. =cut sub setDomain { my ($self, $domain) = @_; my $name = $self->createElement('domain:name'); $name->appendText($domain); $self->getNode('create')->getChildNodes->shift->appendChild($name); return 1; } =pod =head1 $frame->setPeriod(1, 'y'); Set the initial registration period. The second argument is optional. =cut sub setPeriod { my ($self, $period, $unit) = @_; $unit = 'y' if (!defined($unit) || $unit eq ''); my $el = $self->createElement('domain:period'); $el->setAttribute('unit', $unit); $el->appendText(int($period)); $self->getNode('create')->getChildNodes->shift->appendChild($el); return 1; } =pod =head1 $frame->setRegistrant($id); Set the registrant. =cut sub setRegistrant { my ($self, $contact) = @_; my $registrant = $self->createElement('domain:registrant'); $registrant->appendText($contact); $self->getNode('create')->getChildNodes->shift->appendChild($registrant); return 1; } =pod =head1 $frame->setContacts({ 'admin' => 'H12345', 'tech' => 'H54321', 'billing' => 'H23451', })); Set the contacts. =cut sub setContacts { my ($self, $contacts) = @_; my $parent = $self->getNode('create')->getChildNodes->shift; foreach my $type (keys(%{$contacts})) { my $contact = $self->createElement('domain:contact'); $contact->setAttribute('type', $type); $contact->appendText($contacts->{$type}); $parent->appendChild($contact); } return 1; } # # Type of elements of @ns depends on NS model used by EPP server. # hostObj model: # each element is a name of NS host object # hostAttr model: # each element is a hashref: # { # name => 'ns1.example.com, # addrs => [ # { version => 'v4', addr => '192.168.0.10', }, # { version => 'v4', addr => '192.168.0.20', }, # ... # ]; # } # sub setNS { my ($self, @ns) = @_; if (ref $ns[0] eq 'HASH') { $self->addHostAttrNS(@ns); } else { $self->addHostObjNS(@ns); } return 1; } sub addHostAttrNS { my ($self, @ns) = @_; my $ns = $self->createElement('domain:ns'); # Adding attributes foreach my $host (@ns) { my $hostAttr = $self->createElement('domain:hostAttr'); # Adding NS name my $hostName = $self->createElement('domain:hostName'); $hostName->appendText($host->{name}); $hostAttr->appendChild($hostName); # Adding IP addresses if (exists $host->{addrs} && ref $host->{addrs} eq 'ARRAY') { foreach my $addr (@{$host->{addrs}}) { my $hostAddr = $self->createElement('domain:hostAddr'); $hostAddr->appendText($addr->{addr}); $hostAddr->setAttribute(ip => $addr->{version}); $hostAttr->appendChild($hostAddr); } } # Adding host info to frame $ns->appendChild($hostAttr); } $self->getNode('create')->getChildNodes->shift->appendChild($ns); return 1; } sub addHostObjNS { my ($self, @ns) = @_; my $ns = $self->createElement('domain:ns'); foreach my $host (@ns) { my $el = $self->createElement('domain:hostObj'); $el->appendText($host); $ns->appendChild($el); } $self->getNode('create')->getChildNodes->shift->appendChild($ns); return 1; } sub setAuthInfo { my ($self, $authInfo) = @_; my $el = $self->addEl('authInfo'); my $pw = $self->createElement('domain:pw'); $pw->appendText($authInfo); $el->appendChild($pw); return $el; } sub appendStatus { my ($self, $status) = @_; return $self->addEl('status', $status); } sub addEl { my ($self, $name, $value) = @_; my $el = $self->createElement('domain:' . $name); $el->appendText($value) if defined($value); $self->getNode('create')->getChildNodes->shift->appendChild($el); return $el; } =pod =head2 TTL Extension $frame->setTTLs({ NS => 3600, DS => 900, }); Specify TTLs for DNS records above the zone cut. The server must support the TTL extension. =cut sub setTTLs { my ($self, $ttls) = @_; foreach my $type (keys(%{$ttls})) { my $ttl = $self->createExtensionElementFor(Net::EPP::Frame::ObjectSpec->xmlns('ttl'))->appendChild($self->createElement('ttl')); $ttl->appendText($ttls->{$type}); if (any { $type eq $_ } qw(NS DS DNAME A AAAA)) { $ttl->setAttribute('for', $type); } else { $ttl->setAttribute('for', 'custom'); $ttl->setAttribute('custom', $type); } } } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Create/PaxHeader/Host.pm000644 777777 777777 00000000216 14760316103 027356 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Create/Host.pm000644 €JªDI€GÖP;00000006211 14760316103 026133 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Create::Host; use List::Util qw(any); use base qw(Net::EPP::Frame::Command::Create); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Create::Host - an instance of L for host objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Create::Host; use strict; my $create = Net::EPP::Frame::Command::Create::Host->new; $create->setHost('ns1.example.uk.com); print $create->toString(1); This results in an XML document like this: ns1.example.uk.com 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('create'), $package); $self->addObject(Net::EPP::Frame::ObjectSpec->spec('host')); return $self; } =pod =head1 METHODS my $element = $frame->setHost($host_name); This sets the name of the object to be created. Returns the host:nameE> element. =cut sub setHost { my ($self, $host) = @_; my $name = $self->createElement('host:name'); $name->appendText($host); $self->getNode('create')->getChildNodes->shift->appendChild($name); return 1; } =pod $frame->setAddr({ 'ip' => '10.0.0.1', 'version' => 'v4' }); This adds an IP address to the host object. EPP supports multiple addresses of different versions. =cut sub setAddr { my ($self, @addr) = @_; foreach my $ip (@addr) { my $hostAttr = $self->createElement('host:addr'); $hostAttr->appendText($ip->{ip}); $hostAttr->setAttribute('ip', $ip->{version}); $self->getNode('create')->getChildNodes->shift->appendChild($hostAttr); } return 1; } =pod =head2 TTL Extension $frame->setTTLs({ A => 3600, AAAA => 900, }); Specify TTLs for glue records. The server must support the TTL extension. =cut sub setTTLs { my ($self, $ttls) = @_; foreach my $type (keys(%{$ttls})) { my $ttl = $self->createExtensionElementFor(Net::EPP::Frame::ObjectSpec->xmlns('ttl'))->appendChild($self->createElement('ttl')); $ttl->appendText($ttls->{$type}); if (any { $type eq $_ } qw(NS DS DNAME A AAAA)) { $ttl->setAttribute('for', $type); } else { $ttl->setAttribute('for', 'custom'); $ttl->setAttribute('custom', $type); } } } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Create/PaxHeader/Contact.pm000644 777777 777777 00000000216 14760316103 030034 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Create/Contact.pm000644 €JªDI€GÖP;00000007050 14760316103 026613 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Create::Contact; use base qw(Net::EPP::Frame::Command::Create); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Create::Contact - an instance of L for contact objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Create::Contact; use strict; my $create = Net::EPP::Frame::Command::Create::Contact->new; $create->setContact('contact-id); print $create->toString(1); This results in an XML document like this: example-1.tldE/contact:id> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('create'), $package); $self->addObject(Net::EPP::Frame::ObjectSpec->spec('contact')); return $self; } =pod =head1 METHODS my $element = $frame->setContact($contact_id); This sets the contact ID of the object to be created. Returns the Ccontact:nameE> element. =cut sub setContact { my ($self, $id) = @_; return $self->addEl('id', $id); } sub setVoice { my ($self, $voice) = @_; return $self->addEl('voice', $voice); } sub setFax { my ($self, $fax) = @_; return $self->addEl('fax', $fax); } sub setEmail { my ($self, $email) = @_; return $self->addEl('email', $email); } sub setAuthInfo { my ($self, $authInfo) = @_; my $el = $self->addEl('authInfo'); my $pw = $self->createElement('contact:pw'); $pw->appendText($authInfo); $el->appendChild($pw); return $el; } sub addPostalInfo { my ($self, $type, $name, $org, $addr) = @_; my $el = $self->addEl('postalInfo'); $el->setAttribute('type', $type); my $nel = $self->createElement('contact:name'); $nel->appendText($name); my $oel = $self->createElement('contact:org'); $oel->appendText($org); my $ael = $self->createElement('contact:addr'); if (ref($addr->{street}) eq 'ARRAY') { foreach my $street (@{$addr->{street}}) { my $sel = $self->createElement('contact:street'); $sel->appendText($street); $ael->appendChild($sel); } } foreach my $name (qw(city sp pc cc)) { my $vel = $self->createElement('contact:' . $name); $vel->appendText($addr->{$name}); $ael->appendChild($vel); } $el->appendChild($nel); $el->appendChild($oel) if $org; $el->appendChild($ael); return $el; } sub appendStatus { my ($self, $status) = @_; return $self->addEl('status', $status); } sub addEl { my ($self, $name, $value) = @_; my $el = $self->createElement('contact:' . $name); $el->appendText($value) if defined($value); $self->getNode('create')->getChildNodes->shift->appendChild($el); return $el; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Info/PaxHeader/Domain.pm000644 777777 777777 00000000216 14760316103 027340 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Info/Domain.pm000644 €JªDI€GÖP;00000004146 14760316103 026122 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Info::Domain; use base qw(Net::EPP::Frame::Command::Info); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Info::Domain - an instance of L for domain names. =head1 SYNOPSIS use Net::EPP::Frame::Command::Info::Domain; use strict; my $info = Net::EPP::Frame::Command::Info::Domain->new; $info->setDomain('example.tld'); print $info->toString(1); This results in an XML document like this: example-1.tldE/domain:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('info'), $package); my $domain = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('domain')); return $self; } =pod =head1 METHODS $frame->setDomain($domain_name, $hosts); This specifies the domain name for which information is being requested. The C<$hosts> argument is the content of the C attribute (set to C by default). =cut sub setDomain { my ($self, $domain, $hosts) = @_; $hosts = ($hosts || 'all'); my $name = $self->createElement('domain:name'); $name->appendText($domain); $name->setAttribute('hosts', $hosts); $self->getNode('info')->getChildNodes->shift->appendChild($name); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Info/PaxHeader/Host.pm000644 777777 777777 00000000216 14760316103 027046 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Info/Host.pm000644 €JªDI€GÖP;00000003611 14760316103 025624 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Info::Host; use base qw(Net::EPP::Frame::Command::Info); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Info::Host - an instance of L for host objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Info::Host; use strict; my $info = Net::EPP::Frame::Command::Info::Host->new; $info->setHost('ns0.example.tld'); print $info->toString(1); This results in an XML document like this: ns0.example-1.tldE/host:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('info'), $package); my $host = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('host')); return $self; } =pod =head1 METHODS $frame->setHost($host_name); This specifies the hostname for which information is being requested. =cut sub setHost { my ($self, $host) = @_; my $name = $self->createElement('host:name'); $name->appendText($host); $self->getNode('info')->getChildNodes->shift->appendChild($name); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Info/PaxHeader/Contact.pm000644 777777 777777 00000000216 14760316103 027524 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Info/Contact.pm000644 €JªDI€GÖP;00000003663 14760316103 026311 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Info::Contact; use base qw(Net::EPP::Frame::Command::Info); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Info::Contact - an instance of L for contact objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Info::Contact; use strict; my $info = Net::EPP::Frame::Command::Info::Contact->new; $info->setContact('REG-12345'); print $info->toString(1); This results in an XML document like this: REG-12345E/contact:id> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('info'), $package); my $contact = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('contact')); return $self; } =pod =head1 METHODS $frame->setContact($contactID); This specifies the contact object for which information is being requested. =cut sub setContact { my ($self, $id) = @_; my $name = $self->createElement('contact:id'); $name->appendText($id); $self->getNode('info')->getChildNodes->shift->appendChild($name); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Transfer/PaxHeader/Domain.pm000644 777777 777777 00000000216 14760316103 030231 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Transfer/Domain.pm000644 €JªDI€GÖP;00000005371 14760316103 027014 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Transfer::Domain; use base qw(Net::EPP::Frame::Command::Transfer); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Transfer::Domain - an instance of L for domain objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Transfer::Domain; use strict; my $info = Net::EPP::Frame::Command::Transfer::Domain->new; $info->setOp('query'); $info->setDomain('example.tld'); print $info->toString(1); This results in an XML document like this: example.tldE/domain:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('transfer'), $package); my $domain = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('domain')); return $self; } =pod =head1 METHODS $frame->setDomain('example.tld'); This method specifies the domain name for the transfer. =cut sub setDomain { my ($self, $domain) = @_; my $name = $self->createElement('domain:name'); $name->appendText($domain); $self->getNode('transfer')->getChildNodes->shift->appendChild($name); return 1; } =pod $frame->period($years); This sets the optional renewal period for the transfer. =cut sub setPeriod { my ($self, $years) = @_; my $period = $self->createElement('domain:period'); $period->setAttribute('unit', 'y'); $period->appendText($years); $self->getNode('transfer')->getChildNodes->shift->appendChild($period); return 1; } =pod $frame->setAuthInfo($pw); This sets the authInfo code for the transfer. =cut sub setAuthInfo { my ($self, $code) = @_; my $pw = $self->createElement('domain:pw'); $pw->appendText($code); my $authInfo = $self->createElement('domain:authInfo'); $authInfo->appendChild($pw); $self->getNode('transfer')->getChildNodes->shift->appendChild($authInfo); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Transfer/PaxHeader/Contact.pm000644 777777 777777 00000000216 14760316103 030415 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Transfer/Contact.pm000644 €JªDI€GÖP;00000004611 14760316103 027174 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Transfer::Contact; use base qw(Net::EPP::Frame::Command::Transfer); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Transfer::Contact - an instance of L for contact objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Transfer::Contact; use strict; my $info = Net::EPP::Frame::Command::Transfer::Contact->new; $info->setOp('query'); $info->setContact('REG-12345'); print $info->toString(1); This results in an XML document like this: REG-12345E/contact:id> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('transfer'), $package); my $contact = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('contact')); return $self; } =pod =head1 METHODS $frame->setContact($contactID); This specifies the contact object for the transfer. =cut sub setContact { my ($self, $id) = @_; my $name = $self->createElement('contact:id'); $name->appendText($id); $self->getNode('transfer')->getChildNodes->shift->appendChild($name); return 1; } =pod $frame->setAuthInfo($pw); This sets the authInfo code for the transfer. =cut sub setAuthInfo { my ($self, $code) = @_; my $pw = $self->createElement('contact:pw'); $pw->appendText($code); my $authInfo = $self->createElement('contact:authInfo'); $authInfo->appendChild($pw); $self->getNode('transfer')->getChildNodes->shift->appendChild($authInfo); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Delete/PaxHeader/Domain.pm000644 777777 777777 00000000216 14760316103 027647 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Delete/Domain.pm000644 €JªDI€GÖP;00000003665 14760316103 026436 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Delete::Domain; use base qw(Net::EPP::Frame::Command::Delete); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Delete::Domain - an instance of L for domain names. =head1 SYNOPSIS use Net::EPP::Frame::Command::Delete::Domain; use strict; my $delete = Net::EPP::Frame::Command::Delete::Domain->new; $delete->setDomain('example.tld'); print $delete->toString(1); This results in an XML document like this: example.tldE/domain:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('delete'), $package); my $domain = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('domain')); return $self; } =pod =head1 METHODS $frame->setDomain($domain_name); This specifies the domain name to be deleted. =cut sub setDomain { my ($self, $domain) = @_; my $name = $self->createElement('domain:name'); $name->appendText($domain); $self->getNode('delete')->getChildNodes->shift->appendChild($name); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Delete/PaxHeader/Host.pm000644 777777 777777 00000000216 14760316103 027355 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Delete/Host.pm000644 €JªDI€GÖP;00000003615 14760316103 026137 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Delete::Host; use base qw(Net::EPP::Frame::Command::Delete); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Delete::Host - an instance of L for host objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Delete::Host; use strict; my $delete = Net::EPP::Frame::Command::Delete::Host->new; $delete->setHost('example.tld'); print $delete->toString(1); This results in an XML document like this: ns0.example.tldE/host:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('delete'), $package); my $host = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('host')); return $self; } =pod =head1 METHODS $frame->setHost($host_name); This specifies the host object to be deleted. =cut sub setHost { my ($self, $host) = @_; my $name = $self->createElement('host:name'); $name->appendText($host); $self->getNode('delete')->getChildNodes->shift->appendChild($name); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Delete/PaxHeader/Contact.pm000644 777777 777777 00000000216 14760316103 030033 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Delete/Contact.pm000644 €JªDI€GÖP;00000003702 14760316103 026612 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Delete::Contact; use base qw(Net::EPP::Frame::Command::Delete); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Delete::Contact - an instance of L for contact objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Delete::Contact; use strict; my $delete = Net::EPP::Frame::Command::Delete::Contact->new; $delete->setContact('contact-id'); print $delete->toString(1); This results in an XML document like this: contact-idE/contact:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('delete'), $package); my $contact = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('contact')); return $self; } =pod =head1 METHODS $frame->setContact($domain_name); This specifies the contact object to be deleted. =cut sub setContact { my ($self, $id) = @_; my $name = $self->createElement('contact:id'); $name->appendText($id); $self->getNode('delete')->getChildNodes->shift->appendChild($name); return 1; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Update/PaxHeader/Domain.pm000644 777777 777777 00000000216 14760316103 027667 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Update/Domain.pm000644 €JªDI€GÖP;00000021615 14760316103 026451 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Update::Domain; use List::Util qw(any); use base qw(Net::EPP::Frame::Command::Update); use Net::EPP::Frame::ObjectSpec; use strict; use warnings; our $DNSSEC_URN = 'urn:ietf:params:xml:ns:secDNS-1.1'; =pod =head1 NAME Net::EPP::Frame::Command::Update::Domain - an instance of L for domain names. =head1 SYNOPSIS use Net::EPP::Frame::Command::Update::Domain; use strict; my $info = Net::EPP::Frame::Command::Update::Domain->new; $info->setDomain('example.tld'); print $info->toString(1); This results in an XML document like this: example-1.tldE/domain:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('update'), $package); my $domain = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('domain')); foreach my $grp (qw(add rem chg)) { my $el = $self->createElement(sprintf('domain:%s', $grp)); $self->getNode('update')->getChildNodes->shift->appendChild($el); } return $self; } =pod =head1 METHODS $frame->setDomain($domain_name); This specifies the domain name to be updated. =cut sub setDomain { my ($self, $domain) = @_; my $name = $self->createElement('domain:name'); $name->appendText($domain); my $n = $self->getNode('update')->getChildNodes->shift; $n->insertBefore($name, $n->firstChild); return 1; } =pod $frame->addStatus($type, $info); Add a status of $type with the optional extra $info. =cut sub addStatus { my ($self, $type, $info) = @_; my $status = $self->createElement('domain:status'); $status->setAttribute('s', $type); $status->setAttribute('lang', 'en'); if ($info) { $status->appendText($info); } $self->getElementsByLocalName('domain:add')->shift->appendChild($status); return 1; } =pod $frame->remStatus($type); Remove a status of $type. =cut sub remStatus { my ($self, $type) = @_; my $status = $self->createElement('domain:status'); $status->setAttribute('s', $type); $self->getElementsByLocalName('domain:rem')->shift->appendChild($status); return 1; } =pod $frame->addContact($type, $contact); Add a contact of $type. =cut sub addContact { my ($self, $type, $contact_id) = @_; my $contact = $self->createElement('domain:contact'); $contact->setAttribute('type', $type); $contact->appendText($contact_id); $self->getElementsByLocalName('domain:add')->shift->appendChild($contact); return 1; } =pod $frame->remContact($type, $contact); Remove a contact of $type. =cut sub remContact { my ($self, $type, $contact_id) = @_; my $contact = $self->createElement('domain:contact'); $contact->setAttribute('type', $type); $contact->appendText($contact_id); $self->getElementsByLocalName('domain:rem')->shift->appendChild($contact); return 1; } =pod $frame->chgAuthinfo($auth); Change the authinfo. =cut sub chgAuthInfo { my ($self, $authInfo) = @_; my $el = $self->createElement('domain:authInfo'); my $pw = $self->createElement('domain:pw'); $pw->appendText($authInfo); $el->appendChild($pw); $self->getElementsByLocalName('domain:chg')->shift->appendChild($el); return 1; } =pod $frame->chgRegistrant($registrant); Change the authinfo. =cut sub chgRegistrant { my ($self, $contact) = @_; my $registrant = $self->createElement('domain:registrant'); $registrant->appendText($contact); $self->getElementsByLocalName('domain:chg')->shift->appendChild($registrant); return 1; } =pod $frame->addNS('ns0.example.com'); # host object mode $frame->addNS({'name' => 'ns0.example.com', 'addrs' => [ { 'addr' => '127.0.0.1', 'type' => 4 } ] }); # host attribute mode =cut sub addNS { my ($self, @ns) = @_; if (ref $ns[0] eq 'HASH') { $self->addHostAttrNS(@ns); } else { $self->addHostObjNS(@ns); } return 1; } sub addHostAttrNS { my ($self, @ns) = @_; my $ns = $self->createElement('domain:ns'); # Adding attributes foreach my $host (@ns) { my $hostAttr = $self->createElement('domain:hostAttr'); # Adding NS name my $hostName = $self->createElement('domain:hostName'); $hostName->appendText($host->{name}); $hostAttr->appendChild($hostName); # Adding IP addresses if (exists $host->{addrs} && ref $host->{addrs} eq 'ARRAY') { foreach my $addr (@{$host->{addrs}}) { my $hostAddr = $self->createElement('domain:hostAddr'); $hostAddr->appendText($addr->{addr}); $hostAddr->setAttribute(ip => $addr->{version}); $hostAttr->appendChild($hostAddr); } } # Adding host info to frame $ns->appendChild($hostAttr); } $self->getElementsByLocalName('domain:add')->shift->appendChild($ns); return 1; } sub addHostObjNS { my ($self, @ns) = @_; my $ns = $self->createElement('domain:ns'); foreach my $host (@ns) { my $el = $self->createElement('domain:hostObj'); $el->appendText($host); $ns->appendChild($el); } $self->getElementsByLocalName('domain:add')->shift->appendChild($ns); return 1; } =pod $frame->remNS('ns0.example.com'); # host object mode $frame->remNS({'name' => 'ns0.example.com', 'addrs' => [ { 'addr' => '127.0.0.1', 'type' => 4 } ] }); # host attribute mode =cut sub remNS { my ($self, @ns) = @_; if (ref $ns[0] eq 'HASH') { $self->remHostAttrNS(@ns); } else { $self->remHostObjNS(@ns); } return 1; } sub remHostAttrNS { my ($self, @ns) = @_; my $ns = $self->createElement('domain:ns'); # Adding attributes foreach my $host (@ns) { my $hostAttr = $self->createElement('domain:hostAttr'); # Adding NS name my $hostName = $self->createElement('domain:hostName'); $hostName->appendText($host->{name}); $hostAttr->appendChild($hostName); # Adding IP addresses if (exists $host->{addrs} && ref $host->{addrs} eq 'ARRAY') { foreach my $addr (@{$host->{addrs}}) { my $hostAddr = $self->createElement('domain:hostAddr'); $hostAddr->appendText($addr->{addr}); $hostAddr->setAttribute(ip => $addr->{version}); $hostAttr->appendChild($hostAddr); } } # Adding host info to frame $ns->appendChild($hostAttr); } $self->getElementsByLocalName('domain:rem')->shift->appendChild($ns); return 1; } sub remHostObjNS { my ($self, @ns) = @_; my $ns = $self->createElement('domain:ns'); foreach my $host (@ns) { my $el = $self->createElement('domain:hostObj'); $el->appendText($host); $ns->appendChild($el); } $self->getElementsByLocalName('domain:rem')->shift->appendChild($ns); return 1; } =pod =head2 DNSSEC methods =cut sub _get_dnsssec { my $self = shift; my $tag = shift; my $el = self->getElementsByTagNameNS($DNSSEC_URN, $tag); return $el if $el; my $ext = $self->getNode('extension'); $ext = $self->getNode('command')->addNewChild(undef, 'extension') if not defined $ext; my $upd = $ext->addNewChild($DNSSEC_URN, 'secDNS:update'); $upd->addNewChild($DNSSEC_URN, 'secDNS:add'); $upd->addNewChild($DNSSEC_URN, 'secDNS:rem'); return $self->_get_dnssec($tag); } =pod =head2 TTL Extension $frame->chgTTLs({ NS => 3600, DS => 900, }); Specify TTLs for DNS records above the zone cut. The server must support the TTL extension. =cut sub chgTTLs { my ($self, $ttls) = @_; foreach my $type (keys(%{$ttls})) { my $ttl = $self->createExtensionElementFor(Net::EPP::Frame::ObjectSpec->xmlns('ttl'))->appendChild($self->createElement('ttl')); $ttl->appendText($ttls->{$type}); if (any { $type eq $_ } qw(NS DS DNAME A AAAA)) { $ttl->setAttribute('for', $type); } else { $ttl->setAttribute('for', 'custom'); $ttl->setAttribute('custom', $type); } } } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Update/PaxHeader/Host.pm000644 777777 777777 00000000216 14760316103 027375 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Update/Host.pm000644 €JªDI€GÖP;00000012276 14760316103 026162 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Update::Host; use List::Util qw(any); use base qw(Net::EPP::Frame::Command::Update); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Update::Host - an instance of L for host objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Update::Host; use strict; my $info = Net::EPP::Frame::Command::Update::Host->new; $info->setHost('ns0.example.tld'); print $info->toString(1); This results in an XML document like this: example-1.tldE/host:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('update'), $package); my $host = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('host')); # 'chg' element's contents are not optional for hosts, so we'll add # this element only when we plan to use it (accessor is overriden) foreach my $grp (qw(add rem)) { my $el = $self->createElement(sprintf('host:%s', $grp)); $self->getNode('update')->getChildNodes->shift->appendChild($el); } return $self; } =pod =head1 METHODS $frame->setHost($host_name); This specifies the host object to be updated. =cut sub setHost { my ($self, $host) = @_; my $name = $self->createElement('host:name'); $name->appendText($host); my $n = $self->getNode('update')->getChildNodes->shift; $n->insertBefore($name, $n->firstChild); return 1; } =pod $frame->addStatus($type, $info); Add a status of $type with the optional extra $info. =cut sub addStatus { my ($self, $type, $info) = @_; my $status = $self->createElement('host:status'); $status->setAttribute('s', $type); $status->setAttribute('lang', 'en'); if ($info) { $status->appendText($info); } $self->getElementsByLocalName('host:add')->shift->appendChild($status); return 1; } =pod $frame->remStatus($type); Remove a status of $type. =cut sub remStatus { my ($self, $type) = @_; my $status = $self->createElement('host:status'); $status->setAttribute('s', $type); $self->getElementsByLocalName('host:rem')->shift->appendChild($status); return 1; } =pod $frame->addAddr({ 'ip' => '10.0.0.1', 'version' => 'v4' }); Add a set of IP addresses to the host object. EPP supports multiple addresses of different versions. =cut sub addAddr { my ($self, @addr) = @_; foreach my $ip (@addr) { my $el = $self->createElement('host:addr'); $el->appendText($ip->{ip}); $el->setAttribute('ip', $ip->{version}); $self->getElementsByLocalName('host:add')->shift->appendChild($el); } return 1; } =pod $frame->remAddr({ 'ip' => '10.0.0.2', 'version' => 'v4' }); Remove a set of IP addresses from the host object. EPP supports multiple addresses of different versions. =cut sub remAddr { my ($self, @addr) = @_; foreach my $ip (@addr) { my $el = $self->createElement('host:addr'); $el->appendText($ip->{ip}); $el->setAttribute('ip', $ip->{version}); $self->getElementsByLocalName('host:rem')->shift->appendChild($el); } return 1; } =pod my $el = $frame->chg; Lazy-building of 'host:chg'element. =cut sub chg { my $self = shift; my $chg = $self->getElementsByLocalName('host:chg')->shift; if ($chg) { return $chg; } else { my $el = $self->createElement('host:chg'); $self->getNode('update')->getChildNodes->shift->appendChild($el); return $el; } } =pod $frame->chgName('ns2.example.com'); Change a name of host. =cut sub chgName { my ($self, $name) = @_; my $el = $self->createElement('host:name'); $el->appendText($name); $self->chg->appendChild($el); } =pod =head2 TTL Extension $frame->chgTTLs({ A => 3600, AAAA => 900, }); Specify TTLs for glue records. The server must support the TTL extension. =cut sub chgTTLs { my ($self, $ttls) = @_; foreach my $type (keys(%{$ttls})) { my $ttl = $self->createExtensionElementFor(Net::EPP::Frame::ObjectSpec->xmlns('ttl'))->appendChild($self->createElement('ttl')); $ttl->appendText($ttls->{$type}); if (any { $type eq $_ } qw(NS DS DNAME A AAAA)) { $ttl->setAttribute('for', $type); } else { $ttl->setAttribute('for', 'custom'); $ttl->setAttribute('custom', $type); } } } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Update/PaxHeader/Contact.pm000644 777777 777777 00000000216 14760316103 030053 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Update/Contact.pm000644 €JªDI€GÖP;00000011652 14760316103 026635 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Update::Contact; use base qw(Net::EPP::Frame::Command::Update); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Update::Contact - an instance of L for contact objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Update::Contact; use strict; my $info = Net::EPP::Frame::Command::Update::Contact->new; $info->setContact('REG-12345'); print $info->toString(1); This results in an XML document like this: REG-12345 example-1.tldE/contact:id> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('update'), $package); my $contact = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('contact')); foreach my $grp (qw(add rem chg)) { my $el = $self->createElement(sprintf('contact:%s', $grp)); $self->getNode('update')->getChildNodes->shift->appendChild($el); } return $self; } =pod =head1 METHODS $frame->setContact($id); This specifies the contact object to be updated. =cut sub setContact { my ($self, $id) = @_; my $el = $self->createElement('contact:id'); $el->appendText($id); my $n = $self->getNode('update')->getChildNodes->shift; $n->insertBefore($el, $n->firstChild); return 1; } =pod $frame->chgVoice($voice); Change the contacts voice number. =cut sub chgVoice { my ($self, $voice) = @_; return $self->addEl('voice', $voice); } =pod $frame->chgFax($fax); Change the contacts voice number. =cut sub chgFax { my ($self, $fax) = @_; return $self->addEl('fax', $fax); } =pod $frame->chgEmail($email); Change the contacts email. =cut sub chgEmail { my ($self, $email) = @_; return $self->addEl('email', $email); } =pod $frame->addStatus($type, $info); Add a status of $type with the optional extra $info. =cut sub addStatus { my ($self, $type, $info) = @_; my $status = $self->createElement('contact:status'); $status->setAttribute('s', $type); $status->setAttribute('lang', 'en'); if ($info) { $status->appendText($info); } $self->getElementsByLocalName('contact:add')->shift->appendChild($status); return 1; } =pod $frame->remStatus($type); Remove a status of $type. =cut sub remStatus { my ($self, $type) = @_; my $status = $self->createElement('contact:status'); $status->setAttribute('s', $type); $self->getElementsByLocalName('contact:rem')->shift->appendChild($status); return 1; } sub chgPostalInfo { my ($self, $type, $name, $org, $addr) = @_; my $el = $self->createElement('contact:postalInfo'); $el->setAttribute('type', $type); my $nel = $self->createElement('contact:name'); $nel->appendText($name); my $oel = $self->createElement('contact:org'); $oel->appendText($org); my $ael = $self->createElement('contact:addr'); if (ref($addr->{street}) eq 'ARRAY') { foreach my $street (@{$addr->{street}}) { my $sel = $self->createElement('contact:street'); $sel->appendText($street); $ael->appendChild($sel); } } foreach my $name (qw(city sp pc cc)) { my $vel = $self->createElement('contact:' . $name); $vel->appendText($addr->{$name}); $ael->appendChild($vel); } $el->appendChild($nel); $el->appendChild($oel) if $org; $el->appendChild($ael); $self->getElementsByLocalName('contact:chg')->shift->appendChild($el); return $el; } =pod $frame->chgAuthinfo($auth); Change the authinfo. =cut sub chgAuthInfo { my ($self, $authInfo) = @_; my $el = $self->createElement('contact:authInfo'); my $pw = $self->createElement('contact:pw'); $pw->appendText($authInfo); $el->appendChild($pw); $self->getElementsByLocalName('contact:chg')->shift->appendChild($el); return 1; } sub addEl { my ($self, $name, $value) = @_; my $el = $self->createElement('contact:' . $name); $el->appendText($value) if defined($value); $self->getElementsByLocalName('contact:chg')->shift->appendChild($el); return $el; } 1; Net-EPP-0.28/lib/Net/EPP/Frame/Command/Renew/PaxHeader/Domain.pm000644 777777 777777 00000000216 14760316103 027525 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/lib/Net/EPP/Frame/Command/Renew/Domain.pm000644 €JªDI€GÖP;00000005101 14760316103 026277 0ustar00gavin.brownICANN\Domain Users000000 000000 package Net::EPP::Frame::Command::Renew::Domain; use base qw(Net::EPP::Frame::Command::Renew); use Net::EPP::Frame::ObjectSpec; use strict; =pod =head1 NAME Net::EPP::Frame::Command::Renew::Domain - an instance of L for domain objects. =head1 SYNOPSIS use Net::EPP::Frame::Command::Renew::Domain; use strict; my $info = Net::EPP::Frame::Command::Renew::Domain->new; $info->setDomain('example.tld'); print $info->toString(1); This results in an XML document like this: example.tldE/domain:name> 0cf1b8f7e14547d26f03b7641660c641d9e79f45 =head1 OBJECT HIERARCHY L +----L +----L +----L +----L +----L =cut sub new { my $package = shift; my $self = bless($package->SUPER::new('renew'), $package); my $domain = $self->addObject(Net::EPP::Frame::ObjectSpec->spec('domain')); return $self; } =pod =head1 METHODS $frame->setDomain('example.tld'); This method specifies the domain name for the renew. =cut sub setDomain { my ($self, $domain) = @_; my $name = $self->createElement('domain:name'); $name->appendText($domain); $self->getNode('renew')->getChildNodes->shift->appendChild($name); return 1; } =pod $frame->period($years); This sets the optional renewal period. =cut sub setPeriod { my ($self, $years) = @_; my $period = $self->createElement('domain:period'); $period->setAttribute('unit', 'y'); $period->appendText($years); $self->getNode('renew')->getChildNodes->shift->appendChild($period); return 1; } =pod $frame->setCurExpDate($date) This sets the current expiry date for the domain. =cut sub setCurExpDate { my ($self, $date) = @_; my $cur = $self->createElement('domain:curExpDate'); $cur->appendText($date); $self->getNode('renew')->getChildNodes->shift->appendChild($cur); return 1; } 1; Net-EPP-0.28/t/PaxHeader/use.t000755 777777 777777 00000000253 14760316103 021600 xustar00gavin.brownICANN\Domain Users000000 000000 18 gid=1205227579 18 uid=1252672585 29 mtime=1740741699.54213246 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAyAKh92khrDw 49 SCHILY.xattr.com.apple.provenance=È¡÷i!¬< Net-EPP-0.28/t/use.t000755 €JªDI€GÖP;00000000114 14760316103 020350 0ustar00gavin.brownICANN\Domain Users000000 000000 #!perl use Test::More; use strict; require_ok(q{Net::EPP}); done_testing;