File Coverage

blib/lib/FTN/Crypt/Nodelist.pm
Criterion Covered Total %
statement 76 98 77.5
branch 27 42 64.2
condition 2 3 66.6
subroutine 9 9 100.0
pod 2 2 100.0
total 116 154 75.3


line stmt bran cond sub pod time code
1             # FTN::Crypt::Nodelist - Nodelist processing for the FTN::Crypt module
2             #
3             # Copyright (C) 2019 by Petr Antonov
4             #
5             # This library is free software; you can redistribute it and/or modify it
6             # under the same terms as Perl 5.10.0. For more details, see the full text
7             # of the licenses at https://opensource.org/licenses/Artistic-1.0, and
8             # http://www.gnu.org/licenses/gpl-2.0.html.
9             #
10             # This package is provided "as is" and without any express or implied
11             # warranties, including, without limitation, the implied warranties of
12             # merchantability and fitness for a particular purpose.
13             #
14              
15             package FTN::Crypt::Nodelist;
16              
17 3     3   66057 use strict;
  3         16  
  3         88  
18 3     3   15 use warnings;
  3         5  
  3         67  
19 3     3   33 use v5.10.1;
  3         9  
20              
21 3     3   17 use base qw/FTN::Crypt::Error/;
  3         6  
  3         612  
22              
23             #----------------------------------------------------------------------#
24              
25             =head1 NAME
26              
27             FTN::Crypt::Nodelist - Nodelist processing for the L<FTN::Crypt> module.
28              
29             =head1 SYNOPSIS
30              
31             use FTN::Crypt::Nodelist;
32              
33             my $obj = FTN::Crypt::Nodelist->new(
34             Nodelist => 'NODELIST.*',
35             Pointlist => [
36             'pointlist_1.*',
37             'pointlist_2',
38             ],
39             Username => 'user', # optional, defaults to 'sysop'
40             );
41             my ($addr, $method) = $obj->get_email_addr('99:8877/1');
42              
43             =cut
44              
45             #----------------------------------------------------------------------#
46              
47 3     3   489 use FTN::Address;
  3         2240  
  3         127  
48 3     3   425 use FTN::Crypt::Constants;
  3         5  
  3         70  
49 3     3   1410 use FTN::Nodelist;
  3         7931  
  3         2522  
