├── de.po ├── gui └── kapt │ ├── axel-kapt.desktop │ ├── Makefile │ ├── axel-kapt.1 │ └── axel-kapt ├── tcp.h ├── search.h ├── CREDITS ├── ftp.h ├── conf.h ├── http.h ├── conn.h ├── README.md ├── Makefile ├── axel_zh_CN.1 ├── tcp.c ├── axel.h ├── axelrc.example ├── ROADMAP ├── axel.1 ├── conf.c ├── http.c ├── configure ├── search.c ├── zh_CN.po ├── nl.po ├── ru.po ├── ftp.c ├── API ├── conn.c ├── CHANGES ├── text.c ├── COPYING └── axel.c /de.po: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angelj-a/axel/HEAD/de.po -------------------------------------------------------------------------------- /gui/kapt/axel-kapt.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Name=Axel 4 | GenericName=Axel Front-end 5 | Comment=Front-end for Axel - a light download accelerator 6 | Type=Application 7 | Exec=axel-kapt %f 8 | MimeType=text/html; 9 | Icon=connect_creating 10 | Terminal=false 11 | X-KDE-SubstituteUID=false 12 | Categories=Network;FileTransfer;KDE; 13 | -------------------------------------------------------------------------------- /gui/kapt/Makefile: -------------------------------------------------------------------------------- 1 | include ../../Makefile.settings 2 | 3 | all: 4 | 5 | install: 6 | mkdir -p $(DESTDIR)$(BINDIR) 7 | install -m 0755 axel-kapt $(DESTDIR)$(BINDIR) 8 | mkdir -p $(DESTDIR)$(MANDIR)/man1/ 9 | install -m 0644 axel-kapt.1 $(DESTDIR)$(MANDIR)/man1/ 10 | mkdir -p $(DESTDIR)$(SHAREDIR)/applications/ 11 | install -m 0644 axel-kapt.desktop $(DESTDIR)$(SHAREDIR)/applications/ 12 | -------------------------------------------------------------------------------- /gui/kapt/axel-kapt.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\"man-page for axel-kapt 3 | .\" 4 | .\"Derived from axel, which is derived from the man-page example in the 5 | .\"wonderful book called Beginning "Linux Programming", written by Richard 6 | .\"Stone and Neil Matthew. 7 | .\" 8 | .TH AXEL-KAPT 1 9 | 10 | .SH NAME 11 | \fBaxel\-kapt\fP \- Axel front\-end 12 | 13 | .SH SYNOPSIS 14 | .B axel\-kapt 15 | \fIurl1\fP [\fIurl2\fP] [\fIurl...\fP] 16 | 17 | .SH DESCRIPTION 18 | Axel is a program that downloads a file from a FTP or HTTP server through 19 | multiple connection, each connection downloads its own part of the file. 20 | This program is a KDE front\-end to Axel. 21 | 22 | .SH CONFIGURATION 23 | The program is a Python script which generates a Kaptain grammar on the fly. 24 | 25 | .SH "SEE ALSO" 26 | axel(1) 27 | 28 | .SH COPYRIGHT 29 | Axel\-kapt is Copyright 2001 Paul Evans. 30 | 31 | Axel is Copyright 2001 Wilmer van der Gaast. 32 | 33 | .SH AUTHORS 34 | Paul Evans (pevans@catholic.org) 35 | -------------------------------------------------------------------------------- /tcp.h: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* TCP control include file */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | int tcp_connect( char *hostname, int port, char *local_if ); 27 | int get_if_ip( char *iface, char *ip ); 28 | -------------------------------------------------------------------------------- /search.h: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* filesearching.com searcher include file */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | typedef struct 27 | { 28 | char url[MAX_STRING]; 29 | double speed_start_time; 30 | int speed, size; 31 | pthread_t speed_thread[1]; 32 | conf_t *conf; 33 | } search_t; 34 | 35 | int search_makelist( search_t *results, char *url ); 36 | int search_getspeeds( search_t *results, int count ); 37 | void search_sortlist( search_t *results, int count ); 38 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | An not-quite-sorted list of people who helped somehow: 2 | 3 | - Philipp Hagemeister 4 | Bug triage and patches to fix bugs 5 | 6 | - bbbush 7 | RPM spec file 8 | 9 | - newhren 10 | Russian translation 11 | 12 | - Eli Yukelzon 13 | Custom Header Support 14 | 15 | - David Turnbull 16 | Large file support 17 | 18 | - Hermann J. Beckers 19 | German translation. 20 | 21 | - Martin Herrman 22 | Requested the human-readable time/size values. 23 | Advertising in the Dutch Linux User's Manual. (http://2mypage.cjb.net/) 24 | 25 | - Marten Klencke 26 | Early tester. 27 | 28 | - Danny Oude Bos 29 | For having an iMac with a very badly-behaving FTP server... 30 | 31 | - Ralph Slooten 32 | For creating the initial native RPM packages instead of my alienated 33 | .debs. 34 | 35 | - Robert 36 | For patching the program to make it work on FreeBSD and Darwin. 37 | For finding some very stupid bugs. 38 | 39 | - Sjoerd Hemminga 40 | For adding the finish_time feature. It's not yet in the user interface, 41 | though... 42 | For writing axelq. 43 | 44 | - Paul Evans 45 | For being a very good beta tester. 46 | For creating axel-kapt. 47 | 48 | - Justin A 49 | For some testing and for the new (multi-URL) syntax idea. 50 | 51 | - Sebastian Ritterbusch 52 | For some interesting ideas for the new versions. 53 | For writing the alternate progress indicator. 54 | -------------------------------------------------------------------------------- /ftp.h: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* FTP control include file */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #define FTP_PASSIVE 1 27 | #define FTP_PORT 2 28 | 29 | typedef struct 30 | { 31 | char cwd[MAX_STRING]; 32 | char *message; 33 | int status; 34 | int fd; 35 | int data_fd; 36 | int ftp_mode; 37 | char *local_if; 38 | } ftp_t; 39 | 40 | int ftp_connect( ftp_t *conn, char *host, int port, char *user, char *pass ); 41 | void ftp_disconnect( ftp_t *conn ); 42 | int ftp_wait( ftp_t *conn ); 43 | int ftp_command( ftp_t *conn, char *format, ... ); 44 | int ftp_cwd( ftp_t *conn, char *cwd ); 45 | int ftp_data( ftp_t *conn ); 46 | long long int ftp_size( ftp_t *conn, char *file, int maxredir ); 47 | -------------------------------------------------------------------------------- /conf.h: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* Configuration handling include file */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | typedef struct 27 | { 28 | char default_filename[MAX_STRING]; 29 | char http_proxy[MAX_STRING]; 30 | char no_proxy[MAX_STRING]; 31 | int strip_cgi_parameters; 32 | int save_state_interval; 33 | int connection_timeout; 34 | int reconnect_delay; 35 | int num_connections; 36 | int buffer_size; 37 | int max_speed; 38 | int verbose; 39 | int alternate_output; 40 | 41 | if_t *interfaces; 42 | 43 | int search_timeout; 44 | int search_threads; 45 | int search_amount; 46 | int search_top; 47 | 48 | int add_header_count; 49 | char add_header[MAX_ADD_HEADERS][MAX_STRING]; 50 | 51 | char user_agent[MAX_STRING]; 52 | } conf_t; 53 | 54 | int conf_loadfile( conf_t *conf, char *file ); 55 | int conf_init( conf_t *conf ); 56 | -------------------------------------------------------------------------------- /http.h: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* HTTP control include file */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #define MAX_QUERY 2048 /* Should not grow larger.. */ 27 | 28 | typedef struct 29 | { 30 | char host[MAX_STRING]; 31 | char auth[MAX_STRING]; 32 | char request[MAX_QUERY]; 33 | char headers[MAX_QUERY]; 34 | int proto; /* FTP through HTTP proxies */ 35 | int proxy; 36 | long long int firstbyte; 37 | long long int lastbyte; 38 | int status; 39 | int fd; 40 | char *local_if; 41 | } http_t; 42 | 43 | int http_connect( http_t *conn, int proto, char *proxy, char *host, int port, char *user, char *pass ); 44 | void http_disconnect( http_t *conn ); 45 | void http_get( http_t *conn, char *lurl ); 46 | void http_addheader( http_t *conn, char *format, ... ); 47 | int http_exec( http_t *conn ); 48 | char *http_header( http_t *conn, char *header ); 49 | long long int http_size( http_t *conn ); 50 | void http_encode( char *s ); 51 | void http_decode( char *s ); 52 | -------------------------------------------------------------------------------- /conn.h: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* Connection stuff */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #define PROTO_FTP 1 27 | #define PROTO_HTTP 2 28 | #define PROTO_DEFAULT PROTO_FTP 29 | 30 | typedef struct 31 | { 32 | conf_t *conf; 33 | 34 | int proto; 35 | int port; 36 | int proxy; 37 | char host[MAX_STRING]; 38 | char dir[MAX_STRING]; 39 | char file[MAX_STRING]; 40 | char user[MAX_STRING]; 41 | char pass[MAX_STRING]; 42 | 43 | ftp_t ftp[1]; 44 | http_t http[1]; 45 | long long int size; /* File size, not 'connection size'.. */ 46 | long long int currentbyte; 47 | long long int lastbyte; 48 | int fd; 49 | int enabled; 50 | int supported; 51 | int last_transfer; 52 | char *message; 53 | char *local_if; 54 | 55 | int state; 56 | pthread_t setup_thread[1]; 57 | } conn_t; 58 | 59 | int conn_set( conn_t *conn, char *set_url ); 60 | char *conn_url( conn_t *conn ); 61 | void conn_disconnect( conn_t *conn ); 62 | int conn_init( conn_t *conn ); 63 | int conn_setup( conn_t *conn ); 64 | int conn_exec( conn_t *conn ); 65 | int conn_info( conn_t *conn ); 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Axel Home: 2 | 3 | See [http://axel.alioth.debian.org/](http://axel.alioth.debian.org/) for latest information on axel 4 | 5 | 6 | Supported architectures 7 | ----------------------- 8 | 9 | 10 | Should compile on any decent Linux system. Additionaly, it should compile 11 | (and run) on BSD, Solaris, Darwin (Mac OS X) and Win32 (Cygwin) systems. 12 | 13 | If the configure script does weird things on your system, please do warn me! 14 | I test it on as many machines and OS'es as possible, but still anything can 15 | go wrong. 16 | 17 | 18 | 19 | How to install/use 20 | ------------------ 21 | 22 | 23 | Run the configure script (you can supply some options if you want, try 24 | `./configure --help` for more info) and then run `make`. The program should 25 | compile then. There are no special requirements for Axel. You can install 26 | the program using `make install` or you can just run it from the current 27 | directory. You can copy the `axelrc.example` file to `~/.axelrc` then, if you 28 | want to change some of the settings. 29 | 30 | 31 | Run the program like this: 32 | 33 | ``` 34 | axel ftp://ftp.nl.kernel.org/pub/linux/kernel/v2.2/linux-2.2.20.tar.bz2 35 | ``` 36 | 37 | 38 | For a simple single-server-multiple-connection download, or: 39 | 40 | ``` 41 | axel ftp://ftp.{nl,be,de}.kernel.org/pub/linux/kernel/v2.2/linux-2.2.20.tar.bz2 42 | ``` 43 | 44 | If you want to use those three servers for the download. The program can do 45 | an automatic search for FTP mirrors as well (filesearching.com), but that's 46 | not yet perfect... Just try the `-S` option. (The line above should at least 47 | work with the Bash shell. You can type all the mirrors by hand as well, if 48 | you really want to, and/or of necessary...) 49 | 50 | 51 | Just one other thing you should keep in mind when using this program: Some 52 | FTP operators don't like people who use download accelerators. To quote an 53 | administrator at Progeny.Com in a mail to me: 54 | 55 | > Additionally, I should mention that accelerated downloads are 56 | > discouraged as I consider them abusive. 57 | 58 | And he certainly has a point.. Using more than one server at once is a fine 59 | solution IMHO, so please use this feature if possible! 60 | 61 | Wilmer van der Gaast. 62 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ########################### 2 | ## Makefile for Axel ## 3 | ## ## 4 | ## Copyright 2001 Lintux ## 5 | ########################### 6 | 7 | ### DEFINITIONS 8 | 9 | -include Makefile.settings 10 | 11 | .SUFFIXES: .po .mo 12 | 13 | # Add your translation here.. 14 | MOFILES = nl.mo de.mo ru.mo zh_CN.mo 15 | 16 | 17 | all: $(OUTFILE) 18 | install: install-bin install-etc install-man 19 | uninstall: uninstall-bin uninstall-etc uninstall-man 20 | 21 | clean: 22 | rm -f *.o $(OUTFILE) search core *.mo 23 | 24 | distclean: clean 25 | rm -f Makefile.settings config.h axel-*.tar axel-*.tar.gz axel-*.tar.bz2 26 | 27 | install-man: 28 | mkdir -p $(DESTDIR)$(MANDIR)/man1/ 29 | cp axel.1 $(DESTDIR)$(MANDIR)/man1/axel.1 30 | mkdir -p $(DESTDIR)$(MANDIR)/zh_CN/man1/ 31 | cp axel_zh_CN.1 $(DESTDIR)$(MANDIR)/zh_CN/man1/axel.1 32 | 33 | uninstall-man: 34 | rm -f $(MANDIR)/man1/axel.1 35 | rm -f $(MANDIR)/zh_CN/man1/axel.1 36 | 37 | install-etc: 38 | mkdir -p $(DESTDIR)$(ETCDIR)/ 39 | cp axelrc.example $(DESTDIR)$(ETCDIR)/axelrc 40 | 41 | uninstall-etc: 42 | rm -f $(ETCDIR)/axelrc 43 | 44 | ### MAIN PROGRAM 45 | 46 | $(OUTFILE): axel.o conf.o conn.o ftp.o http.o search.o tcp.o text.o 47 | $(CC) *.o -o $(OUTFILE) $(LFLAGS) 48 | $(STRIP) $(OUTFILE) 49 | 50 | .c.o: 51 | $(CC) -c $*.c -o $*.o $(CFLAGS) 52 | 53 | install-bin: 54 | mkdir -p $(DESTDIR)$(BINDIR)/ 55 | cp $(OUTFILE) $(DESTDIR)$(BINDIR)/$(OUTFILE) 56 | 57 | uninstall-bin: 58 | rm -f $(BINDIR)/$(OUTFILE) 59 | 60 | tar: 61 | version=`sed -n 's/#define AXEL_VERSION_STRING[ \t]*"\([^"]*\)"/\1/p' < axel.h` && \ 62 | tar --create --numeric-owner --owner 0 --group 0 --transform "s#^#axel-$${version}/#" "--file=axel-$${version}.tar" --exclude-vcs -- *.c *.h *.po *.1 configure Makefile axelrc.example gui API CHANGES COPYING CREDITS README && \ 63 | gzip --best < "axel-$${version}.tar" > "axel-$${version}.tar.gz" && \ 64 | bzip2 --best < "axel-$${version}.tar" > "axel-$${version}.tar.bz2" 65 | 66 | 67 | ### I18N FILES 68 | 69 | %.po: 70 | -@mv $@ $@.bak 71 | xgettext -k_ -o$@ *.[ch] 72 | @if [ -e $@.bak ]; then \ 73 | echo -n Merging files...; \ 74 | msgmerge -vo $@.combo $@.bak $@; \ 75 | rm -f $@ $@.bak; \ 76 | mv $@.combo $@; \ 77 | fi 78 | 79 | .po.mo: $@.po 80 | msgfmt -vo $@ $*.po 81 | 82 | i18n-mofiles: $(MOFILES) 83 | 84 | install-i18n: 85 | @echo Installing locale files... 86 | @for i in $(MOFILES); do \ 87 | mkdir -p $(DESTDIR)$(LOCALE)/`echo $$i | cut -d. -f1`/LC_MESSAGES/; \ 88 | cp $$i $(DESTDIR)$(LOCALE)/`echo $$i | cut -d. -f1`/LC_MESSAGES/axel.mo; \ 89 | done 90 | 91 | uninstall-i18n: 92 | cd $(LOCALE); find . -name axel.mo -exec 'rm' '{}' ';' 93 | -------------------------------------------------------------------------------- /gui/kapt/axel-kapt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright 2001 by Paul Evans 3 | # Sat Oct 20 01:15:11 2001 Paul Evans 4 | # v 0.3 5 | # This grammar is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, 8 | # or (at your option) any later version. 9 | 10 | # This grammar is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | 15 | # You should have a copy of the GNU General Public License. 16 | # Probably you have *many* of them... 17 | # If not, write to the Free Software Foundation, 18 | # Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | # 20 | 21 | # To use this grammar you need Kaptain. The primary web site for 22 | # Kaptain is http://kaptain.sourceforge.net. You can download the 23 | # latest version, documentation and other Kaptain grammars there. 24 | # 25 | # You may need to specify the location of your kaptain binary. 26 | 27 | 28 | import sys, os, string 29 | 30 | a = ''' 31 | start :framed "Axel-Kapt Download Accelerator" -> info url config local buttons filler; 32 | 33 | info :horizontal -> txt ico; 34 | txt -> @text(x%axel -V%); 35 | ico -> @icon("connect_creating.png"); 36 | 37 | url "Url (you can add mirrors)" -> @string()="''' 38 | 39 | 40 | 41 | b = '''"; 42 | config :horizontal "OPTIONS" -> checks term max connex search; 43 | checks :horizontal -> proxy verb quiet altern; 44 | proxy "No Proxy" -> "-N " | ! @ ; 45 | verb "Verbose" -> "--verbose " | ! @; 46 | quiet "Quiet" -> "-q " | ! @ ; 47 | altern "Alt Progress" -> "-a " | @; 48 | 49 | term "Terminal Type" -> @string()="x-terminal-emulator"; 50 | max "Max bps"-> @integer()=0; 51 | connex :horizontal "Connections" -> @integer()=4; 52 | search :framed "ftp Search" -> numsites | ! @ ; 53 | numsites -> "--search=" @integer()=3 " "; 54 | 55 | 56 | local -> file | ! @ ; 57 | file "Save as (optional). Choose a directory and type a filename..." -> "--output=\\"" @directory() "\\" "; 58 | 59 | buttons :horizontal "Actions" -> help mail doit quit; 60 | help -> @preview(helpstr,"Close")="Help"; 61 | mail -> @preview(bug,"Close")="Bug Report"; 62 | doit -> @exec(axel)="Start"; 63 | #doit -> @echo(axel)="Start"; 64 | quit -> @close="Exit"; 65 | 66 | filler -> @fill(); #sometimes the bottom is obscured.. 67 | #not just in kaptain. Some other qt apps too 68 | 69 | helpstr -> "Axel is a program that downloads a file from a FTP or HTTP \ 70 | server through multiple connection, each connection downloads its own \ 71 | part of the file. Read the manual page - axel(1) for various options"; 72 | 73 | bug -> "Please visit http://axel.alioth.debian.org/ to report bugs on axel-kapt"; 74 | 75 | axel -> term " -e axel -s " max " -n "connex " " proxy verb quiet altern search local url; 76 | ''' 77 | try: 78 | c = string.join(sys.argv[1:]) 79 | except: 80 | c = "" 81 | 82 | cmd = "echo '" + a + "'" + c + "'" + b + "'" + " | kaptain" 83 | os.system(cmd) 84 | -------------------------------------------------------------------------------- /axel_zh_CN.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" Axel 手册页 3 | .\" 4 | .\" 起源于一本由Richard Stone和Neil Matthew写的、名为《Linux程序设计》的书的手册页样本。 5 | .\" 6 | .\" 翻译于08-10-17 7 | .\" 校对于08-11-11 8 | .\" 9 | .TH AXEL 1 10 | 11 | 12 | .SH 名称 13 | \fBAxel\fP \- Linux 下轻量的下载加速器。 14 | 15 | .SH 总览 16 | .B axel 17 | [\fI选项\fP] \fIurl1\fP [\fIurl2\fP] [\fIurl...\fP] 18 | 19 | .SH 描述 20 | Axel\ 是一个通过多个连接从一个\ HTTP\ 或\ FTP\ 服务器下载文件的程序,每个连接下载文件的一部分。 21 | 22 | 跟其它程序不一样,\ Axel\ 会使用单一线程直接下载所有数据到目标文件。 23 | 这样正好可以节省时间,因为程序没有必要如锁链般连接到所有要下载的部分。 24 | 25 | .SH 选项 26 | .PP 27 | 必需要有一个参数--您想下载的文件的\ URL\ 。\ 28 | 当从\ FTP\ 下载,文件名可能包含通配符,程序会尝试解析完整的文件名。 29 | 也可以指定多个\ URL\ ,程序将会通过那些地址下载。\ 30 | 请注意,程序不会检查文件是否相同。 31 | 32 | .PP 33 | 其它选项: 34 | 35 | .TP 36 | \fB\-\-max\-speed=x\fP, \fB\-s\ x\fP 37 | 您可以在这里指定一个速率(每秒字节,B/s),\ Axel\ 将会尝试保持平均速率在这个速率附近。\ 38 | 它很有用──如果您不想程序吃掉您所有的带宽。 39 | 40 | .TP 41 | \fB\-\-num\-connections=x\fP, \fB\-n\ x\fP 42 | 您可以在这里指定一个最终连接数。 43 | 44 | .TP 45 | \fB\-\-output=x\fP, \fB\-o\ x\fP 46 | 下载的数据将会被保存为一个跟\ URL\ 地址文件名同名的本地文件,\ 47 | 除非您使用这个选项指定使用一个不一样的名字。 48 | 您也可以指定一个目录,程序将会追加文件名。 49 | 50 | .TP 51 | \fB\-\-search[=x]\fP, \fB-S[x]\fP 52 | Axel\ 能使用\ filesearching.com\ 搜索引擎,对镜像执行搜索。您使用这个选项它才会这么做。 53 | 您也可以指定应该使用多少个不同的镜像来下载。 54 | 55 | 对镜像搜索非常耗时,因为程序会测试每个服务器的速率,与及文件是否仍然有效。 56 | 57 | .TP 58 | \fB\-\-no\-proxy\fP, \fB\-N\fP 59 | 不使用代理服务器下载文件。当然,当一个透明代理是有效时,这是不可能的。 60 | 61 | .TP 62 | \fB\-\-verbose\fP 63 | 如果您想看到更多的状态信息,您可以使用这个选项。如果您想看到更多,就使用它多几次。 64 | 65 | .TP 66 | \fB\-\-quiet\fP, \fB-q\fP 67 | 不输出到标准输出(stdout)。 68 | 69 | .TP 70 | \fB\-\-alternate\fP, \fB-a\fP 71 | 这将会显示一个文本进度指示器。一个显示不同线程进度和状态,当前速率和评估剩余下载时间的棒形图。 72 | 73 | .TP 74 | \fB\-\-help\fP, \fB\-h\fP 75 | 一个对所有选项的简洁摘要。 76 | 77 | .TP 78 | \fB\-\-version\fP, \fB\-V\fP 79 | 获取版本信息。 80 | 81 | .SH 注意 82 | 如果您的平台识别\ getopt_lang\ 调用,长(两杠破折号)选项才会被支持。\ 83 | 否则(像\ *BSD\ ),只能使用短选项。 84 | 85 | .SH 返回值 86 | 当下载成功,程序返回0,如果真的出错返回1,如果下载被中断返回2,如果返回其它,它肯定是一个臭虫…… 87 | 88 | .SH 例子 89 | .nf 90 | axel\ ftp://ftp.{be,nl,uk,de}.kernel.org/pub/linux/kernel/v2.4/linux-2.4.17.tar.bz2 91 | .fi 92 | 93 | 它将会使用\ Belgian\ 、\ Dutch\ 、\ English\ 和\ German\ 的\ kenel.org\ 镜像下载\ Linux\ 2.4.17\ kernel\ 映象。 94 | 95 | .nf 96 | axel\ \-S4\ ftp://ftp.kernel.org/pub/linux/kernel/v2.4/linux-2.4.17.tar.bz2 97 | .fi 98 | 99 | 它将会在\ filesearching.com\ 搜索\ linux-2.4.17.tar.bz2\ 文件,\ 100 | 然后从四个(如果可能的话)最快的镜像中下载(可能包括\ ftp.kernel.org\ )。 101 | 102 | (当然,这个命令是一个独立行,但他们太长而不能在这个页面内显示为一行。) 103 | 104 | 让\ Gentoo\ GNU/Linux\ 的\ Portage\ 软件包管理器调用\ Axel\ 来下载,把下面的命令添加进\ /etc/make.conf\ 。 105 | 106 | .nf 107 | FETCHCOMMAND='/usr/bin/axel -a -o "${DISTDIR}/${FILE}.axel" "${URI}" && mv "${DISTDIR}/${FILE}.axel" "${DISTDIR}/${FILE}"' 108 | RESUMECOMMAND="${FETCHCOMMAND}" 109 | .fi 110 | 111 | 112 | .SH 文件 113 | .PP 114 | \fI/etc/axelrc\fP 系统全局配置文件 115 | .PP 116 | \fI~/.axelrc\fP 个人配置文件 117 | .PP 118 | 这些文件正文不会在一个手册页内显示,但我希望跟程序一起安装的样本文件包含足够的信息。 119 | 配置文件在不同系统的位置可能不一样。 120 | 121 | .SH 版权 122 | Axel is Copyright 2001-2002 Wilmer van der Gaast. 123 | 124 | .SH 臭虫 125 | .PP 126 | 我坚信在某些地方仍然会有臭虫,请告诉我,我会尝试修复它们。 127 | 128 | 已知臭虫是当使用上百个连接下载时,程序会发生异常。您应该避免它。 129 | 130 | .SH 作者 131 | Wilmer van der Gaast. 132 | 133 | .SH 翻译 134 | 蠡\ Shuge\ Lee\ 135 | 136 | .SH 校对 137 | 李进\ Li\ Jin\ 138 | 139 | .\" 最后更新09-02-06 140 | -------------------------------------------------------------------------------- /tcp.c: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* TCP control file */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #include "axel.h" 27 | 28 | /* Get a TCP connection */ 29 | int tcp_connect( char *hostname, int port, char *local_if ) 30 | { 31 | struct hostent *host = NULL; 32 | struct sockaddr_in addr; 33 | struct sockaddr_in local; 34 | int fd; 35 | 36 | #ifdef DEBUG 37 | socklen_t i = sizeof( local ); 38 | 39 | fprintf( stderr, "tcp_connect( %s, %i ) = ", hostname, port ); 40 | #endif 41 | 42 | /* Why this loop? Because the call might return an empty record. 43 | At least it very rarely does, on my system... */ 44 | for( fd = 0; fd < 5; fd ++ ) 45 | { 46 | if( ( host = gethostbyname( hostname ) ) == NULL ) 47 | return( -1 ); 48 | if( *host->h_name ) break; 49 | } 50 | if( !host || !host->h_name || !*host->h_name ) 51 | return( -1 ); 52 | 53 | if( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) 54 | return( -1 ); 55 | 56 | if( local_if && *local_if ) 57 | { 58 | local.sin_family = AF_INET; 59 | local.sin_port = 0; 60 | local.sin_addr.s_addr = inet_addr( local_if ); 61 | if( bind( fd, (struct sockaddr *) &local, sizeof( struct sockaddr_in ) ) == -1 ) 62 | { 63 | close( fd ); 64 | return( -1 ); 65 | } 66 | } 67 | 68 | addr.sin_family = AF_INET; 69 | addr.sin_port = htons( port ); 70 | addr.sin_addr = *( (struct in_addr *) host->h_addr ); 71 | 72 | if( connect( fd, (struct sockaddr *) &addr, sizeof( struct sockaddr_in ) ) == -1 ) 73 | { 74 | close( fd ); 75 | return( -1 ); 76 | } 77 | 78 | #ifdef DEBUG 79 | getsockname( fd, &local, &i ); 80 | fprintf( stderr, "%i\n", ntohs( local.sin_port ) ); 81 | #endif 82 | 83 | return( fd ); 84 | } 85 | 86 | int get_if_ip( char *iface, char *ip ) 87 | { 88 | struct ifreq ifr; 89 | int fd = socket( PF_INET, SOCK_DGRAM, IPPROTO_IP ); 90 | 91 | memset( &ifr, 0, sizeof( struct ifreq ) ); 92 | 93 | strcpy( ifr.ifr_name, iface ); 94 | ifr.ifr_addr.sa_family = AF_INET; 95 | if( ioctl( fd, SIOCGIFADDR, &ifr ) == 0 ) 96 | { 97 | struct sockaddr_in *x = (struct sockaddr_in *) &ifr.ifr_addr; 98 | strcpy( ip, inet_ntoa( x->sin_addr ) ); 99 | return( 1 ); 100 | } 101 | else 102 | { 103 | return( 0 ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /axel.h: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* Main include file */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #include "config.h" 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #ifndef NOGETOPTLONG 35 | #define _GNU_SOURCE 36 | #include 37 | #endif 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | /* Internationalization */ 57 | #ifdef I18N 58 | #define PACKAGE "axel" 59 | #define _( x ) gettext( x ) 60 | #include 61 | #include 62 | #else 63 | #define _( x ) x 64 | #endif 65 | 66 | /* Compiled-in settings */ 67 | #define MAX_STRING 1024 68 | #define MAX_ADD_HEADERS 10 69 | #define MAX_REDIR 5 70 | #define AXEL_VERSION_STRING "2.4" 71 | #define DEFAULT_USER_AGENT "Axel " AXEL_VERSION_STRING " (" ARCH ")" 72 | 73 | typedef struct 74 | { 75 | void *next; 76 | char text[MAX_STRING]; 77 | } message_t; 78 | 79 | typedef message_t url_t; 80 | typedef message_t if_t; 81 | 82 | #include "conf.h" 83 | #include "tcp.h" 84 | #include "ftp.h" 85 | #include "http.h" 86 | #include "conn.h" 87 | #include "search.h" 88 | 89 | #define min( a, b ) ( (a) < (b) ? (a) : (b) ) 90 | #define max( a, b ) ( (a) > (b) ? (a) : (b) ) 91 | 92 | typedef struct 93 | { 94 | conn_t *conn; 95 | conf_t conf[1]; 96 | char filename[MAX_STRING]; 97 | double start_time; 98 | int next_state, finish_time; 99 | long long bytes_done, start_byte, size; 100 | int bytes_per_second; 101 | int delay_time; 102 | int outfd; 103 | int ready; 104 | message_t *message; 105 | url_t *url; 106 | } axel_t; 107 | 108 | axel_t *axel_new( conf_t *conf, int count, void *url ); 109 | int axel_open( axel_t *axel ); 110 | void axel_start( axel_t *axel ); 111 | void axel_do( axel_t *axel ); 112 | void axel_close( axel_t *axel ); 113 | 114 | double gettime(); 115 | void free_axel_t ( axel_t *axel ); 116 | -------------------------------------------------------------------------------- /axelrc.example: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | ## ## 3 | ## Example configuration file for Axel - A light download accelerator ## 4 | ## ## 5 | ############################################################################ 6 | 7 | # reconnect_delay sets the number of seconds before trying again to build 8 | # a new connection to the server. 9 | # 10 | # reconnect_delay = 20 11 | 12 | # You can set a maximum speed (bytes per second) here, Axel will try to be 13 | # at most 5% faster or 5% slower. 14 | # 15 | # max_speed = 0 16 | 17 | # You can set the maximum number of connections Axel will try to set up 18 | # here. There's a value precompiled in the program too, setting this too 19 | # high requires recompilation. PLEASE respect FTP server operators and other 20 | # users: Don't set this one too high!!! 4 is enough in most cases. 21 | # 22 | # num_connections = 4 23 | 24 | # If no data comes from a connection for this number of seconds, abort (and 25 | # resume) the connection. 26 | # 27 | # connection_timeout = 45 28 | 29 | # Set proxies. no_proxy is a comma-separated list of domains which are 30 | # local, axel won't use any proxy for them. You don't have to specify full 31 | # hostnames there. 32 | # 33 | # Note: If the HTTP_PROXY environment variable is set correctly already, 34 | # you don't have to set it again here. The setting should be in the same 35 | # format as the HTTP_PROXY var, like 'http://host.domain.com:8080/', 36 | # although a string like 'host.domain.com:8080' should work too.. 37 | # 38 | # Sometimes HTTP proxies support FTP downloads too, so the proxy you 39 | # configure here will be used for FTP downloads too. 40 | # 41 | # If you have to use a SOCKS server for some reason, the program should 42 | # work perfectly through socksify without even knowing about that server. 43 | # I haven't tried it myself, so I would love to hear from you about the 44 | # results. 45 | # 46 | # http_proxy = 47 | # no_proxy = 48 | 49 | # Keep CGI arguments in the local filename? 50 | # 51 | # strip_cgi_parameters = 1 52 | 53 | # When downloading a HTTP directory/index page, (like http://localhost/~me/) 54 | # what local filename do we have to store it in? 55 | # 56 | # default_filename = default 57 | 58 | # Save state every x seconds. Set this to 0 to disable state saving during 59 | # download. State files will always be saved when the program terminates 60 | # (unless the download is finished, of course) so this is only useful to 61 | # protect yourself against sudden system crashes. 62 | # 63 | # save_state_interval = 10 64 | 65 | # Buffer size: Maximum amount of bytes to read from a connection. One single 66 | # buffer is used for all the connections (no separate per-connection buffer). 67 | # A smaller buffer might improve the accuracy of the speed limiter, but a 68 | # larger buffer is a better choice for fast connections. 69 | # 70 | # buffer_size = 5120 71 | 72 | # By default some status messages about the download are printed. You can 73 | # disable this by setting this one to zero. 74 | # 75 | # verbose = 1 76 | 77 | # FTP searcher 78 | # 79 | # search_timeout - Maximum time (seconds) to wait for a speed test 80 | # search_threads - Maximum number of speed tests at once 81 | # search_amount - Number of URL's to request from filesearching.com 82 | # search_top - Number of different URL's to use for download 83 | # 84 | # search_timeout = 10 85 | # search_threads = 3 86 | # search_amount = 15 87 | # search_top = 3 88 | 89 | # If you have multiple interfaces to the Internet, you can make Axel use all 90 | # of them by listing them here (interface name or IP address). If one of the 91 | # interfaces is faster than the other(s), you can list it more than once and 92 | # it will be used more often. 93 | # 94 | # This option is blank by default, which means Axel uses the first match in 95 | # the routing table. 96 | # 97 | # interfaces = 98 | 99 | # If you don't like the wget-alike interface, you can set this to 1 to get 100 | # a scp-alike interface. 101 | # 102 | # alternate_output = 1 103 | -------------------------------------------------------------------------------- /ROADMAP: -------------------------------------------------------------------------------- 1 | Roadmap for Axel v2 2 | =================== 3 | 4 | * Check if strrstr is provided by environment 5 | * Use SI prefixes 6 | 7 | Roadmap for Axel v3 8 | =================== 9 | 10 | Note: This document provides only a rough overview what to do next. Refer to the bugtracker ( https://alioth.debian.org/tracker/?group_id=100070&atid=413085 ) for detailled information. 11 | Pre-release version numbers of Axel 3 will start with 2.99. Starting with the 3.x series, the following version scheme will be adopted: 12 | 13 | x.y.z 14 | 15 | x: Complete overhaul of the code structure 16 | y: New features and/or speed/size improvements 17 | z: Bug fixed 18 | 19 | Features 20 | ======== 21 | 22 | * HTTP authentication (#310785) 23 | This is actually already implemented and should be documented. Using -H is possible, too. 24 | 25 | * Metalink (#310625) 26 | Basic Metalink support should not be that difficult. However, it will only be compiled if METALINK is defined. Metalink support will require libxml2. As libmetalink is currently unusable for us (private symbols), we'll implement the format ourselves. 27 | 28 | * .netrc (#310635) 29 | There are lots of GPLed implementations flying around. To minimize code size, it shouldn't be compiled in by default if the code exceeds a couple of bytes. Anyway, it's just one call from Axel's point of view. 30 | 31 | * Prevent connection to same server (#310638) 32 | See tcp.c below for the implementation (aside from a flag in the configuration and a cli flag). 33 | 34 | * Force overriding state file (#311022) 35 | Shouldn't be difficult and take more than a couple of bytes. 36 | 37 | * SSL protocols (HTTPS, FTPS) (#311163) 38 | 39 | * Parse Content-Disposition header (#311101) 40 | Look if the specific problem mentioned in the bug is fixed by this. 41 | 42 | Code structure 43 | ============== 44 | 45 | * conn.c 46 | needs cleanup, possibly even elimination. Most functions look like 47 | if (ftp && !proxy) { 48 | // ... do FTP stuff (15 lines) 49 | } else { 50 | // ... do HTTP stuff (20 lines) 51 | } 52 | We should at least abstract the switch between HTTP and FTP and look what can be done about simplifiying and documenting the functions here. 53 | 54 | Furthermore, redirecting should be cached somehow/done only once lest we reach the redirect limit because it's less than -n. 55 | * tcp.c 56 | should be checked. The functions look a little bit obscure to me. But maybe, that's just me. Before we implement #310638, we should include some round-robin trickery in here. 57 | * Removing MAX_STRING(#311085) and MAX_ADD_HEADERS. These are arbitrary restrictions and may hide a number of strange bugs. Furthermore, statically sized fields are a waste of memory. 58 | * Add die messages: Axel must not exit with != 0 without telling why. 59 | * Add debugging messages: When compiled with DEBUG, Axel could be more verbose. This won't harm anything and may serve as comments. 60 | * Some functions could use a little bit of documentation. 61 | * Remove all logic from text.c 62 | * Ensure correct synchronization of thread state (volatile?) 63 | * Cleanup AXEL_LEGACY 64 | * rewrite axel-kapt to be sane (probably sh, or even #!/usr/bin/env kaptain suffices) or remove it in favor of a sane GUI 65 | 66 | Bugs 67 | ==== 68 | 69 | We're gonna fix them all! 70 | #310979 seems pretty vague. 71 | 72 | Check spaces in FTP and HTTP URLs 73 | 74 | (User) Documentation 75 | ==================== 76 | 77 | * As previously mentioned, authentication should be documented. 78 | * Update API 79 | 80 | 3.1 81 | === 82 | 83 | * Cookies (#310835) 84 | Can be implemented via -H. The bug called for reading the Netcape-style cookies.txt (Wget's --load--cokies option). Domain-specific cookies could be rather complex to implement. If the implementation of this feature costs more than 100B, it should be deselectable. 85 | * Rate-limit status messages (#TODO) 86 | * Don't discard first HTTP connection, but use it adaptively (start requests from the end, RST as soon as first task is fullfilled) 87 | * A -1 option: Just make one request, and only one. 88 | * IPv6 support 89 | 90 | 3.2 91 | === 92 | 93 | * Write a macro ERROR_MESSAGE(msg) (msg), enclose all _("some long error message") and offer a compilation option for a single error message, see if that yields any size improvements 94 | * Check compilation with dietlibc(http://www.fefe.de/dietlibc/) and uclibc(http://www.uclibc.org/): 95 | · How to compile with these libraries 96 | · Does this actually improve the binary size? 97 | · Check warnings/suggestions 98 | * valgrind and friends 99 | * Test very large -n values. Check pthread thread stack size. 100 | 101 | Future/Ideas 102 | ============ 103 | 104 | * Real FTPS (AUTH)? 105 | * Allow downloading to /dev/null for debugging or speed test purposes (Statefile in memory or so) 106 | * Desktop integration, look who likes download accelerators 107 | * Check the syscalls we make. Check whether timing and read() calls can be optimized 108 | * Write automated tests to test all these nifty corner cases. Either a test webserver or LD_PRELOAD injection of all syscalls (see libfake*) 109 | * Write a helper script that displays the final binary size for different configurations to determine what a particular feature costs 110 | * Document and implement coding conventions, versioning scheme 111 | -------------------------------------------------------------------------------- /axel.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\"man-page for Axel 3 | .\" 4 | .\"Derived from the man-page example in the wonderful book called Beginning 5 | .\"Linux Programming, written by Richard Stone and Neil Matthew. 6 | .\" 7 | .TH AXEL 1 8 | 9 | .SH NAME 10 | \fBAxel\fP \- A light download accelerator for Linux. 11 | 12 | .SH SYNOPSIS 13 | .B axel 14 | [\fIOPTIONS\fP] \fIurl1\fP [\fIurl2\fP] [\fIurl...\fP] 15 | 16 | .SH DESCRIPTION 17 | Axel is a program that downloads a file from a FTP or HTTP server through 18 | multiple connection, each connection downloads its own part of the file. 19 | 20 | Unlike most other programs, Axel downloads all the data directly to the 21 | destination file, using one single thread. It just saves some time at the 22 | end because the program doesn't have to concatenate all the downloaded 23 | parts. 24 | 25 | .SH OPTIONS 26 | .PP 27 | One argument is required, the URL to the file you want to download. When 28 | downloading from FTP, the filename may contain wildcards and the program 29 | will try to resolve the full filename. Multiple URL's can be specified 30 | as well and the program will use all those URL's for the download. Please 31 | note that the program does not check whether the files are equal. 32 | 33 | .PP 34 | Other options: 35 | 36 | .TP 37 | \fB\-\-max\-speed=x\fP, \fB\-s\ x\fP 38 | You can specify a speed (bytes per second) here and Axel will try 39 | to keep the average speed around this speed. Useful if you don't want 40 | the program to suck up all of your bandwidth. 41 | 42 | .TP 43 | \fB\-\-num\-connections=x\fP, \fB\-n\ x\fP 44 | You can specify an alternative number of connections here. 45 | 46 | .TP 47 | \fB\-\-output=x\fP, \fB\-o\ x\fP 48 | Downloaded data will be put in a local file with the same name, 49 | unless you specify a different name using this option. You can 50 | specify a directory as well, the program will append the filename. 51 | 52 | .TP 53 | \fB\-\-search[=x]\fP, \fB-S[x]\fP 54 | Axel can do a search for mirrors using the filesearching.com search 55 | engine. This search will be done if you use this option. You can specify how 56 | many different mirrors should be used for the download as well. 57 | 58 | The search for mirrors can be time\-consuming because the program tests 59 | every server's speed, and it checks whether the file's still available. 60 | 61 | .TP 62 | \fB\-\-no\-proxy\fP, \fB\-N\fP 63 | Don't use any proxy server to download the file. Not possible when a 64 | transparent proxy is active somewhere, of course. 65 | 66 | .TP 67 | \fB\-\-verbose\fP 68 | If you want to see more status messages, you can use this option. Use it 69 | more than once if you want to see more. 70 | 71 | .TP 72 | \fB\-\-quiet\fP, \fB-q\fP 73 | No output to stdout. 74 | 75 | .TP 76 | \fB\-\-alternate\fP, \fB-a\fP 77 | This will show an alternate progress indicator. A bar displays the progress 78 | and status of the different threads, along with current speed and an 79 | estimate for the remaining download time. 80 | 81 | .TP 82 | \fB\-\-header=x\fP, \fB\-H\ x\fP 83 | Add an additional HTTP header. This option should be in the form "Header: 84 | Value". See RFC 2616 section 4.2 and 14 for details on the format and 85 | standardized headers. 86 | 87 | .TP 88 | \fB\-\-user-agent=x\fP, \fB\-U\ x\fP 89 | Set the HTTP user agent to use. Some websites serve different content based upon 90 | this parameter. The default value will include "Axel", its version and the 91 | platform. 92 | 93 | .TP 94 | \fB\-\-help\fP, \fB\-h\fP 95 | A brief summary of all the options. 96 | 97 | .TP 98 | \fB\-\-version\fP, \fB\-V\fP 99 | Get version information. 100 | 101 | .SH NOTE 102 | Long (double dash) options are supported only if your platform knows about 103 | the getopt_long call. If it does not (like *BSD), only the short options can 104 | be used. 105 | 106 | .SH RETURN VALUE 107 | The program returns 0 when the download was succesful, 1 if something really 108 | went wrong and 2 if the download was interrupted. If something else comes back, 109 | it must be a bug.. 110 | 111 | .SH EXAMPLES 112 | .nf 113 | axel ftp://ftp.{be,nl,uk,de}.kernel.org/pub/linux/kernel/v2.4/linux-2.4.17.tar.bz2 114 | .fi 115 | 116 | This will use the Belgian, Dutch, English and German kernel.org mirrors to 117 | download a Linux 2.4.17 kernel image. 118 | 119 | .nf 120 | axel \-S4 ftp://ftp.kernel.org/pub/linux/kernel/v2.4/linux-2.4.17.tar.bz2 121 | .fi 122 | 123 | This will do a search for the linux-2.4.17.tar.bz2 file on filesearching.com 124 | and it'll use the four (if possible) fastest mirrors for the download. 125 | (Possibly including ftp.kernel.org) 126 | 127 | (Of course, the commands are a single line, but they're too long to fit on 128 | one line in this page.) 129 | 130 | .SH FILES 131 | .PP 132 | \fI/etc/axelrc\fP System-wide configuration file. Note that development versions 133 | place this file in /usr/local/etc. 134 | .PP 135 | \fI~/.axelrc\fP Personal configuration file 136 | .PP 137 | These files are not documented in a man\-page, but the example file which 138 | comes with the program contains enough information, I hope. The position 139 | of the system-wide configuration file might be different. 140 | 141 | .SH COPYRIGHT 142 | Axel is Copyright 2001-2002 Wilmer van der Gaast. 143 | 144 | .SH BUGS 145 | Please report bugs at https://alioth.debian.org/tracker/?group_id=100070&atid=413085. 146 | 147 | .SH AUTHORS 148 | Wilmer van der Gaast. 149 | -------------------------------------------------------------------------------- /conf.c: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* Configuration handling file */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #include "axel.h" 27 | 28 | /* Some nifty macro's.. */ 29 | #define get_config_string( name ) \ 30 | if( strcmp( key, #name ) == 0 ) \ 31 | { \ 32 | st = 1; \ 33 | strcpy( conf->name, value ); \ 34 | } 35 | #define get_config_number( name ) \ 36 | if( strcmp( key, #name ) == 0 ) \ 37 | { \ 38 | st = 1; \ 39 | sscanf( value, "%i", &conf->name ); \ 40 | } 41 | 42 | int parse_interfaces( conf_t *conf, char *s ); 43 | 44 | int conf_loadfile( conf_t *conf, char *file ) 45 | { 46 | int i, line = 0; 47 | FILE *fp; 48 | char s[MAX_STRING], key[MAX_STRING], value[MAX_STRING]; 49 | 50 | fp = fopen( file, "r" ); 51 | if( fp == NULL ) 52 | return( 1 ); /* Not a real failure */ 53 | 54 | while( !feof( fp ) ) 55 | { 56 | int st; 57 | 58 | line ++; 59 | 60 | *s = 0; 61 | fscanf( fp, "%100[^\n#]s", s ); 62 | fscanf( fp, "%*[^\n]s" ); 63 | fgetc( fp ); /* Skip newline */ 64 | if( strchr( s, '=' ) == NULL ) 65 | continue; /* Probably empty? */ 66 | sscanf( s, "%[^= \t]s", key ); 67 | for( i = 0; s[i]; i ++ ) 68 | if( s[i] == '=' ) 69 | { 70 | for( i ++; isspace( (int) s[i] ) && s[i]; i ++ ); 71 | break; 72 | } 73 | strcpy( value, &s[i] ); 74 | for( i = strlen( value ) - 1; isspace( (int) value[i] ); i -- ) 75 | value[i] = 0; 76 | 77 | st = 0; 78 | 79 | /* Long live macros!! */ 80 | get_config_string( default_filename ); 81 | get_config_string( http_proxy ); 82 | get_config_string( no_proxy ); 83 | get_config_number( strip_cgi_parameters ); 84 | get_config_number( save_state_interval ); 85 | get_config_number( connection_timeout ); 86 | get_config_number( reconnect_delay ); 87 | get_config_number( num_connections ); 88 | get_config_number( buffer_size ); 89 | get_config_number( max_speed ); 90 | get_config_number( verbose ); 91 | get_config_number( alternate_output ); 92 | 93 | get_config_number( search_timeout ); 94 | get_config_number( search_threads ); 95 | get_config_number( search_amount ); 96 | get_config_number( search_top ); 97 | 98 | /* Option defunct but shouldn't be an error */ 99 | if( strcmp( key, "speed_type" ) == 0 ) 100 | st = 1; 101 | 102 | if( strcmp( key, "interfaces" ) == 0 ) 103 | st = parse_interfaces( conf, value ); 104 | 105 | if( !st ) 106 | { 107 | fprintf( stderr, _("Error in %s line %i.\n"), file, line ); 108 | return( 0 ); 109 | } 110 | get_config_number( add_header_count ); 111 | for(i=0;iadd_header_count;i++) 112 | get_config_string( add_header[i] ); 113 | get_config_string( user_agent ); 114 | } 115 | 116 | fclose( fp ); 117 | return( 1 ); 118 | } 119 | 120 | int conf_init( conf_t *conf ) 121 | { 122 | char s[MAX_STRING], *s2; 123 | int i; 124 | 125 | /* Set defaults */ 126 | memset( conf, 0, sizeof( conf_t ) ); 127 | strcpy( conf->default_filename, "default" ); 128 | *conf->http_proxy = 0; 129 | *conf->no_proxy = 0; 130 | conf->strip_cgi_parameters = 1; 131 | conf->save_state_interval = 10; 132 | conf->connection_timeout = 45; 133 | conf->reconnect_delay = 20; 134 | conf->num_connections = 4; 135 | conf->buffer_size = 5120; 136 | conf->max_speed = 0; 137 | conf->verbose = 1; 138 | conf->alternate_output = 0; 139 | 140 | conf->search_timeout = 10; 141 | conf->search_threads = 3; 142 | conf->search_amount = 15; 143 | conf->search_top = 3; 144 | conf->add_header_count = 0; 145 | strncpy( conf->user_agent, DEFAULT_USER_AGENT, MAX_STRING ); 146 | 147 | conf->interfaces = malloc( sizeof( if_t ) ); 148 | memset( conf->interfaces, 0, sizeof( if_t ) ); 149 | conf->interfaces->next = conf->interfaces; 150 | 151 | if( ( s2 = getenv( "http_proxy" ) ) != NULL ) 152 | strncpy( conf->http_proxy, s2, MAX_STRING ); 153 | else if( ( s2 = getenv( "HTTP_PROXY" ) ) != NULL ) 154 | strncpy( conf->http_proxy, s2, MAX_STRING ); 155 | 156 | if( !conf_loadfile( conf, ETCDIR "/axelrc" ) ) 157 | return( 0 ); 158 | 159 | if( ( s2 = getenv( "HOME" ) ) != NULL ) 160 | { 161 | sprintf( s, "%s/%s", s2, ".axelrc" ); 162 | if( !conf_loadfile( conf, s ) ) 163 | return( 0 ); 164 | } 165 | 166 | /* Convert no_proxy to a 0-separated-and-00-terminated list.. */ 167 | for( i = 0; conf->no_proxy[i]; i ++ ) 168 | if( conf->no_proxy[i] == ',' ) 169 | conf->no_proxy[i] = 0; 170 | conf->no_proxy[i+1] = 0; 171 | 172 | return( 1 ); 173 | } 174 | 175 | int parse_interfaces( conf_t *conf, char *s ) 176 | { 177 | char *s2; 178 | if_t *iface; 179 | 180 | iface = conf->interfaces->next; 181 | while( iface != conf->interfaces ) 182 | { 183 | if_t *i; 184 | 185 | i = iface->next; 186 | free( iface ); 187 | iface = i; 188 | } 189 | free( conf->interfaces ); 190 | 191 | if( !*s ) 192 | { 193 | conf->interfaces = malloc( sizeof( if_t ) ); 194 | memset( conf->interfaces, 0, sizeof( if_t ) ); 195 | conf->interfaces->next = conf->interfaces; 196 | return( 1 ); 197 | } 198 | 199 | s[strlen(s)+1] = 0; 200 | conf->interfaces = iface = malloc( sizeof( if_t ) ); 201 | while( 1 ) 202 | { 203 | while( ( *s == ' ' || *s == '\t' ) && *s ) s ++; 204 | for( s2 = s; *s2 != ' ' && *s2 != '\t' && *s2; s2 ++ ); 205 | *s2 = 0; 206 | if( *s < '0' || *s > '9' ) 207 | get_if_ip( s, iface->text ); 208 | else 209 | strcpy( iface->text, s ); 210 | s = s2 + 1; 211 | if( *s ) 212 | { 213 | iface->next = malloc( sizeof( if_t ) ); 214 | iface = iface->next; 215 | } 216 | else 217 | { 218 | iface->next = conf->interfaces; 219 | break; 220 | } 221 | } 222 | 223 | return( 1 ); 224 | } 225 | -------------------------------------------------------------------------------- /http.c: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* HTTP control file */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #include "axel.h" 27 | 28 | int http_connect( http_t *conn, int proto, char *proxy, char *host, int port, char *user, char *pass ) 29 | { 30 | char base64_encode[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 31 | "abcdefghijklmnopqrstuvwxyz0123456789+/"; 32 | char auth[MAX_STRING]; 33 | conn_t tconn[1]; 34 | int i; 35 | 36 | strncpy( conn->host, host, MAX_STRING ); 37 | conn->proto = proto; 38 | 39 | if( proxy != NULL ) { if( *proxy != 0 ) 40 | { 41 | sprintf( conn->host, "%s:%i", host, port ); 42 | if( !conn_set( tconn, proxy ) ) 43 | { 44 | /* We'll put the message in conn->headers, not in request */ 45 | sprintf( conn->headers, _("Invalid proxy string: %s\n"), proxy ); 46 | return( 0 ); 47 | } 48 | host = tconn->host; 49 | port = tconn->port; 50 | conn->proxy = 1; 51 | } 52 | else 53 | { 54 | conn->proxy = 0; 55 | } } 56 | 57 | if( ( conn->fd = tcp_connect( host, port, conn->local_if ) ) == -1 ) 58 | { 59 | /* We'll put the message in conn->headers, not in request */ 60 | sprintf( conn->headers, _("Unable to connect to server %s:%i\n"), host, port ); 61 | return( 0 ); 62 | } 63 | 64 | if( *user == 0 ) 65 | { 66 | *conn->auth = 0; 67 | } 68 | else 69 | { 70 | memset( auth, 0, MAX_STRING ); 71 | snprintf( auth, MAX_STRING, "%s:%s", user, pass ); 72 | for( i = 0; auth[i*3]; i ++ ) 73 | { 74 | conn->auth[i*4] = base64_encode[(auth[i*3]>>2)]; 75 | conn->auth[i*4+1] = base64_encode[((auth[i*3]&3)<<4)|(auth[i*3+1]>>4)]; 76 | conn->auth[i*4+2] = base64_encode[((auth[i*3+1]&15)<<2)|(auth[i*3+2]>>6)]; 77 | conn->auth[i*4+3] = base64_encode[auth[i*3+2]&63]; 78 | if( auth[i*3+2] == 0 ) conn->auth[i*4+3] = '='; 79 | if( auth[i*3+1] == 0 ) conn->auth[i*4+2] = '='; 80 | } 81 | } 82 | 83 | return( 1 ); 84 | } 85 | 86 | void http_disconnect( http_t *conn ) 87 | { 88 | if( conn->fd > 0 ) 89 | close( conn->fd ); 90 | conn->fd = -1; 91 | } 92 | 93 | void http_get( http_t *conn, char *lurl ) 94 | { 95 | *conn->request = 0; 96 | if( conn->proxy ) 97 | { 98 | http_addheader( conn, "GET %s://%s%s HTTP/1.0", 99 | conn->proto == PROTO_HTTP ? "http" : "ftp", conn->host, lurl ); 100 | } 101 | else 102 | { 103 | http_addheader( conn, "GET %s HTTP/1.0", lurl ); 104 | http_addheader( conn, "Host: %s", conn->host ); 105 | } 106 | if( *conn->auth ) 107 | http_addheader( conn, "Authorization: Basic %s", conn->auth ); 108 | if( conn->firstbyte ) 109 | { 110 | if( conn->lastbyte ) 111 | http_addheader( conn, "Range: bytes=%lld-%lld", conn->firstbyte, conn->lastbyte ); 112 | else 113 | http_addheader( conn, "Range: bytes=%lld-", conn->firstbyte ); 114 | } 115 | } 116 | 117 | void http_addheader( http_t *conn, char *format, ... ) 118 | { 119 | char s[MAX_STRING]; 120 | va_list params; 121 | 122 | va_start( params, format ); 123 | vsnprintf( s, MAX_STRING - 3, format, params ); 124 | strcat( s, "\r\n" ); 125 | va_end( params ); 126 | 127 | strncat( conn->request, s, MAX_QUERY - strlen(conn->request) - 1); 128 | } 129 | 130 | int http_exec( http_t *conn ) 131 | { 132 | int i = 0; 133 | char s[2] = " ", *s2; 134 | 135 | #ifdef DEBUG 136 | fprintf( stderr, "--- Sending request ---\n%s--- End of request ---\n", conn->request ); 137 | #endif 138 | 139 | http_addheader( conn, "" ); 140 | write( conn->fd, conn->request, strlen( conn->request ) ); 141 | 142 | *conn->headers = 0; 143 | /* Read the headers byte by byte to make sure we don't touch the 144 | actual data */ 145 | while( 1 ) 146 | { 147 | if( read( conn->fd, s, 1 ) <= 0 ) 148 | { 149 | /* We'll put the message in conn->headers, not in request */ 150 | sprintf( conn->headers, _("Connection gone.\n") ); 151 | return( 0 ); 152 | } 153 | if( *s == '\r' ) 154 | { 155 | continue; 156 | } 157 | else if( *s == '\n' ) 158 | { 159 | if( i == 0 ) 160 | break; 161 | i = 0; 162 | } 163 | else 164 | { 165 | i ++; 166 | } 167 | strncat( conn->headers, s, MAX_QUERY ); 168 | } 169 | 170 | #ifdef DEBUG 171 | fprintf( stderr, "--- Reply headers ---\n%s--- End of headers ---\n", conn->headers ); 172 | #endif 173 | 174 | sscanf( conn->headers, "%*s %3i", &conn->status ); 175 | s2 = strchr( conn->headers, '\n' ); *s2 = 0; 176 | strcpy( conn->request, conn->headers ); 177 | *s2 = '\n'; 178 | 179 | return( 1 ); 180 | } 181 | 182 | char *http_header( http_t *conn, char *header ) 183 | { 184 | char s[32]; 185 | int i; 186 | 187 | for( i = 1; conn->headers[i]; i ++ ) 188 | if( conn->headers[i-1] == '\n' ) 189 | { 190 | sscanf( &conn->headers[i], "%31s", s ); 191 | if( strcasecmp( s, header ) == 0 ) 192 | return( &conn->headers[i+strlen(header)] ); 193 | } 194 | 195 | return( NULL ); 196 | } 197 | 198 | long long int http_size( http_t *conn ) 199 | { 200 | char *i; 201 | long long int j; 202 | 203 | if( ( i = http_header( conn, "Content-Length:" ) ) == NULL ) 204 | return( -2 ); 205 | 206 | sscanf( i, "%lld", &j ); 207 | return( j ); 208 | } 209 | 210 | /* Decode%20a%20file%20name */ 211 | void http_decode( char *s ) 212 | { 213 | char t[MAX_STRING]; 214 | int i, j, k; 215 | 216 | for( i = j = 0; s[i]; i ++, j ++ ) 217 | { 218 | t[j] = s[i]; 219 | if( s[i] == '%' ) 220 | if( sscanf( s + i + 1, "%2x", &k ) ) 221 | { 222 | t[j] = k; 223 | i += 2; 224 | } 225 | } 226 | t[j] = 0; 227 | 228 | strcpy( s, t ); 229 | } 230 | 231 | void http_encode( char *s ) 232 | { 233 | char t[MAX_STRING]; 234 | int i, j; 235 | 236 | for( i = j = 0; s[i]; i ++, j ++ ) 237 | { 238 | /* Fix buffer overflow */ 239 | if (j >= MAX_STRING - 1) { 240 | break; 241 | } 242 | 243 | t[j] = s[i]; 244 | if( s[i] == ' ' ) 245 | { 246 | /* Fix buffer overflow */ 247 | if (j >= MAX_STRING - 3) { 248 | break; 249 | } 250 | 251 | strcpy( t + j, "%20" ); 252 | j += 2; 253 | } 254 | } 255 | t[j] = 0; 256 | 257 | strcpy( s, t ); 258 | } 259 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ########################### 4 | ## Configurer for Axel ## 5 | ## ## 6 | ## Copyright 2001 Lintux ## 7 | ########################### 8 | 9 | prefix='/usr/local' 10 | bindir='$prefix/bin' 11 | etcdir='$prefix/etc' 12 | sharedir='$prefix/share' 13 | mandir='$sharedir/man' 14 | locale='$sharedir/locale' 15 | 16 | i18n=1 17 | debug=0 18 | strip=1 19 | 20 | arch=`uname -s` 21 | 22 | while [ -n "$1" ]; do 23 | e="`expr "$1" : '--\(.*=.*\)'`" 24 | if [ -z "$e" ]; then 25 | cat<Makefile.settings 64 | ## Axel settings, generated by configure 65 | PREFIX=$prefix 66 | BINDIR=$bindir 67 | ETCDIR=$etcdir 68 | SHAREDIR=$sharedir 69 | MANDIR=$mandir 70 | LOCALE=$locale 71 | 72 | OUTFILE=axel 73 | ARCH=$arch 74 | 75 | DESTDIR= 76 | 77 | EOF 78 | 79 | cat<config.h 80 | /* Axel settings, generated by configure */ 81 | #define _REENTRANT 82 | #define _THREAD_SAFE 83 | #define ETCDIR "$etcdir" 84 | #define LOCALE "$locale" 85 | #define ARCH "$arch" 86 | 87 | EOF 88 | 89 | AXEL_LFLAGS=${LFLAGS} 90 | 91 | if [ "$i18n" = "1" ]; then 92 | if type msgfmt > /dev/null 2> /dev/null; then :;else 93 | echo 'WARNING: Internationalization disabled, you don'\''t have the necessary files' 94 | echo ' installed.' 95 | echo '' 96 | i18n=0; 97 | fi; 98 | 99 | echo "all: i18n-mofiles" >> Makefile.settings 100 | echo "install: install-i18n" >> Makefile.settings 101 | echo "uninstall: uninstall-i18n" >> Makefile.settings 102 | fi 103 | 104 | AXEL_CFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -Os ${CFLAGS}" 105 | if [ "$debug" = "1" ]; then 106 | AXEL_CFLAGS="${AXEL_CFLAGS} -g" 107 | echo 'DEBUG=1' >> Makefile.settings 108 | echo '#define DEBUG' >> config.h; 109 | fi 110 | 111 | if [ "$i18n" = "1" ]; then 112 | echo 'I18N=1' >> Makefile.settings 113 | echo '#define I18N' >> config.h 114 | if [ -f /usr/local/include/libintl.h ]; then 115 | AXEL_CFLAGS="${AXEL_CFLAGS} -I/usr/local/include" 116 | AXEL_LFLAGS="${AXEL_LFLAGS} -L/usr/local/lib" 117 | elif [ -f /opt/csw/include/libintl.h ]; then 118 | AXEL_CFLAGS="${AXEL_CFLAGS} -I/opt/csw/include" 119 | AXEL_LFLAGS="${AXEL_LFLAGS} -L/opt/csw/lib" 120 | elif [ -f "${prefix}/include/libintl.h" ]; then 121 | AXEL_CFLAGS="${AXEL_CFLAGS} -I${prefix}/include" 122 | AXEL_LFLAGS="${AXEL_LFLAGS} -L${prefix}/lib" 123 | fi 124 | fi 125 | 126 | if [ "${CC}" != "" ]; then 127 | echo "CC=${CC}" >> Makefile.settings; 128 | elif type gcc > /dev/null 2> /dev/null; then 129 | echo "CC=gcc" >> Makefile.settings; 130 | AXEL_CFLAGS="${AXEL_CFLAGS} -Wall" 131 | elif type cc > /dev/null 2> /dev/null; then 132 | echo "CC=cc" >> Makefile.settings; 133 | else 134 | echo 'Cannot find a C compiler, aborting.' 135 | exit 1; 136 | fi 137 | 138 | if [ "$strip" = 0 ]; then 139 | echo "STRIP=\# skip strip" >> Makefile.settings; 140 | else 141 | if [ "$debug" = 1 ]; then 142 | echo 'Stripping binaries does not make sense when debugging. Stripping disabled.' 143 | echo 144 | echo 'STRIP=\# skip strip' >> Makefile.settings 145 | strip=0; 146 | elif type strip > /dev/null 2> /dev/null; then 147 | echo "STRIP=strip" >> Makefile.settings; 148 | elif [ -x /usr/ccs/bin/strip ]; then 149 | echo "STRIP=/usr/ccs/bin/strip" >> Makefile.settings; 150 | else 151 | echo 'No strip utility found, cannot remove unnecessary parts from executable.' 152 | echo '' 153 | echo 'STRIP=\# skip strip' >> Makefile.settings 154 | strip=0; 155 | fi; 156 | fi 157 | 158 | case "$arch" in 159 | FreeBSD ) 160 | echo '#define NOGETOPTLONG' >> config.h 161 | AXEL_LFLAGS="${AXEL_LFLAGS} -pthread" 162 | if [ "$i18n" = "1" ]; then 163 | AXEL_LFLAGS="${AXEL_LFLAGS} -lintl" 164 | fi 165 | ;; 166 | OpenBSD ) 167 | echo '#define NOGETOPTLONG' >> config.h 168 | AXEL_LFLAGS="${AXEL_LFLAGS} -pthread" 169 | if [ "$i18n" = "1" ]; then 170 | AXEL_LFLAGS="${AXEL_LFLAGS} -lintl" 171 | fi 172 | ;; 173 | NetBSD ) 174 | echo 'WARNING: NetBSD not tested! Using OpenBSD settings.' 175 | echo '#define NOGETOPTLONG' >> config.h 176 | AXEL_LFLAGS="${AXEL_LFLAGS} -pthread" 177 | if [ "$i18n" = "1" ]; then 178 | AXEL_LFLAGS="${AXEL_LFLAGS} -lintl" 179 | fi 180 | ;; 181 | Darwin ) 182 | echo '#define NOGETOPTLONG' >> config.h 183 | AXEL_LFLAGS="${AXEL_LFLAGS} -pthread" 184 | if [ "$i18n" = "1" ]; then 185 | AXEL_LFLAGS="${AXEL_LFLAGS} -lintl" 186 | fi 187 | echo '#define DARWIN' >> config.h 188 | ;; 189 | Linux | GNU/kFreeBSD) 190 | AXEL_LFLAGS="${AXEL_LFLAGS} -pthread" 191 | ;; 192 | SunOS ) 193 | echo '#define NOGETOPTLONG' >> config.h 194 | echo '#define BSD_COMP' >> config.h 195 | AXEL_LFLAGS="${AXEL_LFLAGS} -pthread -lsocket -lnsl" 196 | if [ "$i18n" = "1" ]; then 197 | AXEL_LFLAGS="${AXEL_LFLAGS} -lintl" 198 | fi 199 | ;; 200 | HP-UX ) 201 | echo '#define NOGETOPTLONG' >> config.h 202 | if [ "$i18n" = "1" ]; then 203 | if [ -d /usr/local/lib/hpux32 ]; then 204 | AXEL_LFLAGS="${AXEL_LFLAGS} -L/usr/local/lib/hpux32" 205 | fi 206 | AXEL_LFLAGS="${AXEL_LFLAGS} -lintl" 207 | fi 208 | AXEL_LFLAGS="${AXEL_LFLAGS} -lpthread" 209 | ;; 210 | CYGWIN_* ) 211 | AXEL_LFLAGS="${AXEL_LFLAGS} -pthread" 212 | if [ "$i18n" = "1" ]; then 213 | AXEL_LFLAGS="${AXEL_LFLAGS} -lintl" 214 | fi 215 | echo 'OUTFILE=axel.exe' >> Makefile.settings 216 | ;; 217 | * ) 218 | AXEL_LFLAGS="${AXEL_LFLAGS} -pthread" 219 | echo '#define NOGETOPTLONG' >> config.h 220 | if [ "$i18n" = "1" ]; then 221 | AXEL_LFLAGS="${AXEL_LFLAGS} -lintl"; 222 | fi 223 | echo 'WARNING: This architecture is unknown!' 224 | echo '' 225 | echo 'That does not mean Axel will not work, it just means Axel is not tested on it.' 226 | echo 'It'\''d be a great help if you could send me more information' 227 | echo 'about your platform so that it can be addedto the build tools.' 228 | echo 'You can try to build the program now, if you wish, this default setup might' 229 | echo 'just work.' 230 | echo '' 231 | ;; 232 | esac 233 | 234 | echo "CFLAGS=${AXEL_CFLAGS}" >> Makefile.settings 235 | echo "LFLAGS=${AXEL_LFLAGS}" >> Makefile.settings 236 | 237 | echo 'Configuration done:' 238 | if [ "$i18n" = "1" ]; then 239 | echo ' Internationalization enabled.'; 240 | else 241 | echo ' Internationalization disabled.'; 242 | fi 243 | if [ "$debug" = "1" ]; then 244 | echo ' Debugging enabled.'; 245 | else 246 | echo ' Debugging disabled.'; 247 | fi 248 | if [ "$strip" = "1" ]; then 249 | echo ' Binary stripping enabled.'; 250 | else 251 | echo ' Binary stripping disabled.'; 252 | fi 253 | -------------------------------------------------------------------------------- /search.c: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* filesearching.com searcher */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #include "axel.h" 27 | 28 | static char *axel_strrstr( char *haystack, char *needle ); 29 | static void *search_speedtest( void *r ); 30 | static int search_sortlist_qsort( const void *a, const void *b ); 31 | 32 | #ifdef STANDALONE 33 | int main( int argc, char *argv[] ) 34 | { 35 | conf_t conf[1]; 36 | search_t *res; 37 | int i, j; 38 | 39 | if( argc != 2 ) 40 | { 41 | fprintf( stderr, "Incorrect amount of arguments\n" ); 42 | return( 1 ); 43 | } 44 | 45 | conf_init( conf ); 46 | 47 | res = malloc( sizeof( search_t ) * ( conf->search_amount + 1 ) ); 48 | memset( res, 0, sizeof( search_t ) * ( conf->search_amount + 1 ) ); 49 | res->conf = conf; 50 | 51 | i = search_makelist( res, argv[1] ); 52 | if( i == -1 ) 53 | { 54 | fprintf( stderr, "File not found\n" ); 55 | return( 1 ); 56 | } 57 | printf( "%i usable mirrors:\n", search_getspeeds( res, i ) ); 58 | search_sortlist( res, i ); 59 | for( j = 0; j < i; j ++ ) 60 | printf( "%-70.70s %5i\n", res[j].url, res[j].speed ); 61 | 62 | return( 0 ); 63 | } 64 | #endif 65 | 66 | int search_makelist( search_t *results, char *url ) 67 | { 68 | int i, size = 8192, j = 0; 69 | char *s, *s1, *s2, *s3; 70 | conn_t conn[1]; 71 | double t; 72 | 73 | memset( conn, 0, sizeof( conn_t ) ); 74 | 75 | conn->conf = results->conf; 76 | t = gettime(); 77 | if( !conn_set( conn, url ) ) 78 | return( -1 ); 79 | if( !conn_init( conn ) ) 80 | return( -1 ); 81 | if( !conn_info( conn ) ) 82 | return( -1 ); 83 | 84 | strcpy( results[0].url, url ); 85 | results[0].speed = 1 + 1000 * ( gettime() - t ); 86 | results[0].size = conn->size; 87 | 88 | s = malloc( size ); 89 | 90 | sprintf( s, "http://www.filesearching.com/cgi-bin/s?q=%s&w=a&l=en&" 91 | "t=f&e=on&m=%i&o=n&s1=%lld&s2=%lld&x=15&y=15", 92 | conn->file, results->conf->search_amount, 93 | conn->size, conn->size ); 94 | 95 | conn_disconnect( conn ); 96 | memset( conn, 0, sizeof( conn_t ) ); 97 | conn->conf = results->conf; 98 | 99 | if( !conn_set( conn, s ) ) 100 | { 101 | free( s ); 102 | return( 1 ); 103 | } 104 | if( !conn_setup( conn ) ) 105 | { 106 | free( s ); 107 | return( 1 ); 108 | } 109 | if( !conn_exec( conn ) ) 110 | { 111 | free( s ); 112 | return( 1 ); 113 | } 114 | 115 | while( ( i = read( conn->fd, s + j, size - j ) ) > 0 ) 116 | { 117 | j += i; 118 | if( j + 10 >= size ) 119 | { 120 | size *= 2; 121 | s = realloc( s, size ); 122 | memset( s + size / 2, 0, size / 2 ); 123 | } 124 | } 125 | 126 | conn_disconnect( conn ); 127 | 128 | s1 = strstr( s, "
" ) == NULL )
131 | 	{
132 | 		/* Incomplete list					*/
133 | 		free( s );
134 | 		return( 1 );
135 | 	}
136 | 	for( i = 1; strncmp( s1, "
", 6 ) && i < results->conf->search_amount && *s1; i ++ ) 137 | { 138 | s3 = strchr( s1, '\n' ); *s3 = 0; 139 | s2 = axel_strrstr( s1, "\n" 8 | "Language-Team: Simplified Chinese \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=utf-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Last-Revision: Li Jin \n" 13 | 14 | #: axel.c:55 15 | msgid "Buffer resized for this speed." 16 | msgstr "为这个速率调整缓冲区大小。" 17 | 18 | #: axel.c:91 19 | msgid "Could not parse URL.\n" 20 | msgstr "无法解析URL\n" 21 | 22 | #: axel.c:126 23 | #, fuzzy, c-format 24 | msgid "File size: %lld bytes" 25 | msgstr "文件大小: %i 字节" 26 | 27 | #: axel.c:143 28 | #, c-format 29 | msgid "Opening output file %s" 30 | msgstr "打开输出文件 %s" 31 | 32 | #: axel.c:152 33 | msgid "Server unsupported, starting from scratch with one connection." 34 | msgstr "服务器不支持,开始一个连接。" 35 | 36 | #: axel.c:171 37 | #, fuzzy, c-format 38 | msgid "State file found: %lld bytes downloaded, %lld to go." 39 | msgstr "找到状态文件: %i 字节已下载,继续下载 %i 字节。" 40 | 41 | #: axel.c:178 axel.c:190 42 | msgid "Error opening local file" 43 | msgstr "打开本地文件错误" 44 | 45 | #: axel.c:202 46 | msgid "Crappy filesystem/OS.. Working around. :-(" 47 | msgstr "" 48 | "糟糕的文件系统或操作系统……Working around……(译注德国写的句子,实在不知道如何" 49 | "翻译……):-(" 50 | 51 | #: axel.c:235 52 | msgid "Starting download" 53 | msgstr "开始下载" 54 | 55 | #: axel.c:242 axel.c:401 56 | #, c-format 57 | msgid "Connection %i downloading from %s:%i using interface %s" 58 | msgstr "连接 %i 从 %s:%i 通过接口 %s 下载" 59 | 60 | #: axel.c:249 axel.c:411 61 | msgid "pthread error!!!" 62 | msgstr "线程错误!!!" 63 | 64 | #: axel.c:317 65 | #, c-format 66 | msgid "Error on connection %i! Connection closed" 67 | msgstr "连接 %i 有错误! 连接中断" 68 | 69 | #: axel.c:331 70 | #, c-format 71 | msgid "Connection %i unexpectedly closed" 72 | msgstr "连接 %i 被异常中断" 73 | 74 | #: axel.c:335 axel.c:352 75 | #, c-format 76 | msgid "Connection %i finished" 77 | msgstr "连接 %i 结束" 78 | 79 | #: axel.c:364 80 | msgid "Write error!" 81 | msgstr "写错误!" 82 | 83 | #: axel.c:376 84 | #, c-format 85 | msgid "Connection %i timed out" 86 | msgstr "连接超时 %i" 87 | 88 | #: conf.c:107 89 | #, c-format 90 | msgid "Error in %s line %i.\n" 91 | msgstr "%s %i 行有错误。\n" 92 | 93 | #: conn.c:349 ftp.c:124 94 | #, c-format 95 | msgid "Too many redirects.\n" 96 | msgstr "太多重定向。\n" 97 | 98 | #: conn.c:368 99 | #, c-format 100 | msgid "Unknown HTTP error.\n" 101 | msgstr "未知 HTTP 错误。\n" 102 | 103 | #: ftp.c:35 http.c:60 104 | #, c-format 105 | msgid "Unable to connect to server %s:%i\n" 106 | msgstr "不能连接到服务器 %s:%i\n" 107 | 108 | #: ftp.c:91 109 | #, c-format 110 | msgid "Can't change directory to %s\n" 111 | msgstr "不能变更目录到 %s\n" 112 | 113 | #: ftp.c:117 ftp.c:177 114 | #, c-format 115 | msgid "File not found.\n" 116 | msgstr "找不到文件。\n" 117 | 118 | #: ftp.c:179 119 | #, c-format 120 | msgid "Multiple matches for this URL.\n" 121 | msgstr "这个 URL 有多个匹配。\n" 122 | 123 | #: ftp.c:250 ftp.c:256 124 | #, c-format 125 | msgid "Error opening passive data connection.\n" 126 | msgstr "打开主动数据连接错误。\n" 127 | 128 | #: ftp.c:286 129 | #, c-format 130 | msgid "Error writing command %s\n" 131 | msgstr "写命令出错 %s\n" 132 | 133 | #: ftp.c:311 http.c:150 134 | #, c-format 135 | msgid "Connection gone.\n" 136 | msgstr "连接继续。\n" 137 | 138 | #: http.c:45 139 | #, c-format 140 | msgid "Invalid proxy string: %s\n" 141 | msgstr "代理字符串无效: %s\n" 142 | 143 | #: text.c:154 144 | #, c-format 145 | msgid "Can't redirect stdout to /dev/null.\n" 146 | msgstr "stdout 不能重定向到 /dev/null 。\n" 147 | 148 | #: text.c:176 149 | #, c-format 150 | msgid "Error when trying to read URL (Too long?).\n" 151 | msgstr "" 152 | 153 | #: text.c:185 154 | #, c-format 155 | msgid "Can't handle URLs of length over %d\n" 156 | msgstr "不能处理长度超过 %d 的URLs\n" 157 | 158 | #: text.c:190 159 | #, c-format 160 | msgid "Initializing download: %s\n" 161 | msgstr "初始化下载: %s\n" 162 | 163 | #: text.c:197 164 | #, c-format 165 | msgid "Doing search...\n" 166 | msgstr "进行搜索中...\n" 167 | 168 | #: text.c:201 169 | #, c-format 170 | msgid "File not found\n" 171 | msgstr "文件找不到\n" 172 | 173 | #: text.c:205 174 | #, c-format 175 | msgid "Testing speeds, this can take a while...\n" 176 | msgstr "c测试速度,这可能有点费时……\n" 177 | 178 | #: text.c:210 179 | #, c-format 180 | msgid "%i usable servers found, will use these URLs:\n" 181 | msgstr "%i 可用的服务器没有找到,将使用这些 URLs :\n" 182 | 183 | #: text.c:269 184 | #, c-format 185 | msgid "Filename too long!\n" 186 | msgstr "" 187 | 188 | #: text.c:281 189 | #, c-format 190 | msgid "No state file, cannot resume!\n" 191 | msgstr "没有状态文件,无法恢复!\n" 192 | 193 | #: text.c:286 194 | #, c-format 195 | msgid "State file found, but no downloaded data. Starting from scratch.\n" 196 | msgstr "找到状态文件,但没有已下载数据。重新开始。\n" 197 | 198 | #: text.c:417 199 | #, c-format 200 | msgid "" 201 | "\n" 202 | "Downloaded %s in %s. (%.2f KB/s)\n" 203 | msgstr "" 204 | "\n" 205 | "%s 已下载,用时 %s。(%.2f 千字节/秒)\n" 206 | 207 | #: text.c:439 208 | #, fuzzy, c-format 209 | msgid "%lld byte" 210 | msgstr "%i 字节" 211 | 212 | #: text.c:441 213 | #, fuzzy, c-format 214 | msgid "%lld bytes" 215 | msgstr "%i 字节" 216 | 217 | #: text.c:443 218 | #, c-format 219 | msgid "%.1f kilobytes" 220 | msgstr "%.1f 千字节" 221 | 222 | #: text.c:445 223 | #, c-format 224 | msgid "%.1f megabytes" 225 | msgstr "%.1f 兆字节" 226 | 227 | #: text.c:454 228 | #, c-format 229 | msgid "%i second" 230 | msgstr "%i 秒" 231 | 232 | #: text.c:456 233 | #, c-format 234 | msgid "%i seconds" 235 | msgstr "%i 秒" 236 | 237 | #: text.c:458 238 | #, c-format 239 | msgid "%i:%02i seconds" 240 | msgstr "%i:%02i 秒" 241 | 242 | #: text.c:460 243 | #, c-format 244 | msgid "%i:%02i:%02i seconds" 245 | msgstr "%i:%02i:%02i 秒" 246 | 247 | #: text.c:540 248 | #, fuzzy, c-format 249 | msgid "" 250 | "Usage: axel [options] url1 [url2] [url...]\n" 251 | "\n" 252 | "-s x\tSpecify maximum speed (bytes per second)\n" 253 | "-n x\tSpecify maximum number of connections\n" 254 | "-o f\tSpecify local output file\n" 255 | "-S [x]\tSearch for mirrors and download from x servers\n" 256 | "-H x\tAdd header string\n" 257 | "-U x\tSet user agent\n" 258 | "-N\tJust don't use any proxy server\n" 259 | "-q\tLeave stdout alone\n" 260 | "-v\tMore status information\n" 261 | "-a\tAlternate progress indicator\n" 262 | "-h\tThis information\n" 263 | "-V\tVersion information\n" 264 | "\n" 265 | "Visit http://axel.alioth.debian.org/ to report bugs\n" 266 | msgstr "" 267 | "用法: axel [选项] 地址1 [地址2] [地址...]\n" 268 | "\n" 269 | "-s x\t指定最大速率(字节 / 秒)\n" 270 | "-n x\t指定最大连接数\n" 271 | "-o f\t指定本地输出文件\n" 272 | "-S [x]\t搜索镜像并从 X 服务器下载\n" 273 | "-N\t不使用任何代理服务器\n" 274 | "-q\t使用输出简单信息模式\n" 275 | "-v\t更多状态信息\n" 276 | "-a\t文本式进度指示器\n" 277 | "-h\t帮助信息\n" 278 | "-V\t版本信息\n" 279 | "\n" 280 | "请向 shuge.lee@gmail.com 提交翻译错误,请向 http://axel.alioth.debian.org/ 提" 281 | "交程序漏洞\n" 282 | 283 | #: text.c:557 284 | #, fuzzy, c-format 285 | msgid "" 286 | "Usage: axel [options] url1 [url2] [url...]\n" 287 | "\n" 288 | "--max-speed=x\t\t-s x\tSpecify maximum speed (bytes per second)\n" 289 | "--num-connections=x\t-n x\tSpecify maximum number of connections\n" 290 | "--output=f\t\t-o f\tSpecify local output file\n" 291 | "--search[=x]\t\t-S [x]\tSearch for mirrors and download from x servers\n" 292 | "--header=x\t\t-H x\tAdd header string\n" 293 | "--user-agent=x\t\t-U x\tSet user agent\n" 294 | "--no-proxy\t\t-N\tJust don't use any proxy server\n" 295 | "--quiet\t\t\t-q\tLeave stdout alone\n" 296 | "--verbose\t\t-v\tMore status information\n" 297 | "--alternate\t\t-a\tAlternate progress indicator\n" 298 | "--help\t\t\t-h\tThis information\n" 299 | "--version\t\t-V\tVersion information\n" 300 | "\n" 301 | "Visit http://axel.alioth.debian.org/ to report bugs\n" 302 | msgstr "" 303 | "用法: axel [选项] 地址1 [地址2] [地址...]\n" 304 | "\n" 305 | "--max-speed=x\t\t-s x\t指定最大速率(字节 / 秒)\n" 306 | "--num-connections=x\t-n x\t指定最大连接数\n" 307 | "--output=f\t\t-o f\t指定本地输出文件\n" 308 | "--search[=x]\t\t-S [x]\t搜索镜像并从 X 服务器下载\n" 309 | "--no-proxy\t\t-N\t不使用任何代理服务器\n" 310 | "--quiet\t\t\t-q\t使用输出简单信息模式\n" 311 | "--verbose\t\t-v\t更多状态信息\n" 312 | "--alternate\t\t-a\t文本式进度指示器\n" 313 | "--help\t\t\t-h\t帮助信息\n" 314 | "--version\t\t-V\t版本信息\n" 315 | "\n" 316 | "请向 shuge.lee@gmail.com 提交翻译错误,请向 http://axel.alioth.debian.org/ 提" 317 | "交程序漏洞\n" 318 | 319 | #: text.c:578 320 | #, c-format 321 | msgid "Axel version %s (%s)\n" 322 | msgstr "Axel 版本 %s (%s)\n" 323 | -------------------------------------------------------------------------------- /nl.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: Axel\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: 2009-04-02 00:04+0200\n" 6 | "PO-Revision-Date: 2001-11-14 15:22+0200\n" 7 | "Last-Translator: Wilmer van der Gaast \n" 8 | "Language-Team: Dutch \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=iso-8859-1\n" 11 | "Content-Transfer-Encoding: 8-bit\n" 12 | 13 | #: axel.c:55 14 | msgid "Buffer resized for this speed." 15 | msgstr "Buffer verkleind voor deze snelheid." 16 | 17 | #: axel.c:91 18 | msgid "Could not parse URL.\n" 19 | msgstr "Kan URL niet verwerken.\n" 20 | 21 | #: axel.c:126 22 | #, fuzzy, c-format 23 | msgid "File size: %lld bytes" 24 | msgstr "Bestandsgrootte: %i bytes" 25 | 26 | #: axel.c:143 27 | #, c-format 28 | msgid "Opening output file %s" 29 | msgstr "Openen uitvoerbestand %s" 30 | 31 | #: axel.c:152 32 | msgid "Server unsupported, starting from scratch with one connection." 33 | msgstr "Server niet ondersteund, opnieuw beginnen met 1 verbinding." 34 | 35 | #: axel.c:171 36 | #, fuzzy, c-format 37 | msgid "State file found: %lld bytes downloaded, %lld to go." 38 | msgstr ".st bestand gevonden: %i bytes gedownload, %i te gaan." 39 | 40 | #: axel.c:178 axel.c:190 41 | msgid "Error opening local file" 42 | msgstr "Fout bij openen lokaal bestand" 43 | 44 | #: axel.c:202 45 | msgid "Crappy filesystem/OS.. Working around. :-(" 46 | msgstr "Niet-fatale fout in OS/bestandssysteem, omheen werken.." 47 | 48 | #: axel.c:235 49 | msgid "Starting download" 50 | msgstr "Begin download" 51 | 52 | #: axel.c:242 axel.c:401 53 | #, c-format 54 | msgid "Connection %i downloading from %s:%i using interface %s" 55 | msgstr "Verbinding %i gebruikt server %s:%i via interface %s" 56 | 57 | #: axel.c:249 axel.c:411 58 | msgid "pthread error!!!" 59 | msgstr "pthread fout!!!" 60 | 61 | #: axel.c:317 62 | #, c-format 63 | msgid "Error on connection %i! Connection closed" 64 | msgstr "Fout op verbinding %i! Verbinding gesloten" 65 | 66 | #: axel.c:331 67 | #, c-format 68 | msgid "Connection %i unexpectedly closed" 69 | msgstr "Verbinding %i onverwachts gesloten" 70 | 71 | #: axel.c:335 axel.c:352 72 | #, c-format 73 | msgid "Connection %i finished" 74 | msgstr "Verbinding %i klaar" 75 | 76 | #: axel.c:364 77 | msgid "Write error!" 78 | msgstr "Schrijffout!" 79 | 80 | #: axel.c:376 81 | #, c-format 82 | msgid "Connection %i timed out" 83 | msgstr "Time-out op verbinding %i" 84 | 85 | #: conf.c:107 86 | #, c-format 87 | msgid "Error in %s line %i.\n" 88 | msgstr "Fout in %s regel %i.\n" 89 | 90 | #: conn.c:349 ftp.c:124 91 | #, c-format 92 | msgid "Too many redirects.\n" 93 | msgstr "Te veel redirects.\n" 94 | 95 | #: conn.c:368 96 | #, c-format 97 | msgid "Unknown HTTP error.\n" 98 | msgstr "Onbekende HTTP fout.\n" 99 | 100 | #: ftp.c:35 http.c:60 101 | #, c-format 102 | msgid "Unable to connect to server %s:%i\n" 103 | msgstr "Kan niet verbinden met server %s:%i\n" 104 | 105 | #: ftp.c:91 106 | #, c-format 107 | msgid "Can't change directory to %s\n" 108 | msgstr "" 109 | 110 | #: ftp.c:117 ftp.c:177 111 | #, c-format 112 | msgid "File not found.\n" 113 | msgstr "Bestand niet gevonden.\n" 114 | 115 | #: ftp.c:179 116 | #, c-format 117 | msgid "Multiple matches for this URL.\n" 118 | msgstr "Meerdere bestanden passen bij deze URL.\n" 119 | 120 | #: ftp.c:250 ftp.c:256 121 | #, c-format 122 | msgid "Error opening passive data connection.\n" 123 | msgstr "Fout bij het openen van een data verbinding.\n" 124 | 125 | #: ftp.c:286 126 | #, c-format 127 | msgid "Error writing command %s\n" 128 | msgstr "Fout bij het schrijven van commando %s\n" 129 | 130 | #: ftp.c:311 http.c:150 131 | #, c-format 132 | msgid "Connection gone.\n" 133 | msgstr "Verbinding gesloten.\n" 134 | 135 | #: http.c:45 136 | #, c-format 137 | msgid "Invalid proxy string: %s\n" 138 | msgstr "Ongeldige proxy string: %s\n" 139 | 140 | #: text.c:154 141 | #, c-format 142 | msgid "Can't redirect stdout to /dev/null.\n" 143 | msgstr "Fout bij het afsluiten van stdout.\n" 144 | 145 | #: text.c:176 146 | #, c-format 147 | msgid "Error when trying to read URL (Too long?).\n" 148 | msgstr "" 149 | 150 | #: text.c:185 151 | #, c-format 152 | msgid "Can't handle URLs of length over %d\n" 153 | msgstr "" 154 | 155 | #: text.c:190 156 | #, c-format 157 | msgid "Initializing download: %s\n" 158 | msgstr "Begin download: %s\n" 159 | 160 | #: text.c:197 161 | #, c-format 162 | msgid "Doing search...\n" 163 | msgstr "Zoeken...\n" 164 | 165 | #: text.c:201 166 | #, c-format 167 | msgid "File not found\n" 168 | msgstr "Bestand niet gevonden\n" 169 | 170 | #: text.c:205 171 | #, c-format 172 | msgid "Testing speeds, this can take a while...\n" 173 | msgstr "Snelheden testen, dit kan even duren...\n" 174 | 175 | #: text.c:210 176 | #, c-format 177 | msgid "%i usable servers found, will use these URLs:\n" 178 | msgstr "%i bruikbare servers gevonden, de volgende worden gebruikt:\n" 179 | 180 | #: text.c:269 181 | #, c-format 182 | msgid "Filename too long!\n" 183 | msgstr "" 184 | 185 | #: text.c:281 186 | #, c-format 187 | msgid "No state file, cannot resume!\n" 188 | msgstr "Geen .st bestand, kan niet resumen!\n" 189 | 190 | #: text.c:286 191 | #, c-format 192 | msgid "State file found, but no downloaded data. Starting from scratch.\n" 193 | msgstr ".st bestand gevonden maar geen uitvoerbestand. Opnieuw beginnen.\n" 194 | 195 | #: text.c:417 196 | #, c-format 197 | msgid "" 198 | "\n" 199 | "Downloaded %s in %s. (%.2f KB/s)\n" 200 | msgstr "" 201 | "\n" 202 | "%s gedownload in %s. (%.2f KB/s)\n" 203 | 204 | #: text.c:439 205 | #, fuzzy, c-format 206 | msgid "%lld byte" 207 | msgstr "%i byte" 208 | 209 | #: text.c:441 210 | #, fuzzy, c-format 211 | msgid "%lld bytes" 212 | msgstr "%i bytes" 213 | 214 | #: text.c:443 215 | #, c-format 216 | msgid "%.1f kilobytes" 217 | msgstr "%.1f kilobytes" 218 | 219 | #: text.c:445 220 | #, c-format 221 | msgid "%.1f megabytes" 222 | msgstr "%.1f megabytes" 223 | 224 | #: text.c:454 225 | #, c-format 226 | msgid "%i second" 227 | msgstr "%i seconde" 228 | 229 | #: text.c:456 230 | #, c-format 231 | msgid "%i seconds" 232 | msgstr "%i seconden" 233 | 234 | #: text.c:458 235 | #, c-format 236 | msgid "%i:%02i seconds" 237 | msgstr "%i:%02i seconden" 238 | 239 | #: text.c:460 240 | #, c-format 241 | msgid "%i:%02i:%02i seconds" 242 | msgstr "%i:%02i:%02i seconden" 243 | 244 | #: text.c:540 245 | #, fuzzy, c-format 246 | msgid "" 247 | "Usage: axel [options] url1 [url2] [url...]\n" 248 | "\n" 249 | "-s x\tSpecify maximum speed (bytes per second)\n" 250 | "-n x\tSpecify maximum number of connections\n" 251 | "-o f\tSpecify local output file\n" 252 | "-S [x]\tSearch for mirrors and download from x servers\n" 253 | "-H x\tAdd header string\n" 254 | "-U x\tSet user agent\n" 255 | "-N\tJust don't use any proxy server\n" 256 | "-q\tLeave stdout alone\n" 257 | "-v\tMore status information\n" 258 | "-a\tAlternate progress indicator\n" 259 | "-h\tThis information\n" 260 | "-V\tVersion information\n" 261 | "\n" 262 | "Visit http://axel.alioth.debian.org/ to report bugs\n" 263 | msgstr "" 264 | "Gebruik: axel [opties] url1 [url2] [url...]\n" 265 | "\n" 266 | "-s x\tMaximale snelheid (bytes per seconde)\n" 267 | "-n x\tMaximale aantal verbindingen\n" 268 | "-o f\tLokaal uitvoerbestand\n" 269 | "-S [x]\tMirrors opzoeken en x mirrors gebruiken\n" 270 | "-N\tGeen proxy server gebruiken\n" 271 | "-q\tGeen uitvoer naar stdout\n" 272 | "-v\tMeer status informatie\n" 273 | "-a\tAlternatieve voortgangs indicator\n" 274 | "-h\tDeze informatie\n" 275 | "-V\tVersie informatie\n" 276 | "\n" 277 | "Bugs melden aan lintux@lintux.cx\n" 278 | 279 | #: text.c:557 280 | #, fuzzy, c-format 281 | msgid "" 282 | "Usage: axel [options] url1 [url2] [url...]\n" 283 | "\n" 284 | "--max-speed=x\t\t-s x\tSpecify maximum speed (bytes per second)\n" 285 | "--num-connections=x\t-n x\tSpecify maximum number of connections\n" 286 | "--output=f\t\t-o f\tSpecify local output file\n" 287 | "--search[=x]\t\t-S [x]\tSearch for mirrors and download from x servers\n" 288 | "--header=x\t\t-H x\tAdd header string\n" 289 | "--user-agent=x\t\t-U x\tSet user agent\n" 290 | "--no-proxy\t\t-N\tJust don't use any proxy server\n" 291 | "--quiet\t\t\t-q\tLeave stdout alone\n" 292 | "--verbose\t\t-v\tMore status information\n" 293 | "--alternate\t\t-a\tAlternate progress indicator\n" 294 | "--help\t\t\t-h\tThis information\n" 295 | "--version\t\t-V\tVersion information\n" 296 | "\n" 297 | "Visit http://axel.alioth.debian.org/ to report bugs\n" 298 | msgstr "" 299 | "Gebruik: axel [opties] url1 [url2] [url...]\n" 300 | "\n" 301 | "--max-speed=x\t\t-s x\tMaximale snelheid (bytes per seconde)\n" 302 | "--num-connections=x\t-n x\tMaximale aantal verbindingen\n" 303 | "--output=f\t\t-o f\tLokaal uitvoerbestand\n" 304 | "--search[=x]\t\t-S [x]\tMirrors opzoeken en x mirrors gebruiken\n" 305 | "--no-proxy\t\t-N\tGeen proxy server gebruiken\n" 306 | "--quiet\t\t\t-q\tGeen uitvoer naar stdout\n" 307 | "--verbose\t\t-v\tMeer status informatie\n" 308 | "--alternate\t\t-a\tAlternatieve voortgangs indicator\n" 309 | "--help\t\t\t-h\tDeze informatie\n" 310 | "--version\t\t-V\tVersie informatie\n" 311 | "\n" 312 | "Bugs melden aan lintux@lintux.cx\n" 313 | 314 | #: text.c:578 315 | #, c-format 316 | msgid "Axel version %s (%s)\n" 317 | msgstr "Axel versie %s (%s)\n" 318 | -------------------------------------------------------------------------------- /ru.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: Axel\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: 2009-04-02 00:05+0200\n" 6 | "PO-Revision-Date: 2009-04-02 00:05+0200\n" 7 | "Last-Translator: newhren \n" 8 | "Language-Team: Russian \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=utf-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | 13 | #: axel.c:55 14 | msgid "Buffer resized for this speed." 15 | msgstr "Размер буфера изменен для этой скорости." 16 | 17 | #: axel.c:91 18 | msgid "Could not parse URL.\n" 19 | msgstr "Невозможно обработать URL.\n" 20 | 21 | #: axel.c:126 22 | #, c-format 23 | msgid "File size: %lld bytes" 24 | msgstr "Размер файла: %lld байта(ов)" 25 | 26 | #: axel.c:143 27 | #, c-format 28 | msgid "Opening output file %s" 29 | msgstr "Открывается выходной файл %s" 30 | 31 | #: axel.c:152 32 | msgid "Server unsupported, starting from scratch with one connection." 33 | msgstr "Сервер не поддерживается, начинаем заново с одним соединением." 34 | 35 | #: axel.c:171 36 | #, c-format 37 | msgid "State file found: %lld bytes downloaded, %lld to go." 38 | msgstr "Найден файл состояния: %lld байта(ов) скачано, %lld осталось." 39 | 40 | #: axel.c:178 axel.c:190 41 | msgid "Error opening local file" 42 | msgstr "Ошибка при открытии локального файла" 43 | 44 | #: axel.c:202 45 | msgid "Crappy filesystem/OS.. Working around. :-(" 46 | msgstr "" 47 | "Ошибки в файловой системе или операционной системе.. Пробуем исправить :-(" 48 | 49 | #: axel.c:235 50 | msgid "Starting download" 51 | msgstr "Начинаем скачивание" 52 | 53 | #: axel.c:242 axel.c:401 54 | #, c-format 55 | msgid "Connection %i downloading from %s:%i using interface %s" 56 | msgstr "Соединение %i скачивает с %s:%i через интерфейс %s" 57 | 58 | #: axel.c:249 axel.c:411 59 | msgid "pthread error!!!" 60 | msgstr "ошибка pthread!!!" 61 | 62 | #: axel.c:317 63 | #, c-format 64 | msgid "Error on connection %i! Connection closed" 65 | msgstr "Ошибка в соединении %i! Соединение закрыто" 66 | 67 | #: axel.c:331 68 | #, c-format 69 | msgid "Connection %i unexpectedly closed" 70 | msgstr "Соединение %i неожиданно закрылось" 71 | 72 | #: axel.c:335 axel.c:352 73 | #, c-format 74 | msgid "Connection %i finished" 75 | msgstr "Соединение %i закончилось" 76 | 77 | #: axel.c:364 78 | msgid "Write error!" 79 | msgstr "Ошибка записи!" 80 | 81 | #: axel.c:376 82 | #, c-format 83 | msgid "Connection %i timed out" 84 | msgstr "Время соединения %i вышло" 85 | 86 | #: conf.c:107 87 | #, c-format 88 | msgid "Error in %s line %i.\n" 89 | msgstr "Ошибка в файле %s линия %i.\n" 90 | 91 | #: conn.c:349 ftp.c:124 92 | #, c-format 93 | msgid "Too many redirects.\n" 94 | msgstr "Слишком много перенаправлений.\n" 95 | 96 | #: conn.c:368 97 | #, c-format 98 | msgid "Unknown HTTP error.\n" 99 | msgstr "Неизвестная ошибка HTTP.\n" 100 | 101 | #: ftp.c:35 http.c:60 102 | #, c-format 103 | msgid "Unable to connect to server %s:%i\n" 104 | msgstr "Невозможно подсоединиться к серверу %s:%i\n" 105 | 106 | #: ftp.c:91 107 | #, c-format 108 | msgid "Can't change directory to %s\n" 109 | msgstr "Невозможно сменить директорию на %s\n" 110 | 111 | #: ftp.c:117 ftp.c:177 112 | #, c-format 113 | msgid "File not found.\n" 114 | msgstr "Файл не найден.\n" 115 | 116 | #: ftp.c:179 117 | #, c-format 118 | msgid "Multiple matches for this URL.\n" 119 | msgstr "Несколько совпадений для этого URL.\n" 120 | 121 | #: ftp.c:250 ftp.c:256 122 | #, c-format 123 | msgid "Error opening passive data connection.\n" 124 | msgstr "Ошибка открытия пассивного соединения.\n" 125 | 126 | #: ftp.c:286 127 | #, c-format 128 | msgid "Error writing command %s\n" 129 | msgstr "Ошибка записи команды %s\n" 130 | 131 | #: ftp.c:311 http.c:150 132 | #, c-format 133 | msgid "Connection gone.\n" 134 | msgstr "Соединение пропало.\n" 135 | 136 | #: http.c:45 137 | #, c-format 138 | msgid "Invalid proxy string: %s\n" 139 | msgstr "Некорректная стока прокси: %s\n" 140 | 141 | #: text.c:154 142 | #, c-format 143 | msgid "Can't redirect stdout to /dev/null.\n" 144 | msgstr "Невозможно перенаправить stdout в /dev/null.\n" 145 | 146 | #: text.c:176 147 | #, c-format 148 | msgid "Error when trying to read URL (Too long?).\n" 149 | msgstr "" 150 | 151 | #: text.c:185 152 | #, c-format 153 | msgid "Can't handle URLs of length over %d\n" 154 | msgstr "URLs длинной больше %d не поддерживаются\n" 155 | 156 | #: text.c:190 157 | #, c-format 158 | msgid "Initializing download: %s\n" 159 | msgstr "Начинаю скачивание: %s\n" 160 | 161 | #: text.c:197 162 | #, c-format 163 | msgid "Doing search...\n" 164 | msgstr "Ищем...\n" 165 | 166 | #: text.c:201 167 | #, c-format 168 | msgid "File not found\n" 169 | msgstr "Файл не найден\n" 170 | 171 | #: text.c:205 172 | #, c-format 173 | msgid "Testing speeds, this can take a while...\n" 174 | msgstr "Пробуем скорости, это может занять некоторое время...\n" 175 | 176 | #: text.c:210 177 | #, c-format 178 | msgid "%i usable servers found, will use these URLs:\n" 179 | msgstr "Найдено %i полезных серверов, будут использованы следующие URLs:\n" 180 | 181 | #: text.c:269 182 | #, c-format 183 | msgid "Filename too long!\n" 184 | msgstr "" 185 | 186 | #: text.c:281 187 | #, c-format 188 | msgid "No state file, cannot resume!\n" 189 | msgstr "Файл состояния не найден, возобновление невозможно!\n" 190 | 191 | #: text.c:286 192 | #, c-format 193 | msgid "State file found, but no downloaded data. Starting from scratch.\n" 194 | msgstr "" 195 | "Файл состояния найден, но предварительно скачанные данные отсутствуют. " 196 | "Начинаем заново.\n" 197 | 198 | #: text.c:417 199 | #, c-format 200 | msgid "" 201 | "\n" 202 | "Downloaded %s in %s. (%.2f KB/s)\n" 203 | msgstr "" 204 | "\n" 205 | "%s скачано за %s. (%.2f КБ/с)\n" 206 | 207 | #: text.c:439 208 | #, c-format 209 | msgid "%lld byte" 210 | msgstr "%lld байт" 211 | 212 | #: text.c:441 213 | #, c-format 214 | msgid "%lld bytes" 215 | msgstr "%lld байта(ов)" 216 | 217 | #: text.c:443 218 | #, c-format 219 | msgid "%.1f kilobytes" 220 | msgstr "%.1f килобайта(ов)" 221 | 222 | #: text.c:445 223 | #, c-format 224 | msgid "%.1f megabytes" 225 | msgstr "%.1f мегабайта(ов)" 226 | 227 | #: text.c:454 228 | #, c-format 229 | msgid "%i second" 230 | msgstr "%i секунда" 231 | 232 | #: text.c:456 233 | #, c-format 234 | msgid "%i seconds" 235 | msgstr "%i секунд(ы)" 236 | 237 | #: text.c:458 238 | #, c-format 239 | msgid "%i:%02i seconds" 240 | msgstr "%i:%02i секунд(ы)" 241 | 242 | #: text.c:460 243 | #, c-format 244 | msgid "%i:%02i:%02i seconds" 245 | msgstr "%i:%02i:%02i секунд(ы)" 246 | 247 | #: text.c:540 248 | #, fuzzy, c-format 249 | msgid "" 250 | "Usage: axel [options] url1 [url2] [url...]\n" 251 | "\n" 252 | "-s x\tSpecify maximum speed (bytes per second)\n" 253 | "-n x\tSpecify maximum number of connections\n" 254 | "-o f\tSpecify local output file\n" 255 | "-S [x]\tSearch for mirrors and download from x servers\n" 256 | "-H x\tAdd header string\n" 257 | "-U x\tSet user agent\n" 258 | "-N\tJust don't use any proxy server\n" 259 | "-q\tLeave stdout alone\n" 260 | "-v\tMore status information\n" 261 | "-a\tAlternate progress indicator\n" 262 | "-h\tThis information\n" 263 | "-V\tVersion information\n" 264 | "\n" 265 | "Visit http://axel.alioth.debian.org/ to report bugs\n" 266 | msgstr "" 267 | "Использование: axel [опции] url1 [url2] [url...]\n" 268 | "\n" 269 | "-s x\tМаксимальная скорость (байт в секунду)\n" 270 | "-n x\tМаксимальное число соединений\n" 271 | "-o f\tЛокальный выходной файл\n" 272 | "-S [x]\tПоискать зеркала и скачивать с x серверов\n" 273 | "-N\tНе использовать прокси-сервера\n" 274 | "-q\tНичего не выводить на stdout\n" 275 | "-v\tБольше информации о статусе\n" 276 | "-a\tАльтернативный индикатор прогресса\n" 277 | "-h\tЭта информация\n" 278 | "-V\tИнформация о версии\n" 279 | "\n" 280 | "Об ошибках сообщайте на http://axel.alioth.debian.org/\n" 281 | 282 | #: text.c:557 283 | #, fuzzy, c-format 284 | msgid "" 285 | "Usage: axel [options] url1 [url2] [url...]\n" 286 | "\n" 287 | "--max-speed=x\t\t-s x\tSpecify maximum speed (bytes per second)\n" 288 | "--num-connections=x\t-n x\tSpecify maximum number of connections\n" 289 | "--output=f\t\t-o f\tSpecify local output file\n" 290 | "--search[=x]\t\t-S [x]\tSearch for mirrors and download from x servers\n" 291 | "--header=x\t\t-H x\tAdd header string\n" 292 | "--user-agent=x\t\t-U x\tSet user agent\n" 293 | "--no-proxy\t\t-N\tJust don't use any proxy server\n" 294 | "--quiet\t\t\t-q\tLeave stdout alone\n" 295 | "--verbose\t\t-v\tMore status information\n" 296 | "--alternate\t\t-a\tAlternate progress indicator\n" 297 | "--help\t\t\t-h\tThis information\n" 298 | "--version\t\t-V\tVersion information\n" 299 | "\n" 300 | "Visit http://axel.alioth.debian.org/ to report bugs\n" 301 | msgstr "" 302 | "Использование: axel [опции] url1 [url2] [url...]\n" 303 | "\n" 304 | "--max-speed=x\t\t-s x\tМаксимальная скорость (байт в секунду)\n" 305 | "--num-connections=x\t-n x\tМаксимальное число соединений\n" 306 | "--output=f\t\t-o f\tЛокальный выходной файл\n" 307 | "--search[=x]\t\t-S [x]\tПоискать зеркала и скачивать с x серверов\n" 308 | "--no-proxy\t\t-N\tНе использовать прокси-сервера\n" 309 | "--quiet\t\t\t-q\tНичего не выводить на stdout\n" 310 | "--verbose\t\t-v\tБольше информации о статусе\n" 311 | "--alternate\t\t-a\tАльтернативный индикатор прогресса\n" 312 | "--help\t\t\t-h\tЭта информация\n" 313 | "--version\t\t-V\tИнформация о версии\n" 314 | "\n" 315 | "Об ошибках сообщайте на http://axel.alioth.debian.org/\n" 316 | 317 | #: text.c:578 318 | #, c-format 319 | msgid "Axel version %s (%s)\n" 320 | msgstr "Axel, версия %s (%s)\n" 321 | -------------------------------------------------------------------------------- /ftp.c: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* FTP control file */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #include "axel.h" 27 | 28 | int ftp_connect( ftp_t *conn, char *host, int port, char *user, char *pass ) 29 | { 30 | conn->data_fd = -1; 31 | conn->message = malloc( MAX_STRING ); 32 | 33 | if( ( conn->fd = tcp_connect( host, port, conn->local_if ) ) == -1 ) 34 | { 35 | sprintf( conn->message, _("Unable to connect to server %s:%i\n"), host, port ); 36 | return( 0 ); 37 | } 38 | 39 | if( ftp_wait( conn ) / 100 != 2 ) 40 | return( 0 ); 41 | 42 | ftp_command( conn, "USER %s", user ); 43 | if( ftp_wait( conn ) / 100 != 2 ) 44 | { 45 | if( conn->status / 100 == 3 ) 46 | { 47 | ftp_command( conn, "PASS %s", pass ); 48 | if( ftp_wait( conn ) / 100 != 2 ) 49 | return( 0 ); 50 | } 51 | else 52 | { 53 | return( 0 ); 54 | } 55 | } 56 | 57 | /* ASCII mode sucks. Just use Binary.. */ 58 | ftp_command( conn, "TYPE I" ); 59 | if( ftp_wait( conn ) / 100 != 2 ) 60 | return( 0 ); 61 | 62 | return( 1 ); 63 | } 64 | 65 | void ftp_disconnect( ftp_t *conn ) 66 | { 67 | if( conn->fd > 0 ) 68 | close( conn->fd ); 69 | if( conn->data_fd > 0 ) 70 | close( conn->data_fd ); 71 | if( conn->message ) 72 | { 73 | free( conn->message ); 74 | conn->message = NULL; 75 | } 76 | 77 | *conn->cwd = 0; 78 | conn->fd = conn->data_fd = -1; 79 | } 80 | 81 | /* Change current working directory */ 82 | int ftp_cwd( ftp_t *conn, char *cwd ) 83 | { 84 | /* Necessary at all? */ 85 | if( strncmp( conn->cwd, cwd, MAX_STRING ) == 0 ) 86 | return( 1 ); 87 | 88 | ftp_command( conn, "CWD %s", cwd ); 89 | if( ftp_wait( conn ) / 100 != 2 ) 90 | { 91 | fprintf( stderr, _("Can't change directory to %s\n"), cwd ); 92 | return( 0 ); 93 | } 94 | 95 | strncpy( conn->cwd, cwd, MAX_STRING ); 96 | 97 | return( 1 ); 98 | } 99 | 100 | /* Get file size. Should work with all reasonable servers now */ 101 | long long int ftp_size( ftp_t *conn, char *file, int maxredir ) 102 | { 103 | long long int i, j, size = MAX_STRING; 104 | char *reply, *s, fn[MAX_STRING]; 105 | 106 | /* Try the SIZE command first, if possible */ 107 | if( !strchr( file, '*' ) && !strchr( file, '?' ) ) 108 | { 109 | ftp_command( conn, "SIZE %s", file ); 110 | if( ftp_wait( conn ) / 100 == 2 ) 111 | { 112 | sscanf( conn->message, "%*i %lld", &i ); 113 | return( i ); 114 | } 115 | else if( conn->status / 10 != 50 ) 116 | { 117 | sprintf( conn->message, _("File not found.\n") ); 118 | return( -1 ); 119 | } 120 | } 121 | 122 | if( maxredir == 0 ) 123 | { 124 | sprintf( conn->message, _("Too many redirects.\n") ); 125 | return( -1 ); 126 | } 127 | 128 | if( !ftp_data( conn ) ) 129 | return( -1 ); 130 | 131 | ftp_command( conn, "LIST %s", file ); 132 | if( ftp_wait( conn ) / 100 != 1 ) 133 | return( -1 ); 134 | 135 | /* Read reply from the server. */ 136 | reply = malloc( size ); 137 | memset( reply, 0, size ); 138 | *reply = '\n'; 139 | i = 1; 140 | while( ( j = read( conn->data_fd, reply + i, size - i - 3 ) ) > 0 ) 141 | { 142 | i += j; 143 | reply[i] = 0; 144 | if( size - i <= 10 ) 145 | { 146 | size *= 2; 147 | reply = realloc( reply, size ); 148 | memset( reply + size / 2, 0, size / 2 ); 149 | } 150 | } 151 | close( conn->data_fd ); 152 | conn->data_fd = -1; 153 | 154 | if( ftp_wait( conn ) / 100 != 2 ) 155 | { 156 | free( reply ); 157 | return( -1 ); 158 | } 159 | 160 | #ifdef DEBUG 161 | fprintf( stderr, reply ); 162 | #endif 163 | 164 | /* Count the number of probably legal matches: Files&Links only */ 165 | j = 0; 166 | for( i = 1; reply[i] && reply[i+1]; i ++ ) 167 | if( reply[i] == '-' || reply[i] == 'l' ) 168 | j ++; 169 | else 170 | while( reply[i] != '\n' && reply[i] ) 171 | i ++; 172 | 173 | /* No match or more than one match */ 174 | if( j != 1 ) 175 | { 176 | if( j == 0 ) 177 | sprintf( conn->message, _("File not found.\n") ); 178 | else 179 | sprintf( conn->message, _("Multiple matches for this URL.\n") ); 180 | free( reply ); 181 | return( -1 ); 182 | } 183 | 184 | /* Symlink handling */ 185 | if( ( s = strstr( reply, "\nl" ) ) != NULL ) 186 | { 187 | /* Get the real filename */ 188 | sscanf( s, "%*s %*i %*s %*s %*i %*s %*i %*s %100s", fn ); 189 | strcpy( file, fn ); 190 | 191 | /* Get size of the file linked to */ 192 | strncpy( fn, strstr( s, "->" ) + 3, MAX_STRING ); 193 | free( reply ); 194 | if( ( reply = strchr( fn, '\r' ) ) != NULL ) 195 | *reply = 0; 196 | if( ( reply = strchr( fn, '\n' ) ) != NULL ) 197 | *reply = 0; 198 | return( ftp_size( conn, fn, maxredir - 1 ) ); 199 | } 200 | /* Normal file, so read the size! And read filename because of 201 | possible wildcards. */ 202 | else 203 | { 204 | s = strstr( reply, "\n-" ); 205 | i = sscanf( s, "%*s %*i %*s %*s %lld %*s %*i %*s %100s", &size, fn ); 206 | if( i < 2 ) 207 | { 208 | i = sscanf( s, "%*s %*i %lld %*i %*s %*i %*i %100s", &size, fn ); 209 | if( i < 2 ) 210 | { 211 | return( -2 ); 212 | } 213 | } 214 | strcpy( file, fn ); 215 | 216 | free( reply ); 217 | return( size ); 218 | } 219 | } 220 | 221 | /* Open a data connection. Only Passive mode supported yet, easier.. */ 222 | int ftp_data( ftp_t *conn ) 223 | { 224 | int i, info[6]; 225 | char host[MAX_STRING]; 226 | 227 | /* Already done? */ 228 | if( conn->data_fd > 0 ) 229 | return( 0 ); 230 | 231 | /* if( conn->ftp_mode == FTP_PASSIVE ) 232 | { 233 | */ ftp_command( conn, "PASV" ); 234 | if( ftp_wait( conn ) / 100 != 2 ) 235 | return( 0 ); 236 | *host = 0; 237 | for( i = 0; conn->message[i]; i ++ ) 238 | { 239 | if( sscanf( &conn->message[i], "%i,%i,%i,%i,%i,%i", 240 | &info[0], &info[1], &info[2], &info[3], 241 | &info[4], &info[5] ) == 6 ) 242 | { 243 | sprintf( host, "%i.%i.%i.%i", 244 | info[0], info[1], info[2], info[3] ); 245 | break; 246 | } 247 | } 248 | if( !*host ) 249 | { 250 | sprintf( conn->message, _("Error opening passive data connection.\n") ); 251 | return( 0 ); 252 | } 253 | if( ( conn->data_fd = tcp_connect( host, 254 | info[4] * 256 + info[5], conn->local_if ) ) == -1 ) 255 | { 256 | sprintf( conn->message, _("Error opening passive data connection.\n") ); 257 | return( 0 ); 258 | } 259 | 260 | return( 1 ); 261 | /* } 262 | else 263 | { 264 | sprintf( conn->message, _("Active FTP not implemented yet.\n" ) ); 265 | return( 0 ); 266 | } */ 267 | } 268 | 269 | /* Send a command to the server */ 270 | int ftp_command( ftp_t *conn, char *format, ... ) 271 | { 272 | va_list params; 273 | char cmd[MAX_STRING]; 274 | 275 | va_start( params, format ); 276 | vsnprintf( cmd, MAX_STRING - 3, format, params ); 277 | strcat( cmd, "\r\n" ); 278 | va_end( params ); 279 | 280 | #ifdef DEBUG 281 | fprintf( stderr, "fd(%i)<--%s", conn->fd, cmd ); 282 | #endif 283 | 284 | if( write( conn->fd, cmd, strlen( cmd ) ) != strlen( cmd ) ) 285 | { 286 | sprintf( conn->message, _("Error writing command %s\n"), format ); 287 | return( 0 ); 288 | } 289 | else 290 | { 291 | return( 1 ); 292 | } 293 | } 294 | 295 | /* Read status from server. Should handle multi-line replies correctly. 296 | Multi-line replies suck... */ 297 | int ftp_wait( ftp_t *conn ) 298 | { 299 | int size = MAX_STRING, r = 0, complete, i, j; 300 | char *s; 301 | 302 | conn->message = realloc( conn->message, size ); 303 | 304 | do 305 | { 306 | do 307 | { 308 | r += i = read( conn->fd, conn->message + r, 1 ); 309 | if( i <= 0 ) 310 | { 311 | sprintf( conn->message, _("Connection gone.\n") ); 312 | return( -1 ); 313 | } 314 | if( ( r + 10 ) >= size ) 315 | { 316 | size += MAX_STRING; 317 | conn->message = realloc( conn->message, size ); 318 | } 319 | } 320 | while( conn->message[r-1] != '\n' ); 321 | conn->message[r] = 0; 322 | sscanf( conn->message, "%i", &conn->status ); 323 | if( conn->message[3] == ' ' ) 324 | complete = 1; 325 | else 326 | complete = 0; 327 | 328 | for( i = 0; conn->message[i]; i ++ ) if( conn->message[i] == '\n' ) 329 | { 330 | if( complete == 1 ) 331 | { 332 | complete = 2; 333 | break; 334 | } 335 | if( conn->message[i+4] == ' ' ) 336 | { 337 | j = -1; 338 | sscanf( &conn->message[i+1], "%3i", &j ); 339 | if( j == conn->status ) 340 | complete = 1; 341 | } 342 | } 343 | } 344 | while( complete != 2 ); 345 | 346 | #ifdef DEBUG 347 | fprintf( stderr, "fd(%i)-->%s", conn->fd, conn->message ); 348 | #endif 349 | 350 | if( ( s = strchr( conn->message, '\n' ) ) != NULL ) 351 | *s = 0; 352 | if( ( s = strchr( conn->message, '\r' ) ) != NULL ) 353 | *s = 0; 354 | conn->message = realloc( conn->message, max( strlen( conn->message ) + 1, MAX_STRING ) ); 355 | 356 | return( conn->status ); 357 | } 358 | -------------------------------------------------------------------------------- /API: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | 8 | /* Short API description */ 9 | 10 | Until version 0.97, a lot of Axel downloading code was 'stuck' in main(). 11 | This made the development of alternate (ie graphical) interfaces to the 12 | program quite difficult. That's why Axel 0.97 is a major redesign: All the 13 | downloading code is out of main() now. Writing your own downloader which 14 | uses Axel should not be too difficult now. 15 | 16 | This document contains basic instructions on how to write a program which 17 | uses the Axel >=0.97 code to download data. 18 | 19 | Some work needs to be done before I can convert axel into a library. I don't 20 | know whether I'll do it at all.. So this API description is only useful if 21 | you want to create an alternate interface for the program, at the moment. 22 | Later on, I might change this. A Perl port of Axel would be nice too. :-) 23 | 24 | 25 | /* The structures */ 26 | 27 | If you want to use Axel, you should have all the *.[ch] files in your 28 | program's directory (or subdir, whatever you want...) and include the axel.h 29 | file into your program. Then, the following structures and functions will be 30 | available: 31 | 32 | typedef struct 33 | { 34 | conn_t *conn; 35 | conf_t conf[1]; 36 | char filename[MAX_STRING]; 37 | double start_time; 38 | int next_state, finish_time; 39 | int bytes_done, start_byte, size; 40 | int bytes_per_second; 41 | int delay_time; 42 | int outfd; 43 | int ready; 44 | message_t *message; 45 | url_t *url; 46 | } axel_t; 47 | 48 | This is probably the most important structure.. Each axel structure can 49 | handle a separate download, each with a variable amount of connections. 50 | There is no maximum amount of connections hard-coded into the program 51 | anymore, by the way. The way conn_t and conf_t structures work is not very 52 | important for most people, it's mainly important for internal use. You /can/ 53 | use those structures, if you want, they're not that complex... 54 | 55 | The filename string is set correctly by axel_new(). If you want data to 56 | be put into a different file, you can change the variable /after/ calling 57 | axel_new(), and /before/ calling axel_open(). The string can also include 58 | a full pathname. 59 | 60 | start_time contains the time at which the download started. Not very 61 | interesting for you, probably. Neither should next_state be very important, 62 | it just contains the time at which the next state file should be saved. 63 | (State files are important for resuming support, as described in the README 64 | file..) finish_time might be interesting, though. It contains the estimated 65 | time at which the download should be finished. 66 | 67 | bytes_done contains the number of bytes downloaded for this file, size 68 | contains the total file size. start_byte should be zero, usually, unless 69 | you're resuming a download. 70 | 71 | The code also calculates the average speed. This speed is put in the 72 | bytes_per_second variable. 73 | 74 | delay_time is not interesting at all. It's just used for the code which 75 | tries to slow down the download. You shouldn't really touch outfd either, 76 | it contains the file descriptor of the local file. 77 | 78 | ready is set to non-zero as soon as all data is downloaded, or as soon as 79 | something goes wrong. You shouldn't call axel_do() anymore, when ready is 80 | set. 81 | 82 | Last but not least, message. This is a linked list of messages to the user. 83 | You, as the programmer, may decide what to do with them. You can just 84 | destroy them (don't just ignore them, the messages do eat memory!) or you 85 | can log/display them. The structure is very simple, and I hope this is clear 86 | enough: 87 | 88 | typedef struct { 89 | void *next; 90 | char text[MAX_STRING]; 91 | } message_t; 92 | 93 | Just don't forget to free() the message structures after printing them, and 94 | set axel->message to NULL to prevent crashes. See the print_messages() 95 | function in text.c for an example. 96 | 97 | message used to be the last, but I added url. It's a linked list as well, 98 | and in fact url_t == message_t. Not really of any importance, though. This 99 | element contains a number of URL's that'll be used by Axel for the download. 100 | The program can use multiple mirrors at the same time. This structure is 101 | filled in by axel_new, you shouldn't touch it yourself. 102 | 103 | 104 | /* The functions */ 105 | 106 | int conf_init( conf_t *conf ); 107 | 108 | Axel needs some settings. Your program has to allocate a conf_t structure 109 | and initialize it using this function. It sets some defaults, and then it 110 | scans your environment variables for some settings, and it tries to read 111 | a system-wide and personal user configuration file. 112 | 113 | axel_t *axel_new( conf_t *conf, char count, char *url ); 114 | axel_t *axel_new( conf_t *conf, char count, search_t *urls ); 115 | 116 | axel_new() allocates a new axel_t structure. You should pass a configuration 117 | structure and an URL. A pointer to a new axel_t structure will be returned. 118 | axel->filename is set now. You can change it, if you want data to be stored 119 | to a different file. Changing axel->filename after calling axel_open does 120 | not make sense, so be quick. :-) 121 | If you want axel to download from more than one mirror at once, you can use 122 | the second syntax. A search_t structure can be generated by the search_* 123 | functions. If you use the second syntax, count should contain the number of 124 | mirrors to be used from the structure. If you just want to pass a string 125 | with one URL (first syntax), count should be zero. Please note that all the 126 | mirrors passed to axel_new() should support acceleration. The support check 127 | should be done before downloading, which isn't much of a problem because 128 | search_getspeeds does it automatically. 129 | The ready element of the returned structure is set to one if nothing goes 130 | wrong. If it's zero, you shouldn't use the returned structure for anything 131 | else than displaying the error message(s) and closing it. 132 | 133 | int axel_open( axel_t *axel ); 134 | 135 | axel_open() opens a local file to store downloaded data. Returns non-zero if 136 | nothing goes wrong. If anything goes wrong, you should still call 137 | axel_close() to clean things up. This is not done automatically, so that you 138 | can read any message still left in the structure. 139 | 140 | void axel_start( axel_t *axel ); 141 | 142 | axel_start() starts the actual downloading. Normally, nothing should go 143 | wrong during this call, so it does not return anything. 144 | 145 | void axel_do( axel_t *axel ); 146 | 147 | axel_do() should be called regularly (ie as often as possible...) to handle 148 | any incoming data. You don't have to do anything else, all data is stored in 149 | the local file automatically. You should stop calling this one as soon as 150 | axel->ready is set. Or you can stop calling it yourself, that's possible. 151 | Just don't forget to call axel_close()! 152 | 153 | void axel_close( axel_t *axel ); 154 | 155 | If you want to stop downloading (ie if the download is complete) you should 156 | deallocate the axel_t structure using this function. Any connection still 157 | open will be closed and deallocated, all messages in the structure are 158 | deleted. You should always call this one when you're ready, if you don't 159 | want to waste memory. 160 | 161 | double gettime(); 162 | 163 | This one is just a 'bonus'... I use it myself in text.c and axel.c, so I 164 | decided to make it global. It just returns the actual time, but with more 165 | precision. 166 | 167 | 168 | /* filesearcher.com interface */ 169 | 170 | If you want to search for a faster mirror to download your file, or if you 171 | want to download from more than one server at once, you can use this 172 | interface. It's quite simple. You should create an array of this type: 173 | 174 | typedef struct 175 | { 176 | char url[MAX_STRING]; 177 | double speed_start_time; 178 | int speed, size; 179 | pthread_t speed_thread[1]; 180 | conf_t *conf; 181 | } search_t; 182 | 183 | And it's wise to memset() it to zero before you start, btw. You also have to 184 | set the conf pointer for the first index of the array. Other fields will 185 | be filled in by these functions: 186 | 187 | int search_makelist( search_t *results, char *url ); 188 | 189 | This function checks your URL, fetches the file size (needed for the search) 190 | and queries the ftpsearcher.com server for any mirror of this file. This one 191 | is finished in a few seconds on my system. It returns the number of mirrors 192 | found. Please note that, after calling this function, the first index of 193 | your search_t array contains the URL you used as an argument to this 194 | function. The speed field is filled in already for that one. 195 | 196 | int search_getspeeds( search_t *results, int count ); 197 | 198 | This is quite time consuming. It tries all the URL's from the list, and 199 | checks the speed. URL's which do not exist, or URL's on non-supported 200 | servers are marked as bad, they can't be used. This is more time-consuming 201 | than a simple ping (it takes about twenty seconds on my system, but it 202 | heavily depends on the connection and your settings), but it makes sure only 203 | usable URL's are passed to the downloader. The function returns the number 204 | of not-bad servers. 205 | 206 | void search_sortlist( search_t *results, int count ); 207 | 208 | It's very wise to sort the list of mirrors using this function before 209 | passing it to axel_new(). The fastest URL will be put on top of the list, 210 | bad URL's will be put at the bottom. Please note that count has to be the 211 | total number of servers, returned by search_makelist(), and not just the 212 | number of not-bad servers returned by search_getspeed(). 213 | -------------------------------------------------------------------------------- /conn.c: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* Connection stuff */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #include "axel.h" 27 | 28 | char string[MAX_STRING]; 29 | 30 | /* Convert an URL to a conn_t structure */ 31 | int conn_set( conn_t *conn, char *set_url ) 32 | { 33 | char url[MAX_STRING]; 34 | char *i, *j; 35 | 36 | /* protocol:// */ 37 | if( ( i = strstr( set_url, "://" ) ) == NULL ) 38 | { 39 | conn->proto = PROTO_DEFAULT; 40 | strncpy( url, set_url, MAX_STRING ); 41 | } 42 | else 43 | { 44 | if( set_url[0] == 'f' ) 45 | conn->proto = PROTO_FTP; 46 | else if( set_url[0] == 'h' ) 47 | conn->proto = PROTO_HTTP; 48 | else 49 | { 50 | return( 0 ); 51 | } 52 | strncpy( url, i + 3, MAX_STRING ); 53 | } 54 | 55 | /* Split */ 56 | if( ( i = strchr( url, '/' ) ) == NULL ) 57 | { 58 | strcpy( conn->dir, "/" ); 59 | } 60 | else 61 | { 62 | *i = 0; 63 | snprintf( conn->dir, MAX_STRING, "/%s", i + 1 ); 64 | if( conn->proto == PROTO_HTTP ) 65 | http_encode( conn->dir ); 66 | } 67 | strncpy( conn->host, url, MAX_STRING ); 68 | j = strchr( conn->dir, '?' ); 69 | if( j != NULL ) 70 | *j = 0; 71 | i = strrchr( conn->dir, '/' ); 72 | *i = 0; 73 | if( j != NULL ) 74 | *j = '?'; 75 | if( i == NULL ) 76 | { 77 | strncpy( conn->file, conn->dir, MAX_STRING ); 78 | strcpy( conn->dir, "/" ); 79 | } 80 | else 81 | { 82 | strncpy( conn->file, i + 1, MAX_STRING ); 83 | strcat( conn->dir, "/" ); 84 | } 85 | 86 | /* Check for username in host field */ 87 | if( strrchr( conn->host, '@' ) != NULL ) 88 | { 89 | strncpy( conn->user, conn->host, MAX_STRING ); 90 | i = strrchr( conn->user, '@' ); 91 | *i = 0; 92 | strncpy( conn->host, i + 1, MAX_STRING ); 93 | *conn->pass = 0; 94 | } 95 | /* If not: Fill in defaults */ 96 | else 97 | { 98 | if( conn->proto == PROTO_FTP ) 99 | { 100 | /* Dash the password: Save traffic by trying 101 | to avoid multi-line responses */ 102 | strcpy( conn->user, "anonymous" ); 103 | strcpy( conn->pass, "mailto:axel-devel@lists.alioth.debian.org" ); 104 | } 105 | else 106 | { 107 | *conn->user = *conn->pass = 0; 108 | } 109 | } 110 | 111 | /* Password? */ 112 | if( ( i = strchr( conn->user, ':' ) ) != NULL ) 113 | { 114 | *i = 0; 115 | strncpy( conn->pass, i + 1, MAX_STRING ); 116 | } 117 | /* Port number? */ 118 | if( ( i = strchr( conn->host, ':' ) ) != NULL ) 119 | { 120 | *i = 0; 121 | sscanf( i + 1, "%i", &conn->port ); 122 | } 123 | /* Take default port numbers from /etc/services */ 124 | else 125 | { 126 | #ifndef DARWIN 127 | struct servent *serv; 128 | 129 | if( conn->proto == PROTO_FTP ) 130 | serv = getservbyname( "ftp", "tcp" ); 131 | else 132 | serv = getservbyname( "www", "tcp" ); 133 | 134 | if( serv ) 135 | conn->port = ntohs( serv->s_port ); 136 | else 137 | #endif 138 | if( conn->proto == PROTO_HTTP ) 139 | conn->port = 80; 140 | else 141 | conn->port = 21; 142 | } 143 | 144 | return( conn->port > 0 ); 145 | } 146 | 147 | /* Generate a nice URL string. */ 148 | char *conn_url( conn_t *conn ) 149 | { 150 | if( conn->proto == PROTO_FTP ) 151 | strcpy( string, "ftp://" ); 152 | else 153 | strcpy( string, "http://" ); 154 | 155 | if( *conn->user != 0 && strcmp( conn->user, "anonymous" ) != 0 ) 156 | sprintf( string + strlen( string ), "%s:%s@", 157 | conn->user, conn->pass ); 158 | 159 | sprintf( string + strlen( string ), "%s:%i%s%s", 160 | conn->host, conn->port, conn->dir, conn->file ); 161 | 162 | return( string ); 163 | } 164 | 165 | /* Simple... */ 166 | void conn_disconnect( conn_t *conn ) 167 | { 168 | if( conn->proto == PROTO_FTP && !conn->proxy ) 169 | ftp_disconnect( conn->ftp ); 170 | else 171 | http_disconnect( conn->http ); 172 | conn->fd = -1; 173 | } 174 | 175 | int conn_init( conn_t *conn ) 176 | { 177 | char *proxy = conn->conf->http_proxy, *host = conn->conf->no_proxy; 178 | int i; 179 | 180 | if( *conn->conf->http_proxy == 0 ) 181 | { 182 | proxy = NULL; 183 | } 184 | else if( *conn->conf->no_proxy != 0 ) 185 | { 186 | for( i = 0; ; i ++ ) 187 | if( conn->conf->no_proxy[i] == 0 ) 188 | { 189 | if( strstr( conn->host, host ) != NULL ) 190 | proxy = NULL; 191 | host = &conn->conf->no_proxy[i+1]; 192 | if( conn->conf->no_proxy[i+1] == 0 ) 193 | break; 194 | } 195 | } 196 | 197 | conn->proxy = proxy != NULL; 198 | 199 | if( conn->proto == PROTO_FTP && !conn->proxy ) 200 | { 201 | conn->ftp->local_if = conn->local_if; 202 | conn->ftp->ftp_mode = FTP_PASSIVE; 203 | if( !ftp_connect( conn->ftp, conn->host, conn->port, conn->user, conn->pass ) ) 204 | { 205 | conn->message = conn->ftp->message; 206 | conn_disconnect( conn ); 207 | return( 0 ); 208 | } 209 | conn->message = conn->ftp->message; 210 | if( !ftp_cwd( conn->ftp, conn->dir ) ) 211 | { 212 | conn_disconnect( conn ); 213 | return( 0 ); 214 | } 215 | } 216 | else 217 | { 218 | conn->http->local_if = conn->local_if; 219 | if( !http_connect( conn->http, conn->proto, proxy, conn->host, conn->port, conn->user, conn->pass ) ) 220 | { 221 | conn->message = conn->http->headers; 222 | conn_disconnect( conn ); 223 | return( 0 ); 224 | } 225 | conn->message = conn->http->headers; 226 | conn->fd = conn->http->fd; 227 | } 228 | return( 1 ); 229 | } 230 | 231 | int conn_setup( conn_t *conn ) 232 | { 233 | if( conn->ftp->fd <= 0 && conn->http->fd <= 0 ) 234 | if( !conn_init( conn ) ) 235 | return( 0 ); 236 | 237 | if( conn->proto == PROTO_FTP && !conn->proxy ) 238 | { 239 | if( !ftp_data( conn->ftp ) ) /* Set up data connnection */ 240 | return( 0 ); 241 | conn->fd = conn->ftp->data_fd; 242 | 243 | if( conn->currentbyte ) 244 | { 245 | ftp_command( conn->ftp, "REST %lld", conn->currentbyte ); 246 | if( ftp_wait( conn->ftp ) / 100 != 3 && 247 | conn->ftp->status / 100 != 2 ) 248 | return( 0 ); 249 | } 250 | } 251 | else 252 | { 253 | char s[MAX_STRING]; 254 | int i; 255 | 256 | snprintf( s, MAX_STRING, "%s%s", conn->dir, conn->file ); 257 | conn->http->firstbyte = conn->currentbyte; 258 | conn->http->lastbyte = conn->lastbyte; 259 | http_get( conn->http, s ); 260 | http_addheader( conn->http, "User-Agent: %s", conn->conf->user_agent ); 261 | for( i = 0; i < conn->conf->add_header_count; i++) 262 | http_addheader( conn->http, "%s", conn->conf->add_header[i] ); 263 | } 264 | return( 1 ); 265 | } 266 | 267 | int conn_exec( conn_t *conn ) 268 | { 269 | if( conn->proto == PROTO_FTP && !conn->proxy ) 270 | { 271 | if( !ftp_command( conn->ftp, "RETR %s", conn->file ) ) 272 | return( 0 ); 273 | return( ftp_wait( conn->ftp ) / 100 == 1 ); 274 | } 275 | else 276 | { 277 | if( !http_exec( conn->http ) ) 278 | return( 0 ); 279 | return( conn->http->status / 100 == 2 ); 280 | } 281 | } 282 | 283 | /* Get file size and other information */ 284 | int conn_info( conn_t *conn ) 285 | { 286 | /* It's all a bit messed up.. But it works. */ 287 | if( conn->proto == PROTO_FTP && !conn->proxy ) 288 | { 289 | ftp_command( conn->ftp, "REST %lld", 1 ); 290 | if( ftp_wait( conn->ftp ) / 100 == 3 || 291 | conn->ftp->status / 100 == 2 ) 292 | { 293 | conn->supported = 1; 294 | ftp_command( conn->ftp, "REST %lld", 0 ); 295 | ftp_wait( conn->ftp ); 296 | } 297 | else 298 | { 299 | conn->supported = 0; 300 | } 301 | 302 | if( !ftp_cwd( conn->ftp, conn->dir ) ) 303 | return( 0 ); 304 | conn->size = ftp_size( conn->ftp, conn->file, MAX_REDIR ); 305 | if( conn->size < 0 ) 306 | conn->supported = 0; 307 | if( conn->size == -1 ) 308 | return( 0 ); 309 | else if( conn->size == -2 ) 310 | conn->size = INT_MAX; 311 | } 312 | else 313 | { 314 | char s[MAX_STRING], *t; 315 | long long int i = 0; 316 | 317 | do 318 | { 319 | conn->currentbyte = 1; 320 | if( !conn_setup( conn ) ) 321 | return( 0 ); 322 | conn_exec( conn ); 323 | conn_disconnect( conn ); 324 | /* Code 3xx == redirect */ 325 | if( conn->http->status / 100 != 3 ) 326 | break; 327 | if( ( t = http_header( conn->http, "location:" ) ) == NULL ) 328 | return( 0 ); 329 | sscanf( t, "%255s", s ); 330 | if( strstr( s, "://" ) == NULL) 331 | { 332 | sprintf( conn->http->headers, "%s%s", 333 | conn_url( conn ), s ); 334 | strncpy( s, conn->http->headers, MAX_STRING ); 335 | } 336 | else if( s[0] == '/' ) 337 | { 338 | sprintf( conn->http->headers, "http://%s:%i%s", 339 | conn->host, conn->port, s ); 340 | strncpy( s, conn->http->headers, MAX_STRING ); 341 | } 342 | conn_set( conn, s ); 343 | i ++; 344 | } 345 | while( conn->http->status / 100 == 3 && i < MAX_REDIR ); 346 | 347 | if( i == MAX_REDIR ) 348 | { 349 | sprintf( conn->message, _("Too many redirects.\n") ); 350 | return( 0 ); 351 | } 352 | 353 | conn->size = http_size( conn->http ); 354 | if( conn->http->status == 206 && conn->size >= 0 ) 355 | { 356 | conn->supported = 1; 357 | conn->size ++; 358 | } 359 | else if( conn->http->status == 200 || conn->http->status == 206 ) 360 | { 361 | conn->supported = 0; 362 | conn->size = INT_MAX; 363 | } 364 | else 365 | { 366 | t = strchr( conn->message, '\n' ); 367 | if( t == NULL ) 368 | sprintf( conn->message, _("Unknown HTTP error.\n") ); 369 | else 370 | *t = 0; 371 | return( 0 ); 372 | } 373 | } 374 | 375 | return( 1 ); 376 | } 377 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | UNRELEASED: 2 | 3 | - Make axel build on HP-UX, thanks Ciro Iriarte 4 | - Fix Solaris support (Closes: #312092), thanks Sebastian Kayser 5 | - Restore kapt meanings (Closes: #311811), thanks Daniel Gimpelevich 6 | - Add PO-Revision-Date header to ru.po 7 | 8 | Version 2.4 9 | 10 | - Fix a buffer overflow caused by wrong size limits when copying strings (Closes: #311569), thanks Michael Schwendt and the Fedora project members 11 | - Fix thread hangups due to incorrect synchronization (Closes: #311469), thanks Yao Shi 12 | - Removed Fedora packaging file. axel will be available in the Fedora repositories soon. 13 | - Use /etc/ instead of /usr/etc/ as the default system-wide configuration location. 14 | - Respect environment CFLAGS in configure. 15 | - Allow special characters in arguments to configure. 16 | - Add MimeType and fix Categories in the desktop file. 17 | 18 | Version 2.3 19 | 20 | - Wait for thread termination in axel.c:axel_do (Closes: #311255), thanks John Ripa 21 | - New Chinese translation and manpage, thanks Shuge Lee 22 | - Fix LFS support for FTP (Closes: #311320) 23 | - Fix LFS support (Closes: #311324), thanks Rodrigue Le Bayon 24 | 25 | Version 2.2: 26 | 27 | - Fix a buffer overflow in http.c:http_encode. 28 | 29 | Version 2.1: 30 | 31 | - Fix version string. 2.0 still reported 1.1, thanks Ajay R Ramjatan 32 | - Fix new MB/s display (was showing B/s). Thanks Philipp Hagemeister 33 | 34 | Version 2.0: 35 | 36 | - Large file support thanks thanks David Turnbull 37 | - Custom Header Support thanks Eli Yukelzon 38 | - New russian translation thanks newhren 39 | - Fix segfault in -H option thanks Philipp Hagemeister 40 | - Honour http_proxy and prefer it over HTTP_PROXY 41 | - Add new RPM spec file thanks bbbush 42 | 43 | Finished Sep 12 2008 44 | 45 | Version 1.1: 46 | 47 | - Compilation for GNU/kFreeBSD, thanks to Cyril Brulebois 48 | - Use simple pop-ups for Help and Bug Report buttons 49 | - Use strncpy instead of strcpy for length sensitive copies 50 | - Always compile with -g, disable -O3 51 | - Translation updates: de.po thanks Hermann J. Beckers 52 | - Update manpages axel.1 and axel-kapt.1 53 | - Prevent crash and raise error if FTP CWD fails 54 | - Prevent crash on long URLs and increase max length of URL to 1024 55 | - Fix segfaults on HTTP404 and HTTP401 responses 56 | 57 | Finished Jan 18 2008 58 | 59 | Version 1.0b: 60 | - Removed spaces between -S[x] in man-pages, etc. They mess things up. 61 | - Fixed configure for OpenBSD. 62 | - Fixed configuration bug: s/alternate_interface/alternate_output/ in 63 | axelrc.example, thanks to CLOTILDE Guy Daniel for the bug report! 64 | - Fixed weird behaviour when downloading from an unsupported server. 65 | - Fixed buffer overflow in conn.c. (CAN-2005-0390) 66 | 67 | Finished Apr 06 2005 68 | 69 | 70 | Version 1.0a: 71 | - gstrip on Solaris/SPARC breaks the binary, so stripping is made optional 72 | (but enabled by default!) and /usr/ccs/bin/strip is used instead of 73 | gstrip. 74 | - Fixed a small (not harmful) errorcode interpretation bug in the ftp_size 75 | code. 76 | - Downloading from unsupported sites works better now. 77 | - Added support for downloading using more than one local network interface. 78 | - Fixed a potential SIGSEGV bug. Would only happen with about more than 64 79 | connections usually. Still strange things can happen with too many 80 | connections when using Linux.. 81 | - Hopefully fixed the problem with downloading from forwarding URL's. 82 | - HTTP %-escapes are handled now. 83 | - Alternate progress indicator with estimation of remaining download time 84 | - Changed the return-code a bit, see man-page for details. 85 | 86 | Finished Feb 19 2002 87 | 88 | 89 | Version 1.0: 90 | - Fixed a reconnect problem: Check for stalled connections was skipped by 91 | previous versions if there is no active connection. 92 | - Solaris does not have www in /etc/services which confused Axel. Fixed. 93 | - Created a new build system. 94 | - install utility not used anymore: Solaris' install does weird things. 95 | - Added support for Cygwin and Solaris. 96 | - Corrected a little problem in de.po. 97 | - Thrown out the packaging stuff. 98 | 99 | Finished Dec 6 2001 100 | 101 | 102 | Version 0.99b brings you: 103 | - Debian package bugfix. 104 | - Restored i18n support. 105 | 106 | Finished Nov 16 2001 107 | 108 | 109 | Version 0.99a brings you: 110 | - Small bugfix for dumb HTTP bug. 111 | 112 | Finished Nov 10 2001 113 | 114 | 115 | Version 0.99 brings you: 116 | - Improved speed limiter. (For low speeds a smaller buffer works better, 117 | so the buffer is resized automatically for low speeds.) 118 | - Some FTP servers don't ask for a password which confused ftp.c. Fixed. 119 | - Some HTTP servers send chunked data when using HTTP/1.1. So I went back 120 | to HTTP/1.0.. (This also fixes the occasional filesearching.com problem) 121 | - Even more problems with FTP server reply codes, but they must be fixed 122 | now, Axel's RFC compliant. 123 | - For HTTP downloads a Range: header is not sent when downloading starting 124 | at byte 0. This is just a work-around for a problem with a weird webserver 125 | which sends corrupted data when a Range: header is sent. It's just a 126 | work-around for a rare problem, it does not really fix anything. 127 | - RPM package for axel-kapt added. 128 | 129 | Finished Nov 9 2001 130 | 131 | 132 | Version 0.98 brings you: 133 | - Fixed the weird percentage indicator bug. (Was buggy for large files, 134 | did not affect the downloaded data.) 135 | - For single connection downloads from Apache: Apache returns a 200 result 136 | code when the specified file range is the complete file. Axel handles 137 | this correctly now. 138 | - Roxen FTP servers return the address and port number without brackets 139 | after a passive command. This is RFC-compliant but quite unique. But now 140 | handled correctly. 141 | - Fixed some things to make it work on Darwin again. 142 | - 'Upgraded' HTTP requests to HTTP/1.1. Tried this to fix a download 143 | corruption bug for downloads from archive.progeny.com, but it did not 144 | work. wget's resume has exactly the same problem. But using HTTP/1.1 is 145 | more compliant (because in fact HTTP/1.0 does not support Ranges) so I'll 146 | keep it this way.. 147 | - Previous version used to delete the statefile in some cases. Fixed. 148 | 149 | Finished Nov 3 2001 150 | 151 | 152 | Version 0.97 (Bitcrusher) brings you: 153 | - Major redesign: Moved a lot of code from main() to separate functions, 154 | it should make it easier to create different interfaces for the program. 155 | - All those ifdefs were a mess, they don't exist anymore. Separate threads 156 | for setting up connections are used by default now. Version 0.96 will not 157 | disappear, by the way. 158 | - HTTP HEAD request not used anymore: Squid's headers are incorrect when 159 | using the HEAD request. 160 | - conn_disconnect did not work for FTP connections through HTTP proxies. 161 | - Documentation fix, sort of: The example configuration file still said 162 | proxies are unsupported. But they are supported for quite some time 163 | already. 164 | - Wrote a small (Small? Larger than any other doc.. :-) description of the 165 | Axel API. 166 | - Added finish_time code. (Credits to sjoerd@huiswerkservice.nl) 167 | - Calling conn_setup without calling conn_init first also works when using 168 | a proxy now. 169 | - A client for filesearching.com. You can use it to search for mirrors and 170 | download from more than mirror at once. 171 | - Fixed another segfault bug which did not show up on my own system... 172 | Also fixed by 0.96a. 173 | - Global error string is gone. Unusable in threaded programs. 174 | - The -V switch stopped working some time ago because I forgot to put it 175 | in the getopt string. Now it's back, alive and kickin'... 176 | - TYPE I should be done quite early. Some servers return weird file sizes 177 | when still in ASCII mode. 178 | - ftp.c (ftp_wait) sometimes resized conn->message to below MAX_STRING 179 | which is Not Good(tm). 180 | - I18N support is a bit broken at this time, it'll be fixed later. 181 | - Tidied up the man-page a bit. 182 | - Removed config.h file, -D flags used again. 183 | - Added axel-kapt interface. 184 | - Changed syntax: Local file must be specified using the -o option now. 185 | This allows the user to specify more than one URL and all of them will 186 | be used for the download. A local directory can be passed as well, the 187 | program will append the correct filename. 188 | - Fixed a bug which caused the program not to be able to download files 189 | for which only one byte has to be downloaded for one of the connections. 190 | - Why bitcrusher? Just because I liked to have a code name for this 191 | release... Bit crusher is a name of a musical group here in the 192 | Netherlands, and it's a nice name for a downloader as well, I hope... 193 | 194 | Finished Oct 25 2001 195 | 196 | 197 | Version 0.96 brings you: 198 | - Fixed a terrible bug which caused any FTP download to corrupt. I promise 199 | I will test the program before any next release. :-(( HTTP did work in 200 | 0.95. 201 | 202 | Finished Aug 14 2001 (Why is this fix so late? Because the actual release 203 | of version 0.95 was only last Friday/Saturday...) 204 | 205 | And yes, I tested it now. It works now. HTTP and FTP. 206 | 207 | 208 | Version 0.95 brings you: 209 | - An important bugfix: When bringing up the connection failed, the program 210 | used to be unable to reconnect. :( 211 | - Small changes to make the program compile on FreeBSD and Darwin. 212 | - Support check for FTP servers is done only once now. 213 | - SIZE command is really used now. 214 | - Fixed a SIGINT-does-not-abort problem. Btw: Ctrl-\ (SIGQUIT) always works! 215 | - Connection status messages are not displayed by default. You can enable 216 | them with the verbose-option. 217 | 218 | Finished Aug 7 2001 219 | 220 | 221 | Version 0.94 brings you: 222 | - 'make install' uses install instead of mkdir/cp now. 223 | - Added 'make uninstall' option. 224 | - Added more explanations to axelrc.example. 225 | - It uses the HTTP HEAD request now. Didn't know that one before. :) 226 | - Debian packaging stuff and RPM .spec file included by default. 227 | - select() problem now really understood... The real point was, that 228 | sometimes select() was called with an empty fd set. Now I solved the 229 | problem in a more 'useful' way. 230 | 231 | Finished Jun 26 2001 232 | 233 | 234 | Version 0.93 brings you: 235 | - A compile-time option to remove all the multi-connection stuff. Program 236 | works without state files then, and it's a bit smaller, just in case you 237 | need a very small program and if you don't believe in acceleration. :) 238 | - The SIZE command is now used as long as the URL does not contain wildcards. 239 | Because FTP servers are just too different. :( 240 | - You can do FTP downloads through HTTP proxies now. 241 | - The weird initial 1-second delay which happened sometimes does not exist 242 | anymore: It was because of select(), which does not return immediately 243 | if there's data on a socket before the call starts. My first solution 244 | is using a lower timeout, I hope there's a better solution available... 245 | - Local file existence check. 246 | - Small bug fixed in conf.c. 247 | 248 | Finished May 22 2001 249 | 250 | 251 | Version 0.92 brings you: 252 | - A credits file!! ;) 253 | - A German translation. Herrman J. Beckers: Thanks a lot! 254 | - ftp.c should understand weird Macintosh FTP servers too, now. 255 | - Connections are initialized in a different thread because then the program 256 | can go on downloading data from other connections while setting up. Quick 257 | hack, but it works. 258 | - config.h contains the configuration definitions now. 259 | - A URL - can be specified. The program will read a URL from stdin. Might 260 | be useful if you don't want other people to see the URL in the 'ps aux' 261 | output. (Think about passwords in URLs...) 262 | 263 | Finished May 11 2001 264 | 265 | 266 | Version 0.91 brings you: 267 | - A man page. 268 | - A quiet mode. 269 | - A Debian package. (0.9 .deb exists too, but that was after the 'official' 270 | 0.9 release..) 271 | - Made the sizes/times displayed after downloading more human-readable. 272 | - Corrected some stupid things in the nl.po file. 273 | - No bug in ftp_wait anymore, (or at least one bug less ;) the program was a 274 | bit too late with the realloc() sometimes. I just hate those multi-line 275 | replies.. :( 276 | - HTTP proxy support. no_proxy configuration flag also in use. 277 | - Support for empty configuration strings. 278 | - URL parser understands wrongly formatted URLs like slashdot.org. (instead 279 | of the correct http://slashdot.org/) 280 | 281 | Finished Apr 30 2001 282 | 283 | 284 | Version 0.9 brings you: 285 | - See the README for all the old features. 286 | - Internationalization support. 287 | - Clearer error messages. 288 | - Probably some bug fixes too. 289 | - A highly sophisticated Makefile.. ;) 290 | 291 | Finished Apr 22 2001 292 | -------------------------------------------------------------------------------- /text.c: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* Text interface */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #include "axel.h" 27 | 28 | static void stop( int signal ); 29 | static char *size_human( long long int value ); 30 | static char *time_human( int value ); 31 | static void print_commas( long long int bytes_done ); 32 | static void print_alternate_output( axel_t *axel ); 33 | static void print_help(); 34 | static void print_version(); 35 | static void print_messages( axel_t *axel ); 36 | 37 | int run = 1; 38 | 39 | #ifdef NOGETOPTLONG 40 | #define getopt_long( a, b, c, d, e ) getopt( a, b, c ) 41 | #else 42 | static struct option axel_options[] = 43 | { 44 | /* name has_arg flag val */ 45 | { "max-speed", 1, NULL, 's' }, 46 | { "num-connections", 1, NULL, 'n' }, 47 | { "output", 1, NULL, 'o' }, 48 | { "search", 2, NULL, 'S' }, 49 | { "no-proxy", 0, NULL, 'N' }, 50 | { "quiet", 0, NULL, 'q' }, 51 | { "verbose", 0, NULL, 'v' }, 52 | { "help", 0, NULL, 'h' }, 53 | { "version", 0, NULL, 'V' }, 54 | { "alternate", 0, NULL, 'a' }, 55 | { "header", 1, NULL, 'H' }, 56 | { "user-agent", 1, NULL, 'U' }, 57 | { NULL, 0, NULL, 0 } 58 | }; 59 | #endif 60 | 61 | /* For returning string values from functions */ 62 | static char string[MAX_STRING]; 63 | 64 | 65 | int main( int argc, char *argv[] ) 66 | { 67 | char fn[MAX_STRING] = ""; 68 | int do_search = 0; 69 | search_t *search; 70 | conf_t conf[1]; 71 | axel_t *axel; 72 | int i, j, cur_head = 0; 73 | char *s; 74 | 75 | #ifdef I18N 76 | setlocale( LC_ALL, "" ); 77 | bindtextdomain( PACKAGE, LOCALE ); 78 | textdomain( PACKAGE ); 79 | #endif 80 | 81 | if( !conf_init( conf ) ) 82 | { 83 | return( 1 ); 84 | } 85 | 86 | opterr = 0; 87 | 88 | j = -1; 89 | while( 1 ) 90 | { 91 | int option; 92 | 93 | option = getopt_long( argc, argv, "s:n:o:S::NqvhVaH:U:", axel_options, NULL ); 94 | if( option == -1 ) 95 | break; 96 | 97 | switch( option ) 98 | { 99 | case 'U': 100 | strncpy( conf->user_agent, optarg, MAX_STRING); 101 | break; 102 | case 'H': 103 | strncpy( conf->add_header[cur_head++], optarg, MAX_STRING ); 104 | break; 105 | case 's': 106 | if( !sscanf( optarg, "%i", &conf->max_speed ) ) 107 | { 108 | print_help(); 109 | return( 1 ); 110 | } 111 | break; 112 | case 'n': 113 | if( !sscanf( optarg, "%i", &conf->num_connections ) ) 114 | { 115 | print_help(); 116 | return( 1 ); 117 | } 118 | break; 119 | case 'o': 120 | strncpy( fn, optarg, MAX_STRING ); 121 | break; 122 | case 'S': 123 | do_search = 1; 124 | if( optarg != NULL ) 125 | if( !sscanf( optarg, "%i", &conf->search_top ) ) 126 | { 127 | print_help(); 128 | return( 1 ); 129 | } 130 | break; 131 | case 'a': 132 | conf->alternate_output = 1; 133 | break; 134 | case 'N': 135 | *conf->http_proxy = 0; 136 | break; 137 | case 'h': 138 | print_help(); 139 | return( 0 ); 140 | case 'v': 141 | if( j == -1 ) 142 | j = 1; 143 | else 144 | j ++; 145 | break; 146 | case 'V': 147 | print_version(); 148 | return( 0 ); 149 | case 'q': 150 | close( 1 ); 151 | conf->verbose = -1; 152 | if( open( "/dev/null", O_WRONLY ) != 1 ) 153 | { 154 | fprintf( stderr, _("Can't redirect stdout to /dev/null.\n") ); 155 | return( 1 ); 156 | } 157 | break; 158 | default: 159 | print_help(); 160 | return( 1 ); 161 | } 162 | } 163 | conf->add_header_count = cur_head; 164 | if( j > -1 ) 165 | conf->verbose = j; 166 | 167 | if( argc - optind == 0 ) 168 | { 169 | print_help(); 170 | return( 1 ); 171 | } 172 | else if( strcmp( argv[optind], "-" ) == 0 ) 173 | { 174 | s = malloc( MAX_STRING ); 175 | if (scanf( "%1024[^\n]s", s) != 1) { 176 | fprintf( stderr, _("Error when trying to read URL (Too long?).\n") ); 177 | return( 1 ); 178 | } 179 | } 180 | else 181 | { 182 | s = argv[optind]; 183 | if( strlen( s ) > MAX_STRING ) 184 | { 185 | fprintf( stderr, _("Can't handle URLs of length over %d\n" ), MAX_STRING ); 186 | return( 1 ); 187 | } 188 | } 189 | 190 | printf( _("Initializing download: %s\n"), s ); 191 | if( do_search ) 192 | { 193 | search = malloc( sizeof( search_t ) * ( conf->search_amount + 1 ) ); 194 | memset( search, 0, sizeof( search_t ) * ( conf->search_amount + 1 ) ); 195 | search[0].conf = conf; 196 | if( conf->verbose ) 197 | printf( _("Doing search...\n") ); 198 | i = search_makelist( search, s ); 199 | if( i < 0 ) 200 | { 201 | fprintf( stderr, _("File not found\n" ) ); 202 | return( 1 ); 203 | } 204 | if( conf->verbose ) 205 | printf( _("Testing speeds, this can take a while...\n") ); 206 | j = search_getspeeds( search, i ); 207 | search_sortlist( search, i ); 208 | if( conf->verbose ) 209 | { 210 | printf( _("%i usable servers found, will use these URLs:\n"), j ); 211 | j = min( j, conf->search_top ); 212 | printf( "%-60s %15s\n", "URL", "Speed" ); 213 | for( i = 0; i < j; i ++ ) 214 | printf( "%-70.70s %5i\n", search[i].url, search[i].speed ); 215 | printf( "\n" ); 216 | } 217 | axel = axel_new( conf, j, search ); 218 | free( search ); 219 | if( axel->ready == -1 ) 220 | { 221 | print_messages( axel ); 222 | axel_close( axel ); 223 | return( 1 ); 224 | } 225 | } 226 | else if( argc - optind == 1 ) 227 | { 228 | axel = axel_new( conf, 0, s ); 229 | if( axel->ready == -1 ) 230 | { 231 | print_messages( axel ); 232 | axel_close( axel ); 233 | return( 1 ); 234 | } 235 | } 236 | else 237 | { 238 | search = malloc( sizeof( search_t ) * ( argc - optind ) ); 239 | memset( search, 0, sizeof( search_t ) * ( argc - optind ) ); 240 | for( i = 0; i < ( argc - optind ); i ++ ) 241 | strncpy( search[i].url, argv[optind+i], MAX_STRING ); 242 | axel = axel_new( conf, argc - optind, search ); 243 | free( search ); 244 | if( axel->ready == -1 ) 245 | { 246 | print_messages( axel ); 247 | axel_close( axel ); 248 | return( 1 ); 249 | } 250 | } 251 | print_messages( axel ); 252 | if( s != argv[optind] ) 253 | { 254 | free( s ); 255 | } 256 | 257 | if( *fn ) 258 | { 259 | struct stat buf; 260 | 261 | if( stat( fn, &buf ) == 0 ) 262 | { 263 | if( S_ISDIR( buf.st_mode ) ) 264 | { 265 | size_t fnlen = strlen(fn); 266 | size_t axelfnlen = strlen(axel->filename); 267 | 268 | if (fnlen + 1 + axelfnlen + 1 > MAX_STRING) { 269 | fprintf( stderr, _("Filename too long!\n")); 270 | return ( 1 ); 271 | } 272 | 273 | fn[fnlen] = '/'; 274 | memcpy(fn+fnlen+1, axel->filename, axelfnlen); 275 | fn[fnlen + 1 + axelfnlen] = '\0'; 276 | } 277 | } 278 | sprintf( string, "%s.st", fn ); 279 | if( access( fn, F_OK ) == 0 && access( string, F_OK ) != 0 ) 280 | { 281 | fprintf( stderr, _("No state file, cannot resume!\n") ); 282 | return( 1 ); 283 | } 284 | if( access( string, F_OK ) == 0 && access( fn, F_OK ) != 0 ) 285 | { 286 | printf( _("State file found, but no downloaded data. Starting from scratch.\n" ) ); 287 | unlink( string ); 288 | } 289 | strcpy( axel->filename, fn ); 290 | } 291 | else 292 | { 293 | /* Local file existence check */ 294 | i = 0; 295 | s = axel->filename + strlen( axel->filename ); 296 | while( 1 ) 297 | { 298 | sprintf( string, "%s.st", axel->filename ); 299 | if( access( axel->filename, F_OK ) == 0 ) 300 | { 301 | if( axel->conn[0].supported ) 302 | { 303 | if( access( string, F_OK ) == 0 ) 304 | break; 305 | } 306 | } 307 | else 308 | { 309 | if( access( string, F_OK ) ) 310 | break; 311 | } 312 | sprintf( s, ".%i", i ); 313 | i ++; 314 | } 315 | } 316 | 317 | if( !axel_open( axel ) ) 318 | { 319 | print_messages( axel ); 320 | return( 1 ); 321 | } 322 | print_messages( axel ); 323 | axel_start( axel ); 324 | print_messages( axel ); 325 | 326 | if( conf->alternate_output ) 327 | { 328 | putchar('\n'); 329 | } 330 | else 331 | { 332 | if( axel->bytes_done > 0 ) /* Print first dots if resuming */ 333 | { 334 | putchar( '\n' ); 335 | print_commas( axel->bytes_done ); 336 | } 337 | } 338 | axel->start_byte = axel->bytes_done; 339 | 340 | /* Install save_state signal handler for resuming support */ 341 | signal( SIGINT, stop ); 342 | signal( SIGTERM, stop ); 343 | 344 | while( !axel->ready && run ) 345 | { 346 | long long int prev, done; 347 | 348 | prev = axel->bytes_done; 349 | axel_do( axel ); 350 | 351 | if( conf->alternate_output ) 352 | { 353 | if( !axel->message && prev != axel->bytes_done ) 354 | print_alternate_output( axel ); 355 | } 356 | else 357 | { 358 | /* The infamous wget-like 'interface'.. ;) */ 359 | done = ( axel->bytes_done / 1024 ) - ( prev / 1024 ); 360 | if( done && conf->verbose > -1 ) 361 | { 362 | for( i = 0; i < done; i ++ ) 363 | { 364 | i += ( prev / 1024 ); 365 | if( ( i % 50 ) == 0 ) 366 | { 367 | if( prev >= 1024 ) 368 | printf( " [%6.1fKB/s]", (double) axel->bytes_per_second / 1024 ); 369 | if( axel->size < 10240000 ) 370 | printf( "\n[%3lld%%] ", min( 100, 102400 * i / axel->size ) ); 371 | else 372 | printf( "\n[%3lld%%] ", min( 100, i / ( axel->size / 102400 ) ) ); 373 | } 374 | else if( ( i % 10 ) == 0 ) 375 | { 376 | putchar( ' ' ); 377 | } 378 | putchar( '.' ); 379 | i -= ( prev / 1024 ); 380 | } 381 | fflush( stdout ); 382 | } 383 | } 384 | 385 | if( axel->message ) 386 | { 387 | if(conf->alternate_output==1) 388 | { 389 | /* clreol-simulation */ 390 | putchar( '\r' ); 391 | for( i = 0; i < 79; i++ ) /* linewidth known? */ 392 | putchar( ' ' ); 393 | putchar( '\r' ); 394 | } 395 | else 396 | { 397 | putchar( '\n' ); 398 | } 399 | print_messages( axel ); 400 | if( !axel->ready ) 401 | { 402 | if(conf->alternate_output!=1) 403 | print_commas( axel->bytes_done ); 404 | else 405 | print_alternate_output(axel); 406 | } 407 | } 408 | else if( axel->ready ) 409 | { 410 | putchar( '\n' ); 411 | } 412 | } 413 | 414 | strcpy( string + MAX_STRING / 2, 415 | size_human( axel->bytes_done - axel->start_byte ) ); 416 | 417 | printf( _("\nDownloaded %s in %s. (%.2f KB/s)\n"), 418 | string + MAX_STRING / 2, 419 | time_human( gettime() - axel->start_time ), 420 | (double) axel->bytes_per_second / 1024 ); 421 | 422 | i = axel->ready ? 0 : 2; 423 | 424 | axel_close( axel ); 425 | 426 | return( i ); 427 | } 428 | 429 | /* SIGINT/SIGTERM handler */ 430 | void stop( int signal ) 431 | { 432 | run = 0; 433 | } 434 | 435 | /* Convert a number of bytes to a human-readable form */ 436 | char *size_human( long long int value ) 437 | { 438 | if( value < 1024 ) 439 | sprintf( string, _("%lld byte"), value ); 440 | else if( value < 1024 * 1024 ) 441 | sprintf( string, _("%.1f Kilobyte"), (float) value / 1024 ); 442 | else if( value < 1024 * 1024 * 1024 ) 443 | sprintf( string, _("%.1f Megabyte"), (float) value / (1024 * 1024) ); 444 | else 445 | sprintf( string, _("%.1f Gigabyte"), (float) value / (1024 * 1024 * 1024) ); 446 | 447 | return( string ); 448 | } 449 | 450 | /* Convert a number of seconds to a human-readable form */ 451 | char *time_human( int value ) 452 | { 453 | if( value == 1 ) 454 | sprintf( string, _("%i second"), value ); 455 | else if( value < 60 ) 456 | sprintf( string, _("%i seconds"), value ); 457 | else if( value < 3600 ) 458 | sprintf( string, _("%i:%02i seconds"), value / 60, value % 60 ); 459 | else 460 | sprintf( string, _("%i:%02i:%02i seconds"), value / 3600, ( value / 60 ) % 60, value % 60 ); 461 | 462 | return( string ); 463 | } 464 | 465 | /* Part of the infamous wget-like interface. Just put it in a function 466 | because I need it quite often.. */ 467 | void print_commas( long long int bytes_done ) 468 | { 469 | int i, j; 470 | 471 | printf( " " ); 472 | j = ( bytes_done / 1024 ) % 50; 473 | if( j == 0 ) j = 50; 474 | for( i = 0; i < j; i ++ ) 475 | { 476 | if( ( i % 10 ) == 0 ) 477 | putchar( ' ' ); 478 | putchar( ',' ); 479 | } 480 | fflush( stdout ); 481 | } 482 | 483 | static void print_alternate_output(axel_t *axel) 484 | { 485 | long long int done=axel->bytes_done; 486 | long long int total=axel->size; 487 | int i,j=0; 488 | double now = gettime(); 489 | 490 | printf("\r[%3ld%%] [", min(100,(long)(done*100./total+.5) ) ); 491 | 492 | for(i=0;iconf->num_connections;i++) 493 | { 494 | for(;j<((double)axel->conn[i].currentbyte/(total+1)*50)-1;j++) 495 | putchar('.'); 496 | 497 | if(axel->conn[i].currentbyteconn[i].lastbyte) 498 | { 499 | if(now <= axel->conn[i].last_transfer + axel->conf->connection_timeout/2 ) 500 | putchar(i+'0'); 501 | else 502 | putchar('#'); 503 | } else 504 | putchar('.'); 505 | 506 | j++; 507 | 508 | for(;j<((double)axel->conn[i].lastbyte/(total+1)*50);j++) 509 | putchar(' '); 510 | } 511 | 512 | if(axel->bytes_per_second > 1048576) 513 | printf( "] [%6.1fMB/s]", (double) axel->bytes_per_second / (1024*1024) ); 514 | else if(axel->bytes_per_second > 1024) 515 | printf( "] [%6.1fKB/s]", (double) axel->bytes_per_second / 1024 ); 516 | else 517 | printf( "] [%6.1fB/s]", (double) axel->bytes_per_second ); 518 | 519 | if(donefinish_time - now; 523 | minutes=seconds/60;seconds-=minutes*60; 524 | hours=minutes/60;minutes-=hours*60; 525 | days=hours/24;hours-=days*24; 526 | if(days) 527 | printf(" [%2dd%2d]",days,hours); 528 | else if(hours) 529 | printf(" [%2dh%02d]",hours,minutes); 530 | else 531 | printf(" [%02d:%02d]",minutes,seconds); 532 | } 533 | 534 | fflush( stdout ); 535 | } 536 | 537 | void print_help() 538 | { 539 | #ifdef NOGETOPTLONG 540 | printf( _("Usage: axel [options] url1 [url2] [url...]\n" 541 | "\n" 542 | "-s x\tSpecify maximum speed (bytes per second)\n" 543 | "-n x\tSpecify maximum number of connections\n" 544 | "-o f\tSpecify local output file\n" 545 | "-S [x]\tSearch for mirrors and download from x servers\n" 546 | "-H x\tAdd header string\n" 547 | "-U x\tSet user agent\n" 548 | "-N\tJust don't use any proxy server\n" 549 | "-q\tLeave stdout alone\n" 550 | "-v\tMore status information\n" 551 | "-a\tAlternate progress indicator\n" 552 | "-h\tThis information\n" 553 | "-V\tVersion information\n" 554 | "\n" 555 | "Visit http://axel.alioth.debian.org/ to report bugs\n") ); 556 | #else 557 | printf( _("Usage: axel [options] url1 [url2] [url...]\n" 558 | "\n" 559 | "--max-speed=x\t\t-s x\tSpecify maximum speed (bytes per second)\n" 560 | "--num-connections=x\t-n x\tSpecify maximum number of connections\n" 561 | "--output=f\t\t-o f\tSpecify local output file\n" 562 | "--search[=x]\t\t-S [x]\tSearch for mirrors and download from x servers\n" 563 | "--header=x\t\t-H x\tAdd header string\n" 564 | "--user-agent=x\t\t-U x\tSet user agent\n" 565 | "--no-proxy\t\t-N\tJust don't use any proxy server\n" 566 | "--quiet\t\t\t-q\tLeave stdout alone\n" 567 | "--verbose\t\t-v\tMore status information\n" 568 | "--alternate\t\t-a\tAlternate progress indicator\n" 569 | "--help\t\t\t-h\tThis information\n" 570 | "--version\t\t-V\tVersion information\n" 571 | "\n" 572 | "Visit http://axel.alioth.debian.org/ to report bugs\n") ); 573 | #endif 574 | } 575 | 576 | void print_version() 577 | { 578 | printf( _("Axel version %s (%s)\n"), AXEL_VERSION_STRING, ARCH ); 579 | printf( "\nCopyright 2001-2002 Wilmer van der Gaast.\n" ); 580 | } 581 | 582 | /* Print any message in the axel structure */ 583 | void print_messages( axel_t *axel ) 584 | { 585 | message_t *m; 586 | 587 | while( axel->message ) 588 | { 589 | printf( "%s\n", axel->message->text ); 590 | m = axel->message; 591 | axel->message = axel->message->next; 592 | free( m ); 593 | } 594 | } 595 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /axel.c: -------------------------------------------------------------------------------- 1 | /********************************************************************\ 2 | * Axel -- A lighter download accelerator for Linux and other Unices. * 3 | * * 4 | * Copyright 2001 Wilmer van der Gaast * 5 | \********************************************************************/ 6 | 7 | /* Main control */ 8 | 9 | /* 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License with 21 | the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL; 22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #include "axel.h" 27 | 28 | /* Axel */ 29 | static void save_state( axel_t *axel ); 30 | static void *setup_thread( void * ); 31 | static void axel_message( axel_t *axel, char *format, ... ); 32 | static void axel_divide( axel_t *axel ); 33 | 34 | static char *buffer = NULL; 35 | 36 | /* Create a new axel_t structure */ 37 | axel_t *axel_new( conf_t *conf, int count, void *url ) 38 | { 39 | search_t *res; 40 | axel_t *axel; 41 | url_t *u; 42 | char *s; 43 | int i; 44 | 45 | axel = malloc( sizeof( axel_t ) ); 46 | memset( axel, 0, sizeof( axel_t ) ); 47 | *axel->conf = *conf; 48 | axel->conn = malloc( sizeof( conn_t ) * axel->conf->num_connections ); 49 | memset( axel->conn, 0, sizeof( conn_t ) * axel->conf->num_connections ); 50 | if( axel->conf->max_speed > 0 ) 51 | { 52 | if( (float) axel->conf->max_speed / axel->conf->buffer_size < 0.5 ) 53 | { 54 | if( axel->conf->verbose >= 2 ) 55 | axel_message( axel, _("Buffer resized for this speed.") ); 56 | axel->conf->buffer_size = axel->conf->max_speed; 57 | } 58 | axel->delay_time = (int) ( (float) 1000000 / axel->conf->max_speed * axel->conf->buffer_size * axel->conf->num_connections ); 59 | } 60 | if( buffer == NULL ) 61 | buffer = malloc( max( MAX_STRING, axel->conf->buffer_size ) ); 62 | 63 | if( count == 0 ) 64 | { 65 | axel->url = malloc( sizeof( url_t ) ); 66 | axel->url->next = axel->url; 67 | strncpy( axel->url->text, (char *) url, MAX_STRING ); 68 | } 69 | else 70 | { 71 | res = (search_t *) url; 72 | u = axel->url = malloc( sizeof( url_t ) ); 73 | for( i = 0; i < count; i ++ ) 74 | { 75 | strncpy( u->text, res[i].url, MAX_STRING ); 76 | if( i < count - 1 ) 77 | { 78 | u->next = malloc( sizeof( url_t ) ); 79 | u = u->next; 80 | } 81 | else 82 | { 83 | u->next = axel->url; 84 | } 85 | } 86 | } 87 | 88 | axel->conn[0].conf = axel->conf; 89 | if( !conn_set( &axel->conn[0], axel->url->text ) ) 90 | { 91 | axel_message( axel, _("Could not parse URL.\n") ); 92 | axel->ready = -1; 93 | return( axel ); 94 | } 95 | 96 | axel->conn[0].local_if = axel->conf->interfaces->text; 97 | axel->conf->interfaces = axel->conf->interfaces->next; 98 | 99 | strncpy( axel->filename, axel->conn[0].file, MAX_STRING ); 100 | http_decode( axel->filename ); 101 | if( *axel->filename == 0 ) /* Index page == no fn */ 102 | strncpy( axel->filename, axel->conf->default_filename, MAX_STRING ); 103 | if( ( s = strchr( axel->filename, '?' ) ) != NULL && axel->conf->strip_cgi_parameters ) 104 | *s = 0; /* Get rid of CGI parameters */ 105 | 106 | if( !conn_init( &axel->conn[0] ) ) 107 | { 108 | axel_message( axel, axel->conn[0].message ); 109 | axel->ready = -1; 110 | return( axel ); 111 | } 112 | 113 | /* This does more than just checking the file size, it all depends 114 | on the protocol used. */ 115 | if( !conn_info( &axel->conn[0] ) ) 116 | { 117 | axel_message( axel, axel->conn[0].message ); 118 | axel->ready = -1; 119 | return( axel ); 120 | } 121 | s = conn_url( axel->conn ); 122 | strncpy( axel->url->text, s, MAX_STRING ); 123 | if( ( axel->size = axel->conn[0].size ) != INT_MAX ) 124 | { 125 | if( axel->conf->verbose > 0 ) 126 | axel_message( axel, _("File size: %lld bytes"), axel->size ); 127 | } 128 | 129 | /* Wildcards in URL --> Get complete filename */ 130 | if( strchr( axel->filename, '*' ) || strchr( axel->filename, '?' ) ) 131 | strncpy( axel->filename, axel->conn[0].file, MAX_STRING ); 132 | 133 | return( axel ); 134 | } 135 | 136 | /* Open a local file to store the downloaded data */ 137 | int axel_open( axel_t *axel ) 138 | { 139 | int i, fd; 140 | long long int j; 141 | 142 | if( axel->conf->verbose > 0 ) 143 | axel_message( axel, _("Opening output file %s"), axel->filename ); 144 | snprintf( buffer, MAX_STRING, "%s.st", axel->filename ); 145 | 146 | axel->outfd = -1; 147 | 148 | /* Check whether server knows about RESTart and switch back to 149 | single connection download if necessary */ 150 | if( !axel->conn[0].supported ) 151 | { 152 | axel_message( axel, _("Server unsupported, " 153 | "starting from scratch with one connection.") ); 154 | axel->conf->num_connections = 1; 155 | axel->conn = realloc( axel->conn, sizeof( conn_t ) ); 156 | axel_divide( axel ); 157 | } 158 | else if( ( fd = open( buffer, O_RDONLY ) ) != -1 ) 159 | { 160 | read( fd, &axel->conf->num_connections, sizeof( axel->conf->num_connections ) ); 161 | 162 | axel->conn = realloc( axel->conn, sizeof( conn_t ) * axel->conf->num_connections ); 163 | memset( axel->conn + 1, 0, sizeof( conn_t ) * ( axel->conf->num_connections - 1 ) ); 164 | 165 | axel_divide( axel ); 166 | 167 | read( fd, &axel->bytes_done, sizeof( axel->bytes_done ) ); 168 | for( i = 0; i < axel->conf->num_connections; i ++ ) 169 | read( fd, &axel->conn[i].currentbyte, sizeof( axel->conn[i].currentbyte ) ); 170 | 171 | axel_message( axel, _("State file found: %lld bytes downloaded, %lld to go."), 172 | axel->bytes_done, axel->size - axel->bytes_done ); 173 | 174 | close( fd ); 175 | 176 | if( ( axel->outfd = open( axel->filename, O_WRONLY, 0666 ) ) == -1 ) 177 | { 178 | axel_message( axel, _("Error opening local file") ); 179 | return( 0 ); 180 | } 181 | } 182 | 183 | /* If outfd == -1 we have to start from scrath now */ 184 | if( axel->outfd == -1 ) 185 | { 186 | axel_divide( axel ); 187 | 188 | if( ( axel->outfd = open( axel->filename, O_CREAT | O_WRONLY, 0666 ) ) == -1 ) 189 | { 190 | axel_message( axel, _("Error opening local file") ); 191 | return( 0 ); 192 | } 193 | 194 | /* And check whether the filesystem can handle seeks to 195 | past-EOF areas.. Speeds things up. :) AFAIK this 196 | should just not happen: */ 197 | if( lseek( axel->outfd, axel->size, SEEK_SET ) == -1 && axel->conf->num_connections > 1 ) 198 | { 199 | /* But if the OS/fs does not allow to seek behind 200 | EOF, we have to fill the file with zeroes before 201 | starting. Slow.. */ 202 | axel_message( axel, _("Crappy filesystem/OS.. Working around. :-(") ); 203 | lseek( axel->outfd, 0, SEEK_SET ); 204 | memset( buffer, 0, axel->conf->buffer_size ); 205 | j = axel->size; 206 | while( j > 0 ) 207 | { 208 | write( axel->outfd, buffer, min( j, axel->conf->buffer_size ) ); 209 | j -= axel->conf->buffer_size; 210 | } 211 | } 212 | } 213 | 214 | return( 1 ); 215 | } 216 | 217 | /* Start downloading */ 218 | void axel_start( axel_t *axel ) 219 | { 220 | int i; 221 | url_t* next_u = axel->url->next; 222 | url_t* current_u = axel->url; 223 | 224 | /* HTTP might've redirected and FTP handles wildcards, so 225 | re-scan the URL for every conn */ 226 | for( i = 0; i < axel->conf->num_connections; i ++ ) 227 | { 228 | conn_set( &axel->conn[i], current_u->text ); 229 | current_u = next_u; 230 | next_u = next_u->next; 231 | 232 | axel->conn[i].local_if = axel->conf->interfaces->text; 233 | axel->conf->interfaces = axel->conf->interfaces->next; 234 | axel->conn[i].conf = axel->conf; 235 | if( i ) axel->conn[i].supported = 1; 236 | } 237 | 238 | if( axel->conf->verbose > 0 ) 239 | axel_message( axel, _("Starting download") ); 240 | 241 | for( i = 0; i < axel->conf->num_connections; i ++ ) 242 | if( axel->conn[i].currentbyte <= axel->conn[i].lastbyte ) 243 | { 244 | if( axel->conf->verbose >= 2 ) 245 | { 246 | axel_message( axel, _("Connection %i downloading from %s:%i using interface %s"), 247 | i, axel->conn[i].host, axel->conn[i].port, axel->conn[i].local_if ); 248 | } 249 | 250 | axel->conn[i].state = 1; 251 | if( pthread_create( axel->conn[i].setup_thread, NULL, setup_thread, &axel->conn[i] ) != 0 ) 252 | { 253 | axel_message( axel, _("pthread error!!!") ); 254 | axel->ready = -1; 255 | } 256 | else 257 | { 258 | axel->conn[i].last_transfer = gettime(); 259 | } 260 | } 261 | 262 | /* The real downloading will start now, so let's start counting */ 263 | axel->start_time = gettime(); 264 | axel->ready = 0; 265 | } 266 | 267 | /* Main 'loop' */ 268 | void axel_do( axel_t *axel ) 269 | { 270 | fd_set fds[1]; 271 | int hifd, i; 272 | long long int remaining,size; 273 | struct timeval timeval[1]; 274 | 275 | /* Create statefile if necessary */ 276 | if( gettime() > axel->next_state ) 277 | { 278 | save_state( axel ); 279 | axel->next_state = gettime() + axel->conf->save_state_interval; 280 | } 281 | 282 | /* Wait for data on (one of) the connections */ 283 | FD_ZERO( fds ); 284 | hifd = 0; 285 | for( i = 0; i < axel->conf->num_connections; i ++ ) 286 | { 287 | if( axel->conn[i].enabled ) 288 | FD_SET( axel->conn[i].fd, fds ); 289 | hifd = max( hifd, axel->conn[i].fd ); 290 | } 291 | if( hifd == 0 ) 292 | { 293 | /* No connections yet. Wait... */ 294 | usleep( 100000 ); 295 | goto conn_check; 296 | } 297 | else 298 | { 299 | timeval->tv_sec = 0; 300 | timeval->tv_usec = 100000; 301 | /* A select() error probably means it was interrupted 302 | by a signal, or that something else's very wrong... */ 303 | if( select( hifd + 1, fds, NULL, NULL, timeval ) == -1 ) 304 | { 305 | axel->ready = -1; 306 | return; 307 | } 308 | } 309 | 310 | /* Handle connections which need attention */ 311 | for( i = 0; i < axel->conf->num_connections; i ++ ) 312 | if( axel->conn[i].enabled ) { 313 | if( FD_ISSET( axel->conn[i].fd, fds ) ) 314 | { 315 | axel->conn[i].last_transfer = gettime(); 316 | size = read( axel->conn[i].fd, buffer, axel->conf->buffer_size ); 317 | if( size == -1 ) 318 | { 319 | if( axel->conf->verbose ) 320 | { 321 | axel_message( axel, _("Error on connection %i! " 322 | "Connection closed"), i ); 323 | } 324 | axel->conn[i].enabled = 0; 325 | conn_disconnect( &axel->conn[i] ); 326 | continue; 327 | } 328 | else if( size == 0 ) 329 | { 330 | if( axel->conf->verbose ) 331 | { 332 | /* Only abnormal behaviour if: */ 333 | if( axel->conn[i].currentbyte < axel->conn[i].lastbyte && axel->size != INT_MAX ) 334 | { 335 | axel_message( axel, _("Connection %i unexpectedly closed"), i ); 336 | } 337 | else 338 | { 339 | axel_message( axel, _("Connection %i finished"), i ); 340 | } 341 | } 342 | if( !axel->conn[0].supported ) 343 | { 344 | axel->ready = 1; 345 | } 346 | axel->conn[i].enabled = 0; 347 | conn_disconnect( &axel->conn[i] ); 348 | continue; 349 | } 350 | /* remaining == Bytes to go */ 351 | remaining = axel->conn[i].lastbyte - axel->conn[i].currentbyte + 1; 352 | if( remaining < size ) 353 | { 354 | if( axel->conf->verbose ) 355 | { 356 | axel_message( axel, _("Connection %i finished"), i ); 357 | } 358 | axel->conn[i].enabled = 0; 359 | conn_disconnect( &axel->conn[i] ); 360 | size = remaining; 361 | /* Don't terminate, still stuff to write! */ 362 | } 363 | /* This should always succeed.. */ 364 | lseek( axel->outfd, axel->conn[i].currentbyte, SEEK_SET ); 365 | if( write( axel->outfd, buffer, size ) != size ) 366 | { 367 | 368 | axel_message( axel, _("Write error!") ); 369 | axel->ready = -1; 370 | return; 371 | } 372 | axel->conn[i].currentbyte += size; 373 | axel->bytes_done += size; 374 | } 375 | else 376 | { 377 | if( gettime() > axel->conn[i].last_transfer + axel->conf->connection_timeout ) 378 | { 379 | if( axel->conf->verbose ) 380 | axel_message( axel, _("Connection %i timed out"), i ); 381 | conn_disconnect( &axel->conn[i] ); 382 | axel->conn[i].enabled = 0; 383 | } 384 | } } 385 | 386 | if( axel->ready ) 387 | return; 388 | 389 | conn_check: 390 | /* Look for aborted connections and attempt to restart them. */ 391 | for( i = 0; i < axel->conf->num_connections; i ++ ) 392 | { 393 | if( !axel->conn[i].enabled && axel->conn[i].currentbyte < axel->conn[i].lastbyte ) 394 | { 395 | if( axel->conn[i].state == 0 ) 396 | { 397 | // Wait for termination of this thread 398 | pthread_join(*(axel->conn[i].setup_thread), NULL); 399 | 400 | conn_set( &axel->conn[i], axel->url->text ); 401 | axel->url = axel->url->next; 402 | /* axel->conn[i].local_if = axel->conf->interfaces->text; 403 | axel->conf->interfaces = axel->conf->interfaces->next; */ 404 | if( axel->conf->verbose >= 2 ) 405 | axel_message( axel, _("Connection %i downloading from %s:%i using interface %s"), 406 | i, axel->conn[i].host, axel->conn[i].port, axel->conn[i].local_if ); 407 | 408 | axel->conn[i].state = 1; 409 | if( pthread_create( axel->conn[i].setup_thread, NULL, setup_thread, &axel->conn[i] ) == 0 ) 410 | { 411 | axel->conn[i].last_transfer = gettime(); 412 | } 413 | else 414 | { 415 | axel_message( axel, _("pthread error!!!") ); 416 | axel->ready = -1; 417 | } 418 | } 419 | else 420 | { 421 | if( gettime() > axel->conn[i].last_transfer + axel->conf->reconnect_delay ) 422 | { 423 | pthread_cancel( *axel->conn[i].setup_thread ); 424 | axel->conn[i].state = 0; 425 | } 426 | } 427 | } 428 | } 429 | 430 | /* Calculate current average speed and finish_time */ 431 | axel->bytes_per_second = (int) ( (double) ( axel->bytes_done - axel->start_byte ) / ( gettime() - axel->start_time ) ); 432 | axel->finish_time = (int) ( axel->start_time + (double) ( axel->size - axel->start_byte ) / axel->bytes_per_second ); 433 | 434 | /* Check speed. If too high, delay for some time to slow things 435 | down a bit. I think a 5% deviation should be acceptable. */ 436 | if( axel->conf->max_speed > 0 ) 437 | { 438 | if( (float) axel->bytes_per_second / axel->conf->max_speed > 1.05 ) 439 | axel->delay_time += 10000; 440 | else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) && ( axel->delay_time >= 10000 ) ) 441 | axel->delay_time -= 10000; 442 | else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) ) 443 | axel->delay_time = 0; 444 | usleep( axel->delay_time ); 445 | } 446 | 447 | /* Ready? */ 448 | if( axel->bytes_done == axel->size ) 449 | axel->ready = 1; 450 | } 451 | 452 | /* Close an axel connection */ 453 | void axel_close( axel_t *axel ) 454 | { 455 | int i; 456 | message_t *m; 457 | 458 | /* Terminate any thread still running */ 459 | for( i = 0; i < axel->conf->num_connections; i ++ ) 460 | /* don't try to kill non existing thread */ 461 | if ( *axel->conn[i].setup_thread != 0 ) 462 | { 463 | pthread_cancel( *axel->conn[i].setup_thread ); 464 | pthread_detach( *axel->conn[i].setup_thread ); 465 | } 466 | 467 | /* Delete state file if necessary */ 468 | if( axel->ready == 1 ) 469 | { 470 | snprintf( buffer, MAX_STRING, "%s.st", axel->filename ); 471 | unlink( buffer ); 472 | } 473 | /* Else: Create it.. */ 474 | else if( axel->bytes_done > 0 ) 475 | { 476 | save_state( axel ); 477 | } 478 | 479 | /* Delete any message not processed yet */ 480 | while( axel->message ) 481 | { 482 | m = axel->message; 483 | axel->message = axel->message->next; 484 | free( m ); 485 | } 486 | 487 | /* Close all connections and local file */ 488 | close( axel->outfd ); 489 | for( i = 0; i < axel->conf->num_connections; i ++ ) 490 | conn_disconnect( &axel->conn[i] ); 491 | 492 | free_axel_t( axel ); 493 | free( buffer ); 494 | } 495 | 496 | /* time() with more precision */ 497 | double gettime() 498 | { 499 | struct timeval time[1]; 500 | 501 | gettimeofday( time, 0 ); 502 | return( (double) time->tv_sec + (double) time->tv_usec / 1000000 ); 503 | } 504 | 505 | /* Save the state of the current download */ 506 | void save_state( axel_t *axel ) 507 | { 508 | int fd, i; 509 | char fn[MAX_STRING+4]; 510 | 511 | /* No use for such a file if the server doesn't support 512 | resuming anyway.. */ 513 | if( !axel->conn[0].supported ) 514 | return; 515 | 516 | snprintf( fn, MAX_STRING, "%s.st", axel->filename ); 517 | if( ( fd = open( fn, O_CREAT | O_TRUNC | O_WRONLY, 0666 ) ) == -1 ) 518 | { 519 | return; /* Not 100% fatal.. */ 520 | } 521 | write( fd, &axel->conf->num_connections, sizeof( axel->conf->num_connections ) ); 522 | write( fd, &axel->bytes_done, sizeof( axel->bytes_done ) ); 523 | for( i = 0; i < axel->conf->num_connections; i ++ ) 524 | { 525 | write( fd, &axel->conn[i].currentbyte, sizeof( axel->conn[i].currentbyte ) ); 526 | } 527 | close( fd ); 528 | } 529 | 530 | /* Thread used to set up a connection */ 531 | void *setup_thread( void *c ) 532 | { 533 | conn_t *conn = c; 534 | int oldstate; 535 | 536 | /* Allow this thread to be killed at any time. */ 537 | pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate ); 538 | pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate ); 539 | 540 | if( conn_setup( conn ) ) 541 | { 542 | conn->last_transfer = gettime(); 543 | if( conn_exec( conn ) ) 544 | { 545 | conn->last_transfer = gettime(); 546 | conn->enabled = 1; 547 | conn->state = 0; 548 | return( NULL ); 549 | } 550 | } 551 | 552 | conn_disconnect( conn ); 553 | conn->state = 0; 554 | return( NULL ); 555 | } 556 | 557 | /* Add a message to the axel->message structure */ 558 | static void axel_message( axel_t *axel, char *format, ... ) 559 | { 560 | message_t *m = malloc( sizeof( message_t ) ), *n = axel->message; 561 | va_list params; 562 | 563 | memset( m, 0, sizeof( message_t ) ); 564 | va_start( params, format ); 565 | vsnprintf( m->text, MAX_STRING, format, params ); 566 | va_end( params ); 567 | 568 | if( axel->message == NULL ) 569 | { 570 | axel->message = m; 571 | } 572 | else 573 | { 574 | while( n->next != NULL ) 575 | n = n->next; 576 | n->next = m; 577 | } 578 | } 579 | 580 | /* Divide the file and set the locations for each connection */ 581 | static void axel_divide( axel_t *axel ) 582 | { 583 | int i; 584 | 585 | axel->conn[0].currentbyte = 0; 586 | axel->conn[0].lastbyte = axel->size / axel->conf->num_connections - 1; 587 | for( i = 1; i < axel->conf->num_connections; i ++ ) 588 | { 589 | #ifdef DEBUG 590 | printf( "Downloading %lld-%lld using conn. %i\n", axel->conn[i-1].currentbyte, axel->conn[i-1].lastbyte, i - 1 ); 591 | #endif 592 | axel->conn[i].currentbyte = axel->conn[i-1].lastbyte + 1; 593 | axel->conn[i].lastbyte = axel->conn[i].currentbyte + axel->size / axel->conf->num_connections; 594 | } 595 | axel->conn[axel->conf->num_connections-1].lastbyte = axel->size - 1; 596 | #ifdef DEBUG 597 | printf( "Downloading %lld-%lld using conn. %i\n", axel->conn[i-1].currentbyte, axel->conn[i-1].lastbyte, i - 1 ); 598 | #endif 599 | } 600 | 601 | 602 | 603 | void free_axel_t ( axel_t *axel ) 604 | { 605 | url_t *current_u = axel->url; 606 | url_t *n_u = axel->url->next; 607 | 608 | while ( current_u != axel->url ) { 609 | free( current_u ); 610 | current_u = n_u; 611 | n_u = n_u->next; 612 | } 613 | free( axel->url ); 614 | 615 | 616 | if_t *current_if = axel->conf->interfaces; 617 | if_t *n_if = axel->conf->interfaces->next; 618 | 619 | while ( current_if != axel->conf->interfaces ) { 620 | free( current_if ); 621 | current_if = n_if; 622 | n_if = n_if->next; 623 | } 624 | free( axel->conf->interfaces ); 625 | 626 | free( axel->conn ); 627 | free( axel ); 628 | } 629 | --------------------------------------------------------------------------------