1 /*
2  * Bittorrent Client using Qt and libtorrent.
3  * Copyright (C) 2015  Vladimir Golovnev <glassez@yandex.ru>
4  * Copyright (C) 2006  Christophe Dumez <chris@qbittorrent.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  * In addition, as a special exception, the copyright holders give permission to
21  * link this program with the OpenSSL project's "OpenSSL" library (or with
22  * modified versions of it that use the same license as the "OpenSSL" library),
23  * and distribute the linked executables. You must obey the GNU General Public
24  * License in all respects for all of the code used other than "OpenSSL".  If you
25  * modify file(s), you may extend this exception to your version of the file(s),
26  * but you are not obligated to do so. If you do not wish to do so, delete this
27  * exception statement from your version.
28  */
29 
30 #pragma once
31 
32 #include <functional>
33 
34 #include <libtorrent/add_torrent_params.hpp>
35 #include <libtorrent/fwd.hpp>
36 #include <libtorrent/socket.hpp>
37 #include <libtorrent/torrent_handle.hpp>
38 #include <libtorrent/torrent_status.hpp>
39 
40 #include <QDateTime>
41 #include <QHash>
42 #include <QMap>
43 #include <QObject>
44 #include <QQueue>
45 #include <QSet>
46 #include <QString>
47 #include <QVector>
48 
49 #include "infohash.h"
50 #include "speedmonitor.h"
51 #include "torrent.h"
52 #include "torrentinfo.h"
53 
54 namespace BitTorrent
55 {
56     class Session;
57     struct AddTorrentParams;
58 
59     struct LoadTorrentParams
60     {
61         lt::add_torrent_params ltAddTorrentParams {};
62 
63         QString name;
64         QString category;
65         QSet<QString> tags;
66         QString savePath;
67         TorrentContentLayout contentLayout = TorrentContentLayout::Original;
68         bool firstLastPiecePriority = false;
69         bool hasSeedStatus = false;
70         bool forced = false;
71         bool paused = false;
72 
73         qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
74         int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
75 
76         bool restored = false;  // is existing torrent job?
77     };
78 
79     enum class MoveStorageMode
80     {
81         KeepExistingFiles,
82         Overwrite
83     };
84 
85     enum class MaintenanceJob
86     {
87         None,
88         HandleMetadata
89     };
90 
91     struct FileErrorInfo
92     {
93         lt::error_code error;
94         lt::operation_t operation;
95     };
96 
97     class TorrentImpl final : public QObject, public Torrent
98     {
99         Q_DISABLE_COPY(TorrentImpl)
100         Q_DECLARE_TR_FUNCTIONS(BitTorrent::TorrentImpl)
101 
102     public:
103         TorrentImpl(Session *session, lt::session *nativeSession
104                           , const lt::torrent_handle &nativeHandle, const LoadTorrentParams &params);
105         ~TorrentImpl() override;
106 
107         bool isValid() const;
108 
109         InfoHash infoHash() const override;
110         QString name() const override;
111         QDateTime creationDate() const override;
112         QString creator() const override;
113         QString comment() const override;
114         bool isPrivate() const override;
115         qlonglong totalSize() const override;
116         qlonglong wantedSize() const override;
117         qlonglong completedSize() const override;
118         qlonglong pieceLength() const override;
119         qlonglong wastedSize() const override;
120         QString currentTracker() const override;
121 
122         QString savePath(bool actual = false) const override;
123         QString rootPath(bool actual = false) const override;
124         QString contentPath(bool actual = false) const override;
125 
126         bool useTempPath() const override;
127 
128         bool isAutoTMMEnabled() const override;
129         void setAutoTMMEnabled(bool enabled) override;
130         QString category() const override;
131         bool belongsToCategory(const QString &category) const override;
132         bool setCategory(const QString &category) override;
133 
134         QSet<QString> tags() const override;
135         bool hasTag(const QString &tag) const override;
136         bool addTag(const QString &tag) override;
137         bool removeTag(const QString &tag) override;
138         void removeAllTags() override;
139 
140         int filesCount() const override;
141         int piecesCount() const override;
142         int piecesHave() const override;
143         qreal progress() const override;
144         QDateTime addedTime() const override;
145         qreal ratioLimit() const override;
146         int seedingTimeLimit() const override;
147 
148         QString filePath(int index) const override;
149         QString fileName(int index) const override;
150         qlonglong fileSize(int index) const override;
151         QStringList absoluteFilePaths() const override;
152         QVector<DownloadPriority> filePriorities() const override;
153 
154         TorrentInfo info() const override;
155         bool isSeed() const override;
156         bool isPaused() const override;
157         bool isQueued() const override;
158         bool isForced() const override;
159         bool isChecking() const override;
160         bool isDownloading() const override;
161         bool isUploading() const override;
162         bool isCompleted() const override;
163         bool isActive() const override;
164         bool isInactive() const override;
165         bool isErrored() const override;
166         bool isSequentialDownload() const override;
167         bool hasFirstLastPiecePriority() const override;
168         TorrentState state() const override;
169         bool hasMetadata() const override;
170         bool hasMissingFiles() const override;
171         bool hasError() const override;
172         bool hasFilteredPieces() const override;
173         int queuePosition() const override;
174         QVector<TrackerEntry> trackers() const override;
175         QVector<QUrl> urlSeeds() const override;
176         QString error() const override;
177         qlonglong totalDownload() const override;
178         qlonglong totalUpload() const override;
179         qlonglong activeTime() const override;
180         qlonglong finishedTime() const override;
181         qlonglong seedingTime() const override;
182         qlonglong eta() const override;
183         QVector<qreal> filesProgress() const override;
184         int seedsCount() const override;
185         int peersCount() const override;
186         int leechsCount() const override;
187         int totalSeedsCount() const override;
188         int totalPeersCount() const override;
189         int totalLeechersCount() const override;
190         int completeCount() const override;
191         int incompleteCount() const override;
192         QDateTime lastSeenComplete() const override;
193         QDateTime completedTime() const override;
194         qlonglong timeSinceUpload() const override;
195         qlonglong timeSinceDownload() const override;
196         qlonglong timeSinceActivity() const override;
197         int downloadLimit() const override;
198         int uploadLimit() const override;
199         bool superSeeding() const override;
200         bool isDHTDisabled() const override;
201         bool isPEXDisabled() const override;
202         bool isLSDDisabled() const override;
203         QVector<PeerInfo> peers() const override;
204         QBitArray pieces() const override;
205         QBitArray downloadingPieces() const override;
206         QVector<int> pieceAvailability() const override;
207         qreal distributedCopies() const override;
208         qreal maxRatio() const override;
209         int maxSeedingTime() const override;
210         qreal realRatio() const override;
211         int uploadPayloadRate() const override;
212         int downloadPayloadRate() const override;
213         qlonglong totalPayloadUpload() const override;
214         qlonglong totalPayloadDownload() const override;
215         int connectionsCount() const override;
216         int connectionsLimit() const override;
217         qlonglong nextAnnounce() const override;
218         QVector<qreal> availableFileFractions() const override;
219 
220         void setName(const QString &name) override;
221         void setSequentialDownload(bool enable) override;
222         void setFirstLastPiecePriority(bool enabled) override;
223         void pause() override;
224         void resume(TorrentOperatingMode mode = TorrentOperatingMode::AutoManaged) override;
225         void move(QString path) override;
226         void forceReannounce(int index = -1) override;
227         void forceDHTAnnounce() override;
228         void forceRecheck() override;
229         void renameFile(int index, const QString &path) override;
230         void prioritizeFiles(const QVector<DownloadPriority> &priorities) override;
231         void setRatioLimit(qreal limit) override;
232         void setSeedingTimeLimit(int limit) override;
233         void setUploadLimit(int limit) override;
234         void setDownloadLimit(int limit) override;
235         void setSuperSeeding(bool enable) override;
236         void setDHTDisabled(bool disable) override;
237         void setPEXDisabled(bool disable) override;
238         void setLSDDisabled(bool disable) override;
239         void flushCache() const override;
240         void addTrackers(const QVector<TrackerEntry> &trackers) override;
241         void replaceTrackers(const QVector<TrackerEntry> &trackers) override;
242         void addUrlSeeds(const QVector<QUrl> &urlSeeds) override;
243         void removeUrlSeeds(const QVector<QUrl> &urlSeeds) override;
244         bool connectPeer(const PeerAddress &peerAddress) override;
245         void clearPeers() override;
246 
247         QString createMagnetURI() const override;
248 
249         bool needSaveResumeData() const;
250 
251         // Session interface
252         lt::torrent_handle nativeHandle() const;
253 
254         void handleAlert(const lt::alert *a);
255         void handleStateUpdate(const lt::torrent_status &nativeStatus);
256         void handleTempPathChanged();
257         void handleCategorySavePathChanged();
258         void handleAppendExtensionToggled();
259         void saveResumeData();
260         void handleMoveStorageJobFinished(bool hasOutstandingJob);
261         void fileSearchFinished(const QString &savePath, const QStringList &fileNames);
262 
263         QString actualStorageLocation() const;
264 
265     private:
266         typedef std::function<void ()> EventTrigger;
267 
268         void updateStatus();
269         void updateStatus(const lt::torrent_status &nativeStatus);
270         void updateState();
271 
272         void handleFastResumeRejectedAlert(const lt::fastresume_rejected_alert *p);
273         void handleFileCompletedAlert(const lt::file_completed_alert *p);
274         void handleFileErrorAlert(const lt::file_error_alert *p);
275         void handleFileRenamedAlert(const lt::file_renamed_alert *p);
276         void handleFileRenameFailedAlert(const lt::file_rename_failed_alert *p);
277         void handleMetadataReceivedAlert(const lt::metadata_received_alert *p);
278         void handlePerformanceAlert(const lt::performance_alert *p) const;
279         void handleSaveResumeDataAlert(const lt::save_resume_data_alert *p);
280         void handleSaveResumeDataFailedAlert(const lt::save_resume_data_failed_alert *p);
281         void handleTorrentCheckedAlert(const lt::torrent_checked_alert *p);
282         void handleTorrentFinishedAlert(const lt::torrent_finished_alert *p);
283         void handleTorrentPausedAlert(const lt::torrent_paused_alert *p);
284         void handleTorrentResumedAlert(const lt::torrent_resumed_alert *p);
285         void handleTrackerErrorAlert(const lt::tracker_error_alert *p);
286         void handleTrackerReplyAlert(const lt::tracker_reply_alert *p);
287         void handleTrackerWarningAlert(const lt::tracker_warning_alert *p);
288 
289         bool isMoveInProgress() const;
290 
291         void setAutoManaged(bool enable);
292 
293         void adjustActualSavePath();
294         void adjustActualSavePath_impl();
295         void move_impl(QString path, MoveStorageMode mode);
296         void moveStorage(const QString &newPath, MoveStorageMode mode);
297         void manageIncompleteFiles();
298         void applyFirstLastPiecePriority(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {});
299 
300         void endReceivedMetadataHandling(const QString &savePath, const QStringList &fileNames);
301         void reload();
302 
303         Session *const m_session;
304         lt::session *m_nativeSession;
305         lt::torrent_handle m_nativeHandle;
306         lt::torrent_status m_nativeStatus;
307         TorrentState m_state = TorrentState::Unknown;
308         TorrentInfo m_torrentInfo;
309         SpeedMonitor m_speedMonitor;
310 
311         InfoHash m_infoHash;
312 
313         // m_moveFinishedTriggers is activated only when the following conditions are met:
314         // all file rename jobs complete, all file move jobs complete
315         QQueue<EventTrigger> m_moveFinishedTriggers;
316         int m_renameCount = 0;
317         bool m_storageIsMoving = false;
318 
319         MaintenanceJob m_maintenanceJob = MaintenanceJob::None;
320 
321         // Until libtorrent provide an "old_name" field in `file_renamed_alert`
322         // we will rely on this workaround to remove empty leftover folders
323         QHash<lt::file_index_t, QVector<QString>> m_oldPath;
324 
325         FileErrorInfo m_lastFileError;
326         QHash<QString, QMap<lt::tcp::endpoint, int>> m_trackerPeerCounts;
327 
328         // Persistent data
329         QString m_name;
330         QString m_savePath;
331         QString m_category;
332         QSet<QString> m_tags;
333         qreal m_ratioLimit;
334         int m_seedingTimeLimit;
335         TorrentOperatingMode m_operatingMode;
336         TorrentContentLayout m_contentLayout;
337         bool m_hasSeedStatus;
338         bool m_fastresumeDataRejected = false;
339         bool m_hasMissingFiles = false;
340         bool m_hasFirstLastPiecePriority = false;
341         bool m_useAutoTMM;
342         bool m_isStopped;
343 
344         bool m_unchecked = false;
345 
346         lt::add_torrent_params m_ltAddTorrentParams;
347     };
348 }
349