Browse Source

2006-04-19 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	To add a readout of estimated remaining time to normal HTTP/FTP
	downloads:
	
	* src/ConsoleDownloadEngine.h (startup): New variable.
	(startupLength): New variable.
	(isStartupLengthSet): New variable.
	(avgSpeed): New variable.
	(eta): New variable.
	* src/ConsoleDownloadEngine.cc (sendStatistics): Added a readout 
of
	estimated remaining time.
	(initStatistics): Initialized newly added variables.
	(calculateStatistics): Calculate average speed and estimated 
remaining
	time.

	To decouple TorrentDownloadEngine from HttpResponseCommand:

	* src/TrackerDownloadCommand.h: Removed.
	* src/TrackerDownloadCommand.cc: Removed.
	* src/TrackerInitCommand.h: Removed.
	* src/TrackerInitCommand.cc: Removed.
	* src/TrackerUpdateCommand.h: Removed.
	* src/TrackerUpdateCommand.cc: Removed.
	* src/TrackerWatcherCommand.cc (execute): The construction of 
request
	url written in TrackerInitCommand was moved here. Do not create
	tracker request command if torretnMan->trackers != 0.
	* src/CompactTrackerResponseProcessor.h: New class.
	* src/CompactTrackerResponseProcessor.cc: New class.
	* src/message.h (MSG_TRACKER_WARNING_MESSAGE): Updated.
	* src/HttpResponseCommand.cc (createHttpDownloadCommand):
	Decoupled TorrentDownloadEngine from this.
	* src/SegmentMan.h (init): New function.
	* src/SegmentMan.cc (init): New function.
	* src/TorrentMan.h (responseProcessor): New variable.
	(trackers): New variable.
	(setTrackerResponseProcessor): New function.
	(getTrackerResponseProcessor): New function.
	(processTrackerResponse): New function.
	* src/TorrentMan.cc (Constructor): Initialized new variable 
trackers.
	(processTrackerResponse): New function.
	* src/main.cc (main): Use ByteArrayDiskWriter and
	CompactTrackerResponseProcessor.
	* src/TorrentDownloadEngine.cc (afterEachIteration): Call 
torrentMan->
	processTrackerResponse().
	
	* src/TorrentConsoleDownloadEngine.cc (printStatistics): Updated 
a
	readout.

	* src/TorrentDownloadEngine.cc (afterEachIteration): Added log 
message
	which indicates download has completed.

	* src/AbstractDiskWriter.cc (Destructor): fd >= 0, not fd >0
	(closeFile): fd >= 0, not fd > 0

	* src/main.cc (main): Added short cut for show-files.
	Added short cut for torrent-file.
	Added new command-line option listen-port.
	Updated i18n messages.
Tatsuhiro Tsujikawa 19 years ago
parent
commit
19f713b99d

+ 60 - 0
ChangeLog

@@ -1,3 +1,63 @@
+2006-04-19  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	To add a readout of estimated remaining time to normal HTTP/FTP
+	downloads:
+	
+	* src/ConsoleDownloadEngine.h (startup): New variable.
+	(startupLength): New variable.
+	(isStartupLengthSet): New variable.
+	(avgSpeed): New variable.
+	(eta): New variable.
+	* src/ConsoleDownloadEngine.cc (sendStatistics): Added a readout of
+	estimated remaining time.
+	(initStatistics): Initialized newly added variables.
+	(calculateStatistics): Calculate average speed and estimated remaining
+	time.
+
+	To decouple TorrentDownloadEngine from HttpResponseCommand:
+
+	* src/TrackerDownloadCommand.h: Removed.
+	* src/TrackerDownloadCommand.cc: Removed.
+	* src/TrackerInitCommand.h: Removed.
+	* src/TrackerInitCommand.cc: Removed.
+	* src/TrackerUpdateCommand.h: Removed.
+	* src/TrackerUpdateCommand.cc: Removed.
+	* src/TrackerWatcherCommand.cc (execute): The construction of request
+	url written in TrackerInitCommand was moved here. Do not create
+	tracker request command if torretnMan->trackers != 0.
+	* src/CompactTrackerResponseProcessor.h: New class.
+	* src/CompactTrackerResponseProcessor.cc: New class.
+	* src/message.h (MSG_TRACKER_WARNING_MESSAGE): Updated.
+	* src/HttpResponseCommand.cc (createHttpDownloadCommand):
+	Decoupled TorrentDownloadEngine from this.
+	* src/SegmentMan.h (init): New function.
+	* src/SegmentMan.cc (init): New function.
+	* src/TorrentMan.h (responseProcessor): New variable.
+	(trackers): New variable.
+	(setTrackerResponseProcessor): New function.
+	(getTrackerResponseProcessor): New function.
+	(processTrackerResponse): New function.
+	* src/TorrentMan.cc (Constructor): Initialized new variable trackers.
+	(processTrackerResponse): New function.
+	* src/main.cc (main): Use ByteArrayDiskWriter and
+	CompactTrackerResponseProcessor.
+	* src/TorrentDownloadEngine.cc (afterEachIteration): Call torrentMan->
+	processTrackerResponse().
+	
+	* src/TorrentConsoleDownloadEngine.cc (printStatistics): Updated a
+	readout.
+
+	* src/TorrentDownloadEngine.cc (afterEachIteration): Added log message
+	which indicates download has completed.
+
+	* src/AbstractDiskWriter.cc (Destructor): fd >= 0, not fd >0
+	(closeFile): fd >= 0, not fd > 0
+
+	* src/main.cc (main): Added short cut for show-files.
+	Added short cut for torrent-file.
+	Added new command-line option listen-port.
+	Updated i18n messages.
+	
 2006-04-18  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	To add LogFactory which creates singleton logger:

+ 14 - 2
README

@@ -21,6 +21,7 @@ aria2 is in very early development stage. Currently it has following features:
 * Cookie support(currently aria2 ignores "expires")
 * It can run as a daemon process.
 * BitTorrent protocol support
+* Selective download in multi-file torrent
 
 3. How to build
 ---------------
@@ -53,11 +54,22 @@ multi-file mode:
     The directory to store the top directory of downloaded files can be
     specified by -d option.
 
-In both mode, aria2 needs at least 2 times more disk space than the file size
-itself because it creates complete temporary file.
+In the default behavior, before download starts, complete directory structure
+is created if needed. Then aria2 opens all files mentioned in .torrent file,
+directly writes to and reads from these files.
+NOTE: Even in selective download, all files are opened.
+
+If "--direct-file-mapping" option set to be false, aria2 creates temporary
+file in the store directory. The length of this file is the sum of length of
+the files in .torrent file, so at least 2 times more disk space than the file
+size itself is required. Writing and reading is done against this file.
+After download completes, aria2 creates complete directory structure if needed,
+and copies whole file or a part of it to the destination.
 
 Note:
 *  -o option is used to change the filename of downloaded .torrent file.
 * This version only supports compact peers list format.
 * The ports aria2c uses are 6881-6999.
 * The maximum number of peers is 55.
+* After selective download completes, aria2 is going to download rest of the
+files.

+ 3 - 4
TODO

@@ -11,11 +11,10 @@
 * Add port range command-line option
 * Add max peers command-line option
 * Distinguish seeder from leecher
+* Add Mainline-compatible DHT support
+* Add Message stream encryption support
+* Add announce-list support
 
 0.4.0 release
 * try to use ftruncate to allocate file.
-* add log message when download completes
 
-0.4.1 release
-* Add port command-line option
-* Add estimated remaining time to normal HTTP/FTP downloading status ouput

+ 10 - 10
configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for aria2c 0.3.1.
+# Generated by GNU Autoconf 2.59 for aria2c 0.4.0.
 #
 # Report bugs to <[email protected]>.
 #
@@ -269,8 +269,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='aria2c'
 PACKAGE_TARNAME='aria2c'
-PACKAGE_VERSION='0.3.1'
-PACKAGE_STRING='aria2c 0.3.1'
+PACKAGE_VERSION='0.4.0'
+PACKAGE_STRING='aria2c 0.4.0'
 PACKAGE_BUGREPORT='[email protected]'
 
 ac_unique_file="src/Socket.h"
