source: trunk/src/halTorrent.cpp @ 432

Revision 432, 57.7 KB checked in by Eoin, 12 years ago (diff)

Torrent creation is working!

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