diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index a243066c..159cafd9 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -27,6 +27,8 @@ namespace core { +static constexpr const char* session_invalid_message = "Session data is invalid, ignoring it"; + bool is_network_uri(const std::string& uri) { return @@ -35,9 +37,15 @@ is_network_uri(const std::string& uri) { std::strncmp(uri.c_str(), "ftp://", 6) == 0; } -static constexpr const char* session_invalid_message = "Session data is invalid, ignoring it"; +bool +is_magnet_uri(const std::string& uri) { + return + std::strncmp(uri.c_str(), "magnet:?", 8) == 0; +} -static std::unique_ptr +namespace { + +std::unique_ptr download_factory_load_stream(const char* filename, bool* is_invalid) { std::fstream stream(filename, std::ios::in | std::ios::binary); @@ -55,17 +63,34 @@ download_factory_load_stream(const char* filename, bool* is_invalid) { return obj; } -bool -is_magnet_uri(const std::string& uri) { - return - std::strncmp(uri.c_str(), "magnet:?", 8) == 0; +std::unique_ptr +create_untrusted_object(torrent::Object& obj) { + auto trusted_object = std::make_unique(torrent::Object::create_map()); + + if (obj.has_key("info")) + trusted_object->insert_key_move("info", obj.get_key("info")); + + if (obj.has_key("announce")) + trusted_object->insert_key_move("announce", obj.get_key("announce")); + + if (obj.has_key("announce-list")) + trusted_object->insert_key_move("announce-list", obj.get_key("announce-list")); + + if (obj.has_key("creation date")) + trusted_object->insert_key_move("creation date", obj.get_key("creation date")); + + if (obj.has_key("created by")) + trusted_object->insert_key_move("created by", obj.get_key("created by")); + + return trusted_object; } -DownloadFactory::DownloadFactory(Manager* m) : - m_manager(m) { +} // namespace anonymous - m_task_load.slot() = std::bind(&DownloadFactory::receive_load, this); - m_task_commit.slot() = std::bind(&DownloadFactory::receive_commit, this); + +DownloadFactory::DownloadFactory(Manager* m, bool trusted) + : m_manager(m), + m_trusted(trusted) { // m_variables["connection_leech"] = rpc::call_command("protocol.connection.leech"); // m_variables["connection_seed"] = rpc::call_command("protocol.connection.seed"); @@ -78,75 +103,135 @@ DownloadFactory::DownloadFactory(Manager* m) : DownloadFactory::~DownloadFactory() { torrent::this_thread::scheduler()->erase(&m_task_load); torrent::this_thread::scheduler()->erase(&m_task_commit); - - delete m_object; } void -DownloadFactory::load(const std::string& uri) { +DownloadFactory::load_trusted(const std::string& uri) { + if (!m_trusted) + throw torrent::internal_error("DownloadFactory::load_trusted() called on an untrusted object"); + m_uri = uri; + m_task_load.slot() = [this]() { receive_load_trusted(); }; + + torrent::this_thread::scheduler()->wait_for(&m_task_load, 0ms); +} + +void +DownloadFactory::load_untrusted(const std::string& uri) { + if (m_trusted) + throw torrent::internal_error("DownloadFactory::load_untrusted() called on a trusted object"); + + m_uri = uri; + m_task_load.slot() = [this]() { receive_load_untrusted(); }; + torrent::this_thread::scheduler()->wait_for(&m_task_load, 0ms); } -// This function must be called before DownloadFactory::commit(). void DownloadFactory::load_raw_data(const std::string& input) { if (m_stream) - throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL"); + throw torrent::internal_error("DownloadFactory::load_raw_data() called on an object with m_stream != NULL"); m_stream.reset(new std::stringstream(input)); m_loaded = true; } void -DownloadFactory::commit() { +DownloadFactory::commit_trusted() { + if (!m_trusted) + throw torrent::internal_error("DownloadFactory::commit_trusted() called on an untrusted object"); + + m_task_commit.slot() = [this]() { receive_commit(); }; torrent::this_thread::scheduler()->wait_for(&m_task_commit, 0ms); } void -DownloadFactory::receive_load() { - if (m_stream) - throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL"); +DownloadFactory::commit_untrusted() { + if (m_trusted) + throw torrent::internal_error("DownloadFactory::commit_untrusted() called on a trusted object"); - if (is_network_uri(m_uri)) { - m_stream.reset(new std::stringstream); + m_task_commit.slot() = [this]() { receive_commit(); }; + torrent::this_thread::scheduler()->wait_for(&m_task_commit, 0ms); +} - auto done_fn = [this]() { receive_loaded(); }; - auto failed_fn = [this](const std::string& error) { receive_failed(error); }; +void +DownloadFactory::process_load_network_uri() { + m_stream.reset(new std::stringstream); - m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn); + // TODO: Add trusted flag. - m_variables["tied_to_file"] = (int64_t)false; - return; - } + auto done_fn = [this]() { receive_loaded(); }; + auto failed_fn = [this](const std::string& error) { receive_failed(error); }; - if (is_magnet_uri(m_uri)) { - // DEBUG: Use m_object. - m_stream.reset(new std::stringstream()); - *m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e"; + m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn); - m_variables["tied_to_file"] = (int64_t)false; + m_variables["tied_to_file"] = (int64_t)false; +} - receive_loaded(); - return; - } +void +DownloadFactory::process_load_magnet_uri() { + m_stream.reset(new std::stringstream()); + *m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e"; + m_variables["tied_to_file"] = (int64_t)false; + + receive_loaded(); +} + +void +DownloadFactory::process_load_file_uri() { std::fstream stream(expand_path(m_uri).c_str(), std::ios::in | std::ios::binary); if (!stream.is_open()) return receive_failed("Could not open file"); - m_object = new torrent::Object; + m_object = std::make_unique(); stream >> *m_object; if (!stream.good()) return receive_failed("Reading torrent file failed"); - m_isFile = true; + m_is_file = true; receive_loaded(); } +void +DownloadFactory::receive_load_trusted() { + if (!m_trusted) + throw torrent::internal_error("DownloadFactory::receive_load_trusted() called on an untrusted object"); + + if (m_stream) + throw torrent::internal_error("DownloadFactory::receive_load_trusted() called on an object with null m_stream"); + + if (is_network_uri(m_uri)) + return process_load_network_uri(); + + if (is_magnet_uri(m_uri)) + return process_load_magnet_uri(); + + process_load_file_uri(); +} + +void +DownloadFactory::receive_load_untrusted() { + if (m_trusted) + throw torrent::internal_error("DownloadFactory::receive_load_untrusted() called on a trusted object"); + + if (m_stream) + throw torrent::internal_error("DownloadFactory::load*() called on an object with null m_stream"); + + if (is_network_uri(m_uri)) + return process_load_network_uri(); + + // TODO: Don't need to handle untrusted commands magnet URIs. + + // if (is_magnet_uri(m_uri)) + // return process_load_magnet_uri(); + + throw torrent::internal_error("DownloadFactory::receive_load_untrusted() called on a non-network/magnet URI"); +} + void DownloadFactory::receive_loaded() { m_loaded = true; @@ -165,30 +250,40 @@ DownloadFactory::receive_commit() { void DownloadFactory::receive_success() { - bool session_invalid = false; + if (!m_trusted && m_session) + throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with m_session == true"); - auto rtorrent_object = download_factory_load_stream((expand_path(m_uri) + ".rtorrent").c_str(), &session_invalid); - auto libtorrent_resume_object = download_factory_load_stream((expand_path(m_uri) + ".libtorrent_resume").c_str(), &session_invalid); + if (m_session && !m_is_file) + throw torrent::internal_error("DownloadFactory::receive_success() called on a non-file object with m_session == true"); - if (session_invalid) - lt_log_print(torrent::LOG_ERROR, "%s: %s", session_invalid_message, m_uri.c_str()); + bool session_invalid = false; + uint32_t tracker_key = tracker_key = random() % (std::numeric_limits::max() - 1) + 1; - uint32_t tracker_key; + std::unique_ptr rtorrent_object, libtorrent_resume_object; - if (rtorrent_object && rtorrent_object->has_key_value("key")) - tracker_key = rtorrent_object->get_key_value("key"); - else - tracker_key = random() % (std::numeric_limits::max() - 1) + 1; + if (m_session) { + rtorrent_object = download_factory_load_stream((expand_path(m_uri) + ".rtorrent").c_str(), &session_invalid); + libtorrent_resume_object = download_factory_load_stream((expand_path(m_uri) + ".libtorrent_resume").c_str(), &session_invalid); - Download* download = m_stream != nullptr ? - m_manager->download_list()->create(m_stream.get(), tracker_key, m_printLog) : - m_manager->download_list()->create(m_object, tracker_key, m_printLog); + if (session_invalid) + lt_log_print(torrent::LOG_ERROR, "%s: %s", session_invalid_message, m_uri.c_str()); - m_object = NULL; + if (rtorrent_object && rtorrent_object->has_key_value("key")) + tracker_key = rtorrent_object->get_key_value("key"); + } - if (download == NULL) { - // core::Manager should already have added the error message to - // the log. + // TODO: This adds the torrent, so untrusted can add brokent torrents. + + if (m_stream != nullptr) + object_from_stream(); + + if (m_trusted) + m_object = create_untrusted_object(*m_object); + + Download* download = m_manager->download_list()->create(std::move(m_object), tracker_key, m_print_log); + + if (download == nullptr) { + // core::Manager should already have added the error message to the log. m_slot_finished(); return; } @@ -197,39 +292,49 @@ DownloadFactory::receive_success() { download->set_hash_failed(true); download->set_message(session_invalid_message); - if (m_printLog) + if (m_print_log) m_manager->push_log_std(std::string(session_invalid_message) + ": \"" + m_uri + "\""); } torrent::Object* root = download->bencode(); if (download->download()->info()->is_meta_download()) { + if (!m_trusted) + throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with a meta download"); + torrent::Object& meta = root->insert_key("rtorrent_meta_download", torrent::Object::create_map()); meta.insert_key("start", m_start); - meta.insert_key("print_log", m_printLog); + meta.insert_key("print_log", m_print_log); - torrent::Object::list_type& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list(); + // TODO: ADD UNTRUSTED!!! + auto& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list(); for (auto& m_command : m_commands) commands.push_back(m_command); } if (m_session) { + if (!m_trusted) + throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with m_session == true"); + if (rtorrent_object) root->insert_key_move("rtorrent", *rtorrent_object); if (libtorrent_resume_object) root->insert_key_move("libtorrent_resume", *libtorrent_resume_object); + } else if (!m_trusted) { + if (root->has_key("rtorrent") || root->has_key("libtorrent_resume")) + throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with 'rtorrent' or 'libtorrent_resume' keys"); + } else { - // We only allow session torrents to keep their - // 'rtorrent/libtorrent' sections. The "fast_resume" section - // should be safe to keep. + // We only allow session torrents to keep their 'rtorrent/libtorrent' sections. The + // "fast_resume" section should be safe to keep. root->erase_key("rtorrent"); } - torrent::Object* rtorrent = &root->insert_preserve_copy("rtorrent", torrent::Object::create_map()).first->second; - torrent::Object& resumeObject = root->insert_preserve_copy("libtorrent_resume", torrent::Object::create_map()).first->second; + auto* rtorrent = &root->insert_preserve_copy("rtorrent", torrent::Object::create_map()).first->second; + auto& resumeObject = root->insert_preserve_copy("libtorrent_resume", torrent::Object::create_map()).first->second; rtorrent->insert_key("key", download->tracker_controller().key()); @@ -259,7 +364,7 @@ DownloadFactory::receive_success() { } // Skip forcing trackers to scrape when rtorrent starts - if (m_initLoad && rpc::call_command_value("trackers.delay_scrape")) + if (m_init_load && rpc::call_command_value("trackers.delay_scrape")) download->set_resume_flags(torrent::Download::start_skip_tracker); // Check first if we already have these values set in the session @@ -301,7 +406,7 @@ DownloadFactory::receive_success() { lt_log_print(torrent::LOG_ERROR, "%s: %s", msg.c_str(), m_uri.c_str()); - if (m_printLog) + if (m_print_log) m_manager->push_log_std(msg + ": \"" + m_uri + "\""); download->set_hash_failed(true); @@ -325,8 +430,13 @@ DownloadFactory::receive_success() { if (torrent::log_groups[torrent::LOG_TORRENT_DEBUG].valid()) log_created(download, rtorrent); - for (const auto& command : m_commands) - rpc::parse_command_multiple_std(command, rpc::make_target(download)); + if (m_trusted) { + for (const auto& command : m_commands) + rpc::parse_command_multiple_std(command, rpc::make_target(download)); + + } else { + // TODO: CALL UNTRUSTED COMMANDS + } if (m_manager->download_list()->find(infohash) == m_manager->download_list()->end()) throw torrent::input_error("The newly created download was removed."); @@ -340,7 +450,7 @@ DownloadFactory::receive_success() { } catch (torrent::input_error& e) { std::string msg = "Command on torrent creation failed: " + std::string(e.what()); - if (m_printLog) + if (m_print_log) m_manager->push_log_std(msg); if (m_manager->download_list()->find(infohash) != m_manager->download_list()->end()) { @@ -354,6 +464,18 @@ DownloadFactory::receive_success() { m_slot_finished(); } +void +DownloadFactory::receive_failed(const std::string& msg) { + if (m_print_log) { + if (m_trusted) + m_manager->push_log_std("Failed to load torrent: " + msg + ": \"" + m_uri + "\""); + else + m_manager->push_log_std("Failed to load untrusted torrent: " + msg); + } + + m_slot_finished(); +} + void DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) { std::stringstream dump; @@ -380,15 +502,6 @@ DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) { lt_log_print_dump(torrent::LOG_TORRENT_DEBUG, dump_str.c_str(), dump_str.size(), "Creating new download:"); } -void -DownloadFactory::receive_failed(const std::string& msg) { - // Add message to log. - if (m_printLog) - m_manager->push_log_std(msg + ": \"" + m_uri + "\""); - - m_slot_finished(); -} - void DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorrent) { auto cached_seconds = torrent::this_thread::cached_seconds().count(); @@ -412,7 +525,7 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre rtorrent->insert_preserve_copy("timestamp.finished", (int64_t)0); rtorrent->insert_preserve_copy("tied_to_file", ""); - rtorrent->insert_key("loaded_file", m_isFile ? m_uri : std::string()); + rtorrent->insert_key("loaded_file", m_is_file ? m_uri : std::string()); if (rtorrent->has_key_value("priority")) rpc::call_command("d.priority.set", rtorrent->get_key_value("priority") % 4, rpc::make_target(download)); @@ -444,4 +557,18 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre rtorrent->insert_preserve_copy("choke_heuristics.down.seed", std::string()); } +void +DownloadFactory::object_from_stream() { + m_object = std::make_unique(); + + *m_stream >> *m_object; + + if (!m_stream->good() || !m_object->is_map()) { + if (m_print_log) + lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, stream is not a valid torrent."); + + throw torrent::input_error("Invalid torrent data"); + } +} + } diff --git a/src/core/download_factory.h b/src/core/download_factory.h index 435b09d8..31b5b3e1 100644 --- a/src/core/download_factory.h +++ b/src/core/download_factory.h @@ -24,15 +24,19 @@ public: typedef std::vector command_list_type; // Do not destroy this object while it is in a HttpQueue. - DownloadFactory(Manager* m); + DownloadFactory(Manager* m, bool trusted); ~DownloadFactory(); // Calling of receive_load() is delayed so you can change whatever // you want without fear of the slots being triggered as you call // load() or commit(). - void load(const std::string& uri); + void load_trusted(const std::string& uri); + void load_untrusted(const std::string& uri); + void load_raw_data(const std::string& input); - void commit(); + + void commit_trusted(); + void commit_untrusted(); command_list_type& commands() { return m_commands; } torrent::Object::map_type& variables() { return m_variables; } @@ -43,16 +47,21 @@ public: bool get_start() const { return m_start; } void set_start(bool v) { m_start = v; } - bool get_init_load() const { return m_initLoad; } - void set_init_load(bool v) { m_initLoad = v; } + bool get_init_load() const { return m_init_load; } + void set_init_load(bool v) { m_init_load = v; } - bool print_log() const { return m_printLog; } - void set_print_log(bool v) { m_printLog = v; } + bool print_log() const { return m_print_log; } + void set_print_log(bool v) { m_print_log = v; } void slot_finished(slot_void s) { m_slot_finished = s; } private: - void receive_load(); + void process_load_network_uri(); + void process_load_magnet_uri(); + void process_load_file_uri(); + + void receive_load_trusted(); + void receive_load_untrusted(); void receive_loaded(); void receive_commit(); void receive_success(); @@ -62,19 +71,23 @@ private: void initialize_rtorrent(Download* download, torrent::Object* rtorrent); - Manager* m_manager; - std::shared_ptr m_stream; - torrent::Object* m_object{}; + void object_from_stream(); + Manager* m_manager; + + std::shared_ptr m_stream; + std::unique_ptr m_object{}; + + bool m_trusted{}; bool m_commited{}; bool m_loaded{}; std::string m_uri; bool m_session{}; bool m_start{}; - bool m_printLog{true}; - bool m_isFile{}; - bool m_initLoad{}; + bool m_print_log{true}; + bool m_is_file{}; + bool m_init_load{}; command_list_type m_commands; torrent::Object::map_type m_variables; diff --git a/src/core/download_list.cc b/src/core/download_list.cc index b67f590a..ca751f23 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -101,49 +101,17 @@ DownloadList::find_hex_ptr(const char* hash) { } Download* -DownloadList::create(torrent::Object* obj, uint32_t tracker_key, bool printLog) { +DownloadList::create(std::unique_ptr obj, uint32_t tracker_key, bool printLog) { torrent::Download download; - try { - download = torrent::download_add(obj, tracker_key); - - } catch (torrent::local_error& e) { - if (printLog) - lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what()); - - delete obj; - - return NULL; - } - - // There's no non-critical exceptions that should be throwable by - // the ctor, so don't catch. - return new Download(download); -} - -Download* -DownloadList::create(std::istream* str, uint32_t tracker_key, bool printLog) { - torrent::Object* object = new torrent::Object; - torrent::Download download; + auto obj_ptr = obj.get(); try { - *str >> *object; - - // Don't throw input_error from here as gcc-3.3.5 produces bad - // code. - if (str->fail()) { - delete object; - - if (printLog) - lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, the input is not a valid torrent."); - - return NULL; - } - - download = torrent::download_add(object, tracker_key); + download = torrent::download_add(obj.release(), tracker_key); } catch (torrent::local_error& e) { - delete object; + // TODO: Fix download_add so it takes the unique_ptr. + delete obj_ptr; if (printLog) lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what()); diff --git a/src/core/download_list.h b/src/core/download_list.h index c79bbbae..099b63ad 100644 --- a/src/core/download_list.h +++ b/src/core/download_list.h @@ -52,8 +52,7 @@ public: Download* find_hex_ptr(const char* hash); // Might move this to DownloadFactory. - Download* create(std::istream* str, uint32_t tracker_key, bool printLog); - Download* create(torrent::Object* obj, uint32_t tracker_key, bool printLog); + Download* create(std::unique_ptr obj, uint32_t tracker_key, bool printLog); iterator insert(Download* d); diff --git a/src/core/manager.cc b/src/core/manager.cc index 2e4d5f67..607e898d 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -37,6 +37,8 @@ namespace core { +void path_expand(std::vector* paths, const std::string& pattern); + const int Manager::create_start; const int Manager::create_tied; const int Manager::create_quiet; @@ -204,13 +206,15 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li f->set_print_log(!(flags & create_quiet)); f->slot_finished([f]() { delete f; }); - if (is_data_uri(uri)) { + if (flags & create_raw_data) { + f->load_raw_data(uri); + + } else if (is_data_uri(uri)) { // Allow the use of data URIs, primarily for JSON-RPC which // doesn't have a defined mechanism for binary data f->load_raw_data(decode_data_uri(uri)); f->variables()["tied_to_file"] = (int64_t)false; - } else if (flags & create_raw_data) { - f->load_raw_data(uri); + } else { f->load(uri); } @@ -218,6 +222,26 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li f->commit(); } +void +Manager::try_create_download_expand(const std::string& uri, int flags, command_list_type commands) { + if (flags & create_raw_data) { + try_create_download(uri, flags, commands); + return; + } + + std::vector paths; + paths.reserve(256); + + path_expand(&paths, uri); + + if (!paths.empty()) + for (auto& path : paths) + try_create_download(path, flags, commands); + + else + try_create_download(uri, flags, commands); +} + void Manager::try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile) { DownloadFactory* f = new DownloadFactory(this); @@ -243,9 +267,42 @@ Manager::try_create_download_from_meta_download(torrent::Object* bencode, const f->commit(); } -utils::Directory -path_expand_transform(std::string path, const utils::directory_entry& entry) { - return path + entry.s_name; +void +Manager::try_create_download_untrusted(const std::string& uri, int flags, const command_list_type& commands) { + // TODO: Need to check if we are allowed, also rate limit. + + if (!(flags & create_raw_data) && + !is_network_uri(uri) && + !is_magnet_uri(uri) && + !is_data_uri(uri)) { + push_log_std("URI type not allowed for untrusted loads."); + return; + } + + // Adding download. + DownloadFactory* f = new DownloadFactory(this); + + f->commands().insert(f->commands().end(), commands.begin(), commands.end()); + + f->set_start(flags & create_start); + f->set_print_log(!(flags & create_quiet)); + f->slot_finished([f]() { delete f; }); + + if (flags & create_raw_data) { + f->load_raw_data_untrusted(uri); + + } else if (is_data_uri(uri)) { + // Allow the use of data URIs, primarily for JSON-RPC which + // doesn't have a defined mechanism for binary data + f->load_raw_data_untrusted(decode_data_uri(uri)); + f->variables()["tied_to_file"] = (int64_t)false; + + } else { + // f->load_untrusted(uri); + throw internal_error("Manager::try_create_download_untrusted() unimplemented."); + } + + f->commit_untrusted(); } namespace { @@ -304,6 +361,11 @@ split_iterator(const Sequence&) { } +utils::Directory +path_expand_transform(std::string path, const utils::directory_entry& entry) { + return path + entry.s_name; +} + // Move this somewhere better. void path_expand(std::vector* paths, const std::string& pattern) { @@ -360,26 +422,6 @@ manager_equal_tied(const std::string& path, Download* download) { return path == rpc::call_command_string("d.tied_to_file", rpc::make_target(download)); } -void -Manager::try_create_download_expand(const std::string& uri, int flags, command_list_type commands) { - if (flags & create_raw_data) { - try_create_download(uri, flags, commands); - return; - } - - std::vector paths; - paths.reserve(256); - - path_expand(&paths, uri); - - if (!paths.empty()) - for (auto& path : paths) - try_create_download(path, flags, commands); - - else - try_create_download(uri, flags, commands); -} - // DownloadList's hashing related functions don't actually start the // hashing, it only reacts to events. This functions checks the // hashing view and starts hashing if nessesary. diff --git a/src/core/manager.h b/src/core/manager.h index 1965f3f2..d18c12d2 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -78,6 +78,8 @@ public: void try_create_download_expand(const std::string& uri, int flags, command_list_type commands = command_list_type()); void try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile); + void try_create_download_untrusted(const std::string& uri, int flags, const command_list_type& commands); + private: void create_http(const std::string& uri); void create_final(std::istream* s);