Преглед изворни кода

2007-03-26 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	To the ability to read options from a config file:
	* src/main.cc: Command-line parameter validation is delegated to
	OptionHandler class.
	* src/OptionHandlerFactory.h, src/OptionHandlerFactory.cc: New 
class.
	* src/Option.h, src/Option.cc (clear): New function.
	* src/OptionParser.h, src/OptionParser.cc: New class.
	* src/OptionHandler.h: New class.
	* src/NameMatchOptionHandler.h: New class.
	* src/OptionHandlerImpl.h: New classes.
	* src/prefs.h: '_' -> '-'
	(FTP_PASV_ENABLED): Renamed to FTP_PASV.
	(FTP_PASV): New definition.
	* src/Util.h, src/Util.cc (getRealSize): New function.
	
	To disable netrc support if .netrc file does not have correct
	permissions:
	* src/File.h, src/File.cc (mode): New function.

	To prevent confidential information to be logged:
	* src/HttpConnection.h, src/HttpConnection.cc
	(eraseConfidentialInfo): New function.
	(sendRequest): Call eraseConfidentialInfo().
	(sendProxyRequest): Call eraseConfidentialInfo().
	* src/main.cc: Validate permissions of .netrc file.
	
	To add --user-agent command-line option:
	* src/main.cc: Added new command line option: --user-agent
	* src/prefs.h (PREF_USER_AGENT): New definition.
	* src/HttpRequestCommand.cc (executeInternal): Set user-agent 
option
	parameter to HttpRequest object.
	
	Marged the patches from Dan Fandrich.
Tatsuhiro Tsujikawa пре 18 година
родитељ
комит
9b73454b07

+ 35 - 0
ChangeLog

@@ -1,3 +1,38 @@
+2007-03-26  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	To the ability to read options from a config file:
+	* src/main.cc: Command-line parameter validation is delegated to
+	OptionHandler class.
+	* src/OptionHandlerFactory.h, src/OptionHandlerFactory.cc: New class.
+	* src/Option.h, src/Option.cc (clear): New function.
+	* src/OptionParser.h, src/OptionParser.cc: New class.
+	* src/OptionHandler.h: New class.
+	* src/NameMatchOptionHandler.h: New class.
+	* src/OptionHandlerImpl.h: New classes.
+	* src/prefs.h: '_' -> '-'
+	(FTP_PASV_ENABLED): Renamed to FTP_PASV.
+	(FTP_PASV): New definition.
+	* src/Util.h, src/Util.cc (getRealSize): New function.
+	
+	To disable netrc support if .netrc file does not have correct
+	permissions:
+	* src/File.h, src/File.cc (mode): New function.
+
+	To prevent confidential information to be logged:
+	* src/HttpConnection.h, src/HttpConnection.cc
+	(eraseConfidentialInfo): New function.
+	(sendRequest): Call eraseConfidentialInfo().
+	(sendProxyRequest): Call eraseConfidentialInfo().
+	* src/main.cc: Validate permissions of .netrc file.
+	
+	To add --user-agent command-line option:
+	* src/main.cc: Added new command line option: --user-agent
+	* src/prefs.h (PREF_USER_AGENT): New definition.
+	* src/HttpRequestCommand.cc (executeInternal): Set user-agent option
+	parameter to HttpRequest object.
+	
+	Marged the patches from Dan Fandrich.
+	
 2007-03-25  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	Use filename and size from Metalink file instead of sending HEAD

+ 1 - 6
TODO

@@ -22,9 +22,4 @@
 * Add --bt-timeout command line option.
 * Fix DefaultBtProgressInfoFile.cc: save(), load()
 * remove blockIndex
-* Add an ability of seeding
-* Rewrite HttpConnection::receiveResponse() using {i,o}stringstream
-
-* Add usage message for -c command line option
-* Netrc, mode 600, enabled in ftp, http, all
-* preallocate file in MultiDiskAdaptor
+* Add seed mode.

+ 2 - 2
src/ChunkChecksumValidator.cc

