2 * This file Copyright (C) Mnemosyne LLC
4 * This file is licensed by the GPL version 2. Works owned by the
5 * Transmission project are granted a special exemption to clause 2 (b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
10 * $Id: rpcimpl.c 14130 2013-07-20 15:37:13Z jordan $
14 #include <ctype.h> /* isdigit */
16 #include <stdlib.h> /* strtol */
17 #include <string.h> /* strcmp */
23 #include <event2/buffer.h>
25 #include "transmission.h"
26 #include "completion.h"
29 #include "platform-quota.h" /* tr_device_info_get_free_space() */
38 #define RPC_VERSION 15
39 #define RPC_VERSION_MIN 1
41 #define RECENTLY_ACTIVE_SECONDS 60
43 #define TR_N_ELEMENTS(ary)(sizeof (ary) / sizeof (*ary))
46 #define dbgmsg(fmt, ...) \
48 fprintf (stderr, "%s:%d"#fmt, __FILE__, __LINE__, __VA_ARGS__); \
49 fprintf (stderr, "\n"); \
55 if (tr_logGetDeepEnabled ()) \
56 tr_logAddDeep (__FILE__, __LINE__, "RPC", __VA_ARGS__); \
66 static tr_rpc_callback_status
67 notify (tr_session
* session
,
71 tr_rpc_callback_status status
= 0;
73 if (session
->rpc_func
)
74 status
= session
->rpc_func (session
, type
, tor
,
75 session
->rpc_func_user_data
);
84 /* For functions that can't be immediately executed, like torrentAdd,
85 * this is the callback data used to pass a response to the caller
86 * when the task is complete */
87 struct tr_rpc_idle_data
90 tr_variant
* response
;
91 tr_variant
* args_out
;
92 tr_rpc_response_func callback
;
93 void * callback_user_data
;
97 tr_idle_function_done (struct tr_rpc_idle_data
* data
, const char * result
)
99 struct evbuffer
* buf
;
103 tr_variantDictAddStr (data
->response
, TR_KEY_result
, result
);
105 buf
= tr_variantToBuf (data
->response
, TR_VARIANT_FMT_JSON_LEAN
);
106 (*data
->callback
)(data
->session
, buf
, data
->callback_user_data
);
109 tr_variantFree (data
->response
);
110 tr_free (data
->response
);
119 getTorrents (tr_session
* session
,
123 int torrentCount
= 0;
125 tr_torrent
** torrents
= NULL
;
129 if (tr_variantDictFindList (args
, TR_KEY_ids
, &ids
))
132 const int n
= tr_variantListSize (ids
);
134 torrents
= tr_new0 (tr_torrent
*, n
);
140 tr_variant
* node
= tr_variantListChild (ids
, i
);
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
);
150 torrents
[torrentCount
++] = tor
;
153 else if (tr_variantDictFindInt (args
, TR_KEY_ids
, &id
)
154 || tr_variantDictFindInt (args
, TR_KEY_id
, &id
))
157 torrents
= tr_new0 (tr_torrent
*, 1);
158 if ((tor
= tr_torrentFindFromId (session
, id
)))
159 torrents
[torrentCount
++] = tor
;
161 else if (tr_variantDictFindStr (args
, TR_KEY_ids
, &str
, NULL
))
163 if (!strcmp (str
, "recently-active"))
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
;
177 torrents
= tr_new0 (tr_torrent
*, 1);
178 if ((tor
= tr_torrentFindFromHashString (session
, str
)))
179 torrents
[torrentCount
++] = tor
;
182 else /* all of them */
184 torrents
= tr_sessionGetTorrents (session
, &torrentCount
);
187 *setmeCount
= torrentCount
;
192 notifyBatchQueueChange (tr_session
* session
, tr_torrent
** torrents
, int n
)
196 notify (session
, TR_RPC_TORRENT_CHANGED
, torrents
[i
]);
197 notify (session
, TR_RPC_SESSION_QUEUE_POSITIONS_CHANGED
, NULL
);
201 queueMoveTop (tr_session
* session
,
202 tr_variant
* args_in
,
203 tr_variant
* args_out UNUSED
,
204 struct tr_rpc_idle_data
* idle_data UNUSED
)
207 tr_torrent
** torrents
= getTorrents (session
, args_in
, &n
);
208 tr_torrentsQueueMoveTop (torrents
, n
);
209 notifyBatchQueueChange (session
, torrents
, n
);
215 queueMoveUp (tr_session
* session
,
216 tr_variant
* args_in
,
217 tr_variant
* args_out UNUSED
,
218 struct tr_rpc_idle_data
* idle_data UNUSED
)
221 tr_torrent
** torrents
= getTorrents (session
, args_in
, &n
);
222 tr_torrentsQueueMoveUp (torrents
, n
);
223 notifyBatchQueueChange (session
, torrents
, n
);
229 queueMoveDown (tr_session
* session
,
230 tr_variant
* args_in
,
231 tr_variant
* args_out UNUSED
,
232 struct tr_rpc_idle_data
* idle_data UNUSED
)
235 tr_torrent
** torrents
= getTorrents (session
, args_in
, &n
);
236 tr_torrentsQueueMoveDown (torrents
, n
);
237 notifyBatchQueueChange (session
, torrents
, n
);
243 queueMoveBottom (tr_session
* session
,
244 tr_variant
* args_in
,
245 tr_variant
* args_out UNUSED
,
246 struct tr_rpc_idle_data
* idle_data UNUSED
)
249 tr_torrent
** torrents
= getTorrents (session
, args_in
, &n
);
250 tr_torrentsQueueMoveBottom (torrents
, n
);
251 notifyBatchQueueChange (session
, torrents
, n
);
257 torrentStart (tr_session
* session
,
258 tr_variant
* args_in
,
259 tr_variant
* args_out UNUSED
,
260 struct tr_rpc_idle_data
* idle_data UNUSED
)
264 tr_torrent
** torrents
;
266 assert (idle_data
== NULL
);
268 torrents
= getTorrents (session
, args_in
, &torrentCount
);
269 for (i
=0; i
<torrentCount
; ++i
)
271 tr_torrent
* tor
= torrents
[i
];
274 tr_torrentStart (tor
);
275 notify (session
, TR_RPC_TORRENT_STARTED
, tor
);
284 torrentStartNow (tr_session
* session
,
285 tr_variant
* args_in
,
286 tr_variant
* args_out UNUSED
,
287 struct tr_rpc_idle_data
* idle_data UNUSED
)
291 tr_torrent
** torrents
;
293 assert (idle_data
== NULL
);
295 torrents
= getTorrents (session
, args_in
, &torrentCount
);
296 for (i
=0; i
<torrentCount
; ++i
)
298 tr_torrent
* tor
= torrents
[i
];
302 tr_torrentStartNow (tor
);
303 notify (session
, TR_RPC_TORRENT_STARTED
, tor
);
312 torrentStop (tr_session
* session
,
313 tr_variant
* args_in
,
314 tr_variant
* args_out UNUSED
,
315 struct tr_rpc_idle_data
* idle_data UNUSED
)
319 tr_torrent
** torrents
;
321 assert (idle_data
== NULL
);
323 torrents
= getTorrents (session
, args_in
, &torrentCount
);
324 for (i
=0; i
<torrentCount
; ++i
)
326 tr_torrent
* tor
= torrents
[i
];
328 if (tor
->isRunning
|| tr_torrentIsQueued (tor
))
330 tor
->isStopping
= true;
331 notify (session
, TR_RPC_TORRENT_STOPPED
, tor
);
340 torrentRemove (tr_session
* session
,
341 tr_variant
* args_in
,
342 tr_variant
* args_out UNUSED
,
343 struct tr_rpc_idle_data
* idle_data UNUSED
)
347 tr_rpc_callback_type type
;
348 bool deleteFlag
= false;
349 tr_torrent
** torrents
;
351 assert (idle_data
== NULL
);
353 tr_variantDictFindBool (args_in
, TR_KEY_delete_local_data
, &deleteFlag
);
354 type
= deleteFlag
? TR_RPC_TORRENT_TRASHING
355 : TR_RPC_TORRENT_REMOVING
;
357 torrents
= getTorrents (session
, args_in
, &torrentCount
);
358 for (i
=0; i
<torrentCount
; ++i
)
360 tr_torrent
* tor
= torrents
[i
];
361 const tr_rpc_callback_status status
= notify (session
, type
, tor
);
363 if (!(status
& TR_RPC_NOREMOVE
))
364 tr_torrentRemove (tor
, deleteFlag
, NULL
);
372 torrentReannounce (tr_session
* session
,
373 tr_variant
* args_in
,
374 tr_variant
* args_out UNUSED
,
375 struct tr_rpc_idle_data
* idle_data UNUSED
)
379 tr_torrent
** torrents
;
381 assert (idle_data
== NULL
);
383 torrents
= getTorrents (session
, args_in
, &torrentCount
);
384 for (i
=0; i
<torrentCount
; ++i
)
386 tr_torrent
* tor
= torrents
[i
];
388 if (tr_torrentCanManualUpdate (tor
))
390 tr_torrentManualUpdate (tor
);
391 notify (session
, TR_RPC_TORRENT_CHANGED
, tor
);
400 torrentVerify (tr_session
* session
,
401 tr_variant
* args_in
,
402 tr_variant
* args_out UNUSED
,
403 struct tr_rpc_idle_data
* idle_data UNUSED
)
407 tr_torrent
** torrents
;
409 assert (idle_data
== NULL
);
411 torrents
= getTorrents (session
, args_in
, &torrentCount
);
412 for (i
=0; i
<torrentCount
; ++i
)
414 tr_torrent
* tor
= torrents
[i
];
415 tr_torrentVerify (tor
, NULL
, NULL
);
416 notify (session
, TR_RPC_TORRENT_CHANGED
, tor
);
428 addFileStats (const tr_torrent
* tor
, tr_variant
* list
)
432 const tr_info
* info
= tr_torrentInfo (tor
);
433 tr_file_stat
* files
= tr_torrentFiles (tor
, &n
);
435 for (i
=0; i
<info
->fileCount
; ++i
)
437 const tr_file
* file
= &info
->files
[i
];
438 tr_variant
* d
= tr_variantListAddDict (list
, 3);
439 tr_variantDictAddInt (d
, TR_KEY_bytesCompleted
, files
[i
].bytesCompleted
);
440 tr_variantDictAddInt (d
, TR_KEY_priority
, file
->priority
);
441 tr_variantDictAddBool (d
, TR_KEY_wanted
, !file
->dnd
);
444 tr_torrentFilesFree (files
, n
);
448 addFiles (const tr_torrent
* tor
, tr_variant
* list
)
452 const tr_info
* info
= tr_torrentInfo (tor
);
453 tr_file_stat
* files
= tr_torrentFiles (tor
, &n
);
455 for (i
=0; i
<info
->fileCount
; ++i
)
457 const tr_file
* file
= &info
->files
[i
];
458 tr_variant
* d
= tr_variantListAddDict (list
, 3);
459 tr_variantDictAddInt (d
, TR_KEY_bytesCompleted
, files
[i
].bytesCompleted
);
460 tr_variantDictAddInt (d
, TR_KEY_length
, file
->length
);
461 tr_variantDictAddStr (d
, TR_KEY_name
, file
->name
);
464 tr_torrentFilesFree (files
, n
);
468 addWebseeds (const tr_info
* info
,
469 tr_variant
* webseeds
)
473 for (i
=0; i
< info
->webseedCount
; ++i
)
474 tr_variantListAddStr (webseeds
, info
->webseeds
[i
]);
478 addTrackers (const tr_info
* info
,
479 tr_variant
* trackers
)
483 for (i
=0; i
<info
->trackerCount
; ++i
)
485 const tr_tracker_info
* t
= &info
->trackers
[i
];
486 tr_variant
* d
= tr_variantListAddDict (trackers
, 4);
487 tr_variantDictAddStr (d
, TR_KEY_announce
, t
->announce
);
488 tr_variantDictAddInt (d
, TR_KEY_id
, t
->id
);
489 tr_variantDictAddStr (d
, TR_KEY_scrape
, t
->scrape
);
490 tr_variantDictAddInt (d
, TR_KEY_tier
, t
->tier
);
495 addTrackerStats (const tr_tracker_stat
* st
, int n
, tr_variant
* list
)
501 const tr_tracker_stat
* s
= &st
[i
];
502 tr_variant
* d
= tr_variantListAddDict (list
, 26);
503 tr_variantDictAddStr (d
, TR_KEY_announce
, s
->announce
);
504 tr_variantDictAddInt (d
, TR_KEY_announceState
, s
->announceState
);
505 tr_variantDictAddInt (d
, TR_KEY_downloadCount
, s
->downloadCount
);
506 tr_variantDictAddBool (d
, TR_KEY_hasAnnounced
, s
->hasAnnounced
);
507 tr_variantDictAddBool (d
, TR_KEY_hasScraped
, s
->hasScraped
);
508 tr_variantDictAddStr (d
, TR_KEY_host
, s
->host
);
509 tr_variantDictAddInt (d
, TR_KEY_id
, s
->id
);
510 tr_variantDictAddBool (d
, TR_KEY_isBackup
, s
->isBackup
);
511 tr_variantDictAddInt (d
, TR_KEY_lastAnnouncePeerCount
, s
->lastAnnouncePeerCount
);
512 tr_variantDictAddStr (d
, TR_KEY_lastAnnounceResult
, s
->lastAnnounceResult
);
513 tr_variantDictAddInt (d
, TR_KEY_lastAnnounceStartTime
, s
->lastAnnounceStartTime
);
514 tr_variantDictAddBool (d
, TR_KEY_lastAnnounceSucceeded
, s
->lastAnnounceSucceeded
);
515 tr_variantDictAddInt (d
, TR_KEY_lastAnnounceTime
, s
->lastAnnounceTime
);
516 tr_variantDictAddBool (d
, TR_KEY_lastAnnounceTimedOut
, s
->lastAnnounceTimedOut
);
517 tr_variantDictAddStr (d
, TR_KEY_lastScrapeResult
, s
->lastScrapeResult
);
518 tr_variantDictAddInt (d
, TR_KEY_lastScrapeStartTime
, s
->lastScrapeStartTime
);
519 tr_variantDictAddBool (d
, TR_KEY_lastScrapeSucceeded
, s
->lastScrapeSucceeded
);
520 tr_variantDictAddInt (d
, TR_KEY_lastScrapeTime
, s
->lastScrapeTime
);
521 tr_variantDictAddInt (d
, TR_KEY_lastScrapeTimedOut
, s
->lastScrapeTimedOut
);
522 tr_variantDictAddInt (d
, TR_KEY_leecherCount
, s
->leecherCount
);
523 tr_variantDictAddInt (d
, TR_KEY_nextAnnounceTime
, s
->nextAnnounceTime
);
524 tr_variantDictAddInt (d
, TR_KEY_nextScrapeTime
, s
->nextScrapeTime
);
525 tr_variantDictAddStr (d
, TR_KEY_scrape
, s
->scrape
);
526 tr_variantDictAddInt (d
, TR_KEY_scrapeState
, s
->scrapeState
);
527 tr_variantDictAddInt (d
, TR_KEY_seederCount
, s
->seederCount
);
528 tr_variantDictAddInt (d
, TR_KEY_tier
, s
->tier
);
533 addPeers (tr_torrent
* tor
, tr_variant
* list
)
537 tr_peer_stat
* peers
= tr_torrentPeers (tor
, &peerCount
);
539 tr_variantInitList (list
, peerCount
);
541 for (i
=0; i
<peerCount
; ++i
)
543 tr_variant
* d
= tr_variantListAddDict (list
, 16);
544 const tr_peer_stat
* peer
= peers
+ i
;
545 tr_variantDictAddStr (d
, TR_KEY_address
, peer
->addr
);
546 tr_variantDictAddStr (d
, TR_KEY_clientName
, peer
->client
);
547 tr_variantDictAddBool (d
, TR_KEY_clientIsChoked
, peer
->clientIsChoked
);
548 tr_variantDictAddBool (d
, TR_KEY_clientIsInterested
, peer
->clientIsInterested
);
549 tr_variantDictAddStr (d
, TR_KEY_flagStr
, peer
->flagStr
);
550 tr_variantDictAddBool (d
, TR_KEY_isDownloadingFrom
, peer
->isDownloadingFrom
);
551 tr_variantDictAddBool (d
, TR_KEY_isEncrypted
, peer
->isEncrypted
);
552 tr_variantDictAddBool (d
, TR_KEY_isIncoming
, peer
->isIncoming
);
553 tr_variantDictAddBool (d
, TR_KEY_isUploadingTo
, peer
->isUploadingTo
);
554 tr_variantDictAddBool (d
, TR_KEY_isUTP
, peer
->isUTP
);
555 tr_variantDictAddBool (d
, TR_KEY_peerIsChoked
, peer
->peerIsChoked
);
556 tr_variantDictAddBool (d
, TR_KEY_peerIsInterested
, peer
->peerIsInterested
);
557 tr_variantDictAddInt (d
, TR_KEY_port
, peer
->port
);
558 tr_variantDictAddReal (d
, TR_KEY_progress
, peer
->progress
);
559 tr_variantDictAddInt (d
, TR_KEY_rateToClient
, toSpeedBytes (peer
->rateToClient_KBps
));
560 tr_variantDictAddInt (d
, TR_KEY_rateToPeer
, toSpeedBytes (peer
->rateToPeer_KBps
));
563 tr_torrentPeersFree (peers
, peerCount
);
567 addField (tr_torrent
* const tor
,
568 const tr_info
* const inf
,
569 const tr_stat
* const st
,
570 tr_variant
* const d
,
577 case TR_KEY_activityDate
:
578 tr_variantDictAddInt (d
, key
, st
->activityDate
);
581 case TR_KEY_addedDate
:
582 tr_variantDictAddInt (d
, key
, st
->addedDate
);
585 case TR_KEY_bandwidthPriority
:
586 tr_variantDictAddInt (d
, key
, tr_torrentGetPriority (tor
));
590 tr_variantDictAddStr (d
, key
, inf
->comment
? inf
->comment
: "");
593 case TR_KEY_corruptEver
:
594 tr_variantDictAddInt (d
, key
, st
->corruptEver
);
598 tr_variantDictAddStr (d
, key
, inf
->creator
? inf
->creator
: "");
601 case TR_KEY_dateCreated
:
602 tr_variantDictAddInt (d
, key
, inf
->dateCreated
);
605 case TR_KEY_desiredAvailable
:
606 tr_variantDictAddInt (d
, key
, st
->desiredAvailable
);
609 case TR_KEY_doneDate
:
610 tr_variantDictAddInt (d
, key
, st
->doneDate
);
613 case TR_KEY_downloadDir
:
614 tr_variantDictAddStr (d
, key
, tr_torrentGetDownloadDir (tor
));
617 case TR_KEY_downloadedEver
:
618 tr_variantDictAddInt (d
, key
, st
->downloadedEver
);
621 case TR_KEY_downloadLimit
:
622 tr_variantDictAddInt (d
, key
, tr_torrentGetSpeedLimit_KBps (tor
, TR_DOWN
));
625 case TR_KEY_downloadLimited
:
626 tr_variantDictAddBool (d
, key
, tr_torrentUsesSpeedLimit (tor
, TR_DOWN
));
630 tr_variantDictAddInt (d
, key
, st
->error
);
633 case TR_KEY_errorString
:
634 tr_variantDictAddStr (d
, key
, st
->errorString
);
638 tr_variantDictAddInt (d
, key
, st
->eta
);
642 addFiles (tor
, tr_variantDictAddList (d
, key
, inf
->fileCount
));
645 case TR_KEY_fileStats
:
646 addFileStats (tor
, tr_variantDictAddList (d
, key
, inf
->fileCount
));
649 case TR_KEY_hashString
:
650 tr_variantDictAddStr (d
, key
, tor
->info
.hashString
);
653 case TR_KEY_haveUnchecked
:
654 tr_variantDictAddInt (d
, key
, st
->haveUnchecked
);
657 case TR_KEY_haveValid
:
658 tr_variantDictAddInt (d
, key
, st
->haveValid
);
661 case TR_KEY_honorsSessionLimits
:
662 tr_variantDictAddBool (d
, key
, tr_torrentUsesSessionLimits (tor
));
666 tr_variantDictAddInt (d
, key
, st
->id
);
669 case TR_KEY_isFinished
:
670 tr_variantDictAddBool (d
, key
, st
->finished
);
673 case TR_KEY_isPrivate
:
674 tr_variantDictAddBool (d
, key
, tr_torrentIsPrivate (tor
));
677 case TR_KEY_isStalled
:
678 tr_variantDictAddBool (d
, key
, st
->isStalled
);
681 case TR_KEY_leftUntilDone
:
682 tr_variantDictAddInt (d
, key
, st
->leftUntilDone
);
685 case TR_KEY_manualAnnounceTime
:
686 tr_variantDictAddInt (d
, key
, st
->manualAnnounceTime
);
689 case TR_KEY_maxConnectedPeers
:
690 tr_variantDictAddInt (d
, key
, tr_torrentGetPeerLimit (tor
));
693 case TR_KEY_magnetLink
:
694 str
= tr_torrentGetMagnetLink (tor
);
695 tr_variantDictAddStr (d
, key
, str
);
699 case TR_KEY_metadataPercentComplete
:
700 tr_variantDictAddReal (d
, key
, st
->metadataPercentComplete
);
704 tr_variantDictAddStr (d
, key
, tr_torrentName (tor
));
707 case TR_KEY_percentDone
:
708 tr_variantDictAddReal (d
, key
, st
->percentDone
);
711 case TR_KEY_peer_limit
:
712 tr_variantDictAddInt (d
, key
, tr_torrentGetPeerLimit (tor
));
716 addPeers (tor
, tr_variantDictAdd (d
, key
));
719 case TR_KEY_peersConnected
:
720 tr_variantDictAddInt (d
, key
, st
->peersConnected
);
723 case TR_KEY_peersFrom
:
725 tr_variant
* tmp
= tr_variantDictAddDict (d
, key
, 7);
726 const int * f
= st
->peersFrom
;
727 tr_variantDictAddInt (tmp
, TR_KEY_fromCache
, f
[TR_PEER_FROM_RESUME
]);
728 tr_variantDictAddInt (tmp
, TR_KEY_fromDht
, f
[TR_PEER_FROM_DHT
]);
729 tr_variantDictAddInt (tmp
, TR_KEY_fromIncoming
, f
[TR_PEER_FROM_INCOMING
]);
730 tr_variantDictAddInt (tmp
, TR_KEY_fromLpd
, f
[TR_PEER_FROM_LPD
]);
731 tr_variantDictAddInt (tmp
, TR_KEY_fromLtep
, f
[TR_PEER_FROM_LTEP
]);
732 tr_variantDictAddInt (tmp
, TR_KEY_fromPex
, f
[TR_PEER_FROM_PEX
]);
733 tr_variantDictAddInt (tmp
, TR_KEY_fromTracker
, f
[TR_PEER_FROM_TRACKER
]);
737 case TR_KEY_peersGettingFromUs
:
738 tr_variantDictAddInt (d
, key
, st
->peersGettingFromUs
);
741 case TR_KEY_peersSendingToUs
:
742 tr_variantDictAddInt (d
, key
, st
->peersSendingToUs
);
746 if (tr_torrentHasMetadata (tor
))
748 size_t byte_count
= 0;
749 void * bytes
= tr_cpCreatePieceBitfield (&tor
->completion
, &byte_count
);
750 char * str
= tr_base64_encode (bytes
, byte_count
, NULL
);
751 tr_variantDictAddStr (d
, key
, str
!=NULL
? str
: "");
757 tr_variantDictAddStr (d
, key
, "");
761 case TR_KEY_pieceCount
:
762 tr_variantDictAddInt (d
, key
, inf
->pieceCount
);
765 case TR_KEY_pieceSize
:
766 tr_variantDictAddInt (d
, key
, inf
->pieceSize
);
769 case TR_KEY_priorities
:
772 tr_variant
* p
= tr_variantDictAddList (d
, key
, inf
->fileCount
);
773 for (i
=0; i
<inf
->fileCount
; ++i
)
774 tr_variantListAddInt (p
, inf
->files
[i
].priority
);
778 case TR_KEY_queuePosition
:
779 tr_variantDictAddInt (d
, key
, st
->queuePosition
);
783 tr_variantDictAddInt (d
, key
, st
->etaIdle
);
786 case TR_KEY_rateDownload
:
787 tr_variantDictAddInt (d
, key
, toSpeedBytes (st
->pieceDownloadSpeed_KBps
));
790 case TR_KEY_rateUpload
:
791 tr_variantDictAddInt (d
, key
, toSpeedBytes (st
->pieceUploadSpeed_KBps
));
794 case TR_KEY_recheckProgress
:
795 tr_variantDictAddReal (d
, key
, st
->recheckProgress
);
798 case TR_KEY_seedIdleLimit
:
799 tr_variantDictAddInt (d
, key
, tr_torrentGetIdleLimit (tor
));
802 case TR_KEY_seedIdleMode
:
803 tr_variantDictAddInt (d
, key
, tr_torrentGetIdleMode (tor
));
806 case TR_KEY_seedRatioLimit
:
807 tr_variantDictAddReal (d
, key
, tr_torrentGetRatioLimit (tor
));
810 case TR_KEY_seedRatioMode
:
811 tr_variantDictAddInt (d
, key
, tr_torrentGetRatioMode (tor
));
814 case TR_KEY_sizeWhenDone
:
815 tr_variantDictAddInt (d
, key
, st
->sizeWhenDone
);
818 case TR_KEY_startDate
:
819 tr_variantDictAddInt (d
, key
, st
->startDate
);
823 tr_variantDictAddInt (d
, key
, st
->activity
);
826 case TR_KEY_secondsDownloading
:
827 tr_variantDictAddInt (d
, key
, st
->secondsDownloading
);
830 case TR_KEY_secondsSeeding
:
831 tr_variantDictAddInt (d
, key
, st
->secondsSeeding
);
834 case TR_KEY_trackers
:
835 addTrackers (inf
, tr_variantDictAddList (d
, key
, inf
->trackerCount
));
838 case TR_KEY_trackerStats
:
841 tr_tracker_stat
* s
= tr_torrentTrackers (tor
, &n
);
842 addTrackerStats (s
, n
, tr_variantDictAddList (d
, key
, n
));
843 tr_torrentTrackersFree (s
, n
);
847 case TR_KEY_torrentFile
:
848 tr_variantDictAddStr (d
, key
, inf
->torrent
);
851 case TR_KEY_totalSize
:
852 tr_variantDictAddInt (d
, key
, inf
->totalSize
);
855 case TR_KEY_uploadedEver
:
856 tr_variantDictAddInt (d
, key
, st
->uploadedEver
);
859 case TR_KEY_uploadLimit
:
860 tr_variantDictAddInt (d
, key
, tr_torrentGetSpeedLimit_KBps (tor
, TR_UP
));
863 case TR_KEY_uploadLimited
:
864 tr_variantDictAddBool (d
, key
, tr_torrentUsesSpeedLimit (tor
, TR_UP
));
867 case TR_KEY_uploadRatio
:
868 tr_variantDictAddReal (d
, key
, st
->ratio
);
874 tr_variant
* w
= tr_variantDictAddList (d
, key
, inf
->fileCount
);
875 for (i
=0; i
<inf
->fileCount
; ++i
)
876 tr_variantListAddInt (w
, inf
->files
[i
].dnd
? 0 : 1);
880 case TR_KEY_webseeds
:
881 addWebseeds (inf
, tr_variantDictAddList (d
, key
, inf
->webseedCount
));
884 case TR_KEY_webseedsSendingToUs
:
885 tr_variantDictAddInt (d
, key
, st
->webseedsSendingToUs
);
894 addInfo (tr_torrent
* tor
, tr_variant
* d
, tr_variant
* fields
)
896 const int n
= tr_variantListSize (fields
);
898 tr_variantInitDict (d
, n
);
903 const tr_info
const * inf
= tr_torrentInfo (tor
);
904 const tr_stat
const * st
= tr_torrentStat ((tr_torrent
*)tor
);
910 if (tr_variantGetStr (tr_variantListChild (fields
, i
), &str
, &len
))
911 addField (tor
, inf
, st
, d
, tr_quark_new (str
, len
));
917 torrentGet (tr_session
* session
,
918 tr_variant
* args_in
,
919 tr_variant
* args_out
,
920 struct tr_rpc_idle_data
* idle_data UNUSED
)
924 tr_torrent
** torrents
= getTorrents (session
, args_in
, &torrentCount
);
925 tr_variant
* list
= tr_variantDictAddList (args_out
, TR_KEY_torrents
, torrentCount
);
928 const char * errmsg
= NULL
;
930 assert (idle_data
== NULL
);
932 if (tr_variantDictFindStr (args_in
, TR_KEY_ids
, &strVal
, NULL
) && !strcmp (strVal
, "recently-active"))
936 const time_t now
= tr_time ();
937 const int interval
= RECENTLY_ACTIVE_SECONDS
;
938 tr_variant
* removed_out
= tr_variantDictAddList (args_out
, TR_KEY_removed
, 0);
939 while ((d
= tr_variantListChild (&session
->removedTorrents
, n
++)))
942 if (tr_variantDictFindInt (d
, TR_KEY_date
, &intVal
) && (intVal
>= now
- interval
))
944 tr_variantDictFindInt (d
, TR_KEY_id
, &intVal
);
945 tr_variantListAddInt (removed_out
, intVal
);
950 if (!tr_variantDictFindList (args_in
, TR_KEY_fields
, &fields
))
951 errmsg
= "no fields specified";
952 else for (i
=0; i
<torrentCount
; ++i
)
953 addInfo (torrents
[i
], tr_variantListAdd (list
), fields
);
964 setFilePriorities (tr_torrent
* tor
,
971 const int n
= tr_variantListSize (list
);
972 const char * errmsg
= NULL
;
973 tr_file_index_t
* files
= tr_new0 (tr_file_index_t
, tor
->info
.fileCount
);
979 if (tr_variantGetInt (tr_variantListChild (list
, i
), &tmp
))
981 if (0 <= tmp
&& tmp
< tor
->info
.fileCount
)
982 files
[fileCount
++] = tmp
;
984 errmsg
= "file index out of range";
988 else /* if empty set, apply to all */
991 for (t
=0; t
<tor
->info
.fileCount
; ++t
)
992 files
[fileCount
++] = t
;
996 tr_torrentSetFilePriorities (tor
, files
, fileCount
, priority
);
1003 setFileDLs (tr_torrent
* tor
,
1010 const int n
= tr_variantListSize (list
);
1011 const char * errmsg
= NULL
;
1012 tr_file_index_t
* files
= tr_new0 (tr_file_index_t
, tor
->info
.fileCount
);
1014 if (n
) /* if argument list, process them */
1018 if (tr_variantGetInt (tr_variantListChild (list
, i
), &tmp
))
1020 if (0 <= tmp
&& tmp
< tor
->info
.fileCount
)
1021 files
[fileCount
++] = tmp
;
1023 errmsg
= "file index out of range";
1027 else /* if empty set, apply to all */
1031 for (t
=0; t
<tor
->info
.fileCount
; ++t
)
1032 files
[fileCount
++] = t
;
1036 tr_torrentSetFileDLs (tor
, files
, fileCount
, do_download
);
1043 findAnnounceUrl (const tr_tracker_info
* t
, int n
, const char * url
, int * pos
)
1050 if (!strcmp (t
[i
].announce
, url
))
1065 copyTrackers (tr_tracker_info
* tgt
, const tr_tracker_info
* src
, int n
)
1072 tgt
[i
].tier
= src
[i
].tier
;
1073 tgt
[i
].announce
= tr_strdup (src
[i
].announce
);
1074 maxTier
= MAX (maxTier
, src
[i
].tier
);
1081 freeTrackers (tr_tracker_info
* trackers
, int n
)
1086 tr_free (trackers
[i
].announce
);
1092 addTrackerUrls (tr_torrent
* tor
, tr_variant
* urls
)
1098 tr_tracker_info
* trackers
;
1099 bool changed
= false;
1100 const tr_info
* inf
= tr_torrentInfo (tor
);
1101 const char * errmsg
= NULL
;
1103 /* make a working copy of the existing announce list */
1104 n
= inf
->trackerCount
;
1105 trackers
= tr_new0 (tr_tracker_info
, n
+ tr_variantListSize (urls
));
1106 tier
= copyTrackers (trackers
, inf
->trackers
, n
);
1108 /* and add the new ones */
1110 while ((val
= tr_variantListChild (urls
, i
++)))
1112 const char * announce
= NULL
;
1114 if ( tr_variantGetStr (val
, &announce
, NULL
)
1115 && tr_urlIsValidTracker (announce
)
1116 && !findAnnounceUrl (trackers
, n
, announce
, NULL
))
1118 trackers
[n
].tier
= ++tier
; /* add a new tier */
1119 trackers
[n
].announce
= tr_strdup (announce
);
1126 errmsg
= "invalid argument";
1127 else if (!tr_torrentSetAnnounceList (tor
, trackers
, n
))
1128 errmsg
= "error setting announce list";
1130 freeTrackers (trackers
, n
);
1135 replaceTrackers (tr_torrent
* tor
, tr_variant
* urls
)
1138 tr_variant
* pair
[2];
1139 tr_tracker_info
* trackers
;
1140 bool changed
= false;
1141 const tr_info
* inf
= tr_torrentInfo (tor
);
1142 const int n
= inf
->trackerCount
;
1143 const char * errmsg
= NULL
;
1145 /* make a working copy of the existing announce list */
1146 trackers
= tr_new0 (tr_tracker_info
, n
);
1147 copyTrackers (trackers
, inf
->trackers
, n
);
1149 /* make the substitutions... */
1151 while (((pair
[0] = tr_variantListChild (urls
,i
))) &&
1152 ((pair
[1] = tr_variantListChild (urls
,i
+1))))
1156 const char * newval
;
1158 if (tr_variantGetInt (pair
[0], &pos
)
1159 && tr_variantGetStr (pair
[1], &newval
, &len
)
1160 && tr_urlIsValidTracker (newval
)
1164 tr_free (trackers
[pos
].announce
);
1165 trackers
[pos
].announce
= tr_strndup (newval
, len
);
1173 errmsg
= "invalid argument";
1174 else if (!tr_torrentSetAnnounceList (tor
, trackers
, n
))
1175 errmsg
= "error setting announce list";
1177 freeTrackers (trackers
, n
);
1182 removeTrackers (tr_torrent
* tor
, tr_variant
* ids
)
1190 tr_tracker_info
* trackers
;
1191 bool changed
= false;
1192 const tr_info
* inf
= tr_torrentInfo (tor
);
1193 const char * errmsg
= NULL
;
1195 /* make a working copy of the existing announce list */
1196 n
= inf
->trackerCount
;
1197 tids
= tr_new0 (int, n
);
1198 trackers
= tr_new0 (tr_tracker_info
, n
);
1199 copyTrackers (trackers
, inf
->trackers
, n
);
1201 /* remove the ones specified in the urls list */
1203 while ((val
= tr_variantListChild (ids
, i
++)))
1207 if (tr_variantGetInt (val
, &pos
) && (0 <= pos
) && (pos
< n
))
1211 /* sort trackerIds and remove from largest to smallest so there is no need to recacluate array indicies */
1212 qsort (tids
, t
, sizeof (int), compareInt
);
1215 /* check for duplicates */
1218 tr_removeElementFromArray (trackers
, tids
[t
], sizeof (tr_tracker_info
), n
--);
1224 errmsg
= "invalid argument";
1225 else if (!tr_torrentSetAnnounceList (tor
, trackers
, n
))
1226 errmsg
= "error setting announce list";
1228 freeTrackers (trackers
, n
);
1234 torrentSet (tr_session
* session
,
1235 tr_variant
* args_in
,
1236 tr_variant
* args_out UNUSED
,
1237 struct tr_rpc_idle_data
* idle_data UNUSED
)
1241 tr_torrent
** torrents
;
1242 const char * errmsg
= NULL
;
1244 assert (idle_data
== NULL
);
1246 torrents
= getTorrents (session
, args_in
, &torrentCount
);
1248 for (i
=0; i
<torrentCount
; ++i
)
1253 tr_variant
* trackers
;
1259 if (tr_variantDictFindInt (args_in
, TR_KEY_bandwidthPriority
, &tmp
))
1260 if (tr_isPriority (tmp
))
1261 tr_torrentSetPriority (tor
, tmp
);
1263 if (!errmsg
&& tr_variantDictFindList (args_in
, TR_KEY_files_unwanted
, &files
))
1264 errmsg
= setFileDLs (tor
, false, files
);
1266 if (!errmsg
&& tr_variantDictFindList (args_in
, TR_KEY_files_wanted
, &files
))
1267 errmsg
= setFileDLs (tor
, true, files
);
1269 if (tr_variantDictFindInt (args_in
, TR_KEY_peer_limit
, &tmp
))
1270 tr_torrentSetPeerLimit (tor
, tmp
);
1272 if (!errmsg
&& tr_variantDictFindList (args_in
, TR_KEY_priority_high
, &files
))
1273 errmsg
= setFilePriorities (tor
, TR_PRI_HIGH
, files
);
1275 if (!errmsg
&& tr_variantDictFindList (args_in
, TR_KEY_priority_low
, &files
))
1276 errmsg
= setFilePriorities (tor
, TR_PRI_LOW
, files
);
1278 if (!errmsg
&& tr_variantDictFindList (args_in
, TR_KEY_priority_normal
, &files
))
1279 errmsg
= setFilePriorities (tor
, TR_PRI_NORMAL
, files
);
1281 if (tr_variantDictFindInt (args_in
, TR_KEY_downloadLimit
, &tmp
))
1282 tr_torrentSetSpeedLimit_KBps (tor
, TR_DOWN
, tmp
);
1284 if (tr_variantDictFindBool (args_in
, TR_KEY_downloadLimited
, &boolVal
))
1285 tr_torrentUseSpeedLimit (tor
, TR_DOWN
, boolVal
);
1287 if (tr_variantDictFindBool (args_in
, TR_KEY_honorsSessionLimits
, &boolVal
))
1288 tr_torrentUseSessionLimits (tor
, boolVal
);
1290 if (tr_variantDictFindInt (args_in
, TR_KEY_uploadLimit
, &tmp
))
1291 tr_torrentSetSpeedLimit_KBps (tor
, TR_UP
, tmp
);
1293 if (tr_variantDictFindBool (args_in
, TR_KEY_uploadLimited
, &boolVal
))
1294 tr_torrentUseSpeedLimit (tor
, TR_UP
, boolVal
);
1296 if (tr_variantDictFindInt (args_in
, TR_KEY_seedIdleLimit
, &tmp
))
1297 tr_torrentSetIdleLimit (tor
, tmp
);
1299 if (tr_variantDictFindInt (args_in
, TR_KEY_seedIdleMode
, &tmp
))
1300 tr_torrentSetIdleMode (tor
, tmp
);
1302 if (tr_variantDictFindReal (args_in
, TR_KEY_seedRatioLimit
, &d
))
1303 tr_torrentSetRatioLimit (tor
, d
);
1305 if (tr_variantDictFindInt (args_in
, TR_KEY_seedRatioMode
, &tmp
))
1306 tr_torrentSetRatioMode (tor
, tmp
);
1308 if (tr_variantDictFindInt (args_in
, TR_KEY_queuePosition
, &tmp
))
1309 tr_torrentSetQueuePosition (tor
, tmp
);
1311 if (!errmsg
&& tr_variantDictFindList (args_in
, TR_KEY_trackerAdd
, &trackers
))
1312 errmsg
= addTrackerUrls (tor
, trackers
);
1314 if (!errmsg
&& tr_variantDictFindList (args_in
, TR_KEY_trackerRemove
, &trackers
))
1315 errmsg
= removeTrackers (tor
, trackers
);
1317 if (!errmsg
&& tr_variantDictFindList (args_in
, TR_KEY_trackerReplace
, &trackers
))
1318 errmsg
= replaceTrackers (tor
, trackers
);
1320 notify (session
, TR_RPC_TORRENT_CHANGED
, tor
);
1328 torrentSetLocation (tr_session
* session
,
1329 tr_variant
* args_in
,
1330 tr_variant
* args_out UNUSED
,
1331 struct tr_rpc_idle_data
* idle_data UNUSED
)
1333 const char * errmsg
= NULL
;
1334 const char * location
= NULL
;
1336 assert (idle_data
== NULL
);
1338 if (!tr_variantDictFindStr (args_in
, TR_KEY_location
, &location
, NULL
))
1340 errmsg
= "no location";
1345 int i
, torrentCount
;
1346 tr_torrent
** torrents
= getTorrents (session
, args_in
, &torrentCount
);
1348 tr_variantDictFindBool (args_in
, TR_KEY_move
, &move
);
1350 for (i
=0; i
<torrentCount
; ++i
)
1352 tr_torrent
* tor
= torrents
[i
];
1353 tr_torrentSetLocation (tor
, location
, move
, NULL
, NULL
);
1354 notify (session
, TR_RPC_TORRENT_MOVED
, tor
);
1368 torrentRenamePathDone (tr_torrent
* tor
,
1369 const char * oldpath
,
1370 const char * newname
,
1374 const char * result
;
1375 struct tr_rpc_idle_data
* data
= user_data
;
1377 tr_variantDictAddInt (data
->args_out
, TR_KEY_id
, tr_torrentId(tor
));
1378 tr_variantDictAddStr (data
->args_out
, TR_KEY_path
, oldpath
);
1379 tr_variantDictAddStr (data
->args_out
, TR_KEY_name
, newname
);
1384 result
= tr_strerror (error
);
1386 tr_idle_function_done (data
, result
);
1390 torrentRenamePath (tr_session
* session
,
1391 tr_variant
* args_in
,
1392 tr_variant
* args_out UNUSED
,
1393 struct tr_rpc_idle_data
* idle_data
)
1396 tr_torrent
** torrents
;
1397 const char * oldpath
= NULL
;
1398 const char * newname
= NULL
;
1400 tr_variantDictFindStr (args_in
, TR_KEY_path
, &oldpath
, NULL
);
1401 tr_variantDictFindStr (args_in
, TR_KEY_name
, &newname
, NULL
);
1402 torrents
= getTorrents (session
, args_in
, &torrentCount
);
1404 if (torrentCount
== 1)
1405 tr_torrentRenamePath (torrents
[0], oldpath
, newname
, torrentRenamePathDone
, idle_data
);
1407 tr_idle_function_done (idle_data
, "torrent-rename-path requires 1 torrent");
1411 return NULL
; /* ignored */
1419 portTested (tr_session
* session UNUSED
,
1420 bool did_connect UNUSED
,
1421 bool did_timeout UNUSED
,
1423 const void * response
,
1424 size_t response_byte_count
,
1428 struct tr_rpc_idle_data
* data
= user_data
;
1430 if (response_code
!= 200)
1432 tr_snprintf (result
, sizeof (result
), "portTested: http error %ld: %s",
1433 response_code
, tr_webGetResponseStr (response_code
));
1437 const bool isOpen
= response_byte_count
&& * (char*)response
== '1';
1438 tr_variantDictAddBool (data
->args_out
, TR_KEY_port_is_open
, isOpen
);
1439 tr_snprintf (result
, sizeof (result
), "success");
1442 tr_idle_function_done (data
, result
);
1446 portTest (tr_session
* session
,
1447 tr_variant
* args_in UNUSED
,
1448 tr_variant
* args_out UNUSED
,
1449 struct tr_rpc_idle_data
* idle_data
)
1451 const int port
= tr_sessionGetPeerPort (session
);
1452 char * url
= tr_strdup_printf ("http://portcheck.transmissionbt.com/%d", port
);
1453 tr_webRun (session
, url
, portTested
, idle_data
);
1463 gotNewBlocklist (tr_session
* session
,
1464 bool did_connect UNUSED
,
1465 bool did_timeout UNUSED
,
1467 const void * response
,
1468 size_t response_byte_count
,
1472 struct tr_rpc_idle_data
* data
= user_data
;
1476 if (response_code
!= 200)
1478 tr_snprintf (result
, sizeof (result
), "gotNewBlocklist: http error %ld: %s",
1479 response_code
, tr_webGetResponseStr (response_code
));
1481 else /* successfully fetched the blocklist... */
1487 const char * configDir
= tr_sessionGetConfigDir (session
);
1488 const size_t buflen
= 1024 * 128; /* 128 KiB buffer */
1489 uint8_t * buf
= tr_valloc (buflen
);
1491 /* this is an odd Magic Number required by zlib to enable gz support.
1492 See zlib's inflateInit2 () documentation for a full description */
1493 const int windowBits
= 15 + 32;
1495 stream
.zalloc
= (alloc_func
) Z_NULL
;
1496 stream
.zfree
= (free_func
) Z_NULL
;
1497 stream
.opaque
= (voidpf
) Z_NULL
;
1498 stream
.next_in
= (void*) response
;
1499 stream
.avail_in
= response_byte_count
;
1500 inflateInit2 (&stream
, windowBits
);
1502 filename
= tr_buildPath (configDir
, "blocklist.tmp", NULL
);
1503 fd
= tr_open_file_for_writing (filename
);
1505 tr_snprintf (result
, sizeof (result
), _("Couldn't save file \"%1$s\": %2$s"), filename
, tr_strerror (errno
));
1509 stream
.next_out
= (void*) buf
;
1510 stream
.avail_out
= buflen
;
1511 err
= inflate (&stream
, Z_NO_FLUSH
);
1513 if (stream
.avail_out
< buflen
)
1515 const int e
= write (fd
, buf
, buflen
- stream
.avail_out
);
1518 tr_snprintf (result
, sizeof (result
), _("Couldn't save file \"%1$s\": %2$s"), filename
, tr_strerror (errno
));
1525 if ((err
!= Z_STREAM_END
) && (err
!= Z_DATA_ERROR
))
1526 tr_snprintf (result
, sizeof (result
), _("Error uncompressing blocklist: %s (%d)"), zError (err
), err
);
1531 inflateEnd (&stream
);
1533 if (err
== Z_DATA_ERROR
) /* couldn't inflate it... it's probably already uncompressed */
1534 if (write (fd
, response
, response_byte_count
) < 0)
1535 tr_snprintf (result
, sizeof (result
), _("Couldn't save file \"%1$s\": %2$s"), filename
, tr_strerror (errno
));
1539 tr_logAddError ("%s", result
);
1543 /* feed it to the session and give the client a response */
1544 const int rule_count
= tr_blocklistSetContent (session
, filename
);
1545 tr_variantDictAddInt (data
->args_out
, TR_KEY_blocklist_size
, rule_count
);
1546 tr_snprintf (result
, sizeof (result
), "success");
1549 tr_remove (filename
);
1554 tr_idle_function_done (data
, result
);
1558 blocklistUpdate (tr_session
* session
,
1559 tr_variant
* args_in UNUSED
,
1560 tr_variant
* args_out UNUSED
,
1561 struct tr_rpc_idle_data
* idle_data
)
1563 tr_webRun (session
, session
->blocklist_url
, gotNewBlocklist
, idle_data
);
1572 addTorrentImpl (struct tr_rpc_idle_data
* data
, tr_ctor
* ctor
)
1576 const char * result
;
1582 tor
= tr_torrentNew (ctor
, &err
, &duplicate_id
);
1587 key
= TR_KEY_torrent_added
;
1590 else if (err
== TR_PARSE_ERR
)
1593 result
= "invalid or corrupt torrent file";
1595 else if (err
== TR_PARSE_DUPLICATE
)
1597 tor
= tr_torrentFindFromId (data
->session
, duplicate_id
);
1598 key
= TR_KEY_torrent_duplicate
;
1599 result
= "duplicate torrent";
1605 tr_variantInitList (&fields
, 3);
1606 tr_variantListAddStr (&fields
, "id");
1607 tr_variantListAddStr (&fields
, "name");
1608 tr_variantListAddStr (&fields
, "hashString");
1609 addInfo (tor
, tr_variantDictAdd (data
->args_out
, key
), &fields
);
1610 notify (data
->session
, TR_RPC_TORRENT_ADDED
, tor
);
1611 tr_variantFree (&fields
);
1615 tr_idle_function_done (data
, result
);
1619 struct add_torrent_idle_data
1621 struct tr_rpc_idle_data
* data
;
1626 gotMetadataFromURL (tr_session
* session UNUSED
,
1627 bool did_connect UNUSED
,
1628 bool did_timeout UNUSED
,
1630 const void * response
,
1631 size_t response_byte_count
,
1634 struct add_torrent_idle_data
* data
= user_data
;
1636 dbgmsg ("torrentAdd: HTTP response code was %ld (%s); response length was %zu bytes",
1637 response_code
, tr_webGetResponseStr (response_code
), response_byte_count
);
1639 if (response_code
==200 || response_code
==221) /* http or ftp success.. */
1641 tr_ctorSetMetainfo (data
->ctor
, response
, response_byte_count
);
1642 addTorrentImpl (data
->data
, data
->ctor
);
1647 tr_snprintf (result
, sizeof (result
), "gotMetadataFromURL: http error %ld: %s",
1648 response_code
, tr_webGetResponseStr (response_code
));
1649 tr_idle_function_done (data
->data
, result
);
1656 isCurlURL (const char * filename
)
1658 if (filename
== NULL
)
1661 return !strncmp (filename
, "ftp://", 6) ||
1662 !strncmp (filename
, "http://", 7) ||
1663 !strncmp (filename
, "https://", 8);
1666 static tr_file_index_t
*
1667 fileListFromList (tr_variant
* list
, tr_file_index_t
* setmeCount
)
1670 const size_t childCount
= tr_variantListSize (list
);
1671 tr_file_index_t n
= 0;
1672 tr_file_index_t
* files
= tr_new0 (tr_file_index_t
, childCount
);
1674 for (i
=0; i
<childCount
; ++i
)
1677 if (tr_variantGetInt (tr_variantListChild (list
, i
), &intVal
))
1678 files
[n
++] = (tr_file_index_t
)intVal
;
1686 torrentAdd (tr_session
* session
,
1687 tr_variant
* args_in
,
1688 tr_variant
* args_out UNUSED
,
1689 struct tr_rpc_idle_data
* idle_data
)
1691 const char * filename
= NULL
;
1692 const char * metainfo_base64
= NULL
;
1694 assert (idle_data
!= NULL
);
1696 tr_variantDictFindStr (args_in
, TR_KEY_filename
, &filename
, NULL
);
1697 tr_variantDictFindStr (args_in
, TR_KEY_metainfo
, &metainfo_base64
, NULL
);
1698 if (!filename
&& !metainfo_base64
)
1700 return "no filename or metainfo specified";
1708 const char * cookies
= NULL
;
1709 tr_ctor
* ctor
= tr_ctorNew (session
);
1711 /* set the optional arguments */
1713 tr_variantDictFindStr (args_in
, TR_KEY_cookies
, &cookies
, NULL
);
1715 if (tr_variantDictFindStr (args_in
, TR_KEY_download_dir
, &str
, NULL
))
1716 tr_ctorSetDownloadDir (ctor
, TR_FORCE
, str
);
1718 if (tr_variantDictFindBool (args_in
, TR_KEY_paused
, &boolVal
))
1719 tr_ctorSetPaused (ctor
, TR_FORCE
, boolVal
);
1721 if (tr_variantDictFindInt (args_in
, TR_KEY_peer_limit
, &i
))
1722 tr_ctorSetPeerLimit (ctor
, TR_FORCE
, i
);
1724 if (tr_variantDictFindInt (args_in
, TR_KEY_bandwidthPriority
, &i
))
1725 tr_ctorSetBandwidthPriority (ctor
, i
);
1727 if (tr_variantDictFindList (args_in
, TR_KEY_files_unwanted
, &l
))
1729 tr_file_index_t fileCount
;
1730 tr_file_index_t
* files
= fileListFromList (l
, &fileCount
);
1731 tr_ctorSetFilesWanted (ctor
, files
, fileCount
, false);
1735 if (tr_variantDictFindList (args_in
, TR_KEY_files_wanted
, &l
))
1737 tr_file_index_t fileCount
;
1738 tr_file_index_t
* files
= fileListFromList (l
, &fileCount
);
1739 tr_ctorSetFilesWanted (ctor
, files
, fileCount
, true);
1743 if (tr_variantDictFindList (args_in
, TR_KEY_priority_low
, &l
))
1745 tr_file_index_t fileCount
;
1746 tr_file_index_t
* files
= fileListFromList (l
, &fileCount
);
1747 tr_ctorSetFilePriorities (ctor
, files
, fileCount
, TR_PRI_LOW
);
1751 if (tr_variantDictFindList (args_in
, TR_KEY_priority_normal
, &l
))
1753 tr_file_index_t fileCount
;
1754 tr_file_index_t
* files
= fileListFromList (l
, &fileCount
);
1755 tr_ctorSetFilePriorities (ctor
, files
, fileCount
, TR_PRI_NORMAL
);
1759 if (tr_variantDictFindList (args_in
, TR_KEY_priority_high
, &l
))
1761 tr_file_index_t fileCount
;
1762 tr_file_index_t
* files
= fileListFromList (l
, &fileCount
);
1763 tr_ctorSetFilePriorities (ctor
, files
, fileCount
, TR_PRI_HIGH
);
1767 dbgmsg ("torrentAdd: filename is \"%s\"", filename
? filename
: " (null)");
1769 if (isCurlURL (filename
))
1771 struct add_torrent_idle_data
* d
= tr_new0 (struct add_torrent_idle_data
, 1);
1772 d
->data
= idle_data
;
1774 tr_webRunWithCookies (session
, filename
, cookies
, gotMetadataFromURL
, d
);
1778 char * fname
= tr_strstrip (tr_strdup (filename
));
1783 char * metainfo
= tr_base64_decode (metainfo_base64
, -1, &len
);
1784 tr_ctorSetMetainfo (ctor
, (uint8_t*)metainfo
, len
);
1787 else if (!strncmp (fname
, "magnet:?", 8))
1789 tr_ctorSetMetainfoFromMagnetLink (ctor
, fname
);
1793 tr_ctorSetMetainfoFromFile (ctor
, fname
);
1796 addTorrentImpl (idle_data
, ctor
);
1811 sessionSet (tr_session
* session
,
1812 tr_variant
* args_in
,
1813 tr_variant
* args_out UNUSED
,
1814 struct tr_rpc_idle_data
* idle_data UNUSED
)
1821 assert (idle_data
== NULL
);
1823 if (tr_variantDictFindInt (args_in
, TR_KEY_cache_size_mb
, &i
))
1824 tr_sessionSetCacheLimit_MB (session
, i
);
1826 if (tr_variantDictFindInt (args_in
, TR_KEY_alt_speed_up
, &i
))
1827 tr_sessionSetAltSpeed_KBps (session
, TR_UP
, i
);
1829 if (tr_variantDictFindInt (args_in
, TR_KEY_alt_speed_down
, &i
))
1830 tr_sessionSetAltSpeed_KBps (session
, TR_DOWN
, i
);
1832 if (tr_variantDictFindBool (args_in
, TR_KEY_alt_speed_enabled
, &boolVal
))
1833 tr_sessionUseAltSpeed (session
, boolVal
);
1835 if (tr_variantDictFindInt (args_in
, TR_KEY_alt_speed_time_begin
, &i
))
1836 tr_sessionSetAltSpeedBegin (session
, i
);
1838 if (tr_variantDictFindInt (args_in
, TR_KEY_alt_speed_time_end
, &i
))
1839 tr_sessionSetAltSpeedEnd (session
, i
);
1841 if (tr_variantDictFindInt (args_in
, TR_KEY_alt_speed_time_day
, &i
))
1842 tr_sessionSetAltSpeedDay (session
, i
);
1844 if (tr_variantDictFindBool (args_in
, TR_KEY_alt_speed_time_enabled
, &boolVal
))
1845 tr_sessionUseAltSpeedTime (session
, boolVal
);
1847 if (tr_variantDictFindBool (args_in
, TR_KEY_blocklist_enabled
, &boolVal
))
1848 tr_blocklistSetEnabled (session
, boolVal
);
1850 if (tr_variantDictFindStr (args_in
, TR_KEY_blocklist_url
, &str
, NULL
))
1851 tr_blocklistSetURL (session
, str
);
1853 if (tr_variantDictFindStr (args_in
, TR_KEY_download_dir
, &str
, NULL
))
1854 tr_sessionSetDownloadDir (session
, str
);
1856 if (tr_variantDictFindInt (args_in
, TR_KEY_queue_stalled_minutes
, &i
))
1857 tr_sessionSetQueueStalledMinutes (session
, i
);
1859 if (tr_variantDictFindBool (args_in
, TR_KEY_queue_stalled_enabled
, &boolVal
))
1860 tr_sessionSetQueueStalledEnabled (session
, boolVal
);
1862 if (tr_variantDictFindInt (args_in
, TR_KEY_download_queue_size
, &i
))
1863 tr_sessionSetQueueSize (session
, TR_DOWN
, i
);
1865 if (tr_variantDictFindBool (args_in
, TR_KEY_download_queue_enabled
, &boolVal
))
1866 tr_sessionSetQueueEnabled (session
, TR_DOWN
, boolVal
);
1868 if (tr_variantDictFindStr (args_in
, TR_KEY_incomplete_dir
, &str
, NULL
))
1869 tr_sessionSetIncompleteDir (session
, str
);
1871 if (tr_variantDictFindBool (args_in
, TR_KEY_incomplete_dir_enabled
, &boolVal
))
1872 tr_sessionSetIncompleteDirEnabled (session
, boolVal
);
1874 if (tr_variantDictFindInt (args_in
, TR_KEY_peer_limit_global
, &i
))
1875 tr_sessionSetPeerLimit (session
, i
);
1877 if (tr_variantDictFindInt (args_in
, TR_KEY_peer_limit_per_torrent
, &i
))
1878 tr_sessionSetPeerLimitPerTorrent (session
, i
);
1880 if (tr_variantDictFindBool (args_in
, TR_KEY_pex_enabled
, &boolVal
))
1881 tr_sessionSetPexEnabled (session
, boolVal
);
1883 if (tr_variantDictFindBool (args_in
, TR_KEY_dht_enabled
, &boolVal
))
1884 tr_sessionSetDHTEnabled (session
, boolVal
);
1886 if (tr_variantDictFindBool (args_in
, TR_KEY_utp_enabled
, &boolVal
))
1887 tr_sessionSetUTPEnabled (session
, boolVal
);
1889 if (tr_variantDictFindBool (args_in
, TR_KEY_lpd_enabled
, &boolVal
))
1890 tr_sessionSetLPDEnabled (session
, boolVal
);
1892 if (tr_variantDictFindBool (args_in
, TR_KEY_peer_port_random_on_start
, &boolVal
))
1893 tr_sessionSetPeerPortRandomOnStart (session
, boolVal
);
1895 if (tr_variantDictFindInt (args_in
, TR_KEY_peer_port
, &i
))
1896 tr_sessionSetPeerPort (session
, i
);
1898 if (tr_variantDictFindBool (args_in
, TR_KEY_port_forwarding_enabled
, &boolVal
))
1899 tr_sessionSetPortForwardingEnabled (session
, boolVal
);
1901 if (tr_variantDictFindBool (args_in
, TR_KEY_rename_partial_files
, &boolVal
))
1902 tr_sessionSetIncompleteFileNamingEnabled (session
, boolVal
);
1904 if (tr_variantDictFindReal (args_in
, TR_KEY_seedRatioLimit
, &d
))
1905 tr_sessionSetRatioLimit (session
, d
);
1907 if (tr_variantDictFindBool (args_in
, TR_KEY_seedRatioLimited
, &boolVal
))
1908 tr_sessionSetRatioLimited (session
, boolVal
);
1910 if (tr_variantDictFindInt (args_in
, TR_KEY_idle_seeding_limit
, &i
))
1911 tr_sessionSetIdleLimit (session
, i
);
1913 if (tr_variantDictFindBool (args_in
, TR_KEY_idle_seeding_limit_enabled
, &boolVal
))
1914 tr_sessionSetIdleLimited (session
, boolVal
);
1916 if (tr_variantDictFindBool (args_in
, TR_KEY_start_added_torrents
, &boolVal
))
1917 tr_sessionSetPaused (session
, !boolVal
);
1919 if (tr_variantDictFindBool (args_in
, TR_KEY_seed_queue_enabled
, &boolVal
))
1920 tr_sessionSetQueueEnabled (session
, TR_UP
, boolVal
);
1922 if (tr_variantDictFindInt (args_in
, TR_KEY_seed_queue_size
, &i
))
1923 tr_sessionSetQueueSize (session
, TR_UP
, i
);
1925 if (tr_variantDictFindStr (args_in
, TR_KEY_script_torrent_done_filename
, &str
, NULL
))
1926 tr_sessionSetTorrentDoneScript (session
, str
);
1928 if (tr_variantDictFindBool (args_in
, TR_KEY_script_torrent_done_enabled
, &boolVal
))
1929 tr_sessionSetTorrentDoneScriptEnabled (session
, boolVal
);
1931 if (tr_variantDictFindBool (args_in
, TR_KEY_trash_original_torrent_files
, &boolVal
))
1932 tr_sessionSetDeleteSource (session
, boolVal
);
1934 if (tr_variantDictFindInt (args_in
, TR_KEY_speed_limit_down
, &i
))
1935 tr_sessionSetSpeedLimit_KBps (session
, TR_DOWN
, i
);
1937 if (tr_variantDictFindBool (args_in
, TR_KEY_speed_limit_down_enabled
, &boolVal
))
1938 tr_sessionLimitSpeed (session
, TR_DOWN
, boolVal
);
1940 if (tr_variantDictFindInt (args_in
, TR_KEY_speed_limit_up
, &i
))
1941 tr_sessionSetSpeedLimit_KBps (session
, TR_UP
, i
);
1943 if (tr_variantDictFindBool (args_in
, TR_KEY_speed_limit_up_enabled
, &boolVal
))
1944 tr_sessionLimitSpeed (session
, TR_UP
, boolVal
);
1946 if (tr_variantDictFindStr (args_in
, TR_KEY_encryption
, &str
, NULL
))
1948 if (!tr_strcmp0 (str
, "required"))
1949 tr_sessionSetEncryption (session
, TR_ENCRYPTION_REQUIRED
);
1950 else if (!tr_strcmp0 (str
, "tolerated"))
1951 tr_sessionSetEncryption (session
, TR_CLEAR_PREFERRED
);
1953 tr_sessionSetEncryption (session
, TR_ENCRYPTION_PREFERRED
);
1956 notify (session
, TR_RPC_SESSION_CHANGED
, NULL
);
1962 sessionStats (tr_session
* session
,
1963 tr_variant
* args_in UNUSED
,
1964 tr_variant
* args_out
,
1965 struct tr_rpc_idle_data
* idle_data UNUSED
)
1970 tr_session_stats currentStats
= { 0.0f
, 0, 0, 0, 0, 0 };
1971 tr_session_stats cumulativeStats
= { 0.0f
, 0, 0, 0, 0, 0 };
1972 tr_torrent
* tor
= NULL
;
1974 assert (idle_data
== NULL
);
1976 while ((tor
= tr_torrentNext (session
, tor
)))
1984 tr_sessionGetStats (session
, ¤tStats
);
1985 tr_sessionGetCumulativeStats (session
, &cumulativeStats
);
1987 tr_variantDictAddInt (args_out
, TR_KEY_activeTorrentCount
, running
);
1988 tr_variantDictAddReal (args_out
, TR_KEY_downloadSpeed
, tr_sessionGetPieceSpeed_Bps (session
, TR_DOWN
));
1989 tr_variantDictAddInt (args_out
, TR_KEY_pausedTorrentCount
, total
- running
);
1990 tr_variantDictAddInt (args_out
, TR_KEY_torrentCount
, total
);
1991 tr_variantDictAddReal (args_out
, TR_KEY_uploadSpeed
, tr_sessionGetPieceSpeed_Bps (session
, TR_UP
));
1993 d
= tr_variantDictAddDict (args_out
, TR_KEY_cumulative_stats
, 5);
1994 tr_variantDictAddInt (d
, TR_KEY_downloadedBytes
, cumulativeStats
.downloadedBytes
);
1995 tr_variantDictAddInt (d
, TR_KEY_filesAdded
, cumulativeStats
.filesAdded
);
1996 tr_variantDictAddInt (d
, TR_KEY_secondsActive
, cumulativeStats
.secondsActive
);
1997 tr_variantDictAddInt (d
, TR_KEY_sessionCount
, cumulativeStats
.sessionCount
);
1998 tr_variantDictAddInt (d
, TR_KEY_uploadedBytes
, cumulativeStats
.uploadedBytes
);
2000 d
= tr_variantDictAddDict (args_out
, TR_KEY_current_stats
, 5);
2001 tr_variantDictAddInt (d
, TR_KEY_downloadedBytes
, currentStats
.downloadedBytes
);
2002 tr_variantDictAddInt (d
, TR_KEY_filesAdded
, currentStats
.filesAdded
);
2003 tr_variantDictAddInt (d
, TR_KEY_secondsActive
, currentStats
.secondsActive
);
2004 tr_variantDictAddInt (d
, TR_KEY_sessionCount
, currentStats
.sessionCount
);
2005 tr_variantDictAddInt (d
, TR_KEY_uploadedBytes
, currentStats
.uploadedBytes
);
2011 sessionGet (tr_session
* s
,
2012 tr_variant
* args_in UNUSED
,
2013 tr_variant
* args_out
,
2014 struct tr_rpc_idle_data
* idle_data UNUSED
)
2017 tr_variant
* d
= args_out
;
2019 assert (idle_data
== NULL
);
2020 tr_variantDictAddInt (d
, TR_KEY_alt_speed_up
, tr_sessionGetAltSpeed_KBps (s
,TR_UP
));
2021 tr_variantDictAddInt (d
, TR_KEY_alt_speed_down
, tr_sessionGetAltSpeed_KBps (s
,TR_DOWN
));
2022 tr_variantDictAddBool (d
, TR_KEY_alt_speed_enabled
, tr_sessionUsesAltSpeed (s
));
2023 tr_variantDictAddInt (d
, TR_KEY_alt_speed_time_begin
, tr_sessionGetAltSpeedBegin (s
));
2024 tr_variantDictAddInt (d
, TR_KEY_alt_speed_time_end
,tr_sessionGetAltSpeedEnd (s
));
2025 tr_variantDictAddInt (d
, TR_KEY_alt_speed_time_day
,tr_sessionGetAltSpeedDay (s
));
2026 tr_variantDictAddBool (d
, TR_KEY_alt_speed_time_enabled
, tr_sessionUsesAltSpeedTime (s
));
2027 tr_variantDictAddBool (d
, TR_KEY_blocklist_enabled
, tr_blocklistIsEnabled (s
));
2028 tr_variantDictAddStr (d
, TR_KEY_blocklist_url
, tr_blocklistGetURL (s
));
2029 tr_variantDictAddInt (d
, TR_KEY_cache_size_mb
, tr_sessionGetCacheLimit_MB (s
));
2030 tr_variantDictAddInt (d
, TR_KEY_blocklist_size
, tr_blocklistGetRuleCount (s
));
2031 tr_variantDictAddStr (d
, TR_KEY_config_dir
, tr_sessionGetConfigDir (s
));
2032 tr_variantDictAddStr (d
, TR_KEY_download_dir
, tr_sessionGetDownloadDir (s
));
2033 tr_variantDictAddInt (d
, TR_KEY_download_dir_free_space
, tr_device_info_get_free_space (s
->downloadDir
));
2034 tr_variantDictAddBool (d
, TR_KEY_download_queue_enabled
, tr_sessionGetQueueEnabled (s
, TR_DOWN
));
2035 tr_variantDictAddInt (d
, TR_KEY_download_queue_size
, tr_sessionGetQueueSize (s
, TR_DOWN
));
2036 tr_variantDictAddInt (d
, TR_KEY_peer_limit_global
, tr_sessionGetPeerLimit (s
));
2037 tr_variantDictAddInt (d
, TR_KEY_peer_limit_per_torrent
, tr_sessionGetPeerLimitPerTorrent (s
));
2038 tr_variantDictAddStr (d
, TR_KEY_incomplete_dir
, tr_sessionGetIncompleteDir (s
));
2039 tr_variantDictAddBool (d
, TR_KEY_incomplete_dir_enabled
, tr_sessionIsIncompleteDirEnabled (s
));
2040 tr_variantDictAddBool (d
, TR_KEY_pex_enabled
, tr_sessionIsPexEnabled (s
));
2041 tr_variantDictAddBool (d
, TR_KEY_utp_enabled
, tr_sessionIsUTPEnabled (s
));
2042 tr_variantDictAddBool (d
, TR_KEY_dht_enabled
, tr_sessionIsDHTEnabled (s
));
2043 tr_variantDictAddBool (d
, TR_KEY_lpd_enabled
, tr_sessionIsLPDEnabled (s
));
2044 tr_variantDictAddInt (d
, TR_KEY_peer_port
, tr_sessionGetPeerPort (s
));
2045 tr_variantDictAddBool (d
, TR_KEY_peer_port_random_on_start
, tr_sessionGetPeerPortRandomOnStart (s
));
2046 tr_variantDictAddBool (d
, TR_KEY_port_forwarding_enabled
, tr_sessionIsPortForwardingEnabled (s
));
2047 tr_variantDictAddBool (d
, TR_KEY_rename_partial_files
, tr_sessionIsIncompleteFileNamingEnabled (s
));
2048 tr_variantDictAddInt (d
, TR_KEY_rpc_version
, RPC_VERSION
);
2049 tr_variantDictAddInt (d
, TR_KEY_rpc_version_minimum
, RPC_VERSION_MIN
);
2050 tr_variantDictAddReal (d
, TR_KEY_seedRatioLimit
, tr_sessionGetRatioLimit (s
));
2051 tr_variantDictAddBool (d
, TR_KEY_seedRatioLimited
, tr_sessionIsRatioLimited (s
));
2052 tr_variantDictAddInt (d
, TR_KEY_idle_seeding_limit
, tr_sessionGetIdleLimit (s
));
2053 tr_variantDictAddBool (d
, TR_KEY_idle_seeding_limit_enabled
, tr_sessionIsIdleLimited (s
));
2054 tr_variantDictAddBool (d
, TR_KEY_seed_queue_enabled
, tr_sessionGetQueueEnabled (s
, TR_UP
));
2055 tr_variantDictAddInt (d
, TR_KEY_seed_queue_size
, tr_sessionGetQueueSize (s
, TR_UP
));
2056 tr_variantDictAddBool (d
, TR_KEY_start_added_torrents
, !tr_sessionGetPaused (s
));
2057 tr_variantDictAddBool (d
, TR_KEY_trash_original_torrent_files
, tr_sessionGetDeleteSource (s
));
2058 tr_variantDictAddInt (d
, TR_KEY_speed_limit_up
, tr_sessionGetSpeedLimit_KBps (s
, TR_UP
));
2059 tr_variantDictAddBool (d
, TR_KEY_speed_limit_up_enabled
, tr_sessionIsSpeedLimited (s
, TR_UP
));
2060 tr_variantDictAddInt (d
, TR_KEY_speed_limit_down
, tr_sessionGetSpeedLimit_KBps (s
, TR_DOWN
));
2061 tr_variantDictAddBool (d
, TR_KEY_speed_limit_down_enabled
, tr_sessionIsSpeedLimited (s
, TR_DOWN
));
2062 tr_variantDictAddStr (d
, TR_KEY_script_torrent_done_filename
, tr_sessionGetTorrentDoneScript (s
));
2063 tr_variantDictAddBool (d
, TR_KEY_script_torrent_done_enabled
, tr_sessionIsTorrentDoneScriptEnabled (s
));
2064 tr_variantDictAddBool (d
, TR_KEY_queue_stalled_enabled
, tr_sessionGetQueueStalledEnabled (s
));
2065 tr_variantDictAddInt (d
, TR_KEY_queue_stalled_minutes
, tr_sessionGetQueueStalledMinutes (s
));
2066 tr_formatter_get_units (tr_variantDictAddDict (d
, TR_KEY_units
, 0));
2067 tr_variantDictAddStr (d
, TR_KEY_version
, LONG_VERSION_STRING
);
2068 switch (tr_sessionGetEncryption (s
))
2070 case TR_CLEAR_PREFERRED
: str
= "tolerated"; break;
2071 case TR_ENCRYPTION_REQUIRED
: str
= "required"; break;
2072 default: str
= "preferred"; break;
2074 tr_variantDictAddStr (d
, TR_KEY_encryption
, str
);
2080 freeSpace (tr_session
* session
,
2081 tr_variant
* args_in
,
2082 tr_variant
* args_out
,
2083 struct tr_rpc_idle_data
* idle_data UNUSED
)
2086 const char * path
= NULL
;
2087 const char * err
= NULL
;
2088 int64_t free_space
= -1;
2090 /* get the free space */
2091 tr_variantDictFindStr (args_in
, TR_KEY_path
, &path
, NULL
);
2094 free_space
= tr_sessionGetDirFreeSpace (session
, path
);
2096 err
= tr_strerror (errno
);
2101 tr_variantDictAddStr (args_out
, TR_KEY_path
, path
);
2102 tr_variantDictAddInt (args_out
, TR_KEY_size_bytes
, free_space
);
2111 sessionClose (tr_session
* session
,
2112 tr_variant
* args_in UNUSED
,
2113 tr_variant
* args_out UNUSED
,
2114 struct tr_rpc_idle_data
* idle_data UNUSED
)
2116 notify (session
, TR_RPC_SESSION_CLOSE
, NULL
);
2124 typedef const char* (*handler
)(tr_session
*, tr_variant
*, tr_variant
*, struct tr_rpc_idle_data
*);
2126 static struct method
2134 { "port-test", false, portTest
},
2135 { "blocklist-update", false, blocklistUpdate
},
2136 { "free-space", true, freeSpace
},
2137 { "session-close", true, sessionClose
},
2138 { "session-get", true, sessionGet
},
2139 { "session-set", true, sessionSet
},
2140 { "session-stats", true, sessionStats
},
2141 { "torrent-add", false, torrentAdd
},
2142 { "torrent-get", true, torrentGet
},
2143 { "torrent-remove", true, torrentRemove
},
2144 { "torrent-rename-path", false, torrentRenamePath
},
2145 { "torrent-set", true, torrentSet
},
2146 { "torrent-set-location", true, torrentSetLocation
},
2147 { "torrent-start", true, torrentStart
},
2148 { "torrent-start-now", true, torrentStartNow
},
2149 { "torrent-stop", true, torrentStop
},
2150 { "torrent-verify", true, torrentVerify
},
2151 { "torrent-reannounce", true, torrentReannounce
},
2152 { "queue-move-top", true, queueMoveTop
},
2153 { "queue-move-up", true, queueMoveUp
},
2154 { "queue-move-down", true, queueMoveDown
},
2155 { "queue-move-bottom", true, queueMoveBottom
}
2159 noop_response_callback (tr_session
* session UNUSED
,
2160 struct evbuffer
* response UNUSED
,
2161 void * user_data UNUSED
)
2166 request_exec (tr_session
* session
,
2167 tr_variant
* request
,
2168 tr_rpc_response_func callback
,
2169 void * callback_user_data
)
2173 tr_variant
* args_in
= tr_variantDictFind (request
, TR_KEY_arguments
);
2174 const char * result
= NULL
;
2176 if (callback
== NULL
)
2177 callback
= noop_response_callback
;
2179 /* parse the request */
2180 if (!tr_variantDictFindStr (request
, TR_KEY_method
, &str
, NULL
))
2182 result
= "no method name";
2186 const int n
= TR_N_ELEMENTS (methods
);
2189 if (!strcmp (str
, methods
[i
].name
))
2193 result
= "method name not recognized";
2196 /* if we couldn't figure out which method to use, return an error */
2200 tr_variant response
;
2201 struct evbuffer
* buf
;
2203 tr_variantInitDict (&response
, 3);
2204 tr_variantDictAddDict (&response
, TR_KEY_arguments
, 0);
2205 tr_variantDictAddStr (&response
, TR_KEY_result
, result
);
2206 if (tr_variantDictFindInt (request
, TR_KEY_tag
, &tag
))
2207 tr_variantDictAddInt (&response
, TR_KEY_tag
, tag
);
2209 buf
= tr_variantToBuf (&response
, TR_VARIANT_FMT_JSON_LEAN
);
2210 (*callback
)(session
, buf
, callback_user_data
);
2211 evbuffer_free (buf
);
2213 tr_variantFree (&response
);
2215 else if (methods
[i
].immediate
)
2218 tr_variant response
;
2219 tr_variant
* args_out
;
2220 struct evbuffer
* buf
;
2222 tr_variantInitDict (&response
, 3);
2223 args_out
= tr_variantDictAddDict (&response
, TR_KEY_arguments
, 0);
2224 result
= (*methods
[i
].func
)(session
, args_in
, args_out
, NULL
);
2227 tr_variantDictAddStr (&response
, TR_KEY_result
, result
);
2228 if (tr_variantDictFindInt (request
, TR_KEY_tag
, &tag
))
2229 tr_variantDictAddInt (&response
, TR_KEY_tag
, tag
);
2231 buf
= tr_variantToBuf (&response
, TR_VARIANT_FMT_JSON_LEAN
);
2232 (*callback
)(session
, buf
, callback_user_data
);
2233 evbuffer_free (buf
);
2235 tr_variantFree (&response
);
2240 struct tr_rpc_idle_data
* data
= tr_new0 (struct tr_rpc_idle_data
, 1);
2241 data
->session
= session
;
2242 data
->response
= tr_new0 (tr_variant
, 1);
2243 tr_variantInitDict (data
->response
, 3);
2244 if (tr_variantDictFindInt (request
, TR_KEY_tag
, &tag
))
2245 tr_variantDictAddInt (data
->response
, TR_KEY_tag
, tag
);
2246 data
->args_out
= tr_variantDictAddDict (data
->response
, TR_KEY_arguments
, 0);
2247 data
->callback
= callback
;
2248 data
->callback_user_data
= callback_user_data
;
2249 (*methods
[i
].func
)(session
, args_in
, data
->args_out
, data
);
2254 tr_rpc_request_exec_json (tr_session
* session
,
2255 const void * request_json
,
2257 tr_rpc_response_func callback
,
2258 void * callback_user_data
)
2263 if (request_len
< 0)
2264 request_len
= strlen (request_json
);
2266 have_content
= !tr_variantFromJson (&top
, request_json
, request_len
);
2267 request_exec (session
, have_content
? &top
: NULL
, callback
, callback_user_data
);
2270 tr_variantFree (&top
);
2274 * Munge the URI into a usable form.
2276 * We have very loose typing on this to make the URIs as simple as possible:
2277 * - anything not a 'tag' or 'method' is automatically in 'arguments'
2278 * - values that are all-digits are numbers
2279 * - values that are all-digits or commas are number lists
2280 * - all other values are strings
2283 tr_rpc_parse_list_str (tr_variant
* setme
,
2289 int * values
= tr_parseNumberRange (str
, len
, &valueCount
);
2291 if (valueCount
== 0)
2293 tr_variantInitStr (setme
, str
, len
);
2295 else if (valueCount
== 1)
2297 tr_variantInitInt (setme
, values
[0]);
2303 tr_variantInitList (setme
, valueCount
);
2305 for (i
=0; i
<valueCount
; ++i
)
2306 tr_variantListAddInt (setme
, values
[i
]);
2313 tr_rpc_request_exec_uri (tr_session
* session
,
2314 const void * request_uri
,
2316 tr_rpc_response_func callback
,
2317 void * callback_user_data
)
2322 char * request
= tr_strndup (request_uri
, request_len
);
2324 tr_variantInitDict (&top
, 3);
2325 args
= tr_variantDictAddDict (&top
, TR_KEY_arguments
, 0);
2327 pch
= strchr (request
, '?');
2328 if (!pch
) pch
= request
;
2331 const char * delim
= strchr (pch
, '=');
2332 const char * next
= strchr (pch
, '&');
2335 char * key
= tr_strndup (pch
, delim
- pch
);
2336 int isArg
= strcmp (key
, "method") && strcmp (key
, "tag");
2337 tr_variant
* parent
= isArg
? args
: &top
;
2339 tr_rpc_parse_list_str (tr_variantDictAdd (parent
, tr_quark_new (key
, delim
-pch
)),
2341 next
? (size_t)(next
- (delim
+ 1)) : strlen (delim
+ 1));
2345 pch
= next
? next
+ 1 : NULL
;
2348 request_exec (session
, &top
, callback
, callback_user_data
);
2351 tr_variantFree (&top
);