File Coverage

blib/lib/IO/Ftp.pm
Criterion Covered Total %
statement 24 144 16.6
branch 0 58 0.0
condition 0 15 0.0
subroutine 8 18 44.4
pod 5 8 62.5
total 37 243 15.2


line stmt bran cond sub pod time code
1             package IO::Ftp;
2             require 5.005_62;
3              
4 1     1   369 use strict;
  1         2  
  1         27  
5 1     1   3 use warnings;
  1         1  
  1         36  
6              
7             require Exporter;
8              
9             our @ISA = qw(Exporter);
10              
11 1     1   3 use vars qw/$VERSION/;
  1         3  
  1         86  
12              
13             $VERSION = 0.06;
14             our %EXPORT_TAGS = ( 'all' => [ qw(
15             new
16             delete
17             rename_to
18             mdtm
19             size
20             filename
21             ) ] );
22              
23             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
24             our @EXPORT = qw();
25              
26              
27 1     1   4 use File::Basename;
  1         1  
  1         67  
28 1     1   435 use URI;
  1         4893  
  1         27  
29 1     1   465 use Symbol;
  1         582  
  1         62  
30 1     1   466 use Net::FTP;
  1         29508  
  1         64  
31 1     1   10 use Carp;
  1         1  
  1         898  
32              
33              
34             sub new {
35 0     0 1   my ($src, $mode, $uri_string, %args) = @_;
36 0   0       my $class = ref $src || 'IO::Ftp';
37 0 0 0       if (ref $src and not $src->isa('IO::Ftp')) {
38 0           carp "Can't make an IO::FTP from a ", ref $src;
39 0           return;
40             }
41              
42 0           my $uri;
43 0 0         if (ref $uri_string) {
44 0 0         unless ($uri_string->isa('URI')) {
45 0           carp "can' t make a URI from a ", ref $uri_string;
46 0           return;
47             }
48 0           $uri = $uri_string;
49             } else {
50 0           $uri = URI->new('ftp:' . $uri_string);
51             }
52              
53 0           my $ftp;
54 0 0 0       if (ref $src and not $uri->host) {
55 0 0         if ($src->connected) {
56 0           warn "Can't reuse host with open connection";
57 0           return;
58             }
59 0           $ftp = ${*$src}{'io_ftp_ftp'};
  0            
60             } else {
61 0           $ftp = Net::FTP->new(
62             $uri->host,
63             Port => $uri->port,
64             Debug => $args{DEBUG},
65             Timeout => $args{Timeout},
66             BlockSize => $args{BlockSize},
67             Passive => $args{Passive},
68             );
69             }
70            
71 0 0         unless ($ftp) {
72 0           carp "Can't connect to host ", $uri->host;
73 0           return;
74             }
75            
76 0           my $self = __open($ftp, $mode, $uri, %args);
77 0 0         return unless $self;
78            
79 0           ${*$self}{'io_ftp_ftp'} = $ftp;
  0            
80 0           ${*$self}{'io_ftp_uri'} = $uri;
  0            
81              
82 0           return bless $self, $class;
83             }
84              
85             sub __open {
86 0     0     my ($ftp, $mode, $uri, %args) = @_;
87              
88 0   0       my $id = $uri->user || 'anonymous';
89 0   0       my $pwd = $uri->password || 'anon@anon.org';
90            
91 0 0         unless ($ftp->login($id, $pwd)) {
92 0           warn "Can't login: ", $ftp->message;
93 0           return;
94             }
95            
96 0 0         fileparse_set_fstype($args{OS}) if $args{OS};
97            
98 0           my ($file, $path) = fileparse($uri->path);
99 0 0         warn "File: $file, Path: $path" if $args{DEBUG};
100              
101 0 0         if ($path =~ m{^//(.*)}) { # initial single / is relative path, // is absolute
102 0           $path = $1;
103 0 0         warn "cwd /" if $args{DEBUG};
104 0 0         unless ($ftp->cwd('/')) {
105 0           warn "Can't cwd to /";
106 0           return;
107             }
108             }
109            
110 0           foreach (split '/', $path) {
111 0 0         next unless $_; #ignore embedded back-to-back /. else will cwd with no parm, which will default to 'cwd /'
112 0 0         warn "cwd $_" if $args{DEBUG};
113 0 0         unless ($ftp->cwd($_)) {
114 0           warn "Can't cwd to $_";
115 0           return;
116             }
117             }
118 0 0         if ($args{type}) {
119 0           $args{type} = uc $args{type};
120 0 0         unless ($args{type} =~ /^[AI]$/) {
121 0           carp "Invalid type: $args{type}";
122 0           return;
123             }
124 0 0         unless ($ftp->type($args{type}) ) {
125 0           carp "Can't set type $args{type}: ", $ftp->message;
126             }
127             }
128              
129 0 0         if ($mode eq '<<') {
130 0           $file = __find_file($ftp, $file);
131 0 0         return unless $file;
132             }
133              
134             # cache these in case user wants initial values. Can't get them once the data connection is open.
135 0           my $size = $ftp->size($file);
136 0           my $mdtm = $ftp->mdtm($file);
137            
138            
139 0           my $dataconn;
140 0 0 0       if ($mode eq '<' or $mode eq '<<') {
    0          
    0          
141 0           $dataconn = $ftp->retr($file);
142             } elsif ($mode eq '>') {
143 0           $dataconn = $ftp->stor($file);
144             } elsif ($mode eq '>>') {
145 0           $dataconn = $ftp->appe($file);
146             } else {
147 0           carp "Invalid mode $mode";
148 0           return;
149             }
150              
151 0 0         unless ($dataconn) {
152 0           carp "Can't open $file: ", $ftp->message ;
153 0           return;
154             }
155              
156             # we want to be a subclass of the dataconn, but its class is dynamic.
157 0           push @ISA, ref $dataconn;
158            
159 0           ${*$dataconn}{'io_ftp_file'} = $file;
  0            
160 0           ${*$dataconn}{'io_ftp_path'} = $path;
  0            
161 0           ${*$dataconn}{'io_ftp_size'} = $size;
  0            
162 0           ${*$dataconn}{'io_ftp_mdtm'} = $mdtm;
  0            
163            
164 0           return $dataconn;
165             }
166              
167             sub __find_file {
168 0     0     my ($ftp,$pattern) = @_;
169              
170 0           my @files = $ftp->ls($pattern);
171 0           return $files[0];
172             }
173              
174              
175             sub filename {
176 0     0 0   my $self = shift;
177 0           return ${*$self}{'io_ftp_file'};
  0            
178             }
179              
180             sub path {
181 0     0 0   my $self = shift;
182 0           return ${*$self}{'io_ftp_path'};
  0            
183             }
184              
185             sub uri {
186 0     0 0   my $self = shift;
187 0           return ${*$self}{'io_ftp_uri'};
  0            
188             }
189              
190             ### allow shortcuts to Net::FTP's rename and delete, but only if data connection not open. OTW we'll hang.
191              
192             sub rename_to {
193 0     0 1   my ($self, $new_name) = @_;
194 0 0         return if $self->connected;
195            
196 0           my $ret = ${*$self}{'io_ftp_ftp'}->rename(${*$self}{'io_ftp_file'}, $new_name);
  0            
  0            
197 0           ${*$self}{'io_ftp_file'} = $new_name;
  0            
198 0           return $ret;
199             }
200              
201             sub delete {
202 0     0 1   my ($self) = @_;
203 0 0         return if $self->connected;
204            
205 0           return ${*$self}{'io_ftp_ftp'}->delete(${*$self}{'io_ftp_file'});
  0            
  0            
206             }
207              
208              
209             ### return cached stats if connected, or real ones if connection closed.
210              
211             sub mdtm {
212 0     0 1   my ($self) = @_;
213 0 0         return ${*$self}{'io_ftp_mdtm'} if $self->connected;
  0            
214            
215 0           return ${*$self}{'io_ftp_ftp'}->mdtm(${*$self}{'io_ftp_file'});
  0            
  0            
216             }
217              
218             sub size {
219 0     0 1   my ($self) = @_;
220 0 0         return ${*$self}{'io_ftp_size'} if $self->connected;
  0            
221            
222 0           return ${*$self}{'io_ftp_ftp'}->size(${*$self}{'io_ftp_file'});
  0            
  0            
223             }
224              
225              
226             1;
227              
228              
229             =head1 NAME
230              
231             IO::Ftp - A simple interface to Net::FTP's socket level get/put (DEPRECATED)
232              
233             =head1 SYNOPSIS
234              
235              
236             use IO::Ftp;
237            
238             my $out = IO::Ftp->new('>','//user:pwd@foo.bar.com/foo/bar/fu.bar', TYPE=>'a');
239             my $in = IO::Ftp->new('<','//foo.bar.com/foo/bar/fu.bar', TYPE=>'a'); #anon access example
240            
241             while (<$in>) {
242             s/foo/bar/g;
243             print $out;
244             }
245            
246             close $in;
247             close $out;
248              
249              
250             ### for something along the lines of 'mget':
251            
252             while (my $in = IO::Ftp->new('<<','//foo.bar.com/foo/bar/*.txt', TYPE=>'a') {
253             print "processing ",$in->filename, "\n";
254             #...
255             $in->close;
256             $in->delete;
257             }
258              
259              
260             =head1 DESCRIPTION
261              
262             Deprecated. Other better options exist. See, for example, IO::All::FTP
263              
264             =head2 EXPORTS
265              
266             None by default.
267              
268             =head2 REQUIRES
269              
270             L
271             L
272             L
273             L
274              
275              
276             =head1 CONSTRUCTOR
277              
278             =over 4
279              
280             =item new ( MODE, URI [,OPTIONS] )
281              
282             C indicates the FTP command to use, and is one of
283              
284             =over 4
285              
286             =item < get
287              
288             =item > put
289              
290             =item >> append
291              
292             =item << get with wildcard match. This allows fetching a file when the name is not known,
293             or is partially known. Wildcarding is as performed by Net::FTP::ls. If more than one file matches,
294             the same one will always be returned. To process a number of files, they must be deleted
295             or renamed to not match the wildcard.
296              
297             =back
298              
299             C is an FTP format URI without the leading 'ftp:'.
300             C are passed in hash format, and can be one or more of
301              
302             =over 4
303              
304             =item TYPE force ASCII (a) or binary (i) mode for the transfer.
305              
306             =item DEBUG Enables debug messages. Also enabled Net::FTP's Debug flag.
307              
308             =item Timeout Passed to Net::FTP::new
309              
310             =item BlockSize Passed to Net::FTP::new
311              
312             =item Passive Passed to Net::FTP::new
313              
314             =back
315              
316             =back
317              
318             =head1 METHODS
319              
320             =over 4
321              
322             =item rename_to (NEW_NAME)
323             Renames the file.
324              
325             =item delete
326             Deletes the file.
327              
328             =item size
329             Returns the size of the file.
330              
331             =item mdtm
332             Returns the modification time of the fiile.
333              
334             =back
335              
336             Note: These methods cannot be performed while the connection is open.
337             rename_to and delete will fail and return undef if used before the socket is closed.
338              
339             size and mdtm cache their values before the socket is opened.
340             After the socket is closed, they call the Net::FTP methods of the same name.
341              
342             =head1 CREDITS
343              
344             Graham Barr for his Net::FTP module, which does all the 'real work'.
345              
346             tye at PerlMonks
347              
348             =head1 COPYRIGHT
349              
350             (c) 2003 Mike Blackwell. All rights reserved.
351             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
352              
353              
354             =head1 AUTHOR
355              
356             Mike Blackwell
357              
358             =head1 SEE ALSO
359              
360             Net::FTP
361             perl(1).
362              
363             =cut