transmission/libtransmission/torrent-ctor.c

479 lines
11 KiB
C

/*
* This file Copyright (C) 2007-2010 Mnemosyne LLC
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*
* $Id$
*/
#include <errno.h> /* EINVAL */
#include "transmission.h"
#include "bencode.h"
#include "magnet.h"
#include "platform.h"
#include "session.h" /* tr_sessionFindTorrentFile() */
#include "torrent.h" /* tr_ctorGetSave() */
#include "utils.h" /* tr_new0 */
struct optional_args
{
tr_bool isSet_paused;
tr_bool isSet_connected;
tr_bool isSet_downloadDir;
tr_bool isPaused;
uint16_t peerLimit;
char * downloadDir;
};
/** Opaque class used when instantiating torrents.
* @ingroup tr_ctor */
struct tr_ctor
{
const tr_session * session;
tr_bool saveInOurTorrentsDir;
tr_bool doDelete;
tr_priority_t bandwidthPriority;
tr_bool isSet_metainfo;
tr_bool isSet_delete;
tr_benc metainfo;
char * sourceFile;
struct optional_args optionalArgs[2];
char * incompleteDir;
tr_file_index_t * want;
tr_file_index_t wantSize;
tr_file_index_t * notWant;
tr_file_index_t notWantSize;
tr_file_index_t * low;
tr_file_index_t lowSize;
tr_file_index_t * normal;
tr_file_index_t normalSize;
tr_file_index_t * high;
tr_file_index_t highSize;
};
/***
****
***/
static void
setSourceFile( tr_ctor * ctor,
const char * sourceFile )
{
tr_free( ctor->sourceFile );
ctor->sourceFile = tr_strdup( sourceFile );
}
static void
clearMetainfo( tr_ctor * ctor )
{
if( ctor->isSet_metainfo )
{
ctor->isSet_metainfo = 0;
tr_bencFree( &ctor->metainfo );
}
setSourceFile( ctor, NULL );
}
int
tr_ctorSetMetainfo( tr_ctor * ctor,
const uint8_t * metainfo,
size_t len )
{
int err;
clearMetainfo( ctor );
err = tr_bencLoad( metainfo, len, &ctor->metainfo, NULL );
ctor->isSet_metainfo = !err;
return err;
}
const char*
tr_ctorGetSourceFile( const tr_ctor * ctor )
{
return ctor->sourceFile;
}
int
tr_ctorSetMetainfoFromMagnetLink( tr_ctor * ctor, const char * magnet_link )
{
int err;
tr_magnet_info * magnet_info = tr_magnetParse( magnet_link );
if( magnet_info == NULL )
err = -1;
else {
int len;
tr_benc tmp;
char * str;
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 );
}
return err;
}
int
tr_ctorSetMetainfoFromFile( tr_ctor * ctor,
const char * filename )
{
uint8_t * metainfo;
size_t len;
int err;
metainfo = tr_loadFile( filename, &len );
if( metainfo && len )
err = tr_ctorSetMetainfo( ctor, metainfo, len );
else
{
clearMetainfo( ctor );
err = 1;
}
setSourceFile( ctor, filename );
/* if no `name' field was set, then set it from the filename */
if( ctor->isSet_metainfo )
{
tr_benc * info;
if( tr_bencDictFindDict( &ctor->metainfo, "info", &info ) )
{
const char * name;
if( !tr_bencDictFindStr( info, "name.utf-8", &name ) )
if( !tr_bencDictFindStr( info, "name", &name ) )
name = NULL;
if( !name || !*name )
{
char * base = tr_basename( filename );
tr_bencDictAddStr( info, "name", base );
tr_free( base );
}
}
}
tr_free( metainfo );
return err;
}
int
tr_ctorSetMetainfoFromHash( tr_ctor * ctor,
const char * hashString )
{
int err;
const char * filename;
filename = tr_sessionFindTorrentFile( ctor->session, hashString );
if( !filename )
err = EINVAL;
else
err = tr_ctorSetMetainfoFromFile( ctor, filename );
return err;
}
/***
****
***/
void
tr_ctorSetFilePriorities( tr_ctor * ctor,
const tr_file_index_t * files,
tr_file_index_t fileCount,
tr_priority_t priority )
{
tr_file_index_t ** myfiles;
tr_file_index_t * mycount;
switch( priority ) {
case TR_PRI_LOW: myfiles = &ctor->low; mycount = &ctor->lowSize; break;
case TR_PRI_HIGH: myfiles = &ctor->high; mycount = &ctor->highSize; break;
default /*TR_PRI_NORMAL*/: myfiles = &ctor->normal; mycount = &ctor->normalSize; break;
}
tr_free( *myfiles );
*myfiles = tr_memdup( files, sizeof(tr_file_index_t)*fileCount );
*mycount = fileCount;
}
void
tr_ctorInitTorrentPriorities( const tr_ctor * ctor, tr_torrent * tor )
{
tr_file_index_t i;
for( i=0; i<ctor->lowSize; ++i )
tr_torrentInitFilePriority( tor, ctor->low[i], TR_PRI_LOW );
for( i=0; i<ctor->normalSize; ++i )
tr_torrentInitFilePriority( tor, ctor->normal[i], TR_PRI_NORMAL );
for( i=0; i<ctor->highSize; ++i )
tr_torrentInitFilePriority( tor, ctor->high[i], TR_PRI_HIGH );
}
void
tr_ctorSetFilesWanted( tr_ctor * ctor,
const tr_file_index_t * files,
tr_file_index_t fileCount,
tr_bool wanted )
{
tr_file_index_t ** myfiles = wanted ? &ctor->want : &ctor->notWant;
tr_file_index_t * mycount = wanted ? &ctor->wantSize : &ctor->notWantSize;
tr_free( *myfiles );
*myfiles = tr_memdup( files, sizeof(tr_file_index_t)*fileCount );
*mycount = fileCount;
}
void
tr_ctorInitTorrentWanted( const tr_ctor * ctor, tr_torrent * tor )
{
if( ctor->notWantSize )
tr_torrentInitFileDLs( tor, ctor->notWant, ctor->notWantSize, FALSE );
if( ctor->wantSize )
tr_torrentInitFileDLs( tor, ctor->want, ctor->wantSize, TRUE );
}
/***
****
***/
void
tr_ctorSetDeleteSource( tr_ctor * ctor,
tr_bool deleteSource )
{
ctor->doDelete = deleteSource != 0;
ctor->isSet_delete = 1;
}
int
tr_ctorGetDeleteSource( const tr_ctor * ctor,
uint8_t * setme )
{
int err = 0;
if( !ctor->isSet_delete )
err = 1;
else if( setme )
*setme = ctor->doDelete ? 1 : 0;
return err;
}
/***
****
***/
void
tr_ctorSetSave( tr_ctor * ctor,
tr_bool saveInOurTorrentsDir )
{
ctor->saveInOurTorrentsDir = saveInOurTorrentsDir != 0;
}
int
tr_ctorGetSave( const tr_ctor * ctor )
{
return ctor && ctor->saveInOurTorrentsDir;
}
void
tr_ctorSetPaused( tr_ctor * ctor,
tr_ctorMode mode,
tr_bool isPaused )
{
struct optional_args * args = &ctor->optionalArgs[mode];
args->isSet_paused = 1;
args->isPaused = isPaused ? 1 : 0;
}
void
tr_ctorSetPeerLimit( tr_ctor * ctor,
tr_ctorMode mode,
uint16_t peerLimit )
{
struct optional_args * args = &ctor->optionalArgs[mode];
args->isSet_connected = 1;
args->peerLimit = peerLimit;
}
void
tr_ctorSetDownloadDir( tr_ctor * ctor,
tr_ctorMode mode,
const char * directory )
{
struct optional_args * args = &ctor->optionalArgs[mode];
tr_free( args->downloadDir );
args->downloadDir = NULL;
args->isSet_downloadDir = 0;
if( directory && *directory )
{
args->isSet_downloadDir = 1;
args->downloadDir = tr_strdup( directory );
}
}
void
tr_ctorSetIncompleteDir( tr_ctor * ctor, const char * directory )
{
tr_free( ctor->incompleteDir );
ctor->incompleteDir = tr_strdup( directory );
}
int
tr_ctorGetPeerLimit( const tr_ctor * ctor,
tr_ctorMode mode,
uint16_t * setmeCount )
{
int err = 0;
const struct optional_args * args = &ctor->optionalArgs[mode];
if( !args->isSet_connected )
err = 1;
else if( setmeCount )
*setmeCount = args->peerLimit;
return err;
}
int
tr_ctorGetPaused( const tr_ctor * ctor,
tr_ctorMode mode,
uint8_t * setmeIsPaused )
{
int err = 0;
const struct optional_args * args = &ctor->optionalArgs[mode];
if( !args->isSet_paused )
err = 1;
else if( setmeIsPaused )
*setmeIsPaused = args->isPaused ? 1 : 0;
return err;
}
int
tr_ctorGetDownloadDir( const tr_ctor * ctor,
tr_ctorMode mode,
const char ** setmeDownloadDir )
{
int err = 0;
const struct optional_args * args = &ctor->optionalArgs[mode];
if( !args->isSet_downloadDir )
err = 1;
else if( setmeDownloadDir )
*setmeDownloadDir = args->downloadDir;
return err;
}
int
tr_ctorGetIncompleteDir( const tr_ctor * ctor,
const char ** setmeIncompleteDir )
{
int err = 0;
if( ctor->incompleteDir == NULL )
err = 1;
else
*setmeIncompleteDir = ctor->incompleteDir;
return err;
}
int
tr_ctorGetMetainfo( const tr_ctor * ctor,
const tr_benc ** setme )
{
int err = 0;
if( !ctor->isSet_metainfo )
err = 1;
else if( setme )
*setme = &ctor->metainfo;
return err;
}
tr_session*
tr_ctorGetSession( const tr_ctor * ctor )
{
return (tr_session*) ctor->session;
}
/***
****
***/
static tr_bool
isPriority( int i )
{
return (i==TR_PRI_LOW) || (i==TR_PRI_NORMAL) || (i==TR_PRI_HIGH);
}
void
tr_ctorSetBandwidthPriority( tr_ctor * ctor, tr_priority_t priority )
{
if( isPriority( priority ) )
ctor->bandwidthPriority = priority;
}
tr_priority_t
tr_ctorGetBandwidthPriority( const tr_ctor * ctor )
{
return ctor->bandwidthPriority;
}
/***
****
***/
tr_ctor*
tr_ctorNew( const tr_session * session )
{
tr_ctor * ctor = tr_new0( struct tr_ctor, 1 );
ctor->session = session;
ctor->bandwidthPriority = TR_PRI_NORMAL;
if( session != NULL )
{
tr_ctorSetDeleteSource( ctor, tr_sessionGetDeleteSource( session ) );
tr_ctorSetPaused( ctor, TR_FALLBACK, tr_sessionGetPaused( session ) );
tr_ctorSetPeerLimit( ctor, TR_FALLBACK, session->peerLimitPerTorrent );
tr_ctorSetDownloadDir( ctor, TR_FALLBACK, session->downloadDir );
}
tr_ctorSetSave( ctor, TRUE );
return ctor;
}
void
tr_ctorFree( tr_ctor * ctor )
{
clearMetainfo( ctor );
tr_free( ctor->optionalArgs[1].downloadDir );
tr_free( ctor->optionalArgs[0].downloadDir );
tr_free( ctor->incompleteDir );
tr_free( ctor->want );
tr_free( ctor->notWant );
tr_free( ctor->low );
tr_free( ctor->high );
tr_free( ctor->normal );
tr_free( ctor );
}