(trunk) #2802, #2716, #2717 -- remember magnet links and their settings between sessions, and allow their trackers to be modified

This commit is contained in:
Charles Kerr 2010-02-02 22:45:22 +00:00
parent b9e8624b3c
commit 36d97610bd
16 changed files with 324 additions and 221 deletions

View File

@ -381,7 +381,7 @@ main( int argc,
if( fileContents != NULL ) {
tr_ctorSetMetainfo( ctor, fileContents, fileLength );
} else if( !memcmp( torrentPath, "magnet:?", 8 ) ) {
tr_ctorSetMagnet( ctor, torrentPath );
tr_ctorSetMetainfoFromMagnetLink( ctor, torrentPath );
} else if( !memcmp( torrentPath, "http", 4 ) ) {
tr_webRun( h, torrentPath, NULL, onTorrentFileDownloaded, ctor );
waitingOnWeb = TRUE;

View File

@ -1052,7 +1052,7 @@ tr_core_add_from_url( TrCore * core, const char * url )
if( gtr_is_hex_hashcode( url ) )
url = tmp = g_strdup_printf( "magnet:?xt=urn:btih:%s", url );
err = tr_ctorSetMagnet( ctor, url );
err = tr_ctorSetMetainfoFromMagnetLink( ctor, url );
if( !err )
{

View File

@ -671,8 +671,7 @@ tr_bencListAdd( tr_benc * list )
}
tr_benc *
tr_bencListAddInt( tr_benc * list,
int64_t val )
tr_bencListAddInt( tr_benc * list, int64_t val )
{
tr_benc * node = tr_bencListAdd( list );
@ -681,15 +680,37 @@ tr_bencListAddInt( tr_benc * list,
}
tr_benc *
tr_bencListAddStr( tr_benc * list,
const char * val )
tr_bencListAddReal( tr_benc * list, double val )
{
tr_benc * node = tr_bencListAdd( list );
tr_bencInitReal( node, val );
return node;
}
tr_benc *
tr_bencListAddBool( tr_benc * list, tr_bool val )
{
tr_benc * node = tr_bencListAdd( list );
tr_bencInitBool( node, val );
return node;
}
tr_benc *
tr_bencListAddStr( tr_benc * list, const char * val )
{
tr_benc * node = tr_bencListAdd( list );
tr_bencInitStr( node, val, -1 );
return node;
}
tr_benc *
tr_bencListAddRaw( tr_benc * list, const uint8_t * val, size_t len )
{
tr_benc * node = tr_bencListAdd( list );
tr_bencInitRaw( node, val, len );
return node;
}
tr_benc*
tr_bencListAddList( tr_benc * list,
size_t reserveCount )
@ -802,6 +823,35 @@ tr_bencDictAddStr( tr_benc * dict, const char * key, const char * val )
return child;
}
tr_benc*
tr_bencDictAddRaw( tr_benc * dict,
const char * key,
const void * src,
size_t len )
{
tr_benc * child;
/* see if it already exists, and if so, try to reuse it */
if(( child = tr_bencDictFind( dict, key ))) {
if( tr_bencIsString( child ) ) {
if( stringIsAlloced( child ) )
tr_free( child->val.s.str.ptr );
} else {
tr_bencDictRemove( dict, key );
child = NULL;
}
}
/* if it doesn't exist, create it */
if( child == NULL )
child = tr_bencDictAdd( dict, key );
/* set it */
tr_bencInitRaw( child, src, len );
return child;
}
tr_benc*
tr_bencDictAddList( tr_benc * dict,
const char * key,
@ -824,18 +874,6 @@ tr_bencDictAddDict( tr_benc * dict,
return child;
}
tr_benc*
tr_bencDictAddRaw( tr_benc * dict,
const char * key,
const void * src,
size_t len )
{
tr_benc * child = tr_bencDictAdd( dict, key );
tr_bencInitRaw( child, src, len );
return child;
}
int
tr_bencDictRemove( tr_benc * dict,
const char * key )
@ -1404,6 +1442,51 @@ static const struct WalkFuncs jsonWalkFuncs = { jsonIntFunc,
****
***/
static void
tr_bencListCopy( tr_benc * target, const tr_benc * src )
{
int i = 0;
const tr_benc * val;
while(( val = tr_bencListChild( (tr_benc*)src, i++ )))
{
if( tr_bencIsBool( val ) )
{
tr_bool boolVal = 0;
tr_bencGetBool( val, &boolVal );
tr_bencListAddBool( target, boolVal );
}
else if( tr_bencIsReal( val ) )
{
double realVal = 0;
tr_bencGetReal( val, &realVal );
tr_bencListAddReal( target, realVal );
}
else if( tr_bencIsInt( val ) )
{
int64_t intVal = 0;
tr_bencGetInt( val, &intVal );
tr_bencListAddInt( target, intVal );
}
else if( tr_bencIsString( val ) )
{
tr_bencListAddRaw( target, (const uint8_t*)getStr( val ), val->val.s.len );
}
else if( tr_bencIsDict( val ) )
{
tr_bencMergeDicts( tr_bencListAddDict( target, 0 ), val );
}
else if ( tr_bencIsList( val ) )
{
tr_bencListCopy( tr_bencListAddList( target, 0 ), val );
}
else
{
tr_err( "tr_bencListCopy skipping item" );
}
}
}
static size_t
tr_bencDictSize( const tr_benc * dict )
{
@ -1470,14 +1553,19 @@ tr_bencMergeDicts( tr_benc * target, const tr_benc * source )
}
else if( tr_bencIsString( val ) )
{
const char * strVal = NULL;
tr_bencGetStr( val, &strVal );
tr_bencDictAddStr( target, key, strVal );
tr_bencDictAddRaw( target, key, getStr( val ), val->val.s.len );
}
else if( tr_bencIsDict( val ) && tr_bencDictFindDict( target, key, &t ) )
{
tr_bencMergeDicts( t, val );
}
else if( tr_bencIsList( val ) )
{
if( tr_bencDictFind( target, key ) == NULL )
{
tr_bencListCopy( tr_bencDictAddList( target, key, tr_bencListSize( val ) ), val );
}
}
else
{
tr_dbg( "tr_bencMergeDicts skipping \"%s\"", key );

View File

@ -138,10 +138,16 @@ int tr_bencListReserve( tr_benc *, size_t reserveCount );
tr_benc * tr_bencListAdd( tr_benc * );
tr_benc * tr_bencListAddBool( tr_benc *, tr_bool val );
tr_benc * tr_bencListAddInt( tr_benc *, int64_t val );
tr_benc * tr_bencListAddReal( tr_benc *, double val );
tr_benc * tr_bencListAddStr( tr_benc *, const char * val );
tr_benc * tr_bencListAddRaw( tr_benc *, const uint8_t * val, size_t len );
tr_benc * tr_bencListAddList( tr_benc *, size_t reserveCount );
tr_benc * tr_bencListAddDict( tr_benc *, size_t reserveCount );

View File

@ -14,6 +14,7 @@
#include <string.h> /* strchr() */
#include "transmission.h"
#include "bencode.h"
#include "magnet.h"
#include "utils.h"
#include "web.h"
@ -193,3 +194,35 @@ tr_magnetFree( tr_magnet_info * info )
tr_free( info );
}
}
void
tr_magnetCreateMetainfo( const tr_magnet_info * info, tr_benc * top )
{
int i;
tr_benc * d;
tr_bencInitDict( top, 4 );
/* announce list */
if( info->trackerCount == 1 )
tr_bencDictAddStr( top, "announce", info->trackers[0] );
else {
tr_benc * trackers = tr_bencDictAddList( top, "announce-list", info->trackerCount );
for( i=0; i<info->trackerCount; ++i )
tr_bencListAddStr( tr_bencListAddList( trackers, 1 ), info->trackers[i] );
}
/* webseeds */
if( info->webseedCount > 0 ) {
tr_benc * urls = tr_bencDictAddList( top, "url-list", info->webseedCount );
for( i=0; i<info->webseedCount; ++i )
tr_bencListAddStr( urls, info->webseeds[i] );
}
/* nonstandard keys */
d = tr_bencDictAddDict( top, "magnet-info", 2 );
tr_bencDictAddRaw( d, "info_hash", info->hash, 20 );
if( info->displayName != NULL )
tr_bencDictAddStr( d, "display-name", info->displayName );
}

View File

@ -35,6 +35,10 @@ tr_magnet_info;
tr_magnet_info * tr_magnetParse( const char * uri );
struct tr_benc;
void tr_magnetCreateMetainfo( const tr_magnet_info *, struct tr_benc * );
void tr_magnetFree( tr_magnet_info * info );
#endif

View File

@ -26,7 +26,6 @@
#include "session.h"
#include "bencode.h"
#include "crypto.h" /* tr_sha1 */
#include "magnet.h"
#include "metainfo.h"
#include "platform.h"
#include "utils.h"
@ -384,29 +383,61 @@ escape( char * out, const uint8_t * in, size_t in_len ) /* rfc2396 */
}
static const char*
tr_metainfoParseImpl( const tr_session * session,
tr_info * inf,
int * infoDictOffset,
int * infoDictLength,
const tr_benc * meta_in )
tr_metainfoParseImpl( const tr_session * session,
tr_info * inf,
tr_bool * hasInfoDict,
int * infoDictOffset,
int * infoDictLength,
const tr_benc * meta_in )
{
int64_t i;
size_t raw_len;
const char * str;
const uint8_t * raw;
tr_benc * beInfo;
tr_benc * d;
tr_benc * infoDict = NULL;
tr_benc * meta = (tr_benc *) meta_in;
tr_bool err;
tr_bool b;
tr_bool isMagnet = FALSE;
/* info_hash: urlencoded 20-byte SHA1 hash of the value of the info key
* from the Metainfo file. Note that the value will be a bencoded
* dictionary, given the definition of the info key above. */
if( !tr_bencDictFindDict( meta, "info", &beInfo ) )
return "info";
b = tr_bencDictFindDict( meta, "info", &infoDict );
if( hasInfoDict != NULL )
*hasInfoDict = b;
if( !b )
{
/* no info dictionary... is this a magnet link? */
if( tr_bencDictFindDict( meta, "magnet-info", &d ) )
{
isMagnet = TRUE;
/* get the info-hash */
if( !tr_bencDictFindRaw( d, "info_hash", &raw, &raw_len ) )
return "info_hash";
if( raw_len != SHA_DIGEST_LENGTH )
return "info_hash";
memcpy( inf->hash, raw, raw_len );
tr_sha1_to_hex( inf->hashString, inf->hash );
escape( inf->hashEscaped, inf->hash, SHA_DIGEST_LENGTH );
/* maybe get the display name */
if( tr_bencDictFindStr( d, "display-name", &str ) ) {
tr_free( inf->name );
inf->name = tr_strdup( str );
}
}
else /* not a magnet link and has no info dict... */
{
return "info";
}
}
else
{
int len;
char * bstr = tr_bencToStr( beInfo, TR_FMT_BENC, &len );
char * bstr = tr_bencToStr( infoDict, TR_FMT_BENC, &len );
tr_sha1( inf->hash, bstr, len, NULL );
tr_sha1_to_hex( inf->hashString, inf->hash );
escape( inf->hashEscaped, inf->hash, SHA_DIGEST_LENGTH );
@ -430,13 +461,15 @@ tr_metainfoParseImpl( const tr_session * session,
}
/* name */
if( !tr_bencDictFindStr( beInfo, "name.utf-8", &str ) )
if( !tr_bencDictFindStr( beInfo, "name", &str ) )
str = "";
if( !str || !*str )
return "name";
tr_free( inf->name );
inf->name = tr_utf8clean( str, -1, &err );
if( !isMagnet ) {
if( !tr_bencDictFindStr( infoDict, "name.utf-8", &str ) )
if( !tr_bencDictFindStr( infoDict, "name", &str ) )
str = "";
if( !str || !*str )
return "name";
tr_free( inf->name );
inf->name = tr_utf8clean( str, -1, &err );
}
/* comment */
if( !tr_bencDictFindStr( meta, "comment.utf-8", &str ) )
@ -458,35 +491,42 @@ tr_metainfoParseImpl( const tr_session * session,
inf->dateCreated = i;
/* private */
if( !tr_bencDictFindInt( beInfo, "private", &i ) )
if( !tr_bencDictFindInt( infoDict, "private", &i ) )
if( !tr_bencDictFindInt( meta, "private", &i ) )
i = 0;
inf->isPrivate = i != 0;
/* piece length */
if( !tr_bencDictFindInt( beInfo, "piece length", &i ) || ( i < 1 ) )
return "piece length";
inf->pieceSize = i;
if( !isMagnet ) {
if( !tr_bencDictFindInt( infoDict, "piece length", &i ) || ( i < 1 ) )
return "piece length";
inf->pieceSize = i;
}
/* pieces */
if( !tr_bencDictFindRaw( beInfo, "pieces", &raw,
&raw_len ) || ( raw_len % SHA_DIGEST_LENGTH ) )
return "pieces";
inf->pieceCount = raw_len / SHA_DIGEST_LENGTH;
inf->pieces = tr_new0( tr_piece, inf->pieceCount );
for( i = 0; i < inf->pieceCount; ++i )
memcpy( inf->pieces[i].hash, &raw[i * SHA_DIGEST_LENGTH],
SHA_DIGEST_LENGTH );
if( !isMagnet ) {
if( !tr_bencDictFindRaw( infoDict, "pieces", &raw, &raw_len ) )
return "pieces";
if( raw_len % SHA_DIGEST_LENGTH )
return "pieces";
inf->pieceCount = raw_len / SHA_DIGEST_LENGTH;
inf->pieces = tr_new0( tr_piece, inf->pieceCount );
for( i = 0; i < inf->pieceCount; ++i )
memcpy( inf->pieces[i].hash, &raw[i * SHA_DIGEST_LENGTH],
SHA_DIGEST_LENGTH );
}
/* files */
if( ( str = parseFiles( inf, tr_bencDictFind( beInfo, "files" ),
tr_bencDictFind( beInfo, "length" ) ) ) )
return str;
if( !inf->fileCount || !inf->totalSize )
return "files";
if( (uint64_t) inf->pieceCount !=
( inf->totalSize + inf->pieceSize - 1 ) / inf->pieceSize )
return "files";
if( !isMagnet ) {
if( ( str = parseFiles( inf, tr_bencDictFind( infoDict, "files" ),
tr_bencDictFind( infoDict, "length" ) ) ) )
return str;
if( !inf->fileCount || !inf->totalSize )
return "files";
if( (uint64_t) inf->pieceCount !=
( inf->totalSize + inf->pieceSize - 1 ) / inf->pieceSize )
return "files";
}
/* get announce or announce-list */
if( ( str = getannounce( inf, meta ) ) )
@ -504,13 +544,15 @@ tr_metainfoParseImpl( const tr_session * session,
tr_bool
tr_metainfoParse( const tr_session * session,
const tr_benc * meta_in,
tr_info * inf,
tr_bool * hasInfoDict,
int * infoDictOffset,
int * infoDictLength,
const tr_benc * meta_in )
int * infoDictLength )
{
const char * badTag = tr_metainfoParseImpl( session,
inf,
hasInfoDict,
infoDictOffset,
infoDictLength,
meta_in );
@ -569,49 +611,3 @@ tr_metainfoRemoveSaved( const tr_session * session,
unlink( filename );
tr_free( filename );
}
/***
****
***/
void
tr_metainfoSetFromMagnet( tr_info * inf, const tr_magnet_info * m )
{
/* hash */
memcpy( inf->hash, m->hash, 20 );
tr_sha1_to_hex( inf->hashString, inf->hash );
escape( inf->hashEscaped, inf->hash, SHA_DIGEST_LENGTH );
/* name */
if( m->displayName && *m->displayName )
inf->name = tr_strdup( m->displayName );
else
inf->name = tr_strdup( inf->hashString );
/* trackers */
if(( inf->trackerCount = m->trackerCount ))
{
int i;
const int n = m->trackerCount;
inf->trackers = tr_new0( tr_tracker_info, n );
for( i=0; i<n; ++i ) {
const char * url = m->trackers[i];
inf->trackers[i].tier = i;
inf->trackers[i].announce = tr_strdup( url );
inf->trackers[i].scrape = tr_convertAnnounceToScrape( url );
inf->trackers[i].id = i;
}
}
/* webseeds */
if(( inf->webseedCount = m->webseedCount ))
{
int i;
const int n = m->webseedCount;
inf->webseeds = tr_new0( char*, n );
for( i=0; i<n; ++i )
inf->webseeds[i] = tr_strdup( m->webseeds[i] );
}
}

View File

@ -20,13 +20,13 @@
#include "transmission.h"
struct tr_benc;
struct tr_magnet_info;
tr_bool tr_metainfoParse( const tr_session * session,
const struct tr_benc * benc,
tr_info * setmeInfo,
tr_bool * setmeHasInfoDict,
int * setmeInfoDictOffset,
int * setmeInfoDictLength,
const struct tr_benc * benc );
int * setmeInfoDictLength );
void tr_metainfoRemoveSaved( const tr_session * session,
const tr_info * info );
@ -34,7 +34,5 @@ void tr_metainfoRemoveSaved( const tr_session * session,
void tr_metainfoMigrate( tr_session * session,
tr_info * inf );
void tr_metainfoSetFromMagnet( tr_info * inf, const struct tr_magnet_info * m );
#endif

View File

@ -517,9 +517,12 @@ tr_torrentSaveResume( const tr_torrent * tor )
tr_bencDictAddInt( &top, KEY_BANDWIDTH_PRIORITY, tr_torrentGetPriority( tor ) );
tr_bencDictAddBool( &top, KEY_PAUSED, !tor->isRunning );
savePeers( &top, tor );
saveFilePriorities( &top, tor );
saveDND( &top, tor );
saveProgress( &top, tor );
if( tr_torrentHasMetadata( tor ) )
{
saveFilePriorities( &top, tor );
saveDND( &top, tor );
saveProgress( &top, tor );
}
saveSpeedLimits( &top, tor );
saveRatioLimits( &top, tor );

View File

@ -1118,7 +1118,7 @@ torrentAdd( tr_session * session,
}
else if( !strncmp( fname, "magnet:?", 8 ) )
{
tr_ctorSetMagnet( ctor, fname );
tr_ctorSetMetainfoFromMagnetLink( ctor, fname );
}
else
{

View File

@ -44,8 +44,6 @@ struct tr_ctor
tr_benc metainfo;
char * sourceFile;
tr_magnet_info * magnetInfo;
struct optional_args optionalArgs[2];
char * incompleteDir;
@ -106,16 +104,26 @@ tr_ctorGetSourceFile( const tr_ctor * ctor )
}
int
tr_ctorSetMagnet( tr_ctor * ctor, const char * uri )
tr_ctorSetMetainfoFromMagnetLink( tr_ctor * ctor, const char * magnet_link )
{
int err;
tr_magnet_info * magnet_info = tr_magnetParse( magnet_link );
if( ctor->magnetInfo != NULL )
tr_magnetFree( ctor->magnetInfo );
if( magnet_info == NULL )
err = -1;
else {
int len;
tr_benc tmp;
char * str;
ctor->magnetInfo = tr_magnetParse( uri );
tr_magnetCreateMetainfo( magnet_info, &tmp );
str = tr_bencToStr( &tmp, TR_FMT_BENC, &len );
err = tr_ctorSetMetainfo( ctor, (const uint8_t*)str, len );
tr_free( str );
tr_magnetFree( magnet_info );
}
err = ctor->magnetInfo == NULL;
return err;
}
@ -389,19 +397,6 @@ tr_ctorGetIncompleteDir( const tr_ctor * ctor,
return err;
}
int
tr_ctorGetMagnet( const tr_ctor * ctor, const tr_magnet_info ** setme )
{
int err = 0;
if( ctor->magnetInfo == NULL )
err = 1;
else
*setme = ctor->magnetInfo;
return err;
}
int
tr_ctorGetMetainfo( const tr_ctor * ctor,
const tr_benc ** setme )

View File

@ -138,10 +138,7 @@ tr_torrentGetMetadataPiece( const tr_torrent * tor, int piece, int * len )
}
void
tr_torrentSetMetadataPiece( tr_torrent * tor,
int piece,
const void * data,
int len )
tr_torrentSetMetadataPiece( tr_torrent * tor, int piece, const void * data, int len )
{
int i;
struct tr_incomplete_metadata * m;
@ -179,58 +176,48 @@ tr_torrentSetMetadataPiece( tr_torrent * tor,
if( m->piecesNeededCount == 0 )
{
tr_bool success = FALSE;
tr_bool checksumPassed = FALSE;
tr_bool metainfoParsed = FALSE;
uint8_t sha1[SHA_DIGEST_LENGTH];
/* we've got a complete set of metainfo... see if it passes the checksum test */
dbgmsg( tor, "metainfo piece %d was the last one", piece );
tr_sha1( sha1, m->metadata, m->metadata_size, NULL );
if( !memcmp( sha1, tor->info.hash, SHA_DIGEST_LENGTH ) )
if(( checksumPassed = !memcmp( sha1, tor->info.hash, SHA_DIGEST_LENGTH )))
{
int err;
tr_benc dict;
struct evbuffer * buf = evbuffer_new( );
dbgmsg( tor, "metadata checksum passed! (length: %d)", (int)m->metadata_size );
/* add a wrapper dictionary to the benc.
* include the announce-list too,
* so we can save it in the .torrent for future sessions */
evbuffer_add_printf( buf, "d" );
evbuffer_add_printf( buf, "13:announce-list" );
evbuffer_add_printf( buf, "l" );
for( i=0; i<tor->info.trackerCount; ++i ) {
const char * url = tor->info.trackers[i].announce;
evbuffer_add_printf( buf, "l%zu:%se", strlen( url ), url );
}
evbuffer_add_printf( buf, "e" );
evbuffer_add_printf( buf, "4:info" );
evbuffer_add( buf, m->metadata, m->metadata_size );
evbuffer_add_printf( buf, "e" );
/* does it parse? */
err = tr_bencLoad( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ), &dict, NULL );
/* checksum passed; now try to parse it as benc */
tr_benc infoDict;
const int err = tr_bencLoad( m->metadata, m->metadata_size, &infoDict, NULL );
dbgmsg( tor, "err is %d", err );
if( !err )
if(( metainfoParsed = !err ))
{
if( tr_metainfoParse( tor->session,
&tor->info,
&tor->infoDictOffset,
&tor->infoDictLength,
&dict ) )
/* yay we have bencoded metainfo... merge it into our .torrnet file */
tr_benc newMetainfo;
const char * path = tor->info.torrent;
if( !tr_bencLoadFile( &newMetainfo, TR_FMT_BENC, path ) )
{
const char * path = tor->info.torrent;
dbgmsg( tor, "saving completed metadata to \"%s\"", path );
tr_bool hasInfo;
tr_benc * tmp;
dbgmsg( tor, "Saving completed metadata to \"%s\"", path );
assert( !tr_bencDictFindDict( &newMetainfo, "info", &tmp ) );
tr_bencMergeDicts( tr_bencDictAddDict( &newMetainfo, "info", 0 ), &infoDict );
tr_bencToFile( &newMetainfo, TR_FMT_BENC, path );
success = tr_metainfoParse( tor->session, &newMetainfo, &tor->info,
&hasInfo, &tor->infoDictOffset, &tor->infoDictLength );
assert( hasInfo );
assert( success );
success = TRUE;
tr_torrentGotNewInfoDict( tor );
tr_bencToFile( &dict, TR_FMT_BENC, path );
tr_sessionSetTorrentFile( tor->session,
tor->info.hashString, path );
tr_torrentSetDirty( tor );
tr_bencFree( &newMetainfo );
}
tr_bencFree( &dict );
tr_bencFree( &infoDict );
}
evbuffer_free( buf );
}
if( success )
@ -241,12 +228,16 @@ tr_torrentSetMetadataPiece( tr_torrent * tor,
else /* drat. */
{
const int n = m->pieceCount;
for( i=0; i<n; ++i ) {
for( i=0; i<n; ++i )
{
m->piecesNeeded[i].piece = i;
m->piecesNeeded[i].requestedAt = 0;
}
m->piecesNeededCount = n;
dbgmsg( tor, "metadata error; trying again. %d pieces left", n );
tr_err( "magnet status: checksum passed %d, metainfo parsed %d",
(int)checksumPassed, (int)metainfoParsed );
}
}
}

View File

@ -712,10 +712,11 @@ torrentInit( tr_torrent * tor, const tr_ctor * ctor )
static tr_parse_result
torrentParseImpl( const tr_ctor * ctor, tr_info * setmeInfo,
int * dictOffset, int * dictLength )
tr_bool * setmeHasInfo, int * dictOffset, int * dictLength )
{
int doFree;
tr_bool didParse;
tr_bool hasInfo = FALSE;
tr_info tmp;
const tr_benc * metainfo;
tr_session * session = tr_ctorGetSession( ctor );
@ -728,13 +729,14 @@ torrentParseImpl( const tr_ctor * ctor, tr_info * setmeInfo,
if( tr_ctorGetMetainfo( ctor, &metainfo ) )
return TR_PARSE_ERR;
didParse = tr_metainfoParse( session, setmeInfo, dictOffset, dictLength, metainfo );
didParse = tr_metainfoParse( session, metainfo, setmeInfo,
&hasInfo, dictOffset, dictLength );
doFree = didParse && ( setmeInfo == &tmp );
if( !didParse )
result = TR_PARSE_ERR;
if( didParse && !getBlockSize( setmeInfo->pieceSize ) )
if( didParse && hasInfo && !getBlockSize( setmeInfo->pieceSize ) )
result = TR_PARSE_ERR;
if( didParse && session && tr_torrentExists( session, setmeInfo->hash ) )
@ -743,56 +745,46 @@ torrentParseImpl( const tr_ctor * ctor, tr_info * setmeInfo,
if( doFree )
tr_metainfoFree( setmeInfo );
if( setmeHasInfo != NULL )
*setmeHasInfo = hasInfo;
return result;
}
tr_parse_result
tr_torrentParse( const tr_ctor * ctor, tr_info * setmeInfo )
{
return torrentParseImpl( ctor, setmeInfo, NULL, NULL );
return torrentParseImpl( ctor, setmeInfo, NULL, NULL, NULL );
}
tr_torrent *
tr_torrentNew( const tr_ctor * ctor, int * setmeError )
{
int off, len;
tr_bool hasInfo;
tr_info tmpInfo;
tr_parse_result r;
tr_torrent * tor = NULL;
const tr_magnet_info * magnetInfo;
tr_session * session = tr_ctorGetSession( ctor );
assert( ctor != NULL );
assert( tr_isSession( session ) );
if( !tr_ctorGetMagnet( ctor, &magnetInfo ) )
r = torrentParseImpl( ctor, &tmpInfo, &hasInfo, &off, &len );
if( r == TR_PARSE_OK )
{
if( tr_torrentFindFromHash( session, magnetInfo->hash ) != NULL )
tor = tr_new0( tr_torrent, 1 );
tor->info = tmpInfo;
if( hasInfo )
{
if( setmeError )
*setmeError = TR_PARSE_DUPLICATE;
}
else
{
tor = tr_new0( tr_torrent, 1 );
tr_metainfoSetFromMagnet( &tor->info, magnetInfo );
torrentInit( tor, ctor );
}
}
else
{
int off, len;
tr_parse_result r = torrentParseImpl( ctor, &tmpInfo, &off, &len );
if( r == TR_PARSE_OK )
{
tor = tr_new0( tr_torrent, 1 );
tor->info = tmpInfo;
tor->infoDictOffset = off;
tor->infoDictLength = len;
torrentInit( tor, ctor );
}
else if( setmeError )
{
*setmeError = r;
}
torrentInit( tor, ctor );
}
else if( setmeError )
{
*setmeError = r;
}
return tor;
@ -1469,7 +1461,7 @@ tr_torrentSave( tr_torrent * tor )
{
assert( tr_isTorrent( tor ) );
if( tor->isDirty && tr_torrentHasMetadata( tor ) )
if( tor->isDirty )
{
tor->isDirty = FALSE;
tr_torrentSaveResume( tor );
@ -2131,7 +2123,8 @@ tr_torrentSetAnnounceList( tr_torrent * tor,
/* save to the .torrent file */
if( ok && !tr_bencLoadFile( &metainfo, TR_FMT_BENC, tor->info.torrent ) )
{
tr_info tmpInfo;
tr_bool hasInfo;
tr_info tmpInfo;
/* remove the old fields */
tr_bencDictRemove( &metainfo, "announce" );
@ -2160,10 +2153,8 @@ tr_torrentSetAnnounceList( tr_torrent * tor,
/* try to parse it back again, to make sure it's good */
memset( &tmpInfo, 0, sizeof( tr_info ) );
if( tr_metainfoParse( tor->session, &tmpInfo,
&tor->infoDictOffset,
&tor->infoDictLength,
&metainfo ) )
if( tr_metainfoParse( tor->session, &metainfo, &tmpInfo,
&hasInfo, &tor->infoDictOffset, &tor->infoDictLength ) )
{
/* it's good, so keep these new trackers and free the old ones */

View File

@ -34,8 +34,6 @@ void tr_ctorSetSave( tr_ctor * ctor,
int tr_ctorGetSave( const tr_ctor * ctor );
int tr_ctorGetMagnet( const tr_ctor * ctor, const struct tr_magnet_info ** setme );
void tr_ctorInitTorrentPriorities( const tr_ctor * ctor, tr_torrent * tor );
void tr_ctorInitTorrentWanted( const tr_ctor * ctor, tr_torrent * tor );

View File

@ -879,8 +879,8 @@ void tr_ctorFree( tr_ctor * ctor );
/** @brief Set whether or not to delete the source .torrent file when a torrent is added. (Default: False) */
void tr_ctorSetDeleteSource( tr_ctor * ctor, tr_bool doDelete );
/** @brief Set the link for creating a tr_torrent from a magnet link */
int tr_ctorSetMagnet( tr_ctor * ctor, const char * magnet_link );
/** @brief Set the constructor's metainfo from a magnet link */
int tr_ctorSetMetainfoFromMagnetLink( tr_ctor * ctor, const char * magnet_link );
/** @brief Set the constructor's metainfo from a raw benc already in memory */
int tr_ctorSetMetainfo( tr_ctor * ctor, const uint8_t * metainfo, size_t len );

View File

@ -1563,7 +1563,7 @@ int trashDataFile(const char * filename)
result = tr_ctorSetMetainfoFromFile(ctor, [path UTF8String]);
if (result != TR_PARSE_OK && magnetAddress)
result = tr_ctorSetMagnet(ctor, [magnetAddress UTF8String]);
result = tr_ctorSetMetainfoFromMagnetLink(ctor, [magnetAddress UTF8String]);
//backup - shouldn't be needed after upgrade to 1.70
if (result != TR_PARSE_OK && hashString)