source: trunk/src/halTorrent.cpp @ 461

Revision 461, 58.7 KB checked in by Eoin, 12 years ago (diff)

Improved Torrent Creation.

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 = params.piece_size;
697                HAL_DEV_MSG(wformat(L"piece size: %1%") % piece_size);
698                t_info->set_piece_size(piece_size);
699
700                HAL_DEV_MSG(L"Files");
701                for (file_size_pairs_t::const_iterator i = params.file_size_pairs.begin(), e = params.file_size_pairs.end();
702                                i != e; ++i)
703                {
704                        HAL_DEV_MSG(wformat(L"file path: %1%, size: %2%") % (*i).first % (*i).second);
705                        t_info->add_file(to_utf8((*i).first.string()), (*i).second);
706                }
707
708                libt::file_pool f_pool;
709               
710                boost::scoped_ptr<libt::storage_interface> store(
711                        libt::default_storage_constructor(t_info, to_utf8(params.root_path.string()),
712                                f_pool));
713
714                HAL_DEV_MSG(L"Trackers");
715                for (tracker_details_t::const_iterator i = params.trackers.begin(), e = params.trackers.end();
716                                i != e; ++i)
717                {
718                        HAL_DEV_MSG(wformat(L"URL: %1%, Tier: %2%") % (*i).url % (*i).tier);
719                        t_info->add_tracker(to_utf8((*i).url), (*i).tier);
720                }
721
722                HAL_DEV_MSG(L"Web Seeds");
723                for (web_seed_details_t::const_iterator i = params.web_seeds.begin(), e = params.web_seeds.end();
724                                i != e; ++i)
725                {
726                        HAL_DEV_MSG(wformat(L"URL: %1%") % (*i).url);
727                        t_info->add_url_seed(to_utf8((*i).url));
728                }
729
730                HAL_DEV_MSG(L"DHT Nodes");
731                for (dht_node_details_t::const_iterator i = params.dht_nodes.begin(), e = params.dht_nodes.end();
732                                i != e; ++i)
733                {
734                        HAL_DEV_MSG(wformat(L"URL: %1%, port: %2%") % (*i).url % (*i).port);
735                        t_info->add_node(hal::make_pair(to_utf8((*i).url), (*i).port));
736                }
737
738                // calculate the hash for all pieces
739                int num = t_info->num_pieces();
740                std::vector<char> piece_buf(piece_size);
741
742                for (int i = 0; i < num; ++i)
743                {
744                        store->read(&piece_buf[0], i, 0, t_info->piece_size(i));
745
746                        libt::hasher h(&piece_buf[0], t_info->piece_size(i));
747                        t_info->set_hash(i, h.final());
748
749                        if (fn(100*i / num, hal::app().res_wstr(HAL_NEWT_HASHING_PIECES)))
750                        {
751                                // User canceled torrent creation.
752
753                                hal::event().post(shared_ptr<hal::EventDetail>(
754                                        new hal::EventMsg(hal::app().res_wstr(HAL_NEWT_CREATION_CANCELED), hal::Event::info)));
755
756                                return true;
757                        }
758                }
759
760                t_info->set_creator(to_utf8(params.creator).c_str());
761                t_info->set_comment(to_utf8(params.comment).c_str());
762               
763                t_info->set_priv(params.private_torrent);
764
765                // create the torrent and print it to out
766                libt::entry e = t_info->create_torrent();
767                halencode(out_file, e);
768                }
769                catch(const std::exception& e)
770                {
771                        event().post(shared_ptr<EventDetail>(
772                                new EventStdException(Event::fatal, e, L"create_torrent")));
773                }       
774
775                return false;
776        }
777       
778        std::pair<libt::entry, libt::entry> prepTorrent(wpath filename, wpath saveDirectory);
779        void removalThread(torrent_internal_ptr pIT, bool wipeFiles);
780       
781        libt::session theSession;
782        asio::io_service io_;
783        asio::deadline_timer timer_;
784        bool keepChecking_;
785       
786        static wpath workingDirectory;
787        ini_file bittorrentIni;
788        TorrentManager theTorrents;     
789       
790        int defTorrentMaxConn_;
791        int defTorrentMaxUpload_;
792        float defTorrentDownload_;
793        float defTorrentUpload_;
794       
795        bool ip_filter_on_;
796        bool ip_filter_loaded_;
797        bool ip_filter_changed_;
798        libt::ip_filter ip_filter_;
799        size_t ip_filter_count_;
800       
801        void ip_filter_count();
802        void ip_filter_load(progress_callback fn);
803        void ip_filter_import(std::vector<libt::ip_range<asio::ip::address_v4> >& v4,
804                std::vector<libt::ip_range<asio::ip::address_v6> >& v6);
805       
806        bool dht_on_;
807        libt::dht_settings dht_settings_;
808        libt::entry dht_state_;
809       
810};
811
812wpath bit_impl::workingDirectory = hal::app().working_directory();
813
814bit::bit() :
815        pimpl(new bit_impl())
816{}
817
818#define HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH(FUNCTION) \
819catch (const libt::invalid_handle&) \
820{\
821        event().post(shared_ptr<EventDetail>( \
822                new EventInvalidTorrent(Event::critical, Event::invalidTorrent, name, std::string(FUNCTION)))); \
823}\
824catch (const invalidTorrent& t) \
825{\
826        event().post(shared_ptr<EventDetail>( \
827                new EventInvalidTorrent(Event::info, Event::invalidTorrent, t.who(), std::string(FUNCTION)))); \
828}\
829catch (const std::exception& e) \
830{\
831        event().post(shared_ptr<EventDetail>( \
832                new EventTorrentException(Event::critical, Event::torrentException, std::string(e.what()), name, std::string(FUNCTION)))); \
833}
834
835#define HAL_GENERIC_TORRENT_EXCEPTION_CATCH(TORRENT, FUNCTION) \
836catch (const libt::invalid_handle&) \
837{\
838        event().post(shared_ptr<EventDetail>( \
839                new EventInvalidTorrent(Event::critical, Event::invalidTorrent, TORRENT, std::string(FUNCTION)))); \
840}\
841catch (const invalidTorrent& t) \
842{\
843        event().post(shared_ptr<EventDetail>( \
844                new EventInvalidTorrent(Event::info, Event::invalidTorrent, t.who(), std::string(FUNCTION)))); \
845}\
846catch (const std::exception& e) \
847{\
848        event().post(shared_ptr<EventDetail>( \
849                new EventTorrentException(Event::critical, Event::torrentException, std::string(e.what()), TORRENT, std::string(FUNCTION)))); \
850}
851
852void bit::shutDownSession()
853{
854        pimpl.reset();
855}
856
857void bit::saveTorrentData()
858{
859        pimpl->saveTorrentData();
860}
861
862bool bit::create_torrent(const create_torrent_params& params, fs::wpath out_file, progress_callback fn)
863{
864        return pimpl->create_torrent(params, out_file, fn);
865}
866
867bit::torrent bit::get_wstr(const std::wstring& filename)
868{
869        return bit::torrent(pimpl->theTorrents.get(filename));
870}
871
872bool bit::listenOn(std::pair<int, int> const& range)
873{
874        try
875        {
876       
877        if (!pimpl->theSession.is_listening())
878        {
879                return pimpl->theSession.listen_on(range);
880        }
881        else
882        {
883                int port = pimpl->theSession.listen_port();
884               
885                if (port < range.first || port > range.second)
886                        return pimpl->theSession.listen_on(range);     
887                else
888                {
889                        pimpl->signals.successful_listen();
890                       
891                        return true;
892                }
893        }
894       
895        }
896        catch (const std::exception& e)
897        {
898                event().post(shared_ptr<EventDetail>(
899                        new EventStdException(Event::fatal, e, L"From bit::listenOn.")));
900
901                return false;
902        }
903        catch(...)
904        {
905                return false;
906        }
907}
908
909int bit::isListeningOn() 
910{
911        if (!pimpl->theSession.is_listening())
912                return -1;     
913        else
914                return pimpl->theSession.listen_port();
915}
916
917void bit::stopListening()
918{
919        ensureDhtOff();
920        pimpl->theSession.listen_on(std::make_pair(0, 0));
921}
922
923bool bit::ensureDhtOn()
924{
925        if (!pimpl->dht_on_)
926        {               
927                try
928                {
929                pimpl->theSession.start_dht(pimpl->dht_state_);
930                pimpl->dht_on_ = true;
931                }
932                catch(...)
933                {}
934        }
935                return pimpl->dht_on_;
936}
937
938void bit::ensureDhtOff()
939{
940        if (pimpl->dht_on_)
941        {
942                pimpl->theSession.stop_dht();           
943                pimpl->dht_on_ = false;
944        }
945}
946
947void bit::setDhtSettings(int max_peers_reply, int search_branching, 
948        int service_port, int max_fail_count)
949{
950        libt::dht_settings settings;
951        settings.max_peers_reply = max_peers_reply;
952        settings.search_branching = search_branching;
953        settings.service_port = service_port;
954        settings.max_fail_count = max_fail_count;
955       
956        if (pimpl->dht_settings_ != settings)
957        {
958                pimpl->dht_settings_ = settings;
959                pimpl->theSession.set_dht_settings(pimpl->dht_settings_);
960        }
961}
962
963void bit::setMapping(int mapping)
964{
965        if (mapping != mappingNone)
966        {
967                if (mapping == mappingUPnP)
968                {
969                        event().post(shared_ptr<EventDetail>(new EventMsg(L"Starting UPnP mapping.")));
970                        pimpl->theSession.stop_upnp();
971                        pimpl->theSession.stop_natpmp();
972
973                        pimpl->signals.successful_listen.connect_once(bind(&libt::session::start_upnp, &pimpl->theSession));
974                }
975                else
976                {
977                        event().post(shared_ptr<EventDetail>(new EventMsg(L"Starting NAT-PMP mapping.")));
978                        pimpl->theSession.stop_upnp();
979                        pimpl->theSession.stop_natpmp();
980
981                        pimpl->signals.successful_listen.connect_once(bind(&libt::session::start_natpmp, &pimpl->theSession));
982                }
983        }
984        else
985        {
986                event().post(shared_ptr<EventDetail>(new EventMsg(L"No mapping.")));
987                pimpl->theSession.stop_upnp();
988                pimpl->theSession.stop_natpmp();
989        }
990}
991
992void bit::setTimeouts(int peers, int tracker)
993{
994        libt::session_settings settings = pimpl->theSession.settings();
995        settings.peer_connect_timeout = peers;
996        settings.tracker_completion_timeout = tracker;
997
998        pimpl->theSession.set_settings(settings);
999
1000        event().post(shared_ptr<EventDetail>(new EventMsg(
1001                wformat(L"Set Timeouts, peer %1%, tracker %2%") % peers % tracker)));
1002}
1003
1004void bit::setSessionLimits(int maxConn, int maxUpload)
1005{               
1006        pimpl->theSession.set_max_uploads(maxUpload);
1007        pimpl->theSession.set_max_connections(maxConn);
1008       
1009        event().post(shared_ptr<EventDetail>(new EventMsg(
1010                wformat(L"Set connections totals %1% and uploads %2%.") 
1011                        % maxConn % maxUpload)));
1012}
1013
1014void bit::setSessionSpeed(float download, float upload)
1015{
1016        int down = (download > 0) ? static_cast<int>(download*1024) : -1;
1017        pimpl->theSession.set_download_rate_limit(down);
1018        int up = (upload > 0) ? static_cast<int>(upload*1024) : -1;
1019        pimpl->theSession.set_upload_rate_limit(up);
1020       
1021        event().post(shared_ptr<EventDetail>(new EventMsg(
1022                wformat(L"Set session rates at download %1% and upload %2%.") 
1023                        % pimpl->theSession.download_rate_limit() % pimpl->theSession.upload_rate_limit())));
1024}
1025
1026void bit_impl::ip_filter_count()
1027{
1028        libt::ip_filter::filter_tuple_t vectors = ip_filter_.export_filter();
1029       
1030        vectors.get<0>().erase(std::remove(vectors.get<0>().begin(), vectors.get<0>().end(), 0),
1031                vectors.get<0>().end());
1032        vectors.get<1>().erase(std::remove(vectors.get<1>().begin(), vectors.get<1>().end(), 0),
1033                vectors.get<1>().end());
1034        ip_filter_count_ = vectors.get<0>().size() + vectors.get<1>().size();
1035}
1036
1037void bit_impl::ip_filter_load(progress_callback fn)
1038{
1039        fs::ifstream ifs(workingDirectory/L"IPFilter.bin", std::ios::binary);
1040        if (ifs)
1041        {
1042                size_t v4_size;
1043                ifs >> v4_size;
1044               
1045                size_t total = v4_size/100;
1046                size_t previous = 0;
1047               
1048                for(unsigned i=0; i<v4_size; ++i)
1049                {
1050                        if (i-previous > total)
1051                        {
1052                                previous = i;
1053
1054                                if (fn) if (fn(size_t(i/total), hal::app().res_wstr(HAL_TORRENT_LOAD_FILTERS))) break;
1055                        }
1056                       
1057                        read_range_to_filter<asio::ip::address_v4>(ifs, ip_filter_);
1058                }
1059        }       
1060}
1061
1062void  bit_impl::ip_filter_import(std::vector<libt::ip_range<asio::ip::address_v4> >& v4,
1063        std::vector<libt::ip_range<asio::ip::address_v6> >& v6)
1064{
1065        for(std::vector<libt::ip_range<asio::ip::address_v4> >::iterator i=v4.begin();
1066                i != v4.end(); ++i)
1067        {
1068                ip_filter_.add_rule(i->first, i->last, libt::ip_filter::blocked);
1069        }
1070/*      for(std::vector<libt::ip_range<asio::ip::address_v6> >::iterator i=v6.begin();
1071                i != v6.end(); ++i)
1072        {
1073                ip_filter_.add_rule(i->first, i->last, libt::ip_filter::blocked);
1074        }
1075*/     
1076        /* Note here we do not set ip_filter_changed_ */
1077}
1078
1079bool bit::ensureIpFilterOn(progress_callback fn)
1080{
1081        try
1082        {
1083       
1084        if (!pimpl->ip_filter_loaded_)
1085        {
1086                pimpl->ip_filter_load(fn);
1087                pimpl->ip_filter_loaded_ = true;
1088        }
1089       
1090        if (!pimpl->ip_filter_on_)
1091        {
1092                pimpl->theSession.set_ip_filter(pimpl->ip_filter_);
1093                pimpl->ip_filter_on_ = true;
1094                pimpl->ip_filter_count();
1095        }
1096       
1097        }
1098        catch(const std::exception& e)
1099        {               
1100                hal::event().post(boost::shared_ptr<hal::EventDetail>(
1101                        new hal::EventStdException(Event::critical, e, L"ensureIpFilterOn"))); 
1102
1103                ensureIpFilterOff();
1104        }
1105
1106        event().post(shared_ptr<EventDetail>(new EventMsg(L"IP filters on."))); 
1107
1108        return false;
1109}
1110
1111void bit::ensureIpFilterOff()
1112{
1113        pimpl->theSession.set_ip_filter(libt::ip_filter());
1114        pimpl->ip_filter_on_ = false;
1115       
1116        event().post(shared_ptr<EventDetail>(new EventMsg(L"IP filters off.")));       
1117}
1118
1119#ifndef TORRENT_DISABLE_ENCRYPTION     
1120void bit::ensurePeOn(int enc_level, int in_enc_policy, int out_enc_policy, bool prefer_rc4)
1121{
1122        libt::pe_settings pe;
1123       
1124        switch (enc_level)
1125        {
1126                case 0:
1127                        pe.allowed_enc_level = libt::pe_settings::plaintext;
1128                        break;
1129                case 1:
1130                        pe.allowed_enc_level = libt::pe_settings::rc4;
1131                        break;
1132                case 2:
1133                        pe.allowed_enc_level = libt::pe_settings::both;
1134                        break;
1135                default:
1136                        pe.allowed_enc_level = libt::pe_settings::both;
1137                       
1138                        hal::event().post(shared_ptr<hal::EventDetail>(
1139                                new hal::EventGeneral(hal::Event::warning, hal::Event::unclassified, 
1140                                        (wformat(hal::app().res_wstr(HAL_INCORRECT_ENCODING_LEVEL)) % enc_level).str())));
1141        }
1142
1143        switch (in_enc_policy)
1144        {
1145                case 0:
1146                        pe.in_enc_policy = libt::pe_settings::forced;
1147                        break;
1148                case 1:
1149                        pe.in_enc_policy = libt::pe_settings::enabled;
1150                        break;
1151                case 2:
1152                        pe.in_enc_policy = libt::pe_settings::disabled;
1153                        break;
1154                default:
1155                        pe.in_enc_policy = libt::pe_settings::enabled;
1156                       
1157                        hal::event().post(shared_ptr<hal::EventDetail>(
1158                                new hal::EventGeneral(hal::Event::warning, hal::Event::unclassified, 
1159                                        (wformat(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % in_enc_policy).str())));
1160        }
1161
1162        switch (out_enc_policy)
1163        {
1164                case 0:
1165                        pe.out_enc_policy = libt::pe_settings::forced;
1166                        break;
1167                case 1:
1168                        pe.out_enc_policy = libt::pe_settings::enabled;
1169                        break;
1170                case 2:
1171                        pe.out_enc_policy = libt::pe_settings::disabled;
1172                        break;
1173                default:
1174                        pe.out_enc_policy = libt::pe_settings::enabled;
1175                       
1176                        hal::event().post(shared_ptr<hal::EventDetail>(
1177                                new hal::EventGeneral(hal::Event::warning, hal::Event::unclassified, 
1178                                        (wformat(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % in_enc_policy).str())));
1179        }
1180       
1181        pe.prefer_rc4 = prefer_rc4;
1182       
1183        try
1184        {
1185       
1186        pimpl->theSession.set_pe_settings(pe);
1187       
1188        }
1189        catch(const std::exception& e)
1190        {
1191                hal::event().post(boost::shared_ptr<hal::EventDetail>(
1192                                new hal::EventStdException(Event::critical, e, L"ensurePeOn"))); 
1193                               
1194                ensurePeOff();         
1195        }
1196       
1197        event().post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption on.")));
1198}
1199
1200void bit::ensurePeOff()
1201{
1202        libt::pe_settings pe;
1203        pe.out_enc_policy = libt::pe_settings::disabled;
1204        pe.in_enc_policy = libt::pe_settings::disabled;
1205       
1206        pe.allowed_enc_level = libt::pe_settings::both;
1207        pe.prefer_rc4 = true;
1208       
1209        pimpl->theSession.set_pe_settings(pe);
1210
1211        event().post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption off.")));
1212}
1213#endif
1214
1215void bit::ip_v4_filter_block(asio::ip::address_v4 first, asio::ip::address_v4 last)
1216{
1217        pimpl->ip_filter_.add_rule(first, last, libt::ip_filter::blocked);
1218        pimpl->ip_filter_count();
1219        pimpl->ip_filter_changed_ = true;
1220}
1221
1222void bit::ip_v6_filter_block(asio::ip::address_v6 first, asio::ip::address_v6 last)
1223{
1224        pimpl->ip_filter_.add_rule(first, last, libt::ip_filter::blocked);
1225        pimpl->ip_filter_count();
1226        pimpl->ip_filter_changed_ = true;
1227}
1228
1229size_t bit::ip_filter_size()
1230{
1231        return pimpl->ip_filter_count_;
1232}
1233
1234void bit::clearIpFilter()
1235{
1236        pimpl->ip_filter_ = libt::ip_filter();
1237        pimpl->theSession.set_ip_filter(libt::ip_filter());     
1238        pimpl->ip_filter_changed_ = true;
1239        pimpl->ip_filter_count();
1240}
1241
1242bool bit::ip_filter_import_dat(boost::filesystem::path file, progress_callback fn, bool octalFix)
1243{
1244        try
1245        {
1246
1247        fs::ifstream ifs(file); 
1248        if (ifs)
1249        {
1250                boost::uintmax_t total = fs::file_size(file)/100;
1251                boost::uintmax_t progress = 0;
1252                boost::uintmax_t previous = 0;
1253               
1254                boost::regex reg("\\s*(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s*-\\s*(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s*.*");
1255                boost::regex ip_reg("0*(\\d*)\\.0*(\\d*)\\.0*(\\d*)\\.0*(\\d*)");
1256                boost::smatch m;
1257               
1258                string ip_address_line;         
1259                while (!std::getline(ifs, ip_address_line).eof())
1260                {               
1261                        progress += (ip_address_line.length() + 2);
1262                        if (progress-previous > total)
1263                        {
1264                                previous = progress;
1265                                if (fn)
1266                                {
1267                                        if (fn(size_t(progress/total), hal::app().res_wstr(HAL_TORRENT_IMPORT_FILTERS))) 
1268                                                break;
1269                                }
1270                        }
1271                       
1272                        if (boost::regex_match(ip_address_line, m, reg))
1273                        {
1274                                string first = m[1];
1275                                string last = m[2];
1276                               
1277                                if (octalFix)
1278                                {
1279                                        if (boost::regex_match(first, m, ip_reg))
1280                                        {
1281                                                first = ((m.length(1) != 0) ? m[1] : string("0")) + "." +
1282                                                                ((m.length(2) != 0) ? m[2] : string("0")) + "." +
1283                                                                ((m.length(3) != 0) ? m[3] : string("0")) + "." +
1284                                                                ((m.length(4) != 0) ? m[4] : string("0"));
1285                                        }                                       
1286                                        if (boost::regex_match(last, m, ip_reg))
1287                                        {
1288                                                last = ((m.length(1) != 0) ? m[1] : string("0")) + "." +
1289                                                           ((m.length(2) != 0) ? m[2] : string("0")) + "." +
1290                                                           ((m.length(3) != 0) ? m[3] : string("0")) + "." +
1291                                                           ((m.length(4) != 0) ? m[4] : string("0"));
1292                                        }
1293                                }
1294                               
1295                                try
1296                                {                       
1297                                pimpl->ip_filter_.add_rule(asio::ip::address_v4::from_string(first),
1298                                        asio::ip::address_v4::from_string(last), libt::ip_filter::blocked);     
1299                                }
1300                                catch(...)
1301                                {
1302                                        hal::event().post(shared_ptr<hal::EventDetail>(
1303                                                new hal::EventDebug(hal::Event::info, 
1304                                                        from_utf8((format("Invalid IP range: %1%-%2%.") % first % last).str()))));
1305                                }
1306                        }
1307                }
1308        }
1309       
1310        pimpl->ip_filter_changed_ = true;
1311        pimpl->ip_filter_count();
1312       
1313        }
1314        catch(const std::exception& e)
1315        {
1316                event().post(shared_ptr<EventDetail>(
1317                        new EventStdException(Event::critical, e, L"ip_filter_import_dat")));
1318        }
1319
1320        return false;
1321}
1322
1323const SessionDetail bit::getSessionDetails()
1324{
1325        SessionDetail details;
1326       
1327        details.port = pimpl->theSession.is_listening() ? pimpl->theSession.listen_port() : -1;
1328       
1329        libt::session_status status = pimpl->theSession.status();
1330       
1331        details.speed = std::pair<double, double>(status.download_rate, status.upload_rate);
1332       
1333        details.dht_on = pimpl->dht_on_;
1334        details.dht_nodes = status.dht_nodes;
1335        details.dht_torrents = status.dht_torrents;
1336       
1337        details.ip_filter_on = pimpl->ip_filter_on_;
1338        details.ip_ranges_filtered = pimpl->ip_filter_count_;
1339       
1340        return details;
1341}
1342
1343void bit::setSessionHalfOpenLimit(int halfConn)
1344{
1345        pimpl->theSession.set_max_half_open_connections(halfConn);
1346
1347        event().post(shared_ptr<EventDetail>(new EventMsg(
1348                wformat(L"Set half-open connections limit to %1%.") % pimpl->theSession.max_half_open_connections())));
1349}
1350
1351void bit::setTorrentDefaults(int maxConn, int maxUpload, float download, float upload)
1352{
1353        pimpl->defTorrentMaxConn_ = maxConn;
1354        pimpl->defTorrentMaxUpload_ = maxUpload;
1355
1356        event().post(shared_ptr<EventDetail>(new EventMsg(
1357                wformat(L"Set torrent connections total %1% and uploads %2%.") % maxConn % maxUpload)));
1358
1359        pimpl->defTorrentDownload_ = download;
1360        pimpl->defTorrentUpload_ = upload;
1361
1362        event().post(shared_ptr<EventDetail>(new EventMsg(
1363                wformat(L"Set torrent default rates at %1$.2fkb/s down and %2$.2fkb/s upload.") % download % upload)));
1364}
1365
1366std::pair<libt::entry, libt::entry> bit_impl::prepTorrent(wpath filename, wpath saveDirectory)
1367{
1368        libt::entry metadata = haldecode(filename);
1369        libt::torrent_info info(metadata);
1370       
1371        wstring torrentName = hal::from_utf8_safe(info.name());
1372        if (!boost::find_last(torrentName, L".torrent")) 
1373                torrentName += L".torrent";
1374       
1375        wpath torrentFilename = torrentName;
1376        const wpath resumeFile = workingDirectory/L"resume"/torrentFilename.leaf();
1377       
1378        //  vvv Handle old naming style!
1379        const wpath oldResumeFile = workingDirectory/L"resume"/filename.leaf();
1380       
1381        if (filename.leaf() != torrentFilename.leaf() && exists(oldResumeFile))
1382                fs::rename(oldResumeFile, resumeFile);
1383        //  ^^^ Handle old naming style!       
1384       
1385        libt::entry resumeData; 
1386       
1387        if (fs::exists(resumeFile)) 
1388        {
1389                try 
1390                {
1391                        resumeData = haldecode(resumeFile);
1392                }
1393                catch(std::exception &e) 
1394                {               
1395                        hal::event().post(boost::shared_ptr<hal::EventDetail>(
1396                                new hal::EventStdException(Event::critical, e, L"prepTorrent, Resume"))); 
1397       
1398                        fs::remove(resumeFile);
1399                }
1400        }
1401
1402        if (!fs::exists(workingDirectory/L"torrents"))
1403                fs::create_directory(workingDirectory/L"torrents");
1404
1405        if (!fs::exists(workingDirectory/L"torrents"/torrentFilename.leaf()))
1406                fs::copy_file(filename.string(), workingDirectory/L"torrents"/torrentFilename.leaf());
1407
1408        if (!fs::exists(saveDirectory))
1409                fs::create_directory(saveDirectory);
1410       
1411        return std::make_pair(metadata, resumeData);
1412}
1413
1414void bit::addTorrent(wpath file, wpath saveDirectory, bool startStopped, bool compactStorage, 
1415                boost::filesystem::wpath moveToDirectory, bool useMoveTo) 
1416{
1417        try 
1418        {       
1419        torrent_internal_ptr TIp;
1420
1421        std::pair<std::string, std::string> names = extract_names(file);
1422        wstring xml_name = from_utf8(names.first) + L".xml";
1423
1424        if (fs::exists(file.branch_path()/xml_name))
1425        {
1426                torrent_standalone tsa;
1427               
1428                if (tsa.load_standalone(file.branch_path()/xml_name))
1429                {
1430                        TIp = tsa.torrent;
1431                       
1432                        TIp->set_save_directory(saveDirectory, true);                   
1433                        if (useMoveTo)
1434                                TIp->set_move_to_directory(moveToDirectory);
1435
1436                        TIp->prepare(file);
1437                }
1438        }
1439
1440        if (!TIp)
1441        {
1442                if (useMoveTo)
1443                        TIp.reset(new torrent_internal(file, saveDirectory, compactStorage, moveToDirectory));         
1444                else
1445                        TIp.reset(new torrent_internal(file, saveDirectory, compactStorage));
1446
1447                TIp->setTransferSpeed(bittorrent().defTorrentDownload(), bittorrent().defTorrentUpload());
1448                TIp->setConnectionLimit(bittorrent().defTorrentMaxConn(), bittorrent().defTorrentMaxUpload());
1449        }
1450       
1451        std::pair<TorrentManager::torrentByName::iterator, bool> p =
1452                pimpl->theTorrents.insert(TIp);
1453       
1454        if (p.second)
1455        {
1456                torrent_internal_ptr me = pimpl->theTorrents.get(TIp->name());         
1457               
1458                if (!startStopped) 
1459                        me->add_to_session();
1460                else
1461                        me->set_state_stopped();
1462        }
1463       
1464        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(to_utf8(file.string()), "addTorrent")
1465}
1466
1467void add_files(libt::torrent_info& t, fs::path const& p, fs::path const& l)
1468{
1469/*      fs::path f(p / l);
1470        if (fs::is_directory(f))
1471        {
1472                for (fs::directory_iterator i(f), end; i != end; ++i)
1473                        add_files(t, p, l / i->leaf());
1474        }
1475        else
1476        {
1477        //      std::cerr << "adding \"" << l.string() << "\"\n";
1478                libt::file fi(f, libt::file::in);
1479                fi.seek(0, libt::file::end);
1480                libtorrent::size_type size = fi.tell();
1481                t.add_file(l, size);
1482        }
1483*/
1484}
1485
1486void bit::newTorrent(wpath filename, wpath files)
1487{
1488/*      try
1489        {
1490       
1491        libtorrent::torrent_info t;
1492        path full_path = pimpl->workingDirectory/"incoming"/files.leaf();
1493       
1494        ofstream out(filename, std::ios_base::binary);
1495       
1496        int piece_size = 256 * 1024;
1497        char const* creator_str = "Halite v0.3 (libtorrent v0.11)";
1498
1499        add_files(t, full_path.branch_path(), full_path.leaf());
1500        t.set_piece_size(piece_size);
1501
1502        libt::storage st(t, full_path.branch_path());
1503        t.add_tracker("http://www.nitcom.com.au/announce.php");
1504        t.set_priv(false);
1505        t.add_node(make_pair("192.168.11.12", 6881));
1506
1507        // calculate the hash for all pieces
1508        int num = t.num_pieces();
1509        std::vector<char> buf(piece_size);
1510        for (int i = 0; i < num; ++i)
1511        {
1512                        st.read(&buf[0], i, 0, t.piece_size(i));
1513                        libtorrent::hasher h(&buf[0], t.piece_size(i));
1514                        t.set_hash(i, h.final());
1515                //      std::cerr << (i+1) << "/" << num << "\r";
1516        }
1517
1518        t.set_creator(creator_str);
1519
1520        // create the torrent and print it to out
1521        libt::entry e = t.create_torrent();
1522        libt::bencode(std::ostream_iterator<char>(out), e);
1523        }
1524        catch (std::exception& e)
1525        {
1526                ::MessageBoxA(0, e.what(), "Create Torrent exception.", 0);
1527        }
1528*/
1529}
1530
1531const TorrentDetails& bit::torrentDetails()
1532{
1533        return torrentDetails_;
1534}
1535
1536const TorrentDetails& bit::updateTorrentDetails(const wstring& focused, const std::set<wstring>& selected)
1537{
1538        try {
1539       
1540        mutex_t::scoped_lock l(torrentDetails_.mutex_); 
1541       
1542        torrentDetails_.clearAll(l);   
1543        torrentDetails_.torrents_.reserve(pimpl->theTorrents.size());
1544       
1545        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); i != e; ++i)
1546        {
1547                wstring utf8Name = (*i).torrent->name();
1548                TorrentDetail_ptr pT = (*i).torrent->getTorrentDetail_ptr();
1549               
1550                if (selected.find(utf8Name) != selected.end())
1551                {
1552                        torrentDetails_.selectedTorrents_.push_back(pT);
1553                }
1554               
1555                if (focused == utf8Name)
1556                        torrentDetails_.selectedTorrent_ = pT;
1557               
1558                torrentDetails_.torrentMap_[(*i).torrent->name()] = pT;
1559                torrentDetails_.torrents_.push_back(pT);
1560        }
1561       
1562        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "updateTorrentDetails")
1563       
1564        return torrentDetails_;
1565}
1566
1567void bit::resumeAll()
1568{
1569        try {
1570               
1571        event().post(shared_ptr<EventDetail>(new EventMsg(L"Resuming torrent.")));
1572       
1573        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); i != e;)
1574        {
1575                wpath file = wpath(pimpl->workingDirectory)/L"torrents"/(*i).torrent->filename();
1576               
1577                if (exists(file))
1578                {               
1579                        try 
1580                        {
1581                               
1582                        (*i).torrent->prepare(file);   
1583
1584                        switch ((*i).torrent->state())
1585                        {
1586                                case TorrentDetail::torrent_stopped:
1587                                        break;
1588                                case TorrentDetail::torrent_paused:
1589                                        (*i).torrent->add_to_session(true);
1590                                        break;
1591                                case TorrentDetail::torrent_active:
1592                                        (*i).torrent->add_to_session(false);
1593                                        break;
1594                                default:
1595                                        assert(false);
1596                        };
1597                       
1598                        ++i;
1599                       
1600                        }
1601                        catch(const libt::duplicate_torrent&)
1602                        {
1603                                hal::event().post(shared_ptr<hal::EventDetail>(
1604                                        new hal::EventDebug(hal::Event::debug, L"Encountered duplicate torrent")));
1605                               
1606                                ++i; // Harmless, don't worry about it.
1607                        }
1608                        catch(const std::exception& e) 
1609                        {
1610                                hal::event().post(shared_ptr<hal::EventDetail>(
1611                                        new hal::EventStdException(hal::Event::warning, e, L"resumeAll")));
1612                               
1613                                pimpl->theTorrents.erase(i++);
1614                        }                       
1615                }
1616                else
1617                {
1618                        pimpl->theTorrents.erase(i++);
1619                }
1620        }
1621       
1622        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "resumeAll")
1623}
1624
1625void bit::closeAll(boost::optional<report_num_active> fn)
1626{
1627        try {
1628       
1629        event().post(shared_ptr<EventDetail>(new EventInfo(L"Stopping all torrents...")));
1630       
1631        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); 
1632                i != e; ++i)
1633        {
1634                if ((*i).torrent->in_session())
1635                {
1636                //      HAL_DEV_MSG(wformat(L"Internalling pausing writeData=%1%") % writeData);
1637                        (*i).torrent->handle().pause(); // Internal pause, not registered in Torrents.xml
1638                }
1639        }
1640       
1641        // Ok this polling loop here is a bit curde, but a blocking wait is actually appropiate.
1642        for (int num_active = -1; num_active != 0; )
1643        {
1644                num_active = 0;
1645
1646                for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); 
1647                                i != e; ++i)
1648                {
1649                        // NB. this checks for an internal paused state.
1650                        if ((*i).torrent->in_session() && !(*i).torrent->handle().is_paused())
1651                                ++num_active;
1652                }
1653               
1654                event().post(shared_ptr<EventDetail>(new EventInfo(wformat(L"%1% still active") % num_active)));
1655
1656                if (fn) (*fn)(num_active);
1657                Sleep(200);
1658        }
1659       
1660        event().post(shared_ptr<EventDetail>(new EventInfo(L"All torrents stopped.")));
1661               
1662        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); 
1663                i != e; ++i)
1664        {
1665                if ((*i).torrent->in_session())
1666                        (*i).torrent->remove_from_session(true);
1667        }
1668       
1669        event().post(shared_ptr<EventDetail>(new EventInfo(L"Fast-resume data written.")));
1670       
1671        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "closeAll")
1672}
1673
1674PeerDetail::PeerDetail(libt::peer_info& peerInfo) :
1675        ipAddress(hal::from_utf8_safe(peerInfo.ip.address().to_string())),
1676        country(L""),
1677        speed(std::make_pair(peerInfo.payload_down_speed, peerInfo.payload_up_speed)),
1678        client(hal::from_utf8_safe(peerInfo.client))
1679{
1680        std::vector<wstring> status_vec;
1681       
1682#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
1683        if (peerInfo.country[0] != 0 && peerInfo.country[1] != 0)
1684                country = (wformat(L"(%1%)") % hal::from_utf8_safe(string(peerInfo.country, 2))).str().c_str();
1685#endif 
1686
1687        if (peerInfo.flags & libt::peer_info::handshake)
1688        {
1689                status_vec.push_back(app().res_wstr(HAL_PEER_HANDSHAKE));
1690        }               
1691        else if (peerInfo.flags & libt::peer_info::connecting)
1692        {
1693                status_vec.push_back(app().res_wstr(HAL_PEER_CONNECTING));
1694        }
1695        else
1696        {
1697        #ifndef TORRENT_DISABLE_ENCRYPTION             
1698                if (peerInfo.flags & libt::peer_info::rc4_encrypted)
1699                        status_vec.push_back(app().res_wstr(HAL_PEER_RC4_ENCRYPTED));           
1700                if (peerInfo.flags & libt::peer_info::plaintext_encrypted)
1701                        status_vec.push_back(app().res_wstr(HAL_PEER_PLAINTEXT_ENCRYPTED));
1702        #endif
1703               
1704                if (peerInfo.flags & libt::peer_info::interesting)
1705                        status_vec.push_back(app().res_wstr(HAL_PEER_INTERESTING));     
1706                if (peerInfo.flags & libt::peer_info::choked)
1707                        status_vec.push_back(app().res_wstr(HAL_PEER_CHOKED)); 
1708                if (peerInfo.flags & libt::peer_info::remote_interested)
1709                        status_vec.push_back(app().res_wstr(HAL_PEER_REMOTE_INTERESTING));     
1710                if (peerInfo.flags & libt::peer_info::remote_choked)
1711                        status_vec.push_back(app().res_wstr(HAL_PEER_REMOTE_CHOKED));   
1712                if (peerInfo.flags & libt::peer_info::supports_extensions)
1713                        status_vec.push_back(app().res_wstr(HAL_PEER_SUPPORT_EXTENSIONS));     
1714        //      if (peerInfo.flags & libt::peer_info::local_connection)                                         // Not sure whats up here?
1715        //              status_vec.push_back(app().res_wstr(HAL_PEER_LOCAL_CONNECTION));                       
1716                if (peerInfo.flags & libt::peer_info::queued)
1717                        status_vec.push_back(app().res_wstr(HAL_PEER_QUEUED));
1718        }
1719       
1720        seed = (peerInfo.flags & libt::peer_info::seed) ? true : false;
1721       
1722        if (!status_vec.empty()) status = status_vec[0];
1723       
1724        if (status_vec.size() > 1)
1725        {
1726                for (size_t i=1; i<status_vec.size(); ++i)
1727                {
1728                        status += L"; ";
1729                        status += status_vec[i];
1730                }
1731        }       
1732}
1733
1734void bit::getAllPeerDetails(const std::string& filename, PeerDetails& peerContainer)
1735{
1736        getAllPeerDetails(from_utf8_safe(filename), peerContainer);
1737}
1738
1739void bit::getAllPeerDetails(const std::wstring& filename, PeerDetails& peerContainer)
1740{
1741        try {
1742       
1743        pimpl->theTorrents.get(filename)->getPeerDetails(peerContainer);
1744       
1745        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getAllPeerDetails")
1746}
1747
1748void bit::getAllFileDetails(const std::string& filename, FileDetails& fileDetails)
1749{
1750        getAllFileDetails(from_utf8_safe(filename), fileDetails);
1751}
1752
1753void bit::getAllFileDetails(const std::wstring& filename, FileDetails& fileDetails)
1754{
1755        try {
1756       
1757        pimpl->theTorrents.get(filename)->getFileDetails(fileDetails);
1758       
1759        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getAllFileDetails")
1760}
1761
1762bool bit::isTorrent(const std::string& filename)
1763{       
1764        return isTorrent(hal::to_wstr_shim(filename));
1765}
1766
1767bool bit::isTorrent(const std::wstring& filename)
1768{       
1769        try {
1770       
1771        return pimpl->theTorrents.exists(filename);
1772       
1773        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "isTorrent")
1774       
1775        return false;
1776}
1777
1778void bit::pauseTorrent(const std::string& filename)
1779{
1780        pauseTorrent(hal::to_wstr_shim(filename));
1781}
1782
1783void bit::pauseTorrent(const std::wstring& filename)
1784{
1785        try {
1786       
1787        pimpl->theTorrents.get(filename)->pause();
1788       
1789        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "pauseTorrent")
1790}
1791
1792void bit::resumeTorrent(const std::string& filename)
1793{
1794        resumeTorrent(hal::to_wstr_shim(filename));
1795}
1796
1797void bit::resumeTorrent(const std::wstring& filename)
1798{
1799        try {
1800       
1801        pimpl->theTorrents.get(filename)->resume();
1802       
1803        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "resumeTorrent")
1804}
1805
1806void bit::stopTorrent(const std::string& filename)
1807{
1808        stopTorrent(hal::to_wstr_shim(filename));
1809}
1810
1811void bit::stopTorrent(const std::wstring& filename)
1812{
1813        try {
1814       
1815        pimpl->theTorrents.get(filename)->stop();
1816       
1817        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "stopTorrent")
1818}
1819
1820bool bit::isTorrentActive(const std::string& filename)
1821{
1822        return isTorrentActive(hal::to_wstr_shim(filename));
1823}
1824
1825bool bit::isTorrentActive(const std::wstring& filename)
1826{
1827        try {
1828       
1829        return pimpl->theTorrents.get(filename)->is_active();
1830       
1831        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "isTorrentActive")
1832       
1833        return false; // ??? is this correct
1834}
1835
1836void bit::reannounceTorrent(const std::string& filename)
1837{
1838        reannounceTorrent(hal::to_wstr_shim(filename));
1839}
1840
1841void bit::reannounceTorrent(const std::wstring& filename)
1842{
1843        try {
1844       
1845        pimpl->theTorrents.get(filename)->handle().force_reannounce();
1846       
1847        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "reannounceTorrent")
1848}
1849/*
1850void bit::setTorrentLogin(const std::string& filename, std::wstring username, std::wstring password)
1851{
1852        setTorrentLogin(hal::to_wstr_shim(filename), username, password);
1853}
1854
1855void bit::setTorrentLogin(const std::wstring& filename, std::wstring username, std::wstring password)
1856{
1857        try {
1858       
1859        pimpl->theTorrents.get(filename)->setTrackerLogin(username, password);
1860       
1861        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentLogin")
1862}
1863
1864std::pair<std::wstring, std::wstring> bit::getTorrentLogin(const std::string& filename)
1865{
1866        return getTorrentLogin(hal::to_wstr_shim(filename));
1867}
1868
1869std::pair<std::wstring, std::wstring> bit::getTorrentLogin(const std::wstring& filename)
1870{
1871        try {
1872       
1873        return pimpl->theTorrents.get(filename)->getTrackerLogin();
1874       
1875        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentLogin")
1876       
1877        return std::make_pair(L"", L"");
1878}
1879*/
1880void bit_impl::removalThread(torrent_internal_ptr pIT, bool wipeFiles)
1881{
1882        try {
1883
1884        if (!wipeFiles)
1885        {
1886                theSession.remove_torrent(pIT->handle());
1887        }
1888        else
1889        {
1890                if (pIT->in_session())
1891                {
1892                        theSession.remove_torrent(pIT->handle(), libt::session::delete_files);
1893                }
1894                else
1895                {
1896                        libt::torrent_info m_info = pIT->infoMemory();
1897                       
1898                        // delete the files from disk
1899                        std::string error;
1900                        std::set<std::string> directories;
1901                       
1902                        for (libt::torrent_info::file_iterator i = m_info.begin_files(true)
1903                                , end(m_info.end_files(true)); i != end; ++i)
1904                        {
1905                                std::string p = (hal::path_to_utf8(pIT->saveDirectory()) / i->path).string();
1906                                fs::path bp = i->path.branch_path();
1907                               
1908                                std::pair<std::set<std::string>::iterator, bool> ret;
1909                                ret.second = true;
1910                                while (ret.second && !bp.empty())
1911                                {
1912                                        std::pair<std::set<std::string>::iterator, bool> ret = 
1913                                                directories.insert((hal::path_to_utf8(pIT->saveDirectory()) / bp).string());
1914                                        bp = bp.branch_path();
1915                                }
1916                                if (!fs::remove(hal::from_utf8(p).c_str()) && errno != ENOENT)
1917                                        error = std::strerror(errno);
1918                        }
1919
1920                        // remove the directories. Reverse order to delete subdirectories first
1921
1922                        for (std::set<std::string>::reverse_iterator i = directories.rbegin()
1923                                , end(directories.rend()); i != end; ++i)
1924                        {
1925                                if (!fs::remove(hal::from_utf8(*i).c_str()) && errno != ENOENT)
1926                                        error = std::strerror(errno);
1927                        }
1928                }
1929        }
1930
1931        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "removalThread")
1932}
1933
1934void bit::removeTorrent(const std::string& filename)
1935{
1936        removeTorrent(hal::to_wstr_shim(filename));
1937}
1938
1939void bit::removeTorrent(const std::wstring& filename)
1940{
1941        try {
1942       
1943        torrent_internal_ptr pTI = pimpl->theTorrents.get(filename);
1944        libt::torrent_handle handle = pTI->handle();
1945        pimpl->theTorrents.erase(filename);
1946       
1947        thread_t t(bind(&bit_impl::removalThread, &*pimpl, pTI, false));       
1948       
1949        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "removeTorrent")
1950}
1951
1952void bit::recheckTorrent(const std::string& filename)
1953{
1954        recheckTorrent(hal::to_wstr_shim(filename));
1955}
1956
1957void bit::recheckTorrent(const std::wstring& filename)
1958{
1959        try {
1960       
1961        pimpl->theTorrents.get(filename)->force_recheck();
1962       
1963        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "recheckTorrent")
1964}
1965
1966void bit::removeTorrentWipeFiles(const std::string& filename)
1967{
1968        removeTorrentWipeFiles(hal::to_wstr_shim(filename));
1969}
1970
1971void bit::removeTorrentWipeFiles(const std::wstring& filename)
1972{
1973        try {
1974       
1975        torrent_internal_ptr pTI = pimpl->theTorrents.get(filename);
1976        libt::torrent_handle handle = pTI->handle();
1977        pimpl->theTorrents.erase(filename);
1978       
1979        thread_t t(bind(&bit_impl::removalThread, &*pimpl, pTI, true)); 
1980       
1981        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "removeTorrentWipeFiles")
1982}
1983
1984void bit::pauseAllTorrents()
1985{       
1986        try {
1987       
1988        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end();
1989                i != e; ++i)
1990        {               
1991                if ((*i).torrent->in_session())
1992                        (*i).torrent->pause();
1993        }
1994       
1995        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "pauseAllTorrents")
1996}
1997
1998void bit::unpauseAllTorrents()
1999{       
2000        try {
2001       
2002        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end();
2003                i != e; ++i)
2004        {
2005                if ((*i).torrent->in_session() && (*i).torrent->state() == TorrentDetail::torrent_paused)
2006                        (*i).torrent->resume();
2007        }
2008       
2009        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "unpauseAllTorrents")
2010}
2011
2012bit::torrent::torrent()
2013{}
2014
2015bit::torrent::torrent(boost::shared_ptr<torrent_internal> p) :
2016        ptr(p)
2017{}
2018
2019bool bit::torrent::is_open() const
2020{
2021        return ptr;
2022}
2023
2024bit::torrent::exec_around_ptr::proxy::proxy(torrent_internal* t) : 
2025        t_(t),
2026        l_(t->mutex_)
2027{
2028        HAL_DEV_MSG(L"Ctor proxy");
2029}
2030
2031bit::torrent::exec_around_ptr::proxy::~proxy() 
2032{
2033        HAL_DEV_MSG(L"Dtor proxy");
2034}
2035
2036const std::wstring bit::torrent::get_name() const
2037{
2038        try {
2039       
2040        return ptr->name();
2041       
2042        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(L"Torrent Unknown", "torrent::get_name()")
2043       
2044        return 0;
2045}
2046
2047float bit::torrent::get_ratio() const
2048{
2049        try {
2050       
2051        return ptr->get_ratio();
2052       
2053        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::get_ratio")
2054       
2055        return 0;
2056}
2057
2058void bit::torrent::set_ratio(float r)
2059{
2060        try {
2061
2062        ptr->set_ratio(r);
2063       
2064        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::set_ratio")
2065}
2066
2067std::pair<int, int> bit::torrent::get_connection_limits() const
2068{
2069        try {
2070       
2071        return ptr->getConnectionLimit();
2072       
2073        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::get_connection_limits")
2074       
2075        return std::make_pair(-1, -1);
2076}
2077
2078void bit::torrent::set_connection_limits(const std::pair<int, int>& l)
2079{
2080        try {
2081       
2082        ptr->setConnectionLimit(l.first, l.second);
2083       
2084        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::set_connection_limits")
2085}
2086
2087std::pair<float, float> bit::torrent::get_rate_limits() const
2088{
2089        try {
2090       
2091        return ptr->getTransferSpeed();
2092       
2093        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::get_rate_limits")
2094       
2095        return std::pair<float, float>(-1.0, -1.0);
2096}
2097
2098void bit::torrent::set_rate_limits(const std::pair<float, float>& l)
2099{
2100        try {
2101       
2102        ptr->setTransferSpeed(l.first, l.second);
2103       
2104        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::set_rate_limits")
2105}
2106
2107wpath bit::torrent::get_save_directory() const
2108{
2109        try {
2110       
2111        return ptr->get_save_directory();
2112       
2113        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::get_save_directory")
2114       
2115        return L"";
2116}
2117
2118void bit::torrent::set_save_directory(const wpath& s)
2119{
2120        try {
2121       
2122        ptr->set_save_directory(s);
2123       
2124        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::set_save_directory")
2125}
2126
2127wpath bit::torrent::get_move_to_directory() const
2128{
2129        try {
2130       
2131        return ptr->get_move_to_directory();
2132       
2133        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::get_save_directory")
2134       
2135        return L"";
2136}
2137
2138void bit::torrent::set_move_to_directory(const wpath& m)
2139{
2140        try {
2141       
2142        ptr->set_move_to_directory(m);
2143       
2144        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::set_move_to_directory")
2145}
2146
2147std::pair<wstring, wstring> bit::torrent::get_tracker_login() const
2148{
2149        try {
2150       
2151        return ptr->getTrackerLogin();
2152       
2153        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("get_tracker_login")
2154       
2155        return std::make_pair(L"!!! exception thrown !!!", L"!!! exception thrown !!!");
2156}
2157
2158void bit::torrent::set_tracker_login(const std::pair<wstring, wstring>& p)
2159{
2160        try {
2161       
2162        ptr->setTrackerLogin(p.first, p.second);
2163       
2164        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::set_tracker_login")
2165}
2166
2167bool bit::torrent::get_is_active() const
2168{
2169        try {
2170       
2171        return ptr->is_active();
2172       
2173        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::get_is_active")
2174       
2175        return L"";
2176}
2177
2178bool bit::torrent::get_in_session() const
2179{
2180        try {
2181       
2182        return ptr->in_session();
2183       
2184        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::get_in_session")
2185       
2186        return L"";
2187}
2188
2189std::vector<tracker_detail> bit::torrent::get_trackers() const
2190{
2191        try {
2192       
2193        return ptr->getTrackers();
2194       
2195        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::get_trackers")
2196       
2197        return std::vector<tracker_detail>();
2198}
2199
2200void bit::torrent::set_trackers(const std::vector<tracker_detail>& trackers)
2201{
2202        try {
2203       
2204        ptr->setTrackers(trackers);
2205       
2206        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::set_trackers")
2207}
2208
2209void bit::torrent::reset_trackers()
2210{
2211        try {
2212       
2213        ptr->resetTrackers();
2214       
2215        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::set_trackers")
2216}
2217
2218void bit::torrent::set_file_priorities(const std::pair<std::vector<int>, int>& p)
2219{
2220        try { 
2221
2222        ptr->setFilePriorities(p.first, p.second);
2223       
2224        } HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH("torrent::set_trackers")
2225}
2226
2227void bit::startEventReceiver()
2228{
2229        pimpl->keepChecking_ = true;
2230        thread_t(bind(&asio::io_service::run, &pimpl->io_));
2231}
2232
2233void bit::stopEventReceiver()
2234{
2235        pimpl->keepChecking_ = false;
2236}
2237
2238int bit::defTorrentMaxConn() { return pimpl->defTorrentMaxConn_; }
2239int bit::defTorrentMaxUpload() { return pimpl->defTorrentMaxUpload_; }
2240float bit::defTorrentDownload() { return pimpl->defTorrentDownload_; }
2241float bit::defTorrentUpload() { return pimpl->defTorrentUpload_; }
2242       
2243};
Note: See TracBrowser for help on using the repository browser.