home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / perl / 5.10.0 / File / Fetch.pm < prev    next >
Encoding:
Perl POD Document  |  2009-06-26  |  33.1 KB  |  1,227 lines

  1. package File::Fetch;
  2.  
  3. use strict;
  4. use FileHandle;
  5. use File::Copy;
  6. use File::Spec;
  7. use File::Spec::Unix;
  8. use File::Basename              qw[dirname];
  9.  
  10. use Cwd                         qw[cwd];
  11. use Carp                        qw[carp];
  12. use IPC::Cmd                    qw[can_run run];
  13. use File::Path                  qw[mkpath];
  14. use Params::Check               qw[check];
  15. use Module::Load::Conditional   qw[can_load];
  16. use Locale::Maketext::Simple    Style => 'gettext';
  17.  
  18. use vars    qw[ $VERBOSE $PREFER_BIN $FROM_EMAIL $USER_AGENT
  19.                 $BLACKLIST $METHOD_FAIL $VERSION $METHODS
  20.                 $FTP_PASSIVE $TIMEOUT $DEBUG $WARN
  21.             ];
  22.  
  23. use constant QUOTE  => do { $^O eq 'MSWin32' ? q["] : q['] };            
  24.             
  25.  
  26. $VERSION        = '0.14';
  27. $VERSION        = eval $VERSION;    # avoid warnings with development releases
  28. $PREFER_BIN     = 0;                # XXX TODO implement
  29. $FROM_EMAIL     = 'File-Fetch@example.com';
  30. $USER_AGENT     = 'File::Fetch/$VERSION';
  31. $BLACKLIST      = [qw|ftp|];
  32. $METHOD_FAIL    = { };
  33. $FTP_PASSIVE    = 1;
  34. $TIMEOUT        = 0;
  35. $DEBUG          = 0;
  36. $WARN           = 1;
  37.  
  38. ### methods available to fetch the file depending on the scheme
  39. $METHODS = {
  40.     http    => [ qw|lwp wget curl lynx| ],
  41.     ftp     => [ qw|lwp netftp wget curl ncftp ftp| ],
  42.     file    => [ qw|lwp file| ],
  43.     rsync   => [ qw|rsync| ]
  44. };
  45.  
  46. ### silly warnings ###
  47. local $Params::Check::VERBOSE               = 1;
  48. local $Params::Check::VERBOSE               = 1;
  49. local $Module::Load::Conditional::VERBOSE   = 0;
  50. local $Module::Load::Conditional::VERBOSE   = 0;
  51.  
  52. ### see what OS we are on, important for file:// uris ###
  53. use constant ON_WIN         => ($^O eq 'MSWin32');
  54. use constant ON_VMS         => ($^O eq 'VMS');                                
  55. use constant ON_UNIX        => (!ON_WIN);
  56. use constant HAS_VOL        => (ON_WIN);
  57. use constant HAS_SHARE      => (ON_WIN);
  58. =pod
  59.  
  60. =head1 NAME
  61.  
  62. File::Fetch - A generic file fetching mechanism
  63.  
  64. =head1 SYNOPSIS
  65.  
  66.     use File::Fetch;
  67.  
  68.     ### build a File::Fetch object ###
  69.     my $ff = File::Fetch->new(uri => 'http://some.where.com/dir/a.txt');
  70.  
  71.     ### fetch the uri to cwd() ###
  72.     my $where = $ff->fetch() or die $ff->error;
  73.  
  74.     ### fetch the uri to /tmp ###
  75.     my $where = $ff->fetch( to => '/tmp' );
  76.  
  77.     ### parsed bits from the uri ###
  78.     $ff->uri;
  79.     $ff->scheme;
  80.     $ff->host;
  81.     $ff->path;
  82.     $ff->file;
  83.  
  84. =head1 DESCRIPTION
  85.  
  86. File::Fetch is a generic file fetching mechanism.
  87.  
  88. It allows you to fetch any file pointed to by a C<ftp>, C<http>,
  89. C<file>, or C<rsync> uri by a number of different means.
  90.  
  91. See the C<HOW IT WORKS> section further down for details.
  92.  
  93. =head1 ACCESSORS
  94.  
  95. A C<File::Fetch> object has the following accessors
  96.  
  97. =over 4
  98.  
  99. =item $ff->uri
  100.  
  101. The uri you passed to the constructor
  102.  
  103. =item $ff->scheme
  104.  
  105. The scheme from the uri (like 'file', 'http', etc)
  106.  
  107. =item $ff->host
  108.  
  109. The hostname in the uri.  Will be empty if host was originally 
  110. 'localhost' for a 'file://' url.
  111.  
  112. =item $ff->vol
  113.  
  114. On operating systems with the concept of a volume the second element
  115. of a file:// is considered to the be volume specification for the file.
  116. Thus on Win32 this routine returns the volume, on other operating
  117. systems this returns nothing.
  118.  
  119. On Windows this value may be empty if the uri is to a network share, in 
  120. which case the 'share' property will be defined. Additionally, volume 
  121. specifications that use '|' as ':' will be converted on read to use ':'.
  122.  
  123. On VMS, which has a volume concept, this field will be empty because VMS
  124. file specifications are converted to absolute UNIX format and the volume
  125. information is transparently included.
  126.  
  127. =item $ff->share
  128.  
  129. On systems with the concept of a network share (currently only Windows) returns 
  130. the sharename from a file://// url.  On other operating systems returns empty.
  131.  
  132. =item $ff->path
  133.  
  134. The path from the uri, will be at least a single '/'.
  135.  
  136. =item $ff->file
  137.  
  138. The name of the remote file. For the local file name, the
  139. result of $ff->output_file will be used. 
  140.  
  141. =cut
  142.  
  143.  
  144. ##########################
  145. ### Object & Accessors ###
  146. ##########################
  147.  
  148. {
  149.     ### template for new() and autogenerated accessors ###
  150.     my $Tmpl = {
  151.         scheme          => { default => 'http' },
  152.         host            => { default => 'localhost' },
  153.         path            => { default => '/' },
  154.         file            => { required => 1 },
  155.         uri             => { required => 1 },
  156.         vol             => { default => '' }, # windows for file:// uris
  157.         share           => { default => '' }, # windows for file:// uris
  158.         _error_msg      => { no_override => 1 },
  159.         _error_msg_long => { no_override => 1 },
  160.     };
  161.     
  162.     for my $method ( keys %$Tmpl ) {
  163.         no strict 'refs';
  164.         *$method = sub {
  165.                         my $self = shift;
  166.                         $self->{$method} = $_[0] if @_;
  167.                         return $self->{$method};
  168.                     }
  169.     }
  170.     
  171.     sub _create {
  172.         my $class = shift;
  173.         my %hash  = @_;
  174.         
  175.         my $args = check( $Tmpl, \%hash ) or return;
  176.         
  177.         bless $args, $class;
  178.     
  179.         if( lc($args->scheme) ne 'file' and not $args->host ) {
  180.             return File::Fetch->_error(loc(
  181.                 "Hostname required when fetching from '%1'",$args->scheme));
  182.         }
  183.         
  184.         for (qw[path file]) {
  185.             unless( $args->$_() ) { # 5.5.x needs the ()
  186.                 return File::Fetch->_error(loc("No '%1' specified",$_));
  187.             }
  188.         }
  189.         
  190.         return $args;
  191.     }    
  192. }
  193.  
  194. =item $ff->output_file
  195.  
  196. The name of the output file. This is the same as $ff->file,
  197. but any query parameters are stripped off. For example:
  198.  
  199.     http://example.com/index.html?x=y
  200.  
  201. would make the output file be C<index.html> rather than 
  202. C<index.html?x=y>.
  203.  
  204. =back
  205.  
  206. =cut
  207.  
  208. sub output_file {
  209.     my $self = shift;
  210.     my $file = $self->file;
  211.     
  212.     $file =~ s/\?.*$//g;
  213.     
  214.     return $file;
  215. }
  216.  
  217. ### XXX do this or just point to URI::Escape?
  218. # =head2 $esc_uri = $ff->escaped_uri
  219. # =cut
  220. # ### most of this is stolen straight from URI::escape
  221. # {   ### Build a char->hex map
  222. #     my %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255;
  223. #     sub escaped_uri {
  224. #         my $self = shift;
  225. #         my $uri  = $self->uri;
  226. #         ### Default unsafe characters.  RFC 2732 ^(uric - reserved)
  227. #         $uri =~ s/([^A-Za-z0-9\-_.!~*'()])/
  228. #                     $escapes{$1} || $self->_fail_hi($1)/ge;
  229. #         return $uri;
  230. #     }
  231. #     sub _fail_hi {
  232. #         my $self = shift;
  233. #         my $char = shift;
  234. #         
  235. #         $self->_error(loc(
  236. #             "Can't escape '%1', try using the '%2' module instead", 
  237. #             sprintf("\\x{%04X}", ord($char)), 'URI::Escape'
  238. #         ));            
  239. #     }
  240. #     sub output_file {
  241. #     
  242. #     }
  243. #     
  244. #     
  245. # }
  246.  
  247. =head1 METHODS
  248.  
  249. =head2 $ff = File::Fetch->new( uri => 'http://some.where.com/dir/file.txt' );
  250.  
  251. Parses the uri and creates a corresponding File::Fetch::Item object,
  252. that is ready to be C<fetch>ed and returns it.
  253.  
  254. Returns false on failure.
  255.  
  256. =cut
  257.  
  258. sub new {
  259.     my $class = shift;
  260.     my %hash  = @_;
  261.  
  262.     my ($uri);
  263.     my $tmpl = {
  264.         uri => { required => 1, store => \$uri },
  265.     };
  266.  
  267.     check( $tmpl, \%hash ) or return;
  268.  
  269.     ### parse the uri to usable parts ###
  270.     my $href    = __PACKAGE__->_parse_uri( $uri ) or return;
  271.  
  272.     ### make it into a FFI object ###
  273.     my $ff      = File::Fetch->_create( %$href ) or return;
  274.  
  275.  
  276.     ### return the object ###
  277.     return $ff;
  278. }
  279.  
  280. ### parses an uri to a hash structure:
  281. ###
  282. ### $class->_parse_uri( 'ftp://ftp.cpan.org/pub/mirror/index.txt' )
  283. ###
  284. ### becomes:
  285. ###
  286. ### $href = {
  287. ###     scheme  => 'ftp',
  288. ###     host    => 'ftp.cpan.org',
  289. ###     path    => '/pub/mirror',
  290. ###     file    => 'index.html'
  291. ### };
  292. ###
  293. ### In the case of file:// urls there maybe be additional fields
  294. ###
  295. ### For systems with volume specifications such as Win32 there will be 
  296. ### a volume specifier provided in the 'vol' field.
  297. ###
  298. ###   'vol' => 'volumename'
  299. ###
  300. ### For windows file shares there may be a 'share' key specified
  301. ###
  302. ###   'share' => 'sharename' 
  303. ###
  304. ### Note that the rules of what a file:// url means vary by the operating system 
  305. ### of the host being addressed. Thus file:///d|/foo/bar.txt means the obvious
  306. ### 'D:\foo\bar.txt' on windows, but on unix it means '/d|/foo/bar.txt' and 
  307. ### not '/foo/bar.txt'
  308. ###
  309. ### Similarly if the host interpreting the url is VMS then 
  310. ### file:///disk$user/my/notes/note12345.txt' means 
  311. ### 'DISK$USER:[MY.NOTES]NOTE123456.TXT' but will be returned the same as
  312. ### if it is unix where it means /disk$user/my/notes/note12345.txt'.
  313. ### Except for some cases in the File::Spec methods, Perl on VMS will generally
  314. ### handle UNIX format file specifications.
  315. ###
  316. ### This means it is impossible to serve certain file:// urls on certain systems.
  317. ###
  318. ### Thus are the problems with a protocol-less specification. :-(
  319. ###
  320.  
  321. sub _parse_uri {
  322.     my $self = shift;
  323.     my $uri  = shift or return;
  324.  
  325.     my $href = { uri => $uri };
  326.  
  327.     ### find the scheme ###
  328.     $uri            =~ s|^(\w+)://||;
  329.     $href->{scheme} = $1;
  330.  
  331.     ### See rfc 1738 section 3.10
  332.     ### http://www.faqs.org/rfcs/rfc1738.html
  333.     ### And wikipedia for more on windows file:// urls
  334.     ### http://en.wikipedia.org/wiki/File://
  335.     if( $href->{scheme} eq 'file' ) {
  336.         
  337.         my @parts = split '/',$uri;
  338.  
  339.         ### file://hostname/...
  340.         ### file://hostname/...
  341.         ### normalize file://localhost with file:///
  342.         $href->{host} = $parts[0] || '';
  343.  
  344.         ### index in @parts where the path components begin;
  345.         my $index = 1;  
  346.  
  347.         ### file:////hostname/sharename/blah.txt        
  348.         if ( HAS_SHARE and not length $parts[0] and not length $parts[1] ) {
  349.             
  350.             $href->{host}   = $parts[2] || '';  # avoid warnings
  351.             $href->{share}  = $parts[3] || '';  # avoid warnings        
  352.  
  353.             $index          = 4         # index after the share
  354.  
  355.         ### file:///D|/blah.txt
  356.         ### file:///D:/blah.txt
  357.         } elsif (HAS_VOL) {
  358.         
  359.             ### this code comes from dmq's patch, but:
  360.             ### XXX if volume is empty, wouldn't that be an error? --kane
  361.             ### if so, our file://localhost test needs to be fixed as wel            
  362.             $href->{vol}    = $parts[1] || '';
  363.  
  364.             ### correct D| style colume descriptors
  365.             $href->{vol}    =~ s/\A([A-Z])\|\z/$1:/i if ON_WIN;
  366.  
  367.             $index          = 2;        # index after the volume
  368.         } 
  369.  
  370.         ### rebuild the path from the leftover parts;
  371.         $href->{path} = join '/', '', splice( @parts, $index, $#parts );
  372.  
  373.     } else {
  374.         ### using anything but qw() in hash slices may produce warnings 
  375.         ### in older perls :-(
  376.         @{$href}{ qw(host path) } = $uri =~ m|([^/]*)(/.*)$|s;
  377.     }
  378.  
  379.     ### split the path into file + dir ###
  380.     {   my @parts = File::Spec::Unix->splitpath( delete $href->{path} );
  381.         $href->{path} = $parts[1];
  382.         $href->{file} = $parts[2];
  383.     }
  384.  
  385.     ### host will be empty if the target was 'localhost' and the 
  386.     ### scheme was 'file'
  387.     $href->{host} = '' if   ($href->{host}      eq 'localhost') and
  388.                             ($href->{scheme}    eq 'file');
  389.  
  390.     return $href;
  391. }
  392.  
  393. =head2 $ff->fetch( [to => /my/output/dir/] )
  394.  
  395. Fetches the file you requested. By default it writes to C<cwd()>,
  396. but you can override that by specifying the C<to> argument.
  397.  
  398. Returns the full path to the downloaded file on success, and false
  399. on failure.
  400.  
  401. =cut
  402.  
  403. sub fetch {
  404.     my $self = shift or return;
  405.     my %hash = @_;
  406.  
  407.     my $to;
  408.     my $tmpl = {
  409.         to  => { default => cwd(), store => \$to },
  410.     };
  411.  
  412.     check( $tmpl, \%hash ) or return;
  413.  
  414.     ### On VMS force to VMS format so File::Spec will work.
  415.     $to = VMS::Filespec::vmspath($to) if ON_VMS;
  416.  
  417.     ### create the path if it doesn't exist yet ###
  418.     unless( -d $to ) {
  419.         eval { mkpath( $to ) };
  420.  
  421.         return $self->_error(loc("Could not create path '%1'",$to)) if $@;
  422.     }
  423.  
  424.     ### set passive ftp if required ###
  425.     local $ENV{FTP_PASSIVE} = $FTP_PASSIVE;
  426.  
  427.     ### we dont use catfile on win32 because if we are using a cygwin tool
  428.     ### under cmd.exe they wont understand windows style separators.
  429.     my $out_to = ON_WIN ? $to.'/'.$self->output_file 
  430.                         : File::Spec->catfile( $to, $self->output_file );
  431.     
  432.     for my $method ( @{ $METHODS->{$self->scheme} } ) {
  433.         my $sub =  '_'.$method.'_fetch';
  434.  
  435.         unless( __PACKAGE__->can($sub) ) {
  436.             $self->_error(loc("Cannot call method for '%1' -- WEIRD!",
  437.                         $method));
  438.             next;
  439.         }
  440.  
  441.         ### method is blacklisted ###
  442.         next if grep { lc $_ eq $method } @$BLACKLIST;
  443.  
  444.         ### method is known to fail ###
  445.         next if $METHOD_FAIL->{$method};
  446.  
  447.         ### there's serious issues with IPC::Run and quoting of command
  448.         ### line arguments. using quotes in the wrong place breaks things,
  449.         ### and in the case of say, 
  450.         ### C:\cygwin\bin\wget.EXE --quiet --passive-ftp --output-document
  451.         ### "index.html" "http://www.cpan.org/index.html?q=1&y=2"
  452.         ### it doesn't matter how you quote, it always fails.
  453.         local $IPC::Cmd::USE_IPC_RUN = 0;
  454.         
  455.         if( my $file = $self->$sub( 
  456.                         to => $out_to
  457.         )){
  458.  
  459.             unless( -e $file && -s _ ) {
  460.                 $self->_error(loc("'%1' said it fetched '%2', ".
  461.                      "but it was not created",$method,$file));
  462.  
  463.                 ### mark the failure ###
  464.                 $METHOD_FAIL->{$method} = 1;
  465.  
  466.                 next;
  467.  
  468.             } else {
  469.  
  470.                 my $abs = File::Spec->rel2abs( $file );
  471.                 return $abs;
  472.             }
  473.         }
  474.     }
  475.  
  476.  
  477.     ### if we got here, we looped over all methods, but we weren't able
  478.     ### to fetch it.
  479.     return;
  480. }
  481.  
  482. ########################
  483. ### _*_fetch methods ###
  484. ########################
  485.  
  486. ### LWP fetching ###
  487. sub _lwp_fetch {
  488.     my $self = shift;
  489.     my %hash = @_;
  490.  
  491.     my ($to);
  492.     my $tmpl = {
  493.         to  => { required => 1, store => \$to }
  494.     };
  495.     check( $tmpl, \%hash ) or return;
  496.  
  497.     ### modules required to download with lwp ###
  498.     my $use_list = {
  499.         LWP                 => '0.0',
  500.         'LWP::UserAgent'    => '0.0',
  501.         'HTTP::Request'     => '0.0',
  502.         'HTTP::Status'      => '0.0',
  503.         URI                 => '0.0',
  504.  
  505.     };
  506.  
  507.     if( can_load(modules => $use_list) ) {
  508.  
  509.         ### setup the uri object
  510.         my $uri = URI->new( File::Spec::Unix->catfile(
  511.                                     $self->path, $self->file
  512.                         ) );
  513.  
  514.         ### special rules apply for file:// uris ###
  515.         $uri->scheme( $self->scheme );
  516.         $uri->host( $self->scheme eq 'file' ? '' : $self->host );
  517.         $uri->userinfo("anonymous:$FROM_EMAIL") if $self->scheme ne 'file';
  518.  
  519.         ### set up the useragent object
  520.         my $ua = LWP::UserAgent->new();
  521.         $ua->timeout( $TIMEOUT ) if $TIMEOUT;
  522.         $ua->agent( $USER_AGENT );
  523.         $ua->from( $FROM_EMAIL );
  524.         $ua->env_proxy;
  525.  
  526.         my $res = $ua->mirror($uri, $to) or return;
  527.  
  528.         ### uptodate or fetched ok ###
  529.         if ( $res->code == 304 or $res->code == 200 ) {
  530.             return $to;
  531.  
  532.         } else {
  533.             return $self->_error(loc("Fetch failed! HTTP response: %1 %2 [%3]",
  534.                         $res->code, HTTP::Status::status_message($res->code),
  535.                         $res->status_line));
  536.         }
  537.  
  538.     } else {
  539.         $METHOD_FAIL->{'lwp'} = 1;
  540.         return;
  541.     }
  542. }
  543.  
  544. ### Net::FTP fetching
  545. sub _netftp_fetch {
  546.     my $self = shift;
  547.     my %hash = @_;
  548.  
  549.     my ($to);
  550.     my $tmpl = {
  551.         to  => { required => 1, store => \$to }
  552.     };
  553.     check( $tmpl, \%hash ) or return;
  554.  
  555.     ### required modules ###
  556.     my $use_list = { 'Net::FTP' => 0 };
  557.  
  558.     if( can_load( modules => $use_list ) ) {
  559.  
  560.         ### make connection ###
  561.         my $ftp;
  562.         my @options = ($self->host);
  563.         push(@options, Timeout => $TIMEOUT) if $TIMEOUT;
  564.         unless( $ftp = Net::FTP->new( @options ) ) {
  565.             return $self->_error(loc("Ftp creation failed: %1",$@));
  566.         }
  567.  
  568.         ### login ###
  569.         unless( $ftp->login( anonymous => $FROM_EMAIL ) ) {
  570.             return $self->_error(loc("Could not login to '%1'",$self->host));
  571.         }
  572.  
  573.         ### set binary mode, just in case ###
  574.         $ftp->binary;
  575.  
  576.         ### create the remote path 
  577.         ### remember remote paths are unix paths! [#11483]
  578.         my $remote = File::Spec::Unix->catfile( $self->path, $self->file );
  579.  
  580.         ### fetch the file ###
  581.         my $target;
  582.         unless( $target = $ftp->get( $remote, $to ) ) {
  583.             return $self->_error(loc("Could not fetch '%1' from '%2'",
  584.                         $remote, $self->host));
  585.         }
  586.  
  587.         ### log out ###
  588.         $ftp->quit;
  589.  
  590.         return $target;
  591.  
  592.     } else {
  593.         $METHOD_FAIL->{'netftp'} = 1;
  594.         return;
  595.     }
  596. }
  597.  
  598. ### /bin/wget fetch ###
  599. sub _wget_fetch {
  600.     my $self = shift;
  601.     my %hash = @_;
  602.  
  603.     my ($to);
  604.     my $tmpl = {
  605.         to  => { required => 1, store => \$to }
  606.     };
  607.     check( $tmpl, \%hash ) or return;
  608.  
  609.     ### see if we have a wget binary ###
  610.     if( my $wget = can_run('wget') ) {
  611.  
  612.         ### no verboseness, thanks ###
  613.         my $cmd = [ $wget, '--quiet' ];
  614.  
  615.         ### if a timeout is set, add it ###
  616.         push(@$cmd, '--timeout=' . $TIMEOUT) if $TIMEOUT;
  617.  
  618.         ### run passive if specified ###
  619.         push @$cmd, '--passive-ftp' if $FTP_PASSIVE;
  620.  
  621.         ### set the output document, add the uri ###
  622.         push @$cmd, '--output-document', 
  623.                     ### DO NOT quote things for IPC::Run, it breaks stuff.
  624.                     $IPC::Cmd::USE_IPC_RUN
  625.                         ? ($to, $self->uri)
  626.                         : (QUOTE. $to .QUOTE, QUOTE. $self->uri .QUOTE);
  627.  
  628.         ### shell out ###
  629.         my $captured;
  630.         unless(run( command => $cmd, 
  631.                     buffer  => \$captured, 
  632.                     verbose => $DEBUG  
  633.         )) {
  634.             ### wget creates the output document always, even if the fetch
  635.             ### fails.. so unlink it in that case
  636.             1 while unlink $to;
  637.             
  638.             return $self->_error(loc( "Command failed: %1", $captured || '' ));
  639.         }
  640.  
  641.         return $to;
  642.  
  643.     } else {
  644.         $METHOD_FAIL->{'wget'} = 1;
  645.         return;
  646.     }
  647. }
  648.  
  649.  
  650. ### /bin/ftp fetch ###
  651. sub _ftp_fetch {
  652.     my $self = shift;
  653.     my %hash = @_;
  654.  
  655.     my ($to);
  656.     my $tmpl = {
  657.         to  => { required => 1, store => \$to }
  658.     };
  659.     check( $tmpl, \%hash ) or return;
  660.  
  661.     ### see if we have a ftp binary ###
  662.     if( my $ftp = can_run('ftp') ) {
  663.  
  664.         my $fh = FileHandle->new;
  665.  
  666.         local $SIG{CHLD} = 'IGNORE';
  667.  
  668.         unless ($fh->open("|$ftp -n")) {
  669.             return $self->_error(loc("%1 creation failed: %2", $ftp, $!));
  670.         }
  671.  
  672.         my @dialog = (
  673.             "lcd " . dirname($to),
  674.             "open " . $self->host,
  675.             "user anonymous $FROM_EMAIL",
  676.             "cd /",
  677.             "cd " . $self->path,
  678.             "binary",
  679.             "get " . $self->file . " " . $self->output_file,
  680.             "quit",
  681.         );
  682.  
  683.         foreach (@dialog) { $fh->print($_, "\n") }
  684.         $fh->close or return;
  685.  
  686.         return $to;
  687.     }
  688. }
  689.  
  690. ### lynx is stupid - it decompresses any .gz file it finds to be text
  691. ### use /bin/lynx to fetch files
  692. sub _lynx_fetch {
  693.     my $self = shift;
  694.     my %hash = @_;
  695.  
  696.     my ($to);
  697.     my $tmpl = {
  698.         to  => { required => 1, store => \$to }
  699.     };
  700.     check( $tmpl, \%hash ) or return;
  701.  
  702.     ### see if we have a lynx binary ###
  703.     if( my $lynx = can_run('lynx') ) {
  704.  
  705.         unless( IPC::Cmd->can_capture_buffer ) {
  706.             $METHOD_FAIL->{'lynx'} = 1;
  707.  
  708.             return $self->_error(loc( 
  709.                 "Can not capture buffers. Can not use '%1' to fetch files",
  710.                 'lynx' ));
  711.         }            
  712.  
  713.         ### write to the output file ourselves, since lynx ass_u_mes to much
  714.         my $local = FileHandle->new(">$to")
  715.                         or return $self->_error(loc(
  716.                             "Could not open '%1' for writing: %2",$to,$!));
  717.  
  718.         ### dump to stdout ###
  719.         my $cmd = [
  720.             $lynx,
  721.             '-source',
  722.             "-auth=anonymous:$FROM_EMAIL",
  723.         ];
  724.  
  725.         push @$cmd, "-connect_timeout=$TIMEOUT" if $TIMEOUT;
  726.  
  727.         ### DO NOT quote things for IPC::Run, it breaks stuff.
  728.         push @$cmd, $IPC::Cmd::USE_IPC_RUN
  729.                         ? $self->uri
  730.                         : QUOTE. $self->uri .QUOTE;
  731.  
  732.  
  733.         ### shell out ###
  734.         my $captured;
  735.         unless(run( command => $cmd,
  736.                     buffer  => \$captured,
  737.                     verbose => $DEBUG )
  738.         ) {
  739.             return $self->_error(loc("Command failed: %1", $captured || ''));
  740.         }
  741.  
  742.         ### print to local file ###
  743.         ### XXX on a 404 with a special error page, $captured will actually
  744.         ### hold the contents of that page, and make it *appear* like the
  745.         ### request was a success, when really it wasn't :(
  746.         ### there doesn't seem to be an option for lynx to change the exit
  747.         ### code based on a 4XX status or so.
  748.         ### the closest we can come is using --error_file and parsing that,
  749.         ### which is very unreliable ;(
  750.         $local->print( $captured );
  751.         $local->close or return;
  752.  
  753.         return $to;
  754.  
  755.     } else {
  756.         $METHOD_FAIL->{'lynx'} = 1;
  757.         return;
  758.     }
  759. }
  760.  
  761. ### use /bin/ncftp to fetch files
  762. sub _ncftp_fetch {
  763.     my $self = shift;
  764.     my %hash = @_;
  765.  
  766.     my ($to);
  767.     my $tmpl = {
  768.         to  => { required => 1, store => \$to }
  769.     };
  770.     check( $tmpl, \%hash ) or return;
  771.  
  772.     ### we can only set passive mode in interactive sesssions, so bail out
  773.     ### if $FTP_PASSIVE is set
  774.     return if $FTP_PASSIVE;
  775.  
  776.     ### see if we have a ncftp binary ###
  777.     if( my $ncftp = can_run('ncftp') ) {
  778.  
  779.         my $cmd = [
  780.             $ncftp,
  781.             '-V',                   # do not be verbose
  782.             '-p', $FROM_EMAIL,      # email as password
  783.             $self->host,            # hostname
  784.             dirname($to),           # local dir for the file
  785.                                     # remote path to the file
  786.             ### DO NOT quote things for IPC::Run, it breaks stuff.
  787.             $IPC::Cmd::USE_IPC_RUN
  788.                         ? File::Spec::Unix->catdir( $self->path, $self->file )
  789.                         : QUOTE. File::Spec::Unix->catdir( 
  790.                                         $self->path, $self->file ) .QUOTE
  791.             
  792.         ];
  793.  
  794.         ### shell out ###
  795.         my $captured;
  796.         unless(run( command => $cmd,
  797.                     buffer  => \$captured,
  798.                     verbose => $DEBUG )
  799.         ) {
  800.             return $self->_error(loc("Command failed: %1", $captured || ''));
  801.         }
  802.  
  803.         return $to;
  804.  
  805.     } else {
  806.         $METHOD_FAIL->{'ncftp'} = 1;
  807.         return;
  808.     }
  809. }
  810.  
  811. ### use /bin/curl to fetch files
  812. sub _curl_fetch {
  813.     my $self = shift;
  814.     my %hash = @_;
  815.  
  816.     my ($to);
  817.     my $tmpl = {
  818.         to  => { required => 1, store => \$to }
  819.     };
  820.     check( $tmpl, \%hash ) or return;
  821.  
  822.     if (my $curl = can_run('curl')) {
  823.  
  824.         ### these long opts are self explanatory - I like that -jmb
  825.         my $cmd = [ $curl ];
  826.  
  827.         push(@$cmd, '--connect-timeout', $TIMEOUT) if $TIMEOUT;
  828.  
  829.         push(@$cmd, '--silent') unless $DEBUG;
  830.  
  831.         ### curl does the right thing with passive, regardless ###
  832.         if ($self->scheme eq 'ftp') {
  833.             push(@$cmd, '--user', "anonymous:$FROM_EMAIL");
  834.         }
  835.  
  836.         ### curl doesn't follow 302 (temporarily moved) etc automatically
  837.         ### so we add --location to enable that.
  838.         push @$cmd, '--fail', '--location', '--output', 
  839.                     ### DO NOT quote things for IPC::Run, it breaks stuff.
  840.                     $IPC::Cmd::USE_IPC_RUN
  841.                         ? ($to, $self->uri)
  842.                         : (QUOTE. $to .QUOTE, QUOTE. $self->uri .QUOTE);
  843.  
  844.         my $captured;
  845.         unless(run( command => $cmd,
  846.                     buffer  => \$captured,
  847.                     verbose => $DEBUG )
  848.         ) {
  849.  
  850.             return $self->_error(loc("Command failed: %1", $captured || ''));
  851.         }
  852.  
  853.         return $to;
  854.  
  855.     } else {
  856.         $METHOD_FAIL->{'curl'} = 1;
  857.         return;
  858.     }
  859. }
  860.  
  861.  
  862. ### use File::Copy for fetching file:// urls ###
  863. ###
  864. ### See section 3.10 of RFC 1738 (http://www.faqs.org/rfcs/rfc1738.html)
  865. ### Also see wikipedia on file:// (http://en.wikipedia.org/wiki/File://)
  866. ###
  867.     
  868. sub _file_fetch {
  869.     my $self = shift;
  870.     my %hash = @_;
  871.  
  872.     my ($to);
  873.     my $tmpl = {
  874.         to  => { required => 1, store => \$to }
  875.     };
  876.     check( $tmpl, \%hash ) or return;
  877.  
  878.     
  879.     
  880.     ### prefix a / on unix systems with a file uri, since it would
  881.     ### look somewhat like this:
  882.     ###     file:///home/kane/file
  883.     ### wheras windows file uris for 'c:\some\dir\file' might look like:
  884.     ###     file:///C:/some/dir/file
  885.     ###     file:///C|/some/dir/file
  886.     ### or for a network share '\\host\share\some\dir\file':
  887.     ###     file:////host/share/some/dir/file
  888.     ###    
  889.     ### VMS file uri's for 'DISK$USER:[MY.NOTES]NOTE123456.TXT' might look like:
  890.     ###     file://vms.host.edu/disk$user/my/notes/note12345.txt
  891.     ###
  892.     
  893.     my $path    = $self->path;
  894.     my $vol     = $self->vol;
  895.     my $share   = $self->share;
  896.  
  897.     my $remote;
  898.     if (!$share and $self->host) {
  899.         return $self->_error(loc( 
  900.             "Currently %1 cannot handle hosts in %2 urls",
  901.             'File::Fetch', 'file://'
  902.         ));            
  903.     }
  904.     
  905.     if( $vol ) {
  906.         $path   = File::Spec->catdir( split /\//, $path );
  907.         $remote = File::Spec->catpath( $vol, $path, $self->file);
  908.  
  909.     } elsif( $share ) {
  910.         ### win32 specific, and a share name, so we wont bother with File::Spec
  911.         $path   =~ s|/+|\\|g;
  912.         $remote = "\\\\".$self->host."\\$share\\$path";
  913.  
  914.     } else {
  915.         ### File::Spec on VMS can not currently handle UNIX syntax.
  916.         my $file_class = ON_VMS
  917.             ? 'File::Spec::Unix'
  918.             : 'File::Spec';
  919.  
  920.         $remote  = $file_class->catfile( $path, $self->file );
  921.     }
  922.  
  923.     ### File::Copy is littered with 'die' statements :( ###
  924.     my $rv = eval { File::Copy::copy( $remote, $to ) };
  925.  
  926.     ### something went wrong ###
  927.     if( !$rv or $@ ) {
  928.         return $self->_error(loc("Could not copy '%1' to '%2': %3 %4",
  929.                              $remote, $to, $!, $@));
  930.     }
  931.  
  932.     return $to;
  933. }
  934.  
  935. ### use /usr/bin/rsync to fetch files
  936. sub _rsync_fetch {
  937.     my $self = shift;
  938.     my %hash = @_;
  939.  
  940.     my ($to);
  941.     my $tmpl = {
  942.         to  => { required => 1, store => \$to }
  943.     };
  944.     check( $tmpl, \%hash ) or return;
  945.  
  946.     if (my $rsync = can_run('rsync')) {
  947.  
  948.         my $cmd = [ $rsync ];
  949.  
  950.         ### XXX: rsync has no I/O timeouts at all, by default
  951.         push(@$cmd, '--timeout=' . $TIMEOUT) if $TIMEOUT;
  952.  
  953.         push(@$cmd, '--quiet') unless $DEBUG;
  954.  
  955.         ### DO NOT quote things for IPC::Run, it breaks stuff.
  956.         push @$cmd, $IPC::Cmd::USE_IPC_RUN
  957.                         ? ($self->uri, $to)
  958.                         : (QUOTE. $self->uri .QUOTE, QUOTE. $to .QUOTE);
  959.  
  960.         my $captured;
  961.         unless(run( command => $cmd,
  962.                     buffer  => \$captured,
  963.                     verbose => $DEBUG )
  964.         ) {
  965.  
  966.             return $self->_error(loc("Command %1 failed: %2", 
  967.                 "@$cmd" || '', $captured || ''));
  968.         }
  969.  
  970.         return $to;
  971.  
  972.     } else {
  973.         $METHOD_FAIL->{'rsync'} = 1;
  974.         return;
  975.     }
  976. }
  977.  
  978. #################################
  979. #
  980. # Error code
  981. #
  982. #################################
  983.  
  984. =pod
  985.  
  986. =head2 $ff->error([BOOL])
  987.  
  988. Returns the last encountered error as string.
  989. Pass it a true value to get the C<Carp::longmess()> output instead.
  990.  
  991. =cut
  992.  
  993. ### error handling the way Archive::Extract does it
  994. sub _error {
  995.     my $self    = shift;
  996.     my $error   = shift;
  997.     
  998.     $self->_error_msg( $error );
  999.     $self->_error_msg_long( Carp::longmess($error) );
  1000.     
  1001.     if( $WARN ) {
  1002.         carp $DEBUG ? $self->_error_msg_long : $self->_error_msg;
  1003.     }
  1004.  
  1005.     return;
  1006. }
  1007.  
  1008. sub error {
  1009.     my $self = shift;
  1010.     return shift() ? $self->_error_msg_long : $self->_error_msg;
  1011. }
  1012.  
  1013.  
  1014. 1;
  1015.  
  1016. =pod
  1017.  
  1018. =head1 HOW IT WORKS
  1019.  
  1020. File::Fetch is able to fetch a variety of uris, by using several
  1021. external programs and modules.
  1022.  
  1023. Below is a mapping of what utilities will be used in what order
  1024. for what schemes, if available:
  1025.  
  1026.     file    => LWP, file
  1027.     http    => LWP, wget, curl, lynx
  1028.     ftp     => LWP, Net::FTP, wget, curl, ncftp, ftp
  1029.     rsync   => rsync
  1030.  
  1031. If you'd like to disable the use of one or more of these utilities
  1032. and/or modules, see the C<$BLACKLIST> variable further down.
  1033.  
  1034. If a utility or module isn't available, it will be marked in a cache
  1035. (see the C<$METHOD_FAIL> variable further down), so it will not be
  1036. tried again. The C<fetch> method will only fail when all options are
  1037. exhausted, and it was not able to retrieve the file.
  1038.  
  1039. A special note about fetching files from an ftp uri:
  1040.  
  1041. By default, all ftp connections are done in passive mode. To change
  1042. that, see the C<$FTP_PASSIVE> variable further down.
  1043.  
  1044. Furthermore, ftp uris only support anonymous connections, so no
  1045. named user/password pair can be passed along.
  1046.  
  1047. C</bin/ftp> is blacklisted by default; see the C<$BLACKLIST> variable
  1048. further down.
  1049.  
  1050. =head1 GLOBAL VARIABLES
  1051.  
  1052. The behaviour of File::Fetch can be altered by changing the following
  1053. global variables:
  1054.  
  1055. =head2 $File::Fetch::FROM_EMAIL
  1056.  
  1057. This is the email address that will be sent as your anonymous ftp
  1058. password.
  1059.  
  1060. Default is C<File-Fetch@example.com>.
  1061.  
  1062. =head2 $File::Fetch::USER_AGENT
  1063.  
  1064. This is the useragent as C<LWP> will report it.
  1065.  
  1066. Default is C<File::Fetch/$VERSION>.
  1067.  
  1068. =head2 $File::Fetch::FTP_PASSIVE
  1069.  
  1070. This variable controls whether the environment variable C<FTP_PASSIVE>
  1071. and any passive switches to commandline tools will be set to true.
  1072.  
  1073. Default value is 1.
  1074.  
  1075. Note: When $FTP_PASSIVE is true, C<ncftp> will not be used to fetch
  1076. files, since passive mode can only be set interactively for this binary
  1077.  
  1078. =head2 $File::Fetch::TIMEOUT
  1079.  
  1080. When set, controls the network timeout (counted in seconds).
  1081.  
  1082. Default value is 0.
  1083.  
  1084. =head2 $File::Fetch::WARN
  1085.  
  1086. This variable controls whether errors encountered internally by
  1087. C<File::Fetch> should be C<carp>'d or not.
  1088.  
  1089. Set to false to silence warnings. Inspect the output of the C<error()>
  1090. method manually to see what went wrong.
  1091.  
  1092. Defaults to C<true>.
  1093.  
  1094. =head2 $File::Fetch::DEBUG
  1095.  
  1096. This enables debugging output when calling commandline utilities to
  1097. fetch files.
  1098. This also enables C<Carp::longmess> errors, instead of the regular
  1099. C<carp> errors.
  1100.  
  1101. Good for tracking down why things don't work with your particular
  1102. setup.
  1103.  
  1104. Default is 0.
  1105.  
  1106. =head2 $File::Fetch::BLACKLIST
  1107.  
  1108. This is an array ref holding blacklisted modules/utilities for fetching
  1109. files with.
  1110.  
  1111. To disallow the use of, for example, C<LWP> and C<Net::FTP>, you could
  1112. set $File::Fetch::BLACKLIST to:
  1113.  
  1114.     $File::Fetch::BLACKLIST = [qw|lwp netftp|]
  1115.  
  1116. The default blacklist is [qw|ftp|], as C</bin/ftp> is rather unreliable.
  1117.  
  1118. See the note on C<MAPPING> below.
  1119.  
  1120. =head2 $File::Fetch::METHOD_FAIL
  1121.  
  1122. This is a hashref registering what modules/utilities were known to fail
  1123. for fetching files (mostly because they weren't installed).
  1124.  
  1125. You can reset this cache by assigning an empty hashref to it, or
  1126. individually remove keys.
  1127.  
  1128. See the note on C<MAPPING> below.
  1129.  
  1130. =head1 MAPPING
  1131.  
  1132.  
  1133. Here's a quick mapping for the utilities/modules, and their names for
  1134. the $BLACKLIST, $METHOD_FAIL and other internal functions.
  1135.  
  1136.     LWP         => lwp
  1137.     Net::FTP    => netftp
  1138.     wget        => wget
  1139.     lynx        => lynx
  1140.     ncftp       => ncftp
  1141.     ftp         => ftp
  1142.     curl        => curl
  1143.     rsync       => rsync
  1144.  
  1145. =head1 FREQUENTLY ASKED QUESTIONS
  1146.  
  1147. =head2 So how do I use a proxy with File::Fetch?
  1148.  
  1149. C<File::Fetch> currently only supports proxies with LWP::UserAgent.
  1150. You will need to set your environment variables accordingly. For
  1151. example, to use an ftp proxy:
  1152.  
  1153.     $ENV{ftp_proxy} = 'foo.com';
  1154.  
  1155. Refer to the LWP::UserAgent manpage for more details.
  1156.  
  1157. =head2 I used 'lynx' to fetch a file, but its contents is all wrong!
  1158.  
  1159. C<lynx> can only fetch remote files by dumping its contents to C<STDOUT>,
  1160. which we in turn capture. If that content is a 'custom' error file
  1161. (like, say, a C<404 handler>), you will get that contents instead.
  1162.  
  1163. Sadly, C<lynx> doesn't support any options to return a different exit
  1164. code on non-C<200 OK> status, giving us no way to tell the difference
  1165. between a 'successfull' fetch and a custom error page.
  1166.  
  1167. Therefor, we recommend to only use C<lynx> as a last resort. This is 
  1168. why it is at the back of our list of methods to try as well.
  1169.  
  1170. =head2 Files I'm trying to fetch have reserved characters or non-ASCII characters in them. What do I do?
  1171.  
  1172. C<File::Fetch> is relatively smart about things. When trying to write 
  1173. a file to disk, it removes the C<query parameters> (see the 
  1174. C<output_file> method for details) from the file name before creating
  1175. it. In most cases this suffices.
  1176.  
  1177. If you have any other characters you need to escape, please install 
  1178. the C<URI::Escape> module from CPAN, and pre-encode your URI before
  1179. passing it to C<File::Fetch>. You can read about the details of URIs 
  1180. and URI encoding here:
  1181.  
  1182.   http://www.faqs.org/rfcs/rfc2396.html
  1183.  
  1184. =head1 TODO
  1185.  
  1186. =over 4
  1187.  
  1188. =item Implement $PREFER_BIN
  1189.  
  1190. To indicate to rather use commandline tools than modules
  1191.  
  1192. =back
  1193.  
  1194. =head1 BUG REPORTS
  1195.  
  1196. Please report bugs or other issues to E<lt>bug-file-fetch@rt.cpan.org<gt>.
  1197.  
  1198. =head1 AUTHOR
  1199.  
  1200. This module by Jos Boumans E<lt>kane@cpan.orgE<gt>.
  1201.  
  1202. =head1 COPYRIGHT
  1203.  
  1204. This library is free software; you may redistribute and/or modify it 
  1205. under the same terms as Perl itself.
  1206.  
  1207.  
  1208. =cut
  1209.  
  1210. # Local variables:
  1211. # c-indentation-style: bsd
  1212. # c-basic-offset: 4
  1213. # indent-tabs-mode: nil
  1214. # End:
  1215. # vim: expandtab shiftwidth=4:
  1216.  
  1217.  
  1218.  
  1219.  
  1220.