File Coverage

blib/lib/Net/DRI/Protocol/EPP/Util.pm
Criterion Covered Total %
statement 18 211 8.5
branch 0 104 0.0
condition 0 71 0.0
subroutine 6 23 26.0
pod 0 16 0.0
total 24 425 5.6


line stmt bran cond sub pod time code
1             ## Domain Registry Interface, EPP Protocol Utility functions
2             ##
3             ## Copyright (c) 2009,2010,2015 Patrick Mevzek . All rights reserved.
4             ##
5             ## This file is part of Net::DRI
6             ##
7             ## Net::DRI is free software; you can redistribute it and/or modify
8             ## it under the terms of the GNU General Public License as published by
9             ## the Free Software Foundation; either version 2 of the License, or
10             ## (at your option) any later version.
11             ##
12             ## See the LICENSE file that comes with this distribution for more details.
13             ####################################################################################################
14              
15             package Net::DRI::Protocol::EPP::Util;
16              
17 1     1   990 use utf8;
  1         3  
  1         6  
18 1     1   26 use strict;
  1         2  
  1         23  
19 1     1   4 use warnings;
  1         7  
  1         25  
20 1     1   5 use feature 'state';
  1         2  
  1         94  
21              
22 1     1   4 use Net::DRI::Util;
  1         2  
  1         19  
23 1     1   4 use Net::DRI::Exception;
  1         1  
  1         2554  
