File Coverage

blib/lib/IO/EPP/TCI.pm
Criterion Covered Total %
statement 12 108 11.1
branch 0 44 0.0
condition 0 16 0.0
subroutine 4 12 33.3
pod 4 7 57.1
total 20 187 10.7


line stmt bran cond sub pod time code
1             package IO::EPP::TCI;
2              
3             =encoding utf8
4              
5             =head1 NAME
6              
7             IO::EPP::TCI
8              
9             =head1 SYNOPSIS
10              
11             use IO::EPP::TCI;
12              
13             # Parameters for IO::Socket::SSL
14             my %sock_params = (
15             PeerHost => 'uap.tcinet.ru',
16             PeerPort => 8130, # .дети 8130, .tatar 8131
17             SSL_key_file => 'key_file.pem',
18             SSL_cert_file => 'cert_file.pem',
19             Timeout => 30,
20             );
21              
22             # Create object, get greeting and call login()
23             my $conn = IO::EPP::TCI->new( {
24             user => 'XXX-DETI',
25             pass => 'XXXXXXXX',
26             sock_params => \%sock_params,
27             server => 'afilias', # or pir, ...
28             test_mode => 0, # real connect
29             } );
30              
31             # Check domain
32             my ( $answ, $code, $msg ) = $conn->check_domains( { domains => [ 'xn--80akfym3e.xn--d1acj3b' ] } );
33              
34             # Call logout() and destroy object
35             undef $conn;
36              
37             =head1 DESCRIPTION
38              
39             Work with normal TCI EPP API
40              
41             .дети/.xn--d1acj3b documents:
42             L, L
43              
44             .tatar documents:
45             L, L
46              
47             =cut
48              
49 1     1   1758 use IO::EPP::Base;
  1         22  
  1         32  
50 1     1   6 use parent qw( IO::EPP::Base );
  1         1  
  1         5  
51              
52 1     1   54 use strict;
  1         2  
  1         14  
53 1     1   4 use warnings;
  1         1  
  1         1214  