@@ -106,7 +106,7 @@ void ChunkChecksumValidator::validate(BitfieldMan* bitfieldMan,
   fileAllocationMonitor->showProgress();
   Time cp;
   for(int32_t i = 0; i < x; ++i) {
-    (this->*f)(bitfieldMan, i, checksums.at(i), checksumLength, checksumLength);
+    (this->*f)(bitfieldMan, i, checksums[i], checksumLength, checksumLength);
     if(cp.elapsedInMillis(500)) {
       fileAllocationMonitor->setCurrentValue(i*checksumLength);
       fileAllocationMonitor->showProgress();
@@ -114,7 +114,7 @@ void ChunkChecksumValidator::validate(BitfieldMan* bitfieldMan,
     }
   }
   if(r) {
-    (this->*f)(bitfieldMan, x, checksums.at(x), r, checksumLength);
+    (this->*f)(bitfieldMan, x, checksums[x], r, checksumLength);
   }
   fileAllocationMonitor->setCurrentValue(bitfieldMan->getTotalLength());
   fileAllocationMonitor->showProgress();

+ 2 - 2
src/DefaultBtContext.cc

@@ -121,7 +121,7 @@ void DefaultBtContext::extractFileEntries(Dictionary* infoDic,
       const MetaList& paths = pathList->getList();
       string path;
       for(int32_t i = 0; i < (int32_t)paths.size()-1; i++) {
-	Data* subpath = (Data*)paths.at(i);
+	Data* subpath = (Data*)paths[i];
 	path += subpath->toString()+"/";
       }
       // TODO use dynamic_cast
@@ -212,7 +212,7 @@ string DefaultBtContext::getPieceHash(int32_t index) const {
   if(index < 0 || numPieces <= index) {
     return "";
   }
-  return pieceHashes.at(index);
+  return pieceHashes[index];
 }
 
 int64_t DefaultBtContext::getTotalLength() const {

+ 2 - 2
src/DefaultPieceStorage.cc

@@ -313,8 +313,8 @@ void DefaultPieceStorage::setFileFilter(const Integers& fileIndexes) {
   const FileEntries& entries = diskAdaptor->getFileEntries();
   for(int i = 0; i < (int)entries.size(); i++) {
     if(find(fileIndexes.begin(), fileIndexes.end(), i+1) != fileIndexes.end()) {
-      logger->debug("index=%d is %s", i+1, entries.at(i)->getPath().c_str());
-      filePaths.push_back(entries.at(i)->getPath());
+      logger->debug("index=%d is %s", i+1, entries[i]->getPath().c_str());
+      filePaths.push_back(entries[i]->getPath());
     }
   }
   setFileFilter(filePaths);

+ 1 - 1
src/DiskAdaptor.cc

@@ -65,7 +65,7 @@ bool DiskAdaptor::addDownloadEntry(int index) {
   if(fileEntries.size() <= (unsigned int)index) {
     return false;
   }
-  fileEntries.at(index)->setRequested(true);
+  fileEntries[index]->setRequested(true);
   return true;
 }
 

+ 10 - 1
src/File.cc

@@ -77,7 +77,7 @@ bool File::remove() {
   }
 }
 
-long long int File::size() {
+int64_t File::size() {
   struct stat fstat;
   if(fillStat(fstat) < 0) {
     return 0;
@@ -111,3 +111,12 @@ bool File::mkdirs() {
   }
   return true;
 }
+
+mode_t File::mode()
+{
+  struct stat fstat;
+  if(fillStat(fstat) < 0) {
+    return 0;
+  }
+  return fstat.st_mode;
+}

+ 6 - 2
src/File.h

@@ -36,7 +36,9 @@
 #define _D_FILE_H_
 
 #include "common.h"
-#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 using namespace std;
 
@@ -81,7 +83,9 @@ public:
    */
   bool mkdirs();
 
-  long long int size();
+  int64_t size();
+
+  mode_t mode();
 };
 
 #endif // _D_FILE_H_

+ 2 - 2
src/FtpNegotiationCommand.cc

@@ -209,7 +209,7 @@ bool FtpNegotiationCommand::recvSize() {
   } else if(e->segmentMan->totalSize != size) {
     throw new DlAbortEx(EX_SIZE_MISMATCH, e->segmentMan->totalSize, size);
   }
-  if(e->option->get(PREF_FTP_PASV_ENABLED) == V_TRUE) {
+  if(e->option->get(PREF_FTP_PASV) == V_TRUE) {
     sequence = SEQ_SEND_PASV;
   } else {
     sequence = SEQ_SEND_PORT;
@@ -303,7 +303,7 @@ bool FtpNegotiationCommand::recvRetr() {
   if(status != 150 && status != 125) {
     throw new DlRetryEx(EX_BAD_STATUS, status);
   }
-  if(e->option->get(PREF_FTP_PASV_ENABLED) != V_TRUE) {
+  if(e->option->get(PREF_FTP_PASV) != V_TRUE) {
     assert(serverSocket->getSockfd() != -1);
     dataSocket = serverSocket->acceptConnection();
   }

+ 20 - 2
src/HttpConnection.cc

@@ -39,6 +39,7 @@
 #include "message.h"
 #include "prefs.h"
 #include "LogFactory.h"
+#include <sstream>
 
 HttpConnection::HttpConnection(int cuid,
 			       const SocketHandle& socket,
@@ -47,10 +48,27 @@ HttpConnection::HttpConnection(int cuid,
   logger = LogFactory::getInstance();
 }
 
+string HttpConnection::eraseConfidentialInfo(const string& request)
+{
+  istringstream istr(request);
+  ostringstream ostr;
+  string line;
+  while(getline(istr, line)) {
+    if(Util::startsWith(line, "Authorization: Basic")) {
+      ostr << "Authorization: Basic ********\n";
+    } else if(Util::startsWith(line, "Proxy-Authorization: Basic")) {
+      ostr << "Proxy-Authorization: Basic ********\n";
+    } else {
+      ostr << line << "\n";
+    }
+  }
+  return ostr.str();
+}
+
 void HttpConnection::sendRequest(const HttpRequestHandle& httpRequest)
 {
   string request = httpRequest->createRequest();
-  logger->info(MSG_SENDING_REQUEST, cuid, request.c_str());
+  logger->info(MSG_SENDING_REQUEST, cuid, eraseConfidentialInfo(request).c_str());
   socket->writeData(request.c_str(), request.size());
   outstandingHttpRequests.push_back(httpRequest);
 }
@@ -58,7 +76,7 @@ void HttpConnection::sendRequest(const HttpRequestHandle& httpRequest)
 void HttpConnection::sendProxyRequest(const HttpRequestHandle& httpRequest)
 {
   string request = httpRequest->createProxyRequest();
-  logger->info(MSG_SENDING_REQUEST, cuid, request.c_str());
+  logger->info(MSG_SENDING_REQUEST, cuid, eraseConfidentialInfo(request).c_str());
   socket->writeData(request.c_str(), request.size());
   outstandingHttpRequests.push_back(httpRequest);
 }

+ 1 - 0
src/HttpConnection.h

@@ -60,6 +60,7 @@ private:
   HttpRequests outstandingHttpRequests;
 
   int findEndOfHeader(const char* buf, const char* substr, int bufLength) const;
+  string eraseConfidentialInfo(const string& request);
 public:
   HttpConnection(int cuid,
 		 const SocketHandle& socket,

+ 1 - 0
src/HttpRequestCommand.cc

@@ -57,6 +57,7 @@ bool HttpRequestCommand::executeInternal() {
     req->setKeepAlive(false);
   }
   HttpRequestHandle httpRequest = new HttpRequest();
+  httpRequest->setUserAgent(e->option->get(PREF_USER_AGENT));
   httpRequest->setRequest(req);
   httpRequest->setSegment(segment);
   httpRequest->setEntityLength(e->segmentMan->totalSize);

+ 3 - 1
src/Makefile.am

@@ -78,7 +78,9 @@ SRCS =  Socket.h\
 	NetrcAuthResolver.cc NetrcAuthResolver.h\
 	RequestFactory.cc RequestFactory.h\
 	DefaultFileAllocator.cc DefaultFileAllocator.h\
-	GlowFileAllocator.cc GlowFileAllocator.h
+	GlowFileAllocator.cc GlowFileAllocator.h\
+	OptionParser.cc OptionParser.h\
+	OptionHandlerFactory.cc OptionHandlerFactory.h
 #	debug_new.cpp
 
 if ENABLE_ASYNC_DNS

+ 14 - 8
src/Makefile.in

@@ -222,12 +222,14 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	DefaultAuthResolver.h NetrcAuthResolver.cc NetrcAuthResolver.h \
 	RequestFactory.cc RequestFactory.h DefaultFileAllocator.cc \
 	DefaultFileAllocator.h GlowFileAllocator.cc \
-	GlowFileAllocator.h NameResolver.cc NameResolver.h MetaEntry.h \
-	Data.cc Data.h Dictionary.cc Dictionary.h List.cc List.h \
-	MetaFileUtil.cc MetaFileUtil.h MetaEntryVisitor.h \
-	ShaVisitor.cc ShaVisitor.h PeerConnection.cc PeerConnection.h \
-	PeerMessageUtil.cc PeerMessageUtil.h PeerAbstractCommand.cc \
-	PeerAbstractCommand.h PeerInitiateConnectionCommand.cc \
+	GlowFileAllocator.h OptionParser.cc OptionParser.h \
+	OptionHandlerFactory.cc OptionHandlerFactory.h NameResolver.cc \
+	NameResolver.h MetaEntry.h Data.cc Data.h Dictionary.cc \
+	Dictionary.h List.cc List.h MetaFileUtil.cc MetaFileUtil.h \
+	MetaEntryVisitor.h ShaVisitor.cc ShaVisitor.h \
+	PeerConnection.cc PeerConnection.h PeerMessageUtil.cc \
+	PeerMessageUtil.h PeerAbstractCommand.cc PeerAbstractCommand.h \
+	PeerInitiateConnectionCommand.cc \
 	PeerInitiateConnectionCommand.h PeerInteractionCommand.cc \
 	PeerInteractionCommand.h Peer.cc Peer.h \
 	TorrentDownloadEngine.cc TorrentDownloadEngine.h \
@@ -393,6 +395,7 @@ am__objects_4 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
 	AuthConfig.$(OBJEXT) DefaultAuthResolver.$(OBJEXT) \
 	NetrcAuthResolver.$(OBJEXT) RequestFactory.$(OBJEXT) \
 	DefaultFileAllocator.$(OBJEXT) GlowFileAllocator.$(OBJEXT) \
+	OptionParser.$(OBJEXT) OptionHandlerFactory.$(OBJEXT) \
 	$(am__objects_1) $(am__objects_2) $(am__objects_3)
 am_libaria2c_a_OBJECTS = $(am__objects_4)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
@@ -608,8 +611,9 @@ SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \
 	DefaultAuthResolver.h NetrcAuthResolver.cc NetrcAuthResolver.h \
 	RequestFactory.cc RequestFactory.h DefaultFileAllocator.cc \
 	DefaultFileAllocator.h GlowFileAllocator.cc \
-	GlowFileAllocator.h $(am__append_1) $(am__append_2) \
-	$(am__append_3)
+	GlowFileAllocator.h OptionParser.cc OptionParser.h \
+	OptionHandlerFactory.cc OptionHandlerFactory.h $(am__append_1) \
+	$(am__append_2) $(am__append_3)
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
 aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
@@ -793,6 +797,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Netrc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetrcAuthResolver.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Option.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OptionHandlerFactory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OptionParser.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Peer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerAbstractCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerChokeCommand.Po@am__quote@

+ 56 - 0
src/NameMatchOptionHandler.h

@@ -0,0 +1,56 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_NAME_MATCH_OPTION_HANDLER_H_
+#define _D_NAME_MATCH_OPTION_HANDLER_H_
+
+#include "OptionHandler.h"
+
+class NameMatchOptionHandler : public OptionHandler {
+protected:
+  string _optName;
+public:
+  NameMatchOptionHandler(const string& optName):_optName(optName) {}
+
+  virtual ~NameMatchOptionHandler() {}
+  
+  virtual bool canHandle(const string& optName)
+  {
+    return strcasecmp(_optName.c_str(), optName.c_str()) == 0;
+  }
+};
+
+typedef SharedHandle<NameMatchOptionHandler> NameMatchOptionHandlerHandle;
+
+#endif // _D_NAME_MATCH_OPTION_HANDLER_H_

+ 5 - 0
src/Option.cc

@@ -91,3 +91,8 @@ double Option::getAsDouble(const string& name) const {
     return strtod(value.c_str(), 0);
   }
 }
+
+void Option::clear()
+{
+  table.clear();
+}

+ 2 - 0
src/Option.h

@@ -55,6 +55,8 @@ public:
   long long int getAsLLInt(const string& name) const;
   bool getAsBool(const string& name) const;
   double getAsDouble(const string& name) const;
+  
+  void clear();
 };
 
 #endif // _D_OPTION_H_

+ 51 - 0
src/OptionHandler.h

@@ -0,0 +1,51 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_OPTION_HANDLER_H_
+#define _D_OPTION_HANDLER_H_
+
+#include "common.h"
+#include "Option.h"
+
+class OptionHandler {
+public:
+  virtual ~OptionHandler() {}
+  
+  virtual bool canHandle(const string& optName) = 0;
+  virtual void parseArg(Option* option, const string& arg) = 0;
+};
+
+typedef SharedHandle<OptionHandler> OptionHandlerHandle;
+typedef deque<OptionHandlerHandle> OptionHandlers;
+#endif // _D_OPTION_HANDLER_H_

+ 94 - 0
src/OptionHandlerFactory.cc

@@ -0,0 +1,94 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "OptionHandlerFactory.h"
+#include "prefs.h"
+#include "OptionHandlerImpl.h"
+
+OptionHandlers OptionHandlerFactory::createOptionHandlers()
+{
+  OptionHandlers handlers;
+  handlers.push_back(new HttpProxyOptionHandler(PREF_HTTP_PROXY));
+  handlers.push_back(new DefaultOptionHandler(PREF_HTTP_USER));
+  handlers.push_back(new DefaultOptionHandler(PREF_HTTP_PASSWD));
+  handlers.push_back(new DefaultOptionHandler(PREF_HTTP_PROXY_USER));
+  handlers.push_back(new DefaultOptionHandler(PREF_HTTP_PROXY_PASSWD));
+  handlers.push_back(new ParameterOptionHandler(PREF_HTTP_AUTH_SCHEME, V_BASIC));
+  handlers.push_back(new DefaultOptionHandler(PREF_REFERER));
+  handlers.push_back(new NumberOptionHandler(PREF_RETRY_WAIT, 0, 60));
+  handlers.push_back(new DefaultOptionHandler(PREF_FTP_USER));
+  handlers.push_back(new DefaultOptionHandler(PREF_FTP_PASSWD));
+  handlers.push_back(new ParameterOptionHandler(PREF_FTP_TYPE, V_BINARY, V_ASCII));
+  handlers.push_back(new ParameterOptionHandler(PREF_FTP_VIA_HTTP_PROXY,
+						V_GET, V_TUNNEL));
+  handlers.push_back(new UnitNumberOptionHandler(PREF_MIN_SEGMENT_SIZE, 1024));
+  handlers.push_back(new ParameterOptionHandler(PREF_HTTP_PROXY_METHOD,
+						V_GET, V_TUNNEL));
+  handlers.push_back(new NumberOptionHandler(PREF_LISTEN_PORT, 1024, UINT16_MAX));
+  handlers.push_back(new BooleanOptionHandler(PREF_FOLLOW_TORRENT));
+  handlers.push_back(new BooleanOptionHandler(PREF_NO_PREALLOCATION));
+  handlers.push_back(new BooleanOptionHandler(PREF_DIRECT_FILE_MAPPING));
+  handlers.push_back(new DefaultOptionHandler(PREF_SELECT_FILE));
+  handlers.push_back(new NumberOptionHandler(PREF_SEED_TIME, 0));
+  handlers.push_back(new FloatNumberOptionHandler(PREF_SEED_RATIO, 0.0));
+  handlers.push_back(new UnitNumberOptionHandler(PREF_MAX_UPLOAD_LIMIT, 0));
+  handlers.push_back(new DefaultOptionHandler(PREF_METALINK_VERSION));
+  handlers.push_back(new DefaultOptionHandler(PREF_METALINK_LANGUAGE));
+  handlers.push_back(new DefaultOptionHandler(PREF_METALINK_OS));
+  handlers.push_back(new BooleanOptionHandler(PREF_FOLLOW_METALINK));
+  handlers.push_back(new DefaultOptionHandler(PREF_METALINK_LOCATION));
+  handlers.push_back(new UnitNumberOptionHandler(PREF_LOWEST_SPEED_LIMIT, 0));
+  handlers.push_back(new UnitNumberOptionHandler(PREF_MAX_DOWNLOAD_LIMIT, 0));
+  handlers.push_back(new BooleanOptionHandler(PREF_ALLOW_OVERWRITE));
+  handlers.push_back(new BooleanOptionHandler(PREF_CHECK_INTEGRITY));
+  handlers.push_back(new BooleanOptionHandler(PREF_REALTIME_CHUNK_CHECKSUM));
+  handlers.push_back(new BooleanOptionHandler(PREF_DAEMON));
+  handlers.push_back(new DefaultOptionHandler(PREF_DIR));
+  handlers.push_back(new DefaultOptionHandler(PREF_OUT));
+  handlers.push_back(new LogOptionHandler(PREF_LOG));
+  handlers.push_back(new NumberOptionHandler(PREF_SPLIT, 1, 5));
+  handlers.push_back(new NumberOptionHandler(PREF_TIMEOUT, 1, 600));
+  handlers.push_back(new NumberOptionHandler(PREF_MAX_TRIES, 0));
+  handlers.push_back(new BooleanOptionHandler(PREF_FTP_PASV));
+  handlers.push_back(new BooleanOptionHandler(PREF_SHOW_FILES));
+  handlers.push_back(new DefaultOptionHandler(PREF_TORRENT_FILE));
+  handlers.push_back(new DefaultOptionHandler(PREF_METALINK_FILE));
+  handlers.push_back(new NumberOptionHandler(PREF_METALINK_SERVERS, 1));
+  handlers.push_back(new ParameterOptionHandler(PREF_FILE_ALLOCATION,
+						V_NONE, V_PREALLOC));
+  handlers.push_back(new BooleanOptionHandler(PREF_CONTINUE));
+  handlers.push_back(new DefaultOptionHandler(PREF_USER_AGENT));
+
+  return handlers;
+}

+ 46 - 0
src/OptionHandlerFactory.h

@@ -0,0 +1,46 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_OPTION_HANDLER_FACTORY_H_
+#define _D_OPTION_HANDLER_FACTORY_H_
+
+#include "common.h"
+#include "OptionHandler.h"
+
+class OptionHandlerFactory {
+public:
+  static OptionHandlers createOptionHandlers();
+};
+
+#endif // _D_OPTION_HANDLER_FACTORY_H_

+ 249 - 0
src/OptionHandlerImpl.h

@@ -0,0 +1,249 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_OPTION_HANDLER_IMPL_H_
+#define _D_OPTION_HANDLER_IMPL_H_
+
+#include "OptionHandler.h"
+#include "NameMatchOptionHandler.h"
+#include "Util.h"
+#include "FatalException.h"
+#include "prefs.h"
+#include <netinet/in.h>
+
+class NullOptionHandler : public OptionHandler {
+public:
+  virtual ~NullOptionHandler() {}
+
+  virtual bool canHandle(const string& optName) { return true; }
+
+  virtual void parseArg(Option* option, const string& arg) {}
+};
+
+class BooleanOptionHandler : public NameMatchOptionHandler {
+public:
+  BooleanOptionHandler(const string& optName):NameMatchOptionHandler(optName) {}
+  virtual ~BooleanOptionHandler() {}
+
+  virtual void parseArg(Option* option, const string& optarg)
+  {
+    if(optarg == "true") {
+      option->put(_optName, V_TRUE);
+    } else if(optarg == "false") {
+      option->put(_optName, V_FALSE);
+    } else {
+      string msg = _optName+" "+_("must be either 'true' or 'false'.");
+      throw new FatalException(msg.c_str());
+    }
+  }
+};
+
+class NumberOptionHandler : public NameMatchOptionHandler {
+private:
+  int64_t _min;
+  int64_t _max;
+public:
+  NumberOptionHandler(const string& optName, int64_t min = -1, int64_t max = -1):NameMatchOptionHandler(optName), _min(min), _max(max) {}
+
+  virtual ~NumberOptionHandler() {}
+
+  virtual void parseArg(Option* option, const string& optarg)
+  {
+    int64_t num = strtoll(optarg.c_str(), 0, 10);
+    parseArg(option, num);
+  }
+
+  void parseArg(Option* option, int64_t number)
+  {
+    if((_min == -1 || _min <= number) && (_max ==  -1 || number <= _max)) {
+      option->put(_optName, Util::llitos(number));
+    } else {
+      string msg = _optName+" ";
+      if(_min == -1 && _max != -1) {
+	msg += _("must be smaller than or equal to %lld.");
+	throw new FatalException(msg.c_str(), _max);
+      } else if(_min != -1 && _max != -1) {
+	msg += _("must be between %lld and %lld.");
+	throw new FatalException(msg.c_str(), _min, _max);
+      } else if(_min != -1 && _max == -1) {
+	msg += _("must be greater than or equal to %lld.");
+	throw new FatalException(msg.c_str(), _min);
+      } else {
+	msg += _("must be a number.");
+	throw new FatalException(msg.c_str());
+      }
+    }
+  }
+};
+
+class UnitNumberOptionHandler : public NumberOptionHandler {
+public:
+  UnitNumberOptionHandler(const string& optName, int64_t min = -1, int64_t max = -1):NumberOptionHandler(optName, min, max) {}
+
+  virtual ~UnitNumberOptionHandler() {}
+
+  virtual void parseArg(Option* option, const string& optarg)
+  {
+    int64_t num = Util::getRealSize(optarg);
+    NumberOptionHandler::parseArg(option, num);
+  }
+};
+
+class FloatNumberOptionHandler : public NameMatchOptionHandler {
+private:
+  double _min;
+  double _max;
+public:
+  FloatNumberOptionHandler(const string& optName, double min = -1, double max = -1):NameMatchOptionHandler(optName), _min(min), _max(max) {}
+
+  virtual ~FloatNumberOptionHandler() {}
+
+  virtual void parseArg(Option* option, const string& optarg)
+  {
+    double number = strtod(optarg.c_str(), 0);
+    if((_min < 0 || _min <= number) && (_max < 0 || number <= _max)) {
+      option->put(_optName, optarg);
+    } else {
+      string msg = _optName+" ";
+      if(_min < 0 && _max >= 0) {
+	msg += _("must be smaller than or equal to %.1f.");
+	throw new FatalException(msg.c_str(), _max);
+      } else if(_min >= 0 && _max >= 0) {
+	msg += _("must be between %.1f and %.1f.");
+	throw new FatalException(msg.c_str(), _min, _max);
+      } else if(_min >= 0 && _max < 0) {
+	msg += _("must be greater than or equal to %.1f.");
+	throw new FatalException(msg.c_str(), _min);
+      } else {
+	msg += _("must be a number.");
+	throw new FatalException(msg.c_str());
+      }
+    }
+  }
+};
+
+class DefaultOptionHandler : public NameMatchOptionHandler {
+public:
+  DefaultOptionHandler(const string& optName):NameMatchOptionHandler(optName) {}
+
+  virtual ~DefaultOptionHandler() {}
+
+  virtual void parseArg(Option* option, const string& optarg)
+  {
+    option->put(_optName, optarg);
+  }
+};
+
+class ParameterOptionHandler : public NameMatchOptionHandler {
+private:
+  Strings _validParamValues;
+public:
+  ParameterOptionHandler(const string& optName, const Strings& validParamValues):
+    NameMatchOptionHandler(optName), _validParamValues(validParamValues) {}
+
+  ParameterOptionHandler(const string& optName, const string& validParamValue):
+    NameMatchOptionHandler(optName)
+  {
+    _validParamValues.push_back(validParamValue);
+  }
+
+  ParameterOptionHandler(const string& optName,
+			 const string& validParamValue1,
+			 const string& validParamValue2):
+    NameMatchOptionHandler(optName)
+  {
+    _validParamValues.push_back(validParamValue1);
+    _validParamValues.push_back(validParamValue2);
+  }
+   
+  virtual ~ParameterOptionHandler() {}
+
+  virtual void parseArg(Option* option, const string& optarg)
+  {
+    Strings::const_iterator itr = find(_validParamValues.begin(), _validParamValues.end(), optarg);
+    if(itr == _validParamValues.end()) {
+      string msg = _optName+" "+_("must be one of the following:");
+      if(_validParamValues.size() == 0) {
+	msg += "''";
+      } else {
+	for(Strings::const_iterator itr = _validParamValues.begin();
+	    itr != _validParamValues.end(); ++itr) {
+	  msg += "'"+*itr+"' ";
+	}
+      }
+      throw new FatalException(msg.c_str());
+    } else {
+      option->put(_optName, optarg);
+    }
+  }
+};
+
+class HttpProxyOptionHandler : public NameMatchOptionHandler {
+public:
+  HttpProxyOptionHandler(const string& optName):NameMatchOptionHandler(optName) {}
+
+  virtual ~HttpProxyOptionHandler() {}
+
+  virtual void parseArg(Option* option, const string& optarg)
+  {
+    pair<string, string> proxy = Util::split(optarg, ":");
+    in_port_t port = strtol(proxy.second.c_str(), 0, 10);
+    if(proxy.first.empty() || proxy.second.empty() ||
+       port <= 0) {
+      throw new FatalException(_("unrecognized proxy format"));
+    }
+    option->put(PREF_HTTP_PROXY, optarg);
+    option->put(PREF_HTTP_PROXY_HOST, proxy.first);
+    option->put(PREF_HTTP_PROXY_PORT, Util::itos(port));
+    option->put(PREF_HTTP_PROXY_ENABLED, V_TRUE);
+  }
+};
+
+class LogOptionHandler : public NameMatchOptionHandler {
+public:
+  LogOptionHandler(const string& optName):NameMatchOptionHandler(optName) {}
+
+  virtual ~LogOptionHandler() {}
+
+  virtual void parseArg(Option* option, const string& optarg)
+  {
+    if("-" == optarg) {
+      option->put(PREF_STDOUT_LOG, V_TRUE);
+    } else {
+      option->put(PREF_LOG, optarg);
+    }
+  }
+};
+
+#endif // _D_OPTION_HANDLER_IMPL_H_

+ 63 - 0
src/OptionParser.cc

@@ -0,0 +1,63 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "OptionParser.h"
+#include "Util.h"
+#include "OptionHandlerImpl.h"
+
+void OptionParser::parse(Option* option, istream& is)
+{
+  string line;
+  int32_t linenum = 0;
+  while(getline(is, line)) {
+    ++linenum;
+    if(Util::startsWith(line, "#")) {
+      continue;
+    }
+    pair<string, string> nv = Util::split(line, "=");
+    OptionHandlerHandle handler = getOptionHandlerByName(nv.first);
+    handler->parseArg(option, nv.second);
+  }
+}
+
+OptionHandlerHandle OptionParser::getOptionHandlerByName(const string& optName)
+{
+  for(OptionHandlers::iterator itr = _optionHandlers.begin();
+      itr != _optionHandlers.end(); ++itr) {
+    if((*itr)->canHandle(optName)) {
+      return *itr;
+    }
+  }
+  return new NullOptionHandler();
+}

+ 61 - 0
src/OptionParser.h

@@ -0,0 +1,61 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_OPTION_PARSER_H_
+#define _D_OPTION_PARSER_H_
+
+#include "common.h"
+#include "Option.h"
+#include "OptionHandler.h"
+#include <istream>
+
+class OptionParser {
+private:
+  OptionHandlers _optionHandlers;
+public:
+  ~OptionParser() {}
+
+  OptionHandlerHandle getOptionHandlerByName(const string& optName);
+
+  void parse(Option* option, istream& ios);
+
+  void setOptionHandlers(const OptionHandlers& optionHandlers)
+  {
+    _optionHandlers = optionHandlers;
+  }
+};
+
+typedef SharedHandle<OptionParser> OptionParserHandle;
+
+#endif // _D_OPTION_PARSER_H_

+ 1 - 1
src/SegmentMan.cc

@@ -531,7 +531,7 @@ void SegmentMan::tryChunkChecksumValidation(const SegmentHandle& segment)
       int32_t dataLength =
 	offset+chunkHashLength <= totalSize ? chunkHashLength : totalSize-offset;
       string actualChecksum = diskWriter->messageDigest(offset, dataLength, digestAlgo);
-      string expectedChecksum = pieceHashes.at(index);
+      string expectedChecksum = pieceHashes[index];
       if(expectedChecksum == actualChecksum) {
 	logger->info("Good chunk checksum.");
       } else {

+ 18 - 0
src/Util.cc

@@ -673,3 +673,21 @@ string Util::getHomeDir()
     return "";
   }
 }
+
+int64_t Util::getRealSize(const string& sizeWithUnit)
+{
+  string::size_type p = sizeWithUnit.find_first_of("KM");
+  string size;
+  int mult = 1;
+  if(p == string::npos) {
+    size = sizeWithUnit;
+  } else {
+    if(sizeWithUnit[p] == 'K') {
+      mult = 1024;
+    } else if(sizeWithUnit[p] == 'M') {
+      mult = 1024*1024;
+    }
+    size = sizeWithUnit.substr(0, p);
+  }
+  return strtoll(size.c_str(), 0, 10)*mult;
+}

+ 2 - 0
src/Util.h

@@ -146,6 +146,8 @@ public:
 			 int32_t srcLength, int32_t destLength);
 
   static string getHomeDir();
+
+  static int64_t getRealSize(const string& sizeWithUnit);
 };
 
 #endif // _D_UTIL_H_

+ 3 - 0
src/common.h

@@ -39,9 +39,12 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
+#include <stdio.h>
+#include <stdint.h>
 #include <iostream>
 #include <assert.h>
 #include <limits.h>
+#include <unistd.h>
 #include <string>
 #include <deque>
 #include <algorithm>

+ 115 - 244
src/main.cc

@@ -44,6 +44,10 @@
 #include "ConsoleFileAllocationMonitor.h"
 #include "Netrc.h"
 #include "RequestFactory.h"
+#include "OptionParser.h"
+#include "OptionHandlerFactory.h"
+#include "FatalException.h"
+#include "File.h"
 #include <deque>
 #include <algorithm>
 #include <time.h>
@@ -51,6 +55,8 @@
 #include <unistd.h>
 #include <libgen.h>
 #include <utility>
+#include <fstream>
+#include <sstream>
 extern char* optarg;
 extern int optind, opterr, optopt;
 #include <getopt.h>
@@ -195,6 +201,7 @@ void showUsage() {
 	    "                              which download files from the beginning.\n"
 	    "                              Currently this option is applicable to http(s)/\n"
 	    "                              ftp downloads.") << endl;
+  cout << _(" -U, --user-agent=USER_AGENT  Set user agent for http(s) downloads.") << endl;
 #ifdef ENABLE_BITTORRENT
   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"
@@ -286,21 +293,6 @@ void showUsage() {
   cout << endl;
 }
 
-long long int getRealSize(char* optarg) {
-  string::size_type p = string(optarg).find_first_of("KM");
-  int mult = 1;
-  if(p != string::npos) {
-    if(optarg[p] == 'K') {
-      mult = 1024;
-    } else if(optarg[p] == 'M') {
-      mult = 1024*1024;
-    }
-    optarg[p] = '\0';
-  }
-  long long int size = strtoll(optarg, NULL, 10)*mult;
-  return size;
-}
-
 int main(int argc, char* argv[]) {
 #ifdef ENABLE_NLS
   setlocale (LC_CTYPE, "");
@@ -308,7 +300,7 @@ int main(int argc, char* argv[]) {
   bindtextdomain (PACKAGE, LOCALEDIR);
   textdomain (PACKAGE);
 #endif // ENABLE_NLS
-
+  stringstream cmdstream;
   int c;
   Option* op = new Option();
   op->put(PREF_STDOUT_LOG, V_FALSE);
@@ -359,6 +351,7 @@ int main(int argc, char* argv[]) {
   op->put(PREF_CHECK_INTEGRITY, V_FALSE);
   op->put(PREF_NETRC_PATH, Util::getHomeDir()+"/.netrc");
   op->put(PREF_CONTINUE, V_FALSE);
+  op->put(PREF_USER_AGENT, "aria2");
   while(1) {
     int optIndex = 0;
     int lopt;
@@ -391,7 +384,8 @@ int main(int argc, char* argv[]) {
       { "allow-overwrite", required_argument, &lopt, 202 },
       { "check-integrity", required_argument, &lopt, 203 },
       { "realtime-chunk-checksum", required_argument, &lopt, 204 },
-      { "continue", no_argument, NULL, 'c' },
+      { "continue", no_argument, 0, 'c' },
+      { "user-agent", required_argument, 0, 'U' },
 #ifdef ENABLE_BITTORRENT
       { "torrent-file", required_argument, NULL, 'T' },
       { "listen-port", required_argument, &lopt, 15 },
@@ -426,307 +420,149 @@ int main(int argc, char* argv[]) {
     switch(c) {
     case 0:{
       switch(lopt) {
-      case 1: {
-	pair<string, string> proxy;
-	Util::split(proxy, optarg, ':');
-	int port = (int)strtol(proxy.second.c_str(), NULL, 10);
-	if(proxy.first.empty() || proxy.second.empty() ||
-	   !(0 < port && port <= 65535)) {
-	  cerr << _("unrecognized proxy format") << endl;
-	  exit(EXIT_FAILURE);
-	}
-	op->put(PREF_HTTP_PROXY_HOST, proxy.first);
-	op->put(PREF_HTTP_PROXY_PORT, Util::itos(port));
-	op->put(PREF_HTTP_PROXY_ENABLED, V_TRUE);
+      case 1:
+	cmdstream << PREF_HTTP_PROXY << "=" << optarg << "\n";
 	break;
-      }
       case 2:
-	op->put(PREF_HTTP_USER, optarg);
-	op->put(PREF_HTTP_AUTH_ENABLED, V_TRUE);
+	cmdstream << PREF_HTTP_USER << "=" << optarg << "\n";
 	break;
       case 3:
-	op->put(PREF_HTTP_PASSWD, optarg);
+	cmdstream << PREF_HTTP_PASSWD << "=" << optarg << "\n";
 	break;
       case 4:
-	op->put(PREF_HTTP_PROXY_USER, optarg);
-	op->put(PREF_HTTP_PROXY_AUTH_ENABLED, V_TRUE);
+	cmdstream << PREF_HTTP_PROXY_USER << "=" << optarg << "\n";
 	break;
       case 5: 
-	op->put(PREF_HTTP_PROXY_PASSWD, optarg);
+	cmdstream << PREF_HTTP_PROXY_PASSWD << "=" << optarg << "\n";
 	break;
       case 6:
-	if(string(V_BASIC) == optarg) {
-	  op->put(PREF_HTTP_AUTH_SCHEME, V_BASIC);
-	} else {
-	  cerr << _("Currently, supported authentication scheme is basic.") << endl;
-	}
+	cmdstream << PREF_HTTP_AUTH_SCHEME << "=" << optarg << "\n";
 	break;
       case 7:
-	op->put(PREF_REFERER, optarg);
+	cmdstream << PREF_REFERER << "=" << optarg << "\n";
 	break;
-      case 8: {
-	int wait = (int)strtol(optarg, NULL, 10);
-	if(!(0 <= wait && wait <= 60)) {
-	  cerr << _("retry-wait must be between 0 and 60.") << endl;
-	  exit(EXIT_FAILURE);
-	}
-	op->put(PREF_RETRY_WAIT, Util::itos(wait));
+      case 8:
+	cmdstream << PREF_RETRY_WAIT << "=" << optarg << "\n";
 	break;
-      }
       case 9:
-	op->put(PREF_FTP_USER, optarg);
+	cmdstream << PREF_FTP_USER << "=" << optarg << "\n";
 	break;
       case 10:
-	op->put(PREF_FTP_PASSWD, optarg);
+	cmdstream << PREF_FTP_PASSWD << "=" << optarg << "\n";
 	break;
       case 11:
-	if(string(optarg) == V_BINARY || string(optarg) == V_ASCII) {
-	  op->put(PREF_FTP_TYPE, optarg);
-	} else {
-	  cerr << _("ftp-type must be either 'binary' or 'ascii'.") << endl;
-	  exit(EXIT_FAILURE);
-	}
+	cmdstream << PREF_FTP_TYPE << "=" << optarg << "\n";
 	break;
       case 12:
-	if(string(optarg) == V_GET || string(optarg) == V_TUNNEL) {
-	  op->put(PREF_FTP_VIA_HTTP_PROXY, optarg);
-	} else {
-	  cerr << _("ftp-via-http-proxy must be either 'get' or 'tunnel'.") << endl;
-	  exit(EXIT_FAILURE);
-	}
+	cmdstream << PREF_FTP_VIA_HTTP_PROXY << "=" << optarg << "\n";
 	break;
-      case 13: {
-	long long int size = getRealSize(optarg);
-	if(size < 1024) {
-	  cerr << _("min-segment-size invalid") << endl;
-	  exit(EXIT_FAILURE);
-	}
-	op->put(PREF_MIN_SEGMENT_SIZE, Util::llitos(size));
+      case 13:
+	cmdstream << PREF_MIN_SEGMENT_SIZE << "=" << optarg << "\n";
 	break;
-      }
       case 14:
-	if(string(optarg) == V_GET || string(optarg) == V_TUNNEL) {
-	  op->put(PREF_HTTP_PROXY_METHOD, optarg);
-	} else {
-	  cerr << _("http-proxy-method must be either 'get' or 'tunnel'.") << endl;
-	  exit(EXIT_FAILURE);
-	}
+	cmdstream << PREF_HTTP_PROXY_METHOD << "=" << optarg << "\n";
 	break;
-      case 15: {
-	int listenPort = (int)strtol(optarg, NULL, 10);
-	if(!(1024 <= listenPort && listenPort <= 65535)) {
-	  cerr << _("listen-port must be between 1024 and 65535.") << endl;
-	  exit(EXIT_FAILURE);
-	}
-	op->put(PREF_LISTEN_PORT, Util::itos(listenPort));
+      case 15:
+	cmdstream << PREF_LISTEN_PORT << "=" << optarg << "\n";
 	break;
-      }
       case 16:
-	if(string(optarg) == "true") {
-	  op->put(PREF_FOLLOW_TORRENT, V_TRUE);
-	} else if(string(optarg) == "false") {
-	  op->put(PREF_FOLLOW_TORRENT, V_FALSE);
-	} else {
-	  cerr << _("follow-torrent must be either 'true' or 'false'.") << endl;
-	  exit(EXIT_FAILURE);
-	}
+	cmdstream << PREF_FOLLOW_TORRENT << "=" << optarg << "\n";
 	break;
       case 18:
-	op->put(PREF_NO_PREALLOCATION, V_TRUE);
+	cmdstream << PREF_NO_PREALLOCATION << "=" << V_TRUE << "\n";
 	break;
       case 19:
-	if(string(optarg) == "true") {
-	  op->put(PREF_DIRECT_FILE_MAPPING, V_TRUE);
-	} else if(string(optarg) == "false") {
-	  op->put(PREF_DIRECT_FILE_MAPPING, V_FALSE);
-	} else {
-	  cerr << _("direct-file-mapping must be either 'true' or 'false'.") << endl;
-	  exit(EXIT_FAILURE);
-	}
+	cmdstream << PREF_DIRECT_FILE_MAPPING << "=" << optarg << "\n";
 	break;
       case 21:
-	op->put(PREF_SELECT_FILE, optarg);
+	cmdstream << PREF_SELECT_FILE << "=" << optarg << "\n";
 	break;
-      case 22: {
-	int seedTime = (int)strtol(optarg, NULL, 10);
-	if(seedTime < 0) {
-	  cerr << _("seed-time must be greater than or equal to 0.") << endl;
-	  exit(EXIT_FAILURE);
-	}
-	op->put(PREF_SEED_TIME, Util::itos(seedTime));
+      case 22:
+	cmdstream << PREF_SEED_TIME << "=" << optarg << "\n";
 	break;
-      }
-      case 23: {
-	double ratio = (int)strtod(optarg, NULL);
-	if(ratio < 0.0) {
-	  cerr << _("seed-ratio must be greater than or equal to 0.0.") << endl;
-	  exit(EXIT_FAILURE);
-	}
-	op->put(PREF_SEED_RATIO, optarg);
+      case 23:
+	cmdstream << PREF_SEED_RATIO << "=" << optarg << "\n";
 	break;
-      }
-      case 24: {
-	int limit = getRealSize(optarg);
-	if(limit < 0) {
-	  cerr << _("max-upload-limit must be greater than or equal to 0") << endl;
-	  exit(EXIT_FAILURE);
-	}
-	op->put(PREF_MAX_UPLOAD_LIMIT, Util::itos(limit));
+      case 24:
+	cmdstream << PREF_MAX_UPLOAD_LIMIT << "=" << optarg << "\n";
 	break;
-      }
       case 100:
-	op->put(PREF_METALINK_VERSION, optarg);
+	cmdstream << PREF_METALINK_VERSION << "=" << optarg << "\n";
 	break;
       case 101:
-	op->put(PREF_METALINK_LANGUAGE, optarg);
+	cmdstream << PREF_METALINK_LANGUAGE << "=" << optarg << "\n";
 	break;
       case 102:
-	op->put(PREF_METALINK_OS, optarg);
+	cmdstream << PREF_METALINK_OS << "=" << optarg << "\n";
 	break;
       case 103:
-	if(string(optarg) == "true") {
-	  op->put(PREF_FOLLOW_METALINK, V_TRUE);
-	} else if(string(optarg) == "false") {
-	  op->put(PREF_FOLLOW_METALINK, V_FALSE);
-	} else {
-	  cerr << _("follow-metalink must be either 'true' or 'false'.") << endl;
-	  exit(EXIT_FAILURE);
-	}
+	cmdstream << PREF_FOLLOW_METALINK << "=" << optarg << "\n";
 	break;
       case 104:
-	op->put(PREF_METALINK_LOCATION, optarg);
+	cmdstream << PREF_METALINK_LOCATION << "=" << optarg << "\n";
 	break;
-      case 200: {
-	int limit = getRealSize(optarg);
-	if(limit < 0) {
-	  cerr << _("lowest-speed-limit must be greater than or equal to 0") << endl;
-	  exit(EXIT_FAILURE);
-	}
-	op->put(PREF_LOWEST_SPEED_LIMIT, Util::itos(limit));
+      case 200:
+	cmdstream << PREF_LOWEST_SPEED_LIMIT << "=" << optarg << "\n";
 	break;
-      }
-      case 201: {
-	int limit = getRealSize(optarg);
-	if(limit < 0) {
-	  cerr << _("max-download-limit must be greater than or equal to 0") << endl;
-	  exit(EXIT_FAILURE);
-	}
-	op->put(PREF_MAX_DOWNLOAD_LIMIT, Util::itos(limit));
+      case 201:
+	cmdstream << PREF_MAX_DOWNLOAD_LIMIT << "=" << optarg << "\n";
 	break;
-      }
-      case 202: {
-	if(string(optarg) == "true") {
-	  op->put(PREF_ALLOW_OVERWRITE, V_TRUE);
-	} else if(string(optarg) == "false") {
-	  op->put(PREF_ALLOW_OVERWRITE, V_FALSE);
-	} else {
-	  cerr << _("allow-overwrite must be either 'true' or 'false'.") << endl;
-	  exit(EXIT_FAILURE);
-	}
+      case 202:
+	cmdstream << PREF_ALLOW_OVERWRITE << "=" << optarg << "\n";
 	break;
-      }
-      case 203: {
-	if(string(optarg) == "true") {
-	  op->put(PREF_CHECK_INTEGRITY, V_TRUE);
-	} else if(string(optarg) == "false") {
-	  op->put(PREF_CHECK_INTEGRITY, V_FALSE);
-	} else {
-	  cerr << _("check-integrity must be be either 'true' or 'false'.") << endl;
-	  exit(EXIT_FAILURE);
-	}
+      case 203:
+	cmdstream << PREF_CHECK_INTEGRITY << "=" << optarg << "\n";
 	break;
-      }
-      case 204: {
-	if(string(optarg) == "true") {
-	  op->put(PREF_REALTIME_CHUNK_CHECKSUM, V_TRUE);
-	} else if(string(optarg) == "false") {
-	  op->put(PREF_REALTIME_CHUNK_CHECKSUM, V_FALSE);
-	} else {
-	  cerr << _("realtime-chunk-checksum must be either 'true' or 'false'.") << endl;
-	  exit(EXIT_FAILURE);
-	}
+      case 204:
+	cmdstream << PREF_REALTIME_CHUNK_CHECKSUM << "=" << optarg << "\n";
 	break;
       }
-      }
       break;
     }
     case 'D':
-      op->put(PREF_DAEMON, V_TRUE);
+      cmdstream << PREF_DAEMON << "=" << V_TRUE << "\n";
       break;
     case 'd':
-      op->put(PREF_DIR, optarg);
+      cmdstream << PREF_DIR << "=" << optarg << "\n";
       break;
     case 'o':
-      op->put(PREF_OUT, optarg);
+      cmdstream << PREF_OUT << "=" << optarg << "\n";
       break;
     case 'l':
-      if(strcmp("-", optarg) == 0) {
-	op->put(PREF_STDOUT_LOG, V_TRUE);
-      } else {
-	op->put(PREF_LOG, optarg);
-      }
+      cmdstream << PREF_LOG << "=" << optarg << "\n";
       break;
-    case 's': {
-      int split = (int)strtol(optarg, NULL, 10);
-      if(!(1 <= split && split <= 5)) {
-	cerr << _("split must be between 1 and 5.") << endl;
-	exit(EXIT_FAILURE);
-      }
-      op->put(PREF_SPLIT, Util::itos(split));
+    case 's':
+      cmdstream << PREF_SPLIT << "=" << optarg << "\n";
       break;
-    }
-    case 't': {
-      int timeout = (int)strtol(optarg, NULL, 10);
-      if(1 <= timeout && timeout <= 600) {
-	op->put(PREF_TIMEOUT, Util::itos(timeout));
-      } else {
-	cerr << _("timeout must be between 1 and 600") << endl;
-	exit(EXIT_FAILURE);
-      }
+    case 't':
+      cmdstream << PREF_TIMEOUT << "=" << optarg << "\n";
       break;
-    }
-    case 'm': {
-      int retries = (int)strtol(optarg, NULL, 10);
-      if(retries < 0) {
-	cerr << _("max-tries invalid") << endl;
-	exit(EXIT_FAILURE);
-      }
-      op->put(PREF_MAX_TRIES, Util::itos(retries));
+    case 'm':
+      cmdstream << PREF_MAX_TRIES << "=" << optarg << "\n";
       break;
-    }
     case 'p':
-      op->put(PREF_FTP_PASV_ENABLED, V_TRUE);
+      cmdstream << PREF_FTP_PASV << "=" << V_TRUE << "\n";
       break;
     case 'S':
-      op->put(PREF_SHOW_FILES, V_TRUE);
+      cmdstream << PREF_SHOW_FILES << "=" << V_TRUE << "\n";
       break;
     case 'T':
-      op->put(PREF_TORRENT_FILE, optarg);
+      cmdstream << PREF_TORRENT_FILE << "=" << optarg << "\n";
       break;
     case 'M':
-      op->put(PREF_METALINK_FILE, optarg);
+      cmdstream << PREF_METALINK_FILE << "=" << optarg << "\n";
       break;
-    case 'C': {
-      int metalinkServers = (int)strtol(optarg, NULL, 10);
-      if(metalinkServers <= 0) {
-	cerr << _("metalink-servers must be greater than 0.") << endl;
-	exit(EXIT_FAILURE);
-      }
-      op->put(PREF_METALINK_SERVERS, Util::itos(metalinkServers));
+    case 'C':
+      cmdstream << PREF_METALINK_SERVERS << "=" << optarg << "\n";
       break;
-    }
-    case 'a': {
-      string value = string(optarg);
-      if(value == V_NONE || value == V_PREALLOC) {
-	op->put(PREF_FILE_ALLOCATION, value);
-      } else {
-	cerr << _("file-allocation must be either 'none' or 'prealloc'.") << endl;
-	exit(EXIT_FAILURE);
-      }
+    case 'a':
+      cmdstream << PREF_FILE_ALLOCATION << "=" << optarg << "\n";
       break;
-    }
     case 'c':
-      op->put(PREF_CONTINUE, V_TRUE);
+      cmdstream << PREF_CONTINUE << "=" << V_TRUE << "\n";
+      break;
+    case 'U':
+      cmdstream << PREF_USER_AGENT << "=" << optarg << "\n";
       break;
     case 'v':
       showVersion();
@@ -738,6 +574,34 @@ int main(int argc, char* argv[]) {
       exit(EXIT_FAILURE);
     }
   }
+
+  {
+    OptionParser oparser;
+    oparser.setOptionHandlers(OptionHandlerFactory::createOptionHandlers());
+    string cfname = Util::getHomeDir()+"/.aria2/aria2.conf";
+    ifstream cfstream(cfname.c_str());
+    try {
+      oparser.parse(op, cfstream);
+    } catch(Exception* e) {
+      cerr << "Parse error in " << cfname << endl;
+      cerr << e->getMsg() << endl;
+      delete e;
+      exit(EXIT_FAILURE);
+    }
+    try {
+      oparser.parse(op, cmdstream);
+    } catch(Exception* e) {
+      cerr << e->getMsg() << endl;
+      delete e;
+      exit(EXIT_FAILURE);
+    }
+  }
+  if(op->defined(PREF_HTTP_USER)) {
+    op->put(PREF_HTTP_AUTH_ENABLED, V_TRUE);
+  }
+  if(op->defined(PREF_HTTP_PROXY_USER)) {
+    op->put(PREF_HTTP_PROXY_AUTH_ENABLED, V_TRUE);
+  }
   if(!op->defined(PREF_TORRENT_FILE) && !op->defined(PREF_METALINK_FILE)) {
     if(optind == argc) {
       cerr << _("specify at least one URL") << endl;
@@ -779,9 +643,16 @@ int main(int argc, char* argv[]) {
     logger->info("%s %s", PACKAGE, PACKAGE_VERSION);
     logger->info("Logging started.");
 
-    NetrcHandle netrc = new Netrc();
-    netrc->parse(op->get(PREF_NETRC_PATH));
-
+    NetrcHandle netrc = 0;
+    File netrccf(op->get(PREF_NETRC_PATH));
+    mode_t mode = netrccf.mode();
+    if(mode&(S_IRWXG|S_IRWXO)) {
+      logger->notice(".netrc file %s does not have correct permissions. It should be 600. netrc support disabled.",
+		     op->get(PREF_NETRC_PATH).c_str());
+    } else {
+      netrc = new Netrc();
+      netrc->parse(op->get(PREF_NETRC_PATH));
+    }
     RequestFactoryHandle requestFactory = new RequestFactory();
     requestFactory->setOption(op);
     requestFactory->setNetrc(netrc);

+ 19 - 3
src/messageDigest.h

@@ -79,7 +79,24 @@ public:
   {
     digestFree();
   }
-#ifdef HAVE_LIBSSL
+
+#if defined(HAVE_OLD_LIBSSL)
+  void digestInit() {EVP_DigestInit(&ctx, algo);}
+  void digestReset() {EVP_DigestInit(&ctx, algo);}
+  void digestUpdate(const void* data, int length) {EVP_DigestUpdate(&ctx, data, length);}
+  void digestFinal(unsigned char* md) {
+    int len;
+    EVP_DigestFinal(&ctx, md, (unsigned int*)&len);
+  }
+  void digestFree() {/*empty*/}
+  int digestLength() const {
+    return digestLength(algo);
+  }
+  static int digestLength(DigestAlgo algo) {
+    return EVP_MD_size(algo);
+  }
+
+#elif defined(HAVE_LIBSSL)
   void digestInit() {
     EVP_MD_CTX_init(&ctx);
     digestReset();
@@ -103,9 +120,8 @@ public:
   static int digestLength(DigestAlgo algo) {
     return EVP_MD_size(algo);
   }
-#endif // HAVE_LIBSSL
 
-#ifdef HAVE_LIBGCRYPT
+#elif defined(HAVE_LIBGCRYPT)
   void digestInit() {
     gcry_md_open(&ctx, algo, 0);
   }

+ 57 - 54
src/prefs.h

@@ -48,19 +48,19 @@
  * General preferences
  */
 // values: 1*digit
-#define PREF_RETRY_WAIT "retry_wait"
+#define PREF_RETRY_WAIT "retry-wait"
 // values: 1*digit
 #define PREF_TIMEOUT "timeout"
 // values: 1*digit
-#define PREF_DNS_TIMEOUT "dns_timeout"
+#define PREF_DNS_TIMEOUT "dns-timeout"
 // values: 1*digit
-#define PREF_MAX_TRIES "max_tries"
+#define PREF_MAX_TRIES "max-tries"
 // values: 1*digit
-#define PREF_MIN_SEGMENT_SIZE "min_segment_size"
+#define PREF_MIN_SEGMENT_SIZE "min-segment-size"
 // values: 1*digit
-#define PREF_AUTO_SAVE_INTERVAL "auto_save_interval"
+#define PREF_AUTO_SAVE_INTERVAL "auto-save-interval"
 // values: true | false
-#define PREF_STDOUT_LOG "stdout_log"
+#define PREF_STDOUT_LOG "stdout-log"
 // values: a string that your file system recognizes as a file name.
 #define PREF_LOG "log"
 // values: a string that your file system recognizes as a directory.
@@ -74,120 +74,123 @@
 // value: a string
 #define PREF_REFERER "referer"
 // value: 1*digit
-#define PREF_LOWEST_SPEED_LIMIT "lowest_speed_limit"
+#define PREF_LOWEST_SPEED_LIMIT "lowest-speed-limit"
 // value: 1*digit
-#define PREF_SEGMENT_SIZE "segment_size"
+#define PREF_SEGMENT_SIZE "segment-size"
 // value: 1*digit
-#define PREF_MAX_DOWNLOAD_LIMIT "max_download_limit"
+#define PREF_MAX_DOWNLOAD_LIMIT "max-download-limit"
 // value: 1*digit
-#define PREF_STARTUP_IDLE_TIME "startup_idle_time"
+#define PREF_STARTUP_IDLE_TIME "startup-idle-time"
 // value: prealloc | none
-#define PREF_FILE_ALLOCATION "file_allocation"
+#define PREF_FILE_ALLOCATION "file-allocation"
 #  define V_PREALLOC "prealloc"
 // value: true | false
-#define PREF_ALLOW_OVERWRITE "allow_overwrite"
+#define PREF_ALLOW_OVERWRITE "allow-overwrite"
 // value: true | false
-#define PREF_REALTIME_CHUNK_CHECKSUM "realtime_chunk_checksum"
+#define PREF_REALTIME_CHUNK_CHECKSUM "realtime-chunk-checksum"
 // value: true | false
-#define PREF_CHECK_INTEGRITY "check_integrity"
+#define PREF_CHECK_INTEGRITY "check-integrity"
 // value: string that your file system recognizes as a file name.
-#define PREF_NETRC_PATH "netrc_path"
+#define PREF_NETRC_PATH "netrc-path"
 // value:
 #define PREF_CONTINUE "continue"
 
 /**
  * FTP related preferences
  */
-#define PREF_FTP_USER "ftp_user"
-#define PREF_FTP_PASSWD "ftp_passwd"
+#define PREF_FTP_USER "ftp-user"
+#define PREF_FTP_PASSWD "ftp-passwd"
 // values: binary | ascii
-#define PREF_FTP_TYPE "ftp_type"
+#define PREF_FTP_TYPE "ftp-type"
 #  define V_BINARY "binary"
 #  define V_ASCII "ascii"
 // values: get | tunnel
-#define PREF_FTP_VIA_HTTP_PROXY "ftp_via_http_proxy"
+#define PREF_FTP_VIA_HTTP_PROXY "ftp-via-http-proxy"
 #  define V_GET "get"
 #  define V_TUNNEL "tunnel"
 // values: true | false
-#define PREF_FTP_PASV_ENABLED "ftp_pasv_enabled"
+#define PREF_FTP_PASV "ftp-pasv"
 
 /**
  * HTTP related preferences
  */
-#define PREF_HTTP_USER "http_user"
-#define PREF_HTTP_PASSWD "http_passwd"
+#define PREF_HTTP_USER "http-user"
+#define PREF_HTTP_PASSWD "http-passwd"
 // values: basic
-#define PREF_HTTP_AUTH_SCHEME "http_auth_scheme"
+#define PREF_HTTP_AUTH_SCHEME "http-auth-scheme"
 #  define V_BASIC "basic"
 // values: true | false
-#define PREF_HTTP_AUTH_ENABLED "http_auth_enabled"
+#define PREF_HTTP_AUTH_ENABLED "http-auth-enabled"
 // values: true | false
-#define PREF_HTTP_KEEP_ALIVE "http_keep_alive"
+#define PREF_HTTP_KEEP_ALIVE "http-keep-alive"
+// values: string
+#define PREF_USER_AGENT "user-agent"
 
 /** 
  * HTTP proxy related preferences
  */
-#define PREF_HTTP_PROXY_USER "http_proxy_user"
-#define PREF_HTTP_PROXY_PASSWD "http_proxy_passwd"
-#define PREF_HTTP_PROXY_HOST "http_proxy_host"
-#define PREF_HTTP_PROXY_PORT "http_proxy_port"
+#define PREF_HTTP_PROXY "http-proxy"
+#define PREF_HTTP_PROXY_USER "http-proxy-user"
+#define PREF_HTTP_PROXY_PASSWD "http-proxy-passwd"
+#define PREF_HTTP_PROXY_HOST "http-proxy-host"
+#define PREF_HTTP_PROXY_PORT "http-proxy-port"
 // values: get | tunnel
-#define PREF_HTTP_PROXY_METHOD "http_proxy_method"
+#define PREF_HTTP_PROXY_METHOD "http-proxy-method"
 // values: true | false
-#define PREF_HTTP_PROXY_ENABLED "http_proxy_enabled"
+#define PREF_HTTP_PROXY_ENABLED "http-proxy-enabled"
 // values: true | false
-#define PREF_HTTP_PROXY_AUTH_ENABLED "http_proxy_auth_enabled"
+#define PREF_HTTP_PROXY_AUTH_ENABLED "http-proxy-auth-enabled"
 
 /**
  * BitTorrent related preferences
  */
 // values: 1*digit
-#define PREF_PEER_CONNECTION_TIMEOUT "peer_connection_timeout"
+#define PREF_PEER_CONNECTION_TIMEOUT "peer-connection-timeout"
 // values: 1*digit
-#define PREF_BT_TIMEOUT "bt_timeout"
+#define PREF_BT_TIMEOUT "bt-timeout"
 // values: 1*digit
-#define PREF_BT_REQUEST_TIMEOUT "bt_request_timeout"
+#define PREF_BT_REQUEST_TIMEOUT "bt-request-timeout"
 // values: true | false
-#define PREF_SHOW_FILES "show_files"
+#define PREF_SHOW_FILES "show-files"
 // values: true | false
-#define PREF_NO_PREALLOCATION "no_preallocation"
+#define PREF_NO_PREALLOCATION "no-preallocation"
 // values: true | false
-#define PREF_DIRECT_FILE_MAPPING "direct_file_mapping"
+#define PREF_DIRECT_FILE_MAPPING "direct-file-mapping"
 // values: 1*digit
-#define PREF_MAX_UPLOAD_LIMIT "max_upload_limit"
+#define PREF_MAX_UPLOAD_LIMIT "max-upload-limit"
 // values: a string that your file system recognizes as a file name.
-#define PREF_TORRENT_FILE "torrent_file"
+#define PREF_TORRENT_FILE "torrent-file"
 // values: 1*digit
-#define PREF_LISTEN_PORT "listen_port"
+#define PREF_LISTEN_PORT "listen-port"
 // values: true | false
-#define PREF_FOLLOW_TORRENT "follow_torrent"
+#define PREF_FOLLOW_TORRENT "follow-torrent"
 // values: 1*digit *( (,|-) 1*digit)
-#define PREF_SELECT_FILE "select_file"
+#define PREF_SELECT_FILE "select-file"
 // values: 1*digit
-#define PREF_SEED_TIME "seed_time"
+#define PREF_SEED_TIME "seed-time"
 // values: 1*digit ['.' [ 1*digit ] ]
-#define PREF_SEED_RATIO "seed_ratio"
+#define PREF_SEED_RATIO "seed-ratio"
 // values: 1*digit
-#define PREF_TRACKER_MAX_TRIES "tracker_max_tries"
+#define PREF_TRACKER_MAX_TRIES "tracker-max-tries"
 // values: 1*digit
-#define PREF_BT_KEEP_ALIVE_INTERVAL "bt_keep_alive_interval"
+#define PREF_BT_KEEP_ALIVE_INTERVAL "bt-keep-alive-interval"
 
 /**
  * Metalink related preferences
  */
 // values: a string that your file system recognizes as a file name.
-#define PREF_METALINK_FILE "metalink_file"
+#define PREF_METALINK_FILE "metalink-file"
 // values: a string
-#define PREF_METALINK_VERSION "metalink_version"
+#define PREF_METALINK_VERSION "metalink-version"
 // values: a string
-#define PREF_METALINK_LANGUAGE "metalink_language"
+#define PREF_METALINK_LANGUAGE "metalink-language"
 // values: a string
-#define PREF_METALINK_OS "metalink_os"
+#define PREF_METALINK_OS "metalink-os"
 // values: a string
-#define PREF_METALINK_LOCATION "metalink_location"
+#define PREF_METALINK_LOCATION "metalink-location"
 // values: 1*digit
-#define PREF_METALINK_SERVERS "metalink_servers"
+#define PREF_METALINK_SERVERS "metalink-servers"
 // values: true | false
-#define PREF_FOLLOW_METALINK "follow_metalink"
+#define PREF_FOLLOW_METALINK "follow-metalink"
 
 #endif // _D_PREFS_H_

+ 2 - 1
test/Makefile.am

@@ -1,6 +1,8 @@
 TESTS = aria2c
 check_PROGRAMS = $(TESTS)
 aria2c_SOURCES = AllTest.cc\
+	UtilTest.cc\
+	OptionHandlerTest.cc\
 	SegmentManTest.cc\
 	BitfieldManTest.cc\
 	GlowFileAllocatorTest.cc\
@@ -15,7 +17,6 @@ aria2c_SOURCES = AllTest.cc\
 	FileTest.cc\
 	OptionTest.cc\
 	Base64Test.cc\
-	UtilTest.cc\
 	CookieBoxTest.cc\
 	DataTest.cc\
 	DictionaryTest.cc\

+ 6 - 3
test/Makefile.in

@@ -57,14 +57,15 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 am__EXEEXT_1 = aria2c$(EXEEXT)
-am_aria2c_OBJECTS = AllTest.$(OBJEXT) SegmentManTest.$(OBJEXT) \
+am_aria2c_OBJECTS = AllTest.$(OBJEXT) UtilTest.$(OBJEXT) \
+	OptionHandlerTest.$(OBJEXT) SegmentManTest.$(OBJEXT) \
 	BitfieldManTest.$(OBJEXT) GlowFileAllocatorTest.$(OBJEXT) \
 	RequestTest.$(OBJEXT) HttpRequestTest.$(OBJEXT) \
 	NetrcTest.$(OBJEXT) SingletonHolderTest.$(OBJEXT) \
 	HttpHeaderTest.$(OBJEXT) HttpResponseTest.$(OBJEXT) \
 	SharedHandleTest.$(OBJEXT) ChunkedEncodingTest.$(OBJEXT) \
 	FileTest.$(OBJEXT) OptionTest.$(OBJEXT) Base64Test.$(OBJEXT) \
-	UtilTest.$(OBJEXT) CookieBoxTest.$(OBJEXT) DataTest.$(OBJEXT) \
+	CookieBoxTest.$(OBJEXT) DataTest.$(OBJEXT) \
 	DictionaryTest.$(OBJEXT) ListTest.$(OBJEXT) \
 	MetaFileUtilTest.$(OBJEXT) ShaVisitorTest.$(OBJEXT) \
 	PeerMessageUtilTest.$(OBJEXT) DefaultDiskWriterTest.$(OBJEXT) \
@@ -259,6 +260,8 @@ sysconfdir = @sysconfdir@
 target_alias = @target_alias@
 TESTS = aria2c
 aria2c_SOURCES = AllTest.cc\
+	UtilTest.cc\
+	OptionHandlerTest.cc\
 	SegmentManTest.cc\
 	BitfieldManTest.cc\
 	GlowFileAllocatorTest.cc\
@@ -273,7 +276,6 @@ aria2c_SOURCES = AllTest.cc\
 	FileTest.cc\
 	OptionTest.cc\
 	Base64Test.cc\
-	UtilTest.cc\
 	CookieBoxTest.cc\
 	DataTest.cc\
 	DictionaryTest.cc\
@@ -435,6 +437,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkerTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiDiskAdaptorTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetrcTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OptionHandlerTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OptionTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerMessageUtilTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerTest.Po@am__quote@

+ 360 - 0
test/OptionHandlerTest.cc

@@ -0,0 +1,360 @@
+#include "OptionHandlerImpl.h"
+#include "prefs.h"
+#include "Exception.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class OptionHandlerTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(OptionHandlerTest);
+  CPPUNIT_TEST(testNullOptionHandler);
+  CPPUNIT_TEST(testBooleanOptionHandler);
+  CPPUNIT_TEST(testNumberOptionHandler);
+  CPPUNIT_TEST(testNumberOptionHandler_min);
+  CPPUNIT_TEST(testNumberOptionHandler_max);
+  CPPUNIT_TEST(testNumberOptionHandler_min_max);
+  CPPUNIT_TEST(testUnitNumberOptionHandler);
+  CPPUNIT_TEST(testParameterOptionHandler_1argInit);
+  CPPUNIT_TEST(testParameterOptionHandler_2argsInit);
+  CPPUNIT_TEST(testParameterOptionHandler_listInit);
+  CPPUNIT_TEST(testDefaultOptionHandler);
+  CPPUNIT_TEST(testFloatNumberOptionHandler);
+  CPPUNIT_TEST(testFloatNumberOptionHandler_min);
+  CPPUNIT_TEST(testFloatNumberOptionHandler_max);
+  CPPUNIT_TEST(testFloatNumberOptionHandler_min_max);
+  CPPUNIT_TEST(testLogOptionHandler);
+  CPPUNIT_TEST(testHttpProxyOptionHandler);
+  CPPUNIT_TEST_SUITE_END();
+  
+public:
+  void testNullOptionHandler();
+  void testBooleanOptionHandler();
+  void testNumberOptionHandler();
+  void testNumberOptionHandler_min();
+  void testNumberOptionHandler_max();
+  void testNumberOptionHandler_min_max();
+  void testUnitNumberOptionHandler();
+  void testParameterOptionHandler_1argInit();
+  void testParameterOptionHandler_2argsInit();
+  void testParameterOptionHandler_listInit();
+  void testDefaultOptionHandler();
+  void testFloatNumberOptionHandler();
+  void testFloatNumberOptionHandler_min();
+  void testFloatNumberOptionHandler_max();
+  void testFloatNumberOptionHandler_min_max();
+  void testLogOptionHandler();
+  void testHttpProxyOptionHandler();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( OptionHandlerTest );
+
+void OptionHandlerTest::testNullOptionHandler()
+{
+  NullOptionHandler handler;
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  handler.parseArg(0, "bar");
+}
+
+void OptionHandlerTest::testBooleanOptionHandler()
+{
+  BooleanOptionHandler handler("foo");
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  CPPUNIT_ASSERT(!handler.canHandle("foobar"));
+  Option option;
+  handler.parseArg(&option, V_TRUE);
+  CPPUNIT_ASSERT_EQUAL(string(V_TRUE), option.get("foo"));
+  handler.parseArg(&option, V_FALSE);
+  CPPUNIT_ASSERT_EQUAL(string(V_FALSE), option.get("foo"));
+  try {
+    handler.parseArg(&option, "hello");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+}
+
+void OptionHandlerTest::testNumberOptionHandler()
+{
+  NumberOptionHandler handler("foo");
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  CPPUNIT_ASSERT(!handler.canHandle("foobar"));
+  Option option;
+  handler.parseArg(&option, "0");
+  CPPUNIT_ASSERT_EQUAL(string("0"), option.get("foo"));
+}
+
+void OptionHandlerTest::testNumberOptionHandler_min()
+{
+  NumberOptionHandler handler("foo", 1);
+  Option option;
+  handler.parseArg(&option, "1");
+  CPPUNIT_ASSERT_EQUAL(string("1"), option.get("foo"));
+  try {
+    handler.parseArg(&option, "0");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+
+}
+
+void OptionHandlerTest::testNumberOptionHandler_max()
+{
+  NumberOptionHandler handler("foo", -1, 100);
+  Option option;
+  handler.parseArg(&option, "100");
+  CPPUNIT_ASSERT_EQUAL(string("100"), option.get("foo"));
+  try {
+    handler.parseArg(&option, "101");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+}
+
+void OptionHandlerTest::testNumberOptionHandler_min_max()
+{
+  NumberOptionHandler handler("foo", 1, 100);
+  Option option;
+  handler.parseArg(&option, "1");
+  CPPUNIT_ASSERT_EQUAL(string("1"), option.get("foo"));
+  handler.parseArg(&option, "100");
+  CPPUNIT_ASSERT_EQUAL(string("100"), option.get("foo"));
+  try {
+    handler.parseArg(&option, "0");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+  try {
+    handler.parseArg(&option, "101");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+}
+
+void OptionHandlerTest::testUnitNumberOptionHandler()
+{
+  UnitNumberOptionHandler handler("foo");
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  CPPUNIT_ASSERT(!handler.canHandle("foobar"));
+  Option option;
+  handler.parseArg(&option, "4294967296");
+  CPPUNIT_ASSERT_EQUAL(string("4294967296"), option.get("foo"));
+  handler.parseArg(&option, "4096M");
+  CPPUNIT_ASSERT_EQUAL(string("4294967296"), option.get("foo"));
+  handler.parseArg(&option, "4096K");
+  CPPUNIT_ASSERT_EQUAL(string("4194304"), option.get("foo"));
+  handler.parseArg(&option, "K");
+  CPPUNIT_ASSERT_EQUAL(string("0"), option.get("foo"));
+  handler.parseArg(&option, "M");
+  CPPUNIT_ASSERT_EQUAL(string("0"), option.get("foo"));
+  handler.parseArg(&option, "");
+  CPPUNIT_ASSERT_EQUAL(string("0"), option.get("foo"));
+}
+
+void OptionHandlerTest::testParameterOptionHandler_1argInit()
+{
+  ParameterOptionHandler handler("foo", "value1");
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  CPPUNIT_ASSERT(!handler.canHandle("foobar"));
+  Option option;
+  handler.parseArg(&option, "value1");
+  CPPUNIT_ASSERT_EQUAL(string("value1"), option.get("foo"));
+  try {
+    handler.parseArg(&option, "value3");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+}
+
+void OptionHandlerTest::testParameterOptionHandler_2argsInit()
+{
+  ParameterOptionHandler handler("foo", "value1", "value2");
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  CPPUNIT_ASSERT(!handler.canHandle("foobar"));
+  Option option;
+  handler.parseArg(&option, "value1");
+  CPPUNIT_ASSERT_EQUAL(string("value1"), option.get("foo"));
+  handler.parseArg(&option, "value2");
+  CPPUNIT_ASSERT_EQUAL(string("value2"), option.get("foo"));
+  try {
+    handler.parseArg(&option, "value3");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+}
+
+void OptionHandlerTest::testParameterOptionHandler_listInit()
+{
+  Strings validValues;
+  validValues.push_back("value1");
+  validValues.push_back("value2");
+
+  ParameterOptionHandler handler("foo", validValues);
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  CPPUNIT_ASSERT(!handler.canHandle("foobar"));
+  Option option;
+  handler.parseArg(&option, "value1");
+  CPPUNIT_ASSERT_EQUAL(string("value1"), option.get("foo"));
+  handler.parseArg(&option, "value2");
+  CPPUNIT_ASSERT_EQUAL(string("value2"), option.get("foo"));
+  try {
+    handler.parseArg(&option, "value3");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+}
+
+void OptionHandlerTest::testDefaultOptionHandler()
+{
+  DefaultOptionHandler handler("foo");
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  CPPUNIT_ASSERT(!handler.canHandle("foobar"));
+  Option option;
+  handler.parseArg(&option, "bar");
+  CPPUNIT_ASSERT_EQUAL(string("bar"), option.get("foo"));
+  handler.parseArg(&option, "");
+  CPPUNIT_ASSERT_EQUAL(string(""), option.get("foo"));
+}
+
+void OptionHandlerTest::testFloatNumberOptionHandler()
+{
+  FloatNumberOptionHandler handler("foo");
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  CPPUNIT_ASSERT(!handler.canHandle("foobar"));
+  Option option;
+  handler.parseArg(&option, "1.0");
+  CPPUNIT_ASSERT_EQUAL(string("1.0"), option.get("foo"));
+}
+
+void OptionHandlerTest::testFloatNumberOptionHandler_min()
+{
+  FloatNumberOptionHandler handler("foo", 0.0);
+  Option option;
+  handler.parseArg(&option, "0.0");
+  CPPUNIT_ASSERT_EQUAL(string("0.0"), option.get("foo"));
+  try {
+    handler.parseArg(&option, "-0.1");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+}
+
+void OptionHandlerTest::testFloatNumberOptionHandler_max()
+{
+  FloatNumberOptionHandler handler("foo", -1, 10.0);
+  Option option;
+  handler.parseArg(&option, "10.0");
+  CPPUNIT_ASSERT_EQUAL(string("10.0"), option.get("foo"));
+  try {
+    handler.parseArg(&option, "10.1");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+}
+
+void OptionHandlerTest::testFloatNumberOptionHandler_min_max()
+{
+  FloatNumberOptionHandler handler("foo", 0.0, 10.0);
+  Option option;
+  handler.parseArg(&option, "0.0");
+  CPPUNIT_ASSERT_EQUAL(string("0.0"), option.get("foo"));
+  handler.parseArg(&option, "10.0");
+  CPPUNIT_ASSERT_EQUAL(string("10.0"), option.get("foo"));
+  try {
+    handler.parseArg(&option, "-0.1");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+  try {
+    handler.parseArg(&option, "10.1");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+}
+
+void OptionHandlerTest::testLogOptionHandler()
+{
+  LogOptionHandler handler("foo");
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  CPPUNIT_ASSERT(!handler.canHandle("foobar"));
+  Option option;
+  handler.parseArg(&option, "/tmp/log.txt");
+  CPPUNIT_ASSERT_EQUAL(string("/tmp/log.txt"), option.get(PREF_LOG));
+  CPPUNIT_ASSERT_EQUAL(string(""), option.get(PREF_STDOUT_LOG));
+
+  option.clear();
+  handler.parseArg(&option, "-");
+  CPPUNIT_ASSERT_EQUAL(string(""), option.get(PREF_LOG));
+  CPPUNIT_ASSERT_EQUAL(string(V_TRUE), option.get(PREF_STDOUT_LOG));
+}
+
+void OptionHandlerTest::testHttpProxyOptionHandler()
+{
+  HttpProxyOptionHandler handler("foo");
+  CPPUNIT_ASSERT(handler.canHandle("foo"));
+  CPPUNIT_ASSERT(!handler.canHandle("foobar"));
+  Option option;
+  handler.parseArg(&option, "bar:80");
+  CPPUNIT_ASSERT_EQUAL(string("bar:80"), option.get(PREF_HTTP_PROXY));
+  CPPUNIT_ASSERT_EQUAL(string("bar"), option.get(PREF_HTTP_PROXY_HOST));
+  CPPUNIT_ASSERT_EQUAL(string("80"), option.get(PREF_HTTP_PROXY_PORT));
+  CPPUNIT_ASSERT_EQUAL(string(V_TRUE), option.get(PREF_HTTP_PROXY_ENABLED));
+
+  try {
+    handler.parseArg(&option, "bar");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+  try {
+    handler.parseArg(&option, "bar:");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+  try {
+    handler.parseArg(&option, ":");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+  try {
+    handler.parseArg(&option, ":80");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+  try {
+    handler.parseArg(&option, "foo:bar");
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(Exception* e) {
+    cerr << e->getMsg() << endl;
+    delete e;
+  }
+}

+ 10 - 0
test/UtilTest.cc

@@ -22,6 +22,7 @@ class UtilTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testToLower);
   CPPUNIT_TEST(testUrldecode);
   CPPUNIT_TEST(testCountBit);
+  CPPUNIT_TEST(testGetRealSize);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -44,6 +45,7 @@ public:
   void testToLower();
   void testUrldecode();
   void testCountBit();
+  void testGetRealSize();
 };
 
 
@@ -289,3 +291,11 @@ void UtilTest::testCountBit() {
   CPPUNIT_ASSERT_EQUAL(32, Util::countBit(UINT32_MAX));
   CPPUNIT_ASSERT_EQUAL(8, Util::countBit(255));
 }
+
+void UtilTest::testGetRealSize()
+{
+  CPPUNIT_ASSERT_EQUAL((int64_t)4294967296LL, Util::getRealSize("4096M"));
+  CPPUNIT_ASSERT_EQUAL((int64_t)1024, Util::getRealSize("1K"));
+  CPPUNIT_ASSERT_EQUAL((int64_t)0, Util::getRealSize(""));
+  CPPUNIT_ASSERT_EQUAL((int64_t)0, Util::getRealSize("foo"));
+}