File Coverage

blib/lib/Net/FTP/Common.pm
Criterion Covered Total %
statement 115 185 62.1
branch 21 64 32.8
condition 3 10 30.0
subroutine 17 30 56.6
pod 18 24 75.0
total 174 313 55.5


line stmt bran cond sub pod time code
1             package Net::FTP::Common;
2              
3 4     4   45030 use strict;
  4         9  
  4         161  
4              
5 4     4   22 use Carp qw(cluck confess);
  4         6  
  4         265  
6 4     4   4182 use Data::Dumper;
  4         44325  
  4         307  
7 4     4   10311 use Net::FTP;
  4         216671  
  4         284  
8              
9              
10 4     4   45 use vars qw(@ISA $VERSION);
  4         9  
  4         9356  
11              
12             @ISA = qw(Net::FTP);
13              
14             $VERSION = '7.0.d';
15              
16             # Preloaded methods go here.
17              
18             sub new {
19 4     4 1 781 my $pkg = shift;
20 4         10 my $common_cfg_in = shift;
21 4         21 my %netftp_cfg_in = @_;
22              
23 4         29 my %common_cfg_default =
24             (
25             Host => 'ftp.microsoft.com',
26             RemoteDir => '/pub',
27             # LocalDir => '.', # setup something for $ez->get
28             Type => 'I'
29             );
30              
31 4         23 my %netftp_cfg_default = ( Debug => 1, Timeout => 240, Passive => 1 );
32              
33             # overwrite defaults with values supplied by constructor input
34 4         29 @common_cfg_default{keys %$common_cfg_in} = values %$common_cfg_in;
35 4         21 @netftp_cfg_default{keys %netftp_cfg_in} = values %netftp_cfg_in;
36            
37 4         13 my $self = {};
38              
39 4         15 @{$self->{Common}}{keys %common_cfg_default} = values %common_cfg_default;
  4         22  
40 4         16 @{$self }{keys %netftp_cfg_default} = values %netftp_cfg_default;
  4         12  
41              
42 4         25 my $new_self = { %$self, Common => $self->{Common} } ;
43              
44 4 50       25 if (my $file = $self->{Common}{STDERR}) {
45 0 0       0 open DUP, ">$file" or die "cannot dup STDERR to $file: $!";
46 0         0 lstat DUP; # kill used only once error
47 0         0 open STDERR, ">&DUP";
48             }
49              
50 4 50       409 warn "Net::FTP::Common::VERSION = ", $Net::FTP::Common::VERSION
51             if $self->{Debug} ;
52              
53              
54 4         43 bless $new_self, $pkg;
55             }
56              
57             sub config_dump {
58 1     1 0 2 my $self = shift;
59            
60 1         118 sprintf '
61             Here are the configuration parameters:
62             -------------------------------------
63             %s
64             ', Dumper($self);
65              
66             }
67              
68              
69             sub Common {
70 11     11 1 100 my $self = shift;
71              
72 11 50       65 not (@_ % 2) or die
73             "
74             Odd number of elements in assignment hash in call to Common().
75             Common() is a 'setter' subroutine. You cannot call it with an
76             odd number of arguments (e.g. $self->Common('Type') ) and
77             expect it to get a value. use GetCommon() for that.
78              
79             Here is what you passed in.
80             ", Dumper(\@_);
81              
82 11         47 my %tmp = @_;
83              
84             # warn "HA: ", Dumper(\%tmp,\@_);
85              
86 11         33 @{$self->{Common}}{keys %tmp} = values %tmp;
  11         229  
87             }
88              
89             sub GetCommon {
90 42     42 1 77 my ($self,$key) = @_;
91              
92 42 50       92 if ($key) {
93 42 100       156 if (defined($self->{Common}{$key})) {
94 36         207 return ($self->{Common}{$key});
95             } else {
96 6         27 return undef;
97             }
98             } else {
99 0         0 $self->{Common};
100             }
101             }
102              
103             sub Host {
104 6 50   6 0 132 $_[0]->{Common}->{Host}
105              
106             or die "Host must be defined when creating a __PACKAGE__ object"
107             }
108              
109             sub NetFTP {
110              
111 0     0 1 0 my ($self, %config) = @_;
112              
113 0         0 @{$self}{keys %config} = values %config;
  0         0  
114              
115             }
116              
117             sub login {
118 5     5 1 23 my ($self, %config) = @_;
119              
120 5         10 shift;
121              
122 5 50       23 if (@_ % 2) {
123 0         0 die sprintf "Do not confuse Net::FTP::Common's login() with Net::FTP's login()
124             Net::FTP::Common's login() expects to be supplied a hash.
125             E.g. \$ez->login(Host => \$Host)
126              
127             It was called incorrectly (%s). Program terminating
128             %s
129             ", (join ':', @_), $self->config_dump;
130             }
131              
132             # my $ftp_session = Net::FTP->new($self->Host, %{$self->{NetFTP}});
133 5         24 my $ftp_session = Net::FTP->new($self->Host, %$self);
134              
135             # $ftp_session or return undef;
136 5 100       121260249 $ftp_session or
137             die sprintf 'FATAL: attempt to create Net::FTP session on host %s failed.
138             If you cannot figure out why, supply the configuration parameters when
139             emailing the support email list.
140             %s', $self->Host, $self->config_dump;
141              
142              
143 4         38 my $session;
144 4         27 my $account = $self->GetCommon('Account');
145 4 50 33     16 if ($self->GetCommon('User') and $self->GetCommon('Pass')) {
146 4         14 $session =
147             $ftp_session->login($self->GetCommon('User') ,
148             $self->GetCommon('Pass'),
149             $account);
150             } else {
151 0         0 warn "either User or Pass was not defined. Attempting .netrc for login";
152 0         0 $session =
153             $ftp_session->login;
154             }
155              
156 4 0 0     982787 $session and ($self->Common('FTPSession', $ftp_session))
      33        
      50        
157             and return $ftp_session
158             or
159             warn "error logging in: $!" and return undef;
160              
161             }
162              
163             sub ls {
164 2     2 1 13 my ($self, @config) = @_;
165 2         8 my %config=@config;
166              
167 2         10 my $ftp = $self->prep(%config);
168              
169 2         14 my $ls = $ftp->ls;
170 2 50       714484 if (!defined($ls)) {
171 0         0 return ();
172             } else {
173 2         5 return @{$ls};
  2         27  
174             }
175             }
176              
177             # contributed by kevin evans
178             # this returns a hash of hashes keyed by filename with attributes for each
179             sub dir {
180 1     1 1 9 my ($self, @config) = @_;
181 1         4 my %config=@config;
182              
183              
184 1         7 my $ftp = $self->prep(%config);
185              
186 1         8 my $dir = $ftp->dir;
187 1 50       402350 if (!defined($dir)) {
188 0         0 return ();
189             } else
190             {
191 1         4 my %HoH;
192              
193             # Comments were made on this code in this thread:
194             # http://perlmonks.org/index.pl?node_id=287552
195              
196 1         4 foreach (@{$dir})
  1         5  
197             {
198             # $_ =~ m#([a-z-]*)\s*([0-9]*)\s*([0-9a-zA-Z]*)\s*([0-9a-zA-Z]*)\s*([0-9]*)\s*([A-Za-z]*)\s*([0-9]*)\s*([0-9A-Za-z:]*)\s*([A-Za-z0-9.-]*)#;
199             #$_ = m#([a-z-]*)\s*([0-9]*)\s*([0-9a-zA-Z]*)\s*([0-9a-zA-Z]*)\s*([0-9]*)\s*([A-Za-z]*)\s*([0-9]*)\s*([0-9A-Za-z:]*)\s*([\w*\W*\s*\S*]*)#;
200              
201             =for comment
202              
203             drwxr-xr-x 8 0 0 4096 Sep 27 2003 .
204             drwxr-xr-x 8 0 0 4096 Sep 27 2003 ..
205             drwxr-xr-x 3 0 0 4096 Sep 11 2003 .afs
206             -rw-r--r-- 1 0 0 809 Sep 26 2003 .banner
207             ----r-xr-x 1 0 0 0 Mar 4 2002 .notar
208             -rw-r--r-- 1 0 0 796 Sep 27 2003 README
209              
210             =cut
211              
212 12 50       4161 warn "input-line: $_" if $self->{Debug} ;
213              
214 12         138 $_ =~ m!^
215             ([\-FlrwxsStTdD]{10}) # directory and permissions
216             \s+
217             (\d+) # inode
218             \s+
219             (\w+) # 2nd number
220             \s+
221             (\w+) # 3rd number
222             \s+
223             (\d+) # file/dir size
224             \s+
225             (\w{3,4}) # month
226             \s+
227             (\d{1,2}) # day
228             \s+
229             (\d{1,2}:\d{2}|\d{4}) # year
230             \s+
231             (.+) # filename
232             $!x;
233              
234              
235 12         38 my $perm = $1;
236 12         101 my $inode = $2;
237 12         24 my $owner = $3;
238 12         21 my $group = $4;
239 12         24 my $size = $5;
240 12         18 my $month = $6;
241 12         20 my $day = $7;
242 12         26 my $yearOrTime = $8;
243 12         21 my $name = $9;
244 12         107 my $linkTarget;
245              
246 12 50       1349 warn "
247             my $perm = $1;
248             my $inode = $2;
249             my $owner = $3;
250             my $group = $4;
251             my $size = $5;
252             my $month = $6;
253             my $day = $7;
254             my $yearOrTime = $8;
255             my $name = $9;
256             my $linkTarget;
257             " if $self->{Debug} ;
258              
259 12 50       76 if ( $' =~ m#\s*->\s*([A-Za-z0-9.-/]*)# ) # it's a symlink
260 0         0 { $linkTarget = $1; }
261              
262 12         262 $HoH{$name}{perm} = $perm;
263 12         68 $HoH{$name}{inode} = $inode;
264 12         29 $HoH{$name}{owner} = $owner;
265 12         29 $HoH{$name}{group} = $group;
266 12         156 $HoH{$name}{size} = $size;
267 12         28 $HoH{$name}{month} = $month;
268 12         25 $HoH{$name}{day} = $day;
269 12         33 $HoH{$name}{yearOrTime} = $yearOrTime;
270 12         26 $HoH{$name}{linkTarget} = $linkTarget;
271              
272 12 50       195 warn "regexp-matches for ($name): ", Dumper(\$HoH{$name}) if $self->{Debug} ;
273              
274             }
275 1         229 return(%HoH);
276             }
277             }
278              
279              
280              
281             sub mkdir {
282 0     0 1 0 my ($self,%config) = @_;
283              
284 0         0 my $ftp = $self->prep(%config);
285 0         0 my $rd = $self->GetCommon('RemoteDir');
286 0         0 my $r = $self->GetCommon('Recurse');
287 0         0 $ftp->mkdir($rd, $r);
288             }
289              
290              
291             sub exists {
292 1     1 1 843 my ($self,%cfg) = @_;
293              
294 1         6 my @listing = $self->ls(%cfg);
295              
296 1         10 my $rf = $self->GetCommon('RemoteFile');
297              
298 1 50       96 warn sprintf "[checking @listing for [%s]]", $rf if $self->{Debug} ;
299              
300 1         4 scalar grep { $_ eq $self->GetCommon('RemoteFile') } @listing;
  12         25  
301             }
302              
303             sub delete {
304 0     0 1 0 my ($self,%cfg) = @_;
305              
306 0         0 my $ftp = $self->prep(%cfg);
307 0         0 my $rf = $self->GetCommon('RemoteFile');
308              
309            
310 0 0       0 warn Dumper \%cfg if $self->{Debug} ;
311              
312 0         0 $ftp->delete($rf);
313              
314             }
315              
316             sub grep {
317              
318 1     1 1 14 my ($self,%cfg) = @_;
319              
320             # warn sprintf "self: %s host: %s cfg: %s", $self, $host, Data::Dumper::Dumper(\%cfg);
321              
322 1         7 my @listing = $self->ls(%cfg);
323              
324 1         5 grep { $_ =~ /$cfg{Grep}/ } @listing;
  12         42  
325             }
326              
327             sub connected {
328 0     0 1 0 my $self = shift;
329              
330             # warn "CONNECTED SELF ", Dumper($self);
331              
332 0 0       0 my $session = $self->GetCommon('FTPSession') or return 0;
333              
334 0         0 local $@;
335 0         0 my $pwd;
336 0 0       0 my $connected = $session->pwd ? 1 : 0;
337             # warn "connected: $connected RESP: $connected";
338 0         0 $connected;
339             }
340              
341             sub quit {
342 0     0 1 0 my $self = shift;
343              
344 0 0       0 $self->connected and $self->GetCommon('FTPSession')->quit;
345              
346             }
347              
348              
349             sub prepped {
350 0     0 0 0 my $self = shift;
351 0 0       0 my $prepped = $self->GetCommon('FTPSession') and $self->connected;
352             # warn "prepped: $prepped";
353 0         0 $prepped;
354             }
355              
356             sub prep {
357 4     4 0 9 my $self = shift;
358 4         9 my %cfg = @_;
359              
360 4         21 $self->Common(%cfg);
361              
362             # This will not work if the Host changes and you are still connected
363             # to the prior host. It might be wise to simply drop connection
364             # if the Host key changes, but I don't think I will go there right now.
365             # my $ftp = $self->connected
366             # ? $self->GetCommon('FTPSession')
367             # : $self->login ;
368             # So instead:
369 4         18 my $ftp = $self->login ;
370              
371            
372 3 100       375 $self->Common(LocalDir => '.') unless
373             $self->GetCommon('LocalDir') ;
374              
375 3 50       16 if ($self->{Common}->{RemoteDir}) {
376 3         11 $ftp->cwd($self->GetCommon('RemoteDir'))
377             } else {
378 0         0 warn "RemoteDir not configured. ftp->cwd will not work. certain Net::FTP usages will failed.";
379             }
380 3         272449 $ftp->type($self->GetCommon('Type'));
381              
382 3         273160 $ftp;
383             }
384              
385             sub binary {
386 0     0 1 0 my $self = shift;
387              
388 0         0 $self->{Common}{Type} = 'I';
389             }
390              
391             sub ascii {
392 0     0 1 0 my $self = shift;
393              
394 0         0 $self->{Common}{Type} = 'A';
395             }
396              
397             sub get {
398              
399 1     1 1 10 my ($self,%cfg) = @_;
400              
401 1         6 my $ftp = $self->prep(%cfg);
402              
403 0           my $r;
404              
405             my $file;
406              
407 0 0         if ($self->GetCommon('LocalFile')) {
408 0           $file= $self->GetCommon('LocalFile');
409             } else {
410 0           $file=$self->GetCommon('RemoteFile');
411             }
412            
413 0           my $local_file = join '/', ($self->GetCommon('LocalDir'), $file);
414            
415             # warn "LF: $local_file ", "D: ", Dumper($self);
416              
417              
418 0 0         if ($r = $ftp->get($self->GetCommon('RemoteFile'), $local_file)) {
419 0           return $r;
420             } else {
421 0           warn sprintf 'download of %s to %s failed',
422             $self->GetCommon('RemoteFile'), $self->GetCommon('LocalFile');
423 0           warn
424             'here are the settings in your Net::FTP::Common object: %s',
425             Dumper($self);
426 0           return undef;
427             }
428            
429              
430             }
431              
432             sub file_attr {
433 0     0 0   my $self = shift;
434 0           my %hash;
435 0           my @key = qw(LocalFile LocalDir RemoteFile RemoteDir);
436 0           @hash{@key} = @{$self->{Common}}{@key};
  0            
437 0           %hash;
438             }
439              
440             sub bad_filename {
441 0     0 0   shift =~ /[\r\n]/s;
442             }
443              
444             sub send {
445 0     0 1   my ($self,%cfg) = @_;
446              
447 0           my $ftp = $self->prep(%cfg);
448              
449             # warn "send_self", Dumper($self);
450              
451 0           my %fa = $self->file_attr;
452              
453 0 0         if (bad_filename($fa{LocalFile})) {
454 0           warn "filenames may not have CRLF in them. skipping $fa{LocalFile}";
455 0           return;
456             }
457              
458 0 0         warn "send_fa: ", Dumper(\%fa) if $self->{Debug} ;
459              
460              
461 0           my $lf = sprintf "%s/%s", $fa{LocalDir}, $fa{LocalFile};
462 0 0         my $RF = $fa{RemoteFile} ? $fa{RemoteFile} : $fa{LocalFile};
463 0           my $rf = sprintf "%s/%s", $fa{RemoteDir}, $RF;
464              
465 0 0         warn "[upload $lf as $rf]" if $self->{Debug} ;
466              
467 0 0         $ftp->put($lf, $RF) or
468             confess sprintf "upload of %s to %s failed", $lf, $rf;
469             }
470              
471 0     0 1   sub put { goto &send }
472              
473 0     0     sub DESTROY {
474              
475              
476             }
477              
478              
479             1;
480             __END__