source: src/halTorrent.cpp @ 345

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

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