Changeset 14079
- Timestamp:
- May 23, 2013, 12:11:09 AM (10 years ago)
- Location:
- trunk/libtransmission
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/rpcimpl.c
r14077 r14079 87 87 struct tr_rpc_idle_data 88 88 { 89 90 91 92 93 89 tr_session * session; 90 tr_variant * response; 91 tr_variant * args_out; 92 tr_rpc_response_func callback; 93 void * callback_user_data; 94 94 }; 95 95 … … 97 97 tr_idle_function_done (struct tr_rpc_idle_data * data, const char * result) 98 98 { 99 100 101 102 103 104 105 106 107 108 109 110 111 99 struct evbuffer * buf; 100 101 if (result == NULL) 102 result = "success"; 103 tr_variantDictAddStr (data->response, TR_KEY_result, result); 104 105 buf = tr_variantToBuf (data->response, TR_VARIANT_FMT_JSON_LEAN); 106 (*data->callback)(data->session, buf, data->callback_user_data); 107 evbuffer_free (buf); 108 109 tr_variantFree (data->response); 110 tr_free (data->response); 111 tr_free (data); 112 112 } 113 113 … … 121 121 int * setmeCount) 122 122 { 123 int torrentCount = 0; 124 int64_t id; 125 tr_torrent ** torrents = NULL; 126 tr_variant * ids; 127 const char * str; 128 129 if (tr_variantDictFindList (args, TR_KEY_ids, &ids)) 130 { 131 int i; 132 const int n = tr_variantListSize (ids); 133 134 torrents = tr_new0 (tr_torrent *, n); 135 136 for (i = 0; i < n; ++i) 137 { 138 tr_torrent * tor = NULL; 139 tr_variant * node = tr_variantListChild (ids, i); 140 const char * str; 141 if (tr_variantGetInt (node, &id)) 142 tor = tr_torrentFindFromId (session, id); 143 else if (tr_variantGetStr (node, &str, NULL)) 144 tor = tr_torrentFindFromHashString (session, str); 145 if (tor) 146 torrents[torrentCount++] = tor; 147 } 148 } 149 else if (tr_variantDictFindInt (args, TR_KEY_ids, &id) 150 || tr_variantDictFindInt (args, TR_KEY_id, &id)) 151 { 152 tr_torrent * tor; 153 torrents = tr_new0 (tr_torrent *, 1); 154 if ((tor = tr_torrentFindFromId (session, id))) 123 int torrentCount = 0; 124 int64_t id; 125 tr_torrent ** torrents = NULL; 126 tr_variant * ids; 127 const char * str; 128 129 if (tr_variantDictFindList (args, TR_KEY_ids, &ids)) 130 { 131 int i; 132 const int n = tr_variantListSize (ids); 133 134 torrents = tr_new0 (tr_torrent *, n); 135 136 for (i=0; i<n; ++i) 137 { 138 const char * str; 139 tr_torrent * tor; 140 tr_variant * node = tr_variantListChild (ids, i); 141 142 if (tr_variantGetInt (node, &id)) 143 tor = tr_torrentFindFromId (session, id); 144 else if (tr_variantGetStr (node, &str, NULL)) 145 tor = tr_torrentFindFromHashString (session, str); 146 else 147 tor = NULL; 148 149 if (tor != NULL) 155 150 torrents[torrentCount++] = tor; 156 }157 else if (tr_variantDictFindStr (args, TR_KEY_ids, &str, NULL))158 {159 if (!strcmp (str, "recently-active"))160 161 tr_torrent * tor = NULL;162 const time_t now = tr_time ();163 const time_t window = RECENTLY_ACTIVE_SECONDS;164 const int n = tr_sessionCountTorrents (session);165 torrents = tr_new0 (tr_torrent *, n);166 while ((tor = tr_torrentNext (session, tor)))167 if (tor->anyDate >= now - window)168 torrents[torrentCount++] = tor;169 }170 else171 {172 tr_torrent * tor;173 torrents = tr_new0 (tr_torrent *, 1);174 if ((tor = tr_torrentFindFromHashString (session, str)))175 torrents[torrentCount++] = tor;176 }177 }178 else /* all of them */179 {180 tr_torrent * tor = NULL;181 const int n = tr_sessionCountTorrents (session);182 torrents = tr_new0 (tr_torrent *, n);183 while ((tor = tr_torrentNext (session, tor)))151 } 152 } 153 else if (tr_variantDictFindInt (args, TR_KEY_ids, &id) 154 || tr_variantDictFindInt (args, TR_KEY_id, &id)) 155 { 156 tr_torrent * tor; 157 torrents = tr_new0 (tr_torrent *, 1); 158 if ((tor = tr_torrentFindFromId (session, id))) 159 torrents[torrentCount++] = tor; 160 } 161 else if (tr_variantDictFindStr (args, TR_KEY_ids, &str, NULL)) 162 { 163 if (!strcmp (str, "recently-active")) 164 { 165 tr_torrent * tor = NULL; 166 const time_t now = tr_time (); 167 const time_t window = RECENTLY_ACTIVE_SECONDS; 168 const int n = tr_sessionCountTorrents (session); 169 torrents = tr_new0 (tr_torrent *, n); 170 while ((tor = tr_torrentNext (session, tor))) 171 if (tor->anyDate >= now - window) 172 torrents[torrentCount++] = tor; 173 } 174 else 175 { 176 tr_torrent * tor; 177 torrents = tr_new0 (tr_torrent *, 1); 178 if ((tor = tr_torrentFindFromHashString (session, str))) 184 179 torrents[torrentCount++] = tor; 185 } 186 187 *setmeCount = torrentCount; 188 return torrents; 180 } 181 } 182 else /* all of them */ 183 { 184 tr_torrent * tor = NULL; 185 const int n = tr_sessionCountTorrents (session); 186 torrents = tr_new0 (tr_torrent *, n); 187 while ((tor = tr_torrentNext (session, tor))) 188 torrents[torrentCount++] = tor; 189 } 190 191 *setmeCount = torrentCount; 192 return torrents; 189 193 } 190 194 … … 192 196 notifyBatchQueueChange (tr_session * session, tr_torrent ** torrents, int n) 193 197 { 194 195 196 197 198 int i; 199 for (i=0; i<n; ++i) 200 notify (session, TR_RPC_TORRENT_CHANGED, torrents[i]); 201 notify (session, TR_RPC_SESSION_QUEUE_POSITIONS_CHANGED, NULL); 198 202 } 199 203 … … 204 208 struct tr_rpc_idle_data * idle_data UNUSED) 205 209 { 206 207 208 209 210 211 210 int n; 211 tr_torrent ** torrents = getTorrents (session, args_in, &n); 212 tr_torrentsQueueMoveTop (torrents, n); 213 notifyBatchQueueChange (session, torrents, n); 214 tr_free (torrents); 215 return NULL; 212 216 } 213 217 … … 218 222 struct tr_rpc_idle_data * idle_data UNUSED) 219 223 { 220 221 222 223 224 225 224 int n; 225 tr_torrent ** torrents = getTorrents (session, args_in, &n); 226 tr_torrentsQueueMoveUp (torrents, n); 227 notifyBatchQueueChange (session, torrents, n); 228 tr_free (torrents); 229 return NULL; 226 230 } 227 231 … … 232 236 struct tr_rpc_idle_data * idle_data UNUSED) 233 237 { 234 235 236 237 238 239 238 int n; 239 tr_torrent ** torrents = getTorrents (session, args_in, &n); 240 tr_torrentsQueueMoveDown (torrents, n); 241 notifyBatchQueueChange (session, torrents, n); 242 tr_free (torrents); 243 return NULL; 240 244 } 241 245 … … 246 250 struct tr_rpc_idle_data * idle_data UNUSED) 247 251 { 248 249 250 251 252 253 252 int n; 253 tr_torrent ** torrents = getTorrents (session, args_in, &n); 254 tr_torrentsQueueMoveBottom (torrents, n); 255 notifyBatchQueueChange (session, torrents, n); 256 tr_free (torrents); 257 return NULL; 254 258 } 255 259 … … 260 264 struct tr_rpc_idle_data * idle_data UNUSED) 261 265 { 262 int i, torrentCount; 263 tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount); 264 265 assert (idle_data == NULL); 266 267 for (i = 0; i < torrentCount; ++i) 268 { 269 tr_torrent * tor = torrents[i]; 270 if (!tor->isRunning) 271 { 272 tr_torrentStart (tor); 273 notify (session, TR_RPC_TORRENT_STARTED, tor); 274 } 275 } 276 tr_free (torrents); 277 return NULL; 266 int i; 267 int torrentCount; 268 tr_torrent ** torrents; 269 270 assert (idle_data == NULL); 271 272 torrents = getTorrents (session, args_in, &torrentCount); 273 for (i=0; i<torrentCount; ++i) 274 { 275 tr_torrent * tor = torrents[i]; 276 if (!tor->isRunning) 277 { 278 tr_torrentStart (tor); 279 notify (session, TR_RPC_TORRENT_STARTED, tor); 280 } 281 } 282 283 tr_free (torrents); 284 return NULL; 278 285 } 279 286 … … 284 291 struct tr_rpc_idle_data * idle_data UNUSED) 285 292 { 286 int i, torrentCount; 287 tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount); 288 289 assert (idle_data == NULL); 290 291 for (i = 0; i < torrentCount; ++i) 292 { 293 tr_torrent * tor = torrents[i]; 294 if (!tor->isRunning) 295 { 296 tr_torrentStartNow (tor); 297 notify (session, TR_RPC_TORRENT_STARTED, tor); 298 } 299 } 300 tr_free (torrents); 301 return NULL; 293 int i; 294 int torrentCount; 295 tr_torrent ** torrents; 296 297 assert (idle_data == NULL); 298 299 torrents = getTorrents (session, args_in, &torrentCount); 300 for (i=0; i<torrentCount; ++i) 301 { 302 tr_torrent * tor = torrents[i]; 303 304 if (!tor->isRunning) 305 { 306 tr_torrentStartNow (tor); 307 notify (session, TR_RPC_TORRENT_STARTED, tor); 308 } 309 } 310 311 tr_free (torrents); 312 return NULL; 302 313 } 303 314 … … 308 319 struct tr_rpc_idle_data * idle_data UNUSED) 309 320 { 310 int i, torrentCount; 311 tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount); 312 313 assert (idle_data == NULL); 314 315 for (i = 0; i < torrentCount; ++i) 316 { 317 tr_torrent * tor = torrents[i]; 318 319 if (tor->isRunning || tr_torrentIsQueued (tor)) 320 { 321 tor->isStopping = true; 322 notify (session, TR_RPC_TORRENT_STOPPED, tor); 323 } 324 } 325 tr_free (torrents); 326 return NULL; 321 int i; 322 int torrentCount; 323 tr_torrent ** torrents; 324 325 assert (idle_data == NULL); 326 327 torrents = getTorrents (session, args_in, &torrentCount); 328 for (i=0; i<torrentCount; ++i) 329 { 330 tr_torrent * tor = torrents[i]; 331 332 if (tor->isRunning || tr_torrentIsQueued (tor)) 333 { 334 tor->isStopping = true; 335 notify (session, TR_RPC_TORRENT_STOPPED, tor); 336 } 337 } 338 339 tr_free (torrents); 340 return NULL; 327 341 } 328 342 … … 333 347 struct tr_rpc_idle_data * idle_data UNUSED) 334 348 { 335 int i; 336 int torrentCount; 337 tr_rpc_callback_type type; 338 bool deleteFlag = false; 339 tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount); 340 341 assert (idle_data == NULL); 342 343 tr_variantDictFindBool (args_in, TR_KEY_delete_local_data, &deleteFlag); 344 type = deleteFlag ? TR_RPC_TORRENT_TRASHING 345 : TR_RPC_TORRENT_REMOVING; 346 347 for (i=0; i<torrentCount; ++i) 348 { 349 tr_torrent * tor = torrents[i]; 350 const tr_rpc_callback_status status = notify (session, type, tor); 351 if (! (status & TR_RPC_NOREMOVE)) 352 tr_torrentRemove (tor, deleteFlag, NULL); 353 } 354 355 tr_free (torrents); 356 return NULL; 349 int i; 350 int torrentCount; 351 tr_rpc_callback_type type; 352 bool deleteFlag = false; 353 tr_torrent ** torrents; 354 355 assert (idle_data == NULL); 356 357 tr_variantDictFindBool (args_in, TR_KEY_delete_local_data, &deleteFlag); 358 type = deleteFlag ? TR_RPC_TORRENT_TRASHING 359 : TR_RPC_TORRENT_REMOVING; 360 361 torrents = getTorrents (session, args_in, &torrentCount); 362 for (i=0; i<torrentCount; ++i) 363 { 364 tr_torrent * tor = torrents[i]; 365 const tr_rpc_callback_status status = notify (session, type, tor); 366 367 if (!(status & TR_RPC_NOREMOVE)) 368 tr_torrentRemove (tor, deleteFlag, NULL); 369 } 370 371 tr_free (torrents); 372 return NULL; 357 373 } 358 374 … … 363 379 struct tr_rpc_idle_data * idle_data UNUSED) 364 380 { 365 int i, torrentCount; 366 tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount); 367 368 assert (idle_data == NULL); 369 370 for (i=0; i<torrentCount; ++i) 371 { 372 tr_torrent * tor = torrents[i]; 373 if (tr_torrentCanManualUpdate (tor)) 374 { 375 tr_torrentManualUpdate (tor); 376 notify (session, TR_RPC_TORRENT_CHANGED, tor); 377 } 378 } 379 380 tr_free (torrents); 381 return NULL; 381 int i; 382 int torrentCount; 383 tr_torrent ** torrents; 384 385 assert (idle_data == NULL); 386 387 torrents = getTorrents (session, args_in, &torrentCount); 388 for (i=0; i<torrentCount; ++i) 389 { 390 tr_torrent * tor = torrents[i]; 391 392 if (tr_torrentCanManualUpdate (tor)) 393 { 394 tr_torrentManualUpdate (tor); 395 notify (session, TR_RPC_TORRENT_CHANGED, tor); 396 } 397 } 398 399 tr_free (torrents); 400 return NULL; 382 401 } 383 402 … … 388 407 struct tr_rpc_idle_data * idle_data UNUSED) 389 408 { 390 int i, torrentCount; 391 tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount); 392 393 assert (idle_data == NULL); 394 395 for (i = 0; i < torrentCount; ++i) 396 { 397 tr_torrent * tor = torrents[i]; 398 tr_torrentVerify (tor, NULL, NULL); 399 notify (session, TR_RPC_TORRENT_CHANGED, tor); 400 } 401 402 tr_free (torrents); 403 return NULL; 409 int i; 410 int torrentCount; 411 tr_torrent ** torrents; 412 413 assert (idle_data == NULL); 414 415 torrents = getTorrents (session, args_in, &torrentCount); 416 for (i=0; i<torrentCount; ++i) 417 { 418 tr_torrent * tor = torrents[i]; 419 tr_torrentVerify (tor, NULL, NULL); 420 notify (session, TR_RPC_TORRENT_CHANGED, tor); 421 } 422 423 tr_free (torrents); 424 return NULL; 404 425 } 405 426 … … 411 432 addFileStats (const tr_torrent * tor, tr_variant * list) 412 433 { 413 414 415 416 417 418 for (i = 0; i <info->fileCount; ++i)419 { 420 421 422 423 424 425 } 426 427 434 tr_file_index_t i; 435 tr_file_index_t n; 436 const tr_info * info = tr_torrentInfo (tor); 437 tr_file_stat * files = tr_torrentFiles (tor, &n); 438 439 for (i=0; i<info->fileCount; ++i) 440 { 441 const tr_file * file = &info->files[i]; 442 tr_variant * d = tr_variantListAddDict (list, 3); 443 tr_variantDictAddInt (d, TR_KEY_bytesCompleted, files[i].bytesCompleted); 444 tr_variantDictAddInt (d, TR_KEY_priority, file->priority); 445 tr_variantDictAddBool (d, TR_KEY_wanted, !file->dnd); 446 } 447 448 tr_torrentFilesFree (files, n); 428 449 } 429 450 … … 431 452 addFiles (const tr_torrent * tor, tr_variant * list) 432 453 { 433 434 435 436 437 438 for (i = 0; i <info->fileCount; ++i)439 { 440 441 tr_variant *d = tr_variantListAddDict (list, 3);442 443 444 445 } 446 447 454 tr_file_index_t i; 455 tr_file_index_t n; 456 const tr_info * info = tr_torrentInfo (tor); 457 tr_file_stat * files = tr_torrentFiles (tor, &n); 458 459 for (i=0; i<info->fileCount; ++i) 460 { 461 const tr_file * file = &info->files[i]; 462 tr_variant * d = tr_variantListAddDict (list, 3); 463 tr_variantDictAddInt (d, TR_KEY_bytesCompleted, files[i].bytesCompleted); 464 tr_variantDictAddInt (d, TR_KEY_length, file->length); 465 tr_variantDictAddStr (d, TR_KEY_name, file->name); 466 } 467 468 tr_torrentFilesFree (files, n); 448 469 } 449 470 … … 478 499 addTrackerStats (const tr_tracker_stat * st, int n, tr_variant * list) 479 500 { 480 481 482 483 { 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 501 int i; 502 503 for (i=0; i<n; ++i) 504 { 505 const tr_tracker_stat * s = &st[i]; 506 tr_variant * d = tr_variantListAddDict (list, 26); 507 tr_variantDictAddStr (d, TR_KEY_announce, s->announce); 508 tr_variantDictAddInt (d, TR_KEY_announceState, s->announceState); 509 tr_variantDictAddInt (d, TR_KEY_downloadCount, s->downloadCount); 510 tr_variantDictAddBool (d, TR_KEY_hasAnnounced, s->hasAnnounced); 511 tr_variantDictAddBool (d, TR_KEY_hasScraped, s->hasScraped); 512 tr_variantDictAddStr (d, TR_KEY_host, s->host); 513 tr_variantDictAddInt (d, TR_KEY_id, s->id); 514 tr_variantDictAddBool (d, TR_KEY_isBackup, s->isBackup); 515 tr_variantDictAddInt (d, TR_KEY_lastAnnouncePeerCount, s->lastAnnouncePeerCount); 516 tr_variantDictAddStr (d, TR_KEY_lastAnnounceResult, s->lastAnnounceResult); 517 tr_variantDictAddInt (d, TR_KEY_lastAnnounceStartTime, s->lastAnnounceStartTime); 518 tr_variantDictAddBool (d, TR_KEY_lastAnnounceSucceeded, s->lastAnnounceSucceeded); 519 tr_variantDictAddInt (d, TR_KEY_lastAnnounceTime, s->lastAnnounceTime); 520 tr_variantDictAddBool (d, TR_KEY_lastAnnounceTimedOut, s->lastAnnounceTimedOut); 521 tr_variantDictAddStr (d, TR_KEY_lastScrapeResult, s->lastScrapeResult); 522 tr_variantDictAddInt (d, TR_KEY_lastScrapeStartTime, s->lastScrapeStartTime); 523 tr_variantDictAddBool (d, TR_KEY_lastScrapeSucceeded, s->lastScrapeSucceeded); 524 tr_variantDictAddInt (d, TR_KEY_lastScrapeTime, s->lastScrapeTime); 525 tr_variantDictAddInt (d, TR_KEY_lastScrapeTimedOut, s->lastScrapeTimedOut); 526 tr_variantDictAddInt (d, TR_KEY_leecherCount, s->leecherCount); 527 tr_variantDictAddInt (d, TR_KEY_nextAnnounceTime, s->nextAnnounceTime); 528 tr_variantDictAddInt (d, TR_KEY_nextScrapeTime, s->nextScrapeTime); 529 tr_variantDictAddStr (d, TR_KEY_scrape, s->scrape); 530 tr_variantDictAddInt (d, TR_KEY_scrapeState, s->scrapeState); 531 tr_variantDictAddInt (d, TR_KEY_seederCount, s->seederCount); 532 tr_variantDictAddInt (d, TR_KEY_tier, s->tier); 512 533 } 513 534 } … … 524 545 for (i=0; i<peerCount; ++i) 525 546 { 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 } 545 546 547 tr_variant * d = tr_variantListAddDict (list, 16); 548 const tr_peer_stat * peer = peers + i; 549 tr_variantDictAddStr (d, TR_KEY_address, peer->addr); 550 tr_variantDictAddStr (d, TR_KEY_clientName, peer->client); 551 tr_variantDictAddBool (d, TR_KEY_clientIsChoked, peer->clientIsChoked); 552 tr_variantDictAddBool (d, TR_KEY_clientIsInterested, peer->clientIsInterested); 553 tr_variantDictAddStr (d, TR_KEY_flagStr, peer->flagStr); 554 tr_variantDictAddBool (d, TR_KEY_isDownloadingFrom, peer->isDownloadingFrom); 555 tr_variantDictAddBool (d, TR_KEY_isEncrypted, peer->isEncrypted); 556 tr_variantDictAddBool (d, TR_KEY_isIncoming, peer->isIncoming); 557 tr_variantDictAddBool (d, TR_KEY_isUploadingTo, peer->isUploadingTo); 558 tr_variantDictAddBool (d, TR_KEY_isUTP, peer->isUTP); 559 tr_variantDictAddBool (d, TR_KEY_peerIsChoked, peer->peerIsChoked); 560 tr_variantDictAddBool (d, TR_KEY_peerIsInterested, peer->peerIsInterested); 561 tr_variantDictAddInt (d, TR_KEY_port, peer->port); 562 tr_variantDictAddReal (d, TR_KEY_progress, peer->progress); 563 tr_variantDictAddInt (d, TR_KEY_rateToClient, toSpeedBytes (peer->rateToClient_KBps)); 564 tr_variantDictAddInt (d, TR_KEY_rateToPeer, toSpeedBytes (peer->rateToPeer_KBps)); 565 } 566 567 tr_torrentPeersFree (peers, peerCount); 547 568 } 548 569 … … 899 920 static const char* 900 921 torrentGet (tr_session * session, 901 tr_variant 902 tr_variant 922 tr_variant * args_in, 923 tr_variant * args_out, 903 924 struct tr_rpc_idle_data * idle_data UNUSED) 904 925 { 905 int i, torrentCount; 906 tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount); 907 tr_variant * list = tr_variantDictAddList (args_out, TR_KEY_torrents, torrentCount); 908 tr_variant * fields; 909 const char * msg = NULL; 910 const char * strVal; 911 912 assert (idle_data == NULL); 913 914 if (tr_variantDictFindStr (args_in, TR_KEY_ids, &strVal, NULL) && !strcmp (strVal, "recently-active")) { 915 int n = 0; 916 tr_variant * d; 917 const time_t now = tr_time (); 918 const int interval = RECENTLY_ACTIVE_SECONDS; 919 tr_variant * removed_out = tr_variantDictAddList (args_out, TR_KEY_removed, 0); 920 while ((d = tr_variantListChild (&session->removedTorrents, n++))) { 921 int64_t intVal; 922 if (tr_variantDictFindInt (d, TR_KEY_date, &intVal) && (intVal >= now - interval)) { 923 tr_variantDictFindInt (d, TR_KEY_id, &intVal); 924 tr_variantListAddInt (removed_out, intVal); 926 int i; 927 int torrentCount; 928 tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount); 929 tr_variant * list = tr_variantDictAddList (args_out, TR_KEY_torrents, torrentCount); 930 tr_variant * fields; 931 const char * strVal; 932 const char * errmsg = NULL; 933 934 assert (idle_data == NULL); 935 936 if (tr_variantDictFindStr (args_in, TR_KEY_ids, &strVal, NULL) && !strcmp (strVal, "recently-active")) 937 { 938 int n = 0; 939 tr_variant * d; 940 const time_t now = tr_time (); 941 const int interval = RECENTLY_ACTIVE_SECONDS; 942 tr_variant * removed_out = tr_variantDictAddList (args_out, TR_KEY_removed, 0); 943 while ((d = tr_variantListChild (&session->removedTorrents, n++))) 944 { 945 int64_t intVal; 946 if (tr_variantDictFindInt (d, TR_KEY_date, &intVal) && (intVal >= now - interval)) 947 { 948 tr_variantDictFindInt (d, TR_KEY_id, &intVal); 949 tr_variantListAddInt (removed_out, intVal); 925 950 } 926 951 } 927 952 } 928 953 929 930 931 else for (i = 0; i <torrentCount; ++i)932 933 934 935 returnmsg;954 if (!tr_variantDictFindList (args_in, TR_KEY_fields, &fields)) 955 errmsg = "no fields specified"; 956 else for (i=0; i<torrentCount; ++i) 957 addInfo (torrents[i], tr_variantListAdd (list), fields); 958 959 tr_free (torrents); 960 return errmsg; 936 961 } 937 962 … … 943 968 setFilePriorities (tr_torrent * tor, 944 969 int priority, 945 tr_variant * list) 946 { 947 int i; 948 int64_t tmp; 949 int fileCount = 0; 950 const int n = tr_variantListSize (list); 951 const char * errmsg = NULL; 952 tr_file_index_t * files = tr_new0 (tr_file_index_t, tor->info.fileCount); 953 954 if (n) 955 { 956 for (i = 0; i < n; ++i) { 957 if (tr_variantGetInt (tr_variantListChild (list, i), &tmp)) { 958 if (0 <= tmp && tmp < tor->info.fileCount) { 959 files[fileCount++] = tmp; 960 } else { 961 errmsg = "file index out of range"; 962 } 970 tr_variant * list) 971 { 972 int i; 973 int64_t tmp; 974 int fileCount = 0; 975 const int n = tr_variantListSize (list); 976 const char * errmsg = NULL; 977 tr_file_index_t * files = tr_new0 (tr_file_index_t, tor->info.fileCount); 978 979 if (n) 980 { 981 for (i=0; i<n; ++i) 982 { 983 if (tr_variantGetInt (tr_variantListChild (list, i), &tmp)) 984 { 985 if (0 <= tmp && tmp < tor->info.fileCount) 986 files[fileCount++] = tmp; 987 else 988 errmsg = "file index out of range"; 963 989 } 964 990 } 965 991 } 966 967 { 968 969 for (t = 0; t <tor->info.fileCount; ++t)970 971 } 972 973 974 975 976 977 992 else /* if empty set, apply to all */ 993 { 994 tr_file_index_t t; 995 for (t=0; t<tor->info.fileCount; ++t) 996 files[fileCount++] = t; 997 } 998 999 if (fileCount) 1000 tr_torrentSetFilePriorities (tor, files, fileCount, priority); 1001 1002 tr_free (files); 1003 return errmsg; 978 1004 } 979 1005 … … 981 1007 setFileDLs (tr_torrent * tor, 982 1008 int do_download, 983 tr_variant * list) 984 { 985 int i; 986 int64_t tmp; 987 int fileCount = 0; 988 const int n = tr_variantListSize (list); 989 const char * errmsg = NULL; 990 tr_file_index_t * files = tr_new0 (tr_file_index_t, tor->info.fileCount); 991 992 if (n) /* if argument list, process them */ 993 { 994 for (i = 0; i < n; ++i) { 995 if (tr_variantGetInt (tr_variantListChild (list, i), &tmp)) { 996 if (0 <= tmp && tmp < tor->info.fileCount) { 997 files[fileCount++] = tmp; 998 } else { 999 errmsg = "file index out of range"; 1000 } 1009 tr_variant * list) 1010 { 1011 int i; 1012 int64_t tmp; 1013 int fileCount = 0; 1014 const int n = tr_variantListSize (list); 1015 const char * errmsg = NULL; 1016 tr_file_index_t * files = tr_new0 (tr_file_index_t, tor->info.fileCount); 1017 1018 if (n) /* if argument list, process them */ 1019 { 1020 for (i=0; i<n; ++i) 1021 { 1022 if (tr_variantGetInt (tr_variantListChild (list, i), &tmp)) 1023 { 1024 if (0 <= tmp && tmp < tor->info.fileCount) 1025 files[fileCount++] = tmp; 1026 else 1027 errmsg = "file index out of range"; 1001 1028 } 1002 1029 } 1003 1030 } 1004 else /* if empty set, apply to all */ 1005 { 1006 tr_file_index_t t; 1007 for (t = 0; t < tor->info.fileCount; ++t) 1008 files[fileCount++] = t; 1009 } 1010 1011 if (fileCount) 1012 tr_torrentSetFileDLs (tor, files, fileCount, do_download); 1013 1014 tr_free (files); 1015 return errmsg; 1031 else /* if empty set, apply to all */ 1032 { 1033 tr_file_index_t t; 1034 1035 for (t=0; t<tor->info.fileCount; ++t) 1036 files[fileCount++] = t; 1037 } 1038 1039 if (fileCount) 1040 tr_torrentSetFileDLs (tor, files, fileCount, do_download); 1041 1042 tr_free (files); 1043 return errmsg; 1016 1044 } 1017 1045 … … 1019 1047 findAnnounceUrl (const tr_tracker_info * t, int n, const char * url, int * pos) 1020 1048 { 1021 int i; 1022 bool found = false; 1023 1024 for (i=0; i<n; ++i) 1025 { 1026 if (!strcmp (t[i].announce, url)) 1027 { 1028 found = true; 1029 if (pos) *pos = i; 1030 break; 1031 } 1032 } 1033 1034 return found; 1049 int i; 1050 bool found = false; 1051 1052 for (i=0; i<n; ++i) 1053 { 1054 if (!strcmp (t[i].announce, url)) 1055 { 1056 found = true; 1057 1058 if (pos != NULL) 1059 *pos = i; 1060 1061 break; 1062 } 1063 } 1064 1065 return found; 1035 1066 } 1036 1067 … … 1038 1069 copyTrackers (tr_tracker_info * tgt, const tr_tracker_info * src, int n) 1039 1070 { 1040 1041 1042 1043 1044 { 1045 1046 1047 1048 } 1049 1050 1071 int i; 1072 int maxTier = -1; 1073 1074 for (i=0; i<n; ++i) 1075 { 1076 tgt[i].tier = src[i].tier; 1077 tgt[i].announce = tr_strdup (src[i].announce); 1078 maxTier = MAX (maxTier, src[i].tier); 1079 } 1080 1081 return maxTier; 1051 1082 } 1052 1083 … … 1054 1085 freeTrackers (tr_tracker_info * trackers, int n) 1055 1086 { 1056 1057 1058 1059 1060 1061 1087 int i; 1088 1089 for (i=0; i<n; ++i) 1090 tr_free (trackers[i].announce); 1091 1092 tr_free (trackers); 1062 1093 } 1063 1094 … … 1065 1096 addTrackerUrls (tr_torrent * tor, tr_variant * urls) 1066 1097 { 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 { 1085 1086 1087 1088 1089 1090 { 1091 1092 1093 1094 1095 } 1096 } 1097 1098 1099 1100 1101 1102 1103 1104 1098 int i; 1099 int n; 1100 int tier; 1101 tr_variant * val; 1102 tr_tracker_info * trackers; 1103 bool changed = false; 1104 const tr_info * inf = tr_torrentInfo (tor); 1105 const char * errmsg = NULL; 1106 1107 /* make a working copy of the existing announce list */ 1108 n = inf->trackerCount; 1109 trackers = tr_new0 (tr_tracker_info, n + tr_variantListSize (urls)); 1110 tier = copyTrackers (trackers, inf->trackers, n); 1111 1112 /* and add the new ones */ 1113 i = 0; 1114 while ((val = tr_variantListChild (urls, i++))) 1115 { 1116 const char * announce = NULL; 1117 1118 if ( tr_variantGetStr (val, &announce, NULL) 1119 && tr_urlIsValidTracker (announce) 1120 && !findAnnounceUrl (trackers, n, announce, NULL)) 1121 { 1122 trackers[n].tier = ++tier; /* add a new tier */ 1123 trackers[n].announce = tr_strdup (announce); 1124 ++n; 1125 changed = true; 1126 } 1127 } 1128 1129 if (!changed) 1130 errmsg = "invalid argument"; 1131 else if (!tr_torrentSetAnnounceList (tor, trackers, n)) 1132 errmsg = "error setting announce list"; 1133 1134 freeTrackers (trackers, n); 1135 return errmsg; 1105 1136 } 1106 1137 … … 1108 1139 replaceTrackers (tr_torrent * tor, tr_variant * urls) 1109 1140 { 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 ((pair[1] = tr_variantListChild (urls,i+1))))1126 { 1127 1128 1129 1130 1131 if (tr_variantGetInt (pair[0], &pos)1132 1133 1134 1135 1136 { 1137 1138 1139 1140 } 1141 1142 1143 } 1144 1145 1146 1147 1148 1149 1150 1151 1141 int i; 1142 tr_variant * pair[2]; 1143 tr_tracker_info * trackers; 1144 bool changed = false; 1145 const tr_info * inf = tr_torrentInfo (tor); 1146 const int n = inf->trackerCount; 1147 const char * errmsg = NULL; 1148 1149 /* make a working copy of the existing announce list */ 1150 trackers = tr_new0 (tr_tracker_info, n); 1151 copyTrackers (trackers, inf->trackers, n); 1152 1153 /* make the substitutions... */ 1154 i = 0; 1155 while (((pair[0] = tr_variantListChild (urls,i))) && 1156 ((pair[1] = tr_variantListChild (urls,i+1)))) 1157 { 1158 size_t len; 1159 int64_t pos; 1160 const char * newval; 1161 1162 if (tr_variantGetInt (pair[0], &pos) 1163 && tr_variantGetStr (pair[1], &newval, &len) 1164 && tr_urlIsValidTracker (newval) 1165 && pos < n 1166 && pos >= 0) 1167 { 1168 tr_free (trackers[pos].announce); 1169 trackers[pos].announce = tr_strndup (newval, len); 1170 changed = true; 1171 } 1172 1173 i += 2; 1174 } 1175 1176 if (!changed) 1177 errmsg = "invalid argument"; 1178 else if (!tr_torrentSetAnnounceList (tor, trackers, n)) 1179 errmsg = "error setting announce list"; 1180 1181 freeTrackers (trackers, n); 1182 return errmsg; 1152 1183 } 1153 1184 … … 1155 1186 removeTrackers (tr_torrent * tor, tr_variant * ids) 1156 1187 { 1157 int i; 1158 int n; 1159 int t = 0; 1160 int dup = -1; 1161 int * tids; 1162 tr_variant * val; 1163 tr_tracker_info * trackers; 1164 bool changed = false; 1165 const tr_info * inf = tr_torrentInfo (tor); 1166 const char * errmsg = NULL; 1167 1168 /* make a working copy of the existing announce list */ 1169 n = inf->trackerCount; 1170 tids = tr_new0 (int, n); 1171 trackers = tr_new0 (tr_tracker_info, n); 1172 copyTrackers (trackers, inf->trackers, n); 1173 1174 /* remove the ones specified in the urls list */ 1175 i = 0; 1176 while ((val = tr_variantListChild (ids, i++))) 1177 { 1178 int64_t pos; 1179 1180 if ( tr_variantGetInt (val, &pos) 1181 && pos < n 1182 && pos >= 0) 1183 tids[t++] = pos; 1184 } 1185 1186 /* sort trackerIds and remove from largest to smallest so there is no need to recacluate array indicies */ 1187 qsort (tids, t, sizeof (int), compareInt); 1188 while (t--) 1189 { 1190 /* check for duplicates */ 1191 if (tids[t] == dup) 1192 continue; 1193 tr_removeElementFromArray (trackers, tids[t], sizeof (tr_tracker_info), n--); 1194 dup = tids[t]; 1195 changed = true; 1196 } 1197 1198 if (!changed) 1199 errmsg = "invalid argument"; 1200 else if (!tr_torrentSetAnnounceList (tor, trackers, n)) 1201 errmsg = "error setting announce list"; 1202 1203 freeTrackers (trackers, n); 1204 tr_free (tids); 1205 return errmsg; 1188 int i; 1189 int n; 1190 int t = 0; 1191 int dup = -1; 1192 int * tids; 1193 tr_variant * val; 1194 tr_tracker_info * trackers; 1195 bool changed = false; 1196 const tr_info * inf = tr_torrentInfo (tor); 1197 const char * errmsg = NULL; 1198 1199 /* make a working copy of the existing announce list */ 1200 n = inf->trackerCount; 1201 tids = tr_new0 (int, n); 1202 trackers = tr_new0 (tr_tracker_info, n); 1203 copyTrackers (trackers, inf->trackers, n); 1204 1205 /* remove the ones specified in the urls list */ 1206 i = 0; 1207 while ((val = tr_variantListChild (ids, i++))) 1208 { 1209 int64_t pos; 1210 1211 if (tr_variantGetInt (val, &pos) && (0 <= pos) && (pos < n)) 1212 tids[t++] = pos; 1213 } 1214 1215 /* sort trackerIds and remove from largest to smallest so there is no need to recacluate array indicies */ 1216 qsort (tids, t, sizeof (int), compareInt); 1217 while (t--) 1218 { 1219 /* check for duplicates */ 1220 if (tids[t] == dup) 1221 continue; 1222 tr_removeElementFromArray (trackers, tids[t], sizeof (tr_tracker_info), n--); 1223 dup = tids[t]; 1224 changed = true; 1225 } 1226 1227 if (!changed) 1228 errmsg = "invalid argument"; 1229 else if (!tr_torrentSetAnnounceList (tor, trackers, n)) 1230 errmsg = "error setting announce list"; 1231 1232 freeTrackers (trackers, n); 1233 tr_free (tids); 1234 return errmsg; 1206 1235 } 1207 1236 … … 1212 1241 struct tr_rpc_idle_data * idle_data UNUSED) 1213 1242 { 1214 const char * errmsg = NULL; 1215 int i, torrentCount; 1216 tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount); 1217 1218 assert (idle_data == NULL); 1219 1220 for (i = 0; i < torrentCount; ++i) 1221 { 1222 int64_t tmp; 1223 double d; 1224 tr_variant * files; 1225 tr_variant * trackers; 1226 bool boolVal; 1227 tr_torrent * tor = torrents[i]; 1228 1229 if (tr_variantDictFindInt (args_in, TR_KEY_bandwidthPriority, &tmp)) 1230 if (tr_isPriority (tmp)) 1231 tr_torrentSetPriority (tor, tmp); 1232 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_files_unwanted, &files)) 1233 errmsg = setFileDLs (tor, false, files); 1234 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_files_wanted, &files)) 1235 errmsg = setFileDLs (tor, true, files); 1236 if (tr_variantDictFindInt (args_in, TR_KEY_peer_limit, &tmp)) 1237 tr_torrentSetPeerLimit (tor, tmp); 1238 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_priority_high, &files)) 1239 errmsg = setFilePriorities (tor, TR_PRI_HIGH, files); 1240 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_priority_low, &files)) 1241 errmsg = setFilePriorities (tor, TR_PRI_LOW, files); 1242 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_priority_normal, &files)) 1243 errmsg = setFilePriorities (tor, TR_PRI_NORMAL, files); 1244 if (tr_variantDictFindInt (args_in, TR_KEY_downloadLimit, &tmp)) 1245 tr_torrentSetSpeedLimit_KBps (tor, TR_DOWN, tmp); 1246 if (tr_variantDictFindBool (args_in, TR_KEY_downloadLimited, &boolVal)) 1247 tr_torrentUseSpeedLimit (tor, TR_DOWN, boolVal); 1248 if (tr_variantDictFindBool (args_in, TR_KEY_honorsSessionLimits, &boolVal)) 1249 tr_torrentUseSessionLimits (tor, boolVal); 1250 if (tr_variantDictFindInt (args_in, TR_KEY_uploadLimit, &tmp)) 1251 tr_torrentSetSpeedLimit_KBps (tor, TR_UP, tmp); 1252 if (tr_variantDictFindBool (args_in, TR_KEY_uploadLimited, &boolVal)) 1253 tr_torrentUseSpeedLimit (tor, TR_UP, boolVal); 1254 if (tr_variantDictFindInt (args_in, TR_KEY_seedIdleLimit, &tmp)) 1255 tr_torrentSetIdleLimit (tor, tmp); 1256 if (tr_variantDictFindInt (args_in, TR_KEY_seedIdleMode, &tmp)) 1257 tr_torrentSetIdleMode (tor, tmp); 1258 if (tr_variantDictFindReal (args_in, TR_KEY_seedRatioLimit, &d)) 1259 tr_torrentSetRatioLimit (tor, d); 1260 if (tr_variantDictFindInt (args_in, TR_KEY_seedRatioMode, &tmp)) 1261 tr_torrentSetRatioMode (tor, tmp); 1262 if (tr_variantDictFindInt (args_in, TR_KEY_queuePosition, &tmp)) 1263 tr_torrentSetQueuePosition (tor, tmp); 1264 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_trackerAdd, &trackers)) 1265 errmsg = addTrackerUrls (tor, trackers); 1266 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_trackerRemove, &trackers)) 1267 errmsg = removeTrackers (tor, trackers); 1268 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_trackerReplace, &trackers)) 1269 errmsg = replaceTrackers (tor, trackers); 1270 notify (session, TR_RPC_TORRENT_CHANGED, tor); 1271 } 1272 1273 tr_free (torrents); 1274 return errmsg; 1243 int i; 1244 int torrentCount; 1245 tr_torrent ** torrents; 1246 const char * errmsg = NULL; 1247 1248 assert (idle_data == NULL); 1249 1250 torrents = getTorrents (session, args_in, &torrentCount); 1251 1252 for (i=0; i<torrentCount; ++i) 1253 { 1254 int64_t tmp; 1255 double d; 1256 tr_variant * files; 1257 tr_variant * trackers; 1258 bool boolVal; 1259 tr_torrent * tor; 1260 1261 tor = torrents[i]; 1262 1263 if (tr_variantDictFindInt (args_in, TR_KEY_bandwidthPriority, &tmp)) 1264 if (tr_isPriority (tmp)) 1265 tr_torrentSetPriority (tor, tmp); 1266 1267 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_files_unwanted, &files)) 1268 errmsg = setFileDLs (tor, false, files); 1269 1270 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_files_wanted, &files)) 1271 errmsg = setFileDLs (tor, true, files); 1272 1273 if (tr_variantDictFindInt (args_in, TR_KEY_peer_limit, &tmp)) 1274 tr_torrentSetPeerLimit (tor, tmp); 1275 1276 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_priority_high, &files)) 1277 errmsg = setFilePriorities (tor, TR_PRI_HIGH, files); 1278 1279 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_priority_low, &files)) 1280 errmsg = setFilePriorities (tor, TR_PRI_LOW, files); 1281 1282 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_priority_normal, &files)) 1283 errmsg = setFilePriorities (tor, TR_PRI_NORMAL, files); 1284 1285 if (tr_variantDictFindInt (args_in, TR_KEY_downloadLimit, &tmp)) 1286 tr_torrentSetSpeedLimit_KBps (tor, TR_DOWN, tmp); 1287 1288 if (tr_variantDictFindBool (args_in, TR_KEY_downloadLimited, &boolVal)) 1289 tr_torrentUseSpeedLimit (tor, TR_DOWN, boolVal); 1290 1291 if (tr_variantDictFindBool (args_in, TR_KEY_honorsSessionLimits, &boolVal)) 1292 tr_torrentUseSessionLimits (tor, boolVal); 1293 1294 if (tr_variantDictFindInt (args_in, TR_KEY_uploadLimit, &tmp)) 1295 tr_torrentSetSpeedLimit_KBps (tor, TR_UP, tmp); 1296 1297 if (tr_variantDictFindBool (args_in, TR_KEY_uploadLimited, &boolVal)) 1298 tr_torrentUseSpeedLimit (tor, TR_UP, boolVal); 1299 1300 if (tr_variantDictFindInt (args_in, TR_KEY_seedIdleLimit, &tmp)) 1301 tr_torrentSetIdleLimit (tor, tmp); 1302 1303 if (tr_variantDictFindInt (args_in, TR_KEY_seedIdleMode, &tmp)) 1304 tr_torrentSetIdleMode (tor, tmp); 1305 1306 if (tr_variantDictFindReal (args_in, TR_KEY_seedRatioLimit, &d)) 1307 tr_torrentSetRatioLimit (tor, d); 1308 1309 if (tr_variantDictFindInt (args_in, TR_KEY_seedRatioMode, &tmp)) 1310 tr_torrentSetRatioMode (tor, tmp); 1311 1312 if (tr_variantDictFindInt (args_in, TR_KEY_queuePosition, &tmp)) 1313 tr_torrentSetQueuePosition (tor, tmp); 1314 1315 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_trackerAdd, &trackers)) 1316 errmsg = addTrackerUrls (tor, trackers); 1317 1318 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_trackerRemove, &trackers)) 1319 errmsg = removeTrackers (tor, trackers); 1320 1321 if (!errmsg && tr_variantDictFindList (args_in, TR_KEY_trackerReplace, &trackers)) 1322 errmsg = replaceTrackers (tor, trackers); 1323 1324 notify (session, TR_RPC_TORRENT_CHANGED, tor); 1325 } 1326 1327 tr_free (torrents); 1328 return errmsg; 1275 1329 } 1276 1330 … … 1375 1429 void * user_data) 1376 1430 { 1377 1378 1379 1380 1381 { 1382 1383 1384 } 1385 1386 { 1387 1388 1389 1431 char result[1024]; 1432 struct tr_rpc_idle_data * data = user_data; 1433 1434 if (response_code != 200) 1435 { 1436 tr_snprintf (result, sizeof (result), "portTested: http error %ld: %s", 1437 response_code, tr_webGetResponseStr (response_code)); 1438 } 1439 else /* success */ 1440 { 1441 const bool isOpen = response_byte_count && * (char*)response == '1'; 1442 tr_variantDictAddBool (data->args_out, TR_KEY_port_is_open, isOpen); 1443 tr_snprintf (result, sizeof (result), "success"); 1390 1444 } 1391 1445 … … 1399 1453 struct tr_rpc_idle_data * idle_data) 1400 1454 { 1401 1402 1403 1404 1405 1455 const int port = tr_sessionGetPeerPort (session); 1456 char * url = tr_strdup_printf ("http://portcheck.transmissionbt.com/%d", port); 1457 tr_webRun (session, url, portTested, idle_data); 1458 tr_free (url); 1459 return NULL; 1406 1460 } 1407 1461 … … 1419 1473 void * user_data) 1420 1474 { 1421 char result[1024]; 1422 struct tr_rpc_idle_data * data = user_data; 1423 1424 *result = '\0'; 1425 1426 if (response_code != 200) 1427 { 1428 tr_snprintf (result, sizeof (result), "gotNewBlocklist: http error %ld: %s", 1429 response_code, tr_webGetResponseStr (response_code)); 1430 } 1431 else /* successfully fetched the blocklist... */ 1432 { 1433 int fd; 1434 int err; 1435 char * filename; 1436 z_stream stream; 1437 const char * configDir = tr_sessionGetConfigDir (session); 1438 const size_t buflen = 1024 * 128; /* 128 KiB buffer */ 1439 uint8_t * buf = tr_valloc (buflen); 1440 1441 /* this is an odd Magic Number required by zlib to enable gz support. 1442 See zlib's inflateInit2 () documentation for a full description */ 1443 const int windowBits = 15 + 32; 1444 1445 stream.zalloc = (alloc_func) Z_NULL; 1446 stream.zfree = (free_func) Z_NULL; 1447 stream.opaque = (voidpf) Z_NULL; 1448 stream.next_in = (void*) response; 1449 stream.avail_in = response_byte_count; 1450 inflateInit2 (&stream, windowBits); 1451 1452 filename = tr_buildPath (configDir, "blocklist.tmp", NULL); 1453 fd = tr_open_file_for_writing (filename); 1454 if (fd < 0) 1455 tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno)); 1456 1457 for (;;) 1458 { 1459 stream.next_out = (void*) buf; 1460 stream.avail_out = buflen; 1461 err = inflate (&stream, Z_NO_FLUSH); 1462 1463 if (stream.avail_out < buflen) { 1464 const int e = write (fd, buf, buflen - stream.avail_out); 1465 if (e < 0) { 1466 tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno)); 1467 break; 1475 char result[1024]; 1476 struct tr_rpc_idle_data * data = user_data; 1477 1478 *result = '\0'; 1479 1480 if (response_code != 200) 1481 { 1482 tr_snprintf (result, sizeof (result), "gotNewBlocklist: http error %ld: %s", 1483 response_code, tr_webGetResponseStr (response_code)); 1484 } 1485 else /* successfully fetched the blocklist... */ 1486 { 1487 int fd; 1488 int err; 1489 char * filename; 1490 z_stream stream; 1491 const char * configDir = tr_sessionGetConfigDir (session); 1492 const size_t buflen = 1024 * 128; /* 128 KiB buffer */ 1493 uint8_t * buf = tr_valloc (buflen); 1494 1495 /* this is an odd Magic Number required by zlib to enable gz support. 1496 See zlib's inflateInit2 () documentation for a full description */ 1497 const int windowBits = 15 + 32; 1498 1499 stream.zalloc = (alloc_func) Z_NULL; 1500 stream.zfree = (free_func) Z_NULL; 1501 stream.opaque = (voidpf) Z_NULL; 1502 stream.next_in = (void*) response; 1503 stream.avail_in = response_byte_count; 1504 inflateInit2 (&stream, windowBits); 1505 1506 filename = tr_buildPath (configDir, "blocklist.tmp", NULL); 1507 fd = tr_open_file_for_writing (filename); 1508 if (fd < 0) 1509 tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno)); 1510 1511 for (;;) 1512 { 1513 stream.next_out = (void*) buf; 1514 stream.avail_out = buflen; 1515 err = inflate (&stream, Z_NO_FLUSH); 1516 1517 if (stream.avail_out < buflen) 1518 { 1519 const int e = write (fd, buf, buflen - stream.avail_out); 1520 if (e < 0) 1521 { 1522 tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno)); 1523 break; 1468 1524 } 1469 1525 } 1470 1526 1471 if (err != Z_OK) { 1472 if ((err != Z_STREAM_END) && (err != Z_DATA_ERROR)) 1473 tr_snprintf (result, sizeof (result), _("Error uncompressing blocklist: %s (%d)"), zError (err), err); 1474 break; 1527 if (err != Z_OK) 1528 { 1529 if ((err != Z_STREAM_END) && (err != Z_DATA_ERROR)) 1530 tr_snprintf (result, sizeof (result), _("Error uncompressing blocklist: %s (%d)"), zError (err), err); 1531 break; 1475 1532 } 1476 1533 } 1477 1534 1478 inflateEnd (&stream); 1479 1480 if (err == Z_DATA_ERROR) /* couldn't inflate it... it's probably already uncompressed */ 1481 if (write (fd, response, response_byte_count) < 0) 1482 tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno)); 1483 1484 if (*result) 1485 tr_logAddError ("%s", result); 1486 else { 1487 /* feed it to the session and give the client a response */ 1488 const int rule_count = tr_blocklistSetContent (session, filename); 1489 tr_variantDictAddInt (data->args_out, TR_KEY_blocklist_size, rule_count); 1490 tr_snprintf (result, sizeof (result), "success"); 1491 } 1492 1493 tr_remove (filename); 1494 tr_free (filename); 1495 tr_free (buf); 1496 } 1497 1498 tr_idle_function_done (data, result); 1535 inflateEnd (&stream); 1536 1537 if (err == Z_DATA_ERROR) /* couldn't inflate it... it's probably already uncompressed */ 1538 if (write (fd, response, response_byte_count) < 0) 1539 tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno)); 1540 1541 if (*result) 1542 { 1543 tr_logAddError ("%s", result); 1544 } 1545 else 1546 { 1547 /* feed it to the session and give the client a response */ 1548 const int rule_count = tr_blocklistSetContent (session, filename); 1549 tr_variantDictAddInt (data->args_out, TR_KEY_blocklist_size, rule_count); 1550 tr_snprintf (result, sizeof (result), "success"); 1551 } 1552 1553 tr_remove (filename); 1554 tr_free (filename); 1555 tr_free (buf); 1556 } 1557 1558 tr_idle_function_done (data, result); 1499 1559 } 1500 1560 … … 1505 1565 struct tr_rpc_idle_data * idle_data) 1506 1566 { 1507 1508 1567 tr_webRun (session, session->blocklist_url, gotNewBlocklist, idle_data); 1568 return NULL; 1509 1569 } 1510 1570 … … 1561 1621 struct add_torrent_idle_data 1562 1622 { 1563 1564 1623 struct tr_rpc_idle_data * data; 1624 tr_ctor * ctor; 1565 1625 }; 1566 1626 … … 1574 1634 void * user_data) 1575 1635 { 1576 1577 1578 1579 1580 1581 1582 { 1583 1584 1585 } 1586 1587 { 1588 1589 1590 1591 1592 } 1593 1594 1636 struct add_torrent_idle_data * data = user_data; 1637 1638 dbgmsg ("torrentAdd: HTTP response code was %ld (%s); response length was %zu bytes", 1639 response_code, tr_webGetResponseStr (response_code), response_byte_count); 1640 1641 if (response_code==200 || response_code==221) /* http or ftp success.. */ 1642 { 1643 tr_ctorSetMetainfo (data->ctor, response, response_byte_count); 1644 addTorrentImpl (data->data, data->ctor); 1645 } 1646 else 1647 { 1648 char result[1024]; 1649 tr_snprintf (result, sizeof (result), "gotMetadataFromURL: http error %ld: %s", 1650 response_code, tr_webGetResponseStr (response_code)); 1651 tr_idle_function_done (data->data, result); 1652 } 1653 1654 tr_free (data); 1595 1655 } 1596 1656 … … 1598 1658 isCurlURL (const char * filename) 1599 1659 { 1600 1601 1602 1603 1604 1605 1660 if (filename == NULL) 1661 return false; 1662 1663 return !strncmp (filename, "ftp://", 6) || 1664 !strncmp (filename, "http://", 7) || 1665 !strncmp (filename, "https://", 8); 1606 1666 } 1607 1667 … … 1609 1669 fileListFromList (tr_variant * list, tr_file_index_t * setmeCount) 1610 1670 { 1611 size_t i; 1612 const size_t childCount = tr_variantListSize (list); 1613 tr_file_index_t n = 0; 1614 tr_file_index_t * files = tr_new0 (tr_file_index_t, childCount); 1615 1616 for (i=0; i<childCount; ++i) { 1617 int64_t intVal; 1618 if (tr_variantGetInt (tr_variantListChild (list, i), &intVal)) 1619 files[n++] = (tr_file_index_t)intVal; 1620 } 1621 1622 *setmeCount = n; 1623 return files; 1671 size_t i; 1672 const size_t childCount = tr_variantListSize (list); 1673 tr_file_index_t n = 0; 1674 tr_file_index_t * files = tr_new0 (tr_file_index_t, childCount); 1675 1676 for (i=0; i<childCount; ++i) 1677 { 1678 int64_t intVal; 1679 if (tr_variantGetInt (tr_variantListChild (list, i), &intVal)) 1680 files[n++] = (tr_file_index_t)intVal; 1681 } 1682 1683 *setmeCount = n; 1684 return files; 1624 1685 } 1625 1686 … … 1630 1691 struct tr_rpc_idle_data * idle_data) 1631 1692 { 1632 const char * filename = NULL; 1633 const char * metainfo_base64 = NULL; 1634 1635 assert (idle_data != NULL); 1636 1637 tr_variantDictFindStr (args_in, TR_KEY_filename, &filename, NULL); 1638 tr_variantDictFindStr (args_in, TR_KEY_metainfo, &metainfo_base64, NULL); 1639 if (!filename && !metainfo_base64) 1640 return "no filename or metainfo specified"; 1641 else 1642 { 1643 int64_t i; 1644 bool boolVal; 1645 tr_variant * l; 1646 const char * str; 1647 const char * cookies = NULL; 1648 tr_ctor * ctor = tr_ctorNew (session); 1649 1650 /* set the optional arguments */ 1651 1652 tr_variantDictFindStr (args_in, TR_KEY_cookies, &cookies, NULL); 1653 1654 if (tr_variantDictFindStr (args_in, TR_KEY_download_dir, &str, NULL)) 1655 tr_ctorSetDownloadDir (ctor, TR_FORCE, str); 1656 1657 if (tr_variantDictFindBool (args_in, TR_KEY_paused, &boolVal)) 1658 tr_ctorSetPaused (ctor, TR_FORCE, boolVal); 1659 1660 if (tr_variantDictFindInt (args_in, TR_KEY_peer_limit, &i)) 1661 tr_ctorSetPeerLimit (ctor, TR_FORCE, i); 1662 1663 if (tr_variantDictFindInt (args_in, TR_KEY_bandwidthPriority, &i)) 1664 tr_ctorSetBandwidthPriority (ctor, i); 1665 1666 if (tr_variantDictFindList (args_in, TR_KEY_files_unwanted, &l)) { 1667 tr_file_index_t fileCount; 1668 tr_file_index_t * files = fileListFromList (l, &fileCount); 1669 tr_ctorSetFilesWanted (ctor, files, fileCount, false); 1670 tr_free (files); 1671 } 1672 if (tr_variantDictFindList (args_in, TR_KEY_files_wanted, &l)) { 1673 tr_file_index_t fileCount; 1674 tr_file_index_t * files = fileListFromList (l, &fileCount); 1675 tr_ctorSetFilesWanted (ctor, files, fileCount, true); 1676 tr_free (files); 1677 } 1678 1679 if (tr_variantDictFindList (args_in, TR_KEY_priority_low, &l)) { 1680 tr_file_index_t fileCount; 1681 tr_file_index_t * files = fileListFromList (l, &fileCount); 1682 tr_ctorSetFilePriorities (ctor, files, fileCount, TR_PRI_LOW); 1683 tr_free (files); 1684 } 1685 if (tr_variantDictFindList (args_in, TR_KEY_priority_normal, &l)) { 1686 tr_file_index_t fileCount; 1687 tr_file_index_t * files = fileListFromList (l, &fileCount); 1688 tr_ctorSetFilePriorities (ctor, files, fileCount, TR_PRI_NORMAL); 1689 tr_free (files); 1690 } 1691 if (tr_variantDictFindList (args_in, TR_KEY_priority_high, &l)) { 1692 tr_file_index_t fileCount; 1693 tr_file_index_t * files = fileListFromList (l, &fileCount); 1694 tr_ctorSetFilePriorities (ctor, files, fileCount, TR_PRI_HIGH); 1695 tr_free (files); 1696 } 1697 1698 dbgmsg ("torrentAdd: filename is \"%s\"", filename ? filename : " (null)"); 1699 1700 if (isCurlURL (filename)) 1701 { 1702 struct add_torrent_idle_data * d = tr_new0 (struct add_torrent_idle_data, 1); 1703 d->data = idle_data; 1704 d->ctor = ctor; 1705 tr_webRunWithCookies (session, filename, cookies, gotMetadataFromURL, d); 1706 } 1707 else 1708 { 1709 char * fname = tr_strstrip (tr_strdup (filename)); 1710 1711 if (fname == NULL) 1693 const char * filename = NULL; 1694 const char * metainfo_base64 = NULL; 1695 1696 assert (idle_data != NULL); 1697 1698 tr_variantDictFindStr (args_in, TR_KEY_filename, &filename, NULL); 1699 tr_variantDictFindStr (args_in, TR_KEY_metainfo, &metainfo_base64, NULL); 1700 if (!filename && !metainfo_base64) 1701 { 1702 return "no filename or metainfo specified"; 1703 } 1704 else 1705 { 1706 int64_t i; 1707 bool boolVal; 1708 tr_variant * l; 1709 const char * str; 1710 const char * cookies = NULL; 1711 tr_ctor * ctor = tr_ctorNew (session); 1712 1713 /* set the optional arguments */ 1714 1715 tr_variantDictFindStr (args_in, TR_KEY_cookies, &cookies, NULL); 1716 1717 if (tr_variantDictFindStr (args_in, TR_KEY_download_dir, &str, NULL)) 1718 tr_ctorSetDownloadDir (ctor, TR_FORCE, str); 1719 1720 if (tr_variantDictFindBool (args_in, TR_KEY_paused, &boolVal)) 1721 tr_ctorSetPaused (ctor, TR_FORCE, boolVal); 1722 1723 if (tr_variantDictFindInt (args_in, TR_KEY_peer_limit, &i)) 1724 tr_ctorSetPeerLimit (ctor, TR_FORCE, i); 1725 1726 if (tr_variantDictFindInt (args_in, TR_KEY_bandwidthPriority, &i)) 1727 tr_ctorSetBandwidthPriority (ctor, i); 1728 1729 if (tr_variantDictFindList (args_in, TR_KEY_files_unwanted, &l)) 1730 { 1731 tr_file_index_t fileCount; 1732 tr_file_index_t * files = fileListFromList (l, &fileCount); 1733 tr_ctorSetFilesWanted (ctor, files, fileCount, false); 1734 tr_free (files); 1735 } 1736 1737 if (tr_variantDictFindList (args_in, TR_KEY_files_wanted, &l)) 1738 { 1739 tr_file_index_t fileCount; 1740 tr_file_index_t * files = fileListFromList (l, &fileCount); 1741 tr_ctorSetFilesWanted (ctor, files, fileCount, true); 1742 tr_free (files); 1743 } 1744 1745 if (tr_variantDictFindList (args_in, TR_KEY_priority_low, &l)) 1746 { 1747 tr_file_index_t fileCount; 1748 tr_file_index_t * files = fileListFromList (l, &fileCount); 1749 tr_ctorSetFilePriorities (ctor, files, fileCount, TR_PRI_LOW); 1750 tr_free (files); 1751 } 1752 1753 if (tr_variantDictFindList (args_in, TR_KEY_priority_normal, &l)) 1754 { 1755 tr_file_index_t fileCount; 1756 tr_file_index_t * files = fileListFromList (l, &fileCount); 1757 tr_ctorSetFilePriorities (ctor, files, fileCount, TR_PRI_NORMAL); 1758 tr_free (files); 1759 } 1760 1761 if (tr_variantDictFindList (args_in, TR_KEY_priority_high, &l)) 1762 { 1763 tr_file_index_t fileCount; 1764 tr_file_index_t * files = fileListFromList (l, &fileCount); 1765 tr_ctorSetFilePriorities (ctor, files, fileCount, TR_PRI_HIGH); 1766 tr_free (files); 1767 } 1768 1769 dbgmsg ("torrentAdd: filename is \"%s\"", filename ? filename : " (null)"); 1770 1771 if (isCurlURL (filename)) 1772 { 1773 struct add_torrent_idle_data * d = tr_new0 (struct add_torrent_idle_data, 1); 1774 d->data = idle_data; 1775 d->ctor = ctor; 1776 tr_webRunWithCookies (session, filename, cookies, gotMetadataFromURL, d); 1777 } 1778 else 1779 { 1780 char * fname = tr_strstrip (tr_strdup (filename)); 1781 1782 if (fname == NULL) 1712 1783 { 1713 1714 1715 1716 1784 int len; 1785 char * metainfo = tr_base64_decode (metainfo_base64, -1, &len); 1786 tr_ctorSetMetainfo (ctor, (uint8_t*)metainfo, len); 1787 tr_free (metainfo); 1717 1788 } 1718 1789 else if (!strncmp (fname, "magnet:?", 8)) 1719 1790 { 1720 1791 tr_ctorSetMetainfoFromMagnetLink (ctor, fname); 1721 1792 } 1722 1793 else 1723 1794 { 1724 1795 tr_ctorSetMetainfoFromFile (ctor, fname); 1725 1796 } 1726 1797 1727 1728 1729 1730 } 1731 1732 } 1733 1734 1798 addTorrentImpl (idle_data, ctor); 1799 1800 tr_free (fname); 1801 } 1802 1803 } 1804 1805 return NULL; 1735 1806 } 1736 1807 … … 1745 1816 struct tr_rpc_idle_data * idle_data UNUSED) 1746 1817 { 1747 int64_t i; 1748 double d; 1749 bool boolVal; 1750 const char * str; 1751 1752 assert (idle_data == NULL); 1753 1754 if (tr_variantDictFindInt (args_in, TR_KEY_cache_size_mb, &i)) 1755 tr_sessionSetCacheLimit_MB (session, i); 1756 if (tr_variantDictFindInt (args_in, TR_KEY_alt_speed_up, &i)) 1757 tr_sessionSetAltSpeed_KBps (session, TR_UP, i); 1758 if (tr_variantDictFindInt (args_in, TR_KEY_alt_speed_down, &i)) 1759 tr_sessionSetAltSpeed_KBps (session, TR_DOWN, i); 1760 if (tr_variantDictFindBool (args_in, TR_KEY_alt_speed_enabled, &boolVal)) 1761 tr_sessionUseAltSpeed (session, boolVal); 1762 if (tr_variantDictFindInt (args_in, TR_KEY_alt_speed_time_begin, &i)) 1763 tr_sessionSetAltSpeedBegin (session, i); 1764 if (tr_variantDictFindInt (args_in, TR_KEY_alt_speed_time_end, &i)) 1765 tr_sessionSetAltSpeedEnd (session, i); 1766 if (tr_variantDictFindInt (args_in, TR_KEY_alt_speed_time_day, &i)) 1767 tr_sessionSetAltSpeedDay (session, i); 1768 if (tr_variantDictFindBool (args_in, TR_KEY_alt_speed_time_enabled, &boolVal)) 1769 tr_sessionUseAltSpeedTime (session, boolVal); 1770 if (tr_variantDictFindBool (args_in, TR_KEY_blocklist_enabled, &boolVal)) 1771 tr_blocklistSetEnabled (session, boolVal); 1772 if (tr_variantDictFindStr (args_in, TR_KEY_blocklist_url, &str, NULL)) 1773 tr_blocklistSetURL (session, str); 1774 if (tr_variantDictFindStr (args_in, TR_KEY_download_dir, &str, NULL)) 1775 tr_sessionSetDownloadDir (session, str); 1776 if (tr_variantDictFindInt (args_in, TR_KEY_queue_stalled_minutes, &i)) 1777 tr_sessionSetQueueStalledMinutes (session, i); 1778 if (tr_variantDictFindBool (args_in, TR_KEY_queue_stalled_enabled, &boolVal)) 1779 tr_sessionSetQueueStalledEnabled (session, boolVal); 1780 if (tr_variantDictFindInt (args_in, TR_KEY_download_queue_size, &i)) 1781 tr_sessionSetQueueSize (session, TR_DOWN, i); 1782 if (tr_variantDictFindBool (args_in, TR_KEY_download_queue_enabled, &boolVal)) 1783 tr_sessionSetQueueEnabled (session, TR_DOWN, boolVal); 1784 if (tr_variantDictFindStr (args_in, TR_KEY_incomplete_dir, &str, NULL)) 1785 tr_sessionSetIncompleteDir (session, str); 1786 if (tr_variantDictFindBool (args_in, TR_KEY_incomplete_dir_enabled, &boolVal)) 1787 tr_sessionSetIncompleteDirEnabled (session, boolVal); 1788 if (tr_variantDictFindInt (args_in, TR_KEY_peer_limit_global, &i)) 1789 tr_sessionSetPeerLimit (session, i); 1790 if (tr_variantDictFindInt (args_in, TR_KEY_peer_limit_per_torrent, &i)) 1791 tr_sessionSetPeerLimitPerTorrent (session, i); 1792 if (tr_variantDictFindBool (args_in, TR_KEY_pex_enabled, &boolVal)) 1793 tr_sessionSetPexEnabled (session, boolVal); 1794 if (tr_variantDictFindBool (args_in, TR_KEY_dht_enabled, &boolVal)) 1795 tr_sessionSetDHTEnabled (session, boolVal); 1796 if (tr_variantDictFindBool (args_in, TR_KEY_utp_enabled, &boolVal)) 1797 tr_sessionSetUTPEnabled (session, boolVal); 1798 if (tr_variantDictFindBool (args_in, TR_KEY_lpd_enabled, &boolVal)) 1799 tr_sessionSetLPDEnabled (session, boolVal); 1800 if (tr_variantDictFindBool (args_in, TR_KEY_peer_port_random_on_start, &boolVal)) 1801 tr_sessionSetPeerPortRandomOnStart (session, boolVal); 1802 if (tr_variantDictFindInt (args_in, TR_KEY_peer_port, &i)) 1803 tr_sessionSetPeerPort (session, i); 1804 if (tr_variantDictFindBool (args_in, TR_KEY_port_forwarding_enabled, &boolVal)) 1805 tr_sessionSetPortForwardingEnabled (session, boolVal); 1806 if (tr_variantDictFindBool (args_in, TR_KEY_rename_partial_files, &boolVal)) 1807 tr_sessionSetIncompleteFileNamingEnabled (session, boolVal); 1808 if (tr_variantDictFindReal (args_in, TR_KEY_seedRatioLimit, &d)) 1809 tr_sessionSetRatioLimit (session, d); 1810 if (tr_variantDictFindBool (args_in, TR_KEY_seedRatioLimited, &boolVal)) 1811 tr_sessionSetRatioLimited (session, boolVal); 1812 if (tr_variantDictFindInt (args_in, TR_KEY_idle_seeding_limit, &i)) 1813 tr_sessionSetIdleLimit (session, i); 1814 if (tr_variantDictFindBool (args_in, TR_KEY_idle_seeding_limit_enabled, &boolVal)) 1815 tr_sessionSetIdleLimited (session, boolVal); 1816 if (tr_variantDictFindBool (args_in, TR_KEY_start_added_torrents, &boolVal)) 1817 tr_sessionSetPaused (session, !boolVal); 1818 if (tr_variantDictFindBool (args_in, TR_KEY_seed_queue_enabled, &boolVal)) 1819 tr_sessionSetQueueEnabled (session, TR_UP, boolVal); 1820 if (tr_variantDictFindInt (args_in, TR_KEY_seed_queue_size, &i)) 1821 tr_sessionSetQueueSize (session, TR_UP, i); 1822 if (tr_variantDictFindStr (args_in, TR_KEY_script_torrent_done_filename, &str, NULL)) 1823 tr_sessionSetTorrentDoneScript (session, str); 1824 if (tr_variantDictFindBool (args_in, TR_KEY_script_torrent_done_enabled, &boolVal)) 1825 tr_sessionSetTorrentDoneScriptEnabled (session, boolVal); 1826 if (tr_variantDictFindBool (args_in, TR_KEY_trash_original_torrent_files, &boolVal)) 1827 tr_sessionSetDeleteSource (session, boolVal); 1828 if (tr_variantDictFindInt (args_in, TR_KEY_speed_limit_down, &i)) 1829 tr_sessionSetSpeedLimit_KBps (session, TR_DOWN, i); 1830 if (tr_variantDictFindBool (args_in, TR_KEY_speed_limit_down_enabled, &boolVal)) 1831 tr_sessionLimitSpeed (session, TR_DOWN, boolVal); 1832 if (tr_variantDictFindInt (args_in, TR_KEY_speed_limit_up, &i)) 1833 tr_sessionSetSpeedLimit_KBps (session, TR_UP, i); 1834 if (tr_variantDictFindBool (args_in, TR_KEY_speed_limit_up_enabled, &boolVal)) 1835 tr_sessionLimitSpeed (session, TR_UP, boolVal); 1836 if (tr_variantDictFindStr (args_in, TR_KEY_encryption, &str, NULL)) { 1837 if (!strcmp (str, "required")) 1838 tr_sessionSetEncryption (session, TR_ENCRYPTION_REQUIRED); 1839 else if (!strcmp (str, "tolerated")) 1840 tr_sessionSetEncryption (session, TR_CLEAR_PREFERRED); 1841 else 1842 tr_sessionSetEncryption (session, TR_ENCRYPTION_PREFERRED); 1843 } 1844 1845 notify (session, TR_RPC_SESSION_CHANGED, NULL); 1846 1847 return NULL; 1818 int64_t i; 1819 double d; 1820 bool boolVal; 1821 const char * str; 1822 1823 assert (idle_data == NULL); 1824 1825 if (tr_variantDictFindInt (args_in, TR_KEY_cache_size_mb, &i)) 1826 tr_sessionSetCacheLimit_MB (session, i); 1827 1828 if (tr_variantDictFindInt (args_in, TR_KEY_alt_speed_up, &i)) 1829 tr_sessionSetAltSpeed_KBps (session, TR_UP, i); 1830 1831 if (tr_variantDictFindInt (args_in, TR_KEY_alt_speed_down, &i)) 1832 tr_sessionSetAltSpeed_KBps (session, TR_DOWN, i); 1833 1834 if (tr_variantDictFindBool (args_in, TR_KEY_alt_speed_enabled, &boolVal)) 1835 tr_sessionUseAltSpeed (session, boolVal); 1836 1837 if (tr_variantDictFindInt (args_in, TR_KEY_alt_speed_time_begin, &i)) 1838 tr_sessionSetAltSpeedBegin (session, i); 1839 1840 if (tr_variantDictFindInt (args_in, TR_KEY_alt_speed_time_end, &i)) 1841 tr_sessionSetAltSpeedEnd (session, i); 1842 1843 if (tr_variantDictFindInt (args_in, TR_KEY_alt_speed_time_day, &i)) 1844 tr_sessionSetAltSpeedDay (session, i); 1845 1846 if (tr_variantDictFindBool (args_in, TR_KEY_alt_speed_time_enabled, &boolVal)) 1847 tr_sessionUseAltSpeedTime (session, boolVal); 1848 1849 if (tr_variantDictFindBool (args_in, TR_KEY_blocklist_enabled, &boolVal)) 1850 tr_blocklistSetEnabled (session, boolVal); 1851 1852 if (tr_variantDictFindStr (args_in, TR_KEY_blocklist_url, &str, NULL)) 1853 tr_blocklistSetURL (session, str); 1854 1855 if (tr_variantDictFindStr (args_in, TR_KEY_download_dir, &str, NULL)) 1856 tr_sessionSetDownloadDir (session, str); 1857 1858 if (tr_variantDictFindInt (args_in, TR_KEY_queue_stalled_minutes, &i)) 1859 tr_sessionSetQueueStalledMinutes (session, i); 1860 1861 if (tr_variantDictFindBool (args_in, TR_KEY_queue_stalled_enabled, &boolVal)) 1862 tr_sessionSetQueueStalledEnabled (session, boolVal); 1863 1864 if (tr_variantDictFindInt (args_in, TR_KEY_download_queue_size, &i)) 1865 tr_sessionSetQueueSize (session, TR_DOWN, i); 1866 1867 if (tr_variantDictFindBool (args_in, TR_KEY_download_queue_enabled, &boolVal)) 1868 tr_sessionSetQueueEnabled (session, TR_DOWN, boolVal); 1869 1870 if (tr_variantDictFindStr (args_in, TR_KEY_incomplete_dir, &str, NULL)) 1871 tr_sessionSetIncompleteDir (session, str); 1872 1873 if (tr_variantDictFindBool (args_in, TR_KEY_incomplete_dir_enabled, &boolVal)) 1874 tr_sessionSetIncompleteDirEnabled (session, boolVal); 1875 1876 if (tr_variantDictFindInt (args_in, TR_KEY_peer_limit_global, &i)) 1877 tr_sessionSetPeerLimit (session, i); 1878 1879 if (tr_variantDictFindInt (args_in, TR_KEY_peer_limit_per_torrent, &i)) 1880 tr_sessionSetPeerLimitPerTorrent (session, i); 1881 1882 if (tr_variantDictFindBool (args_in, TR_KEY_pex_enabled, &boolVal)) 1883 tr_sessionSetPexEnabled (session, boolVal); 1884 1885 if (tr_variantDictFindBool (args_in, TR_KEY_dht_enabled, &boolVal)) 1886 tr_sessionSetDHTEnabled (session, boolVal); 1887 1888 if (tr_variantDictFindBool (args_in, TR_KEY_utp_enabled, &boolVal)) 1889 tr_sessionSetUTPEnabled (session, boolVal); 1890 1891 if (tr_variantDictFindBool (args_in, TR_KEY_lpd_enabled, &boolVal)) 1892 tr_sessionSetLPDEnabled (session, boolVal); 1893 1894 if (tr_variantDictFindBool (args_in, TR_KEY_peer_port_random_on_start, &boolVal)) 1895 tr_sessionSetPeerPortRandomOnStart (session, boolVal); 1896 1897 if (tr_variantDictFindInt (args_in, TR_KEY_peer_port, &i)) 1898 tr_sessionSetPeerPort (session, i); 1899 1900 if (tr_variantDictFindBool (args_in, TR_KEY_port_forwarding_enabled, &boolVal)) 1901 tr_sessionSetPortForwardingEnabled (session, boolVal); 1902 1903 if (tr_variantDictFindBool (args_in, TR_KEY_rename_partial_files, &boolVal)) 1904 tr_sessionSetIncompleteFileNamingEnabled (session, boolVal); 1905 1906 if (tr_variantDictFindReal (args_in, TR_KEY_seedRatioLimit, &d)) 1907 tr_sessionSetRatioLimit (session, d); 1908 1909 if (tr_variantDictFindBool (args_in, TR_KEY_seedRatioLimited, &boolVal)) 1910 tr_sessionSetRatioLimited (session, boolVal); 1911 1912 if (tr_variantDictFindInt (args_in, TR_KEY_idle_seeding_limit, &i)) 1913 tr_sessionSetIdleLimit (session, i); 1914 1915 if (tr_variantDictFindBool (args_in, TR_KEY_idle_seeding_limit_enabled, &boolVal)) 1916 tr_sessionSetIdleLimited (session, boolVal); 1917 1918 if (tr_variantDictFindBool (args_in, TR_KEY_start_added_torrents, &boolVal)) 1919 tr_sessionSetPaused (session, !boolVal); 1920 1921 if (tr_variantDictFindBool (args_in, TR_KEY_seed_queue_enabled, &boolVal)) 1922 tr_sessionSetQueueEnabled (session, TR_UP, boolVal); 1923 1924 if (tr_variantDictFindInt (args_in, TR_KEY_seed_queue_size, &i)) 1925 tr_sessionSetQueueSize (session, TR_UP, i); 1926 1927 if (tr_variantDictFindStr (args_in, TR_KEY_script_torrent_done_filename, &str, NULL)) 1928 tr_sessionSetTorrentDoneScript (session, str); 1929 1930 if (tr_variantDictFindBool (args_in, TR_KEY_script_torrent_done_enabled, &boolVal)) 1931 tr_sessionSetTorrentDoneScriptEnabled (session, boolVal); 1932 1933 if (tr_variantDictFindBool (args_in, TR_KEY_trash_original_torrent_files, &boolVal)) 1934 tr_sessionSetDeleteSource (session, boolVal); 1935 1936 if (tr_variantDictFindInt (args_in, TR_KEY_speed_limit_down, &i)) 1937 tr_sessionSetSpeedLimit_KBps (session, TR_DOWN, i); 1938 1939 if (tr_variantDictFindBool (args_in, TR_KEY_speed_limit_down_enabled, &boolVal)) 1940 tr_sessionLimitSpeed (session, TR_DOWN, boolVal); 1941 1942 if (tr_variantDictFindInt (args_in, TR_KEY_speed_limit_up, &i)) 1943 tr_sessionSetSpeedLimit_KBps (session, TR_UP, i); 1944 1945 if (tr_variantDictFindBool (args_in, TR_KEY_speed_limit_up_enabled, &boolVal)) 1946 tr_sessionLimitSpeed (session, TR_UP, boolVal); 1947 1948 if (tr_variantDictFindStr (args_in, TR_KEY_encryption, &str, NULL)) 1949 { 1950 if (!tr_strcmp0 (str, "required")) 1951 tr_sessionSetEncryption (session, TR_ENCRYPTION_REQUIRED); 1952 else if (!tr_strcmp0 (str, "tolerated")) 1953 tr_sessionSetEncryption (session, TR_CLEAR_PREFERRED); 1954 else 1955 tr_sessionSetEncryption (session, TR_ENCRYPTION_PREFERRED); 1956 } 1957 1958 notify (session, TR_RPC_SESSION_CHANGED, NULL); 1959 1960 return NULL; 1848 1961 } 1849 1962 1850 1963 static const char* 1851 1964 sessionStats (tr_session * session, 1852 tr_variant 1853 tr_variant 1965 tr_variant * args_in UNUSED, 1966 tr_variant * args_out, 1854 1967 struct tr_rpc_idle_data * idle_data UNUSED) 1855 1968 { 1856 int running = 0; 1857 int total = 0; 1858 tr_variant * d; 1859 tr_session_stats currentStats = { 0.0f, 0, 0, 0, 0, 0 }; 1860 tr_session_stats cumulativeStats = { 0.0f, 0, 0, 0, 0, 0 }; 1861 tr_torrent * tor = NULL; 1862 1863 assert (idle_data == NULL); 1864 1865 while ((tor = tr_torrentNext (session, tor))) { 1866 ++total; 1867 if (tor->isRunning) 1868 ++running; 1869 } 1870 1871 tr_sessionGetStats (session, ¤tStats); 1872 tr_sessionGetCumulativeStats (session, &cumulativeStats); 1873 1874 tr_variantDictAddInt (args_out, TR_KEY_activeTorrentCount, running); 1875 tr_variantDictAddReal (args_out, TR_KEY_downloadSpeed, tr_sessionGetPieceSpeed_Bps (session, TR_DOWN)); 1876 tr_variantDictAddInt (args_out, TR_KEY_pausedTorrentCount, total - running); 1877 tr_variantDictAddInt (args_out, TR_KEY_torrentCount, total); 1878 tr_variantDictAddReal (args_out, TR_KEY_uploadSpeed, tr_sessionGetPieceSpeed_Bps (session, TR_UP)); 1879 1880 d = tr_variantDictAddDict (args_out, TR_KEY_cumulative_stats, 5); 1881 tr_variantDictAddInt (d, TR_KEY_downloadedBytes, cumulativeStats.downloadedBytes); 1882 tr_variantDictAddInt (d, TR_KEY_filesAdded, cumulativeStats.filesAdded); 1883 tr_variantDictAddInt (d, TR_KEY_secondsActive, cumulativeStats.secondsActive); 1884 tr_variantDictAddInt (d, TR_KEY_sessionCount, cumulativeStats.sessionCount); 1885 tr_variantDictAddInt (d, TR_KEY_uploadedBytes, cumulativeStats.uploadedBytes); 1886 1887 d = tr_variantDictAddDict (args_out, TR_KEY_current_stats, 5); 1888 tr_variantDictAddInt (d, TR_KEY_downloadedBytes, currentStats.downloadedBytes); 1889 tr_variantDictAddInt (d, TR_KEY_filesAdded, currentStats.filesAdded); 1890 tr_variantDictAddInt (d, TR_KEY_secondsActive, currentStats.secondsActive); 1891 tr_variantDictAddInt (d, TR_KEY_sessionCount, currentStats.sessionCount); 1892 tr_variantDictAddInt (d, TR_KEY_uploadedBytes, currentStats.uploadedBytes); 1893 1894 return NULL; 1969 int running = 0; 1970 int total = 0; 1971 tr_variant * d; 1972 tr_session_stats currentStats = { 0.0f, 0, 0, 0, 0, 0 }; 1973 tr_session_stats cumulativeStats = { 0.0f, 0, 0, 0, 0, 0 }; 1974 tr_torrent * tor = NULL; 1975 1976 assert (idle_data == NULL); 1977 1978 while ((tor = tr_torrentNext (session, tor))) 1979 { 1980 ++total; 1981 1982 if (tor->isRunning) 1983 ++running; 1984 } 1985 1986 tr_sessionGetStats (session, ¤tStats); 1987 tr_sessionGetCumulativeStats (session, &cumulativeStats); 1988 1989 tr_variantDictAddInt (args_out, TR_KEY_activeTorrentCount, running); 1990 tr_variantDictAddReal (args_out, TR_KEY_downloadSpeed, tr_sessionGetPieceSpeed_Bps (session, TR_DOWN)); 1991 tr_variantDictAddInt (args_out, TR_KEY_pausedTorrentCount, total - running); 1992 tr_variantDictAddInt (args_out, TR_KEY_torrentCount, total); 1993 tr_variantDictAddReal (args_out, TR_KEY_uploadSpeed, tr_sessionGetPieceSpeed_Bps (session, TR_UP)); 1994 1995 d = tr_variantDictAddDict (args_out, TR_KEY_cumulative_stats, 5); 1996 tr_variantDictAddInt (d, TR_KEY_downloadedBytes, cumulativeStats.downloadedBytes); 1997 tr_variantDictAddInt (d, TR_KEY_filesAdded, cumulativeStats.filesAdded); 1998 tr_variantDictAddInt (d, TR_KEY_secondsActive, cumulativeStats.secondsActive); 1999 tr_variantDictAddInt (d, TR_KEY_sessionCount, cumulativeStats.sessionCount); 2000 tr_variantDictAddInt (d, TR_KEY_uploadedBytes, cumulativeStats.uploadedBytes); 2001 2002 d = tr_variantDictAddDict (args_out, TR_KEY_current_stats, 5); 2003 tr_variantDictAddInt (d, TR_KEY_downloadedBytes, currentStats.downloadedBytes); 2004 tr_variantDictAddInt (d, TR_KEY_filesAdded, currentStats.filesAdded); 2005 tr_variantDictAddInt (d, TR_KEY_secondsActive, currentStats.secondsActive); 2006 tr_variantDictAddInt (d, TR_KEY_sessionCount, currentStats.sessionCount); 2007 tr_variantDictAddInt (d, TR_KEY_uploadedBytes, currentStats.uploadedBytes); 2008 2009 return NULL; 1895 2010 } 1896 2011 … … 1901 2016 struct tr_rpc_idle_data * idle_data UNUSED) 1902 2017 { 1903 const char * str; 1904 tr_variant * d = args_out; 1905 1906 assert (idle_data == NULL); 1907 tr_variantDictAddInt (d, TR_KEY_alt_speed_up, tr_sessionGetAltSpeed_KBps (s,TR_UP)); 1908 tr_variantDictAddInt (d, TR_KEY_alt_speed_down, tr_sessionGetAltSpeed_KBps (s,TR_DOWN)); 1909 tr_variantDictAddBool (d, TR_KEY_alt_speed_enabled, tr_sessionUsesAltSpeed (s)); 1910 tr_variantDictAddInt (d, TR_KEY_alt_speed_time_begin, tr_sessionGetAltSpeedBegin (s)); 1911 tr_variantDictAddInt (d, TR_KEY_alt_speed_time_end,tr_sessionGetAltSpeedEnd (s)); 1912 tr_variantDictAddInt (d, TR_KEY_alt_speed_time_day,tr_sessionGetAltSpeedDay (s)); 1913 tr_variantDictAddBool (d, TR_KEY_alt_speed_time_enabled, tr_sessionUsesAltSpeedTime (s)); 1914 tr_variantDictAddBool (d, TR_KEY_blocklist_enabled, tr_blocklistIsEnabled (s)); 1915 tr_variantDictAddStr (d, TR_KEY_blocklist_url, tr_blocklistGetURL (s)); 1916 tr_variantDictAddInt (d, TR_KEY_cache_size_mb, tr_sessionGetCacheLimit_MB (s)); 1917 tr_variantDictAddInt (d, TR_KEY_blocklist_size, tr_blocklistGetRuleCount (s)); 1918 tr_variantDictAddStr (d, TR_KEY_config_dir, tr_sessionGetConfigDir (s)); 1919 tr_variantDictAddStr (d, TR_KEY_download_dir, tr_sessionGetDownloadDir (s)); 1920 tr_variantDictAddInt (d, TR_KEY_download_dir_free_space, tr_device_info_get_free_space (s->downloadDir)); 1921 tr_variantDictAddBool (d, TR_KEY_download_queue_enabled, tr_sessionGetQueueEnabled (s, TR_DOWN)); 1922 tr_variantDictAddInt (d, TR_KEY_download_queue_size, tr_sessionGetQueueSize (s, TR_DOWN)); 1923 tr_variantDictAddInt (d, TR_KEY_peer_limit_global, tr_sessionGetPeerLimit (s)); 1924 tr_variantDictAddInt (d, TR_KEY_peer_limit_per_torrent, tr_sessionGetPeerLimitPerTorrent (s)); 1925 tr_variantDictAddStr (d, TR_KEY_incomplete_dir, tr_sessionGetIncompleteDir (s)); 1926 tr_variantDictAddBool (d, TR_KEY_incomplete_dir_enabled, tr_sessionIsIncompleteDirEnabled (s)); 1927 tr_variantDictAddBool (d, TR_KEY_pex_enabled, tr_sessionIsPexEnabled (s)); 1928 tr_variantDictAddBool (d, TR_KEY_utp_enabled, tr_sessionIsUTPEnabled (s)); 1929 tr_variantDictAddBool (d, TR_KEY_dht_enabled, tr_sessionIsDHTEnabled (s)); 1930 tr_variantDictAddBool (d, TR_KEY_lpd_enabled, tr_sessionIsLPDEnabled (s)); 1931 tr_variantDictAddInt (d, TR_KEY_peer_port, tr_sessionGetPeerPort (s)); 1932 tr_variantDictAddBool (d, TR_KEY_peer_port_random_on_start, tr_sessionGetPeerPortRandomOnStart (s)); 1933 tr_variantDictAddBool (d, TR_KEY_port_forwarding_enabled, tr_sessionIsPortForwardingEnabled (s)); 1934 tr_variantDictAddBool (d, TR_KEY_rename_partial_files, tr_sessionIsIncompleteFileNamingEnabled (s)); 1935 tr_variantDictAddInt (d, TR_KEY_rpc_version, RPC_VERSION); 1936 tr_variantDictAddInt (d, TR_KEY_rpc_version_minimum, RPC_VERSION_MIN); 1937 tr_variantDictAddReal (d, TR_KEY_seedRatioLimit, tr_sessionGetRatioLimit (s)); 1938 tr_variantDictAddBool (d, TR_KEY_seedRatioLimited, tr_sessionIsRatioLimited (s)); 1939 tr_variantDictAddInt (d, TR_KEY_idle_seeding_limit, tr_sessionGetIdleLimit (s)); 1940 tr_variantDictAddBool (d, TR_KEY_idle_seeding_limit_enabled, tr_sessionIsIdleLimited (s)); 1941 tr_variantDictAddBool (d, TR_KEY_seed_queue_enabled, tr_sessionGetQueueEnabled (s, TR_UP)); 1942 tr_variantDictAddInt (d, TR_KEY_seed_queue_size, tr_sessionGetQueueSize (s, TR_UP)); 1943 tr_variantDictAddBool (d, TR_KEY_start_added_torrents, !tr_sessionGetPaused (s)); 1944 tr_variantDictAddBool (d, TR_KEY_trash_original_torrent_files, tr_sessionGetDeleteSource (s)); 1945 tr_variantDictAddInt (d, TR_KEY_speed_limit_up, tr_sessionGetSpeedLimit_KBps (s, TR_UP)); 1946 tr_variantDictAddBool (d, TR_KEY_speed_limit_up_enabled, tr_sessionIsSpeedLimited (s, TR_UP)); 1947 tr_variantDictAddInt (d, TR_KEY_speed_limit_down, tr_sessionGetSpeedLimit_KBps (s, TR_DOWN)); 1948 tr_variantDictAddBool (d, TR_KEY_speed_limit_down_enabled, tr_sessionIsSpeedLimited (s, TR_DOWN)); 1949 tr_variantDictAddStr (d, TR_KEY_script_torrent_done_filename, tr_sessionGetTorrentDoneScript (s)); 1950 tr_variantDictAddBool (d, TR_KEY_script_torrent_done_enabled, tr_sessionIsTorrentDoneScriptEnabled (s)); 1951 tr_variantDictAddBool (d, TR_KEY_queue_stalled_enabled, tr_sessionGetQueueStalledEnabled (s)); 1952 tr_variantDictAddInt (d, TR_KEY_queue_stalled_minutes, tr_sessionGetQueueStalledMinutes (s)); 1953 tr_formatter_get_units (tr_variantDictAddDict (d, TR_KEY_units, 0)); 1954 tr_variantDictAddStr (d, TR_KEY_version, LONG_VERSION_STRING); 1955 switch (tr_sessionGetEncryption (s)) { 1956 case TR_CLEAR_PREFERRED: str = "tolerated"; break; 1957 case TR_ENCRYPTION_REQUIRED: str = "required"; break; 1958 default: str = "preferred"; break; 1959 } 1960 tr_variantDictAddStr (d, TR_KEY_encryption, str); 1961 1962 return NULL; 2018 const char * str; 2019 tr_variant * d = args_out; 2020 2021 assert (idle_data == NULL); 2022 tr_variantDictAddInt (d, TR_KEY_alt_speed_up, tr_sessionGetAltSpeed_KBps (s,TR_UP)); 2023 tr_variantDictAddInt (d, TR_KEY_alt_speed_down, tr_sessionGetAltSpeed_KBps (s,TR_DOWN)); 2024 tr_variantDictAddBool (d, TR_KEY_alt_speed_enabled, tr_sessionUsesAltSpeed (s)); 2025 tr_variantDictAddInt (d, TR_KEY_alt_speed_time_begin, tr_sessionGetAltSpeedBegin (s)); 2026 tr_variantDictAddInt (d, TR_KEY_alt_speed_time_end,tr_sessionGetAltSpeedEnd (s)); 2027 tr_variantDictAddInt (d, TR_KEY_alt_speed_time_day,tr_sessionGetAltSpeedDay (s)); 2028 tr_variantDictAddBool (d, TR_KEY_alt_speed_time_enabled, tr_sessionUsesAltSpeedTime (s)); 2029 tr_variantDictAddBool (d, TR_KEY_blocklist_enabled, tr_blocklistIsEnabled (s)); 2030 tr_variantDictAddStr (d, TR_KEY_blocklist_url, tr_blocklistGetURL (s)); 2031 tr_variantDictAddInt (d, TR_KEY_cache_size_mb, tr_sessionGetCacheLimit_MB (s)); 2032 tr_variantDictAddInt (d, TR_KEY_blocklist_size, tr_blocklistGetRuleCount (s)); 2033 tr_variantDictAddStr (d, TR_KEY_config_dir, tr_sessionGetConfigDir (s)); 2034 tr_variantDictAddStr (d, TR_KEY_download_dir, tr_sessionGetDownloadDir (s)); 2035 tr_variantDictAddInt (d, TR_KEY_download_dir_free_space, tr_device_info_get_free_space (s->downloadDir)); 2036 tr_variantDictAddBool (d, TR_KEY_download_queue_enabled, tr_sessionGetQueueEnabled (s, TR_DOWN)); 2037 tr_variantDictAddInt (d, TR_KEY_download_queue_size, tr_sessionGetQueueSize (s, TR_DOWN)); 2038 tr_variantDictAddInt (d, TR_KEY_peer_limit_global, tr_sessionGetPeerLimit (s)); 2039 tr_variantDictAddInt (d, TR_KEY_peer_limit_per_torrent, tr_sessionGetPeerLimitPerTorrent (s)); 2040 tr_variantDictAddStr (d, TR_KEY_incomplete_dir, tr_sessionGetIncompleteDir (s)); 2041 tr_variantDictAddBool (d, TR_KEY_incomplete_dir_enabled, tr_sessionIsIncompleteDirEnabled (s)); 2042 tr_variantDictAddBool (d, TR_KEY_pex_enabled, tr_sessionIsPexEnabled (s)); 2043 tr_variantDictAddBool (d, TR_KEY_utp_enabled, tr_sessionIsUTPEnabled (s)); 2044 tr_variantDictAddBool (d, TR_KEY_dht_enabled, tr_sessionIsDHTEnabled (s)); 2045 tr_variantDictAddBool (d, TR_KEY_lpd_enabled, tr_sessionIsLPDEnabled (s)); 2046 tr_variantDictAddInt (d, TR_KEY_peer_port, tr_sessionGetPeerPort (s)); 2047 tr_variantDictAddBool (d, TR_KEY_peer_port_random_on_start, tr_sessionGetPeerPortRandomOnStart (s)); 2048 tr_variantDictAddBool (d, TR_KEY_port_forwarding_enabled, tr_sessionIsPortForwardingEnabled (s)); 2049 tr_variantDictAddBool (d, TR_KEY_rename_partial_files, tr_sessionIsIncompleteFileNamingEnabled (s)); 2050 tr_variantDictAddInt (d, TR_KEY_rpc_version, RPC_VERSION); 2051 tr_variantDictAddInt (d, TR_KEY_rpc_version_minimum, RPC_VERSION_MIN); 2052 tr_variantDictAddReal (d, TR_KEY_seedRatioLimit, tr_sessionGetRatioLimit (s)); 2053 tr_variantDictAddBool (d, TR_KEY_seedRatioLimited, tr_sessionIsRatioLimited (s)); 2054 tr_variantDictAddInt (d, TR_KEY_idle_seeding_limit, tr_sessionGetIdleLimit (s)); 2055 tr_variantDictAddBool (d, TR_KEY_idle_seeding_limit_enabled, tr_sessionIsIdleLimited (s)); 2056 tr_variantDictAddBool (d, TR_KEY_seed_queue_enabled, tr_sessionGetQueueEnabled (s, TR_UP)); 2057 tr_variantDictAddInt (d, TR_KEY_seed_queue_size, tr_sessionGetQueueSize (s, TR_UP)); 2058 tr_variantDictAddBool (d, TR_KEY_start_added_torrents, !tr_sessionGetPaused (s)); 2059 tr_variantDictAddBool (d, TR_KEY_trash_original_torrent_files, tr_sessionGetDeleteSource (s)); 2060 tr_variantDictAddInt (d, TR_KEY_speed_limit_up, tr_sessionGetSpeedLimit_KBps (s, TR_UP)); 2061 tr_variantDictAddBool (d, TR_KEY_speed_limit_up_enabled, tr_sessionIsSpeedLimited (s, TR_UP)); 2062 tr_variantDictAddInt (d, TR_KEY_speed_limit_down, tr_sessionGetSpeedLimit_KBps (s, TR_DOWN)); 2063 tr_variantDictAddBool (d, TR_KEY_speed_limit_down_enabled, tr_sessionIsSpeedLimited (s, TR_DOWN)); 2064 tr_variantDictAddStr (d, TR_KEY_script_torrent_done_filename, tr_sessionGetTorrentDoneScript (s)); 2065 tr_variantDictAddBool (d, TR_KEY_script_torrent_done_enabled, tr_sessionIsTorrentDoneScriptEnabled (s)); 2066 tr_variantDictAddBool (d, TR_KEY_queue_stalled_enabled, tr_sessionGetQueueStalledEnabled (s)); 2067 tr_variantDictAddInt (d, TR_KEY_queue_stalled_minutes, tr_sessionGetQueueStalledMinutes (s)); 2068 tr_formatter_get_units (tr_variantDictAddDict (d, TR_KEY_units, 0)); 2069 tr_variantDictAddStr (d, TR_KEY_version, LONG_VERSION_STRING); 2070 switch (tr_sessionGetEncryption (s)) 2071 { 2072 case TR_CLEAR_PREFERRED: str = "tolerated"; break; 2073 case TR_ENCRYPTION_REQUIRED: str = "required"; break; 2074 default: str = "preferred"; break; 2075 } 2076 tr_variantDictAddStr (d, TR_KEY_encryption, str); 2077 2078 return NULL; 1963 2079 } 1964 2080 … … 1996 2112 static const char* 1997 2113 sessionClose (tr_session * session, 1998 tr_variant 1999 tr_variant 2114 tr_variant * args_in UNUSED, 2115 tr_variant * args_out UNUSED, 2000 2116 struct tr_rpc_idle_data * idle_data UNUSED) 2001 2117 { 2002 2003 2118 notify (session, TR_RPC_SESSION_CLOSE, NULL); 2119 return NULL; 2004 2120 } 2005 2121 … … 2012 2128 static struct method 2013 2129 { 2014 2015 2016 2130 const char * name; 2131 bool immediate; 2132 handler func; 2017 2133 } 2018 2134 methods[] = 2019 2135 { 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2136 { "port-test", false, portTest }, 2137 { "blocklist-update", false, blocklistUpdate }, 2138 { "free-space", true, freeSpace }, 2139 { "session-close", true, sessionClose }, 2140 { "session-get", true, sessionGet }, 2141 { "session-set", true, sessionSet }, 2142 { "session-stats", true, sessionStats }, 2143 { "torrent-add", false, torrentAdd }, 2144 { "torrent-get", true, torrentGet }, 2145 { "torrent-remove", true, torrentRemove }, 2146 { "torrent-rename-path", false, torrentRenamePath }, 2147 { "torrent-set", true, torrentSet }, 2148 { "torrent-set-location", true, torrentSetLocation }, 2149 { "torrent-start", true, torrentStart }, 2150 { "torrent-start-now", true, torrentStartNow }, 2151 { "torrent-stop", true, torrentStop }, 2152 { "torrent-verify", true, torrentVerify }, 2153 { "torrent-reannounce", true, torrentReannounce }, 2154 { "queue-move-top", true, queueMoveTop }, 2155 { "queue-move-up", true, queueMoveUp }, 2156 { "queue-move-down", true, queueMoveDown }, 2157 { "queue-move-bottom", true, queueMoveBottom } 2042 2158 }; 2043 2159 … … 2055 2171 void * callback_user_data) 2056 2172 { 2057 int i; 2058 const char * str; 2059 tr_variant * args_in = tr_variantDictFind (request, TR_KEY_arguments); 2060 const char * result = NULL; 2061 2062 if (callback == NULL) 2063 callback = noop_response_callback; 2064 2065 /* parse the request */ 2066 if (!tr_variantDictFindStr (request, TR_KEY_method, &str, NULL)) 2067 result = "no method name"; 2068 else { 2069 const int n = TR_N_ELEMENTS (methods); 2070 for (i = 0; i < n; ++i) 2071 if (!strcmp (str, methods[i].name)) 2072 break; 2073 if (i ==n) 2074 result = "method name not recognized"; 2075 } 2076 2077 /* if we couldn't figure out which method to use, return an error */ 2078 if (result != NULL) 2079 { 2080 int64_t tag; 2081 tr_variant response; 2082 struct evbuffer * buf; 2083 2084 tr_variantInitDict (&response, 3); 2085 tr_variantDictAddDict (&response, TR_KEY_arguments, 0); 2086 tr_variantDictAddStr (&response, TR_KEY_result, result); 2087 if (tr_variantDictFindInt (request, TR_KEY_tag, &tag)) 2088 tr_variantDictAddInt (&response, TR_KEY_tag, tag); 2089 2090 buf = tr_variantToBuf (&response, TR_VARIANT_FMT_JSON_LEAN); 2173 int i; 2174 const char * str; 2175 tr_variant * args_in = tr_variantDictFind (request, TR_KEY_arguments); 2176 const char * result = NULL; 2177 2178 if (callback == NULL) 2179 callback = noop_response_callback; 2180 2181 /* parse the request */ 2182 if (!tr_variantDictFindStr (request, TR_KEY_method, &str, NULL)) 2183 { 2184 result = "no method name"; 2185 } 2186 else 2187 { 2188 const int n = TR_N_ELEMENTS (methods); 2189 2190 for (i=0; i<n; ++i) 2191 if (!strcmp (str, methods[i].name)) 2192 break; 2193 2194 if (i ==n) 2195 result = "method name not recognized"; 2196 } 2197 2198 /* if we couldn't figure out which method to use, return an error */ 2199 if (result != NULL) 2200 { 2201 int64_t tag; 2202 tr_variant response; 2203 struct evbuffer * buf; 2204 2205 tr_variantInitDict (&response, 3); 2206 tr_variantDictAddDict (&response, TR_KEY_arguments, 0); 2207 tr_variantDictAddStr (&response, TR_KEY_result, result); 2208 if (tr_variantDictFindInt (request, TR_KEY_tag, &tag)) 2209 tr_variantDictAddInt (&response, TR_KEY_tag, tag); 2210 2211 buf = tr_variantToBuf (&response, TR_VARIANT_FMT_JSON_LEAN); 2091 2212 (*callback)(session, buf, callback_user_data); 2092 2093 2094 2095 } 2096 2097 { 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 } 2118 2119 { 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2213 evbuffer_free (buf); 2214 2215 tr_variantFree (&response); 2216 } 2217 else if (methods[i].immediate) 2218 { 2219 int64_t tag; 2220 tr_variant response; 2221 tr_variant * args_out; 2222 struct evbuffer * buf; 2223 2224 tr_variantInitDict (&response, 3); 2225 args_out = tr_variantDictAddDict (&response, TR_KEY_arguments, 0); 2226 result = (*methods[i].func)(session, args_in, args_out, NULL); 2227 if (result == NULL) 2228 result = "success"; 2229 tr_variantDictAddStr (&response, TR_KEY_result, result); 2230 if (tr_variantDictFindInt (request, TR_KEY_tag, &tag)) 2231 tr_variantDictAddInt (&response, TR_KEY_tag, tag); 2232 2233 buf = tr_variantToBuf (&response, TR_VARIANT_FMT_JSON_LEAN); 2234 (*callback)(session, buf, callback_user_data); 2235 evbuffer_free (buf); 2236 2237 tr_variantFree (&response); 2238 } 2239 else 2240 { 2241 int64_t tag; 2242 struct tr_rpc_idle_data * data = tr_new0 (struct tr_rpc_idle_data, 1); 2243 data->session = session; 2244 data->response = tr_new0 (tr_variant, 1); 2245 tr_variantInitDict (data->response, 3); 2246 if (tr_variantDictFindInt (request, TR_KEY_tag, &tag)) 2247 tr_variantDictAddInt (data->response, TR_KEY_tag, tag); 2248 data->args_out = tr_variantDictAddDict (data->response, TR_KEY_arguments, 0); 2249 data->callback = callback; 2250 data->callback_user_data = callback_user_data; 2251 (*methods[i].func)(session, args_in, data->args_out, data); 2131 2252 } 2132 2253 } … … 2139 2260 void * callback_user_data) 2140 2261 { 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2262 tr_variant top; 2263 int have_content; 2264 2265 if (request_len < 0) 2266 request_len = strlen (request_json); 2267 2268 have_content = !tr_variantFromJson (&top, request_json, request_len); 2269 request_exec (session, have_content ? &top : NULL, callback, callback_user_data); 2270 2271 if (have_content) 2272 tr_variantFree (&top); 2152 2273 } 2153 2274 … … 2167 2288 2168 2289 { 2169 int valueCount; 2170 int * values = tr_parseNumberRange (str, len, &valueCount); 2171 2172 if (valueCount == 0) 2173 tr_variantInitStr (setme, str, len); 2174 else if (valueCount == 1) 2175 tr_variantInitInt (setme, values[0]); 2176 else { 2177 int i; 2178 tr_variantInitList (setme, valueCount); 2179 for (i=0; i<valueCount; ++i) 2180 tr_variantListAddInt (setme, values[i]); 2181 } 2182 2183 tr_free (values); 2290 int valueCount; 2291 int * values = tr_parseNumberRange (str, len, &valueCount); 2292 2293 if (valueCount == 0) 2294 { 2295 tr_variantInitStr (setme, str, len); 2296 } 2297 else if (valueCount == 1) 2298 { 2299 tr_variantInitInt (setme, values[0]); 2300 } 2301 else 2302 { 2303 int i; 2304 2305 tr_variantInitList (setme, valueCount); 2306 2307 for (i=0; i<valueCount; ++i) 2308 tr_variantListAddInt (setme, values[i]); 2309 } 2310 2311 tr_free (values); 2184 2312 } 2185 2313 … … 2191 2319 void * callback_user_data) 2192 2320 { 2193 tr_variant top, * args; 2194 char * request = tr_strndup (request_uri, request_len); 2195 const char * pch; 2196 2197 tr_variantInitDict (&top, 3); 2198 args = tr_variantDictAddDict (&top, TR_KEY_arguments, 0); 2199 2200 pch = strchr (request, '?'); 2201 if (!pch) pch = request; 2202 while (pch) 2203 { 2204 const char * delim = strchr (pch, '='); 2205 const char * next = strchr (pch, '&'); 2206 if (delim) 2207 { 2208 char * key = tr_strndup (pch, delim - pch); 2209 int isArg = strcmp (key, "method") && strcmp (key, "tag"); 2210 tr_variant * parent = isArg ? args : ⊤ 2211 tr_rpc_parse_list_str (tr_variantDictAdd (parent, tr_quark_new (key, delim-pch)), 2212 delim + 1, 2213 next ? (size_t)( 2214 next - 2215 (delim + 1)) : strlen (delim + 1)); 2216 tr_free (key); 2217 } 2218 pch = next ? next + 1 : NULL; 2219 } 2220 2221 request_exec (session, &top, callback, callback_user_data); 2222 2223 /* cleanup */ 2224 tr_variantFree (&top); 2225 tr_free (request); 2226 } 2321 const char * pch; 2322 tr_variant top; 2323 tr_variant * args; 2324 char * request = tr_strndup (request_uri, request_len); 2325 2326 tr_variantInitDict (&top, 3); 2327 args = tr_variantDictAddDict (&top, TR_KEY_arguments, 0); 2328 2329 pch = strchr (request, '?'); 2330 if (!pch) pch = request; 2331 while (pch) 2332 { 2333 const char * delim = strchr (pch, '='); 2334 const char * next = strchr (pch, '&'); 2335 if (delim) 2336 { 2337 char * key = tr_strndup (pch, delim - pch); 2338 int isArg = strcmp (key, "method") && strcmp (key, "tag"); 2339 tr_variant * parent = isArg ? args : ⊤ 2340 2341 tr_rpc_parse_list_str (tr_variantDictAdd (parent, tr_quark_new (key, delim-pch)), 2342 delim + 1, 2343 next ? (size_t)(next - (delim + 1)) : strlen (delim + 1)); 2344 tr_free (key); 2345 } 2346 2347 pch = next ? next + 1 : NULL; 2348 } 2349 2350 request_exec (session, &top, callback, callback_user_data); 2351 2352 /* cleanup */ 2353 tr_variantFree (&top); 2354 tr_free (request); 2355 } -
trunk/libtransmission/torrent.c
r14078 r14079 75 75 tr_torrentName (const tr_torrent * tor) 76 76 { 77 77 return tor ? tor->info.name : ""; 78 78 } 79 79 … … 81 81 tr_torrentId (const tr_torrent * tor) 82 82 { 83 83 return tor ? tor->uniqueId : -1; 84 84 } 85 85 … … 87 87 tr_torrentFindFromId (tr_session * session, int id) 88 88 { 89 90 91 92 93 94 95 89 tr_torrent * tor = NULL; 90 91 while ((tor = tr_torrentNext (session, tor))) 92 if (tor->uniqueId == id) 93 return tor; 94 95 return NULL; 96 96 } 97 97 … … 99 99 tr_torrentFindFromHashString (tr_session * session, const char * str) 100 100 { 101 102 103 104 105 106 107 101 tr_torrent * tor = NULL; 102 103 while ((tor = tr_torrentNext (session, tor))) 104 if (!evutil_ascii_strcasecmp (str, tor->info.hashString)) 105 return tor; 106 107 return NULL; 108 108 } 109 109 … … 111 111 tr_torrentFindFromHash (tr_session * session, const uint8_t * torrentHash) 112 112 { 113 114 115 116 117 118 119 120 113 tr_torrent * tor = NULL; 114 115 while ((tor = tr_torrentNext (session, tor))) 116 if (*tor->info.hash == *torrentHash) 117 if (!memcmp (tor->info.hash, torrentHash, SHA_DIGEST_LENGTH)) 118 return tor; 119 120 return NULL; 121 121 } 122 122 … … 124 124 tr_torrentFindFromMagnetLink (tr_session * session, const char * magnet) 125 125 { 126 127 128 129 130 { 131 132 133 } 134 135 126 tr_magnet_info * info; 127 tr_torrent * tor = NULL; 128 129 if ((info = tr_magnetParse (magnet))) 130 { 131 tor = tr_torrentFindFromHash (session, info->hash); 132 tr_magnetFree (info); 133 } 134 135 return tor; 136 136 } 137 137 … … 140 140 const uint8_t * obfuscatedTorrentHash) 141 141 { 142 tr_torrent * tor = NULL; 143 144 while ((tor = tr_torrentNext (session, tor))) 145 if (!memcmp (tor->obfuscatedHash, obfuscatedTorrentHash, 146 SHA_DIGEST_LENGTH)) 147 return tor; 148 149 return NULL; 142 tr_torrent * tor = NULL; 143 144 while ((tor = tr_torrentNext (session, tor))) 145 if (!memcmp (tor->obfuscatedHash, obfuscatedTorrentHash, SHA_DIGEST_LENGTH)) 146 return tor; 147 148 return NULL; 150 149 } 151 150 … … 224 223 tr_torrentSetSpeedLimit_Bps (tr_torrent * tor, tr_direction dir, unsigned int Bps) 225 224 { 226 227 228 229 230 225 assert (tr_isTorrent (tor)); 226 assert (tr_isDirection (dir)); 227 228 if (tr_bandwidthSetDesiredSpeed_Bps (&tor->bandwidth, dir, Bps)) 229 tr_torrentSetDirty (tor); 231 230 } 232 231 void 233 232 tr_torrentSetSpeedLimit_KBps (tr_torrent * tor, tr_direction dir, unsigned int KBps) 234 233 { 235 234 tr_torrentSetSpeedLimit_Bps (tor, dir, toSpeedBytes (KBps)); 236 235 } 237 236 … … 239 238 tr_torrentGetSpeedLimit_Bps (const tr_torrent * tor, tr_direction dir) 240 239 { 241 242 243 244 240 assert (tr_isTorrent (tor)); 241 assert (tr_isDirection (dir)); 242 243 return tr_bandwidthGetDesiredSpeed_Bps (&tor->bandwidth, dir); 245 244 } 246 245 unsigned int … … 398 397 tr_torrentIsSeedRatioDone (const tr_torrent * tor) 399 398 { 400 401 399 uint64_t bytesLeft; 400 return tr_torrentGetSeedRatioBytes (tor, &bytesLeft, NULL) && !bytesLeft; 402 401 } 403 402 … … 409 408 tr_torrentSetIdleMode (tr_torrent * tor, tr_idlelimit mode) 410 409 { 411 412 413 414 415 { 416 417 418 410 assert (tr_isTorrent (tor)); 411 assert (mode==TR_IDLELIMIT_GLOBAL || mode==TR_IDLELIMIT_SINGLE || mode==TR_IDLELIMIT_UNLIMITED); 412 413 if (mode != tor->idleLimitMode) 414 { 415 tor->idleLimitMode = mode; 416 417 tr_torrentSetDirty (tor); 419 418 } 420 419 } … … 423 422 tr_torrentGetIdleMode (const tr_torrent * tor) 424 423 { 425 426 427 424 assert (tr_isTorrent (tor)); 425 426 return tor->idleLimitMode; 428 427 } 429 428 … … 431 430 tr_torrentSetIdleLimit (tr_torrent * tor, uint16_t idleMinutes) 432 431 { 433 434 435 436 { 437 438 439 432 assert (tr_isTorrent (tor)); 433 434 if (idleMinutes > 0) 435 { 436 tor->idleLimitMinutes = idleMinutes; 437 438 tr_torrentSetDirty (tor); 440 439 } 441 440 } … … 444 443 tr_torrentGetIdleLimit (const tr_torrent * tor) 445 444 { 446 447 448 445 assert (tr_isTorrent (tor)); 446 447 return tor->idleLimitMinutes; 449 448 } 450 449 … … 452 451 tr_torrentGetSeedIdle (const tr_torrent * tor, uint16_t * idleMinutes) 453 452 { 454 455 456 457 { 458 459 460 if (idleMinutes)461 462 463 464 465 466 467 468 469 470 471 472 473 } 474 475 453 bool isLimited; 454 455 switch (tr_torrentGetIdleMode (tor)) 456 { 457 case TR_IDLELIMIT_SINGLE: 458 isLimited = true; 459 if (idleMinutes != NULL) 460 *idleMinutes = tr_torrentGetIdleLimit (tor); 461 break; 462 463 case TR_IDLELIMIT_GLOBAL: 464 isLimited = tr_sessionIsIdleLimited (tor->session); 465 if (isLimited && idleMinutes) 466 *idleMinutes = tr_sessionGetIdleLimit (tor->session); 467 break; 468 469 default: /* TR_IDLELIMIT_UNLIMITED */ 470 isLimited = false; 471 break; 472 } 473 474 return isLimited; 476 475 } 477 476 … … 479 478 tr_torrentIsSeedIdleLimitDone (tr_torrent * tor) 480 479 { 481 482 483 480 uint16_t idleMinutes; 481 return tr_torrentGetSeedIdle (tor, &idleMinutes) 482 && difftime (tr_time (), MAX (tor->startDate, tor->activityDate)) >= idleMinutes * 60u; 484 483 } 485 484 … … 491 490 tr_torrentCheckSeedLimit (tr_torrent * tor) 492 491 { 493 494 495 496 497 498 499 500 { 501 502 503 504 505 506 507 508 } 509 510 511 { 512 513 514 515 516 517 518 519 492 assert (tr_isTorrent (tor)); 493 494 if (!tor->isRunning || tor->isStopping || !tr_torrentIsSeed (tor)) 495 return; 496 497 /* if we're seeding and reach our seed ratio limit, stop the torrent */ 498 if (tr_torrentIsSeedRatioDone (tor)) 499 { 500 tr_logAddTorInfo (tor, "%s", "Seed ratio reached; pausing torrent"); 501 502 tor->isStopping = true; 503 504 /* maybe notify the client */ 505 if (tor->ratio_limit_hit_func != NULL) 506 tor->ratio_limit_hit_func (tor, tor->ratio_limit_hit_func_user_data); 507 } 508 /* if we're seeding and reach our inactiviy limit, stop the torrent */ 509 else if (tr_torrentIsSeedIdleLimitDone (tor)) 510 { 511 tr_logAddTorInfo (tor, "%s", "Seeding idle limit reached; pausing torrent"); 512 513 tor->isStopping = true; 514 tor->finishedSeedingByIdle = true; 515 516 /* maybe notify the client */ 517 if (tor->idle_limit_hit_func != NULL) 518 tor->idle_limit_hit_func (tor, tor->idle_limit_hit_func_user_data); 520 519 } 521 520 } … … 528 527 tr_torrentSetLocalError (tr_torrent * tor, const char * fmt, ...) 529 528 { 530 531 532 533 534 535 536 537 538 539 540 541 542 543 529 va_list ap; 530 531 assert (tr_isTorrent (tor)); 532 533 va_start (ap, fmt); 534 tor->error = TR_STAT_LOCAL_ERROR; 535 tor->errorTracker[0] = '\0'; 536 evutil_vsnprintf (tor->errorString, sizeof (tor->errorString), fmt, ap); 537 va_end (ap); 538 539 tr_logAddTorErr (tor, "%s", tor->errorString); 540 541 if (tor->isRunning) 542 tor->isStopping = true; 544 543 } 545 544 … … 547 546 tr_torrentClearError (tr_torrent * tor) 548 547 { 549 550 551 548 tor->error = TR_STAT_OK; 549 tor->errorString[0] = '\0'; 550 tor->errorTracker[0] = '\0'; 552 551 } 553 552 … … 555 554 onTrackerResponse (tr_torrent * tor, const tr_tracker_event * event, void * unused UNUSED) 556 555 { 557 558 { 559 556 switch (event->messageType) 557 { 558 case TR_TRACKER_PEERS: 560 559 { 561 562 563 564 565 566 567 568 569 570 571 572 573 560 size_t i; 561 const int8_t seedProbability = event->seedProbability; 562 const bool allAreSeeds = seedProbability == 100; 563 564 if (allAreSeeds) 565 tr_logAddTorDbg (tor, "Got %zu seeds from tracker", event->pexCount); 566 else 567 tr_logAddTorDbg (tor, "Got %zu peers from tracker", event->pexCount); 568 569 for (i = 0; i < event->pexCount; ++i) 570 tr_peerMgrAddPex (tor, TR_PEER_FROM_TRACKER, &event->pex[i], seedProbability); 571 572 break; 574 573 } 575 574 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 575 case TR_TRACKER_WARNING: 576 tr_logAddTorErr (tor, _("Tracker warning: \"%s\""), event->text); 577 tor->error = TR_STAT_TRACKER_WARNING; 578 tr_strlcpy (tor->errorTracker, event->tracker, sizeof (tor->errorTracker)); 579 tr_strlcpy (tor->errorString, event->text, sizeof (tor->errorString)); 580 break; 581 582 case TR_TRACKER_ERROR: 583 tr_logAddTorErr (tor, _("Tracker error: \"%s\""), event->text); 584 tor->error = TR_STAT_TRACKER_ERROR; 585 tr_strlcpy (tor->errorTracker, event->tracker, sizeof (tor->errorTracker)); 586 tr_strlcpy (tor->errorString, event->text, sizeof (tor->errorString)); 587 break; 588 589 case TR_TRACKER_ERROR_CLEAR: 590 if (tor->error != TR_STAT_LOCAL_ERROR) 591 tr_torrentClearError (tor); 592 break; 594 593 } 595 594 } … … 604 603 getBytePiece (const tr_info * info, uint64_t byteOffset) 605 604 { 606 607 608 609 610 611 612 613 614 615 616 617 605 tr_piece_index_t piece; 606 607 assert (info); 608 assert (info->pieceSize != 0); 609 610 piece = byteOffset / info->pieceSize; 611 612 /* handle 0-byte files at the end of a torrent */ 613 if (byteOffset == info->totalSize) 614 piece = info->pieceCount - 1; 615 616 return piece; 618 617 } 619 618 … … 622 621 tr_file_index_t fileIndex) 623 622 { 624 625 626 627 628 629 630 631 632 633 634 623 tr_file * file; 624 uint64_t firstByte, lastByte; 625 626 assert (info); 627 assert (fileIndex < info->fileCount); 628 629 file = &info->files[fileIndex]; 630 firstByte = file->offset; 631 lastByte = firstByte + (file->length ? file->length - 1 : 0); 632 file->firstPiece = getBytePiece (info, firstByte); 633 file->lastPiece = getBytePiece (info, lastByte); 635 634 } 636 635 … … 639 638 const tr_file * file) 640 639 { 641 640 return (file->firstPiece <= piece) && (piece <= file->lastPiece); 642 641 } 643 642 … … 647 646 int fileHint) 648 647 { 649 tr_file_index_t i; 650 tr_priority_t priority = TR_PRI_LOW; 651 652 /* find the first file that has data in this piece */ 653 if (fileHint >= 0) { 654 i = fileHint; 655 while (i > 0 && pieceHasFile (piece, &tor->info.files[i - 1])) 656 --i; 657 } else { 658 for (i = 0; i < tor->info.fileCount; ++i) 659 if (pieceHasFile (piece, &tor->info.files[i])) 660 break; 661 } 662 663 /* the piece's priority is the max of the priorities 664 * of all the files in that piece */ 665 for (; i < tor->info.fileCount; ++i) 666 { 667 const tr_file * file = &tor->info.files[i]; 668 669 if (!pieceHasFile (piece, file)) 670 break; 671 672 priority = MAX (priority, file->priority); 673 674 /* when dealing with multimedia files, getting the first and 675 last pieces can sometimes allow you to preview it a bit 676 before it's fully downloaded... */ 677 if (file->priority >= TR_PRI_NORMAL) 678 if (file->firstPiece == piece || file->lastPiece == piece) 679 priority = TR_PRI_HIGH; 680 } 681 682 return priority; 648 tr_file_index_t i; 649 tr_priority_t priority = TR_PRI_LOW; 650 651 /* find the first file that has data in this piece */ 652 if (fileHint >= 0) 653 { 654 i = fileHint; 655 while (i > 0 && pieceHasFile (piece, &tor->info.files[i - 1])) 656 --i; 657 } 658 else 659 { 660 for (i=0; i<tor->info.fileCount; ++i) 661 if (pieceHasFile (piece, &tor->info.files[i])) 662 break; 663 } 664 665 /* the piece's priority is the max of the priorities 666 * of all the files in that piece */ 667 for (; i<tor->info.fileCount; ++i) 668 { 669 const tr_file * file = &tor->info.files[i]; 670 671 if (!pieceHasFile (piece, file)) 672 break; 673 674 priority = MAX (priority, file->priority); 675 676 /* when dealing with multimedia files, getting the first and 677 last pieces can sometimes allow you to preview it a bit 678 before it's fully downloaded... */ 679 if (file->priority >= TR_PRI_NORMAL) 680 if (file->firstPiece == piece || file->lastPiece == piece) 681 priority = TR_PRI_HIGH; 682 } 683 684 return priority; 683 685 } 684 686 … … 686 688 tr_torrentInitFilePieces (tr_torrent * tor) 687 689 { 688 int * firstFiles; 689 tr_file_index_t f; 690 tr_piece_index_t p; 691 uint64_t offset = 0; 692 tr_info * inf = &tor->info; 693 694 /* assign the file offsets */ 695 for (f=0; f<inf->fileCount; ++f) { 696 inf->files[f].offset = offset; 697 offset += inf->files[f].length; 698 initFilePieces (inf, f); 699 } 700 701 /* build the array of first-file hints to give calculatePiecePriority */ 702 firstFiles = tr_new (int, inf->pieceCount); 703 for (p=f=0; p<inf->pieceCount; ++p) { 704 while (inf->files[f].lastPiece < p) 705 ++f; 706 firstFiles[p] = f; 690 int * firstFiles; 691 tr_file_index_t f; 692 tr_piece_index_t p; 693 uint64_t offset = 0; 694 tr_info * inf = &tor->info; 695 696 /* assign the file offsets */ 697 for (f=0; f<inf->fileCount; ++f) 698 { 699 inf->files[f].offset = offset; 700 offset += inf->files[f].length; 701 initFilePieces (inf, f); 702 } 703 704 /* build the array of first-file hints to give calculatePiecePriority */ 705 firstFiles = tr_new (int, inf->pieceCount); 706 for (p=f=0; p<inf->pieceCount; ++p) 707 { 708 while (inf->files[f].lastPiece < p) 709 ++f; 710 firstFiles[p] = f; 707 711 } 708 712 709 713 #if 0 710 /* test to confirm the first-file hints are correct */ 711 for (p=0; p<inf->pieceCount; ++p) { 712 f = firstFiles[p]; 713 assert (inf->files[f].firstPiece <= p); 714 assert (inf->files[f].lastPiece >= p); 715 if (f > 0) 716 assert (inf->files[f-1].lastPiece < p); 717 for (f=0; f<inf->fileCount; ++f) 718 if (pieceHasFile (p, &inf->files[f])) 719 break; 720 assert ((int)f == firstFiles[p]); 714 /* test to confirm the first-file hints are correct */ 715 for (p=0; p<inf->pieceCount; ++p) 716 { 717 f = firstFiles[p]; 718 assert (inf->files[f].firstPiece <= p); 719 assert (inf->files[f].lastPiece >= p); 720 if (f > 0) 721 assert (inf->files[f-1].lastPiece < p); 722 723 for (f=0; f<inf->fileCount; ++f) 724 if (pieceHasFile (p, &inf->files[f])) 725 break; 726 727 assert ((int)f == firstFiles[p]); 721 728 } 722 729 #endif 723 730 724 725 726 727 731 for (p=0; p<inf->pieceCount; ++p) 732 inf->pieces[p].priority = calculatePiecePriority (tor, p, firstFiles[p]); 733 734 tr_free (firstFiles); 728 735 } 729 736 … … 738 745 tr_getBlockSize (uint32_t pieceSize) 739 746 { 740 uint32_t b = pieceSize; 741 742 while (b > MAX_BLOCK_SIZE) 743 b /= 2u; 744 745 if (!b || (pieceSize % b)) /* not cleanly divisible */ 746 return 0; 747 return b; 747 uint32_t b = pieceSize; 748 749 while (b > MAX_BLOCK_SIZE) 750 b /= 2u; 751 752 if (!b || (pieceSize % b)) /* not cleanly divisible */ 753 return 0; 754 755 return b; 748 756 } 749 757 … … 753 761 torrentInitFromInfo (tr_torrent * tor) 754 762 { 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 763 uint64_t t; 764 tr_info * info = &tor->info; 765 766 tor->blockSize = tr_getBlockSize (info->pieceSize); 767 768 if (info->pieceSize) 769 tor->lastPieceSize = (uint32_t)(info->totalSize % info->pieceSize); 770 771 if (!tor->lastPieceSize) 772 tor->lastPieceSize = info->pieceSize; 773 774 if (tor->blockSize) 775 tor->lastBlockSize = info->totalSize % tor->blockSize; 776 777 if (!tor->lastBlockSize) 778 tor->lastBlockSize = tor->blockSize; 779 780 tor->blockCount = tor->blockSize 781 ? (info->totalSize + tor->blockSize - 1) / tor->blockSize 782 : 0; 783 784 tor->blockCountInPiece = tor->blockSize 785 ? info->pieceSize / tor->blockSize 786 : 0; 787 788 tor->blockCountInLastPiece = tor->blockSize 789 ? (tor->lastPieceSize + tor->blockSize - 1) / tor->blockSize 790 : 0; 791 792 /* check our work */ 793 if (tor->blockSize != 0) 794 assert ((info->pieceSize % tor->blockSize) == 0); 795 t = info->pieceCount - 1; 796 t *= info->pieceSize; 797 t += tor->lastPieceSize; 798 assert (t == info->totalSize); 799 t = tor->blockCount - 1; 800 t *= tor->blockSize; 801 t += tor->lastBlockSize; 802 assert (t == info->totalSize); 803 t = info->pieceCount - 1; 804 t *= tor->blockCountInPiece; 805 t += tor->blockCountInLastPiece; 806 assert (t == (uint64_t)tor->blockCount); 807 808 tr_cpConstruct (&tor->completion, tor); 809 810 tr_torrentInitFilePieces (tor); 811 812 tor->completeness = tr_cpGetStatus (&tor->completion); 805 813 } 806 814 … … 810 818 tr_torrentGotNewInfoDict (tr_torrent * tor) 811 819 { 812 813 814 815 816 820 torrentInitFromInfo (tor); 821 822 tr_peerMgrOnTorrentGotMetainfo (tor); 823 824 tr_torrentFireMetadataCompleted (tor); 817 825 } 818 826 … … 820 828 hasAnyLocalData (const tr_torrent * tor) 821 829 { 822 823 824 825 826 827 828 830 tr_file_index_t i; 831 832 for (i=0; i<tor->info.fileCount; ++i) 833 if (tr_torrentFindFile2 (tor, i, NULL, NULL, NULL)) 834 return true; 835 836 return false; 829 837 } 830 838 … … 832 840 setLocalErrorIfFilesDisappeared (tr_torrent * tor) 833 841 { 834 835 836 837 { 838 839 840 } 841 842 842 const bool disappeared = (tr_cpHaveTotal (&tor->completion) > 0) && !hasAnyLocalData (tor); 843 844 if (disappeared) 845 { 846 tr_deeplog_tor (tor, "%s", "[LAZY] uh oh, the files disappeared"); 847 tr_torrentSetLocalError (tor, "%s", _("No data found! Ensure your drives are connected or use \"Set Location\". To re-download, remove the torrent and re-add it.")); 848 } 849 850 return disappeared; 843 851 } 844 852 … … 846 854 torrentInit (tr_torrent * tor, const tr_ctor * ctor) 847 855 { 848 int doStart; 849 uint64_t loaded; 850 const char * dir; 851 bool isNewTorrent; 852 struct stat st; 853 static int nextUniqueId = 1; 854 tr_session * session = tr_ctorGetSession (ctor); 855 856 assert (session != NULL); 857 858 tr_sessionLock (session); 859 860 tor->session = session; 861 tor->uniqueId = nextUniqueId++; 862 tor->magicNumber = TORRENT_MAGIC_NUMBER; 863 tor->queuePosition = session->torrentCount; 864 865 tr_sha1 (tor->obfuscatedHash, "req2", 4, 866 tor->info.hash, SHA_DIGEST_LENGTH, 867 NULL); 868 869 if (!tr_ctorGetDownloadDir (ctor, TR_FORCE, &dir) || 870 !tr_ctorGetDownloadDir (ctor, TR_FALLBACK, &dir)) 871 tor->downloadDir = tr_strdup (dir); 872 873 if (tr_ctorGetIncompleteDir (ctor, &dir)) 874 dir = tr_sessionGetIncompleteDir (session); 875 if (tr_sessionIsIncompleteDirEnabled (session)) 876 tor->incompleteDir = tr_strdup (dir); 877 878 tr_bandwidthConstruct (&tor->bandwidth, session, &session->bandwidth); 879 880 tor->bandwidth.priority = tr_ctorGetBandwidthPriority (ctor); 881 882 tor->error = TR_STAT_OK; 883 884 tor->finishedSeedingByIdle = false; 885 886 tr_peerMgrAddTorrent (session->peerMgr, tor); 887 888 assert (!tor->downloadedCur); 889 assert (!tor->uploadedCur); 890 891 tr_torrentSetAddedDate (tor, tr_time ()); /* this is a default value to be 892 overwritten by the resume file */ 893 894 torrentInitFromInfo (tor); 895 loaded = tr_torrentLoadResume (tor, ~0, ctor); 896 tor->completeness = tr_cpGetStatus (&tor->completion); 897 setLocalErrorIfFilesDisappeared (tor); 898 899 tr_ctorInitTorrentPriorities (ctor, tor); 900 tr_ctorInitTorrentWanted (ctor, tor); 901 902 refreshCurrentDir (tor); 903 904 doStart = tor->isRunning; 905 tor->isRunning = 0; 906 907 if (! (loaded & TR_FR_SPEEDLIMIT)) 908 { 909 tr_torrentUseSpeedLimit (tor, TR_UP, false); 910 tr_torrentSetSpeedLimit_Bps (tor, TR_UP, tr_sessionGetSpeedLimit_Bps (tor->session, TR_UP)); 911 tr_torrentUseSpeedLimit (tor, TR_DOWN, false); 912 tr_torrentSetSpeedLimit_Bps (tor, TR_DOWN, tr_sessionGetSpeedLimit_Bps (tor->session, TR_DOWN)); 913 tr_torrentUseSessionLimits (tor, true); 914 } 915 916 if (! (loaded & TR_FR_RATIOLIMIT)) 917 { 918 tr_torrentSetRatioMode (tor, TR_RATIOLIMIT_GLOBAL); 919 tr_torrentSetRatioLimit (tor, tr_sessionGetRatioLimit (tor->session)); 920 } 921 922 if (! (loaded & TR_FR_IDLELIMIT)) 923 { 924 tr_torrentSetIdleMode (tor, TR_IDLELIMIT_GLOBAL); 925 tr_torrentSetIdleLimit (tor, tr_sessionGetIdleLimit (tor->session)); 926 } 927 928 /* add the torrent to tr_session.torrentList */ 929 session->torrentCount++; 930 if (session->torrentList == NULL) 931 session->torrentList = tor; 932 else { 933 tr_torrent * it = session->torrentList; 934 while (it->next != NULL) 935 it = it->next; 936 it->next = tor; 937 } 938 939 /* if we don't have a local .torrent file already, assume the torrent is new */ 940 isNewTorrent = stat (tor->info.torrent, &st); 941 942 /* maybe save our own copy of the metainfo */ 943 if (tr_ctorGetSave (ctor)) 944 { 945 const tr_variant * val; 946 if (!tr_ctorGetMetainfo (ctor, &val)) 856 int doStart; 857 uint64_t loaded; 858 const char * dir; 859 bool isNewTorrent; 860 struct stat st; 861 tr_session * session = tr_ctorGetSession (ctor); 862 static int nextUniqueId = 1; 863 864 assert (session != NULL); 865 866 tr_sessionLock (session); 867 868 tor->session = session; 869 tor->uniqueId = nextUniqueId++; 870 tor->magicNumber = TORRENT_MAGIC_NUMBER; 871 tor->queuePosition = session->torrentCount; 872 873 tr_sha1 (tor->obfuscatedHash, "req2", 4, 874 tor->info.hash, SHA_DIGEST_LENGTH, 875 NULL); 876 877 if (!tr_ctorGetDownloadDir (ctor, TR_FORCE, &dir) || 878 !tr_ctorGetDownloadDir (ctor, TR_FALLBACK, &dir)) 879 tor->downloadDir = tr_strdup (dir); 880 881 if (tr_ctorGetIncompleteDir (ctor, &dir)) 882 dir = tr_sessionGetIncompleteDir (session); 883 if (tr_sessionIsIncompleteDirEnabled (session)) 884 tor->incompleteDir = tr_strdup (dir); 885 886 tr_bandwidthConstruct (&tor->bandwidth, session, &session->bandwidth); 887 888 tor->bandwidth.priority = tr_ctorGetBandwidthPriority (ctor); 889 890 tor->error = TR_STAT_OK; 891 892 tor->finishedSeedingByIdle = false; 893 894 tr_peerMgrAddTorrent (session->peerMgr, tor); 895 896 assert (!tor->downloadedCur); 897 assert (!tor->uploadedCur); 898 899 tr_torrentSetAddedDate (tor, tr_time ()); /* this is a default value to be 900 overwritten by the resume file */ 901 902 torrentInitFromInfo (tor); 903 loaded = tr_torrentLoadResume (tor, ~0, ctor); 904 tor->completeness = tr_cpGetStatus (&tor->completion); 905 setLocalErrorIfFilesDisappeared (tor); 906 907 tr_ctorInitTorrentPriorities (ctor, tor); 908 tr_ctorInitTorrentWanted (ctor, tor); 909 910 refreshCurrentDir (tor); 911 912 doStart = tor->isRunning; 913 tor->isRunning = 0; 914 915 if (!(loaded & TR_FR_SPEEDLIMIT)) 916 { 917 tr_torrentUseSpeedLimit (tor, TR_UP, false); 918 tr_torrentSetSpeedLimit_Bps (tor, TR_UP, tr_sessionGetSpeedLimit_Bps (tor->session, TR_UP)); 919 tr_torrentUseSpeedLimit (tor, TR_DOWN, false); 920 tr_torrentSetSpeedLimit_Bps (tor, TR_DOWN, tr_sessionGetSpeedLimit_Bps (tor->session, TR_DOWN)); 921 tr_torrentUseSessionLimits (tor, true); 922 } 923 924 if (!(loaded & TR_FR_RATIOLIMIT)) 925 { 926 tr_torrentSetRatioMode (tor, TR_RATIOLIMIT_GLOBAL); 927 tr_torrentSetRatioLimit (tor, tr_sessionGetRatioLimit (tor->session)); 928 } 929 930 if (!(loaded & TR_FR_IDLELIMIT)) 931 { 932 tr_torrentSetIdleMode (tor, TR_IDLELIMIT_GLOBAL); 933 tr_torrentSetIdleLimit (tor, tr_sessionGetIdleLimit (tor->session)); 934 } 935 936 /* add the torrent to tr_session.torrentList */ 937 session->torrentCount++; 938 if (session->torrentList == NULL) 939 { 940 session->torrentList = tor; 941 } 942 else 943 { 944 tr_torrent * it = session->torrentList; 945 while (it->next != NULL) 946 it = it->next; 947 it->next = tor; 948 } 949 950 /* if we don't have a local .torrent file already, assume the torrent is new */ 951 isNewTorrent = stat (tor->info.torrent, &st); 952 953 /* maybe save our own copy of the metainfo */ 954 if (tr_ctorGetSave (ctor)) 955 { 956 const tr_variant * val; 957 if (!tr_ctorGetMetainfo (ctor, &val)) 947 958 { 948 949 950 951 952 959 const char * path = tor->info.torrent; 960 const int err = tr_variantToFile (val, TR_VARIANT_FMT_BENC, path); 961 if (err) 962 tr_torrentSetLocalError (tor, "Unable to save torrent file: %s", tr_strerror (err)); 963 tr_sessionSetTorrentFile (tor->session, tor->info.hashString, path); 953 964 } 954 965 } 955 966 956 957 958 959 { 960 961 962 } 963 964 { 965 966 } 967 968 967 tor->tiers = tr_announcerAddTorrent (tor, onTrackerResponse, NULL); 968 969 if (isNewTorrent) 970 { 971 tor->startAfterVerify = doStart; 972 tr_torrentVerify (tor, NULL, NULL); 973 } 974 else if (doStart) 975 { 976 tr_torrentStart (tor); 977 } 978 979 tr_sessionUnlock (session); 969 980 } 970 981 … … 976 987 int * setme_duplicate_id) 977 988 { 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 989 bool doFree; 990 bool didParse; 991 bool hasInfo = false; 992 tr_info tmp; 993 const tr_variant * metainfo; 994 tr_session * session = tr_ctorGetSession (ctor); 995 tr_parse_result result = TR_PARSE_OK; 996 997 if (setmeInfo == NULL) 998 setmeInfo = &tmp; 999 memset (setmeInfo, 0, sizeof (tr_info)); 1000 1001 if (tr_ctorGetMetainfo (ctor, &metainfo)) 1002 return TR_PARSE_ERR; 1003 1004 didParse = tr_metainfoParse (session, metainfo, setmeInfo, 1005 &hasInfo, dictLength); 1006 doFree = didParse && (setmeInfo == &tmp); 1007 1008 if (!didParse) 1009 result = TR_PARSE_ERR; 1010 1011 if (didParse && hasInfo && !tr_getBlockSize (setmeInfo->pieceSize)) 1012 result = TR_PARSE_ERR; 1013 1014 if (didParse && session && (result == TR_PARSE_OK)) 1015 { 1016 const tr_torrent * const tor = tr_torrentFindFromHash (session, setmeInfo->hash); 1017 1018 if (tor != NULL) 1019 { 1020 result = TR_PARSE_DUPLICATE; 1021 1022 if (setme_duplicate_id != NULL) 1023 *setme_duplicate_id = tr_torrentId (tor); 1024 } 1025 } 1026 1027 if (doFree) 1028 tr_metainfoFree (setmeInfo); 1029 1030 if (setmeHasInfo != NULL) 1031 *setmeHasInfo = hasInfo; 1032 1033 return result; 1023 1034 } 1024 1035 … … 1026 1037 tr_torrentParse (const tr_ctor * ctor, tr_info * setmeInfo) 1027 1038 { 1028 1039 return torrentParseImpl (ctor, setmeInfo, NULL, NULL, NULL); 1029 1040 } 1030 1041 … … 1052 1063 torrentInit (tor, ctor); 1053 1064 } 1054 1065 else 1055 1066 { 1056 1067 if (r == TR_PARSE_DUPLICATE) … … 1071 1082 tr_torrentSetDownloadDir (tr_torrent * tor, const char * path) 1072 1083 { 1073 1074 1075 1076 { 1077 1078 1079 1080 } 1081 1082 1084 assert (tr_isTorrent (tor)); 1085 1086 if (!path || !tor->downloadDir || strcmp (path, tor->downloadDir)) 1087 { 1088 tr_free (tor->downloadDir); 1089 tor->downloadDir = tr_strdup (path); 1090 tr_torrentSetDirty (tor); 1091 } 1092 1093 refreshCurrentDir (tor); 1083 1094 } 1084 1095 … … 1086 1097 tr_torrentGetDownloadDir (const tr_torrent * tor) 1087 1098 { 1088 1089 1090 1099 assert (tr_isTorrent (tor)); 1100 1101 return tor->downloadDir; 1091 1102 } 1092 1103 … … 1094 1105 tr_torrentGetCurrentDir (const tr_torrent * tor) 1095 1106 { 1096 1097 1098 1107 assert (tr_isTorrent (tor)); 1108 1109 return tor->currentDir; 1099 1110 } 1100 1111 … … 1103 1114 tr_torrentChangeMyPort (tr_torrent * tor) 1104 1115 { 1105 1106 1107 1108 1116 assert (tr_isTorrent (tor)); 1117 1118 if (tor->isRunning) 1119 tr_announcerChangeMyPort (tor); 1109 1120 } 1110 1121 … … 1112 1123 tr_torrentManualUpdateImpl (void * vtor) 1113 1124 { 1114 1115 1116 1117 1118 1119 1125 tr_torrent * tor = vtor; 1126 1127 assert (tr_isTorrent (tor)); 1128 1129 if (tor->isRunning) 1130 tr_announcerManualAnnounce (tor); 1120 1131 } 1121 1132 … … 1123 1134 tr_torrentManualUpdate (tr_torrent * tor) 1124 1135 { 1125 1126 1127 1136 assert (tr_isTorrent (tor)); 1137 1138 tr_runInEventThread (tor->session, tr_torrentManualUpdateImpl, tor); 1128 1139 } 1129 1140 … … 1131 1142 tr_torrentCanManualUpdate (const tr_torrent * tor) 1132 1143 { 1133 1134 1135 1144 return (tr_isTorrent (tor)) 1145 && (tor->isRunning) 1146 && (tr_announcerCanManualAnnounce (tor)); 1136 1147 } 1137 1148 … … 1139 1150 tr_torrentInfo (const tr_torrent * tor) 1140 1151 { 1141 1152 return tr_isTorrent (tor) ? &tor->info : NULL; 1142 1153 } 1143 1154 … … 1145 1156 tr_torrentStatCached (tr_torrent * tor) 1146 1157 { 1147 1148 1149 1150 1151 1158 const time_t now = tr_time (); 1159 1160 return tr_isTorrent (tor) && (now == tor->lastStatTime) 1161 ? &tor->stats 1162 : tr_torrentStat (tor); 1152 1163 } 1153 1164 … … 1155 1166 tr_torrentSetVerifyState (tr_torrent * tor, tr_verify_state state) 1156 1167 { 1157 1158 1159 1160 1161 1168 assert (tr_isTorrent (tor)); 1169 assert (state==TR_VERIFY_NONE || state==TR_VERIFY_WAIT || state==TR_VERIFY_NOW); 1170 1171 tor->verifyState = state; 1172 tor->anyDate = tr_time (); 1162 1173 } 1163 1174 … … 1195 1206 torrentGetIdleSecs (const tr_torrent * tor) 1196 1207 { 1197 1198 1199 1200 1201 1202 1203 1204 1205 1208 int idle_secs; 1209 const tr_torrent_activity activity = tr_torrentGetActivity (tor); 1210 1211 if ((activity == TR_STATUS_DOWNLOAD || activity == TR_STATUS_SEED) && tor->startDate != 0) 1212 idle_secs = difftime (tr_time (), MAX (tor->startDate, tor->activityDate)); 1213 else 1214 idle_secs = -1; 1215 1216 return idle_secs; 1206 1217 } 1207 1218 … … 1209 1220 tr_torrentIsStalled (const tr_torrent * tor) 1210 1221 { 1211 1212 1222 return tr_sessionGetQueueStalledEnabled (tor->session) 1223 && (torrentGetIdleSecs (tor) > (tr_sessionGetQueueStalledMinutes (tor->session) * 60)); 1213 1224 } 1214 1225 … … 1386 1397 countFileBytesCompleted (const tr_torrent * tor, tr_file_index_t index) 1387 1398 { 1388 1389 1390 1391 1392 { 1393 1394 1395 1396 1397 1399 uint64_t total = 0; 1400 const tr_file * f = &tor->info.files[index]; 1401 1402 if (f->length) 1403 { 1404 tr_block_index_t first; 1405 tr_block_index_t last; 1406 tr_torGetFileBlockRange (tor, index, &first, &last); 1407 1408 if (first == last) 1398 1409 { 1399 1400 1410 if (tr_cpBlockIsComplete (&tor->completion, first)) 1411 total = f->length; 1401 1412 } 1402 1413 else 1403 1414 { 1404 /* the first block */ 1405 if (tr_cpBlockIsComplete (&tor->completion, first)) 1406 total += tor->blockSize - (f->offset % tor->blockSize); 1407 1408 /* the middle blocks */ 1409 if (first + 1 < last) { 1410 uint64_t u = tr_bitfieldCountRange (&tor->completion.blockBitfield, first+1, last); 1411 u *= tor->blockSize; 1412 total += u; 1415 /* the first block */ 1416 if (tr_cpBlockIsComplete (&tor->completion, first)) 1417 total += tor->blockSize - (f->offset % tor->blockSize); 1418 1419 /* the middle blocks */ 1420 if (first + 1 < last) 1421 { 1422 uint64_t u = tr_bitfieldCountRange (&tor->completion.blockBitfield, first+1, last); 1423 u *= tor->blockSize; 1424 total += u; 1413 1425 } 1414 1426 1415 1416 1417 1427 /* the last block */ 1428 if (tr_cpBlockIsComplete (&tor->completion, last)) 1429 total += (f->offset + f->length) - ((uint64_t)tor->blockSize * last); 1418 1430 } 1419 1431 } 1420 1432 1421 1433 return total; 1422 1434 } 1423 1435 1424 1436 tr_file_stat * 1425 1437 tr_torrentFiles (const tr_torrent * tor, 1426 tr_file_index_t * fileCount) 1427 { 1428 tr_file_index_t i; 1429 const tr_file_index_t n = tor->info.fileCount; 1430 tr_file_stat * files = tr_new0 (tr_file_stat, n); 1431 tr_file_stat * walk = files; 1432 const bool isSeed = tor->completeness == TR_SEED; 1433 1434 assert (tr_isTorrent (tor)); 1435 1436 for (i=0; i<n; ++i, ++walk) { 1437 const uint64_t b = isSeed ? tor->info.files[i].length : countFileBytesCompleted (tor, i); 1438 walk->bytesCompleted = b; 1439 walk->progress = tor->info.files[i].length > 0 ? ((float)b / tor->info.files[i].length) : 1.0f; 1440 } 1441 1442 if (fileCount) 1443 *fileCount = n; 1444 1445 return files; 1446 } 1447 1448 void 1449 tr_torrentFilesFree (tr_file_stat * files, 1450 tr_file_index_t fileCount UNUSED) 1451 { 1452 tr_free (files); 1438 tr_file_index_t * fileCount) 1439 { 1440 tr_file_index_t i; 1441 const tr_file_index_t n = tor->info.fileCount; 1442 tr_file_stat * files = tr_new0 (tr_file_stat, n); 1443 tr_file_stat * walk = files; 1444 const bool isSeed = tor->completeness == TR_SEED; 1445 1446 assert (tr_isTorrent (tor)); 1447 1448 for (i=0; i<n; ++i, ++walk) 1449 { 1450 const uint64_t b = isSeed ? tor->info.files[i].length : countFileBytesCompleted (tor, i); 1451 walk->bytesCompleted = b; 1452 walk->progress = tor->info.files[i].length > 0 ? ((float)b / tor->info.files[i].length) : 1.0f; 1453 } 1454 1455 if (fileCount != NULL) 1456 *fileCount = n; 1457 1458 return files; 1459 } 1460 1461 void 1462 tr_torrentFilesFree (tr_file_stat * files, 1463 tr_file_index_t fileCount UNUSED) 1464 { 1465 tr_free (files); 1453 1466 } 1454 1467 … … 1511 1524 tr_torrentResetTransferStats (tr_torrent * tor) 1512 1525 { 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1526 tr_torrentLock (tor); 1527 1528 tor->downloadedPrev += tor->downloadedCur; 1529 tor->downloadedCur = 0; 1530 tor->uploadedPrev += tor->uploadedCur; 1531 tor->uploadedCur = 0; 1532 tor->corruptPrev += tor->corruptCur; 1533 tor->corruptCur = 0; 1534 1535 tr_torrentSetDirty (tor); 1536 1537 tr_torrentUnlock (tor); 1525 1538 } 1526 1539 … … 1530 1543 bool has) 1531 1544 { 1532 1533 1534 1535 1536 1537 1538 1545 assert (tr_isTorrent (tor)); 1546 assert (pieceIndex < tor->info.pieceCount); 1547 1548 if (has) 1549 tr_cpPieceAdd (&tor->completion, pieceIndex); 1550 else 1551 tr_cpPieceRem (&tor->completion, pieceIndex); 1539 1552 } 1540 1553 … … 1550 1563 freeTorrent (tr_torrent * tor) 1551 1564 { 1552 tr_torrent * t; 1553 tr_session * session = tor->session; 1554 tr_info * inf = &tor->info; 1555 const time_t now = tr_time (); 1556 1557 assert (!tor->isRunning); 1558 1559 tr_sessionLock (session); 1560 1561 tr_peerMgrRemoveTorrent (tor); 1562 1563 tr_announcerRemoveTorrent (session->announcer, tor); 1564 1565 tr_cpDestruct (&tor->completion); 1566 1567 tr_free (tor->downloadDir); 1568 tr_free (tor->incompleteDir); 1569 1570 if (tor == session->torrentList) 1571 session->torrentList = tor->next; 1572 else for (t = session->torrentList; t != NULL; t = t->next) { 1573 if (t->next == tor) { 1574 t->next = tor->next; 1575 break; 1565 tr_torrent * t; 1566 tr_session * session = tor->session; 1567 tr_info * inf = &tor->info; 1568 const time_t now = tr_time (); 1569 1570 assert (!tor->isRunning); 1571 1572 tr_sessionLock (session); 1573 1574 tr_peerMgrRemoveTorrent (tor); 1575 1576 tr_announcerRemoveTorrent (session->announcer, tor); 1577 1578 tr_cpDestruct (&tor->completion); 1579 1580 tr_free (tor->downloadDir); 1581 tr_free (tor->incompleteDir); 1582 1583 if (tor == session->torrentList) 1584 { 1585 session->torrentList = tor->next; 1586 } 1587 else for (t = session->torrentList; t != NULL; t = t->next) 1588 { 1589 if (t->next == tor) 1590 { 1591 t->next = tor->next; 1592 break; 1576 1593 } 1577 1594 } 1578 1595 1579 /* decrement the torrent count */ 1580 assert (session->torrentCount >= 1); 1581 session->torrentCount--; 1582 1583 /* resequence the queue positions */ 1584 t = NULL; 1585 while ((t = tr_torrentNext (session, t))) { 1586 if (t->queuePosition > tor->queuePosition) { 1587 t->queuePosition--; 1588 t->anyDate = now; 1596 /* decrement the torrent count */ 1597 assert (session->torrentCount >= 1); 1598 session->torrentCount--; 1599 1600 /* resequence the queue positions */ 1601 t = NULL; 1602 while ((t = tr_torrentNext (session, t))) 1603 { 1604 if (t->queuePosition > tor->queuePosition) 1605 { 1606 t->queuePosition--; 1607 t->anyDate = now; 1589 1608 } 1590 1609 } 1591 1592 1593 1594 1595 1596 1597 1598 1599 1610 assert (queueIsSequenced (session)); 1611 1612 tr_bandwidthDestruct (&tor->bandwidth); 1613 1614 tr_metainfoFree (inf); 1615 memset (tor, ~0, sizeof (tr_torrent)); 1616 tr_free (tor); 1617 1618 tr_sessionUnlock (session); 1600 1619 } 1601 1620 … … 1609 1628 torrentStartImpl (void * vtor) 1610 1629 { 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1630 time_t now; 1631 tr_torrent * tor = vtor; 1632 1633 assert (tr_isTorrent (tor)); 1634 1635 tr_sessionLock (tor->session); 1636 1637 tr_torrentRecheckCompleteness (tor); 1638 torrentSetQueued (tor, false); 1639 1640 now = tr_time (); 1641 tor->isRunning = true; 1642 tor->completeness = tr_cpGetStatus (&tor->completion); 1643 tor->startDate = tor->anyDate = now; 1644 tr_torrentClearError (tor); 1645 tor->finishedSeedingByIdle = false; 1646 1647 tr_torrentResetTransferStats (tor); 1648 tr_announcerTorrentStarted (tor); 1649 tor->dhtAnnounceAt = now + tr_cryptoWeakRandInt (20); 1650 tor->dhtAnnounce6At = now + tr_cryptoWeakRandInt (20); 1651 tor->lpdAnnounceAt = now; 1652 tr_peerMgrStartTorrent (tor); 1653 1654 tr_sessionUnlock (tor->session); 1636 1655 } 1637 1656 … … 1639 1658 tr_torrentGetCurrentSizeOnDisk (const tr_torrent * tor) 1640 1659 { 1641 1642 1643 1644 1645 1646 { 1647 1648 1649 1650 1651 1652 1653 1654 1655 } 1656 1657 1660 tr_file_index_t i; 1661 uint64_t byte_count = 0; 1662 const tr_file_index_t n = tor->info.fileCount; 1663 1664 for (i=0; i<n; ++i) 1665 { 1666 struct stat sb; 1667 char * filename = tr_torrentFindFile (tor, i); 1668 1669 sb.st_size = 0; 1670 if (filename && !stat (filename, &sb)) 1671 byte_count += sb.st_size; 1672 1673 tr_free (filename); 1674 } 1675 1676 return byte_count; 1658 1677 } 1659 1678 … … 1661 1680 torrentShouldQueue (const tr_torrent * tor) 1662 1681 { 1663 1664 1665 1682 const tr_direction dir = tr_torrentGetQueueDirection (tor); 1683 1684 return tr_sessionCountQueueFreeSlots (tor->session, dir) == 0; 1666 1685 } 1667 1686 … … 1669 1688 torrentStart (tr_torrent * tor, bool bypass_queue) 1670 1689 { 1671 switch (tr_torrentGetActivity (tor)) 1672 { 1673 case TR_STATUS_SEED: 1674 case TR_STATUS_DOWNLOAD: 1675 return; /* already started */ 1676 break; 1677 1678 case TR_STATUS_SEED_WAIT: 1679 case TR_STATUS_DOWNLOAD_WAIT: 1680 if (!bypass_queue) 1681 return; /* already queued */ 1682 break; 1683 1684 case TR_STATUS_CHECK: 1685 case TR_STATUS_CHECK_WAIT: 1686 /* verifying right now... wait until that's done so 1687 * we'll know what completeness to use/announce */ 1688 tor->startAfterVerify = true; 1690 switch (tr_torrentGetActivity (tor)) 1691 { 1692 case TR_STATUS_SEED: 1693 case TR_STATUS_DOWNLOAD: 1694 return; /* already started */ 1695 break; 1696 1697 case TR_STATUS_SEED_WAIT: 1698 case TR_STATUS_DOWNLOAD_WAIT: 1699 if (!bypass_queue) 1700 return; /* already queued */ 1701 break; 1702 1703 case TR_STATUS_CHECK: 1704 case TR_STATUS_CHECK_WAIT: 1705 /* verifying right now... wait until that's done so 1706 * we'll know what completeness to use/announce */ 1707 tor->startAfterVerify = true; 1708 return; 1709 break; 1710 1711 case TR_STATUS_STOPPED: 1712 if (!bypass_queue && torrentShouldQueue (tor)) 1713 { 1714 torrentSetQueued (tor, true); 1689 1715 return; 1690 break; 1691 1692 case TR_STATUS_STOPPED: 1693 if (!bypass_queue && torrentShouldQueue (tor)) { 1694 torrentSetQueued (tor, true); 1695 return; 1696 } 1697 break; 1698 } 1699 1700 /* don't allow the torrent to be started if the files disappeared */ 1701 if (setLocalErrorIfFilesDisappeared (tor)) 1702 return; 1703 1704 /* otherwise, start it now... */ 1705 tr_sessionLock (tor->session); 1706 1707 /* allow finished torrents to be resumed */ 1708 if (tr_torrentIsSeedRatioDone (tor)) { 1709 tr_logAddTorInfo (tor, "%s", _("Restarted manually -- disabling its seed ratio")); 1710 tr_torrentSetRatioMode (tor, TR_RATIOLIMIT_UNLIMITED); 1711 } 1712 1713 /* corresponds to the peer_id sent as a tracker request parameter. 1714 * one tracker admin says: "When the same torrent is opened and 1715 * closed and opened again without quitting Transmission ... 1716 * change the peerid. It would help sometimes if a stopped event 1717 * was missed to ensure that we didn't think someone was cheating. */ 1718 tr_torrentUnsetPeerId (tor); 1719 tor->isRunning = true; 1720 tr_torrentSetDirty (tor); 1721 tr_runInEventThread (tor->session, torrentStartImpl, tor); 1722 1723 tr_sessionUnlock (tor->session); 1716 } 1717 break; 1718 } 1719 1720 /* don't allow the torrent to be started if the files disappeared */ 1721 if (setLocalErrorIfFilesDisappeared (tor)) 1722 return; 1723 1724 /* otherwise, start it now... */ 1725 tr_sessionLock (tor->session); 1726 1727 /* allow finished torrents to be resumed */ 1728 if (tr_torrentIsSeedRatioDone (tor)) 1729 { 1730 tr_logAddTorInfo (tor, "%s", _("Restarted manually -- disabling its seed ratio")); 1731 tr_torrentSetRatioMode (tor, TR_RATIOLIMIT_UNLIMITED); 1732 } 1733 1734 /* corresponds to the peer_id sent as a tracker request parameter. 1735 * one tracker admin says: "When the same torrent is opened and 1736 * closed and opened again without quitting Transmission ... 1737 * change the peerid. It would help sometimes if a stopped event 1738 * was missed to ensure that we didn't think someone was cheating. */ 1739 tr_torrentUnsetPeerId (tor); 1740 tor->isRunning = true; 1741 tr_torrentSetDirty (tor); 1742 tr_runInEventThread (tor->session, torrentStartImpl, tor); 1743 1744 tr_sessionUnlock (tor->session); 1724 1745 } 1725 1746 … … 1727 1748 tr_torrentStart (tr_torrent * tor) 1728 1749 { 1729 1730 1750 if (tr_isTorrent (tor)) 1751 torrentStart (tor, false); 1731 1752 } 1732 1753 … … 1734 1755 tr_torrentStartNow (tr_torrent * tor) 1735 1756 { 1736 1737 1757 if (tr_isTorrent (tor)) 1758 torrentStart (tor, true); 1738 1759 } 1739 1760 … … 1818 1839 tr_torrentSave (tr_torrent * tor) 1819 1840 { 1820 1821 1822 1823 { 1824 1825 1841 assert (tr_isTorrent (tor)); 1842 1843 if (tor->isDirty) 1844 { 1845 tor->isDirty = false; 1846 tr_torrentSaveResume (tor); 1826 1847 } 1827 1848 } … … 1854 1875 tr_torrentStop (tr_torrent * tor) 1855 1876 { 1856 1857 1858 1859 { 1860 1861 1862 1863 1864 1865 1866 1867 1877 assert (tr_isTorrent (tor)); 1878 1879 if (tr_isTorrent (tor)) 1880 { 1881 tr_sessionLock (tor->session); 1882 1883 tor->isRunning = 0; 1884 tor->isStopping = 0; 1885 tr_torrentSetDirty (tor); 1886 tr_runInEventThread (tor->session, stopTorrent, tor); 1887 1888 tr_sessionUnlock (tor->session); 1868 1889 } 1869 1890 } … … 1872 1893 closeTorrent (void * vtor) 1873 1894 { 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 { 1889 1890 1891 } 1892 1893 1894 1895 tr_variant * d; 1896 tr_torrent * tor = vtor; 1897 1898 assert (tr_isTorrent (tor)); 1899 1900 d = tr_variantListAddDict (&tor->session->removedTorrents, 2); 1901 tr_variantDictAddInt (d, TR_KEY_id, tor->uniqueId); 1902 tr_variantDictAddInt (d, TR_KEY_date, tr_time ()); 1903 1904 tr_logAddTorInfo (tor, "%s", _("Removing torrent")); 1905 1906 stopTorrent (tor); 1907 1908 if (tor->isDeleting) 1909 { 1910 tr_metainfoRemoveSaved (tor->session, &tor->info); 1911 tr_torrentRemoveResume (tor); 1912 } 1913 1914 tor->isRunning = 0; 1915 freeTorrent (tor); 1895 1916 } 1896 1917 … … 1942 1963 tr_fileFunc deleteFunc) 1943 1964 { 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1965 struct remove_data * data; 1966 1967 assert (tr_isTorrent (tor)); 1968 tor->isDeleting = 1; 1969 1970 data = tr_new0 (struct remove_data, 1); 1971 data->tor = tor; 1972 data->deleteFlag = deleteFlag; 1973 data->deleteFunc = deleteFunc; 1974 tr_runInEventThread (tor->session, removeTorrent, data); 1954 1975 } 1955 1976 … … 1961 1982 getCompletionString (int type) 1962 1983 { 1963 1964 { 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1984 switch (type) 1985 { 1986 /* Translators: this is a minor point that's safe to skip over, but FYI: 1987 "Complete" and "Done" are specific, different terms in Transmission: 1988 "Complete" means we've downloaded every file in the torrent. 1989 "Done" means we're done downloading the files we wanted, but NOT all 1990 that exist */ 1991 case TR_PARTIAL_SEED: 1992 return _("Done"); 1993 1994 case TR_SEED: 1995 return _("Complete"); 1996 1997 default: 1998 return _("Incomplete"); 1978 1999 } 1979 2000 } … … 1984 2005 bool wasRunning) 1985 2006 { 1986 1987 1988 1989 1990 1991 1992 2007 assert ((status == TR_LEECH) 2008 || (status == TR_SEED) 2009 || (status == TR_PARTIAL_SEED)); 2010 2011 if (tor->completeness_func) 2012 tor->completeness_func (tor, status, wasRunning, 2013 tor->completeness_func_user_data); 1993 2014 } 1994 2015 … … 1998 2019 void * user_data) 1999 2020 { 2000 2001 2002 2003 2021 assert (tr_isTorrent (tor)); 2022 2023 tor->completeness_func = func; 2024 tor->completeness_func_user_data = user_data; 2004 2025 } 2005 2026 … … 2007 2028 tr_torrentClearCompletenessCallback (tr_torrent * torrent) 2008 2029 { 2009 2030 tr_torrentSetCompletenessCallback (torrent, NULL, NULL); 2010 2031 } 2011 2032 … … 2015 2036 void * user_data) 2016 2037 { 2017 2018 2019 2020 2038 assert (tr_isTorrent (tor)); 2039 2040 tor->ratio_limit_hit_func = func; 2041 tor->ratio_limit_hit_func_user_data = user_data; 2021 2042 } 2022 2043 … … 2024 2045 tr_torrentClearRatioLimitHitCallback (tr_torrent * torrent) 2025 2046 { 2026 2047 tr_torrentSetRatioLimitHitCallback (torrent, NULL, NULL); 2027 2048 } 2028 2049 … … 2032 2053 void * user_data) 2033 2054 { 2034 2035 2036 2037 2055 assert (tr_isTorrent (tor)); 2056 2057 tor->idle_limit_hit_func = func; 2058 tor->idle_limit_hit_func_user_data = user_data; 2038 2059 } 2039 2060 … … 2041 2062 tr_torrentClearIdleLimitHitCallback (tr_torrent * torrent) 2042 2063 { 2043 2064 tr_torrentSetIdleLimitHitCallback (torrent, NULL, NULL); 2044 2065 } 2045 2066 … … 2047 2068 onSigCHLD (int i UNUSED) 2048 2069 { 2049 2070 waitpid (-1, NULL, WNOHANG); 2050 2071 } 2051 2072 … … 2053 2074 torrentCallScript (const tr_torrent * tor, const char * script) 2054 2075 { 2055 2056 2057 2058 2059 2060 2061 2062 { 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2076 char timeStr[128]; 2077 const time_t now = tr_time (); 2078 2079 tr_strlcpy (timeStr, ctime (&now), sizeof (timeStr)); 2080 *strchr (timeStr,'\n') = '\0'; 2081 2082 if (script && *script) 2083 { 2084 int i; 2085 char * cmd[] = { tr_strdup (script), NULL }; 2086 char * env[] = { 2087 tr_strdup_printf ("TR_APP_VERSION=%s", SHORT_VERSION_STRING), 2088 tr_strdup_printf ("TR_TIME_LOCALTIME=%s", timeStr), 2089 tr_strdup_printf ("TR_TORRENT_DIR=%s", tor->currentDir), 2090 tr_strdup_printf ("TR_TORRENT_ID=%d", tr_torrentId (tor)), 2091 tr_strdup_printf ("TR_TORRENT_HASH=%s", tor->info.hashString), 2092 tr_strdup_printf ("TR_TORRENT_NAME=%s", tr_torrentName (tor)), 2093 NULL }; 2094 2095 tr_logAddTorInfo (tor, "Calling script \"%s\"", script); 2075 2096 2076 2097 #ifdef WIN32 2077 2078 2098 if (_spawnvpe (_P_NOWAIT, script, (const char*)cmd, env) == -1) 2099 tr_logAddTorErr (tor, "error executing script \"%s\": %s", cmd[0], tr_strerror (errno)); 2079 2100 #else 2080 2081 2082 2101 signal (SIGCHLD, onSigCHLD); 2102 2103 if (!fork ()) 2083 2104 { 2084 2085 2086 2087 2088 2089 2090 2105 for (i=0; env[i]; ++i) 2106 putenv (env[i]); 2107 2108 if (execvp (script, cmd) == -1) 2109 tr_logAddTorErr (tor, "error executing script \"%s\": %s", cmd[0], tr_strerror (errno)); 2110 2111 _exit (0); 2091 2112 } 2092 2113 #endif 2093 2114 2094 2095 2115 for (i=0; cmd[i]; ++i) tr_free (cmd[i]); 2116 for (i=0; env[i]; ++i) tr_free (env[i]); 2096 2117 } 2097 2118 } … … 2159 2180 tr_torrentFireMetadataCompleted (tr_torrent * tor) 2160 2181 { 2161 2162 2163 if (tor->metadata_func)2164 2182 assert (tr_isTorrent (tor)); 2183 2184 if (tor->metadata_func != NULL) 2185 tor->metadata_func (tor, tor->metadata_func_user_data); 2165 2186 } 2166 2187 … … 2170 2191 void * user_data) 2171 2192 { 2172 2173 2174 2175 2193 assert (tr_isTorrent (tor)); 2194 2195 tor->metadata_func = func; 2196 tor->metadata_func_user_data = user_data; 2176 2197 } 2177 2198 … … 2186 2207 tr_priority_t priority) 2187 2208 { 2188 tr_piece_index_t i;2189 tr_file * file;2190 2191 2192 2193 2194 2195 2196 2197 for (i = file->firstPiece; i <=file->lastPiece; ++i)2198 2209 tr_file * file; 2210 tr_piece_index_t i; 2211 2212 assert (tr_isTorrent (tor)); 2213 assert (fileIndex < tor->info.fileCount); 2214 assert (tr_isPriority (priority)); 2215 2216 file = &tor->info.files[fileIndex]; 2217 file->priority = priority; 2218 for (i=file->firstPiece; i<=file->lastPiece; ++i) 2219 tor->info.pieces[i].priority = calculatePiecePriority (tor, i, fileIndex); 2199 2220 } 2200 2221 … … 2205 2226 tr_priority_t priority) 2206 2227 { 2207 2208 2209 2210 2211 for (i = 0; i <fileCount; ++i)2212 2213 2214 2215 2216 2217 2228 tr_file_index_t i; 2229 assert (tr_isTorrent (tor)); 2230 tr_torrentLock (tor); 2231 2232 for (i=0; i<fileCount; ++i) 2233 if (files[i] < tor->info.fileCount) 2234 tr_torrentInitFilePriority (tor, files[i], priority); 2235 tr_torrentSetDirty (tor); 2236 tr_peerMgrRebuildRequests (tor); 2237 2238 tr_torrentUnlock (tor); 2218 2239 } 2219 2240 … … 2241 2262 setFileDND (tr_torrent * tor, tr_file_index_t fileIndex, int doDownload) 2242 2263 { 2243 const int8_tdnd = !doDownload;2244 2245 int8_tfirstPieceDND;2246 2247 int8_tlastPieceDND;2248 2249 tr_file *file = &tor->info.files[fileIndex];2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 { 2260 for (i = fileIndex -1; firstPieceDND; --i)2264 const int8_t dnd = !doDownload; 2265 tr_piece_index_t firstPiece; 2266 int8_t firstPieceDND; 2267 tr_piece_index_t lastPiece; 2268 int8_t lastPieceDND; 2269 tr_file_index_t i; 2270 tr_file * file = &tor->info.files[fileIndex]; 2271 2272 file->dnd = dnd; 2273 firstPiece = file->firstPiece; 2274 lastPiece = file->lastPiece; 2275 2276 /* can't set the first piece to DND unless 2277 every file using that piece is DND */ 2278 firstPieceDND = dnd; 2279 if (fileIndex > 0) 2280 { 2281 for (i=fileIndex-1; firstPieceDND; --i) 2261 2282 { 2262 if (tor->info.files[i].lastPiece != firstPiece) 2263 break; 2264 firstPieceDND = tor->info.files[i].dnd; 2265 if (!i) 2266 break; 2283 if (tor->info.files[i].lastPiece != firstPiece) 2284 break; 2285 2286 firstPieceDND = tor->info.files[i].dnd; 2287 if (!i) 2288 break; 2267 2289 } 2268 2290 } 2269 2291 2270 2271 2272 2273 for (i = fileIndex + 1; lastPieceDND && i <tor->info.fileCount; ++i)2274 { 2275 2276 2277 2278 } 2279 2280 2281 { 2282 2283 } 2284 2285 { 2286 2287 2288 2289 for (pp = firstPiece + 1; pp <lastPiece; ++pp)2290 2292 /* can't set the last piece to DND unless 2293 every file using that piece is DND */ 2294 lastPieceDND = dnd; 2295 for (i=fileIndex+1; lastPieceDND && i<tor->info.fileCount; ++i) 2296 { 2297 if (tor->info.files[i].firstPiece != lastPiece) 2298 break; 2299 lastPieceDND = tor->info.files[i].dnd; 2300 } 2301 2302 if (firstPiece == lastPiece) 2303 { 2304 tor->info.pieces[firstPiece].dnd = firstPieceDND && lastPieceDND; 2305 } 2306 else 2307 { 2308 tr_piece_index_t pp; 2309 tor->info.pieces[firstPiece].dnd = firstPieceDND; 2310 tor->info.pieces[lastPiece].dnd = lastPieceDND; 2311 for (pp=firstPiece+1; pp<lastPiece; ++pp) 2312 tor->info.pieces[pp].dnd = dnd; 2291 2313 } 2292 2314 } … … 2298 2320 bool doDownload) 2299 2321 { 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2322 tr_file_index_t i; 2323 2324 assert (tr_isTorrent (tor)); 2325 2326 tr_torrentLock (tor); 2327 2328 for (i=0; i<fileCount; ++i) 2329 if (files[i] < tor->info.fileCount) 2330 setFileDND (tor, files[i], doDownload); 2331 2332 tr_cpInvalidateDND (&tor->completion); 2333 2334 tr_torrentUnlock (tor); 2313 2335 } 2314 2336 … … 2319 2341 bool doDownload) 2320 2342 { 2321 2322 2323 2324 2325 2326 2327 2328 2329 2343 assert (tr_isTorrent (tor)); 2344 tr_torrentLock (tor); 2345 2346 tr_torrentInitFileDLs (tor, files, fileCount, doDownload); 2347 tr_torrentSetDirty (tor); 2348 tr_torrentRecheckCompleteness (tor); 2349 tr_peerMgrRebuildRequests (tor); 2350 2351 tr_torrentUnlock (tor); 2330 2352 } 2331 2353 … … 2337 2359 tr_torrentGetPriority (const tr_torrent * tor) 2338 2360 { 2339 2340 2341 2361 assert (tr_isTorrent (tor)); 2362 2363 return tor->bandwidth.priority; 2342 2364 } 2343 2365 … … 2345 2367 tr_torrentSetPriority (tr_torrent * tor, tr_priority_t priority) 2346 2368 { 2347 2348 2349 2350 2351 { 2352 2353 2354 2369 assert (tr_isTorrent (tor)); 2370 assert (tr_isPriority (priority)); 2371 2372 if (tor->bandwidth.priority != priority) 2373 { 2374 tor->bandwidth.priority = priority; 2375 2376 tr_torrentSetDirty (tor); 2355 2377 } 2356 2378 } … … 2364 2386 uint16_t maxConnectedPeers) 2365 2387 { 2366 2367 2368 2369 { 2370 2371 2372 2388 assert (tr_isTorrent (tor)); 2389 2390 if (tor->maxConnectedPeers != maxConnectedPeers) 2391 { 2392 tor->maxConnectedPeers = maxConnectedPeers; 2393 2394 tr_torrentSetDirty (tor); 2373 2395 } 2374 2396 } … … 2377 2399 tr_torrentGetPeerLimit (const tr_torrent * tor) 2378 2400 { 2379 2380 2381 2401 assert (tr_isTorrent (tor)); 2402 2403 return tor->maxConnectedPeers; 2382 2404 } 2383 2405 … … 2393 2415 uint32_t * length) 2394 2416 { 2395 2396 2397 2398 2399 2417 uint64_t pos = block; 2418 pos *= tor->blockSize; 2419 *piece = pos / tor->info.pieceSize; 2420 *offset = pos - (*piece * tor->info.pieceSize); 2421 *length = tr_torBlockCountBytes (tor, block); 2400 2422 } 2401 2423 … … 2406 2428 uint32_t offset) 2407 2429 { 2408 2409 2410 2411 2412 2413 2414 2415 2430 tr_block_index_t ret; 2431 2432 assert (tr_isTorrent (tor)); 2433 2434 ret = index; 2435 ret *= (tor->info.pieceSize / tor->blockSize); 2436 ret += offset / tor->blockSize; 2437 return ret; 2416 2438 } 2417 2439 … … 2422 2444 uint32_t length) 2423 2445 { 2424 int err = 0; 2425 2426 assert (tr_isTorrent (tor)); 2427 2428 if (index >= tor->info.pieceCount) 2429 err = 1; 2430 else if (length < 1) 2431 err = 2; 2432 else if ((offset + length) > tr_torPieceCountBytes (tor, index)) 2433 err = 3; 2434 else if (length > MAX_BLOCK_SIZE) 2435 err = 4; 2436 else if (tr_pieceOffset (tor, index, offset, length) > tor->info.totalSize) 2437 err = 5; 2438 2439 if (err) tr_logAddTorDbg (tor, "index %lu offset %lu length %lu err %d\n", 2440 (unsigned long)index, 2441 (unsigned long)offset, 2442 (unsigned long)length, 2443 err); 2444 2445 return !err; 2446 int err = 0; 2447 2448 assert (tr_isTorrent (tor)); 2449 2450 if (index >= tor->info.pieceCount) 2451 err = 1; 2452 else if (length < 1) 2453 err = 2; 2454 else if ((offset + length) > tr_torPieceCountBytes (tor, index)) 2455 err = 3; 2456 else if (length > MAX_BLOCK_SIZE) 2457 err = 4; 2458 else if (tr_pieceOffset (tor, index, offset, length) > tor->info.totalSize) 2459 err = 5; 2460 2461 if (err) 2462 tr_logAddTorDbg (tor, "index %lu offset %lu length %lu err %d\n", 2463 (unsigned long)index, 2464 (unsigned long)offset, 2465 (unsigned long)length, 2466 err); 2467 2468 return !err; 2446 2469 } 2447 2470 … … 2452 2475 uint32_t length) 2453 2476 { 2454 2455 2456 2457 2458 2459 2460 2461 2462 2477 uint64_t ret; 2478 2479 assert (tr_isTorrent (tor)); 2480 2481 ret = tor->info.pieceSize; 2482 ret *= index; 2483 ret += offset; 2484 ret += length; 2485 return ret; 2463 2486 } 2464 2487 … … 2469 2492 tr_block_index_t * last) 2470 2493 { 2471 const tr_file * f = &tor->info.files[file]; 2472 uint64_t offset = f->offset; 2473 *first = offset / tor->blockSize; 2474 if (!f->length) 2475 *last = *first; 2476 else { 2477 offset += f->length - 1; 2478 *last = offset / tor->blockSize; 2494 const tr_file * f = &tor->info.files[file]; 2495 uint64_t offset = f->offset; 2496 2497 *first = offset / tor->blockSize; 2498 2499 if (!f->length) 2500 { 2501 *last = *first; 2502 } 2503 else 2504 { 2505 offset += f->length - 1; 2506 *last = offset / tor->blockSize; 2479 2507 } 2480 2508 } … … 2486 2514 tr_block_index_t * last) 2487 2515 { 2488 2489 2490 2491 2492 2516 uint64_t offset = tor->info.pieceSize; 2517 offset *= piece; 2518 *first = offset / tor->blockSize; 2519 offset += (tr_torPieceCountBytes (tor, piece) - 1); 2520 *last = offset / tor->blockSize; 2493 2521 } 2494 2522 … … 2501 2529 tr_torrentSetPieceChecked (tr_torrent * tor, tr_piece_index_t pieceIndex) 2502 2530 { 2503 2504 2505 2506 2531 assert (tr_isTorrent (tor)); 2532 assert (pieceIndex < tor->info.pieceCount); 2533 2534 tor->info.pieces[pieceIndex].timeChecked = tr_time (); 2507 2535 } 2508 2536 … … 2510 2538 tr_torrentSetChecked (tr_torrent * tor, time_t when) 2511 2539 { 2512 2513 2514 2515 2516 2517 2540 tr_piece_index_t i, n; 2541 2542 assert (tr_isTorrent (tor)); 2543 2544 for (i=0, n=tor->info.pieceCount; i!=n; ++i) 2545 tor->info.pieces[i].timeChecked = when; 2518 2546 } 2519 2547 … … 2521 2549 tr_torrentCheckPiece (tr_torrent * tor, tr_piece_index_t pieceIndex) 2522 2550 { 2523 2524 2525 2526 2527 2528 2529 2530 2531 2551 const bool pass = tr_ioTestPiece (tor, pieceIndex); 2552 2553 tr_deeplog_tor (tor, "[LAZY] tr_torrentCheckPiece tested piece %zu, pass==%d", (size_t)pieceIndex, (int)pass); 2554 tr_torrentSetHasPiece (tor, pieceIndex, pass); 2555 tr_torrentSetPieceChecked (tor, pieceIndex); 2556 tor->anyDate = tr_time (); 2557 tr_torrentSetDirty (tor); 2558 2559 return pass; 2532 2560 } 2533 2561 … … 2535 2563 tr_torrentGetFileMTime (const tr_torrent * tor, tr_file_index_t i) 2536 2564 { 2537 time_t mtime = 0; 2538 if (!tr_fdFileGetCachedMTime (tor->session, tor->uniqueId, i, &mtime)) 2539 tr_torrentFindFile2 (tor, i, NULL, NULL, &mtime); 2540 return mtime; 2565 time_t mtime = 0; 2566 2567 if (!tr_fdFileGetCachedMTime (tor->session, tor->uniqueId, i, &mtime)) 2568 tr_torrentFindFile2 (tor, i, NULL, NULL, &mtime); 2569 2570 return mtime; 2541 2571 } 2542 2572 … … 2544 2574 tr_torrentPieceNeedsCheck (const tr_torrent * tor, tr_piece_index_t p) 2545 2575 { 2546 uint64_t unused; 2547 tr_file_index_t f; 2548 const tr_info * inf = tr_torrentInfo (tor); 2549 2550 /* if we've never checked this piece, then it needs to be checked */ 2551 if (!inf->pieces[p].timeChecked) 2576 uint64_t unused; 2577 tr_file_index_t f; 2578 const tr_info * inf = tr_torrentInfo (tor); 2579 2580 /* if we've never checked this piece, then it needs to be checked */ 2581 if (!inf->pieces[p].timeChecked) 2582 return true; 2583 2584 /* If we think we've completed one of the files in this piece, 2585 * but it's been modified since we last checked it, 2586 * then it needs to be rechecked */ 2587 tr_ioFindFileLocation (tor, p, 0, &f, &unused); 2588 for (; f < inf->fileCount && pieceHasFile (p, &inf->files[f]); ++f) 2589 if (tr_cpFileIsComplete (&tor->completion, f)) 2590 if (tr_torrentGetFileMTime (tor, f) > inf->pieces[p].timeChecked) 2552 2591 return true; 2553 2592 2554 /* If we think we've completed one of the files in this piece, 2555 * but it's been modified since we last checked it, 2556 * then it needs to be rechecked */ 2557 tr_ioFindFileLocation (tor, p, 0, &f, &unused); 2558 for (; f < inf->fileCount && pieceHasFile (p, &inf->files[f]); ++f) 2559 if (tr_cpFileIsComplete (&tor->completion, f)) 2560 if (tr_torrentGetFileMTime (tor, f) > inf->pieces[p].timeChecked) 2561 return true; 2562 2563 return false; 2593 return false; 2564 2594 } 2565 2595 … … 2571 2601 compareTrackerByTier (const void * va, const void * vb) 2572 2602 { 2573 2574 2575 2576 2577 2578 2579 2580 2581 2603 const tr_tracker_info * a = va; 2604 const tr_tracker_info * b = vb; 2605 2606 /* sort by tier */ 2607 if (a->tier != b->tier) 2608 return a->tier - b->tier; 2609 2610 /* get the effects of a stable sort by comparing the two elements' addresses */ 2611 return a - b; 2582 2612 } 2583 2613 … … 2587 2617 int trackerCount) 2588 2618 { 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 { 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 int i; 2620 tr_variant metainfo; 2621 bool ok = true; 2622 tr_tracker_info * trackers; 2623 2624 tr_torrentLock (tor); 2625 2626 assert (tr_isTorrent (tor)); 2627 2628 /* ensure the trackers' tiers are in ascending order */ 2629 trackers = tr_memdup (trackers_in, sizeof (tr_tracker_info) * trackerCount); 2630 qsort (trackers, trackerCount, sizeof (tr_tracker_info), compareTrackerByTier); 2631 2632 /* look for bad URLs */ 2633 for (i=0; ok && i<trackerCount; ++i) 2634 if (!tr_urlIsValidTracker (trackers[i].announce)) 2635 ok = false; 2636 2637 /* save to the .torrent file */ 2638 if (ok && !tr_variantFromFile (&metainfo, TR_VARIANT_FMT_BENC, tor->info.torrent)) 2639 { 2640 bool hasInfo; 2641 tr_info tmpInfo; 2642 2643 /* remove the old fields */ 2644 tr_variantDictRemove (&metainfo, TR_KEY_announce); 2645 tr_variantDictRemove (&metainfo, TR_KEY_announce_list); 2646 2647 /* add the new fields */ 2648 if (trackerCount > 0) 2619 2649 { 2620 2650 tr_variantDictAddStr (&metainfo, TR_KEY_announce, trackers[0].announce); 2621 2651 } 2622 2652 if (trackerCount > 1) 2623 2653 { 2624 int i; 2625 int prevTier = -1; 2626 tr_variant * tier = NULL; 2627 tr_variant * announceList = tr_variantDictAddList (&metainfo, TR_KEY_announce_list, 0); 2628 2629 for (i=0; i<trackerCount; ++i) { 2630 if (prevTier != trackers[i].tier) { 2631 prevTier = trackers[i].tier; 2632 tier = tr_variantListAddList (announceList, 0); 2654 int i; 2655 int prevTier = -1; 2656 tr_variant * tier = NULL; 2657 tr_variant * announceList = tr_variantDictAddList (&metainfo, TR_KEY_announce_list, 0); 2658 2659 for (i=0; i<trackerCount; ++i) 2660 { 2661 if (prevTier != trackers[i].tier) 2662 { 2663 prevTier = trackers[i].tier; 2664 tier = tr_variantListAddList (announceList, 0); 2633 2665 } 2634 tr_variantListAddStr (tier, trackers[i].announce); 2666 2667 tr_variantListAddStr (tier, trackers[i].announce); 2635 2668 } 2636 2669 } 2637 2670 2638 2639 2640 2641 2671 /* try to parse it back again, to make sure it's good */ 2672 memset (&tmpInfo, 0, sizeof (tr_info)); 2673 if (tr_metainfoParse (tor->session, &metainfo, &tmpInfo, 2674 &hasInfo, &tor->infoDictLength)) 2642 2675 { 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2676 /* it's good, so keep these new trackers and free the old ones */ 2677 2678 tr_info swap; 2679 swap.trackers = tor->info.trackers; 2680 swap.trackerCount = tor->info.trackerCount; 2681 tor->info.trackers = tmpInfo.trackers; 2682 tor->info.trackerCount = tmpInfo.trackerCount; 2683 tmpInfo.trackers = swap.trackers; 2684 tmpInfo.trackerCount = swap.trackerCount; 2685 2686 tr_metainfoFree (&tmpInfo); 2687 tr_variantToFile (&metainfo, TR_VARIANT_FMT_BENC, tor->info.torrent); 2655 2688 } 2656 2689 2657 2658 2659 2660 2661 2662 2663 2664 2690 /* cleanup */ 2691 tr_variantFree (&metainfo); 2692 2693 /* if we had a tracker-related error on this torrent, 2694 * and that tracker's been removed, 2695 * then clear the error */ 2696 if ((tor->error == TR_STAT_TRACKER_WARNING) 2697 || (tor->error == TR_STAT_TRACKER_ERROR)) 2665 2698 { 2666 2667 2668 2669 2670 2671 2672 2673 2699 bool clear = true; 2700 2701 for (i=0; clear && i<trackerCount; ++i) 2702 if (!strcmp (trackers[i].announce, tor->errorTracker)) 2703 clear = false; 2704 2705 if (clear) 2706 tr_torrentClearError (tor); 2674 2707 } 2675 2708 2676 2677 2678 } 2679 2680 2681 2682 2683 2709 /* tell the announcer to reload this torrent's tracker list */ 2710 tr_announcerResetTorrent (tor->session->announcer, tor); 2711 } 2712 2713 tr_torrentUnlock (tor); 2714 2715 tr_free (trackers); 2716 return ok; 2684 2717 } 2685 2718 … … 2692 2725 time_t t) 2693 2726 { 2694 2695 2696 2697 2727 assert (tr_isTorrent (tor)); 2728 2729 tor->addedDate = t; 2730 tor->anyDate = MAX (tor->anyDate, tor->addedDate); 2698 2731 } 2699 2732 … … 2701 2734 tr_torrentSetActivityDate (tr_torrent * tor, time_t t) 2702 2735 { 2703 2704 2705 2706 2736 assert (tr_isTorrent (tor)); 2737 2738 tor->activityDate = t; 2739 tor->anyDate = MAX (tor->anyDate, tor->activityDate); 2707 2740 } 2708 2741 … … 2711 2744 time_t t) 2712 2745 { 2713 2714 2715 2716 2746 assert (tr_isTorrent (tor)); 2747 2748 tor->doneDate = t; 2749 tor->anyDate = MAX (tor->anyDate, tor->doneDate); 2717 2750 } 2718 2751 … … 2724 2757 tr_torrentGetBytesLeftToAllocate (const tr_torrent * tor) 2725 2758 { 2726 2727 2728 2729 2730 2731 2732 { 2733 2759 tr_file_index_t i; 2760 uint64_t bytesLeft = 0; 2761 2762 assert (tr_isTorrent (tor)); 2763 2764 for (i=0; i<tor->info.fileCount; ++i) 2765 { 2766 if (!tor->info.files[i].dnd) 2734 2767 { 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2768 struct stat sb; 2769 const uint64_t length = tor->info.files[i].length; 2770 char * path = tr_torrentFindFile (tor, i); 2771 2772 bytesLeft += length; 2773 2774 if ((path != NULL) && !stat (path, &sb) 2775 && S_ISREG (sb.st_mode) 2776 && ((uint64_t)sb.st_size <= length)) 2777 bytesLeft -= sb.st_size; 2778 2779 tr_free (path); 2747 2780 } 2748 2781 } 2749 2782 2750 2783 return bytesLeft; 2751 2784 } 2752 2785 … … 2758 2791 isJunkFile (const char * base) 2759 2792 { 2760 2761 2762 2763 2764 2765 2766 2793 int i; 2794 static const char * files[] = { ".DS_Store", "desktop.ini", "Thumbs.db" }; 2795 static const int file_count = sizeof (files) / sizeof (files[0]); 2796 2797 for (i=0; i<file_count; ++i) 2798 if (!strcmp (base, files[i])) 2799 return true; 2767 2800 2768 2801 #ifdef SYS_DARWIN 2769 2770 2771 2802 /* check for resource forks. <http://support.apple.com/kb/TA20578> */ 2803 if (!memcmp (base, "._", 2)) 2804 return true; 2772 2805 #endif 2773 2806 2774 2807 return false; 2775 2808 } 2776 2809 … … 2778 2811 removeEmptyFoldersAndJunkFiles (const char * folder) 2779 2812 { 2780 DIR * odir; 2781 if ((odir = opendir (folder))) { 2782 struct dirent * d; 2783 while ((d = readdir (odir))) { 2784 if (strcmp (d->d_name, ".") && strcmp (d->d_name, "..")) { 2785 struct stat sb; 2786 char * filename = tr_buildPath (folder, d->d_name, NULL); 2787 if (!stat (filename, &sb) && S_ISDIR (sb.st_mode)) 2788 removeEmptyFoldersAndJunkFiles (filename); 2789 else if (isJunkFile (d->d_name)) 2790 tr_remove (filename); 2791 tr_free (filename); 2813 DIR * odir; 2814 2815 if ((odir = opendir (folder))) 2816 { 2817 struct dirent * d; 2818 while ((d = readdir (odir))) 2819 { 2820 if (strcmp (d->d_name, ".") && strcmp (d->d_name, "..")) 2821 { 2822 struct stat sb; 2823 char * filename = tr_buildPath (folder, d->d_name, NULL); 2824 2825 if (!stat (filename, &sb) && S_ISDIR (sb.st_mode)) 2826 removeEmptyFoldersAndJunkFiles (filename); 2827 else if (isJunkFile (d->d_name)) 2828 tr_remove (filename); 2829 2830 tr_free (filename); 2792 2831 } 2793 2832 } 2794 tr_remove (folder); 2795 closedir (odir); 2833 2834 tr_remove (folder); 2835 closedir (odir); 2796 2836 } 2797 2837 } … … 2809 2849 deleteLocalData (tr_torrent * tor, tr_fileFunc func) 2810 2850 { 2811 int i, n; 2812 tr_file_index_t f; 2813 char * base; 2814 DIR * odir; 2815 char * tmpdir = NULL; 2816 tr_ptrArray files = TR_PTR_ARRAY_INIT; 2817 tr_ptrArray folders = TR_PTR_ARRAY_INIT; 2818 const void * const vstrcmp = strcmp; 2819 const char * const top = tor->currentDir; 2820 2821 /* if it's a magnet link, there's nothing to move... */ 2822 if (!tr_torrentHasMetadata (tor)) 2823 return; 2824 2825 /*** 2826 **** Move the local data to a new tmpdir 2827 ***/ 2828 2829 base = tr_strdup_printf ("%s__XXXXXX", tr_torrentName (tor)); 2830 tmpdir = tr_buildPath (top, base, NULL); 2831 tr_mkdtemp (tmpdir); 2832 tr_free (base); 2833 2834 for (f=0; f<tor->info.fileCount; ++f) 2835 { 2836 char * filename = tr_buildPath (top, tor->info.files[f].name, NULL); 2837 if (!tr_fileExists (filename, NULL)) { 2838 char * partial = tr_torrentBuildPartial (tor, f); 2839 tr_free (filename); 2840 filename = tr_buildPath (top, partial, NULL); 2841 tr_free (partial); 2842 if (!tr_fileExists (filename, NULL)) { 2843 tr_free (filename); 2844 filename = NULL; 2845 } 2846 } 2847 2848 if (filename != NULL) 2851 int i, n; 2852 tr_file_index_t f; 2853 char * base; 2854 DIR * odir; 2855 char * tmpdir = NULL; 2856 tr_ptrArray files = TR_PTR_ARRAY_INIT; 2857 tr_ptrArray folders = TR_PTR_ARRAY_INIT; 2858 const void * const vstrcmp = strcmp; 2859 const char * const top = tor->currentDir; 2860 2861 /* if it's a magnet link, there's nothing to move... */ 2862 if (!tr_torrentHasMetadata (tor)) 2863 return; 2864 2865 /*** 2866 **** Move the local data to a new tmpdir 2867 ***/ 2868 2869 base = tr_strdup_printf ("%s__XXXXXX", tr_torrentName (tor)); 2870 tmpdir = tr_buildPath (top, base, NULL); 2871 tr_mkdtemp (tmpdir); 2872 tr_free (base); 2873 2874 for (f=0; f<tor->info.fileCount; ++f) 2875 { 2876 char * filename; 2877 2878 /* try to find the file, looking in the partial and download dirs */ 2879 filename = tr_buildPath (top, tor->info.files[f].name, NULL); 2880 if (!tr_fileExists (filename, NULL)) 2849 2881 { 2850 char * target = tr_buildPath (tmpdir, tor->info.files[f].name, NULL); 2851 tr_moveFile (filename, target, NULL); 2852 tr_ptrArrayAppend (&files, target); 2853 tr_free (filename); 2854 } 2855 }