@@ -788,7 +788,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures aria2c 0.3.1 to adapt to many kinds of systems.
+\`configure' configures aria2c 0.4.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -854,7 +854,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of aria2c 0.3.1:";;
+     short | recursive ) echo "Configuration of aria2c 0.4.0:";;
    esac
   cat <<\_ACEOF
 
@@ -994,7 +994,7 @@ fi
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-aria2c configure 0.3.1
+aria2c configure 0.4.0
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1008,7 +1008,7 @@ cat >&5 <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by aria2c $as_me 0.3.1, which was
+It was created by aria2c $as_me 0.4.0, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1651,7 +1651,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='aria2c'
- VERSION='0.3.1'
+ VERSION='0.4.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -11528,7 +11528,7 @@ _ASBOX
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by aria2c $as_me 0.3.1, which was
+This file was extended by aria2c $as_me 0.4.0, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -11591,7 +11591,7 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-aria2c config.status 0.3.1
+aria2c config.status 0.4.0
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 

+ 1 - 1
configure.in

@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 #
 AC_PREREQ(2.59)
-AC_INIT(aria2c, 0.3.1, [email protected])
+AC_INIT(aria2c, 0.4.0, [email protected])
 AM_INIT_AUTOMAKE()
 AM_PATH_CPPUNIT(1.10.2)
 AC_CONFIG_SRCDIR([src/Socket.h])

+ 1 - 1
po/Makefile.in

@@ -9,7 +9,7 @@
 # General Public License and is *not* in the public domain.
 
 PACKAGE = aria2c
-VERSION = 0.3.1
+VERSION = 0.4.0
 
 SHELL = /bin/sh
 

+ 114 - 60
po/aria2c.pot

@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: http://aria2.sourceforge.net/\n"
-"POT-Creation-Date: 2006-04-12 22:55+0900\n"
+"POT-Creation-Date: 2006-04-19 02:02+0900\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <[email protected]>\n"
@@ -177,35 +177,39 @@ msgstr ""
 msgid "Got EOF from the server."
 msgstr ""
 
-#: src/main.cc:63
+#: src/main.cc:64
 #, c-format
 msgid ""
 "\n"
 "The download was complete. <%s>\n"
 msgstr ""
 
-#: src/main.cc:67
+#: src/main.cc:72
 msgid ""
 "\n"
 "The download was not complete because of errors. Check the log.\n"
 msgstr ""
 
-#: src/main.cc:78 src/main.cc:87
+#: src/main.cc:91 src/main.cc:102
 msgid ""
 "\n"
-"SIGINT signal received."
+"stopping application...\n"
 msgstr ""
 
-#: src/main.cc:109
+#: src/main.cc:97 src/main.cc:114
+msgid "done\n"
+msgstr ""
+
+#: src/main.cc:125
 #, c-format
 msgid "Unrecognized URL or unsupported protocol: %s\n"
 msgstr ""
 
-#: src/main.cc:115
+#: src/main.cc:131
 msgid " version "
 msgstr ""
 
-#: src/main.cc:119
+#: src/main.cc:135
 msgid ""
 "This program is free software; you can redistribute it and/or modify\n"
 "it under the terms of the GNU General Public License as published by\n"
@@ -222,40 +226,45 @@ msgid ""
 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
 msgstr ""
 
-#: src/main.cc:133
+#: src/main.cc:149
 #, c-format
 msgid "Contact Info: %s\n"
 msgstr ""
 
-#: src/main.cc:139
+#: src/main.cc:155
 #, c-format
 msgid "Usage: %s [options] URL ...\n"
 msgstr ""
 
-#: src/main.cc:141
+#: src/main.cc:156
+#, c-format
+msgid "       %s [options] -T TORRENT_FILE FILE ...\n"
+msgstr ""
+
+#: src/main.cc:159
 msgid "Options:"
 msgstr ""
 
-#: src/main.cc:142
+#: src/main.cc:160
 msgid " -d, --dir=DIR                The directory to store downloaded file."
 msgstr ""
 
-#: src/main.cc:143
+#: src/main.cc:161
 msgid " -o, --out=FILE               The file name for downloaded file."
 msgstr ""
 
-#: src/main.cc:144
+#: src/main.cc:162
 msgid ""
 " -l, --log=LOG                The file path to store log. If '-' is "
 "specified,\n"
 "                              log is written to stdout."
 msgstr ""
 
-#: src/main.cc:146
+#: src/main.cc:164
 msgid " -D, --daemon                 Run as daemon."
 msgstr ""
 
-#: src/main.cc:147
+#: src/main.cc:165
 msgid ""
 " -s, --split=N                Download a file using N connections. N must "
 "be\n"
@@ -265,24 +274,24 @@ msgid ""
 "                              N connections."
 msgstr ""
 
-#: src/main.cc:151
+#: src/main.cc:169
 msgid ""
 " --retry-wait=SEC             Set amount of time in second between requests\n"
 "                              for errors. Specify a value between 0 and 60.\n"
 "                              Default: 5"
 msgstr ""
 
-#: src/main.cc:154
+#: src/main.cc:172
 msgid " -t, --timeout=SEC            Set timeout in second. Default: 60"
 msgstr ""
 
-#: src/main.cc:155
+#: src/main.cc:173
 msgid ""
 " -m, --max-tries=N            Set number of tries. 0 means unlimited.\n"
 "                              Default: 5"
 msgstr ""
 
-#: src/main.cc:157
+#: src/main.cc:175
 msgid ""
 " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n"
 "                              K or M(1K = 1024, 1M = 1024K). This\n"
@@ -290,40 +299,40 @@ msgid ""
 "                              1024."
 msgstr ""
 
-#: src/main.cc:161
+#: src/main.cc:179
 msgid ""
 " --http-proxy=HOST:PORT       Use HTTP proxy server. This affects to all\n"
 "                              URLs."
 msgstr ""
 
-#: src/main.cc:163
+#: src/main.cc:181
 msgid " --http-user=USER             Set HTTP user. This affects to all URLs."
 msgstr ""
 
-#: src/main.cc:164
+#: src/main.cc:182
 msgid ""
 " --http-passwd=PASSWD         Set HTTP password. This affects to all URLs."
 msgstr ""
 
-#: src/main.cc:165
+#: src/main.cc:183
 msgid ""
 " --http-proxy-user=USER       Set HTTP proxy user. This affects to all URLs"
 msgstr ""
 
-#: src/main.cc:166
+#: src/main.cc:184
 msgid ""
 " --http-proxy-passwd=PASSWD   Set HTTP proxy password. This affects to all "
 "URLs."
 msgstr ""
 
-#: src/main.cc:167
+#: src/main.cc:185
 msgid ""
 " --http-proxy-method=METHOD   Set the method to use in proxy request.\n"
 "                              METHOD is either 'get' or 'tunnel'.\n"
 "                              Default: tunnel"
 msgstr ""
 
-#: src/main.cc:170
+#: src/main.cc:188
 msgid ""
 " --http-auth-scheme=SCHEME    Set HTTP authentication scheme. Currently, "
 "basic\n"
@@ -334,23 +343,23 @@ msgid ""
 "                              as well as --http-user and --http-passwd."
 msgstr ""
 
-#: src/main.cc:174
+#: src/main.cc:192
 msgid " --referer=REFERER            Set Referer. This affects to all URLs."
 msgstr ""
 
-#: src/main.cc:175
+#: src/main.cc:193
 msgid ""
 " --ftp-user=USER              Set FTP user. This affects to all URLs.\n"
 "                              Default: anonymous"
 msgstr ""
 
-#: src/main.cc:177
+#: src/main.cc:195
 msgid ""
 " --ftp-passwd=PASSWD          Set FTP password. This affects to all URLs.\n"
 "                              Default: ARIA2USER@"
 msgstr ""
 
-#: src/main.cc:179
+#: src/main.cc:197
 msgid ""
 " --ftp-type=TYPE              Set FTP transfer type. TYPE is either "
 "'binary'\n"
@@ -358,11 +367,11 @@ msgid ""
 "                              Default: binary"
 msgstr ""
 
-#: src/main.cc:182
+#: src/main.cc:200
 msgid " -p, --ftp-pasv               Use passive mode in FTP."
 msgstr ""
 
-#: src/main.cc:183
+#: src/main.cc:201
 msgid ""
 " --ftp-via-http-proxy=METHOD  Use HTTP proxy in FTP. METHOD is either 'get' "
 "or\n"
@@ -370,11 +379,11 @@ msgid ""
 "                              Default: tunnel"
 msgstr ""
 
-#: src/main.cc:187
-msgid " --torrent-file=TORRENT_FILE  The file path to .torrent file."
+#: src/main.cc:205
+msgid " -T, --torrent-file=TORRENT_FILE  The file path to .torrent file."
 msgstr ""
 
-#: src/main.cc:188
+#: src/main.cc:206
 msgid ""
 " --follow-torrent=true|false  Setting this option to false prevents aria2 "
 "to\n"
@@ -383,97 +392,142 @@ msgid ""
 "                              Default: true"
 msgstr ""
 
-#: src/main.cc:193
+#: src/main.cc:210
+msgid ""
+" -S, --show-files             Print the file listing in .torrent file and "
+"exit."
+msgstr ""
+
+#: src/main.cc:211
+msgid ""
+" --direct-file-mapping=true|false Directly read from and write to each file\n"
+"                              mentioned in .torrent file.\n"
+"                              Default: true"
+msgstr ""
+
+#: src/main.cc:214
+msgid ""
+" --listen-port                Set port number to listen to for peer "
+"connection."
+msgstr ""
+
+#: src/main.cc:216
 msgid " -v, --version                Print the version number and exit."
 msgstr ""
 
-#: src/main.cc:194
+#: src/main.cc:217
 msgid " -h, --help                   Print this message and exit."
 msgstr ""
 
-#: src/main.cc:197
+#: src/main.cc:220
 msgid ""
 " You can specify multiple URLs. All URLs must point to the same file\n"
 " or downloading fails."
 msgstr ""
 
-#: src/main.cc:200
+#: src/main.cc:224
+msgid ""
+" Specify files in multi-file torrent to download. Use conjunction with\n"
+" -T option."
+msgstr ""
+
+#: src/main.cc:227
 msgid "Examples:"
 msgstr ""
 
-#: src/main.cc:201
+#: src/main.cc:228
 msgid " Download a file by 1 connection:"
 msgstr ""
 
-#: src/main.cc:203
+#: src/main.cc:230
 msgid " Download a file by 2 connections:"
 msgstr ""
 
-#: src/main.cc:205
+#: src/main.cc:232
 msgid " Download a file by 2 connections, each connects to a different server:"
 msgstr ""
 
-#: src/main.cc:207
+#: src/main.cc:234
 msgid " You can mix up different protocols:"
 msgstr ""
 
-#: src/main.cc:210
+#: src/main.cc:237
 msgid " Download a torrent:"
 msgstr ""
 
-#: src/main.cc:212
+#: src/main.cc:239
 msgid " Download a torrent using local .torrent file:"
 msgstr ""
 
-#: src/main.cc:216
+#: src/main.cc:241
+msgid " Download only selected files:"
+msgstr ""
+
+#: src/main.cc:245
 #, c-format
-msgid "Reports bugs to %s"
+msgid "Report bugs to %s"
 msgstr ""
 
-#: src/main.cc:307
+#: src/main.cc:338
 msgid "unrecognized proxy format"
 msgstr ""
 
-#: src/main.cc:333
+#: src/main.cc:364
 msgid "Currently, supported authentication scheme is basic."
 msgstr ""
 
-#: src/main.cc:342
+#: src/main.cc:373
 msgid "retry-wait must be between 0 and 60."
 msgstr ""
 
-#: src/main.cc:359
+#: src/main.cc:390
 msgid "ftp-type must be either 'binary' or 'ascii'."
 msgstr ""
 
-#: src/main.cc:368
+#: src/main.cc:399
 msgid "ftp-via-http-proxy must be either 'get' or 'tunnel'."
 msgstr ""
 
-#: src/main.cc:386
+#: src/main.cc:417
 msgid "min-segment-size invalid"
 msgstr ""
 
-#: src/main.cc:397
+#: src/main.cc:428
 msgid "http-proxy-method must be either 'get' or 'tunnel'."
 msgstr ""
 
-#: src/main.cc:411
+#: src/main.cc:436
+msgid "listen-port must be between 1024 and 65535."
+msgstr ""
+
+#: src/main.cc:447
 msgid "follow-torrent must be either 'true' or 'false'."
 msgstr ""
 
-#: src/main.cc:454
+#: src/main.cc:487
 msgid "split must be between 1 and 5."
 msgstr ""
 
-#: src/main.cc:464
+#: src/main.cc:497
 msgid "timeout must be between 1 and 600"
 msgstr ""
 
-#: src/main.cc:473
+#: src/main.cc:506
 msgid "max-tries invalid"
 msgstr ""
 
-#: src/main.cc:496
+#: src/main.cc:535
 msgid "specify at least one URL"
 msgstr ""
+
+#: src/main.cc:542
+msgid "daemon failed"
+msgstr ""
+
+#: src/main.cc:640
+msgid "Files:"
+msgstr ""
+
+#: src/main.cc:663
+msgid "Errors occurred while binding port.\n"
+msgstr ""

BIN
po/ja.gmo


+ 128 - 63
po/ja.po

@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: aria2c 0.2.1\n"
 "Report-Msgid-Bugs-To: http://aria2.sourceforge.net/\n"
-"POT-Creation-Date: 2006-04-12 22:55+0900\n"
-"PO-Revision-Date: 2006-03-22 00:48+0900\n"
+"POT-Creation-Date: 2006-04-19 02:02+0900\n"
+"PO-Revision-Date: 2006-04-19 02:03+0900\n"
 "Last-Translator: Tatsuhiro Tsujikawa <[email protected]>\n"
 "Language-Team: Japanese <[email protected]>\n"
 "MIME-Version: 1.0\n"
@@ -185,7 +185,7 @@ msgstr "
 msgid "Got EOF from the server."
 msgstr "サーバーから EOF を受けとりました."
 
-#: src/main.cc:63
+#: src/main.cc:64
 #, c-format
 msgid ""
 "\n"
@@ -194,7 +194,7 @@ msgstr ""
 "\n"
 "<%s> のダウンロードが完了しました.\n"
 
-#: src/main.cc:67
+#: src/main.cc:72
 msgid ""
 "\n"
 "The download was not complete because of errors. Check the log.\n"
@@ -202,26 +202,30 @@ msgstr ""
 "\n"
 "ダウンロードはエラーのため完了していません. ログを確認してください.\n"
 
-#: src/main.cc:78 src/main.cc:87
+#: src/main.cc:91 src/main.cc:102
 msgid ""
 "\n"
-"SIGINT signal received."
+"stopping application...\n"
 msgstr ""
 "\n"
-"SIGINT シグナルを受け取りました."
+"アプリケーションを終了しています...\n"
 
-#: src/main.cc:109
+#: src/main.cc:97 src/main.cc:114
+msgid "done\n"
+msgstr "完了\n"
+
+#: src/main.cc:125
 #, c-format
 msgid "Unrecognized URL or unsupported protocol: %s\n"
 msgstr ""
 "%s は, 理解できない URL フォーマット, または, サポートされないプロトコルで"
 "す.\n"
 
-#: src/main.cc:115
+#: src/main.cc:131
 msgid " version "
 msgstr " バージョン "
 
-#: src/main.cc:119
+#: src/main.cc:135
 msgid ""
 "This program is free software; you can redistribute it and/or modify\n"
 "it under the terms of the GNU General Public License as published by\n"
@@ -252,31 +256,36 @@ msgstr ""
 "Temple Place, Suite 330, Boston, MA 02111-1307 USA)。\n"
 "(訳: http://www.opensource.jp/gpl/gpl.ja.html.euc-jp)\n"
 
-#: src/main.cc:133
+#: src/main.cc:149
 #, c-format
 msgid "Contact Info: %s\n"
 msgstr "連絡先: %s\n"
 
-#: src/main.cc:139
+#: src/main.cc:155
 #, c-format
 msgid "Usage: %s [options] URL ...\n"
 msgstr "使い方: %s [オプション] URL ...\n"
 
-#: src/main.cc:141
+#: src/main.cc:156
+#, c-format
+msgid "       %s [options] -T TORRENT_FILE FILE ...\n"
+msgstr "        %s [オプション] -T TORRENT_FILE FILE ...\n"
+
+#: src/main.cc:159
 msgid "Options:"
 msgstr "オプション:"
 
-#: src/main.cc:142
+#: src/main.cc:160
 msgid " -d, --dir=DIR                The directory to store downloaded file."
 msgstr ""
 " -d, --dir=DIR                ダウンロードしたファイルを保存するディレクトリ."
 
-#: src/main.cc:143
+#: src/main.cc:161
 msgid " -o, --out=FILE               The file name for downloaded file."
 msgstr ""
 " -o, --out=FILE               ダウンロードしたファイルの保存先ファイル名."
 
-#: src/main.cc:144
+#: src/main.cc:162
 msgid ""
 " -l, --log=LOG                The file path to store log. If '-' is "
 "specified,\n"
@@ -286,11 +295,11 @@ msgstr ""
 "力\n"
 "                              に出力します."
 
-#: src/main.cc:146
+#: src/main.cc:164
 msgid " -D, --daemon                 Run as daemon."
 msgstr " -D, --daemon                 デーモンとして起動します."
 
-#: src/main.cc:147
+#: src/main.cc:165
 msgid ""
 " -s, --split=N                Download a file using N connections. N must "
 "be\n"
@@ -309,7 +318,7 @@ msgstr ""
 "ショ\n"
 "                              ンを確立します."
 
-#: src/main.cc:151
+#: src/main.cc:169
 msgid ""
 " --retry-wait=SEC             Set amount of time in second between requests\n"
 "                              for errors. Specify a value between 0 and 60.\n"
@@ -320,13 +329,13 @@ msgstr ""
 "                              す. 0 - 60 の値を指定してください.\n"
 "                              デフォルト値: 5"
 
-#: src/main.cc:154
+#: src/main.cc:172
 msgid " -t, --timeout=SEC            Set timeout in second. Default: 60"
 msgstr ""
 " -t, --timeout=SEC            タイムアウトとなる時間を秒で指定します.\n"
 "                              デフォルト値: 60"
 
-#: src/main.cc:155
+#: src/main.cc:173
 msgid ""
 " -m, --max-tries=N            Set number of tries. 0 means unlimited.\n"
 "                              Default: 5"
@@ -335,7 +344,7 @@ msgstr ""
 "行\n"
 "                              します. デフォルト値: 5"
 
-#: src/main.cc:157
+#: src/main.cc:175
 msgid ""
 " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n"
 "                              K or M(1K = 1024, 1M = 1024K). This\n"
@@ -348,7 +357,7 @@ msgstr ""
 "1024K).\n"
 "                              1024 以上の値を指定してください."
 
-#: src/main.cc:161
+#: src/main.cc:179
 msgid ""
 " --http-proxy=HOST:PORT       Use HTTP proxy server. This affects to all\n"
 "                              URLs."
@@ -357,14 +366,14 @@ msgstr ""
 "シ\n"
 "                              ョンはすべての URL に影響します."
 
-#: src/main.cc:163
+#: src/main.cc:181
 msgid " --http-user=USER             Set HTTP user. This affects to all URLs."
 msgstr ""
 " --http-user=USER             HTTP での認証ユーザーを指定します. このオプショ"
 "ン\n"
 "                              はすべての URL に影響します."
 
-#: src/main.cc:164
+#: src/main.cc:182
 msgid ""
 " --http-passwd=PASSWD         Set HTTP password. This affects to all URLs."
 msgstr ""
@@ -372,7 +381,7 @@ msgstr ""
 "ショ\n"
 "                              ンはすべての URL に影響します."
 
-#: src/main.cc:165
+#: src/main.cc:183
 msgid ""
 " --http-proxy-user=USER       Set HTTP proxy user. This affects to all URLs"
 msgstr ""
@@ -382,7 +391,7 @@ msgstr ""
 "ま\n"
 "                              す."
 
-#: src/main.cc:166
+#: src/main.cc:184
 msgid ""
 " --http-proxy-passwd=PASSWD   Set HTTP proxy password. This affects to all "
 "URLs."
@@ -393,7 +402,7 @@ msgstr ""
 "し\n"
 "                              ます."
 
-#: src/main.cc:167
+#: src/main.cc:185
 msgid ""
 " --http-proxy-method=METHOD   Set the method to use in proxy request.\n"
 "                              METHOD is either 'get' or 'tunnel'.\n"
@@ -404,7 +413,7 @@ msgstr ""
 "                              す. 'get' または 'tunnel' を指定してください.\n"
 "                              デフォルト値: tunnel"
 
-#: src/main.cc:170
+#: src/main.cc:188
 msgid ""
 " --http-auth-scheme=SCHEME    Set HTTP authentication scheme. Currently, "
 "basic\n"
@@ -422,14 +431,14 @@ msgstr ""
 "定\n"
 "                              する必要があります."
 
-#: src/main.cc:174
+#: src/main.cc:192
 msgid " --referer=REFERER            Set Referer. This affects to all URLs."
 msgstr ""
 " --referer=REFERER            リファラーを指定します. このオプションはすべて"
 "の\n"
 "                               URL に影響します."
 
-#: src/main.cc:175
+#: src/main.cc:193
 msgid ""
 " --ftp-user=USER              Set FTP user. This affects to all URLs.\n"
 "                              Default: anonymous"
@@ -439,7 +448,7 @@ msgstr ""
 "                              はすべての URL に影響します.\n"
 "                              デフォルト値: anonymous"
 
-#: src/main.cc:177
+#: src/main.cc:195
 msgid ""
 " --ftp-passwd=PASSWD          Set FTP password. This affects to all URLs.\n"
 "                              Default: ARIA2USER@"
@@ -449,7 +458,7 @@ msgstr ""
 "                              ンはすべての URL に影響します.\n"
 "                              デフォルト値: ARIA2USER@"
 
-#: src/main.cc:179
+#: src/main.cc:197
 msgid ""
 " --ftp-type=TYPE              Set FTP transfer type. TYPE is either "
 "'binary'\n"
@@ -460,11 +469,11 @@ msgstr ""
 "                              'ascii' を指定してください. デフォルト値: "
 "binary"
 
-#: src/main.cc:182
+#: src/main.cc:200
 msgid " -p, --ftp-pasv               Use passive mode in FTP."
 msgstr " -p, --ftp-pasv               FTP で passive モードを使用します."
 
-#: src/main.cc:183
+#: src/main.cc:201
 msgid ""
 " --ftp-via-http-proxy=METHOD  Use HTTP proxy in FTP. METHOD is either 'get' "
 "or\n"
@@ -477,11 +486,11 @@ msgstr ""
 "く\n"
 "                              ださい. デフォルト値: tunnel"
 
-#: src/main.cc:187
-msgid " --torrent-file=TORRENT_FILE  The file path to .torrent file."
-msgstr " --torrent-file=TORRENT_FILE  .torrent ファイルのパスを指定."
+#: src/main.cc:205
+msgid " -T, --torrent-file=TORRENT_FILE  The file path to .torrent file."
+msgstr " -T, --torrent-file=TORRENT_FILE  .torrent ファイルのパスを指定."
 
-#: src/main.cc:188
+#: src/main.cc:206
 msgid ""
 " --follow-torrent=true|false  Setting this option to false prevents aria2 "
 "to\n"
@@ -496,16 +505,43 @@ msgstr ""
 "                              は, BitTorrent モードに入りません.\n"
 "                              デフォルト値: true"
 
-#: src/main.cc:193
+#: src/main.cc:210
+msgid ""
+" -S, --show-files             Print the file listing in .torrent file and "
+"exit."
+msgstr ""
+" -S, --show-files             .torrent ファイルに記載のファイルリストを出力"
+"し\n"
+"                              終了します."
+
+#: src/main.cc:211
+msgid ""
+" --direct-file-mapping=true|false Directly read from and write to each file\n"
+"                              mentioned in .torrent file.\n"
+"                              Default: true"
+msgstr ""
+" --direct-file-mapping=true|false .torrent ファイル記載のファイルに直接読み書"
+"き\n"
+"                              します.\n"
+"                              デフォルト値: true"
+
+#: src/main.cc:214
+msgid ""
+" --listen-port                Set port number to listen to for peer "
+"connection."
+msgstr ""
+" --listen-port                ピアからの接続を受け付けるポート番号を指定."
+
+#: src/main.cc:216
 msgid " -v, --version                Print the version number and exit."
 msgstr " -v, --version                バージョン番号を表示し, 終了します."
 
-#: src/main.cc:194
+#: src/main.cc:217
 msgid " -h, --help                   Print this message and exit."
 msgstr ""
 " -h, --help                   このヘルプメッセージを表示し, 終了します."
 
-#: src/main.cc:197
+#: src/main.cc:220
 msgid ""
 " You can specify multiple URLs. All URLs must point to the same file\n"
 " or downloading fails."
@@ -514,83 +550,112 @@ msgstr ""
 "れ\n"
 " ばなりません. さもなくばダウンロードは失敗します."
 
-#: src/main.cc:200
+#: src/main.cc:224
+msgid ""
+" Specify files in multi-file torrent to download. Use conjunction with\n"
+" -T option."
+msgstr ""
+" multi-file torrent のとき, ダウンロードするファイルを指定. -T オプションと共"
+"に\n"
+" 使用する."
+
+#: src/main.cc:227
 msgid "Examples:"
 msgstr "例:"
 
-#: src/main.cc:201
+#: src/main.cc:228
 msgid " Download a file by 1 connection:"
 msgstr " 1 コネクションでのダウンロード:"
 
-#: src/main.cc:203
+#: src/main.cc:230
 msgid " Download a file by 2 connections:"
 msgstr " 2 コネクションでのダウンロード:"
 
-#: src/main.cc:205
+#: src/main.cc:232
 msgid " Download a file by 2 connections, each connects to a different server:"
 msgstr " 二つの異なるサーバーに接続してダウンロード:"
 
-#: src/main.cc:207
+#: src/main.cc:234
 msgid " You can mix up different protocols:"
 msgstr " 異なるプロトコルを混合させてダウンロード:"
 
-#: src/main.cc:210
+#: src/main.cc:237
 msgid " Download a torrent:"
 msgstr "torrent をダウンロード:"
 
-#: src/main.cc:212
+#: src/main.cc:239
 msgid " Download a torrent using local .torrent file:"
 msgstr " ローカル .torrent ファイルを使ってダウンロード:"
 
-#: src/main.cc:216
+#: src/main.cc:241
+msgid " Download only selected files:"
+msgstr " ファイルを指定してダウンロード:"
+
+#: src/main.cc:245
 #, c-format
-msgid "Reports bugs to %s"
+msgid "Report bugs to %s"
 msgstr "バグレポートはこちらへ: %s"
 
-#: src/main.cc:307
+#: src/main.cc:338
 msgid "unrecognized proxy format"
 msgstr "理解できないProxyフォーマットです."
 
-#: src/main.cc:333
+#: src/main.cc:364
 msgid "Currently, supported authentication scheme is basic."
 msgstr "現在サポートされている認証方法は basic です."
 
-#: src/main.cc:342
+#: src/main.cc:373
 msgid "retry-wait must be between 0 and 60."
 msgstr "retry-wait は 0 から 60 の間で指定してください."
 
-#: src/main.cc:359
+#: src/main.cc:390
 msgid "ftp-type must be either 'binary' or 'ascii'."
 msgstr "ftp-type は 'binary' または 'ascii' を指定してください."
 
-#: src/main.cc:368
+#: src/main.cc:399
 msgid "ftp-via-http-proxy must be either 'get' or 'tunnel'."
 msgstr "ftp-via-http-proxy は 'get' または 'tunnel' を指定してください."
 
-#: src/main.cc:386
+#: src/main.cc:417
 msgid "min-segment-size invalid"
 msgstr "min-segment-size が不正です."
 
-#: src/main.cc:397
+#: src/main.cc:428
 msgid "http-proxy-method must be either 'get' or 'tunnel'."
 msgstr "http-proxy-method は 'get' または 'tunnel' を指定してください."
 
-#: src/main.cc:411
+#: src/main.cc:436
+msgid "listen-port must be between 1024 and 65535."
+msgstr "listen-port は 1024 - 65535 の値を指定してください."
+
+#: src/main.cc:447
 msgid "follow-torrent must be either 'true' or 'false'."
 msgstr "follow-torrent は 'true' または 'false を指定してください."
 
-#: src/main.cc:454
+#: src/main.cc:487
 msgid "split must be between 1 and 5."
 msgstr "split は 1 - 5 の値を指定してください."
 
-#: src/main.cc:464
+#: src/main.cc:497
 msgid "timeout must be between 1 and 600"
 msgstr "timeout は 1 - 600 の値を指定してください."
 
-#: src/main.cc:473
+#: src/main.cc:506
 msgid "max-tries invalid"
 msgstr "max-tries が不正です."
 
-#: src/main.cc:496
+#: src/main.cc:535
 msgid "specify at least one URL"
 msgstr "一個以上の URL を指定してください."
+
+#: src/main.cc:542
+msgid "daemon failed"
+msgstr "デーモン起動に失敗"
+
+#: src/main.cc:640
+msgid "Files:"
+msgstr "ファイル:"
+
+#: src/main.cc:663
+msgid "Errors occurred while binding port.\n"
+msgstr "ポートをバインド中にエラーが発生しました.\n"

+ 3 - 3
src/AbstractDiskWriter.cc

@@ -36,7 +36,7 @@ AbstractDiskWriter::AbstractDiskWriter():fd(0) {
 }
 
 AbstractDiskWriter::~AbstractDiskWriter() {
-  if(fd > 0) {
+  if(fd >= 0) {
     close(fd);
   }
 #ifdef ENABLE_SHA1DIGEST
@@ -54,9 +54,9 @@ void AbstractDiskWriter::openFile(const string& filename) {
 }
 
 void AbstractDiskWriter::closeFile() {
-  if(fd > 0) {
+  if(fd >= 0) {
     close(fd);
-    fd = 0;
+    fd = -1;
   }
 }
 

+ 136 - 0
src/CompactTrackerResponseProcessor.cc

@@ -0,0 +1,136 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* copyright --> */
+#include "CompactTrackerResponseProcessor.h"
+#include "LogFactory.h"
+#include "TorrentDownloadEngine.h"
+#include "MetaFileUtil.h"
+#include "DlAbortEx.h"
+#include "message.h"
+#include "PeerInitiateConnectionCommand.h"
+#include <netinet/in.h>
+
+CompactTrackerResponseProcessor::CompactTrackerResponseProcessor(ByteArrayDiskWriter* diskWriter, TorrentDownloadEngine* e, Request* req):
+  diskWriter(diskWriter),
+  e(e),
+  req(req) {
+  logger = LogFactory::getInstance();
+}
+
+CompactTrackerResponseProcessor::~CompactTrackerResponseProcessor() {}
+
+void CompactTrackerResponseProcessor::resetTrackerResponse() {
+  if(e->segmentMan->finished()) {
+    diskWriter->reset();
+    e->segmentMan->init();
+  }
+}
+
+void CompactTrackerResponseProcessor::execute() {
+  MetaEntry* entry = NULL;
+  try {
+    entry = MetaFileUtil::bdecoding(diskWriter->getByteArray(),
+				    diskWriter->getByteArrayLength());
+    Dictionary* response = (Dictionary*)entry;
+    Data* failureReason = (Data*)response->get("failure reason");
+    if(failureReason != NULL) {
+      throw new DlAbortEx("Tracker returned failure reason: %s", failureReason->toString().c_str());
+    }
+    Data* warningMessage = (Data*)response->get("warning message");
+    if(warningMessage != NULL) {
+      logger->warn(MSG_TRACKER_WARNING_MESSAGE, warningMessage->toString().c_str());
+    }
+    Data* trackerId = (Data*)response->get("tracker id");
+    if(trackerId != NULL) {
+      e->torrentMan->trackerId = trackerId->toString();
+      logger->debug("Tracker ID:%s", e->torrentMan->trackerId.c_str());
+    }
+    Data* interval = (Data*)response->get("interval");
+    if(interval != NULL) {
+      e->torrentMan->interval = interval->toInt();
+      logger->debug("interval:%d", e->torrentMan->interval);
+    }
+    Data* minInterval = (Data*)response->get("min interval");
+    if(minInterval != NULL) {
+      e->torrentMan->minInterval = minInterval->toInt();
+      logger->debug("min interval:%d", e->torrentMan->minInterval);
+    }
+    if(e->torrentMan->minInterval > e->torrentMan->interval) {
+      e->torrentMan->minInterval = e->torrentMan->interval;
+    }
+    Data* complete = (Data*)response->get("complete");
+    if(complete != NULL) {
+      e->torrentMan->complete = complete->toInt();
+      logger->debug("complete:%d", e->torrentMan->complete);
+    }
+    Data* incomplete = (Data*)response->get("incomplete");
+    if(incomplete != NULL) {
+      e->torrentMan->incomplete = incomplete->toInt();
+      logger->debug("incomplete:%d", e->torrentMan->incomplete);
+    } 
+    Data* peers = (Data*)response->get("peers");
+    if(peers != NULL) {
+      for(int i = 0; i < peers->getLen(); i += 6) {
+	unsigned int ipaddr1 = (unsigned char)*(peers->getData()+i);
+	unsigned int ipaddr2 = (unsigned char)*(peers->getData()+i+1);
+	unsigned int ipaddr3 = (unsigned char)*(peers->getData()+i+2);
+	unsigned int ipaddr4 = (unsigned char)*(peers->getData()+i+3);
+	unsigned int port = ntohs(*(unsigned short int*)(peers->getData()+i+4));
+	char ipaddr[16];
+	
+	snprintf(ipaddr, sizeof(ipaddr), "%d.%d.%d.%d",
+		 ipaddr1, ipaddr2, ipaddr3, ipaddr4);
+	Peer* peer = new Peer(ipaddr, port, e->torrentMan->pieceLength,
+			      e->torrentMan->getTotalLength());
+	if(e->torrentMan->addPeer(peer)) {
+	  logger->debug("adding peer %s:%d", peer->ipaddr.c_str(), peer->port);
+	} else {
+	  delete peer;
+	}
+    }
+    } else {
+      logger->info("no peer list received.");
+    }
+    while(e->torrentMan->isPeerAvailable() &&
+	  e->torrentMan->connections < MAX_PEER_UPDATE) {
+      Peer* peer = e->torrentMan->getPeer();
+      int newCuid =  e->torrentMan->getNewCuid();
+      peer->cuid = newCuid;
+      PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(newCuid, peer, e);
+      e->commands.push(command);
+      logger->debug("adding new command CUID#%d", newCuid);
+    }
+    if(req->getTrackerEvent() == Request::STARTED) {
+      req->setTrackerEvent(Request::AUTO);
+    }
+  } catch(Exception* err) {
+    logger->error("Error occurred while processing tracker response.", err);
+    delete(err);
+  }
+  if(entry != NULL) {
+    delete entry;
+  }
+  e->torrentMan->trackers = 0;
+}
+
+bool CompactTrackerResponseProcessor::isFeeded() const {
+  return e->segmentMan->finished();
+}

+ 19 - 12
src/TrackerUpdateCommand.h → src/CompactTrackerResponseProcessor.h

@@ -19,24 +19,31 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 /* copyright --> */
-#ifndef _D_TRACKER_UPDATE_COMMAND_H_
-#define _D_TRACKER_UPDATE_COMMAND_H_
+#ifndef _D_COMPACT_TRACKER_RESPONSE_PROCESSOR_H_
+#define _D_COMPACT_TRACKER_RESPONSE_PROCESSOR_H_
 
-#include "Command.h"
+#include "common.h"
+#include "ByteArrayDiskWriter.h"
 #include "Request.h"
-#include "TorrentDownloadEngine.h"
-#include "MetaEntry.h"
 
-class TrackerUpdateCommand : public Command {
+class TorrentDownloadEngine;
+class Logger;
+
+class CompactTrackerResponseProcessor {
 private:
-  Request* req;
+  ByteArrayDiskWriter* diskWriter;
   TorrentDownloadEngine* e;
-  MetaEntry* trackerResponse;
+  Request* req;
+  const Logger* logger;
 public:
-  TrackerUpdateCommand(int cuid, Request* req, TorrentDownloadEngine* e, MetaEntry* trackerResponse);
-  ~TrackerUpdateCommand();
+  CompactTrackerResponseProcessor(ByteArrayDiskWriter* diskWriter,
+				  TorrentDownloadEngine* e,
+				  Request* req);
+  ~CompactTrackerResponseProcessor();
 
-  bool execute();
+  bool isFeeded() const;
+  void execute();
+  void resetTrackerResponse();
 };
 
-#endif // _D_TRACKER_UPDATE_COMMAND_H_
+#endif // _D_COMPACT_TRACKER_RESPONSE_PROCESSOR_H_

+ 30 - 10
src/ConsoleDownloadEngine.cc

@@ -27,35 +27,55 @@ ConsoleDownloadEngine::ConsoleDownloadEngine() {}
 ConsoleDownloadEngine::~ConsoleDownloadEngine() {}
 
 void ConsoleDownloadEngine::sendStatistics(long long int currentSize, long long int totalSize) {
-  cout << "\r                                                                            ";
-  cout << "\rProgress " <<
-    Util::llitos(currentSize, true) << " Bytes/" <<
-    Util::llitos(totalSize, true) << " Bytes " <<
-    (totalSize == 0 ? 0 : (currentSize*100)/totalSize) << "% " <<
-    speed/1000.0 << "KB/s " <<
-    "(" << commands.size() << " connections)" << flush;
+  printf("\r                                                                             ");
+  printf("\r");
+  printf("%s/%s Bytes %d%% %s %.2f KB/s %d connections",
+	 Util::llitos(currentSize, true).c_str(),
+	 Util::llitos(totalSize, true).c_str(),
+	 (totalSize == 0 ? 0 : (int)((currentSize*100)/totalSize)),
+	 avgSpeed == 0 ? "-" : Util::secfmt(eta).c_str(),
+	 speed/1024.0,
+	 commands.size());
+  fflush(stdout);
 }
 
 void ConsoleDownloadEngine::initStatistics() {
   cp.tv_sec = cp.tv_usec = 0;
   speed = 0;
   psize = 0;
+  avgSpeed = 0;
+  eta = 0;
+  startupLength = 0;
+  isStartupLengthSet = false;
+  gettimeofday(&startup, NULL);
 }
 
 void ConsoleDownloadEngine::calculateStatistics() {
   long long int dlSize = segmentMan->getDownloadedSize();
+  if(!isStartupLengthSet && dlSize > 0) {
+    startupLength = dlSize;
+    isStartupLengthSet = true;
+  }
   struct timeval now;
   gettimeofday(&now, NULL);
   if(cp.tv_sec == 0 && cp.tv_usec == 0) {
     cp = now;
     psize = dlSize;
   } else {
-    long long int elapsed = Util::difftv(now, cp);
-    if(elapsed >= 500000) {
-      int nspeed = (int)((dlSize-psize)/(elapsed/1000000.0));
+    int elapsed = Util::difftvsec(now, cp);
+    if(elapsed >= 1) {
+      int nspeed = (int)((dlSize-psize)/elapsed);
       speed = (nspeed+speed)/2;
       cp = now;
       psize = dlSize;
+
+      avgSpeed = (int)((dlSize-startupLength)/Util::difftvsec(now, startup));
+      if(avgSpeed < 0) {
+	avgSpeed = 0;
+      } else if(avgSpeed != 0 && segmentMan->totalSize > 0) {
+	eta = (segmentMan->totalSize-dlSize)/avgSpeed;
+      }
+
       sendStatistics(dlSize, segmentMan->totalSize);
     }
   }

+ 9 - 0
src/ConsoleDownloadEngine.h

@@ -29,6 +29,15 @@ private:
   struct timeval cp;
   long long int psize;
   int speed;
+  // The time when startup
+  struct timeval startup;
+  // The number of bytes downloaded at startup
+  long long int startupLength;
+  bool isStartupLengthSet;
+  // The average speed(bytes per second) since startup
+  int avgSpeed;
+  // The estimated remaining time to complete the download.
+  int eta;
 protected:
   void sendStatistics(long long int currentSize, long long int totalSize);
   void initStatistics();

+ 11 - 18
src/HttpResponseCommand.cc

@@ -26,9 +26,6 @@
 #include "HttpInitiateConnectionCommand.h"
 #include "message.h"
 #include "Util.h"
-#include "TrackerDownloadCommand.h"
-// TODO
-#include "TorrentDownloadEngine.h"
 
 HttpResponseCommand::HttpResponseCommand(int cuid, Request* req, DownloadEngine* e, const Socket* s):
   AbstractCommand(cuid, req, e, s) {
@@ -97,6 +94,7 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpHeader& headers) {
     long long int size = headers.getFirstAsLLInt("Content-Length");
     e->segmentMan->totalSize = size;
     e->segmentMan->isSplittable = false;
+    e->segmentMan->downloadStarted = true;
     createHttpDownloadCommand();
     return true;
   }
@@ -138,22 +136,17 @@ bool HttpResponseCommand::handleOtherEncoding(string transferEncoding, const Htt
 }
 
 void HttpResponseCommand::createHttpDownloadCommand(string transferEncoding) {
-  if(!req->isTorrent) {
-    HttpDownloadCommand* command = new HttpDownloadCommand(cuid, req, e, socket);
-    TransferEncoding* enc = NULL;
-    if(transferEncoding.size() && (enc = command->getTransferEncoding(transferEncoding)) == NULL) {
-      delete(command);
-      throw new DlAbortEx(EX_TRANSFER_ENCODING_NOT_SUPPORTED, transferEncoding.c_str());
-    } else {
-      if(enc != NULL) {
-	command->transferEncoding = transferEncoding;
-	enc->init();
-      }
-      e->commands.push(command);
-    }
+  
+  HttpDownloadCommand* command = new HttpDownloadCommand(cuid, req, e, socket);
+  TransferEncoding* enc = NULL;
+  if(transferEncoding.size() && (enc = command->getTransferEncoding(transferEncoding)) == NULL) {
+    delete(command);
+    throw new DlAbortEx(EX_TRANSFER_ENCODING_NOT_SUPPORTED, transferEncoding.c_str());
   } else {
-    // TODO
-    TrackerDownloadCommand* command = new TrackerDownloadCommand(cuid, req, (TorrentDownloadEngine*)e, socket);
+    if(enc != NULL) {
+      command->transferEncoding = transferEncoding;
+      enc->init();
+    }
     e->commands.push(command);
   }
 }

+ 3 - 4
src/Makefile.am

@@ -54,9 +54,6 @@ SRCS =  Socket.cc Socket.h\
 	MetaFileUtil.cc MetaFileUtil.h\
 	MetaEntryVisitor.h\
 	ShaVisitor.cc ShaVisitor.h\
-	TrackerInitCommand.cc TrackerInitCommand.h\
-	TrackerDownloadCommand.cc TrackerDownloadCommand.h\
-	TrackerUpdateCommand.cc TrackerUpdateCommand.h\
 	TorrentMan.cc TorrentMan.h\
 	PeerConnection.cc PeerConnection.h\
 	PeerMessageUtil.cc PeerMessageUtil.h\
@@ -85,7 +82,9 @@ SRCS =  Socket.cc Socket.h\
 	DirectDiskAdaptor.cc DirectDiskAdaptor.h\
 	MultiDiskAdaptor.cc MultiDiskAdaptor.h\
 	FileEntry.h\
-	LogFactory.cc LogFactory.h
+	LogFactory.cc LogFactory.h\
+	CompactTrackerResponseProcessor.cc CompactTrackerResponseProcessor.h\
+	ByteArrayDiskWriter.cc ByteArrayDiskWriter.h
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
 aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\

+ 9 - 12
src/Makefile.in

@@ -86,10 +86,8 @@ am__objects_1 = Socket.$(OBJEXT) SocketCore.$(OBJEXT) \
 	File.$(OBJEXT) Option.$(OBJEXT) Base64.$(OBJEXT) \
 	CookieBox.$(OBJEXT) Data.$(OBJEXT) Dictionary.$(OBJEXT) \
 	List.$(OBJEXT) MetaFileUtil.$(OBJEXT) ShaVisitor.$(OBJEXT) \
-	TrackerInitCommand.$(OBJEXT) TrackerDownloadCommand.$(OBJEXT) \
-	TrackerUpdateCommand.$(OBJEXT) TorrentMan.$(OBJEXT) \
-	PeerConnection.$(OBJEXT) PeerMessageUtil.$(OBJEXT) \
-	PeerAbstractCommand.$(OBJEXT) \
+	TorrentMan.$(OBJEXT) PeerConnection.$(OBJEXT) \
+	PeerMessageUtil.$(OBJEXT) PeerAbstractCommand.$(OBJEXT) \
 	PeerInitiateConnectionCommand.$(OBJEXT) \
 	PeerInteractionCommand.$(OBJEXT) Peer.$(OBJEXT) \
 	BitfieldMan.$(OBJEXT) TorrentDownloadEngine.$(OBJEXT) \
@@ -101,7 +99,8 @@ am__objects_1 = Socket.$(OBJEXT) SocketCore.$(OBJEXT) \
 	SendMessageQueue.$(OBJEXT) MultiDiskWriter.$(OBJEXT) \
 	DiskAdaptor.$(OBJEXT) CopyDiskAdaptor.$(OBJEXT) \
 	DirectDiskAdaptor.$(OBJEXT) MultiDiskAdaptor.$(OBJEXT) \
-	LogFactory.$(OBJEXT)
+	LogFactory.$(OBJEXT) CompactTrackerResponseProcessor.$(OBJEXT) \
+	ByteArrayDiskWriter.$(OBJEXT)
 am_libaria2c_a_OBJECTS = $(am__objects_1)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(bindir)"
@@ -305,9 +304,6 @@ SRCS = Socket.cc Socket.h\
 	MetaFileUtil.cc MetaFileUtil.h\
 	MetaEntryVisitor.h\
 	ShaVisitor.cc ShaVisitor.h\
-	TrackerInitCommand.cc TrackerInitCommand.h\
-	TrackerDownloadCommand.cc TrackerDownloadCommand.h\
-	TrackerUpdateCommand.cc TrackerUpdateCommand.h\
 	TorrentMan.cc TorrentMan.h\
 	PeerConnection.cc PeerConnection.h\
 	PeerMessageUtil.cc PeerMessageUtil.h\
@@ -336,7 +332,9 @@ SRCS = Socket.cc Socket.h\
 	DirectDiskAdaptor.cc DirectDiskAdaptor.h\
 	MultiDiskAdaptor.cc MultiDiskAdaptor.h\
 	FileEntry.h\
-	LogFactory.cc LogFactory.h
+	LogFactory.cc LogFactory.h\
+	CompactTrackerResponseProcessor.cc CompactTrackerResponseProcessor.h\
+	ByteArrayDiskWriter.cc ByteArrayDiskWriter.h
 
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
@@ -426,7 +424,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AbstractDiskWriter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ByteArrayDiskWriter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedEncoding.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CompactTrackerResponseProcessor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConsoleDownloadEngine.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBox.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CopyDiskAdaptor.Po@am__quote@
@@ -488,9 +488,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentConsoleDownloadEngine.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentDownloadEngine.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentMan.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerDownloadCommand.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerInitCommand.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerUpdateCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@

+ 6 - 0
src/SegmentMan.cc

@@ -212,3 +212,9 @@ long long int SegmentMan::getDownloadedSize() const {
   return size;
 }
 
+void SegmentMan::init() {
+  totalSize = 0;
+  isSplittable = false;
+  downloadStarted = false;
+  segments.clear();
+}

+ 3 - 0
src/SegmentMan.h

@@ -89,6 +89,9 @@ public:
   SegmentMan();
   ~SegmentMan();
   
+  // Initializes totalSize, isSplittable, downloadStarted.
+  void init();
+
   /**
    * Returns dir+"/"+filename.
    * If filename is empty, then returns dir+"/"+"inex.html";

+ 2 - 2
src/TorrentConsoleDownloadEngine.cc

@@ -45,7 +45,7 @@ void TorrentConsoleDownloadEngine::printStatistics() {
 	   avgSpeed == 0 ? "-" : Util::secfmt(eta).c_str(),
 	   downloadSpeed/1024.0);
   }
-  printf(" U:%.2f(%s) %dpeers",
+  printf(" U:%.2f(%s) %d peers",
 	 uploadSpeed/1024.0,
 	 Util::llitos(torrentMan->getUploadLength(), true).c_str(),
 	 torrentMan->connections);
@@ -76,7 +76,7 @@ void TorrentConsoleDownloadEngine::initStatistics() {
 }
 
 int TorrentConsoleDownloadEngine::calculateSpeed(long long int sessionLength, int elapsed) {
-  int nowSpeed = (int)(sessionLength/(elapsed*1.0));
+  int nowSpeed = (int)(sessionLength/elapsed);
   return nowSpeed;
 }
 

+ 2 - 0
src/TorrentDownloadEngine.cc

@@ -35,9 +35,11 @@ void TorrentDownloadEngine::afterEachIteration() {
     if(torrentMan->isSelectiveDownloadingMode()) {
       onSelectiveDownloadingCompletes();
     }
+    logger->info("The download was complete.");
     torrentMan->onDownloadComplete();
     if(torrentMan->downloadComplete()) {
       filenameFixed = true;
     }
   }
+  torrentMan->processTrackerResponse();
 }

+ 9 - 2
src/TorrentMan.cc

@@ -50,7 +50,7 @@ TorrentMan::TorrentMan():bitfield(NULL),
 			 interval(DEFAULT_ANNOUNCE_INTERVAL),
 			 minInterval(DEFAULT_ANNOUNCE_MIN_INTERVAL),
 			 complete(0), incomplete(0),
-			 connections(0), diskAdaptor(NULL) {
+			 connections(0), trackers(0), diskAdaptor(NULL) {
   logger = LogFactory::getInstance();
 }
 
@@ -394,7 +394,7 @@ void TorrentMan::setup(string metaInfoFile, const Strings& targetFilePaths) {
       diskAdaptor = new MultiDiskAdaptor(new MultiDiskWriter(pieceLength));
     }
   } else {
-    diskAdaptor = new CopyDiskAdaptor(new DefaultDiskWriter(totalLength));
+    diskAdaptor = new CopyDiskAdaptor(new PreAllocationDiskWriter(totalLength));
     ((CopyDiskAdaptor*)diskAdaptor)->setTempFilename(name+".a2tmp");
   }
   diskAdaptor->setStoreDir(storeDir);
@@ -567,3 +567,10 @@ void TorrentMan::onDownloadComplete() {
     finishSelectiveDownloadingMode();
   }
 }
+
+void TorrentMan::processTrackerResponse() {
+  if(responseProcessor->isFeeded()) {
+    responseProcessor->execute();
+    responseProcessor->resetTrackerResponse();
+  }
+}

+ 13 - 0
src/TorrentMan.h

@@ -32,6 +32,7 @@
 #include "Option.h"
 #include "FileEntry.h"
 #include "DiskAdaptor.h"
+#include "CompactTrackerResponseProcessor.h"
 #include <deque>
 #include <map>
 #include <string>
@@ -74,6 +75,7 @@ private:
   UsedPieces usedPieces;
   bool setupComplete;
   const Logger* logger;
+  CompactTrackerResponseProcessor* responseProcessor;
 
   FILE* openSegFile(string segFilename, string mode) const;
   void read(FILE* file);
@@ -97,6 +99,8 @@ public:
   int complete;
   int incomplete;
   int connections;
+  // The number of tracker request command currently in the command queue.
+  int trackers;
 public:
   TorrentMan();
   ~TorrentMan();
@@ -227,6 +231,15 @@ public:
 
   void onDownloadComplete();
 
+  void setTrackerResponseProcessor(CompactTrackerResponseProcessor* proc) {
+    this->responseProcessor = proc;
+  }
+  CompactTrackerResponseProcessor* getTrackerResponseProcessor() const {
+    return this->responseProcessor;
+  }
+
+  void processTrackerResponse();  
+
   enum FILE_MODE {
     SINGLE,
     MULTI

+ 0 - 99
src/TrackerDownloadCommand.cc

@@ -1,99 +0,0 @@
-/* <!-- copyright */
-/*
- * aria2 - a simple utility for downloading files faster
- *
- * Copyright (C) 2006 Tatsuhiro Tsujikawa
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/* copyright --> */
-#include "TrackerDownloadCommand.h"
-#include "TrackerUpdateCommand.h"
-#include "ChunkedEncoding.h"
-#include "DlRetryEx.h"
-#include "message.h"
-#include "MetaFileUtil.h"
-#include "DlAbortEx.h"
-
-TrackerDownloadCommand::TrackerDownloadCommand(int cuid, Request* req,
-					       TorrentDownloadEngine* e,
-					       const Socket* s)
-  :AbstractCommand(cuid, req, e, s), len(0) {
-  resSize = 256;
-  res = new char[resSize];
-  ChunkedEncoding* ce = new ChunkedEncoding();
-  transferEncodings["chunked"] = ce;
-}
-
-TrackerDownloadCommand::~TrackerDownloadCommand() {
-  delete [] res;
-  for(map<string, TransferEncoding*>::iterator itr = transferEncodings.begin(); itr != transferEncodings.end(); itr++) {
-    delete((*itr).second);
-  }
-}
-
-bool TrackerDownloadCommand::executeInternal(Segment seg) {
-  TransferEncoding* te = NULL;
-  if(transferEncoding.size()) {
-    te = getTransferEncoding(transferEncoding);
-    assert(te != NULL);
-  }
-  int bufSize = 4096;
-  char buf[bufSize];
-  socket->readData(buf, bufSize);
-  if(te != NULL) {
-    int infbufSize = 4096;
-    char infbuf[infbufSize];
-    te->inflate(infbuf, infbufSize, buf, bufSize);
-    if(len+infbufSize >= resSize) {
-      expandBuffer(len+infbufSize);
-    }
-    memcpy(res+len, infbuf, infbufSize);
-    len += infbufSize;
-  } else {
-    if(len+bufSize >= resSize) {
-      expandBuffer(len+bufSize);
-    }
-    memcpy(res+len, buf, bufSize);
-    len += bufSize;
-  }
-  if(e->segmentMan->totalSize != 0 && bufSize == 0) {
-    throw new DlRetryEx(EX_GOT_EOF);
-  }
-  if(te != NULL && te->finished()
-     || te == NULL && len == e->segmentMan->totalSize
-     || bufSize == 0) {
-    if(te != NULL) te->end();
-    logger->info(MSG_DOWNLOAD_COMPLETED, cuid);
-    MetaEntry* entry = MetaFileUtil::bdecoding(res, len);
-    e->commands.push(new TrackerUpdateCommand(cuid, req, (TorrentDownloadEngine*)e, entry));
-    return true;
-  } else {
-    e->commands.push(this);
-    return false;
-  }
-}
-
-TransferEncoding* TrackerDownloadCommand::getTransferEncoding(string name) {
-  return transferEncodings[name];
-}
-
-void TrackerDownloadCommand::expandBuffer(int newSize) {
-  char* newbuf = new char[newSize];
-  memcpy(newbuf, res, len);
-  delete [] res;
-  res = newbuf;
-  resSize = newSize;
-}

+ 0 - 50
src/TrackerDownloadCommand.h

@@ -1,50 +0,0 @@
-/* <!-- copyright */
-/*
- * aria2 - a simple utility for downloading files faster
- *
- * Copyright (C) 2006 Tatsuhiro Tsujikawa
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/* copyright --> */
-#ifndef _D_TRACKER_DOWNLOAD_COMMAND_H_
-#define _D_TRACKER_DOWNLOAD_COMMAND_H_
-
-#include "AbstractCommand.h"
-#include "TorrentDownloadEngine.h"
-#include "TransferEncoding.h"
-#include "Segment.h"
-#include <map>
-
-class TrackerDownloadCommand : public AbstractCommand {
-private:
-  char* res;
-  int resSize;
-  int len;
-  map<string, TransferEncoding*> transferEncodings;
-  void expandBuffer(int newSize);
-protected:
-  bool executeInternal(Segment segment);
-public:
-  TrackerDownloadCommand(int cuid, Request* req, TorrentDownloadEngine* e, const Socket* s);
-  ~TrackerDownloadCommand();
-
-  TransferEncoding* getTransferEncoding(string transferEncoding);
-
-  string transferEncoding;
-};
-
-#endif // _D_TRACKER_DOWNLOAD_COMMAND_H_
-

+ 0 - 77
src/TrackerInitCommand.cc

@@ -1,77 +0,0 @@
-/* <!-- copyright */
-/*
- * aria2 - a simple utility for downloading files faster
- *
- * Copyright (C) 2006 Tatsuhiro Tsujikawa
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/* copyright --> */
-#include "TrackerInitCommand.h"
-#include "Request.h"
-#include "InitiateConnectionCommandFactory.h"
-#include "TorrentMan.h"
-#include "Util.h"
-
-TrackerInitCommand::TrackerInitCommand(int cuid, Request* req, TorrentDownloadEngine* e):Command(cuid), req(req), e(e) {}
-
-TrackerInitCommand::~TrackerInitCommand() {}
-
-bool TrackerInitCommand::execute() {
-  if(e->torrentMan->downloadComplete()) {
-    if(req->getTrackerEvent() == Request::COMPLETED) {
-      req->setTrackerEvent(Request::AFTER_COMPLETED);
-    } else {
-      if(req->getTrackerEvent() == Request::STARTED) {
-	req->setTrackerEvent(Request::AFTER_COMPLETED);
-      } else if(req->getTrackerEvent() != Request::AFTER_COMPLETED) {
-	req->setTrackerEvent(Request::COMPLETED);
-      }
-    }
-  }
-  string event;
-  switch(req->getTrackerEvent()) {
-  case Request::STARTED:
-    event = "started";
-    break;
-  case Request::STOPPED:
-    event = "stopped";
-    break;
-  case Request::COMPLETED:
-    event = "completed";
-    break;
-  }
-  string url = e->torrentMan->announce+"?"+
-    "info_hash="+Util::urlencode(e->torrentMan->getInfoHash(), 20)+"&"+
-    "peer_id="+e->torrentMan->peerId+"&"+
-    "port="+Util::itos(e->torrentMan->getPort())+"&"+
-    "uploaded="+Util::llitos(e->torrentMan->getSessionUploadLength())+"&"+
-    "downloaded="+Util::llitos(e->torrentMan->getSessionDownloadLength())+"&"+
-    "left="+(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength() <= 0
-	     ? "0" : Util::llitos(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength()))+"&"+
-    "compact=1"+"&"+
-    "key="+e->torrentMan->peerId;
-  if(!event.empty()) {
-    url += string("&")+"event="+event;
-  }
-  if(!e->torrentMan->trackerId.empty()) {
-    url += string("&")+"trackerid="+e->torrentMan->trackerId;
-  }
-  req->setUrl(url);
-  Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, e);
-  e->commands.push(command);
-  return true;
-}
-

+ 0 - 40
src/TrackerInitCommand.h

@@ -1,40 +0,0 @@
-/* <!-- copyright */
-/*
- * aria2 - a simple utility for downloading files faster
- *
- * Copyright (C) 2006 Tatsuhiro Tsujikawa
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/* copyright --> */
-#ifndef _D_TRACKER_INIT_COMMAND_H_
-#define _D_TRACKER_INIT_COMMAND_H_
-
-#include "TorrentDownloadEngine.h"
-#include "Request.h"
-#include "Command.h"
-
-class TrackerInitCommand : public Command {
-private:
-  Request* req;
-  TorrentDownloadEngine* e;
-public:
-  TrackerInitCommand(int cuid, Request* req, TorrentDownloadEngine* e);
-  ~TrackerInitCommand();
-
-  bool execute();
-};
-
-#endif // _D_TRACKER_INIT_COMMAND_H_

+ 0 - 116
src/TrackerUpdateCommand.cc

@@ -1,116 +0,0 @@
-/* <!-- copyright */
-/*
- * aria2 - a simple utility for downloading files faster
- *
- * Copyright (C) 2006 Tatsuhiro Tsujikawa
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/* copyright --> */
-#include "TrackerUpdateCommand.h"
-#include "PeerInitiateConnectionCommand.h"
-#include "PeerListenCommand.h"
-#include "Dictionary.h"
-#include "Data.h"
-#include "DlAbortEx.h"
-#include "message.h"
-#include <netinet/in.h>
-
-TrackerUpdateCommand::TrackerUpdateCommand(int cuid, Request* req,
-					   TorrentDownloadEngine* e,
-					   MetaEntry* trackerResponse)
-  :Command(cuid), req(req), e(e), trackerResponse(trackerResponse) {
-}
-
-TrackerUpdateCommand::~TrackerUpdateCommand() {
-  delete trackerResponse;
-}
-
-bool TrackerUpdateCommand::execute() {
-  Dictionary* response = (Dictionary*)trackerResponse;
-  Data* failureReason = (Data*)response->get("failure reason");
-  if(failureReason != NULL) {
-    throw new DlAbortEx("Tracker returned failure reason: %s", failureReason->toString().c_str());
-  }
-  Data* warningMessage = (Data*)response->get("warning message");
-  if(warningMessage != NULL) {
-    logger->warn(MSG_TRACKER_WARNING_MESSAGE, cuid, warningMessage->toString().c_str());
-  }
-  Data* trackerId = (Data*)response->get("tracker id");
-  if(trackerId != NULL) {
-    e->torrentMan->trackerId = trackerId->toString();
-    logger->debug("CUID#%d - Tracker ID:%s", cuid, e->torrentMan->trackerId.c_str());
-  }
-  Data* interval = (Data*)response->get("interval");
-  if(interval != NULL) {
-    e->torrentMan->interval = interval->toInt();
-    logger->debug("CUID#%d - interval:%d", cuid, e->torrentMan->interval);
-  }
-  Data* minInterval = (Data*)response->get("min interval");
-  if(minInterval != NULL) {
-    e->torrentMan->minInterval = minInterval->toInt();
-    logger->debug("CUID#%d - min interval:%d", cuid, e->torrentMan->minInterval);
-  }
-  if(e->torrentMan->minInterval > e->torrentMan->interval) {
-    e->torrentMan->minInterval = e->torrentMan->interval;
-  }
-  Data* complete = (Data*)response->get("complete");
-  if(complete != NULL) {
-    e->torrentMan->complete = complete->toInt();
-    logger->debug("CUID#%d - complete:%d", cuid, e->torrentMan->complete);
-  }
-  Data* incomplete = (Data*)response->get("incomplete");
-  if(incomplete != NULL) {
-    e->torrentMan->incomplete = incomplete->toInt();
-    logger->debug("CUID#%d - incomplete:%d", cuid, e->torrentMan->incomplete);
-  } 
-  Data* peers = (Data*)response->get("peers");
-  if(peers != NULL) {
-    for(int i = 0; i < peers->getLen(); i += 6) {
-      unsigned int ipaddr1 = (unsigned char)*(peers->getData()+i);
-      unsigned int ipaddr2 = (unsigned char)*(peers->getData()+i+1);
-      unsigned int ipaddr3 = (unsigned char)*(peers->getData()+i+2);
-      unsigned int ipaddr4 = (unsigned char)*(peers->getData()+i+3);
-      unsigned int port = ntohs(*(unsigned short int*)(peers->getData()+i+4));
-      char ipaddr[16];
-      
-      snprintf(ipaddr, sizeof(ipaddr), "%d.%d.%d.%d",
-	       ipaddr1, ipaddr2, ipaddr3, ipaddr4);
-      Peer* peer = new Peer(ipaddr, port, e->torrentMan->pieceLength,
-			    e->torrentMan->getTotalLength());
-      if(e->torrentMan->addPeer(peer)) {
-	logger->debug("CUID#%d - adding peer %s:%d", cuid,
-			 peer->ipaddr.c_str(), peer->port);
-      } else {
-	delete peer;
-      }
-    }
-  } else {
-    logger->info("CUID#%d - no peer list received.", cuid);
-  }
-  while(e->torrentMan->isPeerAvailable() &&
-	e->torrentMan->connections < MAX_PEER_UPDATE) {
-    Peer* peer = e->torrentMan->getPeer();
-    int newCuid =  e->torrentMan->getNewCuid();
-    peer->cuid = newCuid;
-    PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(newCuid, peer, e);
-    e->commands.push(command);
-    logger->debug("CUID#%d - adding new command CUID#%d", cuid, newCuid);
-  }
-  if(req->getTrackerEvent() == Request::STARTED) {
-    req->setTrackerEvent(Request::AUTO);
-  }
-  return true;
-}

+ 51 - 9
src/TrackerWatcherCommand.cc

@@ -21,7 +21,8 @@
 /* copyright --> */
 #include "TrackerWatcherCommand.h"
 #include "SleepCommand.h"
-#include "TrackerInitCommand.h"
+#include "InitiateConnectionCommandFactory.h"
+#include "Util.h"
 
 TrackerWatcherCommand::TrackerWatcherCommand(int cuid, Request* req,
 					     TorrentDownloadEngine* e):
@@ -31,14 +32,55 @@ TrackerWatcherCommand::TrackerWatcherCommand(int cuid, Request* req,
 TrackerWatcherCommand::~TrackerWatcherCommand() {}
 
 bool TrackerWatcherCommand::execute() {
-  req->resetTryCount();
-  Command* command = new TrackerInitCommand(e->torrentMan->getNewCuid(),
-					    req,
-					    e);
-  logger->info("CUID#%d - creating new tracker request command #%d", cuid,
-	       command->getCuid());
-  e->commands.push(command);
-
+  if(e->torrentMan->trackers == 0) {
+    req->resetTryCount();
+    
+    if(e->torrentMan->downloadComplete()) {
+      if(req->getTrackerEvent() == Request::COMPLETED) {
+	req->setTrackerEvent(Request::AFTER_COMPLETED);
+      } else {
+	if(req->getTrackerEvent() == Request::STARTED) {
+	  req->setTrackerEvent(Request::AFTER_COMPLETED);
+	} else if(req->getTrackerEvent() != Request::AFTER_COMPLETED) {
+	  req->setTrackerEvent(Request::COMPLETED);
+	}
+      }
+    }
+    string event;
+    switch(req->getTrackerEvent()) {
+    case Request::STARTED:
+      event = "started";
+      break;
+    case Request::STOPPED:
+      event = "stopped";
+      break;
+    case Request::COMPLETED:
+      event = "completed";
+      break;
+    }
+    string url = e->torrentMan->announce+"?"+
+      "info_hash="+Util::urlencode(e->torrentMan->getInfoHash(), 20)+"&"+
+      "peer_id="+e->torrentMan->peerId+"&"+
+      "port="+Util::itos(e->torrentMan->getPort())+"&"+
+      "uploaded="+Util::llitos(e->torrentMan->getSessionUploadLength())+"&"+
+      "downloaded="+Util::llitos(e->torrentMan->getSessionDownloadLength())+"&"+
+      "left="+(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength() <= 0
+	       ? "0" : Util::llitos(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength()))+"&"+
+      "compact=1"+"&"+
+      "key="+e->torrentMan->peerId;
+    if(!event.empty()) {
+      url += string("&")+"event="+event;
+    }
+    if(!e->torrentMan->trackerId.empty()) {
+      url += string("&")+"trackerid="+e->torrentMan->trackerId;
+    }
+    req->setUrl(url);
+    Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(e->torrentMan->getNewCuid(), req, e);
+    e->commands.push(command);
+    e->torrentMan->trackers++;
+    logger->info("CUID#%d - creating new tracker request command #%d", cuid,
+		 command->getCuid());
+  }
   SleepCommand* slpCommand = new SleepCommand(cuid, e, this,
 					      e->torrentMan->minInterval);
   e->commands.push(slpCommand);

+ 53 - 18
src/main.cc

@@ -31,10 +31,11 @@
 #include "Util.h"
 #include "InitiateConnectionCommandFactory.h"
 #include "prefs.h"
-#include "TrackerInitCommand.h"
 #include "PeerListenCommand.h"
 #include "TorrentAutoSaveCommand.h"
 #include "TrackerWatcherCommand.h"
+#include "CompactTrackerResponseProcessor.h"
+#include "ByteArrayDiskWriter.h"
 #include <deque>
 #include <algorithm>
 #include <time.h>
@@ -93,7 +94,7 @@ void handler(int signal) {
   if(e->diskWriter != NULL) {
     e->diskWriter->closeFile();
   }
-  printf("done\n");
+  printf(_("done\n"));
   exit(0);
 }
 
@@ -110,7 +111,7 @@ void torrentHandler(int signal) {
   } else {
     te->torrentMan->save();
   }
-  printf("done\n");
+  printf(_("done\n"));
   exit(0);
 }
 
@@ -152,6 +153,8 @@ void showVersion() {
 
 void showUsage() {
   printf(_("Usage: %s [options] URL ...\n"), PACKAGE_NAME);
+  printf(_("       %s [options] -T TORRENT_FILE FILE ...\n"), PACKAGE_NAME);
+
   cout << endl;
   cout << _("Options:") << endl;
   cout << _(" -d, --dir=DIR                The directory to store downloaded file.") << endl;
@@ -199,11 +202,16 @@ void showUsage() {
 	    "                              'tunnel'.\n"
 	    "                              Default: tunnel") << endl;
 #ifdef ENABLE_BITTORRENT
-  cout << _(" --torrent-file=TORRENT_FILE  The file path to .torrent file.") << endl;
+  cout << _(" -T, --torrent-file=TORRENT_FILE  The file path to .torrent file.") << endl;
   cout << _(" --follow-torrent=true|false  Setting this option to false prevents aria2 to\n"
 	    "                              enter BitTorrent mode even if the filename of\n"
 	    "                              downloaded file ends with .torrent.\n"
 	    "                              Default: true") << endl;
+  cout << _(" -S, --show-files             Print the file listing in .torrent file and exit.") << endl;
+  cout << _(" --direct-file-mapping=true|false Directly read from and write to each file\n"
+	    "                              mentioned in .torrent file.\n"
+	    "                              Default: true") << endl;
+  cout << _(" --listen-port                Set port number to listen to for peer connection.") << endl;
 #endif // ENABLE_BITTORRENT
   cout << _(" -v, --version                Print the version number and exit.") << endl;
   cout << _(" -h, --help                   Print this message and exit.") << endl;
@@ -212,6 +220,10 @@ void showUsage() {
   cout << _(" You can specify multiple URLs. All URLs must point to the same file\n"
 	    " or downloading fails.") << endl;
   cout << endl;
+  cout << "FILE:" << endl;
+  cout << _(" Specify files in multi-file torrent to download. Use conjunction with\n"
+	    " -T option.") << endl;
+  cout << endl;
   cout << _("Examples:") << endl;
   cout << _(" Download a file by 1 connection:") << endl;
   cout << "  aria2c http://AAA.BBB.CCC/file.zip" << endl;
@@ -226,9 +238,11 @@ void showUsage() {
   cout << "  aria2c -o test.torrent http://AAA.BBB.CCC/file.torrent" << endl;
   cout << _(" Download a torrent using local .torrent file:") << endl;
   cout << "  aria2c --torrent-file test.torrent" << endl;
+  cout << _(" Download only selected files:") << endl;
+  cout << "  aria2c --torrent-file test.torrent dir/file1.zip dir/file2.zip" << endl;
   cout << endl;
 #endif // ENABLE_BITTORRENT
-  printf(_("Reports bugs to %s"), "<tujikawa at users dot sourceforge dot net>");
+  printf(_("Report bugs to %s"), "<tujikawa at users dot sourceforge dot net>");
   cout << endl;
 }
 
@@ -247,6 +261,7 @@ int main(int argc, char* argv[]) {
   bool daemonMode = false;
   string referer;
   string torrentFile;
+  int listenPort = -1;
   Strings args;
 #ifdef ENABLE_BITTORRENT
   bool followTorrent = true;
@@ -296,9 +311,10 @@ int main(int argc, char* argv[]) {
       { "min-segment-size", required_argument, &lopt, 13 },
       { "http-proxy-method", required_argument, &lopt, 14 },
 #ifdef ENABLE_BITTORRENT
-      { "torrent-file", required_argument, &lopt, 15 },
+      { "torrent-file", required_argument, NULL, 'T' },
+      { "listen-port", required_argument, &lopt, 15 },
       { "follow-torrent", required_argument, &lopt, 16 },
-      { "show-files", no_argument, &lopt, 17 },
+      { "show-files", no_argument, NULL, 'S' },
       { "no-preallocation", no_argument, &lopt, 18 },
       { "direct-file-mapping", required_argument, &lopt, 19 },
 #endif // ENABLE_BITTORRENT
@@ -306,7 +322,7 @@ int main(int argc, char* argv[]) {
       { "help", no_argument, NULL, 'h' },
       { 0, 0, 0, 0 }
     };
-    c = getopt_long(argc, argv, "Dd:o:l:s:pt:m:vh", longOpts, &optIndex);
+    c = getopt_long(argc, argv, "Dd:o:l:s:pt:m:vhST:", longOpts, &optIndex);
     if(c == -1) {
       break;
     }
@@ -415,7 +431,12 @@ int main(int argc, char* argv[]) {
 	}
 	break;
       case 15:
-	torrentFile = string(optarg);
+	listenPort = (int)strtol(optarg, NULL, 10);
+	if(!(1024 <= listenPort && listenPort <= 65535)) {
+	  cerr << _("listen-port must be between 1024 and 65535.") << endl;
+	  showUsage();
+	  exit(1);
+	}
 	break;
       case 16:
 	if(string(optarg) == "true") {
@@ -428,9 +449,6 @@ int main(int argc, char* argv[]) {
 	  exit(1);
 	}
 	break;
-      case 17:
-	op->put(PREF_SHOW_FILES, V_TRUE);
-	break;
       case 18:
 	op->put(PREF_NO_PREALLOCATION, V_TRUE);
 	break;
@@ -495,6 +513,12 @@ int main(int argc, char* argv[]) {
     case 'p':
       op->put(PREF_FTP_PASV_ENABLED, V_TRUE);
       break;
+    case 'S':
+      op->put(PREF_SHOW_FILES, V_TRUE);
+      break;
+    case 'T':
+      torrentFile = string(optarg);
+      break;
     case 'v':
       showVersion();
       exit(0);
@@ -515,7 +539,7 @@ int main(int argc, char* argv[]) {
   }
   if(daemonMode) {
     if(daemon(1, 1) < 0) {
-      perror("daemon failed");
+      perror(_("daemon failed"));
       exit(1);
     }
   }
@@ -597,18 +621,23 @@ int main(int argc, char* argv[]) {
       req->setTrackerEvent(Request::STARTED);
       te = new TorrentConsoleDownloadEngine();
       te->option = op;
-      te->diskWriter = new DefaultDiskWriter();
+      ByteArrayDiskWriter* byteArrayDiskWriter = new ByteArrayDiskWriter();
+      te->diskWriter = byteArrayDiskWriter;
       te->segmentMan = new SegmentMan();
       te->segmentMan->option = op;
       te->segmentMan->splitter = splitter;
       te->torrentMan = new TorrentMan();
       te->torrentMan->setStoreDir(dir);
       te->torrentMan->option = op;
+      CompactTrackerResponseProcessor* responseProcessor =
+	new CompactTrackerResponseProcessor(byteArrayDiskWriter, te, req);
+      te->torrentMan->setTrackerResponseProcessor(responseProcessor);
       string targetTorrentFile = torrentFile.empty() ?
 	downloadedTorrentFile : torrentFile;
       if(op->get(PREF_SHOW_FILES) == V_TRUE) {
-	FileEntries fileEntries = te->torrentMan->readFileEntryFromMetaInfoFile(targetTorrentFile);
-	cout << "Files:" << endl;
+	FileEntries fileEntries =
+	  te->torrentMan->readFileEntryFromMetaInfoFile(targetTorrentFile);
+	cout << _("Files:") << endl;
 	for(FileEntries::const_iterator itr = fileEntries.begin();
 	    itr != fileEntries.end(); itr++) {
 	  printf("%s %s Bytes\n", itr->path.c_str(),
@@ -624,9 +653,14 @@ int main(int argc, char* argv[]) {
       }
       PeerListenCommand* listenCommand =
 	new PeerListenCommand(te->torrentMan->getNewCuid(), te);
-      int port = listenCommand->bindPort(6881, 6999);
+      int port;
+      if(listenPort == -1) {
+	port = listenCommand->bindPort(6881, 6999);
+      } else {
+	port = listenCommand->bindPort(listenPort, listenPort);
+      }
       if(port == -1) {
-	printf("Errors occurred while binding port.\n");
+	printf(_("Errors occurred while binding port.\n"));
 	exit(1);
       }
       te->torrentMan->setPort(port);
@@ -644,6 +678,7 @@ int main(int argc, char* argv[]) {
 	printDownloadAbortMessage();
       }
       delete(req);
+      delete(responseProcessor);
       delete(te->segmentMan);
       delete(te->torrentMan);
       delete(te->diskWriter);

+ 1 - 1
src/message.h

@@ -43,7 +43,7 @@
 #define MSG_GOT_NEW_PIECE "CUID#%d - we got new piece. index=%d"
 #define MSG_GOT_WRONG_PIECE "CUID#%d - we got wrong piece. index=%d"
 
-#define MSG_TRACKER_WARNING_MESSAGE "CUID#%d - Tracker returned warning message: %s"
+#define MSG_TRACKER_WARNING_MESSAGE "Tracker returned warning message: %s"
 
 #define MSG_SEGMENT_FILE_EXISTS _("The segment file %s exists.")
 #define MSG_SEGMENT_FILE_DOES_NOT_EXIST _("The segment file %s does not exist.")