source: trunk/src/halTorrent.cpp @ 431

Revision 431, 56.9 KB checked in by Eoin, 12 years ago (diff)

Torrent creation soooooo close.

Line 
1
2//         Copyright Eóin O'Callaghan 2006 - 2008.
3// Distributed under the Boost Software License, Version 1.0.
4//    (See accompanying file LICENSE_1_0.txt or copy at
5//          http://www.boost.org/LICENSE_1_0.txt)
6
7#include "stdAfx.hpp"
8
9#define TORRENT_MAX_ALERT_TYPES 20
10
11#include <libtorrent/file.hpp>
12#include <libtorrent/hasher.hpp>
13#include <libtorrent/storage.hpp>
14#include <libtorrent/file_pool.hpp>
15#include <libtorrent/alert_types.hpp>
16#include <libtorrent/entry.hpp>
17#include <libtorrent/bencode.hpp>
18#include <libtorrent/session.hpp>
19#include <libtorrent/ip_filter.hpp>
20#include <libtorrent/torrent_handle.hpp>
21#include <libtorrent/peer_connection.hpp>
22#include <libtorrent/extensions/metadata_transfer.hpp>
23#include <libtorrent/extensions/ut_pex.hpp>
24
25#include "global/wtl_app.hpp"
26#include "global/string_conv.hpp"
27#include "global/ini_adapter.hpp"
28
29#include "halTorrent.hpp"
30#include "halEvent.hpp"
31#include "halSignaler.hpp"
32
33#define foreach BOOST_FOREACH
34
35namespace boost {
36namespace serialization {
37
38#define IP_SAVE  3
39
40template<class Archive, class address_type>
41void save(Archive& ar, const address_type& ip, const unsigned int version)
42{       
43#if IP_SAVE == 1
44        typename address_type::bytes_type bytes = ip.to_bytes();       
45        for (typename address_type::bytes_type::iterator i=bytes.begin(); i != bytes.end(); ++i)
46                ar & BOOST_SERIALIZATION_NVP(*i);
47#elif IP_SAVE == 2
48        string dotted = ip.to_string(); 
49        ar & BOOST_SERIALIZATION_NVP(dotted);
50#elif IP_SAVE == 3
51        unsigned long addr = ip.to_ulong();     
52        ar & BOOST_SERIALIZATION_NVP(addr);
53#endif
54}
55
56template<class Archive, class address_type>
57void load(Archive& ar, address_type& ip, const unsigned int version)
58{       
59#if IP_SAVE == 1
60        typename address_type::bytes_type bytes;       
61        for (typename address_type::bytes_type::iterator i=bytes.begin(); i != bytes.end(); ++i)
62                ar & BOOST_SERIALIZATION_NVP(*i);       
63        ip = address_type(bytes);
64#elif IP_SAVE == 2     
65        string dotted;
66        ar & BOOST_SERIALIZATION_NVP(dotted);   
67        ip = address_type::from_string(dotted);
68#elif IP_SAVE == 3
69        unsigned long addr;
70        ar & BOOST_SERIALIZATION_NVP(addr);     
71        ip = address_type(addr);
72#endif
73}
74
75template<class Archive, class address_type>
76void serialize(Archive& ar, libtorrent::ip_range<address_type>& addr, const unsigned int version)
77{       
78        ar & BOOST_SERIALIZATION_NVP(addr.first);
79        ar & BOOST_SERIALIZATION_NVP(addr.last);
80        addr.flags = libtorrent::ip_filter::blocked;
81}
82
83template<class Archive>
84void serialize(Archive& ar, hal::tracker_detail& tracker, const unsigned int version)
85{       
86        ar & BOOST_SERIALIZATION_NVP(tracker.url);
87        ar & BOOST_SERIALIZATION_NVP(tracker.tier);
88}
89
90} // namespace serialization
91} // namespace boost
92
93BOOST_SERIALIZATION_SPLIT_FREE(asio::ip::address_v4)
94BOOST_SERIALIZATION_SPLIT_FREE(asio::ip::address_v6)
95
96namespace libtorrent
97{
98template<class Addr>
99bool operator==(const libtorrent::ip_range<Addr>& lhs, const int flags)
100{
101        return (lhs.flags == flags);
102}
103
104std::ostream& operator<<(std::ostream& os, libtorrent::ip_range<asio::ip::address_v4>& ip)
105{
106        os << ip.first.to_ulong();
107        os << ip.last.to_ulong();
108       
109        return os;
110}
111
112} // namespace libtorrent
113
114#include "halTorrentInternal.hpp"
115
116namespace hal
117{
118        libtorrent::session* TorrentInternal::the_session_ = 0;
119        wpath_t TorrentInternal::workingDir_;
120}
121
122namespace hal
123{
124
125namespace lbt = libtorrent;
126namespace fs = boost::filesystem;
127namespace pt = boost::posix_time;
128
129typedef std::wstring wstring_t;
130typedef std::string string_t;
131
132typedef boost::wformat wformat_t;
133typedef boost::format format_t;
134
135typedef boost::filesystem::wpath wpath_t;
136typedef boost::filesystem::path path_t;
137
138using boost::serialization::make_nvp;
139using boost::shared_ptr;
140using boost::bind;
141
142BitTorrent& bittorrent()
143{
144        static BitTorrent t;
145        return t;
146}
147
148bool operator!=(const lbt::dht_settings& lhs, const lbt::dht_settings& rhs)
149{
150        return lhs.max_peers_reply != rhs.max_peers_reply ||
151                   lhs.search_branching != rhs.search_branching ||
152                   lhs.service_port != rhs.service_port ||
153           lhs.max_fail_count != rhs.max_fail_count;
154}
155
156template<typename Addr>
157void write_range(fs::ofstream& ofs, const lbt::ip_range<Addr>& range)
158{ 
159        const typename Addr::bytes_type first = range.first.to_bytes();
160        const typename Addr::bytes_type last = range.last.to_bytes();
161        ofs.write((char*)first.elems, first.size());
162        ofs.write((char*)last.elems, last.size());
163}
164
165template<typename Addr>
166void write_vec_range(fs::ofstream& ofs, const std::vector<lbt::ip_range<Addr> >& vec)
167{ 
168        ofs << vec.size();
169       
170        for (typename std::vector<lbt::ip_range<Addr> >::const_iterator i=vec.begin(); 
171                i != vec.end(); ++i)
172        {
173                write_range(ofs, *i);
174        }
175}
176
177template<typename Addr>
178void read_range_to_filter(fs::ifstream& ifs, lbt::ip_filter& ip_filter)
179{ 
180        typename Addr::bytes_type first;
181        typename Addr::bytes_type last;
182        ifs.read((char*)first.elems, first.size());
183        ifs.read((char*)last.elems, last.size());       
184       
185        ip_filter.add_rule(Addr(first), Addr(last),
186                lbt::ip_filter::blocked);
187}
188
189static Event::eventLevel lbtAlertToHalEvent(lbt::alert::severity_t severity)
190{
191        switch (severity)
192        {
193        case lbt::alert::debug:
194                return Event::debug;
195       
196        case lbt::alert::info:
197                return Event::info;
198       
199        case lbt::alert::warning:
200                return Event::warning;
201       
202        case lbt::alert::critical:
203        case lbt::alert::fatal:
204                return Event::critical;
205       
206        default:
207                return Event::none;
208        }
209}
210
211const PeerDetails& TorrentDetail::peerDetails() const
212{
213        if (!peerDetailsFilled_)
214        {
215                bittorrent().getAllPeerDetails(hal::to_utf8(name_), peerDetails_);
216                peerDetailsFilled_ = true;
217        }
218       
219        return peerDetails_;
220}
221
222const FileDetails& TorrentDetail::fileDetails() const
223{
224        if (!fileDetailsFilled_)
225        {
226                bittorrent().getAllFileDetails(hal::to_utf8(name_), fileDetails_);
227                fileDetailsFilled_ = true;
228        }
229       
230        return fileDetails_;
231}
232
233bool nameLess(const TorrentDetail_ptr& left, const TorrentDetail_ptr& right)
234{
235        return left->state() < right->state();
236}
237
238void TorrentDetails::sort(
239        boost::function<bool (const TorrentDetail_ptr&, const TorrentDetail_ptr&)> fn) const
240{
241        std::stable_sort(torrents_.begin(), torrents_.end(), fn);
242}
243
244
245web_seed_or_dht_node_detail::web_seed_or_dht_node_detail(std::wstring u) : 
246        url(u), 
247        port(-1), 
248        type(hal::app().res_wstr(HAL_INT_NEWT_ADD_PEERS_WEB)) 
249{}
250
251web_seed_or_dht_node_detail::web_seed_or_dht_node_detail(std::wstring u, int p) : 
252        url(u), 
253        port(p), 
254        type(hal::app().res_wstr(HAL_INT_NEWT_ADD_PEERS_DHT)) 
255{}
256
257class BitTorrent_impl
258{
259        friend class BitTorrent;
260       
261public:
262       
263        ~BitTorrent_impl()
264        {
265                keepChecking_ = false;
266               
267                saveTorrentData();
268               
269                try
270                {
271               
272                if (ip_filter_changed_)
273                {       
274                        fs::ofstream ofs(workingDirectory/L"IPFilter.bin", std::ios::binary);
275//                      boost::archive::binary_oarchive oba(ofs);
276                       
277                        lbt::ip_filter::filter_tuple_t vectors = ip_filter_.export_filter();   
278                       
279                        std::vector<lbt::ip_range<asio::ip::address_v4> > v4(vectors.get<0>());
280                        std::vector<lbt::ip_range<asio::ip::address_v6> > v6(vectors.get<1>());
281                       
282                        v4.erase(std::remove(v4.begin(), v4.end(), 0), v4.end());
283                        v6.erase(std::remove(v6.begin(), v6.end(), 0), v6.end());
284
285                        write_vec_range(ofs, v4);
286//                      write_vec_range(ofs, v6);
287                }       
288                }
289                catch(std::exception& e)
290                {
291                        hal::event().post(boost::shared_ptr<hal::EventDetail>(
292                                new hal::EventStdException(Event::critical, e, L"~BitTorrent_impl"))); 
293                }
294        }
295
296        struct 
297        {
298                signaler<> successful_listen;
299                signaler<> torrent_finished;
300        } 
301        signals;
302               
303        void alertHandler()
304        {
305                if (keepChecking_)
306                {
307               
308                std::auto_ptr<lbt::alert> p_alert = theSession.pop_alert();
309               
310                class AlertHandler
311                {
312                public:
313                AlertHandler(BitTorrent_impl& bit_impl) :
314                        bit_impl_(bit_impl)
315                {}
316               
317                void operator()(lbt::torrent_finished_alert const& a) const
318                {
319                        event().post(shared_ptr<EventDetail>(
320                                new EventMsg((wformat_t(hal::app().res_wstr(LBT_EVENT_TORRENT_FINISHED)) 
321                                                % get(a.handle)->name()), 
322                                        Event::info, a.timestamp())));
323                       
324                        get(a.handle)->finished();     
325                }
326               
327                void operator()(lbt::torrent_paused_alert const& a) const
328                {
329                        event().post(shared_ptr<EventDetail>(
330                                new EventMsg((wformat_t(hal::app().res_wstr(LBT_EVENT_TORRENT_PAUSED)) 
331                                                % get(a.handle)->name()), 
332                                        Event::info, a.timestamp())));
333
334                        get(a.handle)->signals().torrent_paused();
335                }
336               
337                void operator()(lbt::peer_error_alert const& a) const
338                {
339                        event().post(shared_ptr<EventDetail>(
340                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
341                                        wformat_t(hal::app().res_wstr(HAL_PEER_ALERT))
342                                                % hal::from_utf8_safe(a.msg())
343                                                % hal::from_utf8_safe(a.ip.address().to_string()))
344                        )       );                             
345                }
346                       
347                void operator()(lbt::peer_ban_alert const& a) const
348                {
349                        event().post(shared_ptr<EventDetail>(
350                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
351                                        wformat_t(hal::app().res_wstr(HAL_PEER_BAN_ALERT))
352                                                % get(a.handle)->name()
353                                                % hal::from_utf8_safe(a.ip.address().to_string()))
354                        )       );                             
355                }
356                       
357                void operator()(lbt::hash_failed_alert const& a) const
358                {
359                        event().post(shared_ptr<EventDetail>(
360                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
361                                        wformat_t(hal::app().res_wstr(HAL_HASH_FAIL_ALERT))
362                                                % get(a.handle)->name()
363                                                % a.piece_index)
364                        )       );                             
365                }
366                       
367                void operator()(lbt::url_seed_alert const& a) const
368                {
369                        event().post(shared_ptr<EventDetail>(
370                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
371                                        wformat_t(hal::app().res_wstr(HAL_URL_SEED_ALERT))
372                                                % get(a.handle)->name()
373                                                % hal::from_utf8_safe(a.url)
374                                                % hal::from_utf8_safe(a.msg()))
375                        )       );                             
376                }
377               
378                void operator()(lbt::tracker_warning_alert const& a) const
379                {
380                        event().post(shared_ptr<EventDetail>(
381                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
382                                        wformat_t(hal::app().res_wstr(HAL_TRACKER_WARNING_ALERT))
383                                                % get(a.handle)->name()
384                                                % hal::from_utf8_safe(a.msg()))
385                        )       );                             
386                }
387               
388                void operator()(lbt::tracker_announce_alert const& a) const
389                {
390                        event().post(shared_ptr<EventDetail>(
391                                new EventMsg((wformat_t(hal::app().res_wstr(HAL_TRACKER_ANNOUNCE_ALERT)) 
392                                                % get(a.handle)->name()), 
393                                        Event::info, a.timestamp())));
394                }
395               
396                void operator()(lbt::tracker_alert const& a) const
397                {
398                        event().post(shared_ptr<EventDetail>(
399                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
400                                        wformat_t(hal::app().res_wstr(HAL_TRACKER_ALERT))
401                                                % get(a.handle)->name()
402                                                % hal::from_utf8_safe(a.msg())
403                                                % a.times_in_row
404                                                % a.status_code)
405                        )       );                             
406                }
407               
408                void operator()(lbt::tracker_reply_alert const& a) const
409                {
410                        event().post(shared_ptr<EventDetail>(
411                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
412                                        wformat_t(hal::app().res_wstr(HAL_TRACKER_REPLY_ALERT))
413                                                % get(a.handle)->name()
414                                                % hal::from_utf8_safe(a.msg())
415                                                % a.num_peers)
416                        )       );                             
417                }
418               
419                void operator()(lbt::fastresume_rejected_alert const& a) const
420                {
421                        event().post(shared_ptr<EventDetail>(
422                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
423                                        wformat_t(hal::app().res_wstr(HAL_FAST_RESUME_ALERT))
424                                                % get(a.handle)->name()
425                                                % hal::from_utf8_safe(a.msg()))
426                        )       );                             
427                }
428               
429                void operator()(lbt::piece_finished_alert const& a) const
430                {
431                        event().post(shared_ptr<EventDetail>(
432                                new EventGeneral(Event::debug, a.timestamp(),
433                                        wformat_t(hal::app().res_wstr(HAL_PIECE_FINISHED_ALERT))
434                                                % get(a.handle)->name()
435                                                % a.piece_index)
436                        )       );                             
437                }
438               
439                void operator()(lbt::block_finished_alert const& a) const
440                {
441                        event().post(shared_ptr<EventDetail>(
442                                new EventGeneral(Event::debug, a.timestamp(),
443                                        wformat_t(hal::app().res_wstr(HAL_BLOCK_FINISHED_ALERT))
444                                                % get(a.handle)->name()
445                                                % a.block_index
446                                                % a.piece_index)
447                        )       );                             
448                }
449               
450                void operator()(lbt::block_downloading_alert const& a) const
451                {
452                        event().post(shared_ptr<EventDetail>(
453                                new EventGeneral(Event::debug, a.timestamp(),
454                                        wformat_t(hal::app().res_wstr(HAL_BLOCK_DOWNLOADING_ALERT))
455                                                % get(a.handle)->name()
456                                                % a.block_index
457                                                % a.piece_index)
458                        )       );                             
459                }
460               
461                void operator()(lbt::listen_failed_alert const& a) const
462                {
463                        if (a.endpoint.address().is_v6())
464                        {       
465                                event().post(shared_ptr<EventDetail>(
466                                        new EventGeneral(Event::info, a.timestamp(),
467                                                hal::app().res_wstr(HAL_LISTEN_V6_FAILED_ALERT))
468                                )       );             
469                        }
470                        else
471                        {
472                                event().post(shared_ptr<EventDetail>(
473                                        new EventGeneral(Event::info, a.timestamp(),
474                                                wformat_t(hal::app().res_wstr(HAL_LISTEN_FAILED_ALERT))
475                                                        % hal::from_utf8_safe(a.msg()))
476                                )       );
477                        }
478                }
479               
480                void operator()(lbt::listen_succeeded_alert const& a) const
481                {
482                        event().post(shared_ptr<EventDetail>(
483                                new EventGeneral(Event::info, a.timestamp(),
484                                        wformat_t(hal::app().res_wstr(HAL_LISTEN_SUCCEEDED_ALERT))
485                                                % hal::from_utf8_safe(a.msg()))
486                        )       );     
487
488                        bit_impl_.signals.successful_listen();
489                }
490               
491                void operator()(lbt::peer_blocked_alert const& a) const
492                {
493                        event().post(shared_ptr<EventDetail>(
494                                new EventGeneral(Event::debug, a.timestamp(),
495                                        wformat_t(hal::app().res_wstr(HAL_IPFILTER_ALERT))
496                                                % hal::from_utf8_safe(a.ip.to_string())
497                                                % hal::from_utf8_safe(a.msg()))
498                        )       );                             
499                }
500               
501                void operator()(lbt::alert const& a) const
502                {
503                        event().post(shared_ptr<EventDetail>(
504                                        new EventLibtorrent(lbtAlertToHalEvent(a.severity()), 
505                                                a.timestamp(), Event::unclassified, hal::from_utf8_safe(a.msg()))));           
506                }
507               
508                private:
509                        BitTorrent_impl& bit_impl_;
510                       
511                        TorrentInternal_ptr get(lbt::torrent_handle h) const 
512                        { 
513                                return bit_impl_.theTorrents.get(from_utf8_safe(h.get_torrent_info().name())); 
514                        }
515               
516                } handler(*this);
517               
518                while (p_alert.get())
519                {       
520                        try
521                        {
522                       
523                        lbt::handle_alert<
524                                lbt::torrent_finished_alert,
525                                lbt::torrent_paused_alert,
526                                lbt::peer_error_alert,
527                                lbt::peer_ban_alert,
528                                lbt::hash_failed_alert,
529                                lbt::url_seed_alert,
530                                lbt::tracker_alert,
531                                lbt::tracker_warning_alert,
532                                lbt::tracker_announce_alert,
533                                lbt::tracker_reply_alert,
534                                lbt::fastresume_rejected_alert,
535                                lbt::piece_finished_alert,
536                                lbt::block_finished_alert,
537                                lbt::block_downloading_alert,
538                                lbt::listen_failed_alert,
539                                lbt::listen_succeeded_alert,
540                                lbt::peer_blocked_alert,
541                                lbt::alert
542                        >::handle_alert(p_alert, handler);                     
543                       
544                        }
545                        catch(lbt::unhandled_alert&)
546                        {
547                                handler(*p_alert);
548                        }
549                        catch(std::exception& e)
550                        {
551                                // These are logged as debug because they are rarely important to act on!
552                                event().post(shared_ptr<EventDetail>(\
553                                        new EventStdException(Event::debug, e, L"alertHandler")));
554                        }
555                       
556                        p_alert = theSession.pop_alert();
557                }
558               
559                timer_.expires_from_now(boost::posix_time::seconds(5));
560                timer_.async_wait(bind(&BitTorrent_impl::alertHandler, this));
561                }
562        }
563       
564        void saveTorrentData()
565        {       try
566                {
567               
568                theTorrents.save();
569                bittorrentIni.save_data();
570                       
571                if (dht_on_) 
572                {       
573                        halencode(workingDirectory/L"DHTState.bin", theSession.dht_state());
574                }
575               
576                }               
577                catch(std::exception& e)
578                {
579                        event().post(shared_ptr<EventDetail>(\
580                                new EventStdException(Event::critical, e, L"saveTorrentData")));
581                }
582        }
583       
584        int defTorrentMaxConn() { return defTorrentMaxConn_; }
585        int defTorrentMaxUpload() { return defTorrentMaxUpload_; }
586        float defTorrentDownload() { return defTorrentDownload_; }
587        float defTorrentUpload() { return defTorrentUpload_; }
588       
589        const wpath_t workingDir() { return workingDirectory; };
590
591private:
592        BitTorrent_impl() :
593                theSession(lbt::fingerprint(HALITE_FINGERPRINT)),
594                timer_(io_),
595                keepChecking_(false),
596                bittorrentIni(L"BitTorrent.xml"),
597                theTorrents(bittorrentIni),
598                defTorrentMaxConn_(-1),
599                defTorrentMaxUpload_(-1),
600                defTorrentDownload_(-1),
601                defTorrentUpload_(-1),
602                ip_filter_on_(false),
603                ip_filter_loaded_(false),
604                ip_filter_changed_(false),
605                ip_filter_count_(0),
606                dht_on_(false)
607        {
608                TorrentInternal::the_session_ = &theSession;
609                TorrentInternal::workingDir_ = workingDir();
610               
611                theSession.set_severity_level(lbt::alert::debug);               
612                theSession.add_extension(&lbt::create_metadata_plugin);
613                theSession.add_extension(&lbt::create_ut_pex_plugin);
614                theSession.set_max_half_open_connections(10);
615               
616                hal::event().post(shared_ptr<hal::EventDetail>(
617                        new hal::EventMsg(L"Loading BitTorrent.xml.", hal::Event::info)));             
618                bittorrentIni.load_data();
619                hal::event().post(shared_ptr<hal::EventDetail>(
620                        new hal::EventMsg(L"Loading torrent parameters.", hal::Event::info))); 
621                theTorrents.load();
622                hal::event().post(shared_ptr<hal::EventDetail>(
623                        new hal::EventMsg(L"Loading done!", hal::Event::info)));
624               
625                try
626                {                                               
627                if (fs::exists(workingDirectory/L"Torrents.xml"))
628                {
629                        {
630                        fs::wifstream ifs(workingDirectory/L"Torrents.xml");
631               
632                        event().post(shared_ptr<EventDetail>(new EventMsg(L"Loading old Torrents.xml")));
633               
634                        TorrentMap torrents;
635                        boost::archive::xml_wiarchive ia(ifs); 
636                        ia >> make_nvp("torrents", torrents);
637                       
638                        theTorrents = torrents;
639                        }
640                       
641                        event().post(shared_ptr<EventDetail>(new EventMsg(
642                                wformat_t(L"Total %1%.") % theTorrents.size())));                               
643                       
644                        fs::rename(workingDirectory/L"Torrents.xml", workingDirectory/L"Torrents.xml.safe.to.delete");
645                }                       
646                }
647                catch(const std::exception& e)
648                {
649                        event().post(shared_ptr<EventDetail>(
650                                new EventStdException(Event::fatal, e, L"Loading Old Torrents.xml")));
651                }               
652                               
653                if (exists(workingDirectory/L"DHTState.bin"))
654                {
655                        try
656                        {
657                                dht_state_ = haldecode(workingDirectory/L"DHTState.bin");
658                        }               
659                        catch(const std::exception& e)
660                        {
661                                event().post(shared_ptr<EventDetail>(
662                                        new EventStdException(Event::critical, e, L"Loading DHTState.bin")));
663                        }
664                }
665               
666                {       lbt::session_settings settings = theSession.settings();
667                        settings.user_agent = string_t("Halite ") + HALITE_VERSION_STRING;
668                        theSession.set_settings(settings);
669                }
670               
671                timer_.expires_from_now(boost::posix_time::seconds(5));
672                timer_.async_wait(bind(&BitTorrent_impl::alertHandler, this));
673        }
674
675        void create_torrent(const create_torrent_params& params, fs::wpath out_file, progress_callback fn)
676        {               
677        try
678        {
679                boost::intrusive_ptr<lbt::torrent_info> t_info(new lbt::torrent_info);
680
681                int piece_size = 256 * 1024;
682                t_info->set_piece_size(piece_size);
683
684                HAL_DEV_MSG(L"Files");
685                for (file_size_pairs_t::const_iterator i = params.file_size_pairs.begin(), e = params.file_size_pairs.end();
686                                i != e; ++i)
687                {
688                        HAL_DEV_MSG(wformat_t(L"file path: %1%, size: %2%") % (*i).first % (*i).second);
689                        t_info->add_file(to_utf8((*i).first.string()), (*i).second);
690                }
691
692                lbt::file_pool f_pool;
693               
694                scoped_ptr<lbt::storage_interface> store(
695                        lbt::default_storage_constructor(t_info, to_utf8(params.root_path.string()),
696                                f_pool));
697
698                HAL_DEV_MSG(L"Trackers");
699                for (tracker_details_t::const_iterator i = params.trackers.begin(), e = params.trackers.end();
700                                i != e; ++i)
701                {
702                        HAL_DEV_MSG(wformat_t(L"URL: %1%, Tier: %2%") % (*i).url % (*i).tier);
703                        t_info->add_tracker(to_utf8((*i).url), (*i).tier);
704                }
705
706                // calculate the hash for all pieces
707                int num = t_info->num_pieces();
708                std::vector<char> piece_buf(piece_size);
709
710                for (int i = 0; i < num; ++i)
711                {
712                        store->read(&piece_buf[0], i, 0, t_info->piece_size(i));
713
714                        lbt::hasher h(&piece_buf[0], t_info->piece_size(i));
715                        t_info->set_hash(i, h.final());
716
717                        fn(100*i / num, hal::app().res_wstr(HAL_TORRENT_CREATINGTORRENT));
718
719                        HAL_DEV_MSG(wformat_t(L"%1% , %2%") % i % (100*i / num));
720                }
721
722                t_info->set_creator(to_utf8(params.creator).c_str());
723
724                // create the torrent and print it to out
725                lbt::entry e = t_info->create_torrent();
726                halencode(out_file, e);
727        }
728        catch(const std::exception& e)
729        {
730                event().post(shared_ptr<EventDetail>(
731                        new EventStdException(Event::fatal, e, L"create_torrent")));
732        }       
733        }
734       
735        std::pair<lbt::entry, lbt::entry> prepTorrent(wpath_t filename, wpath_t saveDirectory);
736        void removalThread(TorrentInternal_ptr pIT, bool wipeFiles);
737       
738        lbt::session theSession;
739        asio::io_service io_;
740        asio::deadline_timer timer_;
741        bool keepChecking_;
742       
743        static wpath_t workingDirectory;
744        ini_file bittorrentIni;
745        TorrentManager theTorrents;     
746       
747        int defTorrentMaxConn_;
748        int defTorrentMaxUpload_;
749        float defTorrentDownload_;
750        float defTorrentUpload_;
751       
752        bool ip_filter_on_;
753        bool ip_filter_loaded_;
754        bool ip_filter_changed_;
755        lbt::ip_filter ip_filter_;
756        size_t ip_filter_count_;
757       
758        void ip_filter_count();
759        void ip_filter_load(progress_callback fn);
760        void ip_filter_import(std::vector<lbt::ip_range<asio::ip::address_v4> >& v4,
761                std::vector<lbt::ip_range<asio::ip::address_v6> >& v6);
762       
763        bool dht_on_;
764        lbt::dht_settings dht_settings_;
765        lbt::entry dht_state_;
766       
767};
768
769wpath_t BitTorrent_impl::workingDirectory = hal::app().working_directory();
770
771BitTorrent::BitTorrent() :
772        pimpl(new BitTorrent_impl())
773{}
774
775#define HAL_GENERIC_TORRENT_EXCEPTION_CATCH(TORRENT, FUNCTION) \
776catch (const lbt::invalid_handle&) \
777{\
778        event().post(shared_ptr<EventDetail>( \
779                new EventInvalidTorrent(Event::critical, Event::invalidTorrent, TORRENT, std::string(FUNCTION)))); \
780}\
781catch (const invalidTorrent& t) \
782{\
783        event().post(shared_ptr<EventDetail>( \
784                new EventInvalidTorrent(Event::info, Event::invalidTorrent, t.who(), std::string(FUNCTION)))); \
785}\
786catch (const std::exception& e) \
787{\
788        event().post(shared_ptr<EventDetail>( \
789                new EventTorrentException(Event::critical, Event::torrentException, std::string(e.what()), TORRENT, std::string(FUNCTION)))); \
790}
791
792void BitTorrent::shutDownSession()
793{
794        pimpl.reset();
795}
796
797void BitTorrent::saveTorrentData()
798{
799        pimpl->saveTorrentData();
800}
801
802void BitTorrent::create_torrent(const create_torrent_params& params, fs::wpath out_file, progress_callback fn)
803{
804        pimpl->create_torrent(params, out_file, fn);
805}
806
807bool BitTorrent::listenOn(std::pair<int, int> const& range)
808{
809        try
810        {
811       
812        if (!pimpl->theSession.is_listening())
813        {
814                return pimpl->theSession.listen_on(range);
815        }
816        else
817        {
818                int port = pimpl->theSession.listen_port();
819               
820                if (port < range.first || port > range.second)
821                        return pimpl->theSession.listen_on(range);     
822                else
823                {
824                        pimpl->signals.successful_listen();
825                       
826                        return true;
827                }
828        }
829       
830        }
831        catch (const std::exception& e)
832        {
833                event().post(shared_ptr<EventDetail>(
834                        new EventStdException(Event::fatal, e, L"From BitTorrent::listenOn.")));
835
836                return false;
837        }
838        catch(...)
839        {
840                return false;
841        }
842}
843
844int BitTorrent::isListeningOn() 
845{
846        if (!pimpl->theSession.is_listening())
847                return -1;     
848        else
849                return pimpl->theSession.listen_port();
850}
851
852void BitTorrent::stopListening()
853{
854        ensureDhtOff();
855        pimpl->theSession.listen_on(std::make_pair(0, 0));
856}
857
858bool BitTorrent::ensureDhtOn()
859{
860        if (!pimpl->dht_on_)
861        {               
862                try
863                {
864                pimpl->theSession.start_dht(pimpl->dht_state_);
865                pimpl->dht_on_ = true;
866                }
867                catch(...)
868                {}
869        }
870                return pimpl->dht_on_;
871}
872
873void BitTorrent::ensureDhtOff()
874{
875        if (pimpl->dht_on_)
876        {
877                pimpl->theSession.stop_dht();           
878                pimpl->dht_on_ = false;
879        }
880}
881
882void BitTorrent::setDhtSettings(int max_peers_reply, int search_branching, 
883        int service_port, int max_fail_count)
884{
885        lbt::dht_settings settings;
886        settings.max_peers_reply = max_peers_reply;
887        settings.search_branching = search_branching;
888        settings.service_port = service_port;
889        settings.max_fail_count = max_fail_count;
890       
891        if (pimpl->dht_settings_ != settings)
892        {
893                pimpl->dht_settings_ = settings;
894                pimpl->theSession.set_dht_settings(pimpl->dht_settings_);
895        }
896}
897
898void BitTorrent::setMapping(int mapping)
899{
900        if (mapping != mappingNone)
901        {
902                if (mapping == mappingUPnP)
903                {
904                        event().post(shared_ptr<EventDetail>(new EventMsg(L"Starting UPnP mapping.")));
905                        pimpl->theSession.stop_upnp();
906                        pimpl->theSession.stop_natpmp();
907
908                        pimpl->signals.successful_listen.connect_once(bind(&lbt::session::start_upnp, &pimpl->theSession));
909                }
910                else
911                {
912                        event().post(shared_ptr<EventDetail>(new EventMsg(L"Starting NAT-PMP mapping.")));
913                        pimpl->theSession.stop_upnp();
914                        pimpl->theSession.stop_natpmp();
915
916                        pimpl->signals.successful_listen.connect_once(bind(&lbt::session::start_natpmp, &pimpl->theSession));
917                }
918        }
919        else
920        {
921                event().post(shared_ptr<EventDetail>(new EventMsg(L"No mapping.")));
922                pimpl->theSession.stop_upnp();
923                pimpl->theSession.stop_natpmp();
924        }
925}
926
927void BitTorrent::setTimeouts(int peers, int tracker)
928{
929        lbt::session_settings settings = pimpl->theSession.settings();
930        settings.peer_connect_timeout = peers;
931        settings.tracker_completion_timeout = tracker;
932
933        pimpl->theSession.set_settings(settings);
934
935        event().post(shared_ptr<EventDetail>(new EventMsg(
936                wformat_t(L"Set Timeouts, peer %1%, tracker %2%") % peers % tracker)));
937}
938
939void BitTorrent::setSessionLimits(int maxConn, int maxUpload)
940{               
941        pimpl->theSession.set_max_uploads(maxUpload);
942        pimpl->theSession.set_max_connections(maxConn);
943       
944        event().post(shared_ptr<EventDetail>(new EventMsg(
945                wformat_t(L"Set connections totals %1% and uploads %2%.") 
946                        % maxConn % maxUpload)));
947}
948
949void BitTorrent::setSessionSpeed(float download, float upload)
950{
951        int down = (download > 0) ? static_cast<int>(download*1024) : -1;
952        pimpl->theSession.set_download_rate_limit(down);
953        int up = (upload > 0) ? static_cast<int>(upload*1024) : -1;
954        pimpl->theSession.set_upload_rate_limit(up);
955       
956        event().post(shared_ptr<EventDetail>(new EventMsg(
957                wformat_t(L"Set session rates at download %1% and upload %2%.") 
958                        % pimpl->theSession.download_rate_limit() % pimpl->theSession.upload_rate_limit())));
959}
960
961void BitTorrent_impl::ip_filter_count()
962{
963        lbt::ip_filter::filter_tuple_t vectors = ip_filter_.export_filter();
964       
965        vectors.get<0>().erase(std::remove(vectors.get<0>().begin(), vectors.get<0>().end(), 0),
966                vectors.get<0>().end());
967        vectors.get<1>().erase(std::remove(vectors.get<1>().begin(), vectors.get<1>().end(), 0),
968                vectors.get<1>().end());
969        ip_filter_count_ = vectors.get<0>().size() + vectors.get<1>().size();
970}
971
972void BitTorrent_impl::ip_filter_load(progress_callback fn)
973{
974        fs::ifstream ifs(workingDirectory/L"IPFilter.bin", std::ios::binary);
975        if (ifs)
976        {
977                size_t v4_size;
978                ifs >> v4_size;
979               
980                size_t total = v4_size/100;
981                size_t previous = 0;
982               
983                for(unsigned i=0; i<v4_size; ++i)
984                {
985                        if (i-previous > total)
986                        {
987                                previous = i;
988                                if (fn) if (fn(size_t(i/total),L"")) break;
989                        }
990                       
991                        read_range_to_filter<asio::ip::address_v4>(ifs, ip_filter_);
992                }
993        }       
994}
995
996void  BitTorrent_impl::ip_filter_import(std::vector<lbt::ip_range<asio::ip::address_v4> >& v4,
997        std::vector<lbt::ip_range<asio::ip::address_v6> >& v6)
998{
999        for(std::vector<lbt::ip_range<asio::ip::address_v4> >::iterator i=v4.begin();
1000                i != v4.end(); ++i)
1001        {
1002                ip_filter_.add_rule(i->first, i->last, lbt::ip_filter::blocked);
1003        }
1004/*      for(std::vector<lbt::ip_range<asio::ip::address_v6> >::iterator i=v6.begin();
1005                i != v6.end(); ++i)
1006        {
1007                ip_filter_.add_rule(i->first, i->last, lbt::ip_filter::blocked);
1008        }
1009*/     
1010        /* Note here we do not set ip_filter_changed_ */
1011}
1012
1013void BitTorrent::ensureIpFilterOn(progress_callback fn)
1014{
1015        try
1016        {
1017       
1018        if (!pimpl->ip_filter_loaded_)
1019        {
1020                pimpl->ip_filter_load(fn);
1021                pimpl->ip_filter_loaded_ = true;
1022        }
1023       
1024        if (!pimpl->ip_filter_on_)
1025        {
1026                pimpl->theSession.set_ip_filter(pimpl->ip_filter_);
1027                pimpl->ip_filter_on_ = true;
1028                pimpl->ip_filter_count();
1029        }
1030       
1031        }
1032        catch(const std::exception& e)
1033        {               
1034                hal::event().post(boost::shared_ptr<hal::EventDetail>(
1035                        new hal::EventStdException(Event::critical, e, L"ensureIpFilterOn"))); 
1036
1037                ensureIpFilterOff();
1038        }
1039
1040        event().post(shared_ptr<EventDetail>(new EventMsg(L"IP filters on."))); 
1041}
1042
1043void BitTorrent::ensureIpFilterOff()
1044{
1045        pimpl->theSession.set_ip_filter(lbt::ip_filter());
1046        pimpl->ip_filter_on_ = false;
1047       
1048        event().post(shared_ptr<EventDetail>(new EventMsg(L"IP filters off.")));       
1049}
1050
1051#ifndef TORRENT_DISABLE_ENCRYPTION     
1052void BitTorrent::ensurePeOn(int enc_level, int in_enc_policy, int out_enc_policy, bool prefer_rc4)
1053{
1054        lbt::pe_settings pe;
1055       
1056        switch (enc_level)
1057        {
1058                case 0:
1059                        pe.allowed_enc_level = lbt::pe_settings::plaintext;
1060                        break;
1061                case 1:
1062                        pe.allowed_enc_level = lbt::pe_settings::rc4;
1063                        break;
1064                case 2:
1065                        pe.allowed_enc_level = lbt::pe_settings::both;
1066                        break;
1067                default:
1068                        pe.allowed_enc_level = lbt::pe_settings::both;
1069                       
1070                        hal::event().post(shared_ptr<hal::EventDetail>(
1071                                new hal::EventGeneral(hal::Event::warning, hal::Event::unclassified, 
1072                                        (wformat_t(hal::app().res_wstr(HAL_INCORRECT_ENCODING_LEVEL)) % enc_level).str())));
1073        }
1074
1075        switch (in_enc_policy)
1076        {
1077                case 0:
1078                        pe.in_enc_policy = lbt::pe_settings::forced;
1079                        break;
1080                case 1:
1081                        pe.in_enc_policy = lbt::pe_settings::enabled;
1082                        break;
1083                case 2:
1084                        pe.in_enc_policy = lbt::pe_settings::disabled;
1085                        break;
1086                default:
1087                        pe.in_enc_policy = lbt::pe_settings::enabled;
1088                       
1089                        hal::event().post(shared_ptr<hal::EventDetail>(
1090                                new hal::EventGeneral(hal::Event::warning, hal::Event::unclassified, 
1091                                        (wformat_t(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % in_enc_policy).str())));
1092        }
1093
1094        switch (out_enc_policy)
1095        {
1096                case 0:
1097                        pe.out_enc_policy = lbt::pe_settings::forced;
1098                        break;
1099                case 1:
1100                        pe.out_enc_policy = lbt::pe_settings::enabled;
1101                        break;
1102                case 2:
1103                        pe.out_enc_policy = lbt::pe_settings::disabled;
1104                        break;
1105                default:
1106                        pe.out_enc_policy = lbt::pe_settings::enabled;
1107                       
1108                        hal::event().post(shared_ptr<hal::EventDetail>(
1109                                new hal::EventGeneral(hal::Event::warning, hal::Event::unclassified, 
1110                                        (wformat_t(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % in_enc_policy).str())));
1111        }
1112       
1113        pe.prefer_rc4 = prefer_rc4;
1114       
1115        try
1116        {
1117       
1118        pimpl->theSession.set_pe_settings(pe);
1119       
1120        }
1121        catch(const std::exception& e)
1122        {
1123                hal::event().post(boost::shared_ptr<hal::EventDetail>(
1124                                new hal::EventStdException(Event::critical, e, L"ensurePeOn"))); 
1125                               
1126                ensurePeOff();         
1127        }
1128       
1129        event().post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption on.")));
1130}
1131
1132void BitTorrent::ensurePeOff()
1133{
1134        lbt::pe_settings pe;
1135        pe.out_enc_policy = lbt::pe_settings::disabled;
1136        pe.in_enc_policy = lbt::pe_settings::disabled;
1137       
1138        pe.allowed_enc_level = lbt::pe_settings::both;
1139        pe.prefer_rc4 = true;
1140       
1141        pimpl->theSession.set_pe_settings(pe);
1142
1143        event().post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption off.")));
1144}
1145#endif
1146
1147void BitTorrent::ip_v4_filter_block(asio::ip::address_v4 first, asio::ip::address_v4 last)
1148{
1149        pimpl->ip_filter_.add_rule(first, last, lbt::ip_filter::blocked);
1150        pimpl->ip_filter_count();
1151        pimpl->ip_filter_changed_ = true;
1152}
1153
1154void BitTorrent::ip_v6_filter_block(asio::ip::address_v6 first, asio::ip::address_v6 last)
1155{
1156        pimpl->ip_filter_.add_rule(first, last, lbt::ip_filter::blocked);
1157        pimpl->ip_filter_count();
1158        pimpl->ip_filter_changed_ = true;
1159}
1160
1161size_t BitTorrent::ip_filter_size()
1162{
1163        return pimpl->ip_filter_count_;
1164}
1165
1166void BitTorrent::clearIpFilter()
1167{
1168        pimpl->ip_filter_ = lbt::ip_filter();
1169        pimpl->theSession.set_ip_filter(lbt::ip_filter());     
1170        pimpl->ip_filter_changed_ = true;
1171        pimpl->ip_filter_count();
1172}
1173
1174void BitTorrent::ip_filter_import_dat(boost::filesystem::path file, progress_callback fn, bool octalFix)
1175{
1176        try
1177        {
1178
1179        fs::ifstream ifs(file); 
1180        if (ifs)
1181        {
1182                boost::uintmax_t total = fs::file_size(file)/100;
1183                boost::uintmax_t progress = 0;
1184                boost::uintmax_t previous = 0;
1185               
1186                boost::regex reg("\\s*(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s*-\\s*(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s*.*");
1187                boost::regex ip_reg("0*(\\d*)\\.0*(\\d*)\\.0*(\\d*)\\.0*(\\d*)");
1188                boost::smatch m;
1189               
1190                string_t ip_address_line;               
1191                while (!std::getline(ifs, ip_address_line).eof())
1192                {               
1193                        progress += (ip_address_line.length() + 2);
1194                        if (progress-previous > total)
1195                        {
1196                                previous = progress;
1197                                if (fn)
1198                                {
1199                                        if (fn(size_t(progress/total), hal::app().res_wstr(HAL_TORRENT_IMPORT_FILTERS))) 
1200                                                break;
1201                                }
1202                        }
1203                       
1204                        if (boost::regex_match(ip_address_line, m, reg))
1205                        {
1206                                string_t first = m[1];
1207                                string_t last = m[2];
1208                               
1209                                if (octalFix)
1210                                {
1211                                        if (boost::regex_match(first, m, ip_reg))
1212                                        {
1213                                                first = ((m.length(1) != 0) ? m[1] : string_t("0")) + "." +
1214                                                                ((m.length(2) != 0) ? m[2] : string_t("0")) + "." +
1215                                                                ((m.length(3) != 0) ? m[3] : string_t("0")) + "." +
1216                                                                ((m.length(4) != 0) ? m[4] : string_t("0"));
1217                                        }                                       
1218                                        if (boost::regex_match(last, m, ip_reg))
1219                                        {
1220                                                last = ((m.length(1) != 0) ? m[1] : string_t("0")) + "." +
1221                                                           ((m.length(2) != 0) ? m[2] : string_t("0")) + "." +
1222                                                           ((m.length(3) != 0) ? m[3] : string_t("0")) + "." +
1223                                                           ((m.length(4) != 0) ? m[4] : string_t("0"));
1224                                        }
1225                                }
1226                               
1227                                try
1228                                {                       
1229                                pimpl->ip_filter_.add_rule(asio::ip::address_v4::from_string(first),
1230                                        asio::ip::address_v4::from_string(last), lbt::ip_filter::blocked);     
1231                                }
1232                                catch(...)
1233                                {
1234                                        hal::event().post(shared_ptr<hal::EventDetail>(
1235                                                new hal::EventDebug(hal::Event::info, 
1236                                                        from_utf8((format_t("Invalid IP range: %1%-%2%.") % first % last).str()))));
1237                                }
1238                        }
1239                }
1240        }
1241       
1242        pimpl->ip_filter_changed_ = true;
1243        pimpl->ip_filter_count();
1244       
1245        }
1246        catch(const std::exception& e)
1247        {
1248                event().post(shared_ptr<EventDetail>(
1249                        new EventStdException(Event::critical, e, L"ip_filter_import_dat")));
1250        }
1251}
1252
1253const SessionDetail BitTorrent::getSessionDetails()
1254{
1255        SessionDetail details;
1256       
1257        details.port = pimpl->theSession.is_listening() ? pimpl->theSession.listen_port() : -1;
1258       
1259        lbt::session_status status = pimpl->theSession.status();
1260       
1261        details.speed = std::pair<double, double>(status.download_rate, status.upload_rate);
1262       
1263        details.dht_on = pimpl->dht_on_;
1264        details.dht_nodes = status.dht_nodes;
1265        details.dht_torrents = status.dht_torrents;
1266       
1267        details.ip_filter_on = pimpl->ip_filter_on_;
1268        details.ip_ranges_filtered = pimpl->ip_filter_count_;
1269       
1270        return details;
1271}
1272
1273void BitTorrent::setSessionHalfOpenLimit(int halfConn)
1274{
1275        pimpl->theSession.set_max_half_open_connections(halfConn);
1276
1277        event().post(shared_ptr<EventDetail>(new EventMsg(
1278                wformat_t(L"Set half-open connections limit to %1%.") % pimpl->theSession.max_half_open_connections())));
1279}
1280
1281void BitTorrent::setTorrentDefaults(int maxConn, int maxUpload, float download, float upload)
1282{
1283        pimpl->defTorrentMaxConn_ = maxConn;
1284        pimpl->defTorrentMaxUpload_ = maxUpload;
1285
1286        event().post(shared_ptr<EventDetail>(new EventMsg(
1287                wformat_t(L"Set torrent connections total %1% and uploads %2%.") % maxConn % maxUpload)));
1288
1289        pimpl->defTorrentDownload_ = download;
1290        pimpl->defTorrentUpload_ = upload;
1291
1292        event().post(shared_ptr<EventDetail>(new EventMsg(
1293                wformat_t(L"Set torrent default rates at %1$.2fkb/s down and %2$.2fkb/s upload.") % download % upload)));
1294}
1295
1296std::pair<lbt::entry, lbt::entry> BitTorrent_impl::prepTorrent(wpath_t filename, wpath_t saveDirectory)
1297{
1298        lbt::entry metadata = haldecode(filename);
1299        lbt::torrent_info info(metadata);
1300       
1301        wstring_t torrentName = hal::from_utf8_safe(info.name());
1302        if (!boost::find_last(torrentName, L".torrent")) 
1303                torrentName += L".torrent";
1304       
1305        wpath_t torrentFilename = torrentName;
1306        const wpath_t resumeFile = workingDirectory/L"resume"/torrentFilename.leaf();
1307       
1308        //  vvv Handle old naming style!
1309        const wpath_t oldResumeFile = workingDirectory/L"resume"/filename.leaf();
1310       
1311        if (filename.leaf() != torrentFilename.leaf() && exists(oldResumeFile))
1312                fs::rename(oldResumeFile, resumeFile);
1313        //  ^^^ Handle old naming style!       
1314       
1315        lbt::entry resumeData; 
1316       
1317        if (fs::exists(resumeFile)) 
1318        {
1319                try 
1320                {
1321                        resumeData = haldecode(resumeFile);
1322                }
1323                catch(std::exception &e) 
1324                {               
1325                        hal::event().post(boost::shared_ptr<hal::EventDetail>(
1326                                new hal::EventStdException(Event::critical, e, L"prepTorrent, Resume"))); 
1327       
1328                        fs::remove(resumeFile);
1329                }
1330        }
1331
1332        if (!fs::exists(workingDirectory/L"torrents"))
1333                fs::create_directory(workingDirectory/L"torrents");
1334
1335        if (!fs::exists(workingDirectory/L"torrents"/torrentFilename.leaf()))
1336                fs::copy_file(filename.string(), workingDirectory/L"torrents"/torrentFilename.leaf());
1337
1338        if (!fs::exists(saveDirectory))
1339                fs::create_directory(saveDirectory);
1340       
1341        return std::make_pair(metadata, resumeData);
1342}
1343
1344void BitTorrent::addTorrent(wpath_t file, wpath_t saveDirectory, bool startStopped, bool compactStorage, 
1345                boost::filesystem::wpath moveToDirectory, bool useMoveTo) 
1346{
1347        try 
1348        {       
1349        TorrentInternal_ptr TIp;
1350
1351        std::pair<std::string, std::string> names = extract_names(file);
1352        wstring_t xml_name = from_utf8(names.first) + L".xml";
1353
1354        if (fs::exists(file.branch_path()/xml_name))
1355        {
1356                torrent_standalone tsa;
1357                tsa.load_standalone(file.branch_path()/xml_name);
1358
1359                TIp = tsa.torrent;
1360                TIp->prepare(file);
1361        }
1362        else
1363        {
1364                if (useMoveTo)
1365                        TIp.reset(new TorrentInternal(file, saveDirectory, compactStorage, moveToDirectory));           
1366                else
1367                        TIp.reset(new TorrentInternal(file, saveDirectory, compactStorage));
1368
1369                TIp->setTransferSpeed(bittorrent().defTorrentDownload(), bittorrent().defTorrentUpload());
1370                TIp->setConnectionLimit(bittorrent().defTorrentMaxConn(), bittorrent().defTorrentMaxUpload());
1371        }
1372       
1373        std::pair<TorrentManager::torrentByName::iterator, bool> p =
1374                pimpl->theTorrents.insert(TIp);
1375       
1376        if (p.second)
1377        {
1378                TorrentInternal_ptr me = pimpl->theTorrents.get(TIp->name());           
1379               
1380                if (!startStopped) 
1381                        me->addToSession();
1382                else
1383                        me->set_state_stopped();
1384        }
1385       
1386        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(to_utf8(file.string()), "addTorrent")
1387}
1388
1389void add_files(lbt::torrent_info& t, fs::path const& p, fs::path const& l)
1390{
1391/*      fs::path f(p / l);
1392        if (fs::is_directory(f))
1393        {
1394                for (fs::directory_iterator i(f), end; i != end; ++i)
1395                        add_files(t, p, l / i->leaf());
1396        }
1397        else
1398        {
1399        //      std::cerr << "adding \"" << l.string() << "\"\n";
1400                lbt::file fi(f, lbt::file::in);
1401                fi.seek(0, lbt::file::end);
1402                libtorrent::size_type size = fi.tell();
1403                t.add_file(l, size);
1404        }
1405*/
1406}
1407
1408void BitTorrent::newTorrent(wpath_t filename, wpath_t files)
1409{
1410/*      try
1411        {
1412       
1413        libtorrent::torrent_info t;
1414        path full_path = pimpl->workingDirectory/"incoming"/files.leaf();
1415       
1416        ofstream out(filename, std::ios_base::binary);
1417       
1418        int piece_size = 256 * 1024;
1419        char const* creator_str = "Halite v0.3 (libtorrent v0.11)";
1420
1421        add_files(t, full_path.branch_path(), full_path.leaf());
1422        t.set_piece_size(piece_size);
1423
1424        lbt::storage st(t, full_path.branch_path());
1425        t.add_tracker("http://www.nitcom.com.au/announce.php");
1426        t.set_priv(false);
1427        t.add_node(make_pair("192.168.11.12", 6881));
1428
1429        // calculate the hash for all pieces
1430        int num = t.num_pieces();
1431        std::vector<char> buf(piece_size);
1432        for (int i = 0; i < num; ++i)
1433        {
1434                        st.read(&buf[0], i, 0, t.piece_size(i));
1435                        libtorrent::hasher h(&buf[0], t.piece_size(i));
1436                        t.set_hash(i, h.final());
1437                //      std::cerr << (i+1) << "/" << num << "\r";
1438        }
1439
1440        t.set_creator(creator_str);
1441
1442        // create the torrent and print it to out
1443        lbt::entry e = t.create_torrent();
1444        lbt::bencode(std::ostream_iterator<char>(out), e);
1445        }
1446        catch (std::exception& e)
1447        {
1448                ::MessageBoxA(0, e.what(), "Create Torrent exception.", 0);
1449        }
1450*/
1451}
1452
1453const TorrentDetails& BitTorrent::torrentDetails()
1454{
1455        return torrentDetails_;
1456}
1457
1458const TorrentDetails& BitTorrent::updateTorrentDetails(const wstring_t& focused, const std::set<wstring_t>& selected)
1459{
1460        try {
1461       
1462        mutex_t::scoped_lock l(torrentDetails_.mutex_); 
1463       
1464        torrentDetails_.clearAll(l);   
1465        torrentDetails_.torrents_.reserve(pimpl->theTorrents.size());
1466       
1467        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); i != e; ++i)
1468        {
1469                wstring_t utf8Name = (*i).torrent->name();
1470                TorrentDetail_ptr pT = (*i).torrent->getTorrentDetail_ptr();
1471               
1472                if (selected.find(utf8Name) != selected.end())
1473                {
1474                        torrentDetails_.selectedTorrents_.push_back(pT);
1475                }
1476               
1477                if (focused == utf8Name)
1478                        torrentDetails_.selectedTorrent_ = pT;
1479               
1480                torrentDetails_.torrentMap_[(*i).torrent->name()] = pT;
1481                torrentDetails_.torrents_.push_back(pT);
1482        }
1483       
1484        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "updateTorrentDetails")
1485       
1486        return torrentDetails_;
1487}
1488
1489void BitTorrent::resumeAll()
1490{
1491        try {
1492               
1493        event().post(shared_ptr<EventDetail>(new EventMsg(L"Resuming torrent.")));
1494       
1495        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); i != e;)
1496        {
1497                wpath_t file = wpath_t(pimpl->workingDirectory)/L"torrents"/(*i).torrent->filename();
1498               
1499                if (exists(file))
1500                {               
1501                        try 
1502                        {
1503                               
1504                        (*i).torrent->prepare(file);   
1505
1506                        switch ((*i).torrent->state())
1507                        {
1508                                case TorrentDetail::torrent_stopped:
1509                                        break;
1510                                case TorrentDetail::torrent_paused:
1511                                        (*i).torrent->addToSession(true);
1512                                        break;
1513                                case TorrentDetail::torrent_active:
1514                                        (*i).torrent->addToSession(false);
1515                                        break;
1516                                default:
1517                                        assert(false);
1518                        };
1519                       
1520                        ++i;
1521                       
1522                        }
1523                        catch(const lbt::duplicate_torrent&)
1524                        {
1525                                hal::event().post(shared_ptr<hal::EventDetail>(
1526                                        new hal::EventDebug(hal::Event::debug, L"Encountered duplicate torrent")));
1527                               
1528                                ++i; // Harmless, don't worry about it.
1529                        }
1530                        catch(const std::exception& e) 
1531                        {
1532                                hal::event().post(shared_ptr<hal::EventDetail>(
1533                                        new hal::EventStdException(hal::Event::warning, e, L"resumeAll")));
1534                               
1535                                pimpl->theTorrents.erase(i++);
1536                        }                       
1537                }
1538                else
1539                {
1540                        pimpl->theTorrents.erase(i++);
1541                }
1542        }
1543       
1544        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "resumeAll")
1545}
1546
1547void BitTorrent::closeAll()
1548{
1549        try {
1550       
1551        event().post(shared_ptr<EventDetail>(new EventInfo(L"Stopping all torrents...")));
1552       
1553        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); 
1554                i != e; ++i)
1555        {
1556                if ((*i).torrent->inSession())
1557                {
1558                //      HAL_DEV_MSG(wformat_t(L"Internalling pausing writeData=%1%") % writeData);
1559                        (*i).torrent->handle().pause(); // Internal pause, not registered in Torrents.xml
1560                }
1561        }
1562       
1563        // Ok this polling loop here is a bit curde, but a blocking wait is actually appropiate.
1564        for (bool nonePaused = true; !nonePaused; )
1565        {
1566                for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); 
1567                                i != e; ++i)
1568                {
1569                        // NB. this checks for an internal paused state.
1570                        nonePaused &= ((*i).torrent->inSession() ? (*i).torrent->handle().is_paused() : true);
1571                }
1572               
1573                Sleep(200);
1574        }
1575       
1576        event().post(shared_ptr<EventDetail>(new EventInfo(L"All torrents stopped.")));
1577               
1578        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); 
1579                i != e; ++i)
1580        {
1581                if ((*i).torrent->inSession())
1582                {
1583                        (*i).torrent->removeFromSession();
1584                        (*i).torrent->writeResumeData();
1585                }
1586        }
1587       
1588        event().post(shared_ptr<EventDetail>(new EventInfo(L"Fast-resume data written.")));
1589       
1590        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "closeAll")
1591}
1592
1593PeerDetail::PeerDetail(lbt::peer_info& peerInfo) :
1594        ipAddress(hal::from_utf8_safe(peerInfo.ip.address().to_string())),
1595        country(L""),
1596        speed(std::make_pair(peerInfo.payload_down_speed, peerInfo.payload_up_speed)),
1597        client(hal::from_utf8_safe(peerInfo.client))
1598{
1599        std::vector<wstring_t> status_vec;
1600       
1601#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
1602        if (peerInfo.country[0] != 0 && peerInfo.country[1] != 0)
1603                country = (wformat_t(L"(%1%)") % hal::from_utf8_safe(string_t(peerInfo.country, 2))).str().c_str();
1604#endif 
1605
1606        if (peerInfo.flags & lbt::peer_info::handshake)
1607        {
1608                status_vec.push_back(app().res_wstr(HAL_PEER_HANDSHAKE));
1609        }               
1610        else if (peerInfo.flags & lbt::peer_info::connecting)
1611        {
1612                status_vec.push_back(app().res_wstr(HAL_PEER_CONNECTING));
1613        }
1614        else
1615        {
1616        #ifndef TORRENT_DISABLE_ENCRYPTION             
1617                if (peerInfo.flags & lbt::peer_info::rc4_encrypted)
1618                        status_vec.push_back(app().res_wstr(HAL_PEER_RC4_ENCRYPTED));           
1619                if (peerInfo.flags & lbt::peer_info::plaintext_encrypted)
1620                        status_vec.push_back(app().res_wstr(HAL_PEER_PLAINTEXT_ENCRYPTED));
1621        #endif
1622               
1623                if (peerInfo.flags & lbt::peer_info::interesting)
1624                        status_vec.push_back(app().res_wstr(HAL_PEER_INTERESTING));     
1625                if (peerInfo.flags & lbt::peer_info::choked)
1626                        status_vec.push_back(app().res_wstr(HAL_PEER_CHOKED)); 
1627                if (peerInfo.flags & lbt::peer_info::remote_interested)
1628                        status_vec.push_back(app().res_wstr(HAL_PEER_REMOTE_INTERESTING));     
1629                if (peerInfo.flags & lbt::peer_info::remote_choked)
1630                        status_vec.push_back(app().res_wstr(HAL_PEER_REMOTE_CHOKED));   
1631                if (peerInfo.flags & lbt::peer_info::supports_extensions)
1632                        status_vec.push_back(app().res_wstr(HAL_PEER_SUPPORT_EXTENSIONS));     
1633        //      if (peerInfo.flags & lbt::peer_info::local_connection)                                          // Not sure whats up here?
1634        //              status_vec.push_back(app().res_wstr(HAL_PEER_LOCAL_CONNECTION));                       
1635                if (peerInfo.flags & lbt::peer_info::queued)
1636                        status_vec.push_back(app().res_wstr(HAL_PEER_QUEUED));
1637        }
1638       
1639        seed = (peerInfo.flags & lbt::peer_info::seed) ? true : false;
1640       
1641        if (!status_vec.empty()) status = status_vec[0];
1642       
1643        if (status_vec.size() > 1)
1644        {
1645                for (size_t i=1; i<status_vec.size(); ++i)
1646                {
1647                        status += L"; ";
1648                        status += status_vec[i];
1649                }
1650        }       
1651}
1652
1653void BitTorrent::getAllPeerDetails(const std::string& filename, PeerDetails& peerContainer)
1654{
1655        getAllPeerDetails(from_utf8_safe(filename), peerContainer);
1656}
1657
1658void BitTorrent::getAllPeerDetails(const std::wstring& filename, PeerDetails& peerContainer)
1659{
1660        try {
1661       
1662        pimpl->theTorrents.get(filename)->getPeerDetails(peerContainer);
1663       
1664        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getAllPeerDetails")
1665}
1666
1667void BitTorrent::getAllFileDetails(const std::string& filename, FileDetails& fileDetails)
1668{
1669        getAllFileDetails(from_utf8_safe(filename), fileDetails);
1670}
1671
1672void BitTorrent::getAllFileDetails(const std::wstring& filename, FileDetails& fileDetails)
1673{
1674        try {
1675       
1676        pimpl->theTorrents.get(filename)->getFileDetails(fileDetails);
1677       
1678        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getAllFileDetails")
1679}
1680
1681bool BitTorrent::isTorrent(const std::string& filename)
1682{       
1683        return isTorrent(hal::to_wstr_shim(filename));
1684}
1685
1686bool BitTorrent::isTorrent(const std::wstring& filename)
1687{       
1688        try {
1689       
1690        return pimpl->theTorrents.exists(filename);
1691       
1692        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "isTorrent")
1693       
1694        return false;
1695}
1696
1697void BitTorrent::pauseTorrent(const std::string& filename)
1698{
1699        pauseTorrent(hal::to_wstr_shim(filename));
1700}
1701
1702void BitTorrent::pauseTorrent(const std::wstring& filename)
1703{
1704        try {
1705       
1706        pimpl->theTorrents.get(filename)->pause();
1707       
1708        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "pauseTorrent")
1709}
1710
1711void BitTorrent::resumeTorrent(const std::string& filename)
1712{
1713        resumeTorrent(hal::to_wstr_shim(filename));
1714}
1715
1716void BitTorrent::resumeTorrent(const std::wstring& filename)
1717{
1718        try {
1719       
1720        pimpl->theTorrents.get(filename)->resume();
1721       
1722        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "resumeTorrent")
1723}
1724
1725void BitTorrent::stopTorrent(const std::string& filename)
1726{
1727        stopTorrent(hal::to_wstr_shim(filename));
1728}
1729
1730void BitTorrent::stopTorrent(const std::wstring& filename)
1731{
1732        try {
1733       
1734        pimpl->theTorrents.get(filename)->stop();
1735       
1736        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "stopTorrent")
1737}
1738
1739bool BitTorrent::isTorrentActive(const std::string& filename)
1740{
1741        return isTorrentActive(hal::to_wstr_shim(filename));
1742}
1743
1744bool BitTorrent::isTorrentActive(const std::wstring& filename)
1745{
1746        try {
1747       
1748        return pimpl->theTorrents.get(filename)->isActive();
1749       
1750        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "isTorrentActive")
1751       
1752        return false; // ??? is this correct
1753}
1754
1755void BitTorrent::reannounceTorrent(const std::string& filename)
1756{
1757        reannounceTorrent(hal::to_wstr_shim(filename));
1758}
1759
1760void BitTorrent::reannounceTorrent(const std::wstring& filename)
1761{
1762        try {
1763       
1764        pimpl->theTorrents.get(filename)->handle().force_reannounce();
1765       
1766        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "reannounceTorrent")
1767}
1768
1769void BitTorrent::setTorrentLogin(const std::string& filename, std::wstring username, std::wstring password)
1770{
1771        setTorrentLogin(hal::to_wstr_shim(filename), username, password);
1772}
1773
1774void BitTorrent::setTorrentLogin(const std::wstring& filename, std::wstring username, std::wstring password)
1775{
1776        try {
1777       
1778        pimpl->theTorrents.get(filename)->setTrackerLogin(username, password);
1779       
1780        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentLogin")
1781}
1782
1783std::pair<std::wstring, std::wstring> BitTorrent::getTorrentLogin(const std::string& filename)
1784{
1785        return getTorrentLogin(hal::to_wstr_shim(filename));
1786}
1787
1788std::pair<std::wstring, std::wstring> BitTorrent::getTorrentLogin(const std::wstring& filename)
1789{
1790        try {
1791       
1792        return pimpl->theTorrents.get(filename)->getTrackerLogin();
1793       
1794        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentLogin")
1795       
1796        return std::make_pair(L"", L"");
1797}
1798
1799void BitTorrent_impl::removalThread(TorrentInternal_ptr pIT, bool wipeFiles)
1800{
1801        try {
1802
1803        if (!wipeFiles)
1804        {
1805                theSession.remove_torrent(pIT->handle());
1806        }
1807        else
1808        {
1809                if (pIT->inSession())
1810                {
1811                        theSession.remove_torrent(pIT->handle(), lbt::session::delete_files);
1812                }
1813                else
1814                {
1815                        lbt::torrent_info m_info = pIT->infoMemory();
1816                       
1817                        // delete the files from disk
1818                        std::string error;
1819                        std::set<std::string> directories;
1820                       
1821                        for (lbt::torrent_info::file_iterator i = m_info.begin_files(true)
1822                                , end(m_info.end_files(true)); i != end; ++i)
1823                        {
1824                                std::string p = (hal::to_utf8(pIT->saveDirectory()) / i->path).string();
1825                                fs::path bp = i->path.branch_path();
1826                               
1827                                std::pair<std::set<std::string>::iterator, bool> ret;
1828                                ret.second = true;
1829                                while (ret.second && !bp.empty())
1830                                {
1831                                        std::pair<std::set<std::string>::iterator, bool> ret = 
1832                                                directories.insert((hal::to_utf8(pIT->saveDirectory()) / bp).string());
1833                                        bp = bp.branch_path();
1834                                }
1835                                if (!fs::remove(hal::from_utf8(p).c_str()) && errno != ENOENT)
1836                                        error = std::strerror(errno);
1837                        }
1838
1839                        // remove the directories. Reverse order to delete subdirectories first
1840
1841                        for (std::set<std::string>::reverse_iterator i = directories.rbegin()
1842                                , end(directories.rend()); i != end; ++i)
1843                        {
1844                                if (!fs::remove(hal::from_utf8(*i).c_str()) && errno != ENOENT)
1845                                        error = std::strerror(errno);
1846                        }
1847                }
1848        }
1849
1850        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "removalThread")
1851}
1852
1853void BitTorrent::removeTorrent(const std::string& filename)
1854{
1855        removeTorrent(hal::to_wstr_shim(filename));
1856}
1857
1858void BitTorrent::removeTorrent(const std::wstring& filename)
1859{
1860        try {
1861       
1862        TorrentInternal_ptr pTI = pimpl->theTorrents.get(filename);
1863        lbt::torrent_handle handle = pTI->handle();
1864        pimpl->theTorrents.erase(filename);
1865       
1866        thread_t t(bind(&BitTorrent_impl::removalThread, &*pimpl, pTI, false)); 
1867       
1868        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "removeTorrent")
1869}
1870
1871void BitTorrent::recheckTorrent(const std::string& filename)
1872{
1873        recheckTorrent(hal::to_wstr_shim(filename));
1874}
1875
1876void BitTorrent::recheckTorrent(const std::wstring& filename)
1877{
1878        try {
1879       
1880        pimpl->theTorrents.get(filename)->forceRecheck();
1881       
1882        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "recheckTorrent")
1883}
1884
1885void BitTorrent::removeTorrentWipeFiles(const std::string& filename)
1886{
1887        removeTorrentWipeFiles(hal::to_wstr_shim(filename));
1888}
1889
1890void BitTorrent::removeTorrentWipeFiles(const std::wstring& filename)
1891{
1892        try {
1893       
1894        TorrentInternal_ptr pTI = pimpl->theTorrents.get(filename);
1895        lbt::torrent_handle handle = pTI->handle();
1896        pimpl->theTorrents.erase(filename);
1897       
1898        thread_t t(bind(&BitTorrent_impl::removalThread, &*pimpl, pTI, true)); 
1899       
1900        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "removeTorrentWipeFiles")
1901}
1902
1903void BitTorrent::pauseAllTorrents()
1904{       
1905        try {
1906       
1907        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end();
1908                i != e; ++i)
1909        {               
1910                if ((*i).torrent->inSession())
1911                        (*i).torrent->pause();
1912        }
1913       
1914        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "pauseAllTorrents")
1915}
1916
1917void BitTorrent::unpauseAllTorrents()
1918{       
1919        try {
1920       
1921        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end();
1922                i != e; ++i)
1923        {
1924                if ((*i).torrent->inSession() && (*i).torrent->state() == TorrentDetail::torrent_paused)
1925                        (*i).torrent->resume();
1926        }
1927       
1928        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "unpauseAllTorrents")
1929}
1930
1931void BitTorrent::setTorrentLimit(const std::string& filename, int maxConn, int maxUpload)
1932{
1933        setTorrentLimit(hal::from_utf8_safe(filename), maxConn, maxUpload);
1934}
1935
1936void BitTorrent::setTorrentLimit(const std::wstring& filename, int maxConn, int maxUpload)
1937{
1938        try {
1939       
1940        pimpl->theTorrents.get(filename)->setConnectionLimit(maxConn, maxUpload);
1941       
1942        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentLimit")
1943}
1944
1945void BitTorrent::torrent::set_ratio(float new_ratio)
1946{
1947        try {
1948       
1949        ptr->setRatio(ratio);
1950       
1951        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(L"Me", "torrent::set_ratio")
1952}
1953
1954float BitTorrent::torrent::get_ratio() const
1955{
1956        try {
1957       
1958        return ptr->getRatio();
1959       
1960        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(L"Me", "torrent::get_ratio")
1961       
1962        return 0;
1963}
1964
1965void BitTorrent::setTorrentRatio(const std::string& filename, float ratio)
1966{
1967        setTorrentRatio(hal::from_utf8_safe(filename), ratio);
1968}
1969
1970void BitTorrent::setTorrentRatio(const std::wstring& filename, float ratio)
1971{
1972        try {
1973       
1974        pimpl->theTorrents.get(filename)->setRatio(ratio);
1975       
1976        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentRatio")
1977}
1978
1979float BitTorrent::getTorrentRatio(const std::string& filename)
1980{
1981        return getTorrentRatio(hal::from_utf8_safe(filename));
1982}
1983
1984float BitTorrent::getTorrentRatio(const std::wstring& filename)
1985{
1986        try {
1987       
1988        return pimpl->theTorrents.get(filename)->getRatio();
1989       
1990        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentRatio")
1991       
1992        return 0;
1993}
1994
1995void BitTorrent::setTorrentSpeed(const std::string& filename, float download, float upload)
1996{
1997        setTorrentSpeed(hal::from_utf8_safe(filename), download, upload);
1998}
1999
2000void BitTorrent::setTorrentSpeed(const std::wstring& filename, float download, float upload)
2001{
2002        try {
2003       
2004        pimpl->theTorrents.get(filename)->setTransferSpeed(download, upload);
2005       
2006        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentSpeed")
2007}
2008
2009std::pair<int, int> BitTorrent::getTorrentLimit(const std::string& filename)
2010{
2011        return getTorrentLimit(from_utf8_safe(filename));
2012}
2013
2014std::pair<int, int> BitTorrent::getTorrentLimit(const std::wstring& filename)
2015{
2016        try {
2017       
2018        return pimpl->theTorrents.get(filename)->getConnectionLimit();
2019       
2020        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentLimit")
2021       
2022        return std::pair<int, int>(0, 0);
2023}
2024
2025std::pair<float, float> BitTorrent::getTorrentSpeed(const std::string& filename)
2026{
2027        return getTorrentSpeed(from_utf8_safe(filename));
2028}
2029
2030std::pair<float, float> BitTorrent::getTorrentSpeed(const std::wstring& filename)
2031{
2032        try {
2033       
2034        return pimpl->theTorrents.get(filename)->getTransferSpeed();
2035       
2036        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentSpeed")
2037       
2038        return std::pair<float, float>(0, 0);
2039}
2040
2041void BitTorrent::setTorrentFilePriorities(const std::string& filename, 
2042        std::vector<int> fileIndices, int priority)
2043{
2044        setTorrentFilePriorities(from_utf8_safe(filename), fileIndices, priority);
2045}
2046
2047void BitTorrent::setTorrentFilePriorities(const std::wstring& filename, 
2048        std::vector<int> fileIndices, int priority)
2049{
2050        try {
2051       
2052        pimpl->theTorrents.get(filename)->setFilePriorities(fileIndices, priority);
2053       
2054        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentFilePriorities")
2055}
2056
2057void BitTorrent::setTorrentTrackers(const std::string& filename, 
2058        const std::vector<tracker_detail>& trackers)
2059{
2060        setTorrentTrackers(from_utf8_safe(filename), trackers);
2061}
2062
2063void BitTorrent::setTorrentTrackers(const std::wstring& filename, 
2064        const std::vector<tracker_detail>& trackers)
2065{
2066        try {
2067       
2068        pimpl->theTorrents.get(filename)->setTrackers(trackers);
2069       
2070        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentTrackers")
2071}
2072
2073void BitTorrent::resetTorrentTrackers(const std::string& filename)
2074{
2075        resetTorrentTrackers(from_utf8_safe(filename));
2076}
2077
2078void BitTorrent::resetTorrentTrackers(const std::wstring& filename)
2079{
2080        try {
2081       
2082        pimpl->theTorrents.get(filename)->resetTrackers();
2083       
2084        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "resetTorrentTrackers")
2085}
2086
2087std::vector<tracker_detail> BitTorrent::getTorrentTrackers(const std::string& filename)
2088{
2089        return getTorrentTrackers(from_utf8_safe(filename));
2090}
2091
2092std::vector<tracker_detail> BitTorrent::getTorrentTrackers(const std::wstring& filename)
2093{
2094        try {
2095       
2096        return pimpl->theTorrents.get(filename)->getTrackers();
2097       
2098        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentTrackers")
2099       
2100        return std::vector<tracker_detail>();   
2101}
2102
2103void BitTorrent::startEventReceiver()
2104{
2105        pimpl->keepChecking_ = true;
2106        thread_t(bind(&asio::io_service::run, &pimpl->io_));
2107}
2108
2109void BitTorrent::stopEventReceiver()
2110{
2111        pimpl->keepChecking_ = false;
2112}
2113
2114int BitTorrent::defTorrentMaxConn() { return pimpl->defTorrentMaxConn_; }
2115int BitTorrent::defTorrentMaxUpload() { return pimpl->defTorrentMaxUpload_; }
2116float BitTorrent::defTorrentDownload() { return pimpl->defTorrentDownload_; }
2117float BitTorrent::defTorrentUpload() { return pimpl->defTorrentUpload_; }
2118       
2119};
Note: See TracBrowser for help on using the repository browser.