source: trunk/src/halTorrent.cpp @ 460

Revision 460, 58.6 KB checked in by Eoin, 12 years ago (diff)

Fixed 'Close to Tray' bug. Added name properity to torrents.

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