| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package FTN::Addr; | 
| 2 |  |  |  |  |  |  | $FTN::Addr::VERSION = '20160303'; | 
| 3 |  |  |  |  |  |  |  | 
| 4 | 6 |  |  | 6 |  | 87373 | use strict; | 
|  | 6 |  |  |  |  | 9 |  | 
|  | 6 |  |  |  |  | 176 |  | 
| 5 | 6 |  |  | 6 |  | 21 | use warnings; | 
|  | 6 |  |  |  |  | 9 |  | 
|  | 6 |  |  |  |  | 136 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 6 |  |  | 6 |  | 20 | use Carp (); | 
|  | 6 |  |  |  |  | 10 |  | 
|  | 6 |  |  |  |  | 60 |  | 
| 8 | 6 |  |  | 6 |  | 21 | use Scalar::Util (); | 
|  | 6 |  |  |  |  | 6 |  | 
|  | 6 |  |  |  |  | 267 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | =head1 NAME | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | FTN::Addr - Object-oriented module for creation and working with FTN addresses. | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | =head1 VERSION | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | version 20160303 | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | use FTN::Addr; | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | my $a = FTN::Addr -> new( '1:23/45' ) or die "this is not a correct address"; | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | my $b = FTN::Addr -> new( '1:23/45@fidonet' ) or die 'cannot create address'; | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | print "Hey! They are the same!\n" if $a eq $b; # they actually are, because default domain is 'fidonet' | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | $b -> set_domain( 'othernet' ); | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | print "Hey! They are the same!\n" if $a eq $b; # no output as we changed domain | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | $b = FTN::Addr -> new( '44.22', $a ) or die "cannot create address"; # takes the rest of information from optional $a | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | $b = $a -> new( '44.22' ) or die "cannot create address"; # the same | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | print $a -> f4, "\n"; # 1:23/45.0 | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | print $a -> s4, "\n"; # 1:23/45 | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | print $a -> f5, "\n"; # 1:23/45.0@fidonet | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | print $a -> s5, "\n"; # 1:23/45@fidonet | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | FTN::Addr module is for creation and working with FTN addresses.  Supports domains, different representations and comparison operators. | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | =cut | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | use overload | 
| 51 | 6 |  |  |  |  | 41 | eq => \ &_eq, | 
| 52 |  |  |  |  |  |  | cmp => \ &_cmp, | 
| 53 | 6 |  |  | 6 |  | 6364 | fallback => 1; | 
|  | 6 |  |  |  |  | 5049 |  | 
| 54 |  |  |  |  |  |  |  | 
| 55 | 6 |  |  | 6 |  | 409 | use constant DEFAULT_DOMAIN => 'fidonet'; | 
|  | 6 |  |  |  |  | 9 |  | 
|  | 6 |  |  |  |  | 10600 |  | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | my $domain_re = '[a-z\d_~-]{1,8}'; | 
| 58 |  |  |  |  |  |  | # frl-1028.002: | 
| 59 |  |  |  |  |  |  | # The Domain Name | 
| 60 |  |  |  |  |  |  | # --------------- | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | # The domain name MUST be a character string not more than 8 | 
| 63 |  |  |  |  |  |  | # characters long and MUST include only characters as defined below in | 
| 64 |  |  |  |  |  |  | # BNF. Any other character cannot be used in a domain name. | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | #   domain   = *pchar | 
| 67 |  |  |  |  |  |  | #   pchar    = alphaLC | digit | safe | 
| 68 |  |  |  |  |  |  | #   alphaLC  = "a" | "b" | ... | "z" | 
| 69 |  |  |  |  |  |  | #   digit    = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | 
| 70 |  |  |  |  |  |  | #   safe     = '-' | '_' | '~' | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | sub _remove_presentations { | 
| 74 | 12 |  |  | 12 |  | 9 | my $t = shift; | 
| 75 |  |  |  |  |  |  |  | 
| 76 | 12 |  |  |  |  | 27 | delete @$t{ qw/ full4d full5d short4d short5d fqfa brake_style / }; | 
| 77 |  |  |  |  |  |  | } | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | =head1 OBJECT CREATION | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | =head2 new | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | Can be called as class or object method: | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | my $t = FTN::Addr -> new( '1:23/45' ) or die 'something wrong!'; | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | $t = $t -> new( '1:22/33.44@fidonet' ) or die 'something wrong!'; # advisable to use class call here instead: | 
| 88 |  |  |  |  |  |  | $t = FTN::Addr -> new( '1:22/33.44@fidonet' ) or die 'something wrong!'; | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | Default domain is 'fidonet'.  If point isn't specified, it's considered to be 0. | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | Address can be: | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | 3d/4d                                            1:23/45 or 1:23/45.0 | 
| 95 |  |  |  |  |  |  | 5d                                               1:23/45@fidonet or 1:23/45.0@fidonet | 
| 96 |  |  |  |  |  |  | fqfa                                             fidonet#1:23/45.0 | 
| 97 |  |  |  |  |  |  | The Brake! FTN-compatible mailer for OS/2 style  fidonet.1.23.45.0 | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | If passed address misses any part except point and domain, the base is needed to get the missing information from (including domain).  It can be optional second parameter (already created FTN::Addr object) in case of class method call or object itself in case of object method call. | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | my $an = FTN::Addr -> new( '99', $t ); # class call.  address in $an is 1:22/99.0@fidonet | 
| 102 |  |  |  |  |  |  | $an = $t -> new( '99' );               # object call.  the same resulting address. | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | Performs field validation. | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | In case of error returns undef in scalar context or empty list in list context. | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  | =cut | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | sub new { | 
| 111 | 35 |  |  | 35 | 1 | 8657 | my $either = shift; | 
| 112 | 35 |  | 66 |  |  | 106 | my $class = ref( $either ) || $either; | 
| 113 | 35 |  |  |  |  | 30 | my $addr = shift; | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | return | 
| 116 | 35 | 50 |  |  |  | 52 | unless defined $addr; | 
| 117 |  |  |  |  |  |  |  | 
| 118 | 35 |  |  |  |  | 30 | my %new; | 
| 119 |  |  |  |  |  |  |  | 
| 120 | 35 | 50 |  |  |  | 1068 | if ( $addr =~ m!^($domain_re)\.(\d+)\.(\d+)\.(-?\d+)\.(-?\d+)$! ) { # fidonet.2.451.31.0 | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 121 | 0 |  |  |  |  | 0 | @new{ qw/ domain | 
| 122 |  |  |  |  |  |  | zone | 
| 123 |  |  |  |  |  |  | net | 
| 124 |  |  |  |  |  |  | node | 
| 125 |  |  |  |  |  |  | point | 
| 126 |  |  |  |  |  |  | / | 
| 127 |  |  |  |  |  |  | } = ( $1, $2, $3, $4, $5 ); | 
| 128 |  |  |  |  |  |  | } elsif ( $addr =~ m!^($domain_re)#(\d+):(\d+)/(-?\d+)\.(-?\d+)$! ) { # fidonet#2:451/31.0 | 
| 129 | 0 |  |  |  |  | 0 | @new{ qw/ domain | 
| 130 |  |  |  |  |  |  | zone | 
| 131 |  |  |  |  |  |  | net | 
| 132 |  |  |  |  |  |  | node | 
| 133 |  |  |  |  |  |  | point | 
| 134 |  |  |  |  |  |  | / | 
| 135 |  |  |  |  |  |  | } = ( $1, $2, $3, $4, $5 ); | 
| 136 |  |  |  |  |  |  | } elsif ( $addr =~ m!^(\d+):(\d+)/(-?\d+)(?:\.(-?\d+))?(?:@($domain_re))?$! ) { # 2:451/31.0@fidonet 2:451/31@fidonet 2:451/31.0 2:451/31 | 
| 137 | 21 |  | 100 |  |  | 215 | @new{ qw/ domain | 
|  |  |  | 100 |  |  |  |  | 
| 138 |  |  |  |  |  |  | zone | 
| 139 |  |  |  |  |  |  | net | 
| 140 |  |  |  |  |  |  | node | 
| 141 |  |  |  |  |  |  | point | 
| 142 |  |  |  |  |  |  | / | 
| 143 |  |  |  |  |  |  | } = ( $5 || DEFAULT_DOMAIN, | 
| 144 |  |  |  |  |  |  | $1, $2, $3, | 
| 145 |  |  |  |  |  |  | $4 || 0, | 
| 146 |  |  |  |  |  |  | ); | 
| 147 |  |  |  |  |  |  | } else {	   # partials.  need base.  451/31.0 451/31 31.1 31 .1 | 
| 148 | 14 | 100 |  |  |  | 24 | my $base = ref $either ? $either : shift; | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | return | 
| 151 | 14 | 50 | 33 |  |  | 155 | unless $base | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 152 |  |  |  |  |  |  | && ref $base | 
| 153 |  |  |  |  |  |  | && Scalar::Util::blessed $base | 
| 154 |  |  |  |  |  |  | && $base -> isa( 'FTN::Addr' ); | 
| 155 |  |  |  |  |  |  |  | 
| 156 | 14 | 100 |  |  |  | 76 | if ( $addr =~ m!^(\d+)/(-?\d+)(?:\.(-?\d+))?$! ) { # 451/31.0 451/31 | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 157 | 4 |  | 50 |  |  | 6 | @new{ qw/ domain | 
| 158 |  |  |  |  |  |  | zone | 
| 159 |  |  |  |  |  |  | net | 
| 160 |  |  |  |  |  |  | node | 
| 161 |  |  |  |  |  |  | point | 
| 162 |  |  |  |  |  |  | / | 
| 163 |  |  |  |  |  |  | } = ( $base -> domain, | 
| 164 |  |  |  |  |  |  | $base -> zone, | 
| 165 |  |  |  |  |  |  | $1, | 
| 166 |  |  |  |  |  |  | $2, | 
| 167 |  |  |  |  |  |  | $3 || 0, | 
| 168 |  |  |  |  |  |  | ); | 
| 169 |  |  |  |  |  |  | } elsif ( $addr =~ m!^(-?\d+)(?:\.(-?\d+))?$! ) { # 31.1 31 | 
| 170 | 9 |  | 100 |  |  | 14 | @new{ qw/ domain | 
| 171 |  |  |  |  |  |  | zone | 
| 172 |  |  |  |  |  |  | net | 
| 173 |  |  |  |  |  |  | node | 
| 174 |  |  |  |  |  |  | point | 
| 175 |  |  |  |  |  |  | / | 
| 176 |  |  |  |  |  |  | } = ( $base -> domain, | 
| 177 |  |  |  |  |  |  | $base -> zone, | 
| 178 |  |  |  |  |  |  | $base -> net, | 
| 179 |  |  |  |  |  |  | $1, | 
| 180 |  |  |  |  |  |  | $2 || 0, | 
| 181 |  |  |  |  |  |  | ); | 
| 182 |  |  |  |  |  |  | } elsif ( $addr =~ m!^\.(-?\d+)$! ) { # .1 | 
| 183 | 1 |  |  |  |  | 4 | @new{ qw/ domain | 
| 184 |  |  |  |  |  |  | zone | 
| 185 |  |  |  |  |  |  | net | 
| 186 |  |  |  |  |  |  | node | 
| 187 |  |  |  |  |  |  | point | 
| 188 |  |  |  |  |  |  | / | 
| 189 |  |  |  |  |  |  | } = ( $base -> domain, | 
| 190 |  |  |  |  |  |  | $base -> zone, | 
| 191 |  |  |  |  |  |  | $base -> net, | 
| 192 |  |  |  |  |  |  | $base -> node, | 
| 193 |  |  |  |  |  |  | $1, | 
| 194 |  |  |  |  |  |  | ); | 
| 195 |  |  |  |  |  |  | } else {                    # not recognizable | 
| 196 | 0 |  |  |  |  | 0 | return; | 
| 197 |  |  |  |  |  |  | } | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | return | 
| 201 |  |  |  |  |  |  | unless _validate_domain( $new{domain} ) | 
| 202 |  |  |  |  |  |  | && _validate_zone( $new{zone} ) | 
| 203 |  |  |  |  |  |  | && _validate_net( $new{net} ) | 
| 204 |  |  |  |  |  |  | && _validate_node( $new{node} ) | 
| 205 |  |  |  |  |  |  | && _validate_point( $new{point} ) | 
| 206 |  |  |  |  |  |  | && ( $new{node} != -1       # node application | 
| 207 |  |  |  |  |  |  | || $new{point} == 0 | 
| 208 |  |  |  |  |  |  | ) | 
| 209 |  |  |  |  |  |  | && ( $new{node} > 0         # point application | 
| 210 | 35 | 50 | 33 |  |  | 90 | || $new{point} != -1 | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 211 |  |  |  |  |  |  | ); | 
| 212 |  |  |  |  |  |  |  | 
| 213 | 35 |  |  |  |  | 118 | bless \ %new, $class; | 
| 214 |  |  |  |  |  |  | } | 
| 215 |  |  |  |  |  |  |  | 
| 216 |  |  |  |  |  |  | sub _validate_domain { | 
| 217 | 38 | 50 |  | 38 |  | 406 | defined $_[ 0 ] | 
| 218 |  |  |  |  |  |  | # && length( $_[ 0 ] ) | 
| 219 |  |  |  |  |  |  | # && length( $_[ 0 ] ) <= 8     # FRL-1002.001 | 
| 220 |  |  |  |  |  |  | # && index( $_[ 0 ], '.' ) == -1; # FRL-1002.001 | 
| 221 |  |  |  |  |  |  | && $_[ 0 ] =~ m/^$domain_re$/; # frl-1028.002 | 
| 222 |  |  |  |  |  |  | } | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | sub _validate_zone { | 
| 225 | 37 | 50 | 33 | 37 |  | 264 | defined $_[ 0 ] | 
| 226 |  |  |  |  |  |  | && 1 <= $_[ 0 ] && $_[ 0 ] <= 32767; # FRL-1002.001, frl-1028.002 | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | sub _validate_net { | 
| 230 | 37 | 50 | 33 | 37 |  | 247 | defined $_[ 0 ] | 
| 231 |  |  |  |  |  |  | && 1 <= $_[ 0 ] && $_[ 0 ] <= 32767; # FRL-1002.001, frl-1028.002 | 
| 232 |  |  |  |  |  |  | } | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | sub _validate_node { | 
| 235 | 37 | 50 | 33 | 37 |  | 235 | defined $_[ 0 ] | 
| 236 |  |  |  |  |  |  | && -1 <= $_[ 0 ] && $_[ 0 ] <= 32767; # FRL-1002.001, frl-1028.002 | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | sub _validate_point { | 
| 240 | 38 | 50 | 33 | 38 |  | 621 | defined $_[ 0 ] | 
| 241 |  |  |  |  |  |  | # && 0 <= $_[ 0 ] && $_[ 0 ] <= 32767; # FRL-1002.001: 0 .. 32765 | 
| 242 |  |  |  |  |  |  | && -1 <= $_[ 0 ] && $_[ 0 ] <= 32767; # frl-1028.002: -1 .. 32767 | 
| 243 |  |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  | =head2 clone | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | $th = $an -> clone | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | =cut | 
| 250 |  |  |  |  |  |  |  | 
| 251 |  |  |  |  |  |  | sub clone { | 
| 252 | 1 | 50 |  | 1 | 1 | 5 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 253 |  |  |  |  |  |  |  | 
| 254 | 1 |  |  |  |  | 5 | bless { %$inst }, ref $inst; | 
| 255 |  |  |  |  |  |  | } | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | =head1 FIELD ACCESS | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | Direct access to object fields.  Checking is performed (dies on error).  Setters return itself (for possible chaining). | 
| 260 |  |  |  |  |  |  |  | 
| 261 |  |  |  |  |  |  | =head2 domain: | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | $an -> set_domain( 'mynet' ); | 
| 264 |  |  |  |  |  |  | $an -> domain; | 
| 265 |  |  |  |  |  |  | $an -> domain( 'leftnet' ); | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | =for Pod::Coverage domain set_domain | 
| 268 |  |  |  |  |  |  |  | 
| 269 |  |  |  |  |  |  | =cut | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | sub domain { | 
| 272 | 61 | 50 |  | 61 | 0 | 12371 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | @_ ? | 
| 275 |  |  |  |  |  |  | $inst -> set_domain( @_ ) | 
| 276 | 61 | 100 |  |  |  | 288 | : $inst -> {domain}; | 
| 277 |  |  |  |  |  |  | } | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | sub set_domain { | 
| 280 | 3 | 50 |  | 3 | 0 | 231 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 281 |  |  |  |  |  |  |  | 
| 282 | 3 |  |  |  |  | 3 | my $value = shift; | 
| 283 |  |  |  |  |  |  |  | 
| 284 | 3 | 0 |  |  |  | 7 | die 'incorrect domain: ' . ( defined $value ? $value : 'undef' ) | 
|  |  | 50 |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | unless _validate_domain( $value ); | 
| 286 |  |  |  |  |  |  |  | 
| 287 | 3 |  |  |  |  | 7 | $inst -> {domain} = $value; | 
| 288 | 3 |  |  |  |  | 6 | $inst -> _remove_presentations; | 
| 289 |  |  |  |  |  |  |  | 
| 290 | 3 |  |  |  |  | 4 | $inst; | 
| 291 |  |  |  |  |  |  | } | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | =head2 zone: | 
| 294 |  |  |  |  |  |  |  | 
| 295 |  |  |  |  |  |  | $an -> set_zone( 2 ); | 
| 296 |  |  |  |  |  |  | $an -> zone; | 
| 297 |  |  |  |  |  |  | $an -> zone( 3 ); | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | =for Pod::Coverage zone set_zone | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | =cut | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | sub zone { | 
| 304 | 59 | 50 |  | 59 | 0 | 337 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 305 |  |  |  |  |  |  |  | 
| 306 |  |  |  |  |  |  | @_ ? | 
| 307 |  |  |  |  |  |  | $inst -> set_zone( @_ ) | 
| 308 | 59 | 100 |  |  |  | 248 | : $inst -> {zone}; | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | sub set_zone { | 
| 312 | 2 | 50 |  | 2 | 0 | 216 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 313 |  |  |  |  |  |  |  | 
| 314 | 2 |  |  |  |  | 2 | my $value = shift; | 
| 315 |  |  |  |  |  |  |  | 
| 316 | 2 | 0 |  |  |  | 4 | die 'incorrect zone: ' . ( defined $value ? $value : 'undef' ) | 
|  |  | 50 |  |  |  |  |  | 
| 317 |  |  |  |  |  |  | unless _validate_zone( $value ); | 
| 318 |  |  |  |  |  |  |  | 
| 319 | 2 |  |  |  |  | 4 | $inst -> {zone} = $value; | 
| 320 | 2 |  |  |  |  | 6 | $inst -> _remove_presentations; | 
| 321 |  |  |  |  |  |  |  | 
| 322 | 2 |  |  |  |  | 2 | $inst; | 
| 323 |  |  |  |  |  |  | } | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | =head2 net: | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | $an -> set_net( 456 ); | 
| 328 |  |  |  |  |  |  | $an -> net; | 
| 329 |  |  |  |  |  |  | $an -> net( 5020 ); | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | =for Pod::Coverage net set_net | 
| 332 |  |  |  |  |  |  |  | 
| 333 |  |  |  |  |  |  | =cut | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  | sub net { | 
| 336 | 56 | 50 |  | 56 | 0 | 578 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 337 |  |  |  |  |  |  |  | 
| 338 |  |  |  |  |  |  | @_ ? | 
| 339 |  |  |  |  |  |  | $inst -> set_net( @_ ) | 
| 340 | 56 | 100 |  |  |  | 266 | : $inst -> {net}; | 
| 341 |  |  |  |  |  |  | } | 
| 342 |  |  |  |  |  |  |  | 
| 343 |  |  |  |  |  |  | sub set_net { | 
| 344 | 2 | 50 |  | 2 | 0 | 5 | ref( my $inst = shift ) or Carp::croak "I'm only object method!"; | 
| 345 |  |  |  |  |  |  |  | 
| 346 | 2 |  |  |  |  | 3 | my $value = shift; | 
| 347 |  |  |  |  |  |  |  | 
| 348 | 2 | 0 |  |  |  | 3 | die 'incorrect net: ' . ( defined $value ? $value : 'undef' ) | 
|  |  | 50 |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | unless _validate_net( $value ); | 
| 350 |  |  |  |  |  |  |  | 
| 351 | 2 |  |  |  |  | 3 | $inst -> {net} = $value; | 
| 352 | 2 |  |  |  |  | 4 | $inst -> _remove_presentations; | 
| 353 |  |  |  |  |  |  |  | 
| 354 | 2 |  |  |  |  | 2 | $inst; | 
| 355 |  |  |  |  |  |  | } | 
| 356 |  |  |  |  |  |  |  | 
| 357 |  |  |  |  |  |  | =head2 node: | 
| 358 |  |  |  |  |  |  |  | 
| 359 |  |  |  |  |  |  | $an -> set_node( 33 ); | 
| 360 |  |  |  |  |  |  | $an -> node; | 
| 361 |  |  |  |  |  |  | $an -> node( 60 ); | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | =for Pod::Coverage node set_node | 
| 364 |  |  |  |  |  |  |  | 
| 365 |  |  |  |  |  |  | =cut | 
| 366 |  |  |  |  |  |  |  | 
| 367 |  |  |  |  |  |  | sub node { | 
| 368 | 47 | 50 |  | 47 | 0 | 532 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | @_ ? | 
| 371 |  |  |  |  |  |  | $inst -> set_node( @_ ) | 
| 372 | 47 | 100 |  |  |  | 207 | : $inst -> {node}; | 
| 373 |  |  |  |  |  |  | } | 
| 374 |  |  |  |  |  |  |  | 
| 375 |  |  |  |  |  |  | sub set_node { | 
| 376 | 2 | 50 |  | 2 | 0 | 6 | ref(my $inst = shift) or Carp::croak "I'm only object method!"; | 
| 377 |  |  |  |  |  |  |  | 
| 378 | 2 |  |  |  |  | 14 | my $value = shift; | 
| 379 |  |  |  |  |  |  |  | 
| 380 | 2 | 0 |  |  |  | 3 | die 'incorrect node: ' . ( defined $value ? $value : 'undef' ) | 
|  |  | 50 |  |  |  |  |  | 
| 381 |  |  |  |  |  |  | unless _validate_node( $value ); | 
| 382 |  |  |  |  |  |  |  | 
| 383 | 2 |  |  |  |  | 3 | $inst -> {node} = $value; | 
| 384 | 2 |  |  |  |  | 4 | $inst -> _remove_presentations; | 
| 385 |  |  |  |  |  |  |  | 
| 386 | 2 |  |  |  |  | 4 | $inst; | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  | =head2 point: | 
| 390 |  |  |  |  |  |  |  | 
| 391 |  |  |  |  |  |  | $an -> set_point( 6 ); | 
| 392 |  |  |  |  |  |  | $an -> point; | 
| 393 |  |  |  |  |  |  | $an -> point( 0 ); | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | =for Pod::Coverage point set_point | 
| 396 |  |  |  |  |  |  |  | 
| 397 |  |  |  |  |  |  | =cut | 
| 398 |  |  |  |  |  |  |  | 
| 399 |  |  |  |  |  |  | sub point { | 
| 400 | 46 | 50 |  | 46 | 0 | 543 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | @_ ? | 
| 403 |  |  |  |  |  |  | $inst -> set_point( @_ ) | 
| 404 | 46 | 100 |  |  |  | 190 | : $inst -> {point}; | 
| 405 |  |  |  |  |  |  | } | 
| 406 |  |  |  |  |  |  |  | 
| 407 |  |  |  |  |  |  | sub set_point { | 
| 408 | 3 | 50 |  | 3 | 0 | 10 | ref(my $inst = shift) or Carp::croak "I'm only object method!"; | 
| 409 |  |  |  |  |  |  |  | 
| 410 | 3 |  |  |  |  | 4 | my $value = shift; | 
| 411 |  |  |  |  |  |  |  | 
| 412 | 3 | 0 |  |  |  | 7 | die 'incorrect point: ' . ( defined $value ? $value : 'undef' ) | 
|  |  | 50 |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | unless _validate_point( $value ); | 
| 414 |  |  |  |  |  |  |  | 
| 415 | 3 |  |  |  |  | 6 | $inst -> {point} = $value; | 
| 416 | 3 |  |  |  |  | 8 | $inst -> _remove_presentations; | 
| 417 |  |  |  |  |  |  |  | 
| 418 | 3 |  |  |  |  | 4 | $inst; | 
| 419 |  |  |  |  |  |  | } | 
| 420 |  |  |  |  |  |  |  | 
| 421 |  |  |  |  |  |  | =head1 REPRESENTATION | 
| 422 |  |  |  |  |  |  |  | 
| 423 |  |  |  |  |  |  | =head2 f4 - Full 4d address (without domain): | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | print $an -> f4;   # 1:22/99.0 | 
| 426 |  |  |  |  |  |  |  | 
| 427 |  |  |  |  |  |  | =cut | 
| 428 |  |  |  |  |  |  |  | 
| 429 |  |  |  |  |  |  | sub f4 { | 
| 430 | 23 | 50 |  | 23 | 1 | 62 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | $inst -> {full4d} = sprintf '%d:%d/%d.%d', map $inst -> { $_ }, qw/ zone net node point / | 
| 433 | 23 | 100 |  |  |  | 191 | unless exists $inst -> {full4d}; | 
| 434 |  |  |  |  |  |  |  | 
| 435 | 23 |  |  |  |  | 91 | $inst -> {full4d}; | 
| 436 |  |  |  |  |  |  | } | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  | =head2 s4 - Short form (if possible) of 4d address: | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | print $an -> s4;   # 1:22/99 | 
| 441 |  |  |  |  |  |  |  | 
| 442 |  |  |  |  |  |  | =cut | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  | sub s4 { | 
| 445 | 23 | 50 |  | 23 | 1 | 62 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  | $inst -> {short4d} = sprintf '%d:%d/%d%s', | 
| 448 |  |  |  |  |  |  | map( $inst -> { $_ }, qw/ zone net node / ), | 
| 449 |  |  |  |  |  |  | $inst -> {point} ? '.' . $inst -> {point} : '' | 
| 450 | 23 | 100 |  |  |  | 200 | unless exists $inst -> {short4d}; | 
|  |  | 100 |  |  |  |  |  | 
| 451 |  |  |  |  |  |  |  | 
| 452 | 23 |  |  |  |  | 96 | $inst -> {short4d}; | 
| 453 |  |  |  |  |  |  | } | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  | =head2 f5 - Full 5d address (with domain): | 
| 456 |  |  |  |  |  |  |  | 
| 457 |  |  |  |  |  |  | print $an -> f5;   # 1:22/99.0@fidonet | 
| 458 |  |  |  |  |  |  |  | 
| 459 |  |  |  |  |  |  | =cut | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  | sub f5 { | 
| 462 | 23 | 50 |  | 23 | 1 | 58 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 463 |  |  |  |  |  |  |  | 
| 464 |  |  |  |  |  |  | $inst -> {full5d} = sprintf '%d:%d/%d.%d@%s', map $inst -> { $_ }, qw/ zone net node point domain / | 
| 465 | 23 | 100 |  |  |  | 193 | unless exists $inst -> {full5d}; | 
| 466 |  |  |  |  |  |  |  | 
| 467 | 23 |  |  |  |  | 84 | $inst -> {full5d}; | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | =head2 s5 - Short form (if possible - only for nodes) of 5d address: | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | print $an -> s5;   # 1:22/99@fidonet | 
| 473 |  |  |  |  |  |  |  | 
| 474 |  |  |  |  |  |  | =cut | 
| 475 |  |  |  |  |  |  |  | 
| 476 |  |  |  |  |  |  | sub s5 { | 
| 477 | 23 | 50 |  | 23 | 1 | 99 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | $inst -> {short5d} = sprintf '%d:%d/%d%s@%s', | 
| 480 |  |  |  |  |  |  | map( $inst -> { $_ }, qw/ zone net node / ), | 
| 481 |  |  |  |  |  |  | $inst -> {point} ? '.' . $inst -> {point} : '', | 
| 482 |  |  |  |  |  |  | $inst -> {domain} | 
| 483 | 23 | 100 |  |  |  | 218 | unless exists $inst -> {short5d}; | 
|  |  | 100 |  |  |  |  |  | 
| 484 |  |  |  |  |  |  |  | 
| 485 | 23 |  |  |  |  | 75 | $inst -> {short5d}; | 
| 486 |  |  |  |  |  |  | } | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | =head2 fqfa - Full qualified FTN address: | 
| 489 |  |  |  |  |  |  |  | 
| 490 |  |  |  |  |  |  | print $an -> fqfa; # fidonet#1:22/99.0 | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | =cut | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | sub fqfa { | 
| 495 | 4 | 50 |  | 4 | 1 | 574 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | $inst -> {fqfa} = sprintf '%s#%d:%d/%d.%d', map $inst -> { $_ }, qw/ domain zone net node point / | 
| 498 | 4 | 100 |  |  |  | 26 | unless exists $inst -> {fqfa}; | 
| 499 |  |  |  |  |  |  |  | 
| 500 | 4 |  |  |  |  | 13 | $inst -> {fqfa}; | 
| 501 |  |  |  |  |  |  | } | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | =head2 bs - The Brake! FTN-compatible mailer for OS/2 style representation: | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | print $an -> bs;   # fidonet.1.22.99.0 | 
| 506 |  |  |  |  |  |  |  | 
| 507 |  |  |  |  |  |  | =cut | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | sub bs { | 
| 510 | 12 | 50 |  | 12 | 1 | 32 | ref( my $inst = shift ) or Carp::croak "I'm only an object method!"; | 
| 511 |  |  |  |  |  |  |  | 
| 512 |  |  |  |  |  |  | $inst -> {brake_style} = sprintf '%s.%d.%d.%d.%d', map $inst -> { $_ }, qw/ domain zone net node point / | 
| 513 | 12 | 100 |  |  |  | 97 | unless exists $inst -> {brake_style}; | 
| 514 |  |  |  |  |  |  |  | 
| 515 | 12 |  |  |  |  | 45 | $inst -> {brake_style}; | 
| 516 |  |  |  |  |  |  | } | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | =head1 COMPARISON | 
| 519 |  |  |  |  |  |  |  | 
| 520 |  |  |  |  |  |  | =head2 equal, eq, cmp | 
| 521 |  |  |  |  |  |  |  | 
| 522 |  |  |  |  |  |  | Two addresses can be compared. | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | my $one = FTN::Addr -> new( '1:23/45.66@fidonet' ) or die "cannot create"; | 
| 525 |  |  |  |  |  |  |  | 
| 526 |  |  |  |  |  |  | my $two = FTN::Addr -> new( '1:23/45.66@fidonet' ) or die "cannot create"; | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  | print "the same address!\n" if FTN::Addr -> equal( $one, $two ); # should print the message | 
| 529 |  |  |  |  |  |  |  | 
| 530 |  |  |  |  |  |  | print "the same address!\n" if $one eq $two;                   # the same result | 
| 531 |  |  |  |  |  |  |  | 
| 532 |  |  |  |  |  |  | print "but objects are different\n" if $one != $two;           # should print the message | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | The same way (comparison rules) as 'eq' works 'cmp' operator. | 
| 535 |  |  |  |  |  |  |  | 
| 536 |  |  |  |  |  |  | =cut | 
| 537 |  |  |  |  |  |  |  | 
| 538 |  |  |  |  |  |  | sub _eq {                       # eq operator | 
| 539 |  |  |  |  |  |  | return | 
| 540 | 5 | 50 | 33 | 5 |  | 721 | unless $_[ 1 ] | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 541 |  |  |  |  |  |  | && ref $_[ 1 ] | 
| 542 |  |  |  |  |  |  | && Scalar::Util::blessed $_[ 1 ] | 
| 543 |  |  |  |  |  |  | && $_[ 1 ] -> isa( 'FTN::Addr' ); | 
| 544 |  |  |  |  |  |  |  | 
| 545 | 5 | 50 | 33 |  |  | 12 | $_[ 0 ] -> domain eq $_[ 1 ] -> domain | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 546 |  |  |  |  |  |  | && $_[ 0 ] -> zone == $_[ 1 ] -> zone | 
| 547 |  |  |  |  |  |  | && $_[ 0 ] -> net == $_[ 1 ] -> net | 
| 548 |  |  |  |  |  |  | && $_[ 0 ] -> node == $_[ 1 ] -> node | 
| 549 |  |  |  |  |  |  | && $_[ 0 ] -> point == $_[ 1 ] -> point; | 
| 550 |  |  |  |  |  |  | } | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | sub _cmp {                      # cmp operator | 
| 553 |  |  |  |  |  |  | return | 
| 554 | 2 | 50 | 33 | 2 |  | 49 | unless $_[ 1 ] | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 555 |  |  |  |  |  |  | && ref $_[ 1 ] | 
| 556 |  |  |  |  |  |  | && Scalar::Util::blessed $_[ 1 ] | 
| 557 |  |  |  |  |  |  | && $_[ 1 ] -> isa( 'FTN::Addr' ); | 
| 558 |  |  |  |  |  |  |  | 
| 559 | 2 | 50 |  |  |  | 6 | if ( $_[ 2 ] ) {              # arguments were swapped | 
| 560 | 0 | 0 | 0 |  |  | 0 | $_[ 1 ] -> domain cmp $_[ 0 ] -> domain | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 561 |  |  |  |  |  |  | || $_[ 1 ] -> zone <=> $_[ 0 ] -> zone | 
| 562 |  |  |  |  |  |  | || $_[ 1 ] -> net <=> $_[ 0 ] -> net | 
| 563 |  |  |  |  |  |  | || $_[ 1 ] -> node <=> $_[ 0 ] -> node | 
| 564 |  |  |  |  |  |  | || $_[ 1 ] -> point <=> $_[ 0 ] -> point; | 
| 565 |  |  |  |  |  |  | } else { | 
| 566 | 2 | 50 | 66 |  |  | 4 | $_[ 0 ] -> domain cmp $_[ 1 ] -> domain | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 567 |  |  |  |  |  |  | || $_[ 0 ] -> zone <=> $_[ 1 ] -> zone | 
| 568 |  |  |  |  |  |  | || $_[ 0 ] -> net <=> $_[ 1 ] -> net | 
| 569 |  |  |  |  |  |  | || $_[ 0 ] -> node <=> $_[ 1 ] -> node | 
| 570 |  |  |  |  |  |  | || $_[ 0 ] -> point <=> $_[ 1 ] -> point; | 
| 571 |  |  |  |  |  |  | } | 
| 572 |  |  |  |  |  |  | } | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | sub equal { | 
| 575 | 1 | 50 |  | 1 | 1 | 288 | ref( my $class = shift ) and Carp::croak "I'm only a class method!"; | 
| 576 |  |  |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | return | 
| 578 | 1 | 50 | 33 |  |  | 18 | unless $_[ 0 ] | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 579 |  |  |  |  |  |  | && ref $_[ 0 ] | 
| 580 |  |  |  |  |  |  | && Scalar::Util::blessed $_[ 0 ] | 
| 581 |  |  |  |  |  |  | && $_[ 0 ] -> isa( 'FTN::Addr' ); | 
| 582 |  |  |  |  |  |  |  | 
| 583 | 1 |  |  |  |  | 4 | _eq( @_ ); | 
| 584 |  |  |  |  |  |  | } | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | =head1 AUTHOR | 
| 587 |  |  |  |  |  |  |  | 
| 588 |  |  |  |  |  |  | Valery Kalesnik, C<<  >> | 
| 589 |  |  |  |  |  |  |  | 
| 590 |  |  |  |  |  |  | =head1 BUGS | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | Please report any bugs or feature requests to C, or through | 
| 593 |  |  |  |  |  |  | the web interface at L.  I will be notified, and then you'll | 
| 594 |  |  |  |  |  |  | automatically be notified of progress on your bug as I make changes. | 
| 595 |  |  |  |  |  |  |  | 
| 596 |  |  |  |  |  |  | =head1 SUPPORT | 
| 597 |  |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  | You can find documentation for this module with the perldoc command. | 
| 599 |  |  |  |  |  |  |  | 
| 600 |  |  |  |  |  |  | perldoc FTN::Addr | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | =cut | 
| 603 |  |  |  |  |  |  |  | 
| 604 |  |  |  |  |  |  | 1; |