diff --git a/libtransmission/Makefile.am b/libtransmission/Makefile.am index 624c3245c..31bb9798b 100644 --- a/libtransmission/Makefile.am +++ b/libtransmission/Makefile.am @@ -28,6 +28,7 @@ libtransmission_a_SOURCES = \ shared.c \ stats.c \ torrent.c \ + torrent-ctor.c \ tracker.c \ transmission.c \ trevent.c \ diff --git a/libtransmission/torrent-ctor.c b/libtransmission/torrent-ctor.c new file mode 100644 index 000000000..89b9152e3 --- /dev/null +++ b/libtransmission/torrent-ctor.c @@ -0,0 +1,222 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * 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 "transmission.h" +#include "bencode.h" +#include "platform.h" +#include "trcompat.h" /* strlcpy */ +#include "utils.h" + +struct optional_args +{ + unsigned int isSet_paused : 1; + unsigned int isSet_unchoked : 1; + unsigned int isSet_connected : 1; + unsigned int isSet_destination : 1; + + unsigned int isPaused : 1; + uint8_t maxUnchokedPeers; + uint16_t maxConnectedPeers; + char destination[MAX_PATH_LENGTH]; +}; + +struct tr_ctor +{ + tr_handle * handle; + + unsigned int isSet_metadata : 1; + benc_val_t metadata; + + struct optional_args optionalArgs[2]; +}; + +tr_ctor* +tr_ctorNew( tr_handle * handle ) +{ + tr_ctor * ctor = tr_new0( struct tr_ctor, 1 ); + ctor->handle = handle; + tr_ctorSetMaxConnectedPeers( ctor, TR_FALLBACK, 50 ); + tr_ctorSetMaxUnchokedPeers( ctor, TR_FALLBACK, 16 ); + tr_ctorSetPaused( ctor, TR_FALLBACK, FALSE ); + return ctor; +} + +void +tr_ctorFree( tr_ctor * ctor ) +{ + tr_free( ctor ); +} + +static void +clearMetadata( tr_ctor * ctor ) +{ + if( ctor->isSet_metadata ) { + ctor->isSet_metadata = 0; + tr_bencFree( &ctor->metadata ); + } +} + +int +tr_ctorSetMetadata( tr_ctor * ctor, + const uint8_t * metadata, + size_t len ) +{ + int err; + clearMetadata( ctor ); + err = tr_bencLoad( metadata, len, &ctor->metadata, NULL ); + ctor->isSet_metadata = !err; + return err; +} + +int +tr_ctorSetMetadataFromFile( tr_ctor * ctor, + const char * filename ) +{ + uint8_t * metadata; + size_t len; + int err; + + metadata = tr_loadFile( filename, &len ); + if( metadata && len ) + err = tr_ctorSetMetadata( ctor, metadata, len ); + else { + clearMetadata( ctor ); + err = 1; + } + + tr_free( metadata ); + return err; +} + +int +tr_ctorSetMetadataFromHash( tr_ctor * ctor, + const char * hashString ) +{ + int err = -1; + char basename[2048]; + char filename[MAX_PATH_LENGTH]; + + if( err && ( ctor->handle->tag != NULL ) ) { + snprintf( basename, sizeof(basename), "%s-%s", hashString, ctor->handle->tag ); + tr_buildPath( filename, sizeof(filename), tr_getTorrentsDirectory(), basename ); + err = tr_ctorSetMetadataFromFile( ctor, filename ); + } + + if( err ) { + tr_buildPath( filename, sizeof(filename), tr_getTorrentsDirectory(), hashString ); + err = tr_ctorSetMetadataFromFile( ctor, filename ); + } + + return err; +} + +/*** +**** +***/ + +void +tr_ctorSetPaused( tr_ctor * ctor, + tr_ctorMode mode, + int isPaused ) +{ + struct optional_args * args = &ctor->optionalArgs[mode]; + args->isSet_paused = 1; + args->isPaused = isPaused; +} + +void +tr_ctorSetMaxUnchokedPeers( tr_ctor * ctor, + tr_ctorMode mode, + uint8_t maxUnchokedPeers) +{ + struct optional_args * args = &ctor->optionalArgs[mode]; + args->isSet_unchoked = 1; + args->maxUnchokedPeers = maxUnchokedPeers; +} + +void +tr_ctorSetMaxConnectedPeers( tr_ctor * ctor, + tr_ctorMode mode, + uint16_t maxConnectedPeers ) +{ + struct optional_args * args = &ctor->optionalArgs[mode]; + args->isSet_connected = 1; + args->maxConnectedPeers = maxConnectedPeers; +} + +void +tr_ctorSetDestination( tr_ctor * ctor, + tr_ctorMode mode, + const char * directory ) +{ + struct optional_args * args = &ctor->optionalArgs[mode]; + args->isSet_destination = 1; + strlcpy( args->destination, directory, sizeof( args->destination ) ); +} + +int +tr_ctorGetMaxConnectedPeers( const tr_ctor * ctor, + tr_ctorMode mode, + uint16_t * setmeCount ) +{ + const struct optional_args * args = &ctor->optionalArgs[mode]; + const int isSet = args->isSet_connected; + if( isSet ) + *setmeCount = args->maxConnectedPeers; + return isSet; +} + +int +tr_ctorGetMaxUnchokedPeers( const tr_ctor * ctor, + tr_ctorMode mode, + uint8_t * setmeCount ) +{ + const struct optional_args * args = &ctor->optionalArgs[mode]; + const int isSet = args->isSet_unchoked; + if( isSet ) + *setmeCount = args->maxUnchokedPeers; + return isSet; +} + +int +tr_ctorGetIsPaused( const tr_ctor * ctor, + tr_ctorMode mode, + int * setmeIsPaused ) +{ + const struct optional_args * args = &ctor->optionalArgs[mode]; + const int isSet = args->isSet_paused; + if( isSet ) + *setmeIsPaused = args->isPaused; + return isSet; +} + +int +tr_ctorGetDestination( const tr_ctor * ctor, + tr_ctorMode mode, + const char ** setmeDestination ) +{ + const struct optional_args * args = &ctor->optionalArgs[mode]; + const int isSet = args->isSet_destination; + if( isSet ) + *setmeDestination = args->destination; + return isSet; +} + +int +tr_ctorGetMetadata( const tr_ctor * ctor, + const struct benc_val_s ** setme ) +{ + const int isSet = ctor->isSet_metadata; + if( isSet ) + *setme = &ctor->metadata; + return isSet; +} diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index fdab3434d..6b2872630 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -352,6 +352,124 @@ tr_torrent ** tr_loadTorrents ( tr_handle * h, int * setmeCount ); +/** + * Torrent Instantiation + * + * Creating torrents has gotten more complicated as we've added options, + * and there are now a lot of functions for creating torrents, all slightly + * different. To remedy this, a Torrent Constructor (struct tr_ctor) has + * been introduced. You can fill in the settings you want, and leave the + * rest to the system defaults. It also gives us a backwards-compatable + * way of adding features in the future -- we can add new tr_ctor() functions + * and leave tr_torrentInit()'s signature alone. + * + * You _must_ call one of the SetMetadata() functions before creating + * a torrent with a tr_ctor. The other functions are optional. + * + * You can reuse a tr_ctor when creating a batch of torrents. + * Just call one of the SetMetadata() functions between each + * tr_torrentInit() call. + * + * The tr_ctorGet*() functions will return nonzero if that field + * has been set via one of the tr_ctorSet*() functions. + * + * Every call to tr_ctorSetMetadata*() will free the previous metadata. + * The tr_ctorSetMetadata*() functions return an error number, or zero + * if no error occurred. + */ + +typedef enum +{ + TR_FALLBACK, /* indicates the ctor value should be used only + in case of missing fastresume settings */ + + TR_FORCE, /* manditory use -- overrides the fastresume settings */ +} +tr_ctorMode; + +typedef struct tr_ctor tr_ctor; +struct benc_val_s; + +tr_ctor* tr_ctorNew ( tr_handle * handle); + +void tr_ctorFree ( tr_ctor * ctor ); + +int tr_ctorSetMetadata ( tr_ctor * ctor, + const uint8_t * metadata, + size_t len ); + +int tr_ctorSetMetadataFromFile ( tr_ctor * ctor, + const char * filename ); + +int tr_ctorSetMetadataFromHash ( tr_ctor * ctor, + const char * hashString ); + +void tr_ctorSetMaxConnectedPeers ( tr_ctor * ctor, + tr_ctorMode mode, + uint16_t maxConnectedPeers ); + +void tr_ctorSetMaxUnchokedPeers ( tr_ctor * ctor, + tr_ctorMode mode, + uint8_t maxUnchokedPeers); + +void tr_ctorSetDestination ( tr_ctor * ctor, + tr_ctorMode mode, + const char * directory ); + +void tr_ctorSetPaused ( tr_ctor * ctor, + tr_ctorMode mode, + int isPaused ); + +int tr_ctorGetMaxConnectedPeers ( const tr_ctor * ctor, + tr_ctorMode mode, + uint16_t * setmeCount ); + +int tr_ctorGetMaxUnchokedPeers ( const tr_ctor * ctor, + tr_ctorMode mode, + uint8_t * setmeCount ); + +int tr_ctorGetIsPaused ( const tr_ctor * ctor, + tr_ctorMode mode, + int * setmeIsPaused ); + +int tr_ctorGetDestination ( const tr_ctor * ctor, + tr_ctorMode mode, + const char ** setmeDestination ); + +int tr_ctorGetMetadata ( const tr_ctor * ctor, + const struct benc_val_s ** setme ); + +/** + * Parses the specified metainfo. + * Returns TR_OK if it parsed and can be added to Transmission. + * Returns TR_INVALID if it couldn't be parsed. + * Returns TR_EDUPLICATE if it parsed but can't be added. + * "destination" must be set to test for TR_EDUPLICATE. + * + * "setme_info" can be NULL if you don't need the information. + * If the metainfo can be parsed and setme_info is non-NULL, + * it will be filled with the metadata's info. You'll need to + * call tr_metainfoFree( setme_info ) when done with it. + */ +int tr_torrentParseFromCtor( tr_handle * handle, + const tr_ctor * ctor ); + +/** + * Instantiate the torrent from the given tr_ctor. + */ +#define TR_EINVALID 1 +#define TR_EUNSUPPORTED 2 +#define TR_EDUPLICATE 3 +#define TR_EOTHER 666 +tr_torrent * tr_torrentNew( tr_handle * handle, + const tr_ctor * ctor, + int * setmeError ); + + +/** +*** +**/ + /*********************************************************************** * tr_torrentInit *********************************************************************** @@ -362,10 +480,6 @@ tr_torrent ** tr_loadTorrents ( tr_handle * h, * then it's 20-byte hash will be copied in. If the TR_FLAG_SAVE flag * is passed then a copy of the torrent file will be saved. **********************************************************************/ -#define TR_EINVALID 1 -#define TR_EUNSUPPORTED 2 -#define TR_EDUPLICATE 3 -#define TR_EOTHER 666 tr_torrent * tr_torrentInit( tr_handle * handle, const char * metainfo_filename, const char * destination,