source: src/halTorrent.cpp @ 333

Revision 333, 51.5 KB checked in by Eoin, 12 years ago (diff)

UI fully converted to Autosize.

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