File Coverage

blib/lib/FTN/Nodelist.pm
Criterion Covered Total %
statement 104 119 87.3
branch 55 72 76.3
condition 37 52 71.1
subroutine 9 9 100.0
pod 2 2 100.0
total 207 254 81.5


line stmt bran cond sub pod time code
1             # FTN/Nodelist.pm
2             #
3             # Copyright (c) 2005-2007 Serguei Trouchelle. All rights reserved.
4             # Copyright (c) 2013 Robert James Clay. All rights reserved.
5             #
6             # This program is free software; you can redistribute it and/or modify it
7             # under the same terms as Perl itself.
8              
9             # History:
10             # 1.08 2013/05/09 Move 'pm' files to the more standard locations under the
11             # lib/ directory. Add Author & Copyright information for
12             # Robert James Clay .
13             # 1.07 2007/02/28 License added
14             # 1.06 2007/02/04 Quality update (Test::Pod, Test::Pod::Coverage)
15             # 1.05 2005/09/29 Fixed problem with non-existing node
16             # 1.04 2005/09/29 Fixed problem with missing nodelist
17             # 1.03 2005/02/25 Cache problem fixed
18             # 1.02 2005/02/22 Perl license added
19             # Pointlist processing added
20             # Documentation improved
21             # 1.01 2005/02/16 Initial revision
22              
23             =head1 NAME
24              
25             FTN::Nodelist - Process FTN nodelist
26              
27             =head1 SYNOPSIS
28              
29             my $ndl = new FTN::Nodelist(-file => '/fido/var/ndl/nodelist.*');
30             if (my $node = $ndl->getNode('2:550/4077')) {
31             print $node->sysop();
32             } else {
33             warn 'Cannot find node';
34             }
35              
36             =head1 DESCRIPTION
37              
38             C contains functions that can be used to process Fidonet
39             Technology Network nodelist and pointlist.
40              
41             =head1 METHODS
42              
43             =head2 new
44              
45             This method creates C object.
46             Can get following arguments:
47              
48             Nodelist file path:
49              
50             -file => '/path/to/nodelist'
51              
52             Path can point to definite file (ex.: C<'/var/ndl/nodelist.357'>) or contain
53             wildcard (.*) instead of digital extension. Maximum extension value will be
54             used to find exact nodelist (ex.: C<'/var/ndl/nodelist.*'>)
55              
56             Cacheable status:
57              
58             -cache => 0/1
59              
60             Default is 1. When cacheable status is set to 1, all search results are
61             stored in object cache. It saves resources when searching the same address,
62             but eats memory to store results. Choose appropriate behaviour depending on
63             your tasks.
64              
65             =head2 getNode( $addr )
66              
67             Takes FTN address as argument. Address can be feed in 3D or 4D style
68             (Zone:Net/Node, Zone:Net/Node.Point).
69              
70             If 4D style is specified, point address is searching.
71              
72             Returns C object if node can be found in nodelist.
73              
74             See L for details how these results can be used.
75              
76             Examples:
77              
78             my $node = $ndl->getNode('2:550/0');
79             my $node = $ndl->getNode('2:2/0');
80             my $node = $ndl->getNode('2:550/4077');
81             my $node = $ndl->getNode('2:550/4077.101');
82              
83             =head1 KNOWN ISSUES
84              
85             When using wildcard in nodelist path, maximum extension is taken into
86             account. It may bring to wrong results when there are many nodelist files
87             and current nodelist has lesser number (for example, C and
88             C).
89              
90             This issue may be resolved in next versions of C.
91              
92             =head1 AUTHORS
93              
94             Serguei Trouchelle EFE
95             Robert James Clay EFE
96              
97             =head1 LICENSE
98              
99             This program is free software; you can redistribute it and/or modify it
100             under the same terms as Perl itself.
101              
102             =head1 COPYRIGHT
103              
104             Copyright (c) 2005-2007 Serguei Trouchelle. All rights reserved.
105             Copyright (c) 2013 Robert James Clay. All rights reserved.
106              
107             =cut
108              
109             package FTN::Nodelist;
110              
111 6     6   24318 use FTN::Nodelist::Node;
  6         8  
  6         218  
