1## Domain Registry Interface, Handling of contact data for .NO 2## 3## Copyright (c) 2008-2010 UNINETT Norid AS, E<lt>http://www.norid.noE<gt>, 4## Trond Haugen E<lt>info@norid.noE<gt>. 5## All rights reserved. 6## 7## This file is part of Net::DRI 8## 9## Net::DRI is free software; you can redistribute it and/or modify 10## it under the terms of the GNU General Public License as published by 11## the Free Software Foundation; either version 2 of the License, or 12## (at your option) any later version. 13## 14## See the LICENSE file that comes with this distribution for more details. 15# 16# 17# 18############################################################################### 19 20package Net::DRI::Data::Contact::NO; 21 22use strict; 23use warnings; 24use base qw/Net::DRI::Data::Contact/; 25use Email::Valid; 26use Net::DRI::Util; 27use Net::DRI::Exception; 28 29our $VERSION = do { my @r = ( q$Revision: 1.5 $ =~ /\d+/gmx ); sprintf( "%d" . ".%02d" x $#r, @r ); }; 30 31__PACKAGE__->register_attributes(qw(type identity mobilephone organization rolecontact xemail xdisclose facets)); 32 33=pod 34 35=head1 NAME 36 37Net::DRI::Data::Contact::NO - Handle .NO contact data for Net::DRI 38 39=head1 DESCRIPTION 40 41This subclass of Net::DRI::Data::Contact adds accessors and validation for 42.NO specific data. 43 44=head1 METHODS 45 46The following accessors/mutators can be called in chain, as they all return 47the object itself. 48 49=head2 type() 50 51Mandatory, must be set for all contacts. Specify what type of contact to 52register. Value must be one of: 'person', 'organization' or 'role'. 53 54Example: $co->type('organization') 55 56=head2 identity() 57 58Currently valid for type='organization' only. 59Must then be set to specify the organization number in Br�nn�ysund, 60the Norwegian Business Register. 61 62Example: $co->identity({type=>'organizationNumber', value=>'987654321'}); 63 64=head2 mobilephone() 65 66Optional. Set a mobile phone number for the contact. 67 68Example: $co->mobilephone('+47.123456780') 69 70=head2 organization() 71 72Optional. Set one or more organization-elements which specify organizations 73which the contact belongs to. The value should be the local contact id 74of an organization object. 75 76This element can only be used for role and person contacts. 77 78$co->organization('EFA12O'); 79 80=head2 rolecontact() 81 82Optional. Set one or more roleContact-elements which specify persons which 83belongs to a role contact. The value should be the local contact id of a 84person object. 85 86This element can only be used for role contacts. 87 88Example: $co->rolecontact(['JD12P', 'JD13P']); 89 90=head2 xemail() 91 92Optional. Set one or more email-elements which specify email addresses in 93addition to the mandatory email element in the standard contact create command. 94 95Example: $co->xemail(['xtra1@example.no', 'xtra2@example.no']); 96 97=head2 xdisclose() 98 99Optional. A disclose-element which must contain the child element mobilePhone. 100This element notes the clients preference to allow or restrict disclosure of 101the mobile phone number. If not present, the servers stated data collection 102policy is used. 103 104Example: $co->xdisclose({mobilePhone=>0}); 105 106=head2 facets() 107Facets are some special control attributes that can be used to 108implement a super registrar (admin registrar). 109 110A super registrar can suppress certain checks and perform actions on behalf of a normal registrar. 111 112Facets are key/values pairs. 113Net::DRI will not try to enforce what key/value pairs that are possible, 114but let the registry decide their validity. 115 116Example: $co->facets( { 'skip-manual-review' => 1, 'ignores-exceptions' => 'reg123'} ); 117 118 119=head1 SUPPORT 120 121For now, support questions should be sent to: 122 123E<lt>netdri@dotandco.comE<gt> 124 125Please also see the SUPPORT file in the distribution. 126 127=head1 SEE ALSO 128 129http://www.dotandco.com/services/software/Net-DRI/ 130 131=head1 AUTHOR 132 133Trond Haugen, E<lt>info@norid.noE<gt>. 134 135=head1 COPYRIGHT 136 137Copyright (c) 2008-2010 UNINETT Norid AS, E<lt>http://www.norid.noE<gt>, 138Trond Haugen E<lt>info@norid.noE<gt>. 139All rights reserved. 140 141This program is free software; you can redistribute it and/or modify 142it under the terms of the GNU General Public License as published by 143the Free Software Foundation; either version 2 of the License, or 144(at your option) any later version. 145 146See the LICENSE file that comes with this distribution for more details. 147 148=cut 149 150#################################################################################################### 151 152sub validate { 153 my ( $self, $change ) = @_; 154 $change ||= 0; 155 156 my @errs; 157 158 if ( !$change ) { 159 Net::DRI::Exception::usererr_insufficient_parameters( 160 'Invalid contact information: name/city/cc/email/auth/srid mandatory' 161 ) 162 unless $self->name() 163 && $self->city() 164 && $self->cc() 165 && $self->email() 166 && $self->auth() 167 && $self->srid(); 168 Net::DRI::Exception::usererr_insufficient_parameters( 169 'Invalid contact information: org is not allowed for .NO') 170 if ( $self->org() ); 171 Net::DRI::Exception::usererr_insufficient_parameters( 172 'Invalid contact information: type mandatory') 173 unless ( $self->type() ); 174 } 175 176 push @errs,'srid' if ($self->srid() && ! Net::DRI::Util::xml_is_token($self->srid(),3,16)); 177 push @errs, 'name' 178 if ( $self->name() 179 && grep { !Net::DRI::Util::xml_is_normalizedstring( $_, 1, 255 ) } 180 ( $self->name() ) ); 181 push @errs, 'org' 182 if ( $self->org() 183 && grep { !Net::DRI::Util::xml_is_normalizedstring( $_, undef, 255 ) } 184 ( $self->org() ) ); 185 186 my @rs = ( $self->street() ); 187 188 foreach my $i ( 0, 1 ) { 189 next unless $rs[$i]; 190 push @errs, 'street' 191 if ( 192 ( ref( $rs[$i] ) ne 'ARRAY' ) || ( @{ $rs[$i] } > 3 ) || ( 193 grep { 194 !Net::DRI::Util::xml_is_normalizedstring( $_, undef, 255 ) 195 } @{ $rs[$i] } 196 ) 197 ); 198 } 199 200 push @errs, 'city' 201 if ( $self->city() 202 && grep { !Net::DRI::Util::xml_is_normalizedstring( $_, 1, 255 ) } 203 ( $self->city() ) ); 204 push @errs, 'sp' 205 if ( $self->sp() 206 && grep { !Net::DRI::Util::xml_is_normalizedstring( $_, undef, 255 ) } 207 ( $self->sp() ) ); 208 push @errs, 'pc' 209 if ( $self->pc() 210 && grep { !Net::DRI::Util::xml_is_token( $_, undef, 16 ) } 211 ( $self->pc() ) ); 212 push @errs, 'cc' 213 if ( $self->cc() && grep { !Net::DRI::Util::xml_is_token( $_, 2, 2 ) } 214 ( $self->cc() ) ); 215 push @errs, 'cc' 216 if ( $self->cc() 217 && grep { !exists( $Net::DRI::Util::CCA2{ uc($_) } ) } 218 ( $self->cc() ) ); 219 220 push @errs, 'voice' 221 if ( $self->voice() 222 && !Net::DRI::Util::xml_is_token( $self->voice(), undef, 17 ) 223 && $self->voice() !~ m/^\+[0-9]{1,3}\.[0-9]{1,14}(?:x\d+)?$/mx ); 224 push @errs, 'fax' 225 if ( $self->fax() 226 && !Net::DRI::Util::xml_is_token( $self->fax(), undef, 17 ) 227 && $self->fax() !~ m/^\+[0-9]{1,3}\.[0-9]{1,14}(?:x\d+)?$/mx ); 228 push @errs, 'email' 229 if ( 230 $self->email() 231 && !( 232 Net::DRI::Util::xml_is_token( $self->email(), 1, undef ) 233 && Email::Valid->rfc822( $self->email() ) 234 ) 235 ); 236 237 my $ra = $self->auth(); 238 push @errs, 'auth' 239 if ( $ra 240 && ( ref($ra) eq 'HASH' ) 241 && exists( $ra->{pw} ) 242 && !Net::DRI::Util::xml_is_normalizedstring( $ra->{pw} ) ); 243 244 # .NO 245 my $t = $self->type(); 246 push @errs, 'type' if ( $t && $t !~ m/^(?:person|organization|role)$/mx ); 247 248 $t = $self->identity(); 249 250 if ($t) { 251 my $ty = $t->{type}; 252 my $va = $t->{value}; 253 push @errs, 'identity type' 254 if ( $ty 255 && $ty 256 !~ m/^(?:organizationNumber|localIdentity|nationalIdentityNumber)$/mx 257 ); 258 259 # let the server handle further validation of what identity syntax 260 # and values are legal 261 } 262 $t = $self->mobilephone(); 263 push @errs, 'mobilephone' 264 if ( $t 265 && !Net::DRI::Util::xml_is_token( $t, undef, 17 ) 266 && $t !~ m/^\+[0-9]{1,3}\.[0-9]{1,14}(?:x\d+)?$/mx ); 267 268 # 269 foreach my $el ( 'organization', 'rolecontact', 'xemail' ) { 270 if ( $t = $self->$el() ) { # option, as scalar or array 271 my @em; 272 my $er; 273 274 if ($change) { 275 if ( ref($t) eq 'HASH' ) { 276 foreach my $s ( 'add', 'del' ) { 277 my $e = $t->{$s}; 278 if ( ref($e) eq 'ARRAY' ) { 279 push @em, @$e if (@$e); 280 } else { 281 push @em, $e if ($e); 282 } 283 } 284 } else { 285 $er .= ":update needs an add/del hash:"; 286 } 287 } else { 288 if ( ref($t) eq 'ARRAY' ) { 289 push @em, @$t if (@$t); 290 } else { 291 push @em, $t if ($t); 292 } 293 } 294 foreach my $e (@em) { 295 if ( $el eq 'xemail' ) { 296 $er .= " $e " 297 if ( 298 $e 299 && !( 300 Net::DRI::Util::xml_is_token( $e, 1, undef ) 301 && Email::Valid->rfc822($e) 302 ) 303 ); 304 } else { 305 $er .= " $e " 306 if ( $e 307 && !Net::DRI::Util::xml_is_token( $e, 3, 16 ) ); 308 } 309 push @errs, "xemail:$er" if ($er); 310 } 311 } 312 } 313 314 ## Check that xdisclose only contains mobilePhone 315 if ( my $d = $self->xdisclose() ) { 316 unless ( $d 317 && ( ref($d) eq 'HASH' ) 318 && ( scalar( keys(%$d) ) == 1 ) 319 && ( $d->{mobilePhone} == 1 || $d->{mobilePhone} == 0 ) ) 320 { 321 push @errs, 'xdisclose'; 322 } 323 } 324 Net::DRI::Exception::usererr_invalid_parameters( 325 'Invalid contact information: ' . join( '/', @errs ) ) 326 if @errs; 327 return 1; ## everything ok. 328} 329 330sub init { 331 my ( $self, $what, $ndr ) = @_; 332 333 if ( $what eq 'create' ) { 334 my $a = $self->auth(); 335 $self->auth( { pw => '' } ) 336 unless ( $a && ( ref($a) eq 'HASH' ) && exists( $a->{pw} ) ) 337 ; ## Mandatory in EPP 338 $self->srid('auto') 339 unless defined( $self->srid() ); ## we can not choose the ID 340 } 341 return; 342} 343 344#################################################################################################### 3451; 346