54              
55             sub make_request {
56 0     0 1   my ( $action, $params ) = @_;
57              
58 0           my ( $self, $code, $msg, $answ );
59              
60 0 0         unless ( $params->{conn} ) {
61 0   0       $params->{sock_params}{PeerHost} ||= 'uap.tcinet.ru';
62 0   0       $params->{sock_params}{PeerPort} ||= 8130; # .дети, for .tatar need 8131
63              
64 0           ( $self, $code, $msg ) = __PACKAGE__->new( $params );
65              
66 0 0 0       unless ( $code and $code == 1000 ) {
67 0           goto END_MR;
68             }
69             }
70             else {
71 0           $self = $params->{conn};
72             }
73              
74              
75 0           $self->{critical_error} = '';
76              
77 0 0         if ( $self->can( $action ) ) {
78 0           ( $answ, $code, $msg ) = $self->$action( $params );
79             }
80             else {
81 0           $msg = "undefined command <$action>, request cancelled";
82 0           $code = 0;
83             }
84              
85              
86             END_MR:
87              
88 0 0         $msg .= '; ' . $self->{critical_error} if $self->{critical_error};
89              
90 0           my $full_answ = "code: $code\nmsg: $msg";
91              
92 0 0 0       $answ = {} unless $answ && ref $answ;
93              
94 0           $answ->{code} = $code;
95 0           $answ->{msg} = $msg;
96              
97 0 0         return wantarray ? ( $answ, $full_answ, $self ) : $answ;
98             }
99              
100             =head1 METHODS
101              
102             Further overlap functions where the provider has features
103              
104             =head2 login
105              
106             Ext params for login,
107              
108             INPUT: new password for change
109              
110             =cut
111              
112             sub login {
113 0     0 1   my ( $self, $pw ) = @_;
114              
115 0           my $svcs = '
116             urn:ietf:params:xml:ns:epp-1.0
117             urn:ietf:params:xml:ns:eppcom-1.0
118             urn:ietf:params:xml:ns:contact-1.0
119             urn:ietf:params:xml:ns:domain-1.0
120             urn:ietf:params:xml:ns:host-1.0';
121 0           my $extension = '
122             http://www.tcinet.ru/epp/tci-contact-ext-1.0
123             http://www.tcinet.ru/epp/tci-domain-ext-1.0
124             urn:ietf:params:xml:ns:launch-1.0
125             urn:ietf:params:xml:ns:secDNS-1.1
126             urn:ietf:params:xml:ns:rgp-1.0
127             http://www.tcinet.ru/epp/tci-billing-1.0';
128              
129 0           return $self->SUPER::login( $pw, $svcs, $extension );
130             }
131              
132              
133             sub contact_ext {
134 0     0 0   my ( undef, $params ) = @_;
135              
136 0           my $ext = '';
137              
138 0 0         if ( $params->{birthday} ) {
139 0           $ext .= " \n";
140              
141 0           foreach my $f ( 'birthday', 'passport', 'TIN' ) {
142 0 0         $ext .= " $$params{$f}\n" if $$params{$f};
143             }
144              
145 0           $ext .= " ";
146             }
147              
148 0 0         if ( $params->{legal} ) {
149 0           $ext .= " \n";
150 0           foreach my $type ( 'int', 'loc' ) {
151 0           $ext .= qq| \n|;
152              
153 0 0         $$params{legal}{$type}{addr} = [ $$params{legal}{$type}{addr} ] unless ref $$params{legal}{$type}{addr};
154              
155 0           foreach my $s ( @{$$params{legal}{$type}{addr}} ) {
  0            
156 0           $ext .= " $s\n";
157             }
158              
159 0           $ext .= " $$params{legal}{$type}{city}\n";
160 0 0         $ext .= ( $$params{legal}{$type}{'state'} ? " $$params{legal}{$type}{state}\n" : " \n" );
161 0 0         $ext .= ( $$params{legal}{$type}{postcode} ? " $$params{legal}{$type}{postcode}\n" : " \n" );
162 0           $ext .= " $$params{legal}{$type}{country_code}\n";
163              
164 0           $ext .= " \n";
165             }
166 0           $ext .= " $$params{TIN}\n";
167 0           $ext .= " ";
168             }
169              
170 0           return $ext;
171             }
172              
173              
174             =head2 create_contact
175              
176             When registering a contact, you must specify both int type data and loc type data, and if the domain owner has passport data in Cyrillic,
177             then loc type data must be entered in Cyrillic.
178             This is mandatory for citizens and legal entities of Russia, Ukraine, Belarus and other countries that have the Cyrillic alphabet.
179              
180             In addition, the owner must provide additional information.
181              
182             For individuals:
183              
184             C -- date of birth;
185              
186             C -- passport series and number, by whom and when it was issued;
187              
188             C -- TIN for individual entrepreneurs.
189              
190             For legal entities:
191              
192             hashref C, that contains the legal address, it also needs to specify two types: C and C, consisting of the fields C, C, C, C, C.
193              
194             You also need to specify the C field.
195              
196             An Example:
197              
198             Individuals:
199              
200             my %cont = (
201             int => {
202             first_name => 'Igor',
203             patronymic => 'Igorevich',
204             last_name => 'Igorev',
205             org => '',
206             addr => 'Igoreva str, 129',
207             city => 'Igorevsk',
208             state => 'Ogorevskaya obl.',
209             postcode => '699001',
210             country_code => 'RU',
211             },
212             loc => {
213             first_name => 'Игорь',
214             patronymic => 'Игоревич',
215             last_name => 'Игорев',
216             org => '',
217             addr => 'ул. Игорева, 129',
218             city => 'Игоревск',
219             state => 'Игоревская обл.',
220             postcode => '699001',
221             country_code => 'RU',
222             },
223             birthday => '1909-01-14',
224             passport => '11.11.2011, выдан Отделом УФМС России по Игоревской области в г.Игоревске, 2211 446622',
225             phone => '+7.9012345678',
226             fax => '',
227             email => 'igor@i.ru',
228             TIN => '',
229             };
230              
231             my ( $answ, $msg, $conn ) = make_request( 'create_contact', \%cont );
232              
233             Legal entities:
234              
235             my %cont = (
236             int => {
237             first_name => 'Igor',
238             patronymic => 'Igorevich',
239             last_name => 'Igorev',
240             org => 'Igor and Co',
241             addr => 'Igoreva str, 129',
242             city => 'Igorevsk',
243             state => 'Igorevskaya obl.',
244             postcode => '699001',
245             country_code => 'RU',
246             },
247             loc => {
248             first_name => 'Игорь',
249             patronymic => 'Игоревич',
250             last_name => 'Игорев',
251             org => 'Игорь и Ко',
252             addr => 'ул. Игорева, 129',
253             city => 'Игоревск',
254             state => 'Игоревская обл.',
255             postcode => '699001',
256             country_code => 'RU',
257             },
258             legal => {
259             int => {
260             addr => 'Company str, 1',
261             city => 'Igorevsk',
262             state => 'Igorevskaya obl.',
263             postcode => '699002',
264             country_code => 'RU',
265             },
266             loc => {
267             addr => 'ул. Компаний, 1',
268             city => 'Игоревск',
269             state => 'Игоревская обл.',
270             postcode => '699002',
271             country_code => 'RU',
272             }
273             }
274             };
275              
276             my ( $answ, $code, $msg ) = $conn->create_contact( \%cont );
277              
278             =cut
279              
280             sub create_contact {
281 0     0 1   my ( $self, $params ) = @_;
282              
283 0   0       $params->{cont_id} ||= IO::EPP::Base::gen_id( 16 );
284              
285 0           $params->{authinfo} = IO::EPP::Base::gen_pw( 16 );
286              
287 0           my $extension = $self->contact_ext( $params );
288              
289 0 0         if ( $extension ) {
290 0           $params->{extension} = qq| \n$extension \n|;
291             }
292              
293 0           return $self->SUPER::create_contact( $params );
294             }
295              
296              
297             sub get_contact_ext {
298 0     0 0   my ( undef, $ext ) = @_;
299              
300 0           my %cont;
301              
302 0 0         if ( $ext =~ m|]+tci-contact-ext-1[^<>]+>(.+?)|s ) {
303 0           my $data = $1;
304              
305 0 0         if ( $data =~ m|(.+)|s ) {
306 0           my $person_data = $1;
307              
308 0           my @rows = $person_data =~ m|([^<>]+)|gs;
309              
310 0           foreach my $row ( @rows ) {
311 0 0         if ( $row =~ m|([^<>]+)| ) {
312 0           $cont{$1} = $2;
313             }
314             }
315             }
316              
317 0 0         if ( $data =~ m|(.+)|s ) {
318 0           my $org_data = $1;
319              
320 0           ( $cont{TIN} ) = $org_data =~ /([^<>]+)<\/contact:TIN>/;
321              
322 0           my @atypes = ( 'int', 'loc' );
323 0           foreach my $atype ( @atypes ) {
324 0           my ( $postal ) = $org_data =~ m|(.+?)|s;
325              
326 0 0         next unless $postal;
327              
328 0           $cont{legal}{$atype}{addr} = join(' ', $postal =~ /([^<>]*)<\/contact:street>/ );
329              
330 0           ( $cont{legal}{$atype}{city} ) = $postal =~ /([^<>]*)<\/contact:city>/;
331              
332 0           ( $cont{legal}{$atype}{'state'} ) = $postal =~ /([^<>]*)<\/contact:sp>/;
333              
334 0           ( $cont{legal}{$atype}{postcode} ) = $postal =~ /([^<>]*)<\/contact:pc>/;
335              
336 0           ( $cont{legal}{$atype}{country_code} ) = $postal =~ /([A-Z]+)<\/contact:cc>/;
337             }
338             }
339             }
340              
341 0           return \%cont;
342             }
343              
344              
345             =head2 create_domain
346              
347             Has an optional C field.
348              
349             =cut
350              
351             sub create_domain {
352 0     0 1   my ( $self, $params ) = @_;
353              
354 0   0       $params->{authinfo} ||= IO::EPP::Base::gen_pw( 16 );
355              
356 0           my $extension = '';
357              
358 0 0         if ( $params->{dname} =~ /\.xn--80adxhks$/ ) {
359             # .москва support RU lang only
360 0           $extension .= qq| \n|;
361 0           $extension .= " ru-RU\n";
362 0           $extension .= " \n";
363             }
364              
365 0 0         $params->{extension} = $extension if $extension;
366              
367 0           return $self->SUPER::create_domain( $params );
368             }
369              
370              
371             sub get_domain_spec_ext {
372 0     0 0   my ( undef, $ext ) = @_;
373              
374 0           my %info;
375              
376 0 0         if ( $ext =~ m|]+tci-domain-ext-1[^<>]+>(.+?)|s ) {
377 0           my $tciinfo = $1;
378              
379 0           ( $info{descr} ) = $tciinfo =~ m|([^<>]+)|;
380             }
381              
382 0           return \%info;
383             }
384              
385              
386             sub DESTROY {
387 0     0     local ($!, $@, $^E, $?);
388              
389 0           my $self = shift;
390              
391 0 0         if ( $self->{sock} ) {
392 0           $self->logout();
393             }
394             }
395              
396             1;
397              
398              
399             __END__