source: trunk/src/halTorrentInternal.hpp @ 409

Revision 409, 39.4 KB checked in by Eoin, 12 years ago (diff)

Added support for individual xml saves pre torrent but havn't set when to be saved yet.

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