112 6     6   2305 use FTN::Address;
  6         9358  
  6         247  
113              
114             require Exporter;
115 6     6   28 use Config;
  6         5  
  6         127  
116              
117 6     6   16 use strict;
  6         5  
  6         73  
118 6     6   40 use warnings;
  6         5  
  6         287  
119              
120             our @EXPORT_OK = qw//;
121             our %EXPORT_TAGS = ();
122             our @ISA = qw/Exporter/;
123              
124             $FTN::Nodelist::VERSION = "1.08";
125              
126 6     6   23 use File::Spec;
  6         7  
  6         100  
127 6     6   19 use File::Basename;
  6         6  
  6         5893  
128              
129             sub new {
130 5     5 1 55 my $self = shift;
131 5         16 my %attr = @_;
132 5         10 $self = {};
133              
134 5         13 my $ndlfile = $attr{'-file'};
135              
136 5 50       17 unless (defined $ndlfile) {
137 0         0 @$ = "No `-file' attribute specified, cannot find nodelist";
138 0         0 return undef;
139             }
140              
141 5 50       31 if ($ndlfile =~ /\.\*$/) { # wildmask used, find corresonding nodelist
142 5         272 my $directory = dirname($ndlfile);
143 5         104 my $filename = basename($ndlfile);
144              
145 5         20 $filename =~ s/\.\*$/.\\d\\d\\d/;
146              
147 5 50       184 if (opendir(DIR, $directory)) {
148 6         12 my ($ndl, @rest) = sort {$b cmp $a}
149 5 100       83 grep { /^$filename/ && -f "$directory/$_" }
  80         376  
150             readdir(DIR);
151 5         65 closedir DIR;
152 5 50       16 if (defined $ndl) {
153 5         103 $ndlfile = File::Spec->catfile($directory, $ndl);
154             } else {
155 0         0 $@ = 'Cannot find file ' . $ndlfile;
156 0         0 return undef;
157             }
158              
159             } else {
160             # failed to read directory
161 0         0 $@ = 'Cannot read directory ' . $directory;
162 0         0 return undef;
163             }
164             }
165              
166 5 50       70 unless (-e $ndlfile) {
167 0         0 $@ = 'Cannot find file ' . $ndlfile;
168 0         0 return undef;
169             }
170              
171 5         45 $self->{'__ndlfile'} = $ndlfile;
172              
173 5         9 $self->{'__cache'} = 1; # cache search results by default
174             # but may be overriden
175 5 50       15 $self->{'__cache'} = $attr{'-cache'} if exists $attr{'-cache'};
176              
177 5         6 bless $self ;
178 5         22 return $self;
179             }
180              
181             sub getNode {
182 27     27 1 1640 my $self = shift;
183 27         23 my $node = shift;
184              
185 27 50 33     126 if ($self->{'__cache'} and
186             $self->{'__nodes'}->{$node}) {
187             # Return cached copy
188 0         0 return $self->{'__nodes'}->{$node};
189             }
190              
191 27 50       76 if (my $addr = new FTN::Address($node)) {
192 27 100       572 if ($addr->{'p'}) {
193             # Points are not in nodelist
194             # Process boss/boss-point format pointlists...
195 12 50       244 if (open (F, '<' . $self->{'__ndlfile'})) {
196 12         11 my $found;
197              
198             PNT:
199 12         125 while() {
200 140 100       210 next if /^;/; # strip comments
201 116 100 66     337 if (m!^Boss,(\d+):(\d+)/(\d+)!
      66        
      66        
202             and $1 eq $addr->{'z'}
203             and $2 eq $addr->{'n'}
204             and $3 eq $addr->{'f'} ) {
205 8         26 while() {
206 100 50       108 next if /^;/; # strip comments
207 100 100 50     510 if (((/^,(\d+),/) or
      66        
208             (/^Point,(\d+),/) or
209             0
210             ) and ($addr->{'p'} == $1)) {
211 8         10 $found = $_;
212 8         11 last PNT;
213             }
214              
215 92 50       204 last PNT if /^Boss/; # Not found
216             }
217             }
218             }
219              
220 12         61 close(F);
221 12 100       17 if ($found) {
222 8         15 chomp $found;
223 8         28 my $node = new FTN::Nodelist::Node($addr, $found);
224             # cache result if needed
225 8 50       28 $self->{'__nodes'}->{$node->address()} = $node if $self->{'__cache'};
226 8         18 return $node;
227             } else {
228             # We will search point-format in nodelist
229             }
230             } else {
231 0         0 $@ = 'Cannot read nodelist ' . $@;
232 0         0 return undef;
233             }
234             }
235              
236             # Process nodelist
237              
238 19 50       392 if (open (F, '<' . $self->{'__ndlfile'})) {
239 19         17 my $found;
240              
241             NDL:
242              
243 19         154 while() {
244 76 100       201 next if /^;/; # strip comments
245 19 50 33     123 if ((/^Zone,(\d+),/) and ($addr->{'z'} == $1)) {
246 19 100 100     52 if ($addr->{'z'} eq $addr->{'n'} and $addr->{'f'} == 0) {
247 1         1 $found = $_;
248 1         2 last NDL;
249             }
250 18         14 my $reg;
251 18         40 while() {
252 122 100       194 next if /^;/; # strip comments
253 101 100       126 $reg = 1 if /^Region,/;
254 101 100 100     726 if ((/^Region,(\d+),/ or
    100 100        
      100        
      66        
      100        
255             /^Host,(\d+),/
256             ) and ($addr->{'n'} == $1)) {
257              
258 13 100       25 if ($addr->{'f'} == 0) {
259 2         3 $found = $_;
260 2         3 last NDL;
261             }
262              
263 11         29 while() {
264 24 100       40 next if /^;/; # strip comments
265 20 100 33     91 last NDL if /^Zone,/ or
      66        
266             /^Region,/ or
267             /^Host,/;
268 16 100 50     163 if (((/^,(\d+),/) or
      100        
269             (/^Hub,(\d+),/) or
270             (/^Pvt,(\d+),/) or
271             (/^Hold,(\d+),/) or
272             (/^Down,(\d+),/) or
273             0
274             ) and ($addr->{'f'} == $1)) {
275 7         7 $found = $_;
276 7         13 last NDL;
277             }
278             }
279             } elsif (not $reg and $addr->{'z'} eq $addr->{'n'}
280             and /,(\d+)/ and $addr->{'f'} eq $1) {
281 5         12 $found = $_;
282 5         7 last NDL;
283             }
284             }
285             }
286             }
287              
288 19 100       30 if ($addr->{'p'}) {
289             # Search for point (point-format)
290 4         3 undef $found; # Don't need boss-node
291 4         8 while() {
292 8 50       12 next if /^;/; # strip comments
293 8 50       19 last if /^((Zone)|(Region)|(Host)|(Hub)|(Pvt)|(Hold)|(Down))?,/;
294             # Next node found
295 8 100 66     37 if (/^Point,(\d+),/
296             and $1 == $addr->{'p'}) {
297 4         3 $found = $_;
298 4         4 last;
299             }
300             }
301             }
302              
303 19         95 close(F);
304 19 100       27 if ($found) {
305 15         23 chomp $found;
306 15         44 my $node = new FTN::Nodelist::Node($addr, $found);
307             # cache result if needed
308 15 50       48 $self->{'__nodes'}->{$node->address()} = $node if $self->{'__cache'};
309 15         30 return $node;
310             } else {
311 4         9 return undef; # Not found
312             }
313             } else {
314 0           $@ = 'Cannot read nodelist ' . $@;
315 0           return undef;
316             }
317             } else {
318 0           $@ = 'Invalid address : ' . $node;
319 0           return undef;
320             }
321             }
322              
323             1;