1/* 2 * This file Copyright (C) Mnemosyne LLC 3 * 4 * This file is licensed by the GPL version 2. Works owned by the 5 * Transmission project are granted a special exemption to clause 2(b) 6 * so that the bulk of its code can remain under the MIT license. 7 * This exemption does not extend to derived works not owned by 8 * the Transmission project. 9 * 10 * $Id: torrent-ctor.c 12234 2011-03-25 17:42:47Z jordan $ 11 */ 12 13#include <errno.h> /* EINVAL */ 14#include "transmission.h" 15#include "bencode.h" 16#include "magnet.h" 17#include "session.h" /* tr_sessionFindTorrentFile() */ 18#include "torrent.h" /* tr_ctorGetSave() */ 19#include "utils.h" /* tr_new0 */ 20 21struct optional_args 22{ 23 bool isSet_paused; 24 bool isSet_connected; 25 bool isSet_downloadDir; 26 27 bool isPaused; 28 uint16_t peerLimit; 29 char * downloadDir; 30}; 31 32/** Opaque class used when instantiating torrents. 33 * @ingroup tr_ctor */ 34struct tr_ctor 35{ 36 const tr_session * session; 37 bool saveInOurTorrentsDir; 38 bool doDelete; 39 40 tr_priority_t bandwidthPriority; 41 bool isSet_metainfo; 42 bool isSet_delete; 43 tr_benc metainfo; 44 char * sourceFile; 45 46 struct optional_args optionalArgs[2]; 47 48 char * cookies; 49 char * incompleteDir; 50 51 tr_file_index_t * want; 52 tr_file_index_t wantSize; 53 tr_file_index_t * notWant; 54 tr_file_index_t notWantSize; 55 tr_file_index_t * low; 56 tr_file_index_t lowSize; 57 tr_file_index_t * normal; 58 tr_file_index_t normalSize; 59 tr_file_index_t * high; 60 tr_file_index_t highSize; 61}; 62 63/*** 64**** 65***/ 66 67static void 68setSourceFile( tr_ctor * ctor, 69 const char * sourceFile ) 70{ 71 tr_free( ctor->sourceFile ); 72 ctor->sourceFile = tr_strdup( sourceFile ); 73} 74 75static void 76clearMetainfo( tr_ctor * ctor ) 77{ 78 if( ctor->isSet_metainfo ) 79 { 80 ctor->isSet_metainfo = 0; 81 tr_bencFree( &ctor->metainfo ); 82 } 83 84 setSourceFile( ctor, NULL ); 85} 86 87int 88tr_ctorSetMetainfo( tr_ctor * ctor, 89 const uint8_t * metainfo, 90 size_t len ) 91{ 92 int err; 93 94 clearMetainfo( ctor ); 95 err = tr_bencLoad( metainfo, len, &ctor->metainfo, NULL ); 96 ctor->isSet_metainfo = !err; 97 return err; 98} 99 100const char* 101tr_ctorGetSourceFile( const tr_ctor * ctor ) 102{ 103 return ctor->sourceFile; 104} 105 106int 107tr_ctorSetMetainfoFromMagnetLink( tr_ctor * ctor, const char * magnet_link ) 108{ 109 int err; 110 tr_magnet_info * magnet_info = tr_magnetParse( magnet_link ); 111 112 if( magnet_info == NULL ) 113 err = -1; 114 else { 115 int len; 116 tr_benc tmp; 117 char * str; 118 119 tr_magnetCreateMetainfo( magnet_info, &tmp ); 120 str = tr_bencToStr( &tmp, TR_FMT_BENC, &len ); 121 err = tr_ctorSetMetainfo( ctor, (const uint8_t*)str, len ); 122 123 tr_free( str ); 124 tr_bencFree( &tmp ); 125 tr_magnetFree( magnet_info ); 126 } 127 128 return err; 129} 130 131int 132tr_ctorSetMetainfoFromFile( tr_ctor * ctor, 133 const char * filename ) 134{ 135 uint8_t * metainfo; 136 size_t len; 137 int err; 138 139 metainfo = tr_loadFile( filename, &len ); 140 if( metainfo && len ) 141 err = tr_ctorSetMetainfo( ctor, metainfo, len ); 142 else 143 { 144 clearMetainfo( ctor ); 145 err = 1; 146 } 147 148 setSourceFile( ctor, filename ); 149 150 /* if no `name' field was set, then set it from the filename */ 151 if( ctor->isSet_metainfo ) 152 { 153 tr_benc * info; 154 if( tr_bencDictFindDict( &ctor->metainfo, "info", &info ) ) 155 { 156 const char * name; 157 if( !tr_bencDictFindStr( info, "name.utf-8", &name ) ) 158 if( !tr_bencDictFindStr( info, "name", &name ) ) 159 name = NULL; 160 if( !name || !*name ) 161 { 162 char * base = tr_basename( filename ); 163 tr_bencDictAddStr( info, "name", base ); 164 tr_free( base ); 165 } 166 } 167 } 168 169 tr_free( metainfo ); 170 return err; 171} 172 173int 174tr_ctorSetMetainfoFromHash( tr_ctor * ctor, 175 const char * hashString ) 176{ 177 int err; 178 const char * filename; 179 180 filename = tr_sessionFindTorrentFile( ctor->session, hashString ); 181 if( !filename ) 182 err = EINVAL; 183 else 184 err = tr_ctorSetMetainfoFromFile( ctor, filename ); 185 186 return err; 187} 188 189/*** 190**** 191***/ 192 193void 194tr_ctorSetFilePriorities( tr_ctor * ctor, 195 const tr_file_index_t * files, 196 tr_file_index_t fileCount, 197 tr_priority_t priority ) 198{ 199 tr_file_index_t ** myfiles; 200 tr_file_index_t * mycount; 201 202 switch( priority ) { 203 case TR_PRI_LOW: myfiles = &ctor->low; mycount = &ctor->lowSize; break; 204 case TR_PRI_HIGH: myfiles = &ctor->high; mycount = &ctor->highSize; break; 205 default /*TR_PRI_NORMAL*/: myfiles = &ctor->normal; mycount = &ctor->normalSize; break; 206 } 207 208 tr_free( *myfiles ); 209 *myfiles = tr_memdup( files, sizeof(tr_file_index_t)*fileCount ); 210 *mycount = fileCount; 211} 212 213void 214tr_ctorInitTorrentPriorities( const tr_ctor * ctor, tr_torrent * tor ) 215{ 216 tr_file_index_t i; 217 218 for( i=0; i<ctor->lowSize; ++i ) 219 tr_torrentInitFilePriority( tor, ctor->low[i], TR_PRI_LOW ); 220 for( i=0; i<ctor->normalSize; ++i ) 221 tr_torrentInitFilePriority( tor, ctor->normal[i], TR_PRI_NORMAL ); 222 for( i=0; i<ctor->highSize; ++i ) 223 tr_torrentInitFilePriority( tor, ctor->high[i], TR_PRI_HIGH ); 224} 225 226void 227tr_ctorSetFilesWanted( tr_ctor * ctor, 228 const tr_file_index_t * files, 229 tr_file_index_t fileCount, 230 bool wanted ) 231{ 232 tr_file_index_t ** myfiles = wanted ? &ctor->want : &ctor->notWant; 233 tr_file_index_t * mycount = wanted ? &ctor->wantSize : &ctor->notWantSize; 234 235 tr_free( *myfiles ); 236 *myfiles = tr_memdup( files, sizeof(tr_file_index_t)*fileCount ); 237 *mycount = fileCount; 238} 239 240void 241tr_ctorInitTorrentWanted( const tr_ctor * ctor, tr_torrent * tor ) 242{ 243 if( ctor->notWantSize ) 244 tr_torrentInitFileDLs( tor, ctor->notWant, ctor->notWantSize, false ); 245 if( ctor->wantSize ) 246 tr_torrentInitFileDLs( tor, ctor->want, ctor->wantSize, true ); 247} 248 249/*** 250**** 251***/ 252 253void 254tr_ctorSetDeleteSource( tr_ctor * ctor, bool deleteSource ) 255{ 256 ctor->doDelete = deleteSource != 0; 257 ctor->isSet_delete = 1; 258} 259 260int 261tr_ctorGetDeleteSource( const tr_ctor * ctor, bool * setme ) 262{ 263 int err = 0; 264 265 if( !ctor->isSet_delete ) 266 err = 1; 267 else if( setme ) 268 *setme = ctor->doDelete ? 1 : 0; 269 270 return err; 271} 272 273/*** 274**** 275***/ 276 277void 278tr_ctorSetSave( tr_ctor * ctor, bool saveInOurTorrentsDir ) 279{ 280 ctor->saveInOurTorrentsDir = saveInOurTorrentsDir != 0; 281} 282 283int 284tr_ctorGetSave( const tr_ctor * ctor ) 285{ 286 return ctor && ctor->saveInOurTorrentsDir; 287} 288 289void 290tr_ctorSetPaused( tr_ctor * ctor, 291 tr_ctorMode mode, 292 bool isPaused ) 293{ 294 struct optional_args * args = &ctor->optionalArgs[mode]; 295 296 args->isSet_paused = 1; 297 args->isPaused = isPaused ? 1 : 0; 298} 299 300void 301tr_ctorSetPeerLimit( tr_ctor * ctor, 302 tr_ctorMode mode, 303 uint16_t peerLimit ) 304{ 305 struct optional_args * args = &ctor->optionalArgs[mode]; 306 307 args->isSet_connected = 1; 308 args->peerLimit = peerLimit; 309} 310 311void 312tr_ctorSetDownloadDir( tr_ctor * ctor, 313 tr_ctorMode mode, 314 const char * directory ) 315{ 316 struct optional_args * args = &ctor->optionalArgs[mode]; 317 318 tr_free( args->downloadDir ); 319 args->downloadDir = NULL; 320 args->isSet_downloadDir = 0; 321 322 if( directory && *directory ) 323 { 324 args->isSet_downloadDir = 1; 325 args->downloadDir = tr_strdup( directory ); 326 } 327} 328 329void 330tr_ctorSetIncompleteDir( tr_ctor * ctor, const char * directory ) 331{ 332 tr_free( ctor->incompleteDir ); 333 ctor->incompleteDir = tr_strdup( directory ); 334} 335 336int 337tr_ctorGetPeerLimit( const tr_ctor * ctor, 338 tr_ctorMode mode, 339 uint16_t * setmeCount ) 340{ 341 int err = 0; 342 const struct optional_args * args = &ctor->optionalArgs[mode]; 343 344 if( !args->isSet_connected ) 345 err = 1; 346 else if( setmeCount ) 347 *setmeCount = args->peerLimit; 348 349 return err; 350} 351 352int 353tr_ctorGetPaused( const tr_ctor * ctor, tr_ctorMode mode, bool * setmeIsPaused ) 354{ 355 int err = 0; 356 const struct optional_args * args = &ctor->optionalArgs[mode]; 357 358 if( !args->isSet_paused ) 359 err = 1; 360 else if( setmeIsPaused ) 361 *setmeIsPaused = args->isPaused ? 1 : 0; 362 363 return err; 364} 365 366int 367tr_ctorGetDownloadDir( const tr_ctor * ctor, 368 tr_ctorMode mode, 369 const char ** setmeDownloadDir ) 370{ 371 int err = 0; 372 const struct optional_args * args = &ctor->optionalArgs[mode]; 373 374 if( !args->isSet_downloadDir ) 375 err = 1; 376 else if( setmeDownloadDir ) 377 *setmeDownloadDir = args->downloadDir; 378 379 return err; 380} 381 382int 383tr_ctorGetIncompleteDir( const tr_ctor * ctor, 384 const char ** setmeIncompleteDir ) 385{ 386 int err = 0; 387 388 if( ctor->incompleteDir == NULL ) 389 err = 1; 390 else 391 *setmeIncompleteDir = ctor->incompleteDir; 392 393 return err; 394} 395 396int 397tr_ctorGetMetainfo( const tr_ctor * ctor, 398 const tr_benc ** setme ) 399{ 400 int err = 0; 401 402 if( !ctor->isSet_metainfo ) 403 err = 1; 404 else if( setme ) 405 *setme = &ctor->metainfo; 406 407 return err; 408} 409 410tr_session* 411tr_ctorGetSession( const tr_ctor * ctor ) 412{ 413 return (tr_session*) ctor->session; 414} 415 416/*** 417**** 418***/ 419 420static bool 421isPriority( int i ) 422{ 423 return (i==TR_PRI_LOW) || (i==TR_PRI_NORMAL) || (i==TR_PRI_HIGH); 424} 425 426void 427tr_ctorSetBandwidthPriority( tr_ctor * ctor, tr_priority_t priority ) 428{ 429 if( isPriority( priority ) ) 430 ctor->bandwidthPriority = priority; 431} 432 433tr_priority_t 434tr_ctorGetBandwidthPriority( const tr_ctor * ctor ) 435{ 436 return ctor->bandwidthPriority; 437} 438 439/*** 440**** 441***/ 442 443tr_ctor* 444tr_ctorNew( const tr_session * session ) 445{ 446 tr_ctor * ctor = tr_new0( struct tr_ctor, 1 ); 447 448 ctor->session = session; 449 ctor->bandwidthPriority = TR_PRI_NORMAL; 450 if( session != NULL ) 451 { 452 tr_ctorSetDeleteSource( ctor, tr_sessionGetDeleteSource( session ) ); 453 tr_ctorSetPaused( ctor, TR_FALLBACK, tr_sessionGetPaused( session ) ); 454 tr_ctorSetPeerLimit( ctor, TR_FALLBACK, session->peerLimitPerTorrent ); 455 tr_ctorSetDownloadDir( ctor, TR_FALLBACK, session->downloadDir ); 456 } 457 tr_ctorSetSave( ctor, true ); 458 return ctor; 459} 460 461void 462tr_ctorFree( tr_ctor * ctor ) 463{ 464 clearMetainfo( ctor ); 465 tr_free( ctor->optionalArgs[1].downloadDir ); 466 tr_free( ctor->optionalArgs[0].downloadDir ); 467 tr_free( ctor->incompleteDir ); 468 tr_free( ctor->want ); 469 tr_free( ctor->notWant ); 470 tr_free( ctor->low ); 471 tr_free( ctor->high ); 472 tr_free( ctor->normal ); 473 tr_free( ctor ); 474} 475