@ -1969,6 +1969,7 @@ bool Session::addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams
bool Session : : addTorrent_impl ( CreateTorrentParams params , const MagnetUri & magnetUri ,
bool Session : : addTorrent_impl ( CreateTorrentParams params , const MagnetUri & magnetUri ,
TorrentInfo torrentInfo , const QByteArray & fastresumeData )
TorrentInfo torrentInfo , const QByteArray & fastresumeData )
{
{
# if (LIBTORRENT_VERSION_NUM < 10200)
params . savePath = normalizeSavePath ( params . savePath , " " ) ;
params . savePath = normalizeSavePath ( params . savePath , " " ) ;
if ( ! params . category . isEmpty ( ) ) {
if ( ! params . category . isEmpty ( ) ) {
@ -2000,12 +2001,9 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
lt : : torrent_handle handle = m_nativeSession - > find_torrent ( hash ) ;
lt : : torrent_handle handle = m_nativeSession - > find_torrent ( hash ) ;
// We need to pause it first to create TorrentHandle within the same
// We need to pause it first to create TorrentHandle within the same
// underlying state as in other cases.
// underlying state as in other cases.
# if (LIBTORRENT_VERSION_NUM < 10200)
handle . auto_managed ( false ) ;
handle . auto_managed ( false ) ;
# else
handle . unset_flags ( lt : : torrent_flags : : auto_managed ) ;
# endif
handle . pause ( ) ;
handle . pause ( ) ;
// createTorrentHandle() for this is called in the torrent_paused_alert handler
m_loadedMetadata . remove ( hash ) ;
m_loadedMetadata . remove ( hash ) ;
m_addingTorrents . insert ( hash , params ) ;
m_addingTorrents . insert ( hash , params ) ;
@ -2013,6 +2011,14 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
}
}
p = magnetUri . addTorrentParams ( ) ;
p = magnetUri . addTorrentParams ( ) ;
if ( isTempPathEnabled ( ) ) {
p . save_path = Utils : : Fs : : toNativePath ( tempPath ( ) ) . toStdString ( ) ;
}
else {
// If empty then Automatic mode, otherwise Manual mode
const QString savePath = params . savePath . isEmpty ( ) ? categorySavePath ( params . category ) : params . savePath ;
p . save_path = Utils : : Fs : : toNativePath ( savePath ) . toStdString ( ) ;
}
}
}
else {
else {
if ( ! torrentInfo . isValid ( ) ) {
if ( ! torrentInfo . isValid ( ) ) {
@ -2041,13 +2047,8 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
return true ;
return true ;
}
}
// Record if .fastresume is complete, that is whether it contains
// the required fields to resume a torrent.
bool hasCompleteFastresume = false ;
if ( ! fromMagnetUri ) {
if ( ! fromMagnetUri ) {
if ( params . restored ) { // load from existing fastresume
if ( params . restored ) { // load from existing fastresume
# if (LIBTORRENT_VERSION_NUM < 10200)
// Make sure the torrent will be initially checked and then paused
// Make sure the torrent will be initially checked and then paused
// to perform some service jobs on it. We will start it if needed.
// to perform some service jobs on it. We will start it if needed.
// (Workaround to easily support libtorrent-1.1
// (Workaround to easily support libtorrent-1.1
@ -2058,27 +2059,17 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
p . resume_data = std : : vector < char > { patchedFastresumeData . constData ( )
p . resume_data = std : : vector < char > { patchedFastresumeData . constData ( )
, ( patchedFastresumeData . constData ( ) + patchedFastresumeData . size ( ) ) } ;
, ( patchedFastresumeData . constData ( ) + patchedFastresumeData . size ( ) ) } ;
p . flags | = lt : : add_torrent_params : : flag_use_resume_save_path ;
p . flags | = lt : : add_torrent_params : : flag_use_resume_save_path ;
// Still setup the default parameters and let libtorrent handle
// the parameter merging
hasCompleteFastresume = false ;
# else
lt : : error_code ec ;
p = lt : : read_resume_data ( fastresumeData , ec ) ;
// libtorrent will always apply `file_priorities` to torrents,
// if the field is present then the fastresume is considered to
// be correctly generated and should be complete.
hasCompleteFastresume = ! p . file_priorities . empty ( ) ;
# endif
}
}
else { // new torrent
else { // new torrent
if ( ! params . hasRootFolder )
if ( ! params . hasRootFolder )
torrentInfo . stripRootFolder ( ) ;
torrentInfo . stripRootFolder ( ) ;
// If empty then Automatic mode, otherwise Manual mode
QString savePath = params . savePath . isEmpty ( ) ? categorySavePath ( params . category ) : params . savePath ;
// Metadata
// Metadata
if ( ! params . hasSeedStatus )
if ( ! params . hasSeedStatus )
findIncompleteFiles ( torrentInfo , savePath ) ;
findIncompleteFiles ( torrentInfo , savePath ) ; // if needed points savePath to incomplete folder too
p . save_path = Utils : : Fs : : toNativePath ( savePath ) . toStdString ( ) ;
// if torrent name wasn't explicitly set we handle the case of
// if torrent name wasn't explicitly set we handle the case of
// initial renaming of torrent content and rename torrent accordingly
// initial renaming of torrent content and rename torrent accordingly
@ -2095,12 +2086,7 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
std : : transform ( params . filePriorities . cbegin ( ) , params . filePriorities . cend ( )
std : : transform ( params . filePriorities . cbegin ( ) , params . filePriorities . cend ( )
, std : : back_inserter ( p . file_priorities ) , [ ] ( const DownloadPriority priority )
, std : : back_inserter ( p . file_priorities ) , [ ] ( const DownloadPriority priority )
{
{
# if (LIBTORRENT_VERSION_NUM < 10200)
return static_cast < boost : : uint8_t > ( priority ) ;
return static_cast < boost : : uint8_t > ( priority ) ;
# else
return static_cast < lt : : download_priority_t > (
static_cast < lt : : download_priority_t : : underlying_type > ( priority ) ) ;
# endif
} ) ;
} ) ;
}
}
@ -2108,63 +2094,184 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
}
}
// Common
// Common
# if (LIBTORRENT_VERSION_NUM < 10200)
p . flags & = ~ lt : : add_torrent_params : : flag_duplicate_is_error ; // Already checked
p . flags & = ~ lt : : add_torrent_params : : flag_duplicate_is_error ; // Already checked
# else
p . flags & = ~ lt : : torrent_flags : : duplicate_is_error ; // Already checked
# endif
// Make sure the torrent will be initially checked and then paused
// Make sure the torrent will be initially checked and then paused
// to perform some service jobs on it. We will start it if needed.
// to perform some service jobs on it. We will start it if needed.
# if (LIBTORRENT_VERSION_NUM < 10200)
p . flags | = lt : : add_torrent_params : : flag_paused ;
p . flags | = lt : : add_torrent_params : : flag_paused ;
p . flags | = lt : : add_torrent_params : : flag_auto_managed ;
p . flags | = lt : : add_torrent_params : : flag_auto_managed ;
p . flags | = lt : : add_torrent_params : : flag_stop_when_ready ;
p . flags | = lt : : add_torrent_params : : flag_stop_when_ready ;
// Limits
p . max_connections = maxConnectionsPerTorrent ( ) ;
p . max_uploads = maxUploadsPerTorrent ( ) ;
p . upload_limit = params . uploadLimit ;
p . download_limit = params . downloadLimit ;
// Preallocation mode
p . storage_mode = isPreallocationEnabled ( )
? lt : : storage_mode_allocate : lt : : storage_mode_sparse ;
// Seeding mode
// Skip checking and directly start seeding
if ( params . skipChecking )
p . flags | = lt : : add_torrent_params : : flag_seed_mode ;
else
p . flags & = ~ lt : : add_torrent_params : : flag_seed_mode ;
m_addingTorrents . insert ( hash , params ) ;
// Adding torrent to BitTorrent session
m_nativeSession - > async_add_torrent ( p ) ;
return true ;
# else
# else
p . flags | = lt : : torrent_flags : : paused ;
params . savePath = normalizeSavePath ( params . savePath , " " ) ;
p . flags | = lt : : torrent_flags : : auto_managed ;
p . flags | = lt : : torrent_flags : : stop_when_ready ;
# endif
if ( ! hasCompleteFastresume ) {
if ( ! params . category . isEmpty ( ) ) {
// Limits
if ( ! m_categories . contains ( params . category ) & & ! addCategory ( params . category ) )
p . max_connections = maxConnectionsPerTorrent ( ) ;
params . category = " " ;
p . max_uploads = maxUploadsPerTorrent ( ) ;
}
p . save_path = Utils : : Fs : : toNativePath ( savePath ) . toStdString ( ) ;
const bool fromMagnetUri = magnetUri . isValid ( ) ;
lt : : add_torrent_params p ;
InfoHash hash ;
if ( fromMagnetUri ) {
hash = magnetUri . hash ( ) ;
const auto it = m_loadedMetadata . constFind ( hash ) ;
if ( it ! = m_loadedMetadata . constEnd ( ) ) {
// Adding preloaded torrent...
const TorrentInfo metadata = it . value ( ) ;
if ( metadata . isValid ( ) ) {
// Metadata is received and torrent_handle is being deleted
// so we can't reuse it. Just add torrent using its metadata.
return addTorrent_impl ( params
, MagnetUri { } , metadata , fastresumeData ) ;
}
// Reuse existing torrent_handle
lt : : torrent_handle handle = m_nativeSession - > find_torrent ( hash ) ;
// We need to pause it first to create TorrentHandle within the same
// underlying state as in other cases.
handle . unset_flags ( lt : : torrent_flags : : auto_managed ) ;
handle . pause ( ) ;
// createTorrentHandle() for this is called in the torrent_paused_alert handler
m_loadedMetadata . remove ( hash ) ;
m_addingTorrents . insert ( hash , params ) ;
return true ;
}
p = magnetUri . addTorrentParams ( ) ;
if ( isTempPathEnabled ( ) ) {
p . save_path = Utils : : Fs : : toNativePath ( tempPath ( ) ) . toStdString ( ) ;
}
else {
// If empty then Automatic mode, otherwise Manual mode
const QString savePath = params . savePath . isEmpty ( ) ? categorySavePath ( params . category ) : params . savePath ;
p . save_path = Utils : : Fs : : toNativePath ( savePath ) . toStdString ( ) ;
}
}
else {
if ( ! torrentInfo . isValid ( ) ) {
// We can have an invalid torrentInfo when there isn't a matching
// .torrent file to the .fastresume we loaded. Possibly from a
// failed upgrade.
return false ;
}
hash = torrentInfo . hash ( ) ;
}
// We should not add the torrent if it is already
// processed or is pending to add to session
if ( m_addingTorrents . contains ( hash ) | | m_loadedMetadata . contains ( hash ) )
return false ;
TorrentHandle * const torrent = m_torrents . value ( hash ) ;
if ( torrent ) { // a duplicate torrent is added
if ( torrent - > isPrivate ( ) | | ( ! fromMagnetUri & & torrentInfo . isPrivate ( ) ) )
return false ;
// merge trackers and web seeds
torrent - > addTrackers ( fromMagnetUri ? magnetUri . trackers ( ) : torrentInfo . trackers ( ) ) ;
torrent - > addUrlSeeds ( fromMagnetUri ? magnetUri . urlSeeds ( ) : torrentInfo . urlSeeds ( ) ) ;
return true ;
}
if ( ! fromMagnetUri ) {
if ( params . restored ) { // load from existing fastresume
lt : : error_code ec ;
p = lt : : read_resume_data ( fastresumeData , ec ) ;
}
else { // new torrent
if ( ! params . hasRootFolder )
torrentInfo . stripRootFolder ( ) ;
// If empty then Automatic mode, otherwise Manual mode
QString savePath = params . savePath . isEmpty ( ) ? categorySavePath ( params . category ) : params . savePath ;
// Metadata
if ( ! params . hasSeedStatus )
findIncompleteFiles ( torrentInfo , savePath ) ; // if needed points savePath to incomplete folder too
p . save_path = Utils : : Fs : : toNativePath ( savePath ) . toStdString ( ) ;
// if torrent name wasn't explicitly set we handle the case of
// initial renaming of torrent content and rename torrent accordingly
if ( params . name . isEmpty ( ) ) {
QString contentName = torrentInfo . rootFolder ( ) ;
if ( contentName . isEmpty ( ) & & ( torrentInfo . filesCount ( ) = = 1 ) )
contentName = torrentInfo . fileName ( 0 ) ;
if ( ! contentName . isEmpty ( ) & & ( contentName ! = torrentInfo . name ( ) ) )
params . name = contentName ;
}
Q_ASSERT ( p . file_priorities . empty ( ) ) ;
std : : transform ( params . filePriorities . cbegin ( ) , params . filePriorities . cend ( )
, std : : back_inserter ( p . file_priorities ) , [ ] ( const DownloadPriority priority )
{
return static_cast < lt : : download_priority_t > (
static_cast < lt : : download_priority_t : : underlying_type > ( priority ) ) ;
} ) ;
}
p . ti = torrentInfo . nativeInfo ( ) ;
}
if ( fromMagnetUri & & params . restored & & params . addedTime . isValid ( ) )
p . added_time = params . addedTime . toSecsSinceEpoch ( ) ;
if ( fromMagnetUri | | ! params . restored ) {
p . upload_limit = params . uploadLimit ;
p . upload_limit = params . uploadLimit ;
p . download_limit = params . downloadLimit ;
p . download_limit = params . downloadLimit ;
# if (LIBTORRENT_VERSION_NUM >= 10200)
if ( params . addedTime . isValid ( ) )
p . added_time = params . addedTime . toSecsSinceEpoch ( ) ;
# endif
// Preallocation mode
// Preallocation mode
p . storage_mode = isPreallocationEnabled ( )
p . storage_mode = isPreallocationEnabled ( )
? lt : : storage_mode_allocate : lt : : storage_mode_sparse ;
? lt : : storage_mode_allocate : lt : : storage_mode_sparse ;
// Seeding mode
// Seeding mode
// Skip checking and directly start seeding
// Skip checking and directly start seeding
if ( params . skipChecking ) {
if ( params . skipChecking )
# if (LIBTORRENT_VERSION_NUM < 10200)
p . flags | = lt : : add_torrent_params : : flag_seed_mode ;
# else
p . flags | = lt : : torrent_flags : : seed_mode ;
p . flags | = lt : : torrent_flags : : seed_mode ;
# endif
else
}
else {
# if (LIBTORRENT_VERSION_NUM < 10200)
p . flags & = ~ lt : : add_torrent_params : : flag_seed_mode ;
# else
p . flags & = ~ lt : : torrent_flags : : seed_mode ;
p . flags & = ~ lt : : torrent_flags : : seed_mode ;
# endif
}
}
}
// Common
p . flags & = ~ lt : : torrent_flags : : duplicate_is_error ; // Already checked
// Make sure the torrent will be initially checked and then paused
// to perform some service jobs on it. We will start it if needed.
p . flags | = lt : : torrent_flags : : paused ;
p . flags | = lt : : torrent_flags : : auto_managed ;
p . flags | = lt : : torrent_flags : : stop_when_ready ;
// Limits
p . max_connections = maxConnectionsPerTorrent ( ) ;
p . max_uploads = maxUploadsPerTorrent ( ) ;
m_addingTorrents . insert ( hash , params ) ;
m_addingTorrents . insert ( hash , params ) ;
// Adding torrent to BitTorrent session
// Adding torrent to BitTorrent session
m_nativeSession - > async_add_torrent ( p ) ;
m_nativeSession - > async_add_torrent ( p ) ;
return true ;
return true ;
# endif
}
}
bool Session : : findIncompleteFiles ( TorrentInfo & torrentInfo , QString & savePath ) const
bool Session : : findIncompleteFiles ( TorrentInfo & torrentInfo , QString & savePath ) const