24              
25             ####################################################################################################
26              
27             sub parse_node_status
28             {
29 0     0 0   my ($node)=@_;
30 0           my %tmp=( name => $node->getAttribute('s') );
31 0           ($tmp{lang},$tmp{msg})=parse_node_msg($node);
32 0           return \%tmp;
33             }
34              
35             sub parse_node_msg
36             {
37 0     0 0   my ($node)=@_; ## eppcom:msgType
38 0   0       return (($node->getAttribute('lang') || 'en'),$node->textContent() || '');
      0        
39             }
40              
41             ## Try to enhance parsing of common cases
42             sub parse_node_value
43             {
44 0     0 0   my ($n)=@_;
45 0           my $t=$n->toString();
46 0           $t=~s!^(.+?)$!$1!;
47 0           $t=~s/^\s+//;
48 0           $t=~s/\s+$//;
49 0           $t=~s!^(.+)$!$1!;
50 0           $t=~s!^$!!;
51 0           return $t;
52             }
53              
54             sub parse_node_result
55             {
56 0     0 0   my ($node,$ns,$from)=@_;
57 0 0         $from='eppcom' unless defined $from;
58 0           my ($lang,$msg)=parse_node_msg($node->getChildrenByTagNameNS($ns,'msg')->get_node(1));
59              
60 0           my @i;
61 0           foreach my $el (Net::DRI::Util::xml_list_children($node)) ## or nodes, all optional
62             {
63 0           my ($name,$c)=@$el;
64 0 0         if ($name eq 'extValue')
    0          
65             {
66 0           my @c=Net::DRI::Util::xml_list_children($c); ## we need to use that, instead of directly firstChild/lastChild because we want only element nodes, not whitespaces if there
67 0           my $c1=$c[0]->[1]; ## node
68 0           my $c2=$c[-1]->[1]; ## node
69 0           my ($ll,$lt)=parse_node_msg($c2);
70 0           my $v=parse_node_value($c1);
71 0 0         push @i,{ from => $from.':extValue', type => $v=~m/^ $v, lang => $ll, reason => $lt };
72             } elsif ($name eq 'value')
73             {
74 0           my $v=parse_node_value($c);
75 0 0         push @i,{ from => $from.':value', type => $v=~m/^ $v };
76             }
77             }
78              
79 0           return { code => $node->getAttribute('code'), message => $msg, lang => $lang, extra_info => \@i };
80             }
81              
82             ####################################################################################################
83              
84             sub domain_build_command
85             {
86 0     0 0   my ($msg,$command,$domain,$domainattr)=@_;
87 0 0         my @dom=ref $domain ? @$domain : ($domain);
88 0 0         Net::DRI::Exception->die(1,'protocol/EPP',2,'Domain name needed') unless @dom;
89 0           foreach my $d (@dom)
90             {
91 0 0 0       Net::DRI::Exception->die(1,'protocol/EPP',2,'Domain name needed') unless defined $d && $d;
92 0 0         Net::DRI::Exception->die(1,'protocol/EPP',10,'Invalid domain name: '.$d) unless Net::DRI::Util::xml_is_token($d,1,255);
93             }
94              
95 0 0         my $tcommand=ref $command ? $command->[0] : $command;
96 0           $msg->command([$command,'domain:'.$tcommand,sprintf('xmlns:domain="%s" xsi:schemaLocation="%s %s"',$msg->nsattrs('domain'))]);
97              
98 0           my @d=map { ['domain:name',$_,$domainattr] } @dom;
  0            
99 0           return @d;
100             }
101              
102             sub domain_build_authinfo
103             {
104 0     0 0   my ($epp,$rauth,$isupdate)=@_;
105 0 0 0       return ['domain:authInfo',['domain:null']] if ((! defined $rauth->{pw} || $rauth->{pw} eq '') && $epp->{usenullauth} && (defined($isupdate) && $isupdate));
      0        
      0        
      0        
106 0 0         return ['domain:authInfo',['domain:pw',$rauth->{pw},exists($rauth->{roid})? { 'roid' => $rauth->{roid} } : undef]];
107             }
108              
109             sub build_tel
110             {
111 0     0 0   my ($name,$tel)=@_;
112 0 0         if ($tel=~m/^(\S+)x(\S+)$/)
113             {
114 0           return [$name,$1,{x=>$2}];
115             } else
116             {
117 0           return [$name,$tel];
118             }
119             }
120              
121             sub parse_tel
122             {
123 0     0 0   my $node=shift;
124 0   0       my $ext=$node->getAttribute('x') || '';
125 0           my $num=$node->textContent();
126 0 0         $num.='x'.$ext if $ext;
127 0           return $num;
128             }
129              
130             sub build_period
131             {
132 0     0 0   my $dtd=shift; ## DateTime::Duration
133 0           my ($y,$m)=$dtd->in_units('years','months'); ## all values are integral, but may be negative
134 0 0 0       ($y,$m)=(0,$m+12*$y) if ($y && $m);
135 0           my ($v,$u);
136 0 0         if ($y)
137             {
138 0 0 0       Net::DRI::Exception::usererr_invalid_parameters('years must be between 1 and 99') unless ($y >= 1 && $y <= 99);
139 0           $v=$y;
140 0           $u='y';
141             } else
142             {
143 0 0 0       Net::DRI::Exception::usererr_invalid_parameters('months must be between 1 and 99') unless ($m >= 1 && $m <= 99);
144 0           $v=$m;
145 0           $u='m';
146             }
147              
148 0           return ['domain:period',$v,{'unit' => $u}];
149             }
150              
151             sub build_ns
152             {
153 0     0 0   my ($epp,$ns,$domain,$xmlns,$noip)=@_;
154              
155 0           my @d;
156 0           my $asattr=$epp->{hostasattr};
157              
158 0 0         if ($asattr)
159             {
160 0           foreach my $i (1..$ns->count())
161             {
162 0           my ($n,$r4,$r6)=$ns->get_details($i);
163 0           my @h;
164 0           push @h,['domain:hostName',$n];
165 0 0 0       if ((($n=~m/\S+\.${domain}$/i) || (lc($n) eq lc($domain)) || ($asattr==2)) && (!defined($noip) || !$noip))
      0        
      0        
166             {
167 0 0         push @h,map { ['domain:hostAddr',$_,{ip=>'v4'}] } @$r4 if @$r4;
  0            
168 0 0         push @h,map { ['domain:hostAddr',$_,{ip=>'v6'}] } @$r6 if @$r6;
  0            
169             }
170 0           push @d,['domain:hostAttr',@h];
171             }
172             } else
173             {
174 0           @d=map { ['domain:hostObj',$_] } $ns->get_names();
  0            
175             }
176              
177 0 0         $xmlns='domain' unless defined($xmlns);
178 0           return [$xmlns.':ns',@d];
179             }
180              
181             sub parse_ns ## RFC 4931 ยง1.1
182             {
183 0     0 0   my ($po,$node)=@_;
184 0           my $ns=$po->create_local_object('hosts');
185              
186 0           foreach my $el (Net::DRI::Util::xml_list_children($node))
187             {
188 0           my ($name,$n)=@$el;
189 0 0         if ($name eq 'hostObj')
    0          
190             {
191 0           $ns->add($n->textContent());
192             } elsif ($name eq 'hostAttr')
193             {
194 0           my ($hostname,@ip4,@ip6);
195 0           foreach my $sel (Net::DRI::Util::xml_list_children($n))
196             {
197 0           my ($name2,$nn)=@$sel;
198 0 0         if ($name2 eq 'hostName')
    0          
199             {
200 0           $hostname=$nn->textContent();
201             } elsif ($name2 eq 'hostAddr')
202             {
203 0   0       my $ip=$nn->getAttribute('ip') || 'v4';
204 0 0         if ($ip eq 'v6')
205             {
206 0           push @ip6,$nn->textContent();
207             } else
208             {
209 0           push @ip4,$nn->textContent();
210             }
211             }
212             }
213 0           $ns->add($hostname,\@ip4,\@ip6,1);
214             }
215             }
216 0           return $ns;
217             }
218              
219             ## was Core::Domain::build_contact_noregistrant
220             sub build_core_contacts
221             {
222 0     0 0   my ($epp,$cs,$ns)=@_;
223 0           my @d;
224             # All nonstandard contacts go into the extension section
225 0           my %r=map { $_ => 1 } $epp->core_contact_types();
  0            
226 0           foreach my $t (sort(grep { exists($r{$_}) } $cs->types()))
  0            
227             {
228 0           my @o=$cs->get($t);
229 0   0       push @d,map { [ ($ns // 'domain').':contact',$_->srid(),{'type'=>$t}] } @o;
  0            
230             }
231 0           return @d;
232             }
233              
234             sub parse_postalinfo
235             {
236 0     0 0   my ($epp,$pi,$rcd)=@_;
237 0           my $type=$pi->getAttribute('type'); ## int or loc, mandatory in EPP !
238 0 0 0       $type=$epp->{defaulti18ntype} if (!defined($type) && defined($epp->{defaulti18ntype}));
239 0           state $index={'loc' => 0, 'int' => 1};
240 0           my $ti=$index->{$type};
241              
242 0           foreach my $el (Net::DRI::Util::xml_list_children($pi))
243             {
244 0           my ($name,$node)=@$el;
245 0 0         if ($name=~m/^(name|org)$/)
    0          
246             {
247 0           $rcd->{$name}->[$ti]=$node->textContent();
248             } elsif ($name eq 'addr')
249             {
250 0           my @street;
251 0           foreach my $sel (Net::DRI::Util::xml_list_children($node))
252             {
253 0           my ($subname,$subnode)=@$sel;
254 0 0         if ($subname eq 'street')
    0          
255             {
256 0           push @street,$subnode->textContent();
257             } elsif ($subname=~m/^(city|sp|pc|cc)$/)
258             {
259 0           $rcd->{$subname}->[$ti]=$subnode->textContent();
260             }
261             }
262 0           $rcd->{street}->[$ti]=\@street;
263             }
264             }
265 0           return;
266             }
267              
268             sub parse_disclose
269             {
270 0     0 0   my ($disclose)=@_;
271 0           my $flag=Net::DRI::Util::xml_parse_boolean($disclose->getAttribute('flag'));
272 0           my %r;
273 0           foreach my $el (Net::DRI::Util::xml_list_children($disclose))
274             {
275 0           my ($name,$node)=@$el;
276 0 0         if ($name=~m/^(name|org|addr)$/)
277             {
278 0           $r{$1.'_'.$node->getAttribute('type')}=$flag;
279             } else
280             {
281 0           $r{$name}=$flag;
282             }
283             }
284 0           return \%r;
285             }
286              
287             sub build_disclose
288             {
289 0     0 0   my ($d,$ns,@items)=@_;
290 0   0       $ns//='contact';
291 0 0 0       return () unless $d && ref $d eq 'HASH';
292 0           my %v=map { $_ => 1 } values %$d;
  0            
293 0 0         return () unless keys(%v)==1; ## 1 or 0 as values, not both at same time
294 0           my @d;
295              
296 0           state $l1 = [ qw/name org addr/ ];
297 0           foreach my $item (@$l1)
298             {
299 0 0         if (exists $d->{$item})
300             {
301 0           push @d,[$ns.':'.$item,{type=>'int'}],[$ns.':name',{type=>'loc'}];
302             } else
303             {
304 0 0         push @d,[$ns.':'.$item,{type=>'int'}] if exists $d->{$item.'_int'};
305 0 0         push @d,[$ns.':'.$item,{type=>'loc'}] if exists $d->{$item.'_loc'};
306             }
307             }
308 0           state $l2 = [ qw/voice fax email/ ];
309 0           foreach my $item (@$l2, @items)
310             {
311 0 0         push @d,[$ns.':'.$item] if exists $d->{$item};
312             }
313 0           return [$ns.':disclose',@d,{flag=>(keys(%v))[0]}];
314             }
315              
316             sub _do_locint
317             {
318 0     0     my ($rl,$ri,$contact,$ns,$what)=@_;
319 0           my @tmp=$contact->$what();
320 0 0         return unless @tmp;
321 0 0         if ($what eq 'street')
322             {
323 0 0         if (defined($tmp[0])) { foreach (@{$tmp[0]}) { push @$rl,[$ns.':street',$_]; } };
  0            
  0            
  0            
324 0 0         if (defined($tmp[1])) { foreach (@{$tmp[1]}) { push @$ri,[$ns.':street',$_]; } };
  0            
  0            
  0            
325             } else
326             {
327 0 0         if (defined($tmp[0])) { push @$rl,[$ns.':'.$what,$tmp[0]]; }
  0            
328 0 0         if (defined($tmp[1])) { push @$ri,[$ns.':'.$what,$tmp[1]]; }
  0            
329             }
330 0           return;
331             }
332              
333             sub build_postalinfo
334             {
335 0     0 0   my ($contact,$v,$ns)=@_;
336 0   0       $ns//='contact';
337 0           my $hasloc=$contact->has_loc();
338 0           my $hasint=$contact->has_int();
339 0 0 0       if ($hasint && !$hasloc && (($v & 5) == $v))
    0 0        
      0        
      0        
340             {
341 0           $contact->int2loc();
342 0           $hasloc=1;
343             } elsif ($hasloc && !$hasint && (($v & 6) == $v))
344             {
345 0           $contact->loc2int();
346 0           $hasint=1;
347             }
348              
349 0           my (@postl,@posti,@addrl,@addri);
350 0           _do_locint(\@postl,\@posti,$contact,$ns,'name');
351 0           _do_locint(\@postl,\@posti,$contact,$ns,'org');
352 0           _do_locint(\@addrl,\@addri,$contact,$ns,'street');
353 0           _do_locint(\@addrl,\@addri,$contact,$ns,'city');
354 0           _do_locint(\@addrl,\@addri,$contact,$ns,'sp');
355 0           _do_locint(\@addrl,\@addri,$contact,$ns,'pc');
356 0           _do_locint(\@addrl,\@addri,$contact,$ns,'cc');
357 0 0         push @postl,[$ns.':addr',@addrl] if @addrl;
358 0 0         push @posti,[$ns.':addr',@addri] if @addri;
359              
360 0           my @d;
361 0 0 0       push @d,[$ns.':postalInfo',@postl,{type=>'loc'}] if (($v & 5) && $hasloc); ## loc+int OR loc
362 0 0 0       push @d,[$ns.':postalInfo',@posti,{type=>'int'}] if (($v & 6) && $hasint); ## loc+int OR int
363              
364 0           return @d;
365             }
366              
367             ####################################################################################################
368             1;
369              
370             __END__