source: src/halTorrent.cpp @ 344

Revision 344, 52.5 KB checked in by Eoin, 12 years ago (diff)

Deletes files correctly for stopped torrents

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