source: trunk/src/halTorrentInternal.hpp @ 410

Revision 410, 39.5 KB checked in by Eoin, 12 years ago (diff)

408 Snapshot.

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                        torrent_standalone tsa(shared_from_this());
623                        tsa.save_standalone(workingDir_/L"torrents"/(name_+L".xml"));
624                }
625               
626                HAL_DEV_MSG(L"removing handle from session");
627                the_session_->remove_torrent(handle_);
628                in_session_ = false;
629
630                assert(!inSession());   
631                HAL_DEV_MSG(L"Removed from session!");
632
633                }
634                catch(std::exception& e)
635                {
636                        hal::event().post(boost::shared_ptr<hal::EventDetail>(
637                                new hal::EventStdException(Event::critical, e, L"removeFromSession"))); 
638                }
639        }
640       
641        bool inSession() const
642        { 
643                mutex_t::scoped_lock l(mutex_);
644
645                return (in_session_ && the_session_ != 0 && handle_.is_valid());
646        }
647       
648        void resume()
649        {
650                mutex_t::scoped_lock l(mutex_);
651
652                if (state_ == TorrentDetail::torrent_stopped)
653                {       
654                        addToSession(false);
655                        assert(inSession());                   
656                }
657                else
658                {
659                        assert(inSession());
660                        handle_.resume();
661                }       
662               
663                state_ = TorrentDetail::torrent_active;                 
664                assert(!handle_.is_paused());
665        }
666       
667        void pause()
668        {
669                mutex_t::scoped_lock l(mutex_);
670
671                if (state_ == TorrentDetail::torrent_stopped)
672                {       
673                        addToSession(true);
674
675                        assert(inSession());
676                //      assert(handle_.is_paused());
677                }
678                else
679                {
680                        assert(inSession());
681
682                        handle_.pause();
683                        signals().torrent_paused.disconnect_all_once();
684                        signals().torrent_paused.connect_once(bind(&TorrentInternal::completed_pause, this));
685
686                        state_ = TorrentDetail::torrent_pausing;       
687                }                       
688        }
689       
690        void stop()
691        {
692                mutex_t::scoped_lock l(mutex_);
693
694                if (state_ != TorrentDetail::torrent_stopped)
695                {
696                        if (state_ == TorrentDetail::torrent_active)
697                        {
698                                assert(inSession());
699
700                                signals().torrent_paused.disconnect_all_once();
701                                signals().torrent_paused.connect_once(bind(&TorrentInternal::completed_stop, this));
702                                handle_.pause();
703
704                                state_ = TorrentDetail::torrent_stopping;
705                        }
706                        else if (state_ == TorrentDetail::torrent_paused)
707                        {                       
708                                removeFromSession();
709                                state_ = TorrentDetail::torrent_stopped;                               
710                        }
711                }
712        }
713
714        void set_state_stopped()
715        {
716                state_ = TorrentDetail::torrent_stopped;
717        }
718
719        void forceRecheck()
720        {
721                mutex_t::scoped_lock l(mutex_);         
722                HAL_DEV_MSG(L"forceRecheck()");
723
724                switch (state_)
725                {
726                case TorrentDetail::torrent_stopped:
727                        clearResumeData();
728                        resume();
729                        break;
730
731                case TorrentDetail::torrent_stopping:
732                case TorrentDetail::torrent_pausing:
733                        signals().torrent_paused.disconnect_all_once();
734
735                case TorrentDetail::torrent_active:
736                        signals().torrent_paused.disconnect_all_once();
737                        signals().torrent_paused.connect_once(bind(&TorrentInternal::handle_recheck, this));
738                        handle_.pause();
739                        state_ = TorrentDetail::torrent_pausing;
740                        break;
741
742                default:
743                        assert(false);
744                };
745        }
746       
747        void writeResumeData()
748        {                                       
749                HAL_DEV_MSG(L"writeResumeData()");
750                wpath_t resumeDir = workingDir_/L"resume";
751               
752                if (!exists(resumeDir))
753                        create_directory(resumeDir);
754                               
755                bool halencode_result = halencode(resumeDir/filename_, resumedata_);
756                assert(halencode_result);
757                HAL_DEV_MSG(L"Written!");
758        }
759       
760        void clearResumeData()
761        {
762                wpath_t resumeFile = workingDir_/L"resume"/filename_;
763               
764                if (exists(resumeFile))
765                        remove(resumeFile);
766
767                resumedata_ = lbt::entry();
768        }
769       
770        void finished()
771        {
772                if (finishTime_.is_special())
773                        finishTime_ = boost::posix_time::second_clock::universal_time();
774
775                // Only move seeding torrents for the mo!
776                if (inSession() && handle_.status().state == lbt::torrent_status::seeding)
777                {
778                        if (move_to_directory_ != L"" && move_to_directory_ != save_directory_)
779                        {
780                                handle_.move_storage(to_utf8(move_to_directory_));
781                                save_directory_ = move_to_directory_;
782                        }
783                }
784        }
785       
786        bool isActive() const { return state_ == TorrentDetail::torrent_active; }
787       
788        unsigned state() const { return state_; }
789       
790        void setTrackerLogin(wstring_t username, wstring_t password)
791        {
792                trackerUsername_ = username;
793                trackerPassword_ = password;
794               
795                applyTrackerLogin();
796        }       
797       
798        std::pair<wstring_t, wstring_t> getTrackerLogin() const
799        {
800                return make_pair(trackerUsername_, trackerPassword_);
801        }
802       
803        const wstring_t& filename() const { return filename_; }
804       
805        const wstring_t& originalFilename() const { return originalFilename_; }
806       
807        const lbt::torrent_handle& handle() const { return handle_; }
808
809        void resetTrackers()
810        {
811                if (inSession())
812                {
813                        handle_.replace_trackers(torrent_trackers_);           
814                        trackers_.clear();
815                }
816        }
817       
818        void setTrackers(const std::vector<TrackerDetail>& trackerDetails)
819        {
820                trackers_.clear();
821                trackers_.assign(trackerDetails.begin(), trackerDetails.end());
822               
823                applyTrackers();
824        }
825       
826        const std::vector<TrackerDetail>& getTrackers()
827        {
828                if (trackers_.empty())
829                {
830                        std::vector<lbt::announce_entry> trackers = infoMemory_.trackers();
831                       
832                        foreach (const lbt::announce_entry& entry, trackers)
833                        {
834                                trackers_.push_back(
835                                        TrackerDetail(hal::from_utf8(entry.url), entry.tier));
836                        }
837                }               
838                return trackers_;
839        }
840       
841        void setFilePriorities(std::vector<int> fileIndices, int priority)
842        {
843                if (!filePriorities_.empty())
844                {
845                        foreach(int i, fileIndices)
846                                filePriorities_[i] = priority;
847                               
848                        applyFilePriorities();
849                }
850        }
851
852        const wstring_t& saveDirectory() { return save_directory_; }
853       
854    friend class boost::serialization::access;
855    template<class Archive>
856    void serialize(Archive& ar, const unsigned int version)
857    {
858        ar & make_nvp("transferLimit", transferLimit_);
859        ar & make_nvp("connections", connections_);
860        ar & make_nvp("uploads", uploads_);                     
861                ar & make_nvp("filename", filename_);           
862        ar & make_nvp("saveDirectory", save_directory_);
863                if (version > 0) {
864                        ar & make_nvp("moveToDirectory", move_to_directory_);
865                } else {
866                        move_to_directory_ = save_directory_;
867                }
868               
869                ar & make_nvp("payloadUploaded_", payloadUploaded_);
870                ar & make_nvp("payloadDownloaded_", payloadDownloaded_);
871                ar & make_nvp("uploaded_", uploaded_);
872                ar & make_nvp("downloaded_", downloaded_);     
873                ar & make_nvp("ratio", ratio_); 
874                ar & make_nvp("trackerUsername", trackerUsername_);
875                ar & make_nvp("trackerPassword", trackerPassword_);
876               
877                ar & make_nvp("state", state_);
878                ar & make_nvp("trackers", trackers_);
879               
880                ar & make_nvp("resolve_countries", resolve_countries_);
881               
882                ar & make_nvp("file_priorities", filePriorities_);
883               
884                ar & make_nvp("startTime", startTime_);
885                ar & make_nvp("activeDuration", activeDuration_);
886                ar & make_nvp("seedingDuration", seedingDuration_);
887               
888                ar & make_nvp("name", name_);
889                ar & make_nvp("compactStorage", compactStorage_);
890                ar & make_nvp("finishTime", finishTime_);
891               
892                ar & make_nvp("progress", progress_);
893    }
894
895        void setEntryData(libtorrent::entry metadata, libtorrent::entry resumedata)
896        {               
897                metadata_ = metadata;
898                resumedata_ = resumedata;
899        }
900
901        std::vector<lbt::peer_info>& peers() { return peers_; }
902       
903        boost::tuple<size_t, size_t, size_t, size_t> updatePeers()
904        {
905                if (inSession())
906                        handle_.get_peer_info(peers_);
907               
908                size_t totalPeers = 0;
909                size_t peersConnected = 0;
910                size_t totalSeeds = 0;
911                size_t seedsConnected = 0;
912               
913                foreach (lbt::peer_info& peer, peers_) 
914                {
915                        float speedSum = peer.down_speed + peer.up_speed;
916                       
917                        if (!(peer.flags & lbt::peer_info::seed))
918                        {
919                                ++totalPeers;
920                               
921                                if (speedSum > 0)
922                                        ++peersConnected;
923                        }
924                        else
925                        {
926                                ++totalSeeds;
927                               
928                                if (speedSum > 0)
929                                        ++seedsConnected;
930                        }
931                }       
932               
933                return boost::make_tuple(totalPeers, peersConnected, totalSeeds, seedsConnected);
934        }
935       
936        void getPeerDetails(PeerDetails& peerDetails) const
937        {
938                if (inSession())
939                {
940                        foreach (lbt::peer_info peer, peers_) 
941                        {
942                                peerDetails.push_back(peer);
943                        }       
944                }
945        }
946
947        void getFileDetails(FileDetails& fileDetails)
948        {
949                if (fileDetailsMemory_.empty())
950                {
951                        lbt::torrent_info& info = infoMemory();
952                        std::vector<lbt::file_entry> files;
953                       
954                        std::copy(info.begin_files(), info.end_files(), 
955                                std::back_inserter(files));                                     
956                               
957                        if (filePriorities_.size() != files.size())
958                        {
959                                filePriorities_.clear();
960                                filePriorities_.assign(files.size(), 1);
961                        }
962                       
963                        for(size_t i=0, e=files.size(); i<e; ++i)
964                        {
965                                wstring_t fullPath = hal::from_utf8(files[i].path.string());
966                                boost::int64_t size = static_cast<boost::int64_t>(files[i].size);
967                               
968                                fileDetailsMemory_.push_back(FileDetail(fullPath, size, 0, filePriorities_[i], i));
969                        }       
970                }               
971               
972                if (inSession())
973                {                       
974                        std::vector<float> fileProgress;                       
975                        handle_.file_progress(fileProgress);
976                       
977                        for(size_t i=0, e=fileDetailsMemory_.size(); i<e; ++i)
978                                fileDetailsMemory_[i].progress =  fileProgress[i];                     
979                }
980
981                for(size_t i=0, e=fileDetailsMemory_.size(); i<e; ++i)
982                        fileDetailsMemory_[i].priority =  filePriorities_[i];
983               
984                fileDetails = fileDetailsMemory_;
985        }
986       
987        void prepare(wpath_t filename)
988        {
989                mutex_t::scoped_lock l(mutex_);
990               
991                if (fs::exists(filename)) 
992                        metadata_ = haldecode(filename);
993               
994                extractNames(metadata_);                       
995               
996                const wpath_t resumeFile = workingDir_/L"resume"/filename_;
997                const wpath_t torrentFile = workingDir_/L"torrents"/filename_;
998               
999                event().post(shared_ptr<EventDetail>(new EventMsg(
1000                        wformat_t(L"File: %1%, %2%.") % resumeFile % torrentFile)));
1001               
1002                if (exists(resumeFile)) 
1003                        resumedata_ = haldecode(resumeFile);
1004
1005                if (!exists(workingDir_/L"torrents"))
1006                        create_directory(workingDir_/L"torrents");
1007
1008                if (!exists(torrentFile))
1009                        copy_file(filename.string(), torrentFile);
1010
1011                if (!fs::exists(save_directory_))
1012                        fs::create_directory(save_directory_);
1013
1014                if (state_ == TorrentDetail::torrent_stopping)
1015                        state_ = TorrentDetail::torrent_stopped;
1016                else if (state_ == TorrentDetail::torrent_pausing)
1017                        state_ = TorrentDetail::torrent_paused;
1018        }
1019       
1020        void extractNames(lbt::entry& metadata)
1021        {
1022                mutex_t::scoped_lock l(mutex_);
1023               
1024                lbt::torrent_info info(metadata);                               
1025                name_ = hal::from_utf8_safe(info.name());
1026               
1027                filename_ = name_;
1028                if (!boost::find_last(filename_, L".torrent")) 
1029                                filename_ += L".torrent";
1030               
1031                event().post(shared_ptr<EventDetail>(new EventMsg(
1032                        wformat_t(L"Loaded names: %1%, %2%") % name_ % filename_)));
1033        }
1034       
1035        lbt::torrent_info& infoMemory()
1036        {
1037                if (!infoMemory_.is_valid()) infoMemory_ = lbt::torrent_info(metadata_);
1038               
1039                return infoMemory_;
1040        }
1041       
1042        signalers& signals()
1043        {
1044                mutex_t::scoped_lock l(mutex_);
1045                return signals_;
1046        }
1047
1048private:       
1049        signalers signals_;
1050
1051        void applySettings()
1052        {               
1053                applyTransferSpeed();
1054                applyConnectionLimit();
1055                applyRatio();
1056                applyTrackers();
1057                applyTrackerLogin();
1058                applyFilePriorities();
1059                applyResolveCountries();
1060        }
1061       
1062        void applyTransferSpeed()
1063        {
1064                mutex_t::scoped_lock l(mutex_);
1065                if (inSession())
1066                {
1067                        int down = (transferLimit_.first > 0) ? static_cast<int>(transferLimit_.first*1024) : -1;
1068                        handle_.set_download_limit(down);
1069                       
1070                        int up = (transferLimit_.second > 0) ? static_cast<int>(transferLimit_.second*1024) : -1;
1071                        handle_.set_upload_limit(up);
1072
1073                        HAL_DEV_MSG(wformat_t(L"Applying Transfer Speed %1% - %2%") % down % up);
1074                }
1075        }
1076
1077        void applyConnectionLimit()
1078        {
1079                mutex_t::scoped_lock l(mutex_);
1080                if (inSession())
1081                {
1082                        handle_.set_max_connections(connections_);
1083                        handle_.set_max_uploads(uploads_);
1084
1085                        HAL_DEV_MSG(wformat_t(L"Applying Connection Limit %1% - %2%") % connections_ % uploads_);
1086                }
1087        }
1088       
1089        void applyRatio()
1090        { 
1091                mutex_t::scoped_lock l(mutex_);
1092                if (inSession())
1093                {
1094                        handle_.set_ratio(ratio_);
1095
1096                        HAL_DEV_MSG(wformat_t(L"Applying Ratio %1%") % ratio_);
1097                }
1098        }
1099       
1100        void applyTrackers()
1101        {
1102                mutex_t::scoped_lock l(mutex_);
1103                if (inSession())
1104                {
1105                        if (torrent_trackers_.empty())
1106                                torrent_trackers_ = handle_.trackers();
1107                       
1108                        if (!trackers_.empty())
1109                        {
1110                                std::vector<lbt::announce_entry> trackers;
1111                               
1112                                foreach (const TrackerDetail& tracker, trackers_)
1113                                {
1114                                        trackers.push_back(
1115                                                lbt::announce_entry(hal::to_utf8(tracker.url)));
1116                                        trackers.back().tier = tracker.tier;
1117                                }
1118                                handle_.replace_trackers(trackers);
1119                        }
1120                       
1121                        HAL_DEV_MSG(L"Applying Trackers");
1122                }
1123        }
1124       
1125        void applyTrackerLogin()
1126        {
1127                mutex_t::scoped_lock l(mutex_);
1128                if (inSession())
1129                {
1130                        if (trackerUsername_ != L"")
1131                        {
1132                                handle_.set_tracker_login(hal::to_utf8(trackerUsername_),
1133                                        hal::to_utf8(trackerPassword_));
1134                        }
1135
1136                        HAL_DEV_MSG(wformat_t(L"Applying Tracker Login User: %1%, Pass: %2%") % trackerUsername_ % trackerPassword_ );
1137                }
1138        }
1139       
1140        void applyFilePriorities()
1141        {               
1142                mutex_t::scoped_lock l(mutex_);
1143                if (inSession()) 
1144                {
1145                        if (!filePriorities_.empty())
1146                                handle_.prioritize_files(filePriorities_);
1147                       
1148                        HAL_DEV_MSG(L"Applying File Priorities");
1149                }
1150        }       
1151       
1152        void applyResolveCountries()
1153        {
1154                mutex_t::scoped_lock l(mutex_);
1155                if (inSession())
1156                {
1157                        handle_.resolve_countries(resolve_countries_);
1158                       
1159                        HAL_DEV_MSG(wformat_t(L"Applying Resolve Countries %1%") % resolve_countries_);
1160                }
1161        }
1162       
1163        void completed_pause()
1164        {
1165                mutex_t::scoped_lock l(mutex_);
1166                assert(inSession());
1167                assert(handle_.is_paused());   
1168                               
1169                state_ = TorrentDetail::torrent_paused; 
1170
1171                HAL_DEV_MSG(L"completed_pause()");
1172        }
1173
1174        void completed_stop()
1175        {
1176                mutex_t::scoped_lock l(mutex_);
1177                assert(inSession());
1178                assert(handle_.is_paused());   
1179               
1180                state_ = TorrentDetail::torrent_stopped;
1181               
1182                removeFromSession();
1183                assert(!inSession());
1184
1185                HAL_DEV_MSG(L"completed_stop()");
1186        }
1187
1188        void handle_recheck()
1189        {
1190                mutex_t::scoped_lock l(mutex_);
1191                state_ = TorrentDetail::torrent_stopped;
1192
1193                removeFromSession(false);
1194                assert(!inSession());
1195
1196                clearResumeData();
1197
1198                resume();
1199                assert(inSession());
1200
1201                HAL_DEV_MSG(L"handle_recheck()");
1202        }
1203               
1204        static lbt::session* the_session_;
1205        static wpath_t workingDir_;
1206       
1207        mutable mutex_t mutex_;
1208       
1209        std::pair<float, float> transferLimit_;
1210       
1211        unsigned state_;
1212        int connections_;
1213        int uploads_;
1214        bool in_session_;
1215        float ratio_;
1216        bool resolve_countries_;
1217       
1218        wstring_t filename_;
1219        wstring_t name_;
1220        wstring_t save_directory_;
1221        wstring_t move_to_directory_;
1222        wstring_t originalFilename_;
1223        lbt::torrent_handle handle_;   
1224       
1225        lbt::entry metadata_;
1226        lbt::entry resumedata_;
1227       
1228        wstring_t trackerUsername_;     
1229        wstring_t trackerPassword_;
1230       
1231        boost::int64_t totalUploaded_;
1232        boost::int64_t totalBase_;
1233       
1234        TransferTracker<boost::int64_t> payloadUploaded_;
1235        TransferTracker<boost::int64_t> payloadDownloaded_;
1236        TransferTracker<boost::int64_t> uploaded_;
1237        TransferTracker<boost::int64_t> downloaded_;
1238       
1239        pt::ptime startTime_;
1240        pt::ptime finishTime_;
1241        DurationTracker activeDuration_;
1242        DurationTracker seedingDuration_;
1243       
1244        std::vector<TrackerDetail> trackers_;
1245        std::vector<lbt::announce_entry> torrent_trackers_;
1246        std::vector<lbt::peer_info> peers_;     
1247        std::vector<int> filePriorities_;
1248       
1249        float progress_;
1250       
1251        lbt::torrent_info infoMemory_;
1252        lbt::torrent_status statusMemory_;
1253        FileDetails fileDetailsMemory_;
1254       
1255        bool compactStorage_;
1256};
1257
1258typedef std::map<std::string, TorrentInternalOld> TorrentMap;
1259typedef std::pair<std::string, TorrentInternalOld> TorrentPair;
1260
1261class TorrentManager : 
1262        public hal::IniBase<TorrentManager>
1263{
1264        typedef TorrentManager thisClass;
1265        typedef hal::IniBase<thisClass> iniClass;
1266
1267        struct TorrentHolder
1268        {
1269                mutable TorrentInternal_ptr torrent;
1270               
1271                wstring_t filename;
1272                wstring_t name;         
1273               
1274                TorrentHolder()
1275                {}
1276               
1277                explicit TorrentHolder(TorrentInternal_ptr t) :
1278                        torrent(t), filename(torrent->filename()), name(torrent->name())
1279                {}
1280                                               
1281                friend class boost::serialization::access;
1282                template<class Archive>
1283                void serialize(Archive& ar, const unsigned int version)
1284                {
1285                        if (version < 1)
1286                        {
1287                                TorrentInternalOld t;
1288                                ar & make_nvp("torrent", t);
1289                               
1290                                torrent.reset(new TorrentInternal(t));
1291                        }
1292                        else
1293                        {
1294                                ar & make_nvp("torrent", torrent);
1295                        } 
1296                       
1297                        ar & make_nvp("filename", filename);
1298                        ar & make_nvp("name", name);
1299                }
1300        };
1301       
1302        struct byFilename{};
1303        struct byName{};
1304       
1305        typedef boost::multi_index_container<
1306                TorrentHolder,
1307                boost::multi_index::indexed_by<
1308                        boost::multi_index::ordered_unique<
1309                                boost::multi_index::tag<byFilename>,
1310                                boost::multi_index::member<
1311                                        TorrentHolder, wstring_t, &TorrentHolder::filename> 
1312                                >,
1313                        boost::multi_index::ordered_unique<
1314                                boost::multi_index::tag<byName>,
1315                                boost::multi_index::member<
1316                                        TorrentHolder, wstring_t, &TorrentHolder::name> 
1317                                >
1318                >
1319        > TorrentMultiIndex;
1320       
1321public:
1322        typedef TorrentMultiIndex::index<byFilename>::type torrentByFilename;
1323        typedef TorrentMultiIndex::index<byName>::type torrentByName;
1324       
1325        TorrentManager(ini_file& ini) :
1326                iniClass("bittorrent", "TorrentManager", ini)
1327        {}
1328       
1329        TorrentManager& operator=(const TorrentMap& map)
1330        {
1331                torrents_.clear();
1332               
1333                for (TorrentMap::const_iterator i=map.begin(), e=map.end(); i != e; ++i)
1334                {       
1335                        TorrentInternal_ptr TIp(new TorrentInternal((*i).second));
1336                       
1337                        event().post(shared_ptr<EventDetail>(new EventMsg(
1338                                wformat_t(L"Converting %1%.") % TIp->name())));
1339                       
1340                        torrents_.insert(TorrentHolder(TIp));
1341                }
1342               
1343                return *this;
1344        }
1345       
1346        std::pair<torrentByName::iterator, bool> insert(const TorrentHolder& h)
1347        {
1348                return torrents_.get<byName>().insert(h);
1349        }
1350       
1351        std::pair<torrentByName::iterator, bool> insert(TorrentInternal_ptr t)
1352        {
1353                return insert(TorrentHolder(t));
1354        }
1355
1356        TorrentInternal_ptr getByFile(const wstring_t& filename)
1357        {
1358                torrentByFilename::iterator it = torrents_.get<byFilename>().find(filename);
1359               
1360                if (it != torrents_.get<byFilename>().end() && (*it).torrent)
1361                {
1362                        return (*it).torrent;
1363                }
1364               
1365                throw invalidTorrent(filename);
1366        }
1367       
1368        TorrentInternal_ptr get(const wstring_t& name)
1369        {
1370                torrentByName::iterator it = torrents_.get<byName>().find(name);
1371               
1372                if (it != torrents_.get<byName>().end() && (*it).torrent)
1373                {
1374                        return (*it).torrent;
1375                }
1376               
1377                throw invalidTorrent(name);
1378        }
1379       
1380        torrentByName::iterator erase(torrentByName::iterator where)
1381        {
1382                return torrents_.get<byName>().erase(where);
1383        }
1384       
1385        size_t size()
1386        {
1387                return torrents_.size();
1388        }
1389       
1390        size_t erase(const wstring_t& name)
1391        {
1392                return torrents_.get<byName>().erase(name);
1393        }
1394       
1395        bool exists(const wstring_t& name)
1396        {
1397                torrentByName::iterator it = torrents_.get<byName>().find(name);
1398               
1399                if (it != torrents_.get<byName>().end())
1400                        return true;
1401                else
1402                        return false;
1403        }
1404       
1405        torrentByName::iterator begin() { return torrents_.get<byName>().begin(); }
1406        torrentByName::iterator end() { return torrents_.get<byName>().end(); }
1407       
1408        friend class boost::serialization::access;
1409        template<class Archive>
1410        void serialize(Archive& ar, const unsigned int version)
1411        {
1412                ar & make_nvp("torrents", torrents_);
1413        }       
1414       
1415private:
1416        TorrentMultiIndex torrents_;
1417};
1418
1419void TorrentInternal::setConnectionLimit(int maxConn, int maxUpload)
1420{
1421        mutex_t::scoped_lock l(mutex_);
1422
1423        connections_ = maxConn;
1424        uploads_ = maxUpload;
1425       
1426        applyConnectionLimit();
1427}
1428
1429std::pair<int, int> TorrentInternal::getConnectionLimit()
1430{
1431        return std::make_pair(connections_, uploads_);
1432}
1433
1434void TorrentInternal::setTransferSpeed(float download, float upload)
1435{       
1436        mutex_t::scoped_lock l(mutex_);
1437
1438        transferLimit_ = std::make_pair(download, upload);
1439       
1440        applyTransferSpeed();
1441}
1442
1443std::pair<float, float> TorrentInternal::getTransferSpeed()
1444{
1445        return transferLimit_;
1446}
1447
1448TorrentDetail_ptr TorrentInternal::getTorrentDetail_ptr()
1449{       
1450        mutex_t::scoped_lock l(mutex_);
1451
1452        try
1453        {
1454
1455        if (inSession())
1456        {
1457                statusMemory_ = handle_.status();
1458                progress_ = statusMemory_.progress;
1459        }
1460        else
1461        {
1462                // Wipe these cause they don't make sense for a non-active torrent.
1463               
1464                statusMemory_.download_payload_rate = 0;
1465                statusMemory_.upload_payload_rate = 0;
1466                statusMemory_.next_announce = boost::posix_time::seconds(0);           
1467        }
1468       
1469        wstring_t state;
1470       
1471        switch (state_)
1472        {
1473        case TorrentDetail::torrent_paused:
1474                state = app().res_wstr(HAL_TORRENT_PAUSED);
1475                break;
1476               
1477        case TorrentDetail::torrent_pausing:
1478                state = app().res_wstr(HAL_TORRENT_PAUSING);
1479                break;
1480               
1481        case TorrentDetail::torrent_stopped:
1482                state = app().res_wstr(HAL_TORRENT_STOPPED);
1483                break;
1484               
1485        case TorrentDetail::torrent_stopping:
1486                state = app().res_wstr(HAL_TORRENT_STOPPING);
1487                break;
1488               
1489        default:
1490                switch (statusMemory_.state)
1491                {
1492                case lbt::torrent_status::queued_for_checking:
1493                        state = app().res_wstr(HAL_TORRENT_QUEUED_CHECKING);
1494                        break;
1495                case lbt::torrent_status::checking_files:
1496                        state = app().res_wstr(HAL_TORRENT_CHECKING_FILES);
1497                        break;
1498                case lbt::torrent_status::connecting_to_tracker:
1499                        state = app().res_wstr(HAL_TORRENT_CONNECTING);
1500                        break;
1501                case lbt::torrent_status::downloading_metadata:
1502                        state = app().res_wstr(HAL_TORRENT_METADATA);
1503                        break;
1504                case lbt::torrent_status::downloading:
1505                        state = app().res_wstr(HAL_TORRENT_DOWNLOADING);
1506                        break;
1507                case lbt::torrent_status::finished:
1508                        state = app().res_wstr(HAL_TORRENT_FINISHED);
1509                        break;
1510                case lbt::torrent_status::seeding:
1511                        state = app().res_wstr(HAL_TORRENT_SEEDING);
1512                        break;
1513                case lbt::torrent_status::allocating:
1514                        state = app().res_wstr(HAL_TORRENT_ALLOCATING);
1515                        break;
1516                }       
1517        }
1518       
1519        pt::time_duration td(pt::pos_infin);
1520       
1521        if (statusMemory_.download_payload_rate != 0)
1522        {
1523                td = boost::posix_time::seconds(       
1524                        long(float(statusMemory_.total_wanted-statusMemory_.total_wanted_done) / statusMemory_.download_payload_rate));
1525        }
1526       
1527        totalUploaded_ += (statusMemory_.total_payload_upload - totalBase_);
1528        totalBase_ = statusMemory_.total_payload_upload;
1529       
1530        uploaded_.update(statusMemory_.total_upload);
1531        payloadUploaded_.update(statusMemory_.total_payload_upload);
1532        downloaded_.update(statusMemory_.total_download);
1533        payloadDownloaded_.update(statusMemory_.total_payload_download);
1534       
1535        if (isActive())
1536        {
1537                activeDuration_.update();
1538               
1539                if (lbt::torrent_status::seeding == statusMemory_.state)
1540                        seedingDuration_.update();
1541        }       
1542       
1543        boost::tuple<size_t, size_t, size_t, size_t> connections = updatePeers();               
1544
1545        return TorrentDetail_ptr(new TorrentDetail(name_, filename_, saveDirectory(), state, hal::from_utf8(statusMemory_.current_tracker), 
1546                std::pair<float, float>(statusMemory_.download_payload_rate, statusMemory_.upload_payload_rate),
1547                progress_, statusMemory_.distributed_copies, statusMemory_.total_wanted_done, statusMemory_.total_wanted, uploaded_, payloadUploaded_,
1548                downloaded_, payloadDownloaded_, connections, ratio_, td, statusMemory_.next_announce, activeDuration_, seedingDuration_, startTime_, finishTime_));
1549
1550        }
1551        catch (const lbt::invalid_handle&)
1552        {
1553                event().post(shared_ptr<EventDetail>(
1554                        new EventInvalidTorrent(Event::critical, Event::invalidTorrent, to_utf8(name_), "getTorrentDetail_ptr")));
1555        }
1556        catch (const std::exception& e)
1557        {
1558                event().post(shared_ptr<EventDetail>(
1559                        new EventTorrentException(Event::critical, Event::torrentException, e.what(), to_utf8(name_), "getTorrentDetail_ptr")));
1560        }
1561       
1562        return TorrentDetail_ptr(new TorrentDetail(name_, filename_, saveDirectory(), app().res_wstr(HAL_TORRENT_STOPPED), app().res_wstr(HAL_NA)));
1563}
1564
1565} // namespace hal
1566
1567BOOST_CLASS_VERSION(hal::TorrentManager::TorrentHolder, 1)
1568
1569#endif // RC_INVOKED
1570
Note: See TracBrowser for help on using the repository browser.