root/trunk/Padre/lib/Padre/File/FTP.pm @ 9218

Revision 9215, 5.0 KB (checked in by Sewi, 9 months ago)

Some small fixes and minor changes to Padre::File::FTP

Line 
1package Padre::File::FTP;
2
3use 5.008;
4use strict;
5use warnings;
6
7use Padre::File;
8use File::Temp;
9
10our $VERSION = '0.50';
11our @ISA     = 'Padre::File';
12
13sub new {
14        my $class = shift;
15
16        my $url = shift;
17
18        # Create myself
19        my $self = bless { filename => $url }, $class;
20
21        # Using the config is optional, tests and other usages should run without
22        my $config = eval { return Padre->ide->config; };
23        if (defined($config)) {
24                $self->{_timeout} = $config->file_ftp_timeout;
25                $self->{_passive} = $config->file_ftp_passive;
26        } else {
27                # Use defaults if we have no config
28                $self->{_timeout} = 60;
29                $self->{_passive} = 1;
30        }
31
32        # Don't add a new overall-dependency to Padre:
33        eval { require Net::FTP; };
34        if ($@) {
35
36                $self->{error} = 'Net::FTP is not installed, Padre::File::FTP currently depends on it.';
37                return $self;
38        }
39
40##### START URL parsing #####
41
42##### NO REGEX's below this line (except the parser)! #####
43
44        # TO DO: Improve URL parsing
45        if ( $url !~ /ftp\:\/?\/?((.+?)(\:(.+?))?\@)?([a-z0-9\-\.]+)(\:(\d+))?(\/.+)$/i ) {
46
47                # URL parsing failed
48                # TO DO: Warning should go to a user popup not to the text console
49                $self->{error} = 'Unable to parse ' . $url;
50                return $self;
51        }
52
53
54        # Login data
55        if ( defined($2) ) {
56                $self->{_user} = $2;
57                $self->{_pass} = $4 if defined($4);
58        } else {
59                $self->{_user} = 'ftp';
60                $self->{_pass} = 'padre_user@devnull.perlide.org';
61        }
62
63        # Host & port
64        $self->{_host} = $5;
65        $self->{_port} = $7 || 21;
66
67        # Path & filename
68        $self->{_file} = $8;
69
70##### END URL parsing, regex is allowed again #####
71
72        if ( !defined( $self->{_pass} ) ) {
73
74                # TO DO: Ask the user for a password
75        }
76
77        # TO DO: Handle aborted/timed out connections
78
79        # Create FTP object and connection
80        $self->{_ftp} = Net::FTP->new(
81                Host    => $self->{_host},
82                Port    => $self->{_port},
83                Timeout => $self->{_timeout},
84                Passive => $self->{_passive},
85
86                #               Debug => 3, # Enable for FTP-debugging to STDERR
87        );
88
89        if ( !defined( $self->{_ftp} ) ) {
90
91                $self->{error} = 'Error connecting to ' . $self->{_host} . ':' . $self->{_port} . ': ' . $@;
92                return $self;
93        }
94
95        if ( !$self->{_ftp}->login( $self->{_user}, $self->{_pass} ) ) {
96
97                $self->{error} = 'Error logging in on ' . $self->{_host} . ':' . $self->{_port} . ': ' . $@;
98                return $self;
99        }
100
101        $self->{_ftp}->binary;
102
103        $self->{protocol} = 'ftp'; # Should not be overridden
104
105        $self->{_file_temp} = File::Temp->new( UNLINK => 1 );
106        $self->{_tmpfile} = $self->{_file_temp}->filename;
107
108        return $self;
109}
110
111sub can_run {
112        return 0;
113}
114
115sub size {
116        my $self = shift;
117        return if !defined( $self->{_ftp} );
118        return $self->{_ftp}->size( $self->{_file} );
119}
120
121sub _todo_mode {
122        my $self = shift;
123        return 33024; # Currently fixed: read-only textfile
124}
125
126sub _todo_mtime {
127        my $self = shift;
128
129        # The file-changed-on-disk - function requests this frequently:
130        if ( defined( $self->{_cached_mtime_time} ) and ( $self->{_cached_mtime_time} > ( time - 60 ) ) ) {
131                return $self->{_cached_mtime_value};
132        }
133
134        require HTTP::Date; # Part of LWP which is required for this module but not for Padre
135        my ( $Content, $Result ) = $self->_request('HEAD');
136
137        $self->{_cached_mtime_value} = HTTP::Date::str2time( $Result->header('Last-Modified') );
138        $self->{_cached_mtime_time}  = time;
139
140        return $self->{_cached_mtime_value};
141}
142
143sub exists {
144        my $self = shift;
145        return if !defined( $self->{_ftp} );
146
147        # Cache basename value
148        my $basename = $self->basename;
149
150        for ($self->{_ftp}->ls($self->{_file})) {
151                return 1 if $_ eq $self->{_file};
152                return 1 if $_ eq $basename;
153        }
154
155        # Fallback if ->ls didn't help. A file heaving a size should exist.
156        return 1 if $self->size;
157
158        return 0;
159}
160
161sub basename {
162        my $self = shift;
163
164        my $name = $self->{_file};
165        $name =~ s/^.*\///;
166
167        return $name;
168}
169
170# This method should return the dirname to be used inside Padre, not the one
171# used on the FTP-server.
172sub dirname {
173        my $self = shift;
174
175        my $dir = $self->{filename};
176        $dir =~ s/\/[^\/]*$//;
177
178        return $dir;
179}
180
181sub read {
182        my $self = shift;
183
184        return if !defined( $self->{_ftp} );
185
186        # TO DO: Better error handling
187        $self->{_ftp}->get( $self->{_file}, $self->{_tmpfile} ) or $self->{error} = $@;
188        open my $tmpfh, $self->{_tmpfile};
189        return join( '', <$tmpfh> );
190}
191
192sub readonly {
193
194        # TO DO: Check file access
195        return 0;
196}
197
198sub write {
199        my $self    = shift;
200        my $content = shift;
201        my $encode  = shift || ''; # undef encode = default, but undef will trigger a warning
202
203        return if !defined( $self->{_ftp} );
204
205        my $fh;
206        if ( !open $fh, ">$encode", $self->{_tmpfile} ) {
207                $self->{error} = $!;
208                return 0;
209        }
210        print {$fh} $content;
211        close $fh;
212
213        # TO DO: Better error handling
214        $self->{_ftp}->put( $self->{_tmpfile}, $self->{_file} ) or warn $@;
215
216        return 1;
217}
218
219###############################################################################
220### Internal FTP helper functions
221
222sub _ftp_dirname {
223        my $self = shift;
224
225        my $dir = $self->{_file};
226        $dir =~ s/\/[^\/]*$//;
227
228        return $dir;
229}
230
231
2321;
233
234# Copyright 2008-2009 The Padre development team as listed in Padre.pm.
235# LICENSE
236# This program is free software; you can redistribute it and/or
237# modify it under the same terms as Perl 5 itself.
Note: See TracBrowser for help on using the browser.