* Fixed a regression that threw an exception for torrents with

empty directories.

* When receiving zero length pieces, remove them from the request list.

* Send the interested state before any requests as some clients,
BitTornado 0.7.14 and uTorrent 0.3.0, disconnect if a request has been
received while uninterested.

* WITH_POSIX_FALLOCATE configure macro should check against "yes", not
"no".

* The new priority queue would cause arg torrents to load before
session torrents in some cases. Fixed to perform the session torrent
tasks before loading arg torrents.

* Allow '*' wildcard in filenames when loading torrents.

* Added load, load_run, stop_tied and remove_tied settings which can
be used to scan a directory for new/removed torrents. These torrents
are tied to the lifetime of the torrent file.


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@616 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2006-01-03 21:43:01 +00:00
parent 5a8a402745
commit 4431fd1652
20 changed files with 519 additions and 58 deletions
+1
View File
@@ -10,6 +10,7 @@ EXTRA_DIST= \
rak/functional_fun.h \
rak/priority_queue.h \
rak/priority_queue_default.h \
rak/regex.h
rak/string_manip.h \
rak/timer.h \
rak/unordered_vector.h \
+1 -1
View File
@@ -1,4 +1,4 @@
AC_INIT(rtorrent, 0.4.1, jaris@ifi.uio.no)
AC_INIT(rtorrent, 0.4.2, jaris@ifi.uio.no)
AM_INIT_AUTOMAKE
AM_CONFIG_HEADER(config.h)
+11
View File
@@ -85,6 +85,17 @@ struct priority_compare {
typedef std::equal_to<priority_item*> priority_equal;
typedef priority_queue<priority_item*, priority_compare, priority_equal> priority_queue_default;
inline void
priority_queue_perform(priority_queue_default* queue, timer t) {
while (!queue->empty() && queue->top()->time() <= t) {
priority_item* v = queue->top();
queue->pop();
v->clear_time();
v->call();
}
}
inline void
priority_queue_insert(priority_queue_default* queue, priority_item* item, timer t) {
if (t == timer())
+220
View File
@@ -0,0 +1,220 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// 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.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// This is a hacked up whole string pattern matching. Replace with
// TR1's regex when that becomes widely available. It is intended for
// small strings.
#ifndef RAK_REGEX_H
#define RAK_REGEX_H
#include <sys/types.h>
#include <functional>
#include <string>
#include <list>
namespace rak {
class regex : public std::unary_function<std::string, bool> {
public:
regex() {}
regex(const std::string& p) : m_pattern(p) {}
const std::string& pattern() const { return m_pattern; }
bool operator () (const std::string& p) const;
private:
std::string m_pattern;
};
// This isn't optimized, or very clean. A simple hack that should work.
bool
regex::operator () (const std::string& text) const {
if (m_pattern.empty() ||
text.empty() ||
(m_pattern[0] != '*' && m_pattern[0] != text[0]))
return false;
// Replace with unordered_vector?
std::list<unsigned int> paths;
paths.push_front(0);
for (std::string::const_iterator itrText = ++text.begin(), lastText = text.end(); itrText != lastText; ++itrText) {
for (std::list<unsigned int>::iterator itrPaths = paths.begin(), lastPaths = paths.end(); itrPaths != lastPaths; ) {
unsigned int next = *itrPaths + 1;
if (m_pattern[*itrPaths] != '*')
itrPaths = paths.erase(itrPaths);
else
itrPaths++;
// When we reach the end of 'm_pattern', we don't have a whole
// match of 'text'.
if (next == m_pattern.size())
continue;
// Push to the back so that '*' will match zero length strings.
if (m_pattern[next] == '*')
paths.push_back(next);
if (m_pattern[next] == *itrText)
paths.push_front(next);
}
if (paths.empty())
return false;
}
return std::find(paths.begin(), paths.end(), m_pattern.size() - 1) != paths.end();
}
}
#endif
// rak - Rakshasa's toolbox
// Copyright (C) 2005, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// 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.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// This is a hacked up whole string pattern matching. Replace with
// TR1's regex when that becomes widely available. It is intended for
// small strings.
#ifndef RAK_REGEX_H
#define RAK_REGEX_H
#include <sys/types.h>
#include <functional>
#include <string>
#include <list>
namespace rak {
class regex : public std::unary_function<std::string, bool> {
public:
regex() {}
regex(const std::string& p) : m_pattern(p) {}
const std::string& pattern() const { return m_pattern; }
bool operator () (const std::string& p) const;
private:
std::string m_pattern;
};
// This isn't optimized, or very clean. A simple hack that should work.
bool
regex::operator () (const std::string& text) const {
if (m_pattern.empty() ||
text.empty() ||
(m_pattern[0] != '*' && m_pattern[0] != text[0]))
return false;
// Replace with unordered_vector?
std::list<unsigned int> paths;
paths.push_front(0);
for (std::string::const_iterator itrText = ++text.begin(), lastText = text.end(); itrText != lastText; ++itrText) {
for (std::list<unsigned int>::iterator itrPaths = paths.begin(), lastPaths = paths.end(); itrPaths != lastPaths; ) {
unsigned int next = *itrPaths + 1;
if (m_pattern[*itrPaths] != '*')
itrPaths = paths.erase(itrPaths);
else
itrPaths++;
// When we reach the end of 'm_pattern', we don't have a whole
// match of 'text'.
if (next == m_pattern.size())
continue;
// Push to the back so that '*' will match zero length strings.
if (m_pattern[next] == '*')
paths.push_back(next);
if (m_pattern[next] == *itrText)
paths.push_front(next);
}
if (paths.empty())
return false;
}
return std::find(paths.begin(), paths.end(), m_pattern.size() - 1) != paths.end();
}
}
#endif
+53
View File
@@ -37,6 +37,7 @@
#ifndef RAK_STRING_MANIP_H
#define RAK_STRING_MANIP_H
#include <algorithm>
#include <cctype>
namespace rak {
@@ -74,6 +75,58 @@ Sequence trim(const Sequence& seq) {
return trim_begin(trim_end(seq));
}
// Consider rewritting such that m_seq is replaced by first/last.
template <typename Sequence>
class split_iterator_t {
public:
typedef typename Sequence::const_iterator const_iterator;
typedef typename Sequence::value_type value_type;
split_iterator_t() {}
split_iterator_t(const Sequence& seq, value_type delim) :
m_seq(&seq),
m_delim(delim),
m_pos(seq.begin()),
m_next(std::find(seq.begin(), seq.end(), delim)) {
}
Sequence operator * () { return Sequence(m_pos, m_next); }
split_iterator_t& operator ++ () {
m_pos = m_next;
if (m_pos == m_seq->end())
return *this;
m_pos++;
m_next = std::find(m_pos, m_seq->end(), m_delim);
return *this;
}
bool operator == (const split_iterator_t& itr) const { return m_pos == m_seq->end(); }
bool operator != (const split_iterator_t& itr) const { return m_pos != m_seq->end(); }
private:
const Sequence* m_seq;
value_type m_delim;
const_iterator m_pos;
const_iterator m_next;
};
template <typename Sequence>
inline split_iterator_t<Sequence>
split_iterator(const Sequence& seq, typename Sequence::value_type delim) {
return split_iterator_t<Sequence>(seq, delim);
}
template <typename Sequence>
inline split_iterator_t<Sequence>
split_iterator(const Sequence& seq) {
return split_iterator_t<Sequence>();
}
}
#endif
+2 -2
View File
@@ -174,9 +174,9 @@ AC_DEFUN([TORRENT_CHECK_POSIX_FALLOCATE], [
AC_DEFUN([TORRENT_WITH_POSIX_FALLOCATE], [
AC_ARG_WITH(posix-fallocate,
[ --with-fallocate Check for posix_fallocate],
[ --with-posix-fallocate Check for and use posix_fallocate to allocate files.],
[
if test "$withval" = "no"; then
if test "$withval" = "yes"; then
TORRENT_CHECK_POSIX_FALLOCATE
fi
])
+5
View File
@@ -73,6 +73,9 @@ public:
void set_connection_leech(const std::string& name) { m_connectionLeech = string_to_connection_type(name); }
void set_connection_seed(const std::string& name) { m_connectionSeed = string_to_connection_type(name); }
const std::string& tied_to_file() const { return m_tiedToFile; }
void set_tied_to_file(const std::string& str) { m_tiedToFile = str; }
void enable_udp_trackers(bool state);
// Helper functions for calling functions in torrent::Download
@@ -104,6 +107,8 @@ private:
ConnType m_connectionLeech;
ConnType m_connectionSeed;
std::string m_tiedToFile;
sigc::connection m_connTrackerSucceded;
sigc::connection m_connTrackerFailed;
sigc::connection m_connStorageError;
+31 -11
View File
@@ -40,6 +40,7 @@
#include <sstream>
#include <stdexcept>
#include <torrent/bencode.h>
#include <torrent/exceptions.h>
#include "curl_get.h"
#include "http_queue.h"
@@ -58,7 +59,9 @@ DownloadFactory::DownloadFactory(const std::string& uri, Manager* m) :
m_uri(uri),
m_session(false),
m_start(false) {
m_start(false),
m_printLog(true),
m_tiedToFile(false) {
m_taskLoad.set_slot(rak::mem_fn(this, &DownloadFactory::receive_load));
m_taskCommit.set_slot(rak::mem_fn(this, &DownloadFactory::receive_commit));
@@ -85,7 +88,7 @@ DownloadFactory::commit() {
void
DownloadFactory::receive_load() {
if (m_stream)
throw std::logic_error("DownloadFactory::load() called on an object with m_stream != NULL");
throw torrent::client_error("DownloadFactory::load() called on an object with m_stream != NULL");
if (std::strncmp(m_uri.c_str(), "http://", 7) == 0) {
// Http handling here.
@@ -95,6 +98,8 @@ DownloadFactory::receive_load() {
(*itr)->signal_done().slots().push_front(sigc::mem_fun(*this, &DownloadFactory::receive_loaded));
(*itr)->signal_failed().slots().push_front(sigc::mem_fun(*this, &DownloadFactory::receive_failed));
m_tiedToFile = false;
} else {
m_stream = new std::fstream(m_uri.c_str(), std::ios::in);
@@ -124,9 +129,9 @@ DownloadFactory::receive_commit() {
void
DownloadFactory::receive_success() {
if (m_stream == NULL)
throw std::logic_error("DownloadFactory::receive_success() called on an object with m_stream == NULL");
throw torrent::client_error("DownloadFactory::receive_success() called on an object with m_stream == NULL");
Manager::DListItr itr = m_manager->insert(m_stream);
Manager::DListItr itr = m_manager->insert(m_stream, m_printLog);
if (itr == m_manager->get_download_list().end()) {
// core::Manager should already have added the error message to
@@ -135,15 +140,28 @@ DownloadFactory::receive_success() {
return;
}
torrent::Bencode& bencode = (*itr)->get_bencode();
if (m_session) {
torrent::Bencode& bencode = (*itr)->get_bencode();
// Hmm... this safe?
if (bencode.get_key("rtorrent").get_key("state").as_string() == "started")
m_manager->start(*itr);
m_manager->start(*itr, m_printLog);
if (bencode.get_key("rtorrent").has_key("tied") &&
bencode.get_key("rtorrent").get_key("tied").is_string())
(*itr)->set_tied_to_file(bencode.get_key("rtorrent").get_key("tied").as_string());
} else {
// Remove the settings if this isn't a session torrent.
//bencode.erase_key("rtorrent");
if (m_tiedToFile) {
(*itr)->set_tied_to_file(m_uri);
bencode.get_key("rtorrent").insert_key("tied", m_uri);
}
if (m_start)
m_manager->start(*itr);
m_manager->start(*itr, m_printLog);
m_manager->get_download_store().save(*itr);
}
@@ -154,11 +172,13 @@ DownloadFactory::receive_success() {
void
DownloadFactory::receive_failed(const std::string& msg) {
if (m_stream == NULL)
throw std::logic_error("DownloadFactory::receive_success() called on an object with m_stream == NULL");
throw torrent::client_error("DownloadFactory::receive_success() called on an object with m_stream == NULL");
// Add message to log.
m_manager->get_log_important().push_front(msg + ": \"" + m_uri + "\"");
m_manager->get_log_complete().push_front(msg + ": \"" + m_uri + "\"");
if (m_printLog) {
m_manager->get_log_important().push_front(msg + ": \"" + m_uri + "\"");
m_manager->get_log_complete().push_front(msg + ": \"" + m_uri + "\"");
}
m_slotFinished();
}
+12
View File
@@ -34,6 +34,10 @@
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// The DownloadFactory class assures that loading torrents can be done
// anywhere in the code by queueing the task. The user may change
// settings while, or even after, the torrent is loading.
#ifndef RTORRENT_CORE_DOWNLOAD_FACTORY_H
#define RTORRENT_CORE_DOWNLOAD_FACTORY_H
@@ -67,6 +71,12 @@ public:
bool get_start() const { return m_start; }
void set_start(bool v) { m_start = v; }
bool print_log() const { return m_printLog; }
void set_print_log(bool v) { m_printLog = v; }
bool tied_to_file() const { return m_tiedToFile; }
void set_tied_to_file(bool v) { m_tiedToFile = v; }
void slot_finished(Slot s) { m_slotFinished = s; }
private:
@@ -85,6 +95,8 @@ private:
std::string m_uri;
bool m_session;
bool m_start;
bool m_printLog;
bool m_tiedToFile;
Slot m_slotFinished;
rak::priority_item m_taskLoad;
+3
View File
@@ -46,6 +46,9 @@ namespace core {
void
Log::push_front(const std::string& msg) {
if (!m_enabled)
return;
Base::push_front(Type(cachedTime, msg));
if (size() > 50)
+9
View File
@@ -64,6 +64,13 @@ public:
using Base::empty;
using Base::size;
Log() : m_enabled(true) {}
bool is_enabled() const { return m_enabled; }
void enable() { m_enabled = true; }
void disable() { m_enabled = false; }
void push_front(const std::string& msg);
iterator find_older(rak::timer t);
@@ -71,6 +78,8 @@ public:
Signal& signal_update() { return m_signalUpdate; }
private:
bool m_enabled;
Signal m_signalUpdate;
};
+83 -6
View File
@@ -43,6 +43,8 @@
#include <istream>
#include <unistd.h>
#include <sys/select.h>
#include <rak/regex.h>
#include <rak/string_manip.h>
#include <sigc++/bind.h>
#include <sigc++/hide.h>
#include <torrent/bencode.h>
@@ -50,6 +52,7 @@
#include "curl_get.h"
#include "download.h"
#include "download_factory.h"
#include "manager.h"
#include "poll_manager_epoll.h"
#include "poll_manager_select.h"
@@ -149,13 +152,15 @@ Manager::shutdown(bool force) {
}
Manager::DListItr
Manager::insert(std::istream* s) {
Manager::insert(std::istream* s, bool printLog) {
try {
return m_downloadList.insert(s);
} catch (torrent::local_error& e) {
m_logImportant.push_front(e.what());
m_logComplete.push_front(e.what());
if (printLog) {
m_logImportant.push_front(e.what());
m_logComplete.push_front(e.what());
}
return m_downloadList.end();
}
@@ -173,7 +178,7 @@ Manager::erase(DListItr itr) {
}
void
Manager::start(Download* d) {
Manager::start(Download* d, bool printLog) {
try {
d->get_bencode().get_key("rtorrent").get_key("state") = "started";
@@ -190,8 +195,10 @@ Manager::start(Download* d) {
m_hashQueue.insert(d, sigc::bind(sigc::mem_fun(m_downloadList, &DownloadList::start), d));
} catch (torrent::local_error& e) {
m_logImportant.push_front(e.what());
m_logComplete.push_front(e.what());
if (printLog) {
m_logImportant.push_front(e.what());
m_logComplete.push_front(e.what());
}
}
}
@@ -302,4 +309,74 @@ Manager::receive_download_done_hash_checked(Download* d) {
d->get_download().tracker_send_completed();
}
void
Manager::try_create_download(const std::string& uri, bool start, bool printLog, bool tied) {
// Adding download.
DownloadFactory* f = new DownloadFactory(uri, this);
f->set_start(start);
f->set_print_log(printLog);
f->set_tied_to_file(tied);
f->slot_finished(sigc::bind(sigc::ptr_fun(&rak::call_delete_func<core::DownloadFactory>), f));
f->load();
f->commit();
}
// Move this somewhere better.
void
path_expand(std::vector<std::string>* paths, const std::string& pattern) {
std::vector<utils::Directory> currentCache;
std::vector<utils::Directory> nextCache;
rak::split_iterator_t<std::string> first = rak::split_iterator(pattern, '/');
rak::split_iterator_t<std::string> last = rak::split_iterator(pattern);
if (first == last)
return;
// Check for initial '/' that indicates the root.
if ((*first).empty()) {
currentCache.push_back(utils::Directory("/"));
++first;
} else {
currentCache.push_back(utils::Directory("./"));
}
// Might be an idea to use depth-first search instead.
for (; first != last; ++first) {
rak::regex r(*first);
if (r.pattern().empty())
continue;
for (std::vector<utils::Directory>::iterator itr = currentCache.begin(); itr != currentCache.end(); ++itr) {
itr->update(false);
itr->erase(std::remove_if(itr->begin(), itr->end(), std::not1(r)), itr->end());
std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), std::bind1st(std::plus<std::string>(), itr->get_path() + "/"));
}
currentCache.clear();
currentCache.swap(nextCache);
}
std::transform(currentCache.begin(), currentCache.end(), std::back_inserter(*paths), std::mem_fun_ref(&utils::Directory::get_path));
}
void
Manager::try_create_download_expand(const std::string& uri, bool start, bool printLog, bool tied) {
std::vector<std::string> paths;
paths.reserve(32);
path_expand(&paths, uri);
if (!paths.empty())
for (std::vector<std::string>::iterator itr = paths.begin(); itr != paths.end(); ++itr)
try_create_download(*itr, start, printLog, tied);
else
try_create_download(uri, start, printLog, tied);
}
}
+6 -2
View File
@@ -83,16 +83,20 @@ public:
void shutdown(bool force);
DListItr insert(std::istream* s);
DListItr insert(std::istream* s, bool printLog = true);
DListItr erase(DListItr itr);
void start(Download* d);
void start(Download* d, bool printLog = true);
void stop(Download* d);
void check_hash(Download* d);
void push_log(const std::string& msg) { m_logImportant.push_front(msg); m_logComplete.push_front(msg); }
// Temporary, find a better place for this.
void try_create_download(const std::string& uri, bool start, bool printLog = true, bool tied = false);
void try_create_download_expand(const std::string& uri, bool start, bool printLog = true, bool tied = false);
private:
void create_http(const std::string& uri);
void create_final(std::istream* s);
+2
View File
@@ -83,6 +83,8 @@ WindowPeerInfo::redraw() {
core::Download::connection_type_to_string(m_download->get_connection_current()),
core::Download::connection_type_to_string(m_download->get_connection_leech()),
core::Download::connection_type_to_string(m_download->get_connection_seed()));
m_canvas->print(0, y++, "Tied to file: %s",
m_download->tied_to_file().c_str());
y++;
+14 -24
View File
@@ -143,6 +143,11 @@ initialize_option_handler(Control* c, OptionHandler* optionHandler) {
optionHandler->insert("connection_leech", new OptionHandlerString(c, &apply_connection_leech));
optionHandler->insert("connection_seed", new OptionHandlerString(c, &apply_connection_seed));
optionHandler->insert("load", new OptionHandlerString(c, &apply_load));
optionHandler->insert("load_run", new OptionHandlerString(c, &apply_load_run));
optionHandler->insert("stop_untied", new OptionHandlerString(c, &apply_stop_untied));
optionHandler->insert("remove_untied", new OptionHandlerString(c, &apply_remove_untied));
optionHandler->insert("session", new OptionHandlerString(c, &apply_session_directory));
optionHandler->insert("encoding_list", new OptionHandlerString(c, &apply_encoding_list));
optionHandler->insert("tracker_dump", new OptionHandlerString(c, &apply_tracker_dump));
@@ -220,15 +225,15 @@ main(int argc, char** argv) {
// Just to make sure we did all the stuff on the queue before
// loading any torrents.
while (!taskScheduler.empty() && taskScheduler.top()->time() <= cachedTime) {
rak::priority_item* v = taskScheduler.top();
taskScheduler.pop();
v->clear_time();
v->call();
}
//
// Remove this?
//rak::priority_queue_perform(&taskScheduler, cachedTime);
// Load session torrents and perform scheduled tasks to ensure
// session torrents are loaded before arg torrents.
load_session_torrents(&control);
rak::priority_queue_perform(&taskScheduler, cachedTime);
load_arg_torrents(&control, argv + firstArg, argv + argc);
control.display()->adjust_layout();
@@ -237,22 +242,7 @@ main(int argc, char** argv) {
countTicks++;
cachedTime = rak::timer::current();
// std::list<rak::priority_item*> workQueue;
// std::copy(rak::queue_popper(taskScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), cachedTime)),
// rak::queue_popper(taskScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), rak::timer())),
// std::back_inserter(workQueue));
// std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::clear_time));
// std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::call));
while (!taskScheduler.empty() && taskScheduler.top()->time() <= cachedTime) {
rak::priority_item* v = taskScheduler.top();
taskScheduler.pop();
v->clear_time();
v->call();
}
rak::priority_queue_perform(&taskScheduler, cachedTime);
// This needs to be called every second or so. Currently done by
// the throttle task in libtorrent.
@@ -268,7 +258,7 @@ main(int argc, char** argv) {
} catch (torrent::base_error& e) {
display::Canvas::cleanup();
std::cout << "Caught exception from libtorrent: " << e.what() << std::endl;
std::cout << "Caught exception: " << e.what() << std::endl;
return -1;
} catch (std::exception& e) {
+56
View File
@@ -37,17 +37,21 @@
#include "config.h"
#include <cstdio>
#include <functional>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <rak/functional.h>
#include <rak/string_manip.h>
#include <torrent/bencode.h>
#include <torrent/exceptions.h>
#include <torrent/torrent.h>
#include "core/manager.h"
#include "ui/root.h"
#include "utils/directory.h"
#include "utils/file_stat.h"
#include "control.h"
#include "option_handler_rules.h"
@@ -218,6 +222,58 @@ apply_http_proxy(Control* m, const std::string& arg) {
m->core()->get_poll_manager()->get_http_stack()->set_http_proxy(arg);
}
void
apply_load(Control* m, const std::string& arg) {
m->core()->try_create_download_expand(arg, false, false, true);
}
void
apply_load_run(Control* m, const std::string& arg) {
m->core()->try_create_download_expand(arg, true, false, true);
}
void
apply_stop_untied(Control* m, const std::string& arg) {
core::Manager::DListItr itr = m->core()->get_download_list().begin();
while ((itr = std::find_if(itr, m->core()->get_download_list().end(),
rak::on(std::mem_fun(&core::Download::tied_to_file), std::not1(std::mem_fun_ref(&std::string::empty)))))
!= m->core()->get_download_list().end()) {
utils::FileStat fs;
if (fs.update((*itr)->tied_to_file().c_str()) != 0) {
(*itr)->set_tied_to_file(std::string());
(*itr)->get_bencode().get_key("rtorrent").erase_key("tied");
m->core()->stop(*itr);
}
++itr;
}
}
void
apply_remove_untied(Control* m, const std::string& arg) {
core::Manager::DListItr itr = m->core()->get_download_list().begin();
while ((itr = std::find_if(itr, m->core()->get_download_list().end(),
rak::on(std::mem_fun(&core::Download::tied_to_file), std::not1(std::mem_fun_ref(&std::string::empty)))))
!= m->core()->get_download_list().end()) {
utils::FileStat fs;
if (fs.update((*itr)->tied_to_file().c_str()) != 0) {
(*itr)->set_tied_to_file(std::string());
(*itr)->get_bencode().get_key("rtorrent").erase_key("tied");
m->core()->stop(*itr);
itr = m->core()->erase(itr);
} else {
++itr;
}
}
}
void
apply_session_directory(Control* m, const std::string& arg) {
m->core()->get_download_store().use(arg);
+5
View File
@@ -77,6 +77,11 @@ void apply_check_hash(Control* m, const std::string& arg);
void apply_http_proxy(Control* m, const std::string& arg);
void apply_load(Control* m, const std::string& arg);
void apply_load_run(Control* m, const std::string& arg);
void apply_stop_untied(Control* m, const std::string& arg);
void apply_remove_untied(Control* m, const std::string& arg);
void apply_session_directory(Control* m, const std::string& arg);
void apply_encoding_list(Control* m, const std::string& arg);
+2 -9
View File
@@ -38,12 +38,12 @@
#include <stdexcept>
#include <rak/functional.h>
#include <rak/string_manip.h>
#include <sigc++/bind.h>
#include <sigc++/hide.h>
#include <torrent/torrent.h>
#include "core/download.h"
#include "core/download_factory.h"
#include "core/manager.h"
#include "input/bindings.h"
@@ -265,16 +265,9 @@ DownloadList::receive_exit_input(bool useDefault) {
m_control->ui()->window_statusbar()->set_active(true);
m_windowTextInput->set_active(false);
m_control->input()->set_text_input();
// Adding download.
core::DownloadFactory* f = new core::DownloadFactory(m_windowTextInput->get_input()->str(), m_control->core());
f->set_start(useDefault);
f->slot_finished(sigc::bind(sigc::ptr_fun(&rak::call_delete_func<core::DownloadFactory>), f));
f->load();
f->commit();
m_control->core()->try_create_download_expand(m_windowTextInput->get_input()->str(), useDefault);
// Clean up.
m_windowTextInput->get_input()->clear();
+2 -2
View File
@@ -57,7 +57,7 @@ Directory::is_valid() const {
}
bool
Directory::update() {
Directory::update(bool hideDot) {
if (m_path.empty())
throw std::logic_error("Directory::update() tried to open an empty path");
@@ -71,7 +71,7 @@ Directory::update() {
while ((ent = readdir(d)) != NULL) {
std::string de(ent->d_name);
if (!de.empty() && de[0] != '.')
if (!de.empty() && (!hideDot || de[0] != '.'))
Base::push_back(ent->d_name);
}
+1 -1
View File
@@ -66,7 +66,7 @@ public:
bool is_valid() const;
bool update();
bool update(bool hideDot = true);
const std::string& get_path() { return m_path; }