Add ARM files
[dh-make-perl] / dev / arm / libwww-perl / libwww-perl-5.813 / bin / lwp-download
1 #!/usr/bin/perl -w
2
3 =head1 NAME
4
5 lwp-download - Fetch large files from the web
6
7 =head1 SYNOPSIS
8
9 B<lwp-download> [B<-a>] <I<url>> [<I<local path>>]
10
11 =head1 DESCRIPTION
12
13 The B<lwp-download> program will save the file at I<url> to a local
14 file.
15
16 If I<local path> is not specified, then the current directory is
17 assumed.
18
19 If I<local path> is a directory, then the basename of the file to save
20 is picked up from the Content-Disposition header or the URL of the
21 response.  If the file already exists, then B<lwp-download> will
22 prompt before it overwrites and will fail if its standard input is not
23 a terminal.  This form of invocation will also fail is no acceptable
24 filename can be derived from the sources mentioned above.
25
26 If I<local path> is not a directory, then it is simply used as the
27 path to save into.
28
29 The I<lwp-download> program is implemented using the I<libwww-perl>
30 library.  It is better suited to down load big files than the
31 I<lwp-request> program because it does not store the file in memory.
32 Another benefit is that it will keep you updated about its progress
33 and that you don't have much options to worry about.
34
35 Use the C<-a> option to save the file in text (ascii) mode.  Might
36 make a difference on dosish systems.
37
38 =head1 EXAMPLE
39
40 Fetch the newest and greatest perl version:
41
42  $ lwp-download http://www.perl.com/CPAN/src/latest.tar.gz
43  Saving to 'latest.tar.gz'...
44  11.4 MB received in 8 seconds (1.43 MB/sec)
45
46 =head1 AUTHOR
47
48 Gisle Aas <gisle@aas.no>
49
50 =cut
51
52 #' get emacs out of quote mode
53
54 use strict;
55
56 use LWP::UserAgent ();
57 use LWP::MediaTypes qw(guess_media_type media_suffix);
58 use URI ();
59 use HTTP::Date ();
60
61 my $progname = $0;
62 $progname =~ s,.*/,,;    # only basename left in progname
63 $progname =~ s,.*\\,, if $^O eq "MSWin32";
64 $progname =~ s/\.\w*$//; # strip extension if any
65
66 #parse option
67 use Getopt::Std;
68 my %opt;
69 unless (getopts('a', \%opt)) {
70     usage();
71 }
72
73 my $url = URI->new(shift || usage());
74 my $argfile = shift;
75 usage() if defined($argfile) && !length($argfile);
76 my $VERSION = "5.813";
77
78 my $ua = LWP::UserAgent->new(
79    agent => "lwp-download/$VERSION ",
80    keep_alive => 1,
81    env_proxy => 1,
82 );
83
84 my $file;      # name of file we download into
85 my $length;    # total number of bytes to download
86 my $flength;   # formatted length
87 my $size = 0;  # number of bytes received
88 my $start_t;   # start time of download
89 my $last_dur;  # time of last callback
90
91 my $shown = 0; # have we called the show() function yet
92
93 $SIG{INT} = sub { die "Interrupted\n"; };
94
95 $| = 1;  # autoflush
96
97 my $res = $ua->request(HTTP::Request->new(GET => $url),
98   sub {
99       unless(defined $file) {
100           my $res = $_[1];
101
102           my $directory;
103           if (defined $argfile && -d $argfile) {
104               ($directory, $argfile) = ($argfile, undef);
105           }
106
107           unless (defined $argfile) {
108               # find a suitable name to use
109               $file = $res->filename;
110
111               # if this fails we try to make something from the URL
112               unless ($file) {
113                   my $req = $res->request;  # not always there
114                   my $rurl = $req ? $req->url : $url;
115
116                   $file = ($rurl->path_segments)[-1];
117                   if (!defined($file) || !length($file)) {
118                       $file = "index";
119                       my $suffix = media_suffix($res->content_type);
120                       $file .= ".$suffix" if $suffix;
121                   }
122                   elsif ($rurl->scheme eq 'ftp' ||
123                            $file =~ /\.t[bg]z$/   ||
124                            $file =~ /\.tar(\.(Z|gz|bz2?))?$/
125                           ) {
126                       # leave the filename as it was
127                   }
128                   else {
129                       my $ct = guess_media_type($file);
130                       unless ($ct eq $res->content_type) {
131                           # need a better suffix for this type
132                           my $suffix = media_suffix($res->content_type);
133                           $file .= ".$suffix" if $suffix;
134                       }
135                   }
136               }
137
138               # validate that we don't have a harmful filename now.  The server
139               # might try to trick us into doing something bad.
140               if (!length($file) ||
141                   $file =~ s/([^a-zA-Z0-9_\.\-\+\~])/sprintf "\\x%02x", ord($1)/ge)
142               {
143                   die "Will not save <$url> as \"$file\".\nPlease override file name on the command line.\n";
144               }
145
146               if (defined $directory) {
147                   require File::Spec;
148                   $file = File::Spec->catfile($directory, $file);
149               }
150
151               # Check if the file is already present
152               if (-l $file) {
153                   die "Will not save <$url> to link \"$file\".\nPlease override file name on the command line.\n";
154               }
155               elsif (-f _) {
156                   die "Will not save <$url> as \"$file\" without verification.\nEither run from terminal or override file name on the command line.\n"
157                       unless -t;
158                   $shown = 1;
159                   print "Overwrite $file? [y] ";
160                   my $ans = <STDIN>;
161                   unless (defined($ans) && $ans =~ /^y?\n/) {
162                       if (defined $ans) {
163                           print "Ok, aborting.\n";
164                       }
165                       else {
166                           print "\nAborting.\n";
167                       }
168                       exit 1;
169                   }
170                   $shown = 0;
171               }
172               elsif (-e _) {
173                   die "Will not save <$url> as \"$file\".  Path exists.\n";
174               }
175               else {
176                   print "Saving to '$file'...\n";
177               }
178           }
179           else {
180               $file = $argfile;
181           }
182           open(FILE, ">$file") || die "Can't open $file: $!\n";
183           binmode FILE unless $opt{a};
184           $length = $res->content_length;
185           $flength = fbytes($length) if defined $length;
186           $start_t = time;
187           $last_dur = 0;
188       }
189
190       print FILE $_[0] or die "Can't write to $file: $!\n";
191       $size += length($_[0]);
192
193       if (defined $length) {
194           my $dur  = time - $start_t;
195           if ($dur != $last_dur) {  # don't update too often
196               $last_dur = $dur;
197               my $perc = $size / $length;
198               my $speed;
199               $speed = fbytes($size/$dur) . "/sec" if $dur > 3;
200               my $secs_left = fduration($dur/$perc - $dur);
201               $perc = int($perc*100);
202               my $show = "$perc% of $flength";
203               $show .= " (at $speed, $secs_left remaining)" if $speed;
204               show($show, 1);
205           }
206       }
207       else {
208           show( fbytes($size) . " received");
209       }
210   }
211 );
212
213 if (fileno(FILE)) {
214     close(FILE) || die "Can't write to $file: $!\n";
215
216     show("");  # clear text
217     print "\r";
218     print fbytes($size);
219     print " of ", fbytes($length) if defined($length) && $length != $size;
220     print " received";
221     my $dur = time - $start_t;
222     if ($dur) {
223         my $speed = fbytes($size/$dur) . "/sec";
224         print " in ", fduration($dur), " ($speed)";
225     }
226     print "\n";
227
228     if (my $mtime = $res->last_modified) {
229         utime time, $mtime, $file;
230     }
231
232     if ($res->header("X-Died") || !$res->is_success) {
233         if (my $died = $res->header("X-Died")) {
234             print "$died\n";
235         }
236         if (-t) {
237             print "Transfer aborted.  Delete $file? [n] ";
238             my $ans = <STDIN>;
239             if (defined($ans) && $ans =~ /^y\n/) {
240                 unlink($file) && print "Deleted.\n";
241             }
242             elsif ($length > $size) {
243                 print "Truncated file kept: ", fbytes($length - $size), " missing\n";
244             }
245             else {
246                 print "File kept.\n";
247             }
248             exit 1;
249         }
250         else {
251             print "Transfer aborted, $file kept\n";
252         }
253     }
254     exit 0;
255 }
256
257 # Did not manage to create any file
258 print "\n" if $shown;
259 if (my $xdied = $res->header("X-Died")) {
260     print "$progname: Aborted\n$xdied\n";
261 }
262 else {
263     print "$progname: ", $res->status_line, "\n";
264 }
265 exit 1;
266
267
268 sub fbytes
269 {
270     my $n = int(shift);
271     if ($n >= 1024 * 1024) {
272         return sprintf "%.3g MB", $n / (1024.0 * 1024);
273     }
274     elsif ($n >= 1024) {
275         return sprintf "%.3g KB", $n / 1024.0;
276     }
277     else {
278         return "$n bytes";
279     }
280 }
281
282 sub fduration
283 {
284     use integer;
285     my $secs = int(shift);
286     my $hours = $secs / (60*60);
287     $secs -= $hours * 60*60;
288     my $mins = $secs / 60;
289     $secs %= 60;
290     if ($hours) {
291         return "$hours hours $mins minutes";
292     }
293     elsif ($mins >= 2) {
294         return "$mins minutes";
295     }
296     else {
297         $secs += $mins * 60;
298         return "$secs seconds";
299     }
300 }
301
302
303 BEGIN {
304     my @ani = qw(- \ | /);
305     my $ani = 0;
306
307     sub show
308     {
309         my($mess, $show_ani) = @_;
310         print "\r$mess" . (" " x (75 - length $mess));
311         print $show_ani ? "$ani[$ani++]\b" : " ";
312         $ani %= @ani;
313         $shown++;
314     }
315 }
316
317 sub usage
318 {
319     die "Usage: $progname [-a] <url> [<lpath>]\n";
320 }