source: trunk/src/halTorrentInternal.hpp @ 519

Revision 519, 43.2 KB checked in by Eoin, 11 years ago (diff)

Adding a 'queued view' mode to main listview.

Line 
1
2//         Copyright Eóin O'Callaghan 2006 - 2008.
3// Distributed under the Boost Software License, Version 1.0.
4//    (See accompanying file LICENSE_1_0.txt or copy at
5//          http://www.boost.org/LICENSE_1_0.txt)
6
7#pragma once
8
9#define HALITE_VERSION                                  0, 3, 1, 505
10#define HALITE_VERSION_STRING                   "v 0.3.1.5 dev 505"
11#define HALITE_FINGERPRINT                              "HL", 0, 3, 1, 5
12
13#ifndef HAL_NA
14#define HAL_NA 40013
15#endif
16
17#define HAL_TORRENT_EXT_BEGIN                           41000
18#define LBT_EVENT_TORRENT_FINISHED                      HAL_TORRENT_EXT_BEGIN + 1
19#define HAL_PEER_BAN_ALERT                                      HAL_TORRENT_EXT_BEGIN + 2
20#define HAL_HASH_FAIL_ALERT                                     HAL_TORRENT_EXT_BEGIN + 3
21#define HAL_URL_SEED_ALERT                                      HAL_TORRENT_EXT_BEGIN + 5
22#define HAL_TRACKER_WARNING_ALERT                       HAL_TORRENT_EXT_BEGIN + 4
23#define HAL_TRACKER_ANNOUNCE_ALERT                      HAL_TORRENT_EXT_BEGIN + 6
24#define HAL_TRACKER_ALERT                                       HAL_TORRENT_EXT_BEGIN + 7
25#define HAL_TRACKER_REPLY_ALERT                         HAL_TORRENT_EXT_BEGIN + 8
26#define LBT_EVENT_TORRENT_PAUSED                        HAL_TORRENT_EXT_BEGIN + 9
27#define HAL_FAST_RESUME_ALERT                           HAL_TORRENT_EXT_BEGIN + 10
28#define HAL_PIECE_FINISHED_ALERT                        HAL_TORRENT_EXT_BEGIN + 11
29#define HAL_BLOCK_FINISHED_ALERT                        HAL_TORRENT_EXT_BEGIN + 12
30#define HAL_BLOCK_DOWNLOADING_ALERT                     HAL_TORRENT_EXT_BEGIN + 13
31#define HAL_LISTEN_SUCCEEDED_ALERT                      HAL_TORRENT_EXT_BEGIN + 14
32#define HAL_LISTEN_FAILED_ALERT                         HAL_TORRENT_EXT_BEGIN + 15
33#define HAL_IPFILTER_ALERT                                      HAL_TORRENT_EXT_BEGIN + 16
34#define HAL_INCORRECT_ENCODING_LEVEL            HAL_TORRENT_EXT_BEGIN + 17
35#define HAL_INCORRECT_CONNECT_POLICY            HAL_TORRENT_EXT_BEGIN + 18
36#define HAL_PEER_ALERT                                          HAL_TORRENT_EXT_BEGIN + 19
37#define HAL_LISTEN_V6_FAILED_ALERT                      HAL_TORRENT_EXT_BEGIN + 20
38#define HAL_TORRENT_LOAD_FILTERS                        HAL_TORRENT_EXT_BEGIN + 21
39#define HAL_EXTERNAL_IP_ALERT                           HAL_TORRENT_EXT_BEGIN + 22
40#define HAL_PORTMAP_ERROR_ALERT                         HAL_TORRENT_EXT_BEGIN + 23
41#define HAL_PORTMAP_ALERT                                       HAL_TORRENT_EXT_BEGIN + 24
42#define HAL_PORTMAP_TYPE_PMP                            HAL_TORRENT_EXT_BEGIN + 25                     
43#define HAL_PORTMAP_TYPE_UPNP                           HAL_TORRENT_EXT_BEGIN + 26
44#define HAL_FILE_ERROR_ALERT                            HAL_TORRENT_EXT_BEGIN + 27
45#define HAL_DHT_REPLY_ALERT                                     HAL_TORRENT_EXT_BEGIN + 28
46
47#define HAL_TORRENT_INT_BEGIN                           42000
48#define HAL_PEER_INTERESTING                    HAL_TORRENT_INT_BEGIN + 1
49#define HAL_PEER_CHOKED                         HAL_TORRENT_INT_BEGIN + 2
50#define HAL_PEER_REMOTE_INTERESTING                     HAL_TORRENT_INT_BEGIN + 3
51#define HAL_PEER_REMOTE_CHOKED                          HAL_TORRENT_INT_BEGIN + 4
52#define HAL_PEER_SUPPORT_EXTENSIONS                     HAL_TORRENT_INT_BEGIN + 5
53#define HAL_PEER_LOCAL_CONNECTION                       HAL_TORRENT_INT_BEGIN + 6
54#define HAL_PEER_HANDSHAKE                                      HAL_TORRENT_INT_BEGIN + 7
55#define HAL_PEER_CONNECTING                                     HAL_TORRENT_INT_BEGIN + 8
56#define HAL_PEER_QUEUED                                         HAL_TORRENT_INT_BEGIN + 9
57#define HAL_PEER_RC4_ENCRYPTED                          HAL_TORRENT_INT_BEGIN + 10
58#define HAL_PEER_PLAINTEXT_ENCRYPTED            HAL_TORRENT_INT_BEGIN + 11
59#define HAL_TORRENT_QUEUED_CHECKING                     HAL_TORRENT_INT_BEGIN + 12
60#define HAL_TORRENT_CHECKING_FILES                      HAL_TORRENT_INT_BEGIN + 13
61#define HAL_TORRENT_CONNECTING                          HAL_TORRENT_INT_BEGIN + 14
62#define HAL_TORRENT_DOWNLOADING                         HAL_TORRENT_INT_BEGIN + 15
63#define HAL_TORRENT_FINISHED                            HAL_TORRENT_INT_BEGIN + 16
64#define HAL_TORRENT_SEEDING                                     HAL_TORRENT_INT_BEGIN + 17
65#define HAL_TORRENT_ALLOCATING                          HAL_TORRENT_INT_BEGIN + 18
66#define HAL_TORRENT_QUEUED                                      HAL_TORRENT_INT_BEGIN + 19
67#define HAL_TORRENT_STOPPED                                     HAL_TORRENT_INT_BEGIN + 20
68#define HAL_TORRENT_PAUSED                                      HAL_TORRENT_INT_BEGIN + 21
69#define HAL_TORRENT_STOPPING                            HAL_TORRENT_INT_BEGIN + 22
70#define HAL_TORRENT_PAUSING                                     HAL_TORRENT_INT_BEGIN + 23
71#define HAL_TORRENT_METADATA                    HAL_TORRENT_INT_BEGIN + 24
72#define HAL_NEWT_CREATING_TORRENT                       HAL_TORRENT_INT_BEGIN + 25
73#define HAL_NEWT_HASHING_PIECES                 HAL_TORRENT_INT_BEGIN + 26
74#define HAL_TORRENT_IMPORT_FILTERS              HAL_TORRENT_INT_BEGIN + 27
75#define HAL_INT_NEWT_ADD_PEERS_WEB              HAL_TORRENT_INT_BEGIN + 28
76#define HAL_INT_NEWT_ADD_PEERS_DHT              HAL_TORRENT_INT_BEGIN + 29
77#define HAL_NEWT_CREATION_CANCELED              HAL_TORRENT_INT_BEGIN + 30
78
79#ifndef RC_INVOKED
80
81#include <libtorrent/file.hpp>
82#include <libtorrent/hasher.hpp>
83#include <libtorrent/storage.hpp>
84#include <libtorrent/file_pool.hpp>
85#include <libtorrent/alert_types.hpp>
86#include <libtorrent/entry.hpp>
87#include <libtorrent/bencode.hpp>
88#include <libtorrent/session.hpp>
89#include <libtorrent/ip_filter.hpp>
90#include <libtorrent/torrent_handle.hpp>
91#include <libtorrent/peer_connection.hpp>
92#include <libtorrent/extensions/metadata_transfer.hpp>
93#include <libtorrent/extensions/ut_pex.hpp>
94
95#include <boost/tuple/tuple.hpp>
96#include <boost/enable_shared_from_this.hpp>
97#include <boost/multi_index_container.hpp>
98#include <boost/multi_index/ordered_index.hpp>
99#include <boost/multi_index/indexed_by.hpp>
100#include <boost/multi_index/identity.hpp>
101#include <boost/multi_index/member.hpp>
102#include <boost/multi_index/tag.hpp>
103#include <boost/serialization/shared_ptr.hpp>
104
105#include "halIni.hpp"
106#include "halTypes.hpp"
107#include "halSignaler.hpp"
108
109namespace hal
110{
111class TorrentInternalOld;
112class torrent_internal;
113}
114
115BOOST_CLASS_VERSION(hal::TorrentInternalOld, 9)
116BOOST_CLASS_VERSION(hal::torrent_internal, 2)
117
118namespace hal
119{
120
121namespace libt = libtorrent;
122
123inline
124libt::entry haldecode(const wpath &file) 
125{
126        fs::ifstream ifs(file, fs::ifstream::binary);
127        if (ifs.is_open()) 
128        {
129                ifs.unsetf(fs::ifstream::skipws);
130                return libt::bdecode(std::istream_iterator<char>(ifs), std::istream_iterator<char>());
131        }
132        else return libt::entry();
133}
134
135inline
136bool halencode(const wpath &file, const libt::entry &e) 
137{
138        fs::ofstream ofs(file, fs::ofstream::binary);
139
140        if (!ofs.is_open()) 
141                return false;
142       
143        libt::bencode(std::ostream_iterator<char>(ofs), e);
144        return true;
145}
146
147inline path path_to_utf8(const wpath& wp)
148{
149        return path(to_utf8(wp.string()));
150}
151
152inline wpath path_from_utf8(const path& p)
153{
154        return wpath(from_utf8(p.string()));
155}
156
157inline
158std::pair<std::string, std::string> extract_names(const wpath &file)
159{
160        if (fs::exists(file)) 
161        {       
162                libt::torrent_info info(haldecode(file));
163
164                std::string name = info.name(); 
165                std::string filename = name;
166
167                if (!boost::find_last(filename, ".torrent")) 
168                                filename += ".torrent";
169               
170                event_log.post(shared_ptr<EventDetail>(new EventMsg(
171                        wformat(L"Loaded names: %1%, %2%") % from_utf8(name) % from_utf8(filename))));
172
173                return std::make_pair(name, filename);
174        }
175        else
176                return std::make_pair("", "");
177}
178
179class invalidTorrent : public std::exception
180{
181public:
182        invalidTorrent(const wstring& who) :
183                who_(who)
184        {}
185       
186        virtual ~invalidTorrent() throw () {}
187
188        wstring who() const throw ()
189        {
190                return who_;
191        }       
192       
193private:
194        wstring who_;   
195};
196       
197template<typename T>
198class transfer_tracker
199{
200public:
201        transfer_tracker() :
202                total_(0),
203                total_offset_(0)
204        {}
205       
206        transfer_tracker(T total) :
207                total_(total),
208                total_offset_(0)
209        {}
210       
211        transfer_tracker(T total, T offset) :
212                total_(total),
213                total_offset_(offset)
214        {}
215       
216        void reset(T total) const
217        {
218                total_ = total;
219                total_offset_ = 0;
220        }
221       
222        T update(T rel_total) const
223        {
224                total_ += (rel_total - total_offset_);
225                total_offset_ = rel_total;
226               
227                return total_;
228        }
229       
230        void setOffset(T offset) const
231        {
232                total_offset_ = offset;
233        }
234       
235        operator T() const { return total_; }
236       
237        friend class boost::serialization::access;
238        template<class Archive>
239        void serialize(Archive& ar, const unsigned int version)
240        {
241                ar & boost::serialization::make_nvp("total", total_);
242        }
243       
244private:
245        mutable T total_;
246        mutable T total_offset_;
247};
248
249class duration_tracker
250{
251public:
252        duration_tracker() :
253                total_(boost::posix_time::time_duration(0,0,0,0), 
254                        boost::posix_time::time_duration(0,0,0,0))
255        {}
256       
257        boost::posix_time::time_duration update() const
258        {
259                if (start_.is_not_a_date_time()) 
260                        start_ = boost::posix_time::second_clock::universal_time();
261
262                if (static_cast<boost::posix_time::time_duration>(total_).is_special()) 
263                        total_.setOffset(boost::posix_time::time_duration(0,0,0,0));
264               
265                return total_.update(boost::posix_time::second_clock::universal_time() - start_);
266        }
267       
268        void reset() const
269        {
270                total_.setOffset(boost::posix_time::time_duration(0,0,0,0));
271                start_ = boost::posix_time::second_clock::universal_time();
272        }
273       
274        friend class boost::serialization::access;
275        template<class Archive>
276        void serialize(Archive& ar, const unsigned int version)
277        {
278                ar & boost::serialization::make_nvp("total", total_);
279        }
280       
281        operator boost::posix_time::time_duration() const { return total_; }
282       
283private:
284        transfer_tracker<boost::posix_time::time_duration> total_;     
285        mutable boost::posix_time::ptime start_;               
286};
287       
288class TorrentInternalOld
289{
290public: 
291    friend class boost::serialization::access;
292    template<class Archive>
293    void serialize(Archive& ar, const unsigned int version)
294    {
295                using boost::serialization::make_nvp;
296
297        ar & make_nvp("transferLimit", transferLimit_);
298        ar & make_nvp("connections", connections_);
299        ar & make_nvp("uploads", uploads_);     
300               
301                if (version > 6) {
302                        ar & make_nvp("filename", filename_);
303                }
304                else 
305                {
306                        wstring originalFilename;
307                        ar & make_nvp("filename", originalFilename);
308                       
309                        updatePreVersion7Files(originalFilename);
310                }
311               
312        ar & make_nvp("saveDirectory", save_directory_);
313               
314                if (version > 7) {
315                        ar & make_nvp("payloadUploaded_", payloadUploaded_);
316                        ar & make_nvp("payloadDownloaded_", payloadDownloaded_);
317                        ar & make_nvp("uploaded_", uploaded_);
318                        ar & make_nvp("downloaded_", downloaded_);     
319                        ar & make_nvp("ratio", ratio_); 
320                } 
321                else if (version > 3) {
322                        ar & make_nvp("payloadUploaded_", payloadUploaded_);
323                        ar & make_nvp("payloadDownloaded_", payloadDownloaded_);
324                        ar & make_nvp("uploaded_", uploaded_);
325                        ar & make_nvp("downloaded_", downloaded_);             
326                } 
327                else if (version > 1)
328                {
329                        ar & make_nvp("totalUploaded", totalUploaded_);
330                        ar & make_nvp("ratio", ratio_);
331                       
332                        payloadUploaded_.reset(totalUploaded_);
333                }
334               
335                if (version > 0) {
336                        ar & make_nvp("trackerUsername", trackerUsername_);
337                        ar & make_nvp("trackerPassword", trackerPassword_);
338                }
339                if (version > 1) {
340                        ar & make_nvp("state", state_);
341                        ar & make_nvp("trackers", trackers_);
342                }
343       
344                if (version > 2) {
345                        ar & make_nvp("resolve_countries", resolve_countries_);
346                }
347                if (version > 4) {
348                        ar & make_nvp("file_priorities", filePriorities_);
349                }
350                if (version > 5) {
351                        ar & make_nvp("startTime", startTime_);
352                        ar & make_nvp("activeDuration", activeDuration_);
353                        ar & make_nvp("seedingDuration", seedingDuration_);
354                }
355                if (version > 6) {
356                        ar & make_nvp("name", name_);
357                        ar & make_nvp("compactStorage", compactStorage_);
358                        ar & make_nvp("finishTime", finishTime_);
359                }
360                if (version > 8) {
361                        ar & make_nvp("progress", progress_);
362                }
363    }
364       
365        void extractNames(libt::entry& metadata)
366        {               
367                libt::torrent_info info(metadata);                             
368                name_ = hal::from_utf8_safe(info.name());
369               
370                filename_ = name_;
371                if (!boost::find_last(filename_, L".torrent")) 
372                                filename_ += L".torrent";
373               
374                event_log.post(shared_ptr<EventDetail>(new EventMsg(
375                        wformat(L"Loaded names: %1%, %2%") % name_ % filename_)));
376        }
377       
378        void updatePreVersion7Files(wstring originalFilename)
379        {
380                try 
381                {
382
383                wpath oldFile = app().working_directory()/L"torrents"/originalFilename;
384               
385                if (fs::exists(oldFile)) 
386                        extractNames(haldecode(oldFile));
387               
388                wpath oldResumeFile = app().working_directory()/L"resume"/originalFilename;
389               
390                if (filename_ != originalFilename)
391                {
392                        fs::rename(oldFile, app().working_directory()/L"torrents"/filename_);
393                       
394                        if (fs::exists(oldResumeFile))
395                                fs::rename(oldResumeFile, app().working_directory()/L"resume"/filename_);
396                }
397               
398                }
399                catch(std::exception &e) 
400                {               
401                        hal::event_log.post(boost::shared_ptr<hal::EventDetail>(
402                                new hal::EventStdException(event_logger::critical, e, L"updatePreVersion7Files"))); 
403                }
404        }
405       
406        std::pair<float, float> transferLimit_;
407       
408        unsigned state_;
409        int connections_;
410        int uploads_;
411        bool in_session_;
412        float ratio_;
413        bool resolve_countries_;
414       
415        wstring filename_;
416        wstring name_;
417        wstring save_directory_;
418        wstring originalFilename_;
419        libt::torrent_handle handle_;   
420       
421        libt::entry metadata_;
422        libt::entry resumedata_;
423       
424        wstring trackerUsername_;       
425        wstring trackerPassword_;
426       
427        boost::int64_t totalUploaded_;
428        boost::int64_t totalBase_;
429       
430        transfer_tracker<boost::int64_t> payloadUploaded_;
431        transfer_tracker<boost::int64_t> payloadDownloaded_;
432        transfer_tracker<boost::int64_t> uploaded_;
433        transfer_tracker<boost::int64_t> downloaded_;
434       
435        boost::posix_time::ptime startTime_;
436        boost::posix_time::ptime finishTime_;
437        duration_tracker activeDuration_;
438        duration_tracker seedingDuration_;
439       
440        std::vector<tracker_detail> trackers_;
441        std::vector<libt::announce_entry> torrent_trackers_;
442        std::vector<libt::peer_info> peers_;   
443        std::vector<int> filePriorities_;
444       
445        float progress_;
446       
447        libt::torrent_status statusMemory_;
448        FileDetails fileDetailsMemory_;
449       
450        bool compactStorage_;
451};
452
453
454struct signalers
455{
456        signaler<> torrent_finished;
457        signaler<> torrent_paused;
458};
459
460
461class torrent_internal;
462typedef shared_ptr<torrent_internal> torrent_internal_ptr;
463
464struct torrent_standalone :
465        public hal::IniBase<torrent_standalone>
466{
467        typedef torrent_standalone thisClass;
468        typedef hal::IniBase<thisClass> iniClass;
469
470        torrent_standalone() :
471                iniClass("torrent")
472        {}
473
474        torrent_standalone(torrent_internal_ptr t) :
475                iniClass("torrent"),
476                torrent(t),
477                save_time(pt::second_clock::universal_time())
478        {}
479
480        torrent_internal_ptr torrent;
481        pt::ptime save_time;
482
483    friend class boost::serialization::access;
484    template<class Archive>
485    void serialize(Archive& ar, const unsigned int version)
486    {
487                ar & boost::serialization::make_nvp("torrent", torrent);
488                ar & boost::serialization::make_nvp("save_time", save_time);
489    }
490};
491
492class torrent_internal :
493        public boost::enable_shared_from_this<torrent_internal>,
494        private boost::noncopyable
495{
496        friend class bit_impl; 
497        friend class bit::torrent::exec_around_ptr::proxy;
498
499public:
500        #define TORRENT_INTERNALS_DEFAULTS \
501                originalFilename_(L""), \
502                transferLimit_(std::pair<float, float>(-1, -1)), \
503                connections_(-1), \
504                uploads_(-1), \
505                ratio_(0), \
506                resolve_countries_(true), \
507                totalUploaded_(0), \
508                totalBase_(0), \
509                progress_(0), \
510                startTime_(boost::posix_time::second_clock::universal_time()), \
511                in_session_(false)
512               
513        torrent_internal() :   
514                TORRENT_INTERNALS_DEFAULTS,
515                compactStorage_(true),
516                state_(torrent_details::torrent_stopped)
517        {}
518       
519        torrent_internal(wpath filename, wpath saveDirectory, bool compactStorage, wpath move_to_directory=L"") :
520                TORRENT_INTERNALS_DEFAULTS,
521                save_directory_(saveDirectory.string()),
522                move_to_directory_(move_to_directory.string()),
523                compactStorage_(compactStorage),       
524                state_(torrent_details::torrent_stopped)
525        {
526                assert(the_session_);           
527                prepare(filename);
528        }
529       
530        torrent_internal(const TorrentInternalOld& t) :
531                transferLimit_(t.transferLimit_),
532                state_(t.state_),
533                connections_(t.connections_),
534                uploads_(t.uploads_),
535                ratio_(t.ratio_),
536                resolve_countries_(t.resolve_countries_),
537                filename_(t.filename_),
538                name_(t.name_),
539                save_directory_(t.save_directory_),
540                originalFilename_(t.originalFilename_),
541                handle_(t.handle_),
542                metadata_(t.metadata_),
543                resumedata_(t.resumedata_),
544                trackerUsername_(t.trackerUsername_),   
545                trackerPassword_(t.trackerPassword_),
546                totalUploaded_(t.totalUploaded_),
547                totalBase_(t.totalBase_),
548                payloadUploaded_(t.payloadUploaded_),
549                payloadDownloaded_(t.payloadDownloaded_),
550                uploaded_(t.uploaded_),
551                downloaded_(t.downloaded_),
552                startTime_(t.startTime_),
553                finishTime_(t.finishTime_),
554                activeDuration_(t.activeDuration_),
555                seedingDuration_(t.seedingDuration_),
556                trackers_(t.trackers_),
557                torrent_trackers_(t.torrent_trackers_),
558                peers_(t.peers_),
559                filePriorities_(t.filePriorities_),
560                progress_(t.progress_),
561                statusMemory_(t.statusMemory_),
562                fileDetailsMemory_(t.fileDetailsMemory_),
563                compactStorage_(t.compactStorage_)
564        {}
565       
566        #undef TORRENT_INTERNALS_DEFAULTS
567       
568        torrent_details_ptr gettorrent_details_ptr()
569        {       
570                mutex_t::scoped_lock l(mutex_);
571
572                try
573                {
574
575                if (in_session())
576                {
577                        statusMemory_ = handle_.status();
578                        progress_ = statusMemory_.progress;
579                }
580                else
581                {
582                        // Wipe these cause they don't make sense for a non-active torrent.
583                       
584                        statusMemory_.download_payload_rate = 0;
585                        statusMemory_.upload_payload_rate = 0;
586                        statusMemory_.next_announce = boost::posix_time::seconds(0);           
587                }
588               
589                wstring state;
590               
591                switch (state_)
592                {
593                case torrent_details::torrent_paused:
594                        state = app().res_wstr(HAL_TORRENT_PAUSED);
595                        break;
596                       
597                case torrent_details::torrent_pausing:
598                        state = app().res_wstr(HAL_TORRENT_PAUSING);
599                        break;
600                       
601                case torrent_details::torrent_stopped:
602                        state = app().res_wstr(HAL_TORRENT_STOPPED);
603                        break;
604                       
605                case torrent_details::torrent_stopping:
606                        state = app().res_wstr(HAL_TORRENT_STOPPING);
607                        break;
608                       
609                default:
610                        switch (statusMemory_.state)
611                        {
612                        case libt::torrent_status::queued_for_checking:
613                                state = app().res_wstr(HAL_TORRENT_QUEUED_CHECKING);
614                                break;
615                        case libt::torrent_status::checking_files:
616                                state = app().res_wstr(HAL_TORRENT_CHECKING_FILES);
617                                break;
618                        case libt::torrent_status::connecting_to_tracker:
619                                state = app().res_wstr(HAL_TORRENT_CONNECTING);
620                                break;
621                        case libt::torrent_status::downloading_metadata:
622                                state = app().res_wstr(HAL_TORRENT_METADATA);
623                                break;
624                        case libt::torrent_status::downloading:
625                                state = app().res_wstr(HAL_TORRENT_DOWNLOADING);
626                                break;
627                        case libt::torrent_status::finished:
628                                state = app().res_wstr(HAL_TORRENT_FINISHED);
629                                break;
630                        case libt::torrent_status::seeding:
631                                state = app().res_wstr(HAL_TORRENT_SEEDING);
632                                break;
633                        case libt::torrent_status::allocating:
634                                state = app().res_wstr(HAL_TORRENT_ALLOCATING);
635                                break;
636                        }       
637                }
638               
639                pt::time_duration td(pt::pos_infin);
640               
641                if (statusMemory_.download_payload_rate != 0)
642                {
643                        td = boost::posix_time::seconds(       
644                                long(float(statusMemory_.total_wanted-statusMemory_.total_wanted_done) / statusMemory_.download_payload_rate));
645                }
646               
647                totalUploaded_ += (statusMemory_.total_payload_upload - totalBase_);
648                totalBase_ = statusMemory_.total_payload_upload;
649               
650                uploaded_.update(statusMemory_.total_upload);
651                payloadUploaded_.update(statusMemory_.total_payload_upload);
652                downloaded_.update(statusMemory_.total_download);
653                payloadDownloaded_.update(statusMemory_.total_payload_download);
654               
655                if (is_active())
656                {
657                        activeDuration_.update();
658                       
659                        if (libt::torrent_status::seeding == statusMemory_.state)
660                                seedingDuration_.update();
661                }       
662               
663                boost::tuple<size_t, size_t, size_t, size_t> connections = updatePeers();       
664
665                return torrent_details_ptr(new torrent_details(name_, filename_, saveDirectory().string(), state, hal::from_utf8(statusMemory_.current_tracker), 
666                        std::pair<float, float>(statusMemory_.download_payload_rate, statusMemory_.upload_payload_rate),
667                        progress_, statusMemory_.distributed_copies, statusMemory_.total_wanted_done, statusMemory_.total_wanted, uploaded_, payloadUploaded_,
668                        downloaded_, payloadDownloaded_, connections, ratio_, td, statusMemory_.next_announce, activeDuration_, seedingDuration_, startTime_, finishTime_, handle_.queue_position()));
669
670                }
671                catch (const libt::invalid_handle&)
672                {
673                        event_log.post(shared_ptr<EventDetail>(
674                                new EventInvalidTorrent(event_logger::critical, event_logger::invalidTorrent, to_utf8(name_), "gettorrent_details_ptr")));
675                }
676                catch (const std::exception& e)
677                {
678                        event_log.post(shared_ptr<EventDetail>(
679                                new EventTorrentException(event_logger::critical, event_logger::torrentException, e.what(), to_utf8(name_), "gettorrent_details_ptr")));
680                }
681               
682                return torrent_details_ptr(new torrent_details(name_, filename_, saveDirectory().string(), app().res_wstr(HAL_TORRENT_STOPPED), app().res_wstr(HAL_NA)));
683        }
684
685        void setTransferSpeed(float down, float up)
686        {       
687                mutex_t::scoped_lock l(mutex_);
688
689                transferLimit_ = std::make_pair(down, up);
690               
691                applyTransferSpeed();
692        }
693
694        void setConnectionLimit(int maxConn, int maxUpload)             
695        {
696                mutex_t::scoped_lock l(mutex_);
697
698                connections_ = maxConn;
699                uploads_ = maxUpload;
700               
701                applyConnectionLimit();
702        }
703
704        std::pair<float, float> getTransferSpeed()
705        {
706                return transferLimit_;
707        }
708
709        std::pair<int, int> getConnectionLimit()
710        {
711                return std::make_pair(connections_, uploads_);
712        }
713       
714        const wstring& name() const { return name_; }
715       
716        void set_ratio(float ratio) 
717        { 
718                if (ratio < 0) ratio = 0;
719                ratio_ = ratio; 
720               
721                apply_ratio();
722        }
723       
724        float get_ratio()
725        {
726                return ratio_;
727        }
728       
729        void add_to_session(bool paused = false)
730        {
731                try
732                {
733
734                mutex_t::scoped_lock l(mutex_); 
735                assert(the_session_ != 0);
736
737                HAL_DEV_MSG(wformat(L"add_to_session() paused=%1%") % paused);
738               
739                if (!in_session()) 
740                {                       
741                        path dir = path_to_utf8(save_directory_);
742                       
743                        libt::storage_mode_t storage = libt::storage_mode_sparse;
744                       
745                        if (compactStorage_)
746                                storage = libt::storage_mode_compact;
747                       
748                        handle_ = the_session_->add_torrent(metadata_, dir, resumedata_, storage, paused);                     
749                        assert(handle_.is_valid());
750                       
751                        clear_resume_data();
752                       
753                        in_session_ = true;
754                        if (paused)
755                                state_ = torrent_details::torrent_paused;       
756                        else
757                                state_ = torrent_details::torrent_active;       
758                               
759                        applySettings();
760                        handle_.force_reannounce();
761                }       
762
763                assert(in_session());
764                HAL_DEV_MSG(L"Added to session");
765
766                }
767                catch(std::exception& e)
768                {
769                        hal::event_log.post(boost::shared_ptr<hal::EventDetail>(
770                                new hal::EventStdException(event_logger::critical, e, L"addToSession"))); 
771                }
772        }
773       
774        void remove_from_session(bool writeData=true)
775        {
776                try
777                {
778
779                mutex_t::scoped_lock l(mutex_);
780                assert(in_session());
781
782                HAL_DEV_MSG(wformat(L"remove_from_session() writeData=%1%") % writeData);
783               
784                if (writeData)
785                {
786                        HAL_DEV_MSG(L"getting resume data");
787                        resumedata_ = handle_.write_resume_data(); // Update the fast-resume data
788                        HAL_DEV_MSG(L"writing resume data");
789                        write_resume_data();
790
791                        torrent_standalone tsa(shared_from_this());
792                        tsa.save_standalone(workingDir_/L"torrents"/(name_+L".xml"));
793                }
794               
795                HAL_DEV_MSG(L"removing handle from session");
796                the_session_->remove_torrent(handle_);
797                in_session_ = false;
798
799                assert(!in_session()); 
800                HAL_DEV_MSG(L"Removed from session!");
801
802                }
803                catch(std::exception& e)
804                {
805                        hal::event_log.post(boost::shared_ptr<hal::EventDetail>(
806                                new hal::EventStdException(event_logger::critical, e, L"removeFromSession"))); 
807                }
808        }
809       
810        bool in_session() const
811        { 
812                mutex_t::scoped_lock l(mutex_);
813
814                return (in_session_ && the_session_ != 0 && handle_.is_valid());
815        }
816       
817        void resume()
818        {
819                mutex_t::scoped_lock l(mutex_);
820
821                if (state_ == torrent_details::torrent_stopped)
822                {       
823                        add_to_session(false);
824                        assert(in_session());                   
825                }
826                else
827                {
828                        assert(in_session());
829                        handle_.resume();
830                }       
831               
832                state_ = torrent_details::torrent_active;                       
833                assert(!handle_.is_paused());
834        }
835       
836        void pause()
837        {
838                mutex_t::scoped_lock l(mutex_);
839
840                if (state_ == torrent_details::torrent_stopped)
841                {       
842                        add_to_session(true);
843
844                        assert(in_session());
845                //      assert(handle_.is_paused());
846                }
847                else
848                {
849                        assert(in_session());
850
851                        handle_.pause();
852                        signals().torrent_paused.disconnect_all_once();
853                        signals().torrent_paused.connect_once(bind(&torrent_internal::completed_pause, this));
854
855                        state_ = torrent_details::torrent_pausing;     
856                }                       
857        }
858       
859        void stop()
860        {
861                mutex_t::scoped_lock l(mutex_);
862
863                if (state_ != torrent_details::torrent_stopped)
864                {
865                        if (state_ == torrent_details::torrent_active)
866                        {
867                                assert(in_session());
868
869                                signals().torrent_paused.disconnect_all_once();
870                                signals().torrent_paused.connect_once(bind(&torrent_internal::completed_stop, this));
871                                handle_.pause();
872
873                                state_ = torrent_details::torrent_stopping;
874                        }
875                        else if (state_ == torrent_details::torrent_paused)
876                        {                       
877                                remove_from_session();
878                                state_ = torrent_details::torrent_stopped;                             
879                        }
880                }
881        }
882
883        void set_state_stopped()
884        {
885                state_ = torrent_details::torrent_stopped;
886        }
887
888        void force_recheck()
889        {
890                mutex_t::scoped_lock l(mutex_);         
891                HAL_DEV_MSG(L"force_recheck()");
892
893                switch (state_)
894                {
895                case torrent_details::torrent_stopped:
896                        clear_resume_data();
897                        resume();
898                        break;
899
900                case torrent_details::torrent_stopping:
901                case torrent_details::torrent_pausing:
902                        signals().torrent_paused.disconnect_all_once();
903
904                case torrent_details::torrent_active:
905                        signals().torrent_paused.disconnect_all_once();
906                        signals().torrent_paused.connect_once(bind(&torrent_internal::handle_recheck, this));
907                        handle_.pause();
908                        state_ = torrent_details::torrent_pausing;
909                        break;
910
911                default:
912                        assert(false);
913                };
914        }
915       
916        void write_resume_data()
917        {                                       
918                HAL_DEV_MSG(L"write_resume_data()");
919                wpath resumeDir = workingDir_/L"resume";
920               
921                if (!exists(resumeDir))
922                        create_directory(resumeDir);
923                               
924                bool halencode_result = halencode(resumeDir/filename_, resumedata_);
925                assert(halencode_result);
926                HAL_DEV_MSG(L"Written!");
927        }
928       
929        void clear_resume_data()
930        {
931                wpath resumeFile = workingDir_/L"resume"/filename_;
932               
933                if (exists(resumeFile))
934                        remove(resumeFile);
935
936                resumedata_ = libt::entry();
937        }
938
939        const wpath get_save_directory()
940        {
941                return save_directory_;
942        }
943
944        void set_save_directory(wpath s, bool force=false)
945        {
946                if (in_session() && !is_finished() &&
947                                s != path_from_utf8(handle_.save_path()))
948                {
949                        handle_.move_storage(path_to_utf8(s));
950                        save_directory_ = s;
951                }
952                else if (!in_session() && force)
953                {
954                        save_directory_ = s;
955                }
956        }
957
958        const wpath get_move_to_directory()
959        {
960                return move_to_directory_;
961        }
962       
963        void set_move_to_directory(wpath m)
964        {
965                if (is_finished() && !m.empty())
966                {
967                        if (m != path_from_utf8(handle_.save_path()))
968                        {
969                                handle_.move_storage(path_to_utf8(m));
970                                save_directory_ = move_to_directory_ = m;
971                        }
972                }
973                else
974                {
975                        move_to_directory_ = m;
976                }
977        }
978
979        bool is_finished()
980        {
981                if (in_session())
982                {
983                        libt::torrent_status::state_t s = handle_.status().state;
984
985                        return (s == libt::torrent_status::seeding ||
986                                                s == libt::torrent_status::finished);
987                }
988                else return false;
989        }
990       
991        void finished()
992        {
993                if (finishTime_.is_special())
994                        finishTime_ = boost::posix_time::second_clock::universal_time();
995
996                if (is_finished())
997                {
998                        if (!move_to_directory_.empty() && 
999                                        move_to_directory_ !=  path_from_utf8(handle_.save_path()))
1000                        {
1001                                handle_.move_storage(path_to_utf8(move_to_directory_));
1002                                save_directory_ = move_to_directory_;
1003                        }
1004                }
1005        }
1006       
1007        bool is_active() const { return state_ == torrent_details::torrent_active; }
1008       
1009        unsigned state() const { return state_; }
1010       
1011        void setTrackerLogin(wstring username, wstring password)
1012        {
1013                trackerUsername_ = username;
1014                trackerPassword_ = password;
1015               
1016                applyTrackerLogin();
1017        }       
1018       
1019        std::pair<wstring, wstring> getTrackerLogin() const
1020        {
1021                return make_pair(trackerUsername_, trackerPassword_);
1022        }
1023       
1024        const wstring& filename() const { return filename_; }
1025       
1026        const wstring& originalFilename() const { return originalFilename_; }
1027       
1028        const libt::torrent_handle& handle() const { return handle_; }
1029
1030        void resetTrackers()
1031        {
1032                if (in_session())
1033                {
1034                        handle_.replace_trackers(torrent_trackers_);           
1035                        trackers_.clear();
1036                }
1037        }
1038       
1039        void setTrackers(const std::vector<tracker_detail>& tracker_details)
1040        {
1041                trackers_.clear();
1042                trackers_.assign(tracker_details.begin(), tracker_details.end());
1043               
1044                applyTrackers();
1045        }
1046       
1047        const std::vector<tracker_detail>& getTrackers()
1048        {
1049                if (trackers_.empty() && infoMemory_)
1050                {
1051                        std::vector<libt::announce_entry> trackers = infoMemory_->trackers();
1052                       
1053                        foreach (const libt::announce_entry& entry, trackers)
1054                        {
1055                                trackers_.push_back(
1056                                        tracker_detail(hal::from_utf8(entry.url), entry.tier));
1057                        }
1058                }               
1059                return trackers_;
1060        }
1061       
1062        void setFilePriorities(std::vector<int> fileIndices, int priority)
1063        {
1064                if (!filePriorities_.empty())
1065                {
1066                        foreach(int i, fileIndices)
1067                                filePriorities_[i] = priority;
1068                               
1069                        applyFilePriorities();
1070                }
1071        }
1072
1073        const wpath& saveDirectory() { return save_directory_; }
1074       
1075    friend class boost::serialization::access;
1076    template<class Archive>
1077    void serialize(Archive& ar, const unsigned int version)
1078    {
1079                using boost::serialization::make_nvp;
1080
1081                if (version > 1) {
1082                        ar & make_nvp("transfer_limits", transferLimit_);
1083                        ar & make_nvp("connection_limits", connections_);
1084                        ar & make_nvp("upload_limits", uploads_);       
1085
1086                        ar & make_nvp("name", name_);
1087                        ar & make_nvp("filename", filename_);   
1088
1089                        ar & make_nvp("ratio", ratio_); 
1090                        ar & make_nvp("progress", progress_);
1091                        ar & make_nvp("state", state_);
1092                        ar & make_nvp("compact_storage", compactStorage_);     
1093                        ar & make_nvp("resolve_countries", resolve_countries_); 
1094
1095                        ar & make_nvp("tracker_username", trackerUsername_);
1096                        ar & make_nvp("tracker_password", trackerPassword_);
1097                        ar & make_nvp("trackers", trackers_);
1098
1099                        ar & make_nvp("save_directory", save_directory_);
1100                        ar & make_nvp("move_to_directory", move_to_directory_);
1101                       
1102                        ar & make_nvp("payload_uploaded", payloadUploaded_);
1103                        ar & make_nvp("payload_downloaded", payloadDownloaded_);
1104                        ar & make_nvp("uploaded", uploaded_);
1105                        ar & make_nvp("downloaded", downloaded_);                       
1106                                       
1107                        ar & make_nvp("file_priorities", filePriorities_);
1108                       
1109                        ar & make_nvp("start_time", startTime_);
1110                        ar & make_nvp("finish_time", finishTime_);
1111                        ar & make_nvp("active_duration", activeDuration_);
1112                        ar & make_nvp("seeding_duration", seedingDuration_);
1113                                       
1114                } 
1115                else 
1116                {
1117                    ar & make_nvp("transferLimit", transferLimit_);
1118                        ar & make_nvp("connections", connections_);
1119                        ar & make_nvp("uploads", uploads_);                     
1120                        ar & make_nvp("filename", filename_);   
1121
1122                        wstring s;
1123                        ar & make_nvp("saveDirectory", s);
1124                        save_directory_ = s;
1125
1126                        if (version == 2) {
1127                                wstring m;
1128                                ar & make_nvp("moveToDirectory", m);
1129                                move_to_directory_ = m;
1130                        } else {
1131                                move_to_directory_ = save_directory_;
1132                        }
1133                       
1134                        ar & make_nvp("payloadUploaded_", payloadUploaded_);
1135                        ar & make_nvp("payloadDownloaded_", payloadDownloaded_);
1136                        ar & make_nvp("uploaded_", uploaded_);
1137                        ar & make_nvp("downloaded_", downloaded_);     
1138                        ar & make_nvp("ratio", ratio_); 
1139                        ar & make_nvp("trackerUsername", trackerUsername_);
1140                        ar & make_nvp("trackerPassword", trackerPassword_);
1141                       
1142                        ar & make_nvp("state", state_);
1143                        ar & make_nvp("trackers", trackers_);
1144                       
1145                        ar & make_nvp("resolve_countries", resolve_countries_);
1146                       
1147                        ar & make_nvp("file_priorities", filePriorities_);
1148                       
1149                        ar & make_nvp("startTime", startTime_);
1150                        ar & make_nvp("activeDuration", activeDuration_);
1151                        ar & make_nvp("seedingDuration", seedingDuration_);
1152                       
1153                        ar & make_nvp("name", name_);
1154                        ar & make_nvp("compactStorage", compactStorage_);
1155                        ar & make_nvp("finishTime", finishTime_);
1156                       
1157                        ar & make_nvp("progress", progress_);
1158        }
1159    }
1160
1161        void setEntryData(libtorrent::entry metadata, libtorrent::entry resumedata)
1162        {               
1163                metadata_ = metadata;
1164                resumedata_ = resumedata;
1165        }
1166
1167        std::vector<libt::peer_info>& peers() { return peers_; }
1168       
1169        boost::tuple<size_t, size_t, size_t, size_t> updatePeers()
1170        {
1171                if (in_session())
1172                        handle_.get_peer_info(peers_);
1173               
1174                size_t totalPeers = 0;
1175                size_t peersConnected = 0;
1176                size_t totalSeeds = 0;
1177                size_t seedsConnected = 0;
1178               
1179                foreach (libt::peer_info& peer, peers_) 
1180                {
1181                        float speedSum = peer.down_speed + peer.up_speed;
1182                       
1183                        if (!(peer.flags & libt::peer_info::seed))
1184                        {
1185                                ++totalPeers;
1186                               
1187                                if (speedSum > 0)
1188                                        ++peersConnected;
1189                        }
1190                        else
1191                        {
1192                                ++totalSeeds;
1193                               
1194                                if (speedSum > 0)
1195                                        ++seedsConnected;
1196                        }
1197                }       
1198               
1199                return boost::make_tuple(totalPeers, peersConnected, totalSeeds, seedsConnected);
1200        }
1201       
1202        void getPeerDetails(PeerDetails& peerDetails) const
1203        {
1204                if (in_session())
1205                {
1206                        foreach (libt::peer_info peer, peers_) 
1207                        {
1208                                peerDetails.push_back(peer);
1209                        }       
1210                }
1211        }
1212
1213        void getFileDetails(FileDetails& fileDetails)
1214        {
1215                if (fileDetailsMemory_.empty())
1216                {
1217                        libt::torrent_info& info = infoMemory();
1218                        std::vector<libt::file_entry> files;
1219                       
1220                        std::copy(info.begin_files(), info.end_files(), 
1221                                std::back_inserter(files));                                     
1222                               
1223                        if (filePriorities_.size() != files.size())
1224                        {
1225                                filePriorities_.clear();
1226                                filePriorities_.assign(files.size(), 1);
1227                        }
1228                       
1229                        for(size_t i=0, e=files.size(); i<e; ++i)
1230                        {
1231                                wstring fullPath = hal::from_utf8(files[i].path.string());
1232                                boost::int64_t size = static_cast<boost::int64_t>(files[i].size);
1233                               
1234                                fileDetailsMemory_.push_back(FileDetail(fullPath, size, 0, filePriorities_[i], i));
1235                        }       
1236                }               
1237               
1238                if (in_session())
1239                {                       
1240                        std::vector<float> fileProgress;                       
1241                        handle_.file_progress(fileProgress);
1242                       
1243                        for(size_t i=0, e=fileDetailsMemory_.size(); i<e; ++i)
1244                                fileDetailsMemory_[i].progress =  fileProgress[i];                     
1245                }
1246
1247                for(size_t i=0, e=fileDetailsMemory_.size(); i<e; ++i)
1248                        fileDetailsMemory_[i].priority =  filePriorities_[i];
1249               
1250                fileDetails = fileDetailsMemory_;
1251        }
1252       
1253        void prepare(wpath filename)
1254        {
1255                mutex_t::scoped_lock l(mutex_);
1256               
1257                if (fs::exists(filename)) 
1258                        metadata_ = haldecode(filename);
1259               
1260                extractNames(metadata_);                       
1261               
1262                const wpath resumeFile = workingDir_/L"resume"/filename_;
1263                const wpath torrentFile = workingDir_/L"torrents"/filename_;
1264               
1265                event_log.post(shared_ptr<EventDetail>(new EventMsg(
1266                        wformat(L"File: %1%, %2%.") % resumeFile % torrentFile)));
1267               
1268                if (exists(resumeFile)) 
1269                        resumedata_ = haldecode(resumeFile);
1270
1271                if (!exists(workingDir_/L"torrents"))
1272                        create_directory(workingDir_/L"torrents");
1273
1274                if (!exists(torrentFile))
1275                        copy_file(filename.string(), torrentFile);
1276
1277                if (!fs::exists(save_directory_))
1278                        fs::create_directory(save_directory_);
1279
1280                if (state_ == torrent_details::torrent_stopping)
1281                        state_ = torrent_details::torrent_stopped;
1282                else if (state_ == torrent_details::torrent_pausing)
1283                        state_ = torrent_details::torrent_paused;
1284        }
1285       
1286        void extractNames(libt::entry& metadata)
1287        {
1288                mutex_t::scoped_lock l(mutex_);
1289               
1290                libt::torrent_info info(metadata);                             
1291                name_ = hal::from_utf8_safe(info.name());
1292               
1293                filename_ = name_;
1294                if (!boost::find_last(filename_, L".torrent")) 
1295                                filename_ += L".torrent";
1296               
1297                event_log.post(shared_ptr<EventDetail>(new EventMsg(
1298                        wformat(L"Loaded names: %1%, %2%") % name_ % filename_)));
1299        }
1300       
1301        libt::torrent_info& infoMemory()
1302        {
1303                if (!infoMemory_) infoMemory_ = libt::torrent_info(metadata_);
1304               
1305                return *infoMemory_;
1306        }
1307       
1308        signalers& signals()
1309        {
1310                mutex_t::scoped_lock l(mutex_);
1311                return signals_;
1312        }
1313
1314private:       
1315        signalers signals_;
1316
1317        void applySettings()
1318        {               
1319                applyTransferSpeed();
1320                applyConnectionLimit();
1321                apply_ratio();
1322                applyTrackers();
1323                applyTrackerLogin();
1324                applyFilePriorities();
1325                applyResolveCountries();
1326        }
1327       
1328        void applyTransferSpeed()
1329        {
1330                mutex_t::scoped_lock l(mutex_);
1331                if (in_session())
1332                {
1333                        int down = (transferLimit_.first > 0) ? static_cast<int>(transferLimit_.first*1024) : -1;
1334                        handle_.set_download_limit(down);
1335                       
1336                        int up = (transferLimit_.second > 0) ? static_cast<int>(transferLimit_.second*1024) : -1;
1337                        handle_.set_upload_limit(up);
1338
1339                        HAL_DEV_MSG(wformat(L"Applying Transfer Speed %1% - %2%") % down % up);
1340                }
1341        }
1342
1343        void applyConnectionLimit()
1344        {
1345                mutex_t::scoped_lock l(mutex_);
1346                if (in_session())
1347                {
1348                        handle_.set_max_connections(connections_);
1349                        handle_.set_max_uploads(uploads_);
1350
1351                        HAL_DEV_MSG(wformat(L"Applying Connection Limit %1% - %2%") % connections_ % uploads_);
1352                }
1353        }
1354       
1355        void apply_ratio()
1356        { 
1357                mutex_t::scoped_lock l(mutex_);
1358                if (in_session())
1359                {
1360                        handle_.set_ratio(ratio_);
1361
1362                        HAL_DEV_MSG(wformat(L"Applying Ratio %1%") % ratio_);
1363                }
1364        }
1365       
1366        void applyTrackers()
1367        {
1368                mutex_t::scoped_lock l(mutex_);
1369                if (in_session())
1370                {
1371                        if (torrent_trackers_.empty())
1372                                torrent_trackers_ = handle_.trackers();
1373                       
1374                        if (!trackers_.empty())
1375                        {
1376                                std::vector<libt::announce_entry> trackers;
1377                               
1378                                foreach (const tracker_detail& tracker, trackers_)
1379                                {
1380                                        trackers.push_back(
1381                                                libt::announce_entry(hal::to_utf8(tracker.url)));
1382                                        trackers.back().tier = tracker.tier;
1383                                }
1384                                handle_.replace_trackers(trackers);
1385                        }
1386                       
1387                        HAL_DEV_MSG(L"Applying Trackers");
1388                }
1389        }
1390       
1391        void applyTrackerLogin()
1392        {
1393                mutex_t::scoped_lock l(mutex_);
1394                if (in_session())
1395                {
1396                        if (trackerUsername_ != L"")
1397                        {
1398                                handle_.set_tracker_login(hal::to_utf8(trackerUsername_),
1399                                        hal::to_utf8(trackerPassword_));
1400                        }
1401
1402                        HAL_DEV_MSG(wformat(L"Applying Tracker Login User: %1%, Pass: %2%") % trackerUsername_ % trackerPassword_ );
1403                }
1404        }
1405       
1406        void applyFilePriorities()
1407        {               
1408                mutex_t::scoped_lock l(mutex_);
1409                if (in_session()) 
1410                {
1411                        if (!filePriorities_.empty())
1412                                handle_.prioritize_files(filePriorities_);
1413                       
1414                        HAL_DEV_MSG(L"Applying File Priorities");
1415                }
1416        }       
1417       
1418        void applyResolveCountries()
1419        {
1420                mutex_t::scoped_lock l(mutex_);
1421                if (in_session())
1422                {
1423                        handle_.resolve_countries(resolve_countries_);
1424                       
1425                        HAL_DEV_MSG(wformat(L"Applying Resolve Countries %1%") % resolve_countries_);
1426                }
1427        }
1428       
1429        void completed_pause()
1430        {
1431                mutex_t::scoped_lock l(mutex_);
1432                assert(in_session());
1433                assert(handle_.is_paused());   
1434                               
1435                state_ = torrent_details::torrent_paused;       
1436
1437                HAL_DEV_MSG(L"completed_pause()");
1438        }
1439
1440        void completed_stop()
1441        {
1442                mutex_t::scoped_lock l(mutex_);
1443                assert(in_session());
1444                assert(handle_.is_paused());   
1445               
1446                state_ = torrent_details::torrent_stopped;
1447               
1448                remove_from_session();
1449                assert(!in_session());
1450
1451                HAL_DEV_MSG(L"completed_stop()");
1452        }
1453
1454        void handle_recheck()
1455        {
1456                mutex_t::scoped_lock l(mutex_);
1457                state_ = torrent_details::torrent_stopped;
1458
1459                remove_from_session(false);
1460                assert(!in_session());
1461
1462                clear_resume_data();
1463
1464                resume();
1465                assert(in_session());
1466
1467                HAL_DEV_MSG(L"handle_recheck()");
1468        }
1469               
1470        static libt::session* the_session_;
1471        static wpath workingDir_;
1472       
1473        mutable mutex_t mutex_;
1474       
1475        std::pair<float, float> transferLimit_;
1476       
1477        unsigned state_;
1478        int connections_;
1479        int uploads_;
1480        bool in_session_;
1481        float ratio_;
1482        bool resolve_countries_;
1483       
1484        wstring filename_;
1485        wstring name_;
1486        wpath save_directory_;
1487        wpath move_to_directory_;
1488        wstring originalFilename_;
1489        libt::torrent_handle handle_;   
1490       
1491        libt::entry metadata_;
1492        libt::entry resumedata_;
1493       
1494        wstring trackerUsername_;       
1495        wstring trackerPassword_;
1496       
1497        boost::int64_t totalUploaded_;
1498        boost::int64_t totalBase_;
1499       
1500        transfer_tracker<boost::int64_t> payloadUploaded_;
1501        transfer_tracker<boost::int64_t> payloadDownloaded_;
1502        transfer_tracker<boost::int64_t> uploaded_;
1503        transfer_tracker<boost::int64_t> downloaded_;
1504       
1505        pt::ptime startTime_;
1506        pt::ptime finishTime_;
1507        duration_tracker activeDuration_;
1508        duration_tracker seedingDuration_;
1509       
1510        std::vector<tracker_detail> trackers_;
1511        std::vector<libt::announce_entry> torrent_trackers_;
1512        std::vector<libt::peer_info> peers_;   
1513        std::vector<int> filePriorities_;
1514       
1515        float progress_;
1516       
1517        boost::optional<libt::torrent_info> infoMemory_;
1518        libt::torrent_status statusMemory_;
1519        FileDetails fileDetailsMemory_;
1520       
1521        bool compactStorage_;
1522};
1523
1524typedef std::map<std::string, TorrentInternalOld> TorrentMap;
1525typedef std::pair<std::string, TorrentInternalOld> TorrentPair;
1526
1527class TorrentManager : 
1528        public hal::IniBase<TorrentManager>
1529{
1530        typedef TorrentManager thisClass;
1531        typedef hal::IniBase<thisClass> iniClass;
1532
1533        struct TorrentHolder
1534        {
1535                mutable torrent_internal_ptr torrent;
1536               
1537                wstring filename;
1538                wstring name;           
1539               
1540                TorrentHolder()
1541                {}
1542               
1543                explicit TorrentHolder(torrent_internal_ptr t) :
1544                        torrent(t), filename(torrent->filename()), name(torrent->name())
1545                {}
1546                                               
1547                friend class boost::serialization::access;
1548                template<class Archive>
1549                void serialize(Archive& ar, const unsigned int version)
1550                {
1551                        using boost::serialization::make_nvp;
1552
1553                        if (version < 1)
1554                        {
1555                                TorrentInternalOld t;
1556                                ar & make_nvp("torrent", t);
1557                               
1558                                torrent.reset(new torrent_internal(t));
1559                        }
1560                        else
1561                        {
1562                                ar & make_nvp("torrent", torrent);
1563                        } 
1564                       
1565                        ar & make_nvp("filename", filename);
1566                        ar & make_nvp("name", name);
1567                }
1568        };
1569       
1570        struct byFilename{};
1571        struct byName{};
1572       
1573        typedef boost::multi_index_container<
1574                TorrentHolder,
1575                boost::multi_index::indexed_by<
1576                        boost::multi_index::ordered_unique<
1577                                boost::multi_index::tag<byFilename>,
1578                                boost::multi_index::member<
1579                                        TorrentHolder, wstring, &TorrentHolder::filename> 
1580                                >,
1581                        boost::multi_index::ordered_unique<
1582                                boost::multi_index::tag<byName>,
1583                                boost::multi_index::member<
1584                                        TorrentHolder, wstring, &TorrentHolder::name> 
1585                                >
1586                >
1587        > TorrentMultiIndex;
1588       
1589public:
1590        typedef TorrentMultiIndex::index<byFilename>::type torrentByFilename;
1591        typedef TorrentMultiIndex::index<byName>::type torrentByName;
1592       
1593        TorrentManager(ini_file& ini) :
1594                iniClass("bittorrent", "TorrentManager", ini)
1595        {}
1596       
1597        TorrentManager& operator=(const TorrentMap& map)
1598        {
1599                torrents_.clear();
1600               
1601                for (TorrentMap::const_iterator i=map.begin(), e=map.end(); i != e; ++i)
1602                {       
1603                        torrent_internal_ptr TIp(new torrent_internal((*i).second));
1604                       
1605                        event_log.post(shared_ptr<EventDetail>(new EventMsg(
1606                                wformat(L"Converting %1%.") % TIp->name())));
1607                       
1608                        torrents_.insert(TorrentHolder(TIp));
1609                }
1610               
1611                return *this;
1612        }
1613       
1614        std::pair<torrentByName::iterator, bool> insert(const TorrentHolder& h)
1615        {
1616                return torrents_.get<byName>().insert(h);
1617        }
1618       
1619        std::pair<torrentByName::iterator, bool> insert(torrent_internal_ptr t)
1620        {
1621                return insert(TorrentHolder(t));
1622        }
1623
1624        torrent_internal_ptr getByFile(const wstring& filename)
1625        {
1626                torrentByFilename::iterator it = torrents_.get<byFilename>().find(filename);
1627               
1628                if (it != torrents_.get<byFilename>().end() && (*it).torrent)
1629                {
1630                        return (*it).torrent;
1631                }
1632               
1633                throw invalidTorrent(filename);
1634        }
1635       
1636        torrent_internal_ptr get(const wstring& name)
1637        {
1638                torrentByName::iterator it = torrents_.get<byName>().find(name);
1639               
1640                if (it != torrents_.get<byName>().end() && (*it).torrent)
1641                {
1642                        return (*it).torrent;
1643                }
1644               
1645                throw invalidTorrent(name);
1646        }
1647       
1648        torrentByName::iterator erase(torrentByName::iterator where)
1649        {
1650                return torrents_.get<byName>().erase(where);
1651        }
1652       
1653        size_t size()
1654        {
1655                return torrents_.size();
1656        }
1657       
1658        size_t erase(const wstring& name)
1659        {
1660                return torrents_.get<byName>().erase(name);
1661        }
1662       
1663        bool exists(const wstring& name)
1664        {
1665                torrentByName::iterator it = torrents_.get<byName>().find(name);
1666               
1667                if (it != torrents_.get<byName>().end())
1668                        return true;
1669                else
1670                        return false;
1671        }
1672       
1673        torrentByName::iterator begin() { return torrents_.get<byName>().begin(); }
1674        torrentByName::iterator end() { return torrents_.get<byName>().end(); }
1675       
1676        friend class boost::serialization::access;
1677        template<class Archive>
1678        void serialize(Archive& ar, const unsigned int version)
1679        {
1680                ar & boost::serialization::make_nvp("torrents", torrents_);
1681        }       
1682       
1683private:
1684        TorrentMultiIndex torrents_;
1685};
1686
1687} // namespace hal
1688
1689BOOST_CLASS_VERSION(hal::TorrentManager::TorrentHolder, 1)
1690
1691#endif // RC_INVOKED
1692
Note: See TracBrowser for help on using the repository browser.