50              
51             #----------------------------------------------------------------------#
52              
53             my $DEFAULT_USERNAME = 'sysop';
54              
55             #----------------------------------------------------------------------#
56              
57             =head1 METHODS
58              
59             =cut
60              
61             #----------------------------------------------------------------------#
62              
63             =head2 new()
64              
65             Constructor.
66              
67             =head3 Parameters:
68              
69             =over 4
70              
71             =item * C<Nodelist>: Path to nodelist file(s), either scalar or arrayref. If contains wildcard, file with maximum number in digital extension will be selected.
72              
73             =item * B<Optional> C<Pointlist>: Path to pointlist file(s), either scalar or arrayref. If contains wildcard, file with maximum number in digital extension will be selected.
74              
75             =item * B<Optional> C<Username>: Username part in email address, which corresponds to the FTN one, defaults to 'sysop'.
76              
77             =back
78              
79             =head3 Returns:
80              
81             Created object or error in C<FTN::Crypt::Nodelist-E<gt>error>.
82              
83             Sample:
84              
85             my $obj = FTN::Crypt::Nodelist->new(
86             Nodelist => 'NODELIST.*',
87             Pointlist => [
88             'pointlist_1.*',
89             'pointlist_2',
90             ],
91             Username => 'user', # optional, defaults to 'sysop'
92             );
93              
94             =cut
95              
96             sub new {
97 2     2 1 858 my $class = shift;
98 2         13 my (%opts) = @_;
99              
100 2 50       9 unless (%opts) {
101 0         0 $class->set_error('No options specified');
102 0         0 return;
103             }
104 2 50       9 unless ($opts{Nodelist}) {
105 0         0 $class->set_error('No nodelist specified');
106 0         0 return;
107             }
108              
109 2         12 my $self = {
110             _username => $DEFAULT_USERNAME,
111             };
112              
113 2 50       12 $opts{Nodelist} = [$opts{Nodelist}] unless ref $opts{Nodelist};
114 2 50       9 unless (ref $opts{Nodelist} eq 'ARRAY') {
115 0         0 $class->set_error('Nodelist value error');
116 0         0 return;
117             }
118 2 50       4 unless (scalar @{$opts{Nodelist}}) {
  2         8  
119 0         0 $class->set_error('No nodelist specified');
120 0         0 return;
121             }
122              
123 2         10 $self->{_nodelist} = [];
124 2         6 foreach my $nl_file (@{$opts{Nodelist}}) {
  2         8  
125 2         46 my $nl = FTN::Nodelist->new(-file => $nl_file);
126 2 50       639 unless ($nl) {
127 0         0 $class->set_error($@);
128 0         0 return;
129             }
130 2         6 push @{$self->{_nodelist}}, $nl;
  2         10  
131             }
132              
133 2 50       10 if ($opts{Pointlist}) {
134 2 50       8 $opts{Pointlist} = [$opts{Pointlist}] unless ref $opts{Pointlist};
135 2 50       9 unless (ref $opts{Pointlist} eq 'ARRAY') {
136 0         0 $class->set_error('Pointlist value error');
137 0         0 return;
138             }
139 2 50       4 if (scalar @{$opts{Pointlist}}) {
  2         7  
140 2         5 $self->{_pointlist} = [];
141 2         20 foreach my $pl_file (@{$opts{Pointlist}}) {
  2         9  
142 4         15 my $pl = FTN::Nodelist->new(-file => $pl_file);
143 4 50       454 unless ($pl) {
144 0         0 $class->set_error($@);
145 0         0 return;
146             }
147 4         8 push @{$self->{_pointlist}}, $pl;
  4         14  
148             }
149             }
150             }
151              
152 2 100       7 if ($opts{Username}) {
153 1 50       8 unless ($opts{Username} =~ /^\w+([\.-]?\w+)*$/) {
154 0         0 $class->set_error('Invalid username format');
155 0         0 return;
156             }
157 1         3 $self->{_username} = $opts{Username};
158             }
159              
160 2         12 $self = bless $self, $class;
161 2         11 return $self;
162             }
163              
164             #----------------------------------------------------------------------#
165              
166             =head2 get_email_addr()
167              
168             If recipient supports PGP encryption, get recipient's email address and encryption method.
169              
170             =head3 Parameters:
171              
172             =over 4
173              
174             =item * Recipient's FTN address.
175              
176             =back
177              
178             =head3 Returns:
179              
180             Recipient's email address and encryption method or error in C<$obj-E<gt>error>.
181              
182             Sample:
183              
184             my ($addr, $method) = $obj->get_email_addr('99:8877/1') or die $obj->error;
185              
186             =cut
187              
188             sub get_email_addr {
189 7     7 1 3757 my $self = shift;
190 7         17 my ($ftn_addr) = @_;
191              
192 7 50       17 unless ($ftn_addr) {
193 0         0 $self->set_error('No FTN address specified');
194 0         0 return;
195             }
196              
197 7         27 my $addr = FTN::Address->new($ftn_addr);
198 7 50       194 unless ($addr) {
199 0         0 $self->set_error($@);
200 0         0 return;
201             }
202              
203 7 100 66     67 my $search_list = ($ftn_addr =~ /^\d+:\d+\/\d+\.(\d+)(?:@\w+)?$/ && $1 && $self->{_pointlist}) ? '_pointlist' : '_nodelist';
204              
205 7         12 my $node;
206 7         9 foreach my $list (@{$self->{$search_list}}) {
  7         33  
207 8         36 $node = $list->getNode($ftn_addr);
208 8 100       1469 last if $node;
209             }
210 7 100       19 unless ($node) {
211 1         5 $self->set_error('FTN address not found');
212 1         4 return;
213             }
214              
215 21 100       107 my %flags = map { /:/ ? (split /:/, $_, 2) : ($_ => 1) }
216 21         87 map { tr/\r\n//dr }
217 6         10 @{$node->flags};
  6         22  
218 6 100       30 unless ($flags{$FTN::Crypt::Constants::ENC_NODELIST_FLAG}) {
219 1         10 $self->set_error("No encryption nodelist flag ($FTN::Crypt::Constants::ENC_NODELIST_FLAG)");
220 1         9 return;
221             }
222 5 50       24 unless ($FTN::Crypt::Constants::ENC_METHODS{$flags{$FTN::Crypt::Constants::ENC_NODELIST_FLAG}}) {
223 0         0 $self->set_error("Unsupported encryption method ($flags{$FTN::Crypt::Constants::ENC_NODELIST_FLAG})");
224 0         0 return;
225             }
226              
227 5         22 return "<$self->{_username}@" . $addr->fqdn . '>', $flags{$FTN::Crypt::Constants::ENC_NODELIST_FLAG};
228             }
229              
230             1;
231             __END__
232              
233             =head1 AUTHOR
234              
235             Petr Antonov, E<lt>pietro@cpan.orgE<gt>
236              
237             =head1 COPYRIGHT AND LICENSE
238              
239             Copyright (C) 2019 by Petr Antonov
240              
241             This library is free software; you can redistribute it and/or modify it
242             under the same terms as Perl 5.10.0. For more details, see the full text
243             of the licenses at L<https://opensource.org/licenses/Artistic-1.0>, and
244             L<http://www.gnu.org/licenses/gpl-2.0.html>.
245              
246             This package is provided "as is" and without any express or implied
247             warranties, including, without limitation, the implied warranties of
248             merchantability and fitness for a particular purpose.