1 | /* |
---|
2 | * This file Copyright (C) Mnemosyne LLC |
---|
3 | * |
---|
4 | * This program is free software; you can redistribute it and/or modify |
---|
5 | * it under the terms of the GNU General Public License version 2 |
---|
6 | * as published by the Free Software Foundation. |
---|
7 | * |
---|
8 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
---|
9 | * |
---|
10 | * $Id: session.cc 13919 2013-02-01 18:52:55Z jordan $ |
---|
11 | */ |
---|
12 | |
---|
13 | #include <cassert> |
---|
14 | #include <iostream> |
---|
15 | |
---|
16 | #include <QApplication> |
---|
17 | #include <QByteArray> |
---|
18 | #include <QClipboard> |
---|
19 | #include <QCoreApplication> |
---|
20 | #include <QDesktopServices> |
---|
21 | #include <QMessageBox> |
---|
22 | #include <QNetworkProxy> |
---|
23 | #include <QNetworkProxyFactory> |
---|
24 | #include <QNetworkReply> |
---|
25 | #include <QNetworkRequest> |
---|
26 | #include <QSet> |
---|
27 | #include <QStringList> |
---|
28 | #include <QStyle> |
---|
29 | #include <QTextStream> |
---|
30 | |
---|
31 | #include <curl/curl.h> |
---|
32 | |
---|
33 | #include <event2/buffer.h> |
---|
34 | |
---|
35 | #include <libtransmission/transmission.h> |
---|
36 | #include <libtransmission/bencode.h> |
---|
37 | #include <libtransmission/json.h> |
---|
38 | #include <libtransmission/rpcimpl.h> |
---|
39 | #include <libtransmission/utils.h> // tr_free |
---|
40 | #include <libtransmission/version.h> // LONG_VERSION |
---|
41 | #include <libtransmission/web.h> |
---|
42 | |
---|
43 | #include "add-data.h" |
---|
44 | #include "prefs.h" |
---|
45 | #include "session.h" |
---|
46 | #include "session-dialog.h" |
---|
47 | #include "torrent.h" |
---|
48 | #include "utils.h" |
---|
49 | |
---|
50 | // #define DEBUG_HTTP |
---|
51 | |
---|
52 | namespace |
---|
53 | { |
---|
54 | enum |
---|
55 | { |
---|
56 | TAG_SOME_TORRENTS, |
---|
57 | TAG_ALL_TORRENTS, |
---|
58 | TAG_SESSION_STATS, |
---|
59 | TAG_SESSION_INFO, |
---|
60 | TAG_BLOCKLIST_UPDATE, |
---|
61 | TAG_ADD_TORRENT, |
---|
62 | TAG_PORT_TEST, |
---|
63 | TAG_MAGNET_LINK, |
---|
64 | |
---|
65 | FIRST_UNIQUE_TAG |
---|
66 | }; |
---|
67 | } |
---|
68 | |
---|
69 | /*** |
---|
70 | **** |
---|
71 | ***/ |
---|
72 | |
---|
73 | namespace |
---|
74 | { |
---|
75 | typedef Torrent::KeyList KeyList; |
---|
76 | const KeyList& getInfoKeys( ) { return Torrent::getInfoKeys( ); } |
---|
77 | const KeyList& getStatKeys( ) { return Torrent::getStatKeys( ); } |
---|
78 | const KeyList& getExtraStatKeys( ) { return Torrent::getExtraStatKeys( ); } |
---|
79 | |
---|
80 | void |
---|
81 | addList( tr_benc * list, const KeyList& strings ) |
---|
82 | { |
---|
83 | tr_bencListReserve( list, strings.size( ) ); |
---|
84 | foreach( const char * str, strings ) |
---|
85 | tr_bencListAddStr( list, str ); |
---|
86 | } |
---|
87 | } |
---|
88 | |
---|
89 | /*** |
---|
90 | **** |
---|
91 | ***/ |
---|
92 | |
---|
93 | void |
---|
94 | Session :: sessionSet( const char * key, const QVariant& value ) |
---|
95 | { |
---|
96 | tr_benc top; |
---|
97 | tr_bencInitDict( &top, 2 ); |
---|
98 | tr_bencDictAddStr( &top, "method", "session-set" ); |
---|
99 | tr_benc * args( tr_bencDictAddDict( &top, "arguments", 1 ) ); |
---|
100 | switch( value.type( ) ) { |
---|
101 | case QVariant::Bool: tr_bencDictAddBool ( args, key, value.toBool() ); break; |
---|
102 | case QVariant::Int: tr_bencDictAddInt ( args, key, value.toInt() ); break; |
---|
103 | case QVariant::Double: tr_bencDictAddReal ( args, key, value.toDouble() ); break; |
---|
104 | case QVariant::String: tr_bencDictAddStr ( args, key, value.toString().toUtf8().constData() ); break; |
---|
105 | default: assert( "unknown type" ); |
---|
106 | } |
---|
107 | exec( &top ); |
---|
108 | tr_bencFree( &top ); |
---|
109 | } |
---|
110 | |
---|
111 | void |
---|
112 | Session :: portTest( ) |
---|
113 | { |
---|
114 | tr_benc top; |
---|
115 | tr_bencInitDict( &top, 2 ); |
---|
116 | tr_bencDictAddStr( &top, "method", "port-test" ); |
---|
117 | tr_bencDictAddInt( &top, "tag", TAG_PORT_TEST ); |
---|
118 | exec( &top ); |
---|
119 | tr_bencFree( &top ); |
---|
120 | } |
---|
121 | |
---|
122 | void |
---|
123 | Session :: copyMagnetLinkToClipboard( int torrentId ) |
---|
124 | { |
---|
125 | tr_benc top; |
---|
126 | tr_bencInitDict( &top, 3 ); |
---|
127 | tr_bencDictAddStr( &top, "method", "torrent-get" ); |
---|
128 | tr_bencDictAddInt( &top, "tag", TAG_MAGNET_LINK ); |
---|
129 | tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 ); |
---|
130 | tr_bencListAddInt( tr_bencDictAddList( args, "ids", 1 ), torrentId ); |
---|
131 | tr_bencListAddStr( tr_bencDictAddList( args, "fields", 1 ), "magnetLink" ); |
---|
132 | |
---|
133 | exec( &top ); |
---|
134 | tr_bencFree( &top ); |
---|
135 | } |
---|
136 | |
---|
137 | void |
---|
138 | Session :: updatePref( int key ) |
---|
139 | { |
---|
140 | if( myPrefs.isCore( key ) ) switch( key ) |
---|
141 | { |
---|
142 | case Prefs :: ALT_SPEED_LIMIT_DOWN: |
---|
143 | case Prefs :: ALT_SPEED_LIMIT_ENABLED: |
---|
144 | case Prefs :: ALT_SPEED_LIMIT_TIME_BEGIN: |
---|
145 | case Prefs :: ALT_SPEED_LIMIT_TIME_DAY: |
---|
146 | case Prefs :: ALT_SPEED_LIMIT_TIME_ENABLED: |
---|
147 | case Prefs :: ALT_SPEED_LIMIT_TIME_END: |
---|
148 | case Prefs :: ALT_SPEED_LIMIT_UP: |
---|
149 | case Prefs :: BLOCKLIST_DATE: |
---|
150 | case Prefs :: BLOCKLIST_ENABLED: |
---|
151 | case Prefs :: BLOCKLIST_URL: |
---|
152 | case Prefs :: DHT_ENABLED: |
---|
153 | case Prefs :: DOWNLOAD_DIR: |
---|
154 | case Prefs :: DOWNLOAD_QUEUE_ENABLED: |
---|
155 | case Prefs :: DOWNLOAD_QUEUE_SIZE: |
---|
156 | case Prefs :: DSPEED: |
---|
157 | case Prefs :: DSPEED_ENABLED: |
---|
158 | case Prefs :: IDLE_LIMIT: |
---|
159 | case Prefs :: IDLE_LIMIT_ENABLED: |
---|
160 | case Prefs :: INCOMPLETE_DIR: |
---|
161 | case Prefs :: INCOMPLETE_DIR_ENABLED: |
---|
162 | case Prefs :: LPD_ENABLED: |
---|
163 | case Prefs :: PEER_LIMIT_GLOBAL: |
---|
164 | case Prefs :: PEER_LIMIT_TORRENT: |
---|
165 | case Prefs :: PEER_PORT: |
---|
166 | case Prefs :: PEER_PORT_RANDOM_ON_START: |
---|
167 | case Prefs :: QUEUE_STALLED_MINUTES: |
---|
168 | case Prefs :: PEX_ENABLED: |
---|
169 | case Prefs :: PORT_FORWARDING: |
---|
170 | case Prefs :: RENAME_PARTIAL_FILES: |
---|
171 | case Prefs :: SCRIPT_TORRENT_DONE_ENABLED: |
---|
172 | case Prefs :: SCRIPT_TORRENT_DONE_FILENAME: |
---|
173 | case Prefs :: START: |
---|
174 | case Prefs :: TRASH_ORIGINAL: |
---|
175 | case Prefs :: USPEED: |
---|
176 | case Prefs :: USPEED_ENABLED: |
---|
177 | case Prefs :: UTP_ENABLED: |
---|
178 | sessionSet( myPrefs.keyStr(key), myPrefs.variant(key) ); |
---|
179 | break; |
---|
180 | |
---|
181 | case Prefs :: RATIO: |
---|
182 | sessionSet( "seedRatioLimit", myPrefs.variant(key) ); |
---|
183 | break; |
---|
184 | case Prefs :: RATIO_ENABLED: |
---|
185 | sessionSet( "seedRatioLimited", myPrefs.variant(key) ); |
---|
186 | break; |
---|
187 | |
---|
188 | case Prefs :: ENCRYPTION: |
---|
189 | { |
---|
190 | const int i = myPrefs.variant(key).toInt(); |
---|
191 | switch( i ) |
---|
192 | { |
---|
193 | case 0: |
---|
194 | sessionSet( myPrefs.keyStr(key), "tolerated" ); |
---|
195 | break; |
---|
196 | case 1: |
---|
197 | sessionSet( myPrefs.keyStr(key), "preferred" ); |
---|
198 | break; |
---|
199 | case 2: |
---|
200 | sessionSet( myPrefs.keyStr(key), "required" ); |
---|
201 | break; |
---|
202 | } |
---|
203 | break; |
---|
204 | } |
---|
205 | |
---|
206 | case Prefs :: RPC_AUTH_REQUIRED: |
---|
207 | if( mySession ) |
---|
208 | tr_sessionSetRPCPasswordEnabled( mySession, myPrefs.getBool(key) ); |
---|
209 | break; |
---|
210 | case Prefs :: RPC_ENABLED: |
---|
211 | if( mySession ) |
---|
212 | tr_sessionSetRPCEnabled( mySession, myPrefs.getBool(key) ); |
---|
213 | break; |
---|
214 | case Prefs :: RPC_PASSWORD: |
---|
215 | if( mySession ) |
---|
216 | tr_sessionSetRPCPassword( mySession, myPrefs.getString(key).toUtf8().constData() ); |
---|
217 | break; |
---|
218 | case Prefs :: RPC_PORT: |
---|
219 | if( mySession ) |
---|
220 | tr_sessionSetRPCPort( mySession, myPrefs.getInt(key) ); |
---|
221 | break; |
---|
222 | case Prefs :: RPC_USERNAME: |
---|
223 | if( mySession ) |
---|
224 | tr_sessionSetRPCUsername( mySession, myPrefs.getString(key).toUtf8().constData() ); |
---|
225 | break; |
---|
226 | case Prefs :: RPC_WHITELIST_ENABLED: |
---|
227 | if( mySession ) |
---|
228 | tr_sessionSetRPCWhitelistEnabled( mySession, myPrefs.getBool(key) ); |
---|
229 | break; |
---|
230 | case Prefs :: RPC_WHITELIST: |
---|
231 | if( mySession ) |
---|
232 | tr_sessionSetRPCWhitelist( mySession, myPrefs.getString(key).toUtf8().constData() ); |
---|
233 | break; |
---|
234 | |
---|
235 | default: |
---|
236 | std::cerr << "unhandled pref: " << key << std::endl; |
---|
237 | } |
---|
238 | } |
---|
239 | |
---|
240 | /*** |
---|
241 | **** |
---|
242 | ***/ |
---|
243 | |
---|
244 | Session :: Session( const char * configDir, Prefs& prefs ): |
---|
245 | nextUniqueTag( FIRST_UNIQUE_TAG ), |
---|
246 | myBlocklistSize( -1 ), |
---|
247 | myPrefs( prefs ), |
---|
248 | mySession( 0 ), |
---|
249 | myConfigDir( QString::fromUtf8( configDir ) ), |
---|
250 | myNAM( 0 ) |
---|
251 | { |
---|
252 | myStats.ratio = TR_RATIO_NA; |
---|
253 | myStats.uploadedBytes = 0; |
---|
254 | myStats.downloadedBytes = 0; |
---|
255 | myStats.filesAdded = 0; |
---|
256 | myStats.sessionCount = 0; |
---|
257 | myStats.secondsActive = 0; |
---|
258 | myCumulativeStats = myStats; |
---|
259 | |
---|
260 | connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(updatePref(int)) ); |
---|
261 | } |
---|
262 | |
---|
263 | Session :: ~Session( ) |
---|
264 | { |
---|
265 | stop( ); |
---|
266 | } |
---|
267 | |
---|
268 | QNetworkAccessManager * |
---|
269 | Session :: networkAccessManager( ) |
---|
270 | { |
---|
271 | if( myNAM == 0 ) |
---|
272 | { |
---|
273 | myNAM = new QNetworkAccessManager; |
---|
274 | |
---|
275 | connect( myNAM, SIGNAL(finished(QNetworkReply*)), |
---|
276 | this, SLOT(onFinished(QNetworkReply*)) ); |
---|
277 | |
---|
278 | connect( myNAM, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), |
---|
279 | this, SIGNAL(httpAuthenticationRequired()) ); |
---|
280 | } |
---|
281 | |
---|
282 | return myNAM; |
---|
283 | } |
---|
284 | |
---|
285 | /*** |
---|
286 | **** |
---|
287 | ***/ |
---|
288 | |
---|
289 | void |
---|
290 | Session :: stop( ) |
---|
291 | { |
---|
292 | if( myNAM != 0 ) |
---|
293 | { |
---|
294 | myNAM->deleteLater( ); |
---|
295 | myNAM = 0; |
---|
296 | } |
---|
297 | |
---|
298 | myUrl.clear( ); |
---|
299 | |
---|
300 | if( mySession ) |
---|
301 | { |
---|
302 | tr_sessionClose( mySession ); |
---|
303 | mySession = 0; |
---|
304 | } |
---|
305 | } |
---|
306 | |
---|
307 | void |
---|
308 | Session :: restart( ) |
---|
309 | { |
---|
310 | stop( ); |
---|
311 | start( ); |
---|
312 | } |
---|
313 | |
---|
314 | void |
---|
315 | Session :: start( ) |
---|
316 | { |
---|
317 | if( myPrefs.get<bool>(Prefs::SESSION_IS_REMOTE) ) |
---|
318 | { |
---|
319 | QUrl url; |
---|
320 | url.setScheme( "http" ); |
---|
321 | url.setHost( myPrefs.get<QString>(Prefs::SESSION_REMOTE_HOST) ); |
---|
322 | url.setPort( myPrefs.get<int>(Prefs::SESSION_REMOTE_PORT) ); |
---|
323 | url.setPath( "/transmission/rpc" ); |
---|
324 | if( myPrefs.get<bool>(Prefs::SESSION_REMOTE_AUTH) ) |
---|
325 | { |
---|
326 | url.setUserName( myPrefs.get<QString>(Prefs::SESSION_REMOTE_USERNAME) ); |
---|
327 | url.setPassword( myPrefs.get<QString>(Prefs::SESSION_REMOTE_PASSWORD) ); |
---|
328 | } |
---|
329 | myUrl = url; |
---|
330 | } |
---|
331 | else |
---|
332 | { |
---|
333 | tr_benc settings; |
---|
334 | tr_bencInitDict( &settings, 0 ); |
---|
335 | tr_sessionLoadSettings( &settings, myConfigDir.toUtf8().constData(), "qt" ); |
---|
336 | mySession = tr_sessionInit( "qt", myConfigDir.toUtf8().constData(), true, &settings ); |
---|
337 | tr_bencFree( &settings ); |
---|
338 | |
---|
339 | tr_ctor * ctor = tr_ctorNew( mySession ); |
---|
340 | int torrentCount; |
---|
341 | tr_torrent ** torrents = tr_sessionLoadTorrents( mySession, ctor, &torrentCount ); |
---|
342 | tr_free( torrents ); |
---|
343 | tr_ctorFree( ctor ); |
---|
344 | } |
---|
345 | |
---|
346 | emit sourceChanged( ); |
---|
347 | } |
---|
348 | |
---|
349 | bool |
---|
350 | Session :: isServer( ) const |
---|
351 | { |
---|
352 | return mySession != 0; |
---|
353 | } |
---|
354 | |
---|
355 | bool |
---|
356 | Session :: isLocal( ) const |
---|
357 | { |
---|
358 | if( mySession != 0 ) |
---|
359 | return true; |
---|
360 | |
---|
361 | if( myUrl.host() == "127.0.0.1" ) |
---|
362 | return true; |
---|
363 | |
---|
364 | if( !myUrl.host().compare( "localhost", Qt::CaseInsensitive ) ) |
---|
365 | return true; |
---|
366 | |
---|
367 | return false; |
---|
368 | } |
---|
369 | |
---|
370 | /*** |
---|
371 | **** |
---|
372 | ***/ |
---|
373 | |
---|
374 | namespace |
---|
375 | { |
---|
376 | tr_benc * |
---|
377 | buildRequest( const char * method, tr_benc& top, int tag=-1 ) |
---|
378 | { |
---|
379 | tr_bencInitDict( &top, 3 ); |
---|
380 | tr_bencDictAddStr( &top, "method", method ); |
---|
381 | if( tag >= 0 ) |
---|
382 | tr_bencDictAddInt( &top, "tag", tag ); |
---|
383 | return tr_bencDictAddDict( &top, "arguments", 0 ); |
---|
384 | } |
---|
385 | |
---|
386 | void |
---|
387 | addOptionalIds( tr_benc * args, const QSet<int>& ids ) |
---|
388 | { |
---|
389 | if( !ids.isEmpty( ) ) |
---|
390 | { |
---|
391 | tr_benc * idList( tr_bencDictAddList( args, "ids", ids.size( ) ) ); |
---|
392 | foreach( int i, ids ) |
---|
393 | tr_bencListAddInt( idList, i ); |
---|
394 | } |
---|
395 | } |
---|
396 | } |
---|
397 | |
---|
398 | void |
---|
399 | Session :: torrentSet( const QSet<int>& ids, const QString& key, double value ) |
---|
400 | { |
---|
401 | tr_benc top; |
---|
402 | tr_bencInitDict( &top, 2 ); |
---|
403 | tr_bencDictAddStr( &top, "method", "torrent-set" ); |
---|
404 | tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 ); |
---|
405 | tr_bencDictAddReal( args, key.toUtf8().constData(), value ); |
---|
406 | addOptionalIds( args, ids ); |
---|
407 | exec( &top ); |
---|
408 | tr_bencFree( &top ); |
---|
409 | } |
---|
410 | |
---|
411 | void |
---|
412 | Session :: torrentSet( const QSet<int>& ids, const QString& key, int value ) |
---|
413 | { |
---|
414 | tr_benc top; |
---|
415 | tr_bencInitDict( &top, 2 ); |
---|
416 | tr_bencDictAddStr( &top, "method", "torrent-set" ); |
---|
417 | tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 ); |
---|
418 | tr_bencDictAddInt( args, key.toUtf8().constData(), value ); |
---|
419 | addOptionalIds( args, ids ); |
---|
420 | exec( &top ); |
---|
421 | tr_bencFree( &top ); |
---|
422 | } |
---|
423 | |
---|
424 | void |
---|
425 | Session :: torrentSet( const QSet<int>& ids, const QString& key, bool value ) |
---|
426 | { |
---|
427 | tr_benc top; |
---|
428 | tr_bencInitDict( &top, 2 ); |
---|
429 | tr_bencDictAddStr( &top, "method", "torrent-set" ); |
---|
430 | tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 ); |
---|
431 | tr_bencDictAddBool( args, key.toUtf8().constData(), value ); |
---|
432 | addOptionalIds( args, ids ); |
---|
433 | exec( &top ); |
---|
434 | tr_bencFree( &top ); |
---|
435 | } |
---|
436 | |
---|
437 | void |
---|
438 | Session :: torrentSet( const QSet<int>& ids, const QString& key, const QStringList& value ) |
---|
439 | { |
---|
440 | tr_benc top; |
---|
441 | tr_bencInitDict( &top, 2 ); |
---|
442 | tr_bencDictAddStr( &top, "method", "torrent-set" ); |
---|
443 | tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 ); |
---|
444 | addOptionalIds( args, ids ); |
---|
445 | tr_benc * list( tr_bencDictAddList( args, key.toUtf8().constData(), value.size( ) ) ); |
---|
446 | foreach( const QString str, value ) |
---|
447 | tr_bencListAddStr( list, str.toUtf8().constData() ); |
---|
448 | exec( &top ); |
---|
449 | tr_bencFree( &top ); |
---|
450 | } |
---|
451 | |
---|
452 | void |
---|
453 | Session :: torrentSet( const QSet<int>& ids, const QString& key, const QList<int>& value ) |
---|
454 | { |
---|
455 | tr_benc top; |
---|
456 | tr_bencInitDict( &top, 2 ); |
---|
457 | tr_bencDictAddStr( &top, "method", "torrent-set" ); |
---|
458 | tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) ); |
---|
459 | addOptionalIds( args, ids ); |
---|
460 | tr_benc * list( tr_bencDictAddList( args, key.toUtf8().constData(), value.size( ) ) ); |
---|
461 | foreach( int i, value ) |
---|
462 | tr_bencListAddInt( list, i ); |
---|
463 | exec( &top ); |
---|
464 | tr_bencFree( &top ); |
---|
465 | } |
---|
466 | |
---|
467 | void |
---|
468 | Session :: torrentSet( const QSet<int>& ids, const QString& key, const QPair<int,QString>& value ) |
---|
469 | { |
---|
470 | tr_benc top; |
---|
471 | tr_bencInitDict( &top, 2 ); |
---|
472 | tr_bencDictAddStr( &top, "method", "torrent-set" ); |
---|
473 | tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) ); |
---|
474 | addOptionalIds( args, ids ); |
---|
475 | tr_benc * list( tr_bencDictAddList( args, key.toUtf8().constData(), 2 ) ); |
---|
476 | tr_bencListAddInt( list, value.first ); |
---|
477 | tr_bencListAddStr( list, value.second.toUtf8().constData() ); |
---|
478 | exec( &top ); |
---|
479 | tr_bencFree( &top ); |
---|
480 | } |
---|
481 | |
---|
482 | void |
---|
483 | Session :: torrentSetLocation( const QSet<int>& ids, const QString& location, bool doMove ) |
---|
484 | { |
---|
485 | tr_benc top; |
---|
486 | tr_bencInitDict( &top, 2 ); |
---|
487 | tr_bencDictAddStr( &top, "method", "torrent-set-location" ); |
---|
488 | tr_benc * args( tr_bencDictAddDict( &top, "arguments", 3 ) ); |
---|
489 | addOptionalIds( args, ids ); |
---|
490 | tr_bencDictAddStr( args, "location", location.toUtf8().constData() ); |
---|
491 | tr_bencDictAddBool( args, "move", doMove ); |
---|
492 | exec( &top ); |
---|
493 | tr_bencFree( &top ); |
---|
494 | } |
---|
495 | |
---|
496 | void |
---|
497 | Session :: refreshTorrents( const QSet<int>& ids ) |
---|
498 | { |
---|
499 | if( ids.empty( ) ) |
---|
500 | { |
---|
501 | refreshAllTorrents( ); |
---|
502 | } |
---|
503 | else |
---|
504 | { |
---|
505 | tr_benc top; |
---|
506 | tr_bencInitDict( &top, 3 ); |
---|
507 | tr_bencDictAddStr( &top, "method", "torrent-get" ); |
---|
508 | tr_bencDictAddInt( &top, "tag", TAG_SOME_TORRENTS ); |
---|
509 | tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) ); |
---|
510 | addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) ); |
---|
511 | addOptionalIds( args, ids ); |
---|
512 | exec( &top ); |
---|
513 | tr_bencFree( &top ); |
---|
514 | } |
---|
515 | } |
---|
516 | |
---|
517 | void |
---|
518 | Session :: refreshExtraStats( const QSet<int>& ids ) |
---|
519 | { |
---|
520 | tr_benc top; |
---|
521 | tr_bencInitDict( &top, 3 ); |
---|
522 | tr_bencDictAddStr( &top, "method", "torrent-get" ); |
---|
523 | tr_bencDictAddInt( &top, "tag", TAG_SOME_TORRENTS ); |
---|
524 | tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) ); |
---|
525 | addOptionalIds( args, ids ); |
---|
526 | addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) + getExtraStatKeys( )); |
---|
527 | exec( &top ); |
---|
528 | tr_bencFree( &top ); |
---|
529 | } |
---|
530 | |
---|
531 | void |
---|
532 | Session :: sendTorrentRequest( const char * request, const QSet<int>& ids ) |
---|
533 | { |
---|
534 | tr_benc top; |
---|
535 | tr_benc * args( buildRequest( request, top ) ); |
---|
536 | addOptionalIds( args, ids ); |
---|
537 | exec( &top ); |
---|
538 | tr_bencFree( &top ); |
---|
539 | |
---|
540 | refreshTorrents( ids ); |
---|
541 | } |
---|
542 | |
---|
543 | void Session :: pauseTorrents ( const QSet<int>& ids ) { sendTorrentRequest( "torrent-stop", ids ); } |
---|
544 | void Session :: startTorrents ( const QSet<int>& ids ) { sendTorrentRequest( "torrent-start", ids ); } |
---|
545 | void Session :: startTorrentsNow ( const QSet<int>& ids ) { sendTorrentRequest( "torrent-start-now", ids ); } |
---|
546 | void Session :: queueMoveTop ( const QSet<int>& ids ) { sendTorrentRequest( "queue-move-top", ids ); } |
---|
547 | void Session :: queueMoveUp ( const QSet<int>& ids ) { sendTorrentRequest( "queue-move-up", ids ); } |
---|
548 | void Session :: queueMoveDown ( const QSet<int>& ids ) { sendTorrentRequest( "queue-move-down", ids ); } |
---|
549 | void Session :: queueMoveBottom ( const QSet<int>& ids ) { sendTorrentRequest( "queue-move-bottom", ids ); } |
---|
550 | |
---|
551 | void |
---|
552 | Session :: refreshActiveTorrents( ) |
---|
553 | { |
---|
554 | tr_benc top; |
---|
555 | tr_bencInitDict( &top, 3 ); |
---|
556 | tr_bencDictAddStr( &top, "method", "torrent-get" ); |
---|
557 | tr_bencDictAddInt( &top, "tag", TAG_SOME_TORRENTS ); |
---|
558 | tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) ); |
---|
559 | tr_bencDictAddStr( args, "ids", "recently-active" ); |
---|
560 | addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) ); |
---|
561 | exec( &top ); |
---|
562 | tr_bencFree( &top ); |
---|
563 | } |
---|
564 | |
---|
565 | void |
---|
566 | Session :: refreshAllTorrents( ) |
---|
567 | { |
---|
568 | tr_benc top; |
---|
569 | tr_bencInitDict( &top, 3 ); |
---|
570 | tr_bencDictAddStr( &top, "method", "torrent-get" ); |
---|
571 | tr_bencDictAddInt( &top, "tag", TAG_ALL_TORRENTS ); |
---|
572 | tr_benc * args( tr_bencDictAddDict( &top, "arguments", 1 ) ); |
---|
573 | addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) ); |
---|
574 | exec( &top ); |
---|
575 | tr_bencFree( &top ); |
---|
576 | } |
---|
577 | |
---|
578 | void |
---|
579 | Session :: initTorrents( const QSet<int>& ids ) |
---|
580 | { |
---|
581 | tr_benc top; |
---|
582 | const int tag( ids.isEmpty() ? TAG_ALL_TORRENTS : TAG_SOME_TORRENTS ); |
---|
583 | tr_benc * args( buildRequest( "torrent-get", top, tag ) ); |
---|
584 | addOptionalIds( args, ids ); |
---|
585 | addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys()+getInfoKeys() ); |
---|
586 | exec( &top ); |
---|
587 | tr_bencFree( &top ); |
---|
588 | } |
---|
589 | |
---|
590 | void |
---|
591 | Session :: refreshSessionStats( ) |
---|
592 | { |
---|
593 | tr_benc top; |
---|
594 | tr_bencInitDict( &top, 2 ); |
---|
595 | tr_bencDictAddStr( &top, "method", "session-stats" ); |
---|
596 | tr_bencDictAddInt( &top, "tag", TAG_SESSION_STATS ); |
---|
597 | exec( &top ); |
---|
598 | tr_bencFree( &top ); |
---|
599 | } |
---|
600 | |
---|
601 | void |
---|
602 | Session :: refreshSessionInfo( ) |
---|
603 | { |
---|
604 | tr_benc top; |
---|
605 | tr_bencInitDict( &top, 2 ); |
---|
606 | tr_bencDictAddStr( &top, "method", "session-get" ); |
---|
607 | tr_bencDictAddInt( &top, "tag", TAG_SESSION_INFO ); |
---|
608 | exec( &top ); |
---|
609 | tr_bencFree( &top ); |
---|
610 | } |
---|
611 | |
---|
612 | void |
---|
613 | Session :: updateBlocklist( ) |
---|
614 | { |
---|
615 | tr_benc top; |
---|
616 | tr_bencInitDict( &top, 2 ); |
---|
617 | tr_bencDictAddStr( &top, "method", "blocklist-update" ); |
---|
618 | tr_bencDictAddInt( &top, "tag", TAG_BLOCKLIST_UPDATE ); |
---|
619 | exec( &top ); |
---|
620 | tr_bencFree( &top ); |
---|
621 | } |
---|
622 | |
---|
623 | /*** |
---|
624 | **** |
---|
625 | ***/ |
---|
626 | |
---|
627 | void |
---|
628 | Session :: exec( const tr_benc * request ) |
---|
629 | { |
---|
630 | char * str = tr_bencToStr( request, TR_FMT_JSON_LEAN, NULL ); |
---|
631 | exec( str ); |
---|
632 | tr_free( str ); |
---|
633 | } |
---|
634 | |
---|
635 | void |
---|
636 | Session :: localSessionCallback( tr_session * session, struct evbuffer * json, void * self ) |
---|
637 | { |
---|
638 | Q_UNUSED( session ); |
---|
639 | |
---|
640 | ((Session*)self)->parseResponse( (const char*) evbuffer_pullup( json, -1 ), evbuffer_get_length( json ) ); |
---|
641 | } |
---|
642 | |
---|
643 | #define REQUEST_DATA_PROPERTY_KEY "requestData" |
---|
644 | |
---|
645 | void |
---|
646 | Session :: exec( const char * json ) |
---|
647 | { |
---|
648 | if( mySession ) |
---|
649 | { |
---|
650 | tr_rpc_request_exec_json( mySession, json, strlen( json ), localSessionCallback, this ); |
---|
651 | } |
---|
652 | else if( !myUrl.isEmpty( ) ) |
---|
653 | { |
---|
654 | QNetworkRequest request; |
---|
655 | request.setUrl( myUrl ); |
---|
656 | request.setRawHeader( "User-Agent", QString( QCoreApplication::instance()->applicationName() + "/" + LONG_VERSION_STRING ).toAscii() ); |
---|
657 | request.setRawHeader( "Content-Type", "application/json; charset=UTF-8" ); |
---|
658 | if( !mySessionId.isEmpty( ) ) |
---|
659 | request.setRawHeader( TR_RPC_SESSION_ID_HEADER, mySessionId.toAscii() ); |
---|
660 | |
---|
661 | const QByteArray requestData( json ); |
---|
662 | QNetworkReply * reply = networkAccessManager()->post( request, requestData ); |
---|
663 | reply->setProperty( REQUEST_DATA_PROPERTY_KEY, requestData ); |
---|
664 | connect( reply, SIGNAL(downloadProgress(qint64,qint64)), this, SIGNAL(dataReadProgress())); |
---|
665 | connect( reply, SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(dataSendProgress())); |
---|
666 | |
---|
667 | #ifdef DEBUG_HTTP |
---|
668 | std::cerr << "sending " << "POST " << qPrintable( myUrl.path() ) << std::endl; |
---|
669 | foreach( QByteArray b, request.rawHeaderList() ) |
---|
670 | std::cerr << b.constData() |
---|
671 | << ": " |
---|
672 | << request.rawHeader( b ).constData() |
---|
673 | << std::endl; |
---|
674 | std::cerr << "Body:\n" << json << std::endl; |
---|
675 | #endif |
---|
676 | } |
---|
677 | } |
---|
678 | |
---|
679 | void |
---|
680 | Session :: onFinished( QNetworkReply * reply ) |
---|
681 | { |
---|
682 | #ifdef DEBUG_HTTP |
---|
683 | std::cerr << "http response header: " << std::endl; |
---|
684 | foreach( QByteArray b, reply->rawHeaderList() ) |
---|
685 | std::cerr << b.constData() |
---|
686 | << ": " |
---|
687 | << reply->rawHeader( b ).constData() |
---|
688 | << std::endl; |
---|
689 | std::cerr << "json:\n" << reply->peek( reply->bytesAvailable() ).constData() << std::endl; |
---|
690 | #endif |
---|
691 | |
---|
692 | if( ( reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt() == 409 ) |
---|
693 | && ( reply->hasRawHeader( TR_RPC_SESSION_ID_HEADER ) ) ) |
---|
694 | { |
---|
695 | // we got a 409 telling us our session id has expired. |
---|
696 | // update it and resubmit the request. |
---|
697 | mySessionId = QString( reply->rawHeader( TR_RPC_SESSION_ID_HEADER ) ); |
---|
698 | exec( reply->property( REQUEST_DATA_PROPERTY_KEY ).toByteArray( ).constData( ) ); |
---|
699 | } |
---|
700 | else if( reply->error() != QNetworkReply::NoError ) |
---|
701 | { |
---|
702 | std::cerr << "http error: " << qPrintable( reply->errorString() ) << std::endl; |
---|
703 | } |
---|
704 | else |
---|
705 | { |
---|
706 | const QByteArray response( reply->readAll() ); |
---|
707 | const char * json( response.constData( ) ); |
---|
708 | int jsonLength( response.size( ) ); |
---|
709 | if( jsonLength>0 && json[jsonLength-1] == '\n' ) --jsonLength; |
---|
710 | parseResponse( json, jsonLength ); |
---|
711 | } |
---|
712 | |
---|
713 | reply->deleteLater(); |
---|
714 | } |
---|
715 | |
---|
716 | void |
---|
717 | Session :: parseResponse( const char * json, size_t jsonLength ) |
---|
718 | { |
---|
719 | tr_benc top; |
---|
720 | const uint8_t * end( 0 ); |
---|
721 | const int err( tr_jsonParse( "rpc", json, jsonLength, &top, &end ) ); |
---|
722 | if( !err ) |
---|
723 | { |
---|
724 | int64_t tag = -1; |
---|
725 | const char * result = NULL; |
---|
726 | tr_benc * args = NULL; |
---|
727 | |
---|
728 | tr_bencDictFindInt ( &top, "tag", &tag ); |
---|
729 | tr_bencDictFindStr ( &top, "result", &result ); |
---|
730 | tr_bencDictFindDict( &top, "arguments", &args ); |
---|
731 | |
---|
732 | emit executed( tag, result, args ); |
---|
733 | |
---|
734 | tr_benc * torrents; |
---|
735 | const char * str; |
---|
736 | |
---|
737 | if( tr_bencDictFindInt( &top, "tag", &tag ) ) |
---|
738 | { |
---|
739 | switch( tag ) |
---|
740 | { |
---|
741 | case TAG_SOME_TORRENTS: |
---|
742 | case TAG_ALL_TORRENTS: |
---|
743 | if( tr_bencDictFindDict( &top, "arguments", &args ) ) { |
---|
744 | if( tr_bencDictFindList( args, "torrents", &torrents ) ) |
---|
745 | emit torrentsUpdated( torrents, tag==TAG_ALL_TORRENTS ); |
---|
746 | if( tr_bencDictFindList( args, "removed", &torrents ) ) |
---|
747 | emit torrentsRemoved( torrents ); |
---|
748 | } |
---|
749 | break; |
---|
750 | |
---|
751 | case TAG_SESSION_STATS: |
---|
752 | if( tr_bencDictFindDict( &top, "arguments", &args ) ) |
---|
753 | updateStats( args ); |
---|
754 | break; |
---|
755 | |
---|
756 | case TAG_SESSION_INFO: |
---|
757 | if( tr_bencDictFindDict( &top, "arguments", &args ) ) |
---|
758 | updateInfo( args ); |
---|
759 | break; |
---|
760 | |
---|
761 | case TAG_BLOCKLIST_UPDATE: { |
---|
762 | int64_t intVal = 0; |
---|
763 | if( tr_bencDictFindDict( &top, "arguments", &args ) ) |
---|
764 | if( tr_bencDictFindInt( args, "blocklist-size", &intVal ) ) |
---|
765 | setBlocklistSize( intVal ); |
---|
766 | break; |
---|
767 | } |
---|
768 | |
---|
769 | case TAG_PORT_TEST: { |
---|
770 | bool isOpen = 0; |
---|
771 | if( tr_bencDictFindDict( &top, "arguments", &args ) ) |
---|
772 | tr_bencDictFindBool( args, "port-is-open", &isOpen ); |
---|
773 | emit portTested( (bool)isOpen ); |
---|
774 | } |
---|
775 | |
---|
776 | case TAG_MAGNET_LINK: { |
---|
777 | tr_benc * args; |
---|
778 | tr_benc * torrents; |
---|
779 | tr_benc * child; |
---|
780 | const char * str; |
---|
781 | if( tr_bencDictFindDict( &top, "arguments", &args ) |
---|
782 | && tr_bencDictFindList( args, "torrents", &torrents ) |
---|
783 | && (( child = tr_bencListChild( torrents, 0 ))) |
---|
784 | && tr_bencDictFindStr( child, "magnetLink", &str ) ) |
---|
785 | QApplication::clipboard()->setText( str ); |
---|
786 | break; |
---|
787 | } |
---|
788 | |
---|
789 | case TAG_ADD_TORRENT: |
---|
790 | str = ""; |
---|
791 | if( tr_bencDictFindStr( &top, "result", &str ) && strcmp( str, "success" ) ) { |
---|
792 | QMessageBox * d = new QMessageBox( QMessageBox::Information, |
---|
793 | tr( "Add Torrent" ), |
---|
794 | QString::fromUtf8(str), |
---|
795 | QMessageBox::Close, |
---|
796 | QApplication::activeWindow()); |
---|
797 | connect( d, SIGNAL(rejected()), d, SLOT(deleteLater()) ); |
---|
798 | d->show( ); |
---|
799 | } |
---|
800 | break; |
---|
801 | |
---|
802 | default: |
---|
803 | break; |
---|
804 | } |
---|
805 | } |
---|
806 | tr_bencFree( &top ); |
---|
807 | } |
---|
808 | } |
---|
809 | |
---|
810 | void |
---|
811 | Session :: updateStats( tr_benc * d, struct tr_session_stats * stats ) |
---|
812 | { |
---|
813 | int64_t i; |
---|
814 | |
---|
815 | if( tr_bencDictFindInt( d, "uploadedBytes", &i ) ) |
---|
816 | stats->uploadedBytes = i; |
---|
817 | if( tr_bencDictFindInt( d, "downloadedBytes", &i ) ) |
---|
818 | stats->downloadedBytes = i; |
---|
819 | if( tr_bencDictFindInt( d, "filesAdded", &i ) ) |
---|
820 | stats->filesAdded = i; |
---|
821 | if( tr_bencDictFindInt( d, "sessionCount", &i ) ) |
---|
822 | stats->sessionCount = i; |
---|
823 | if( tr_bencDictFindInt( d, "secondsActive", &i ) ) |
---|
824 | stats->secondsActive = i; |
---|
825 | |
---|
826 | stats->ratio = tr_getRatio( stats->uploadedBytes, stats->downloadedBytes ); |
---|
827 | |
---|
828 | } |
---|
829 | |
---|
830 | void |
---|
831 | Session :: updateStats( tr_benc * d ) |
---|
832 | { |
---|
833 | tr_benc * c; |
---|
834 | |
---|
835 | if( tr_bencDictFindDict( d, "current-stats", &c ) ) |
---|
836 | updateStats( c, &myStats ); |
---|
837 | |
---|
838 | if( tr_bencDictFindDict( d, "cumulative-stats", &c ) ) |
---|
839 | updateStats( c, &myCumulativeStats ); |
---|
840 | |
---|
841 | emit statsUpdated( ); |
---|
842 | } |
---|
843 | |
---|
844 | void |
---|
845 | Session :: updateInfo( tr_benc * d ) |
---|
846 | { |
---|
847 | int64_t i; |
---|
848 | const char * str; |
---|
849 | disconnect( &myPrefs, SIGNAL(changed(int)), this, SLOT(updatePref(int)) ); |
---|
850 | |
---|
851 | for( int i=Prefs::FIRST_CORE_PREF; i<=Prefs::LAST_CORE_PREF; ++i ) |
---|
852 | { |
---|
853 | const tr_benc * b( tr_bencDictFind( d, myPrefs.keyStr( i ) ) ); |
---|
854 | |
---|
855 | if( !b ) |
---|
856 | continue; |
---|
857 | |
---|
858 | if( i == Prefs :: ENCRYPTION ) |
---|
859 | { |
---|
860 | const char * val; |
---|
861 | if( tr_bencGetStr( b, &val ) ) |
---|
862 | { |
---|
863 | if( !qstrcmp( val , "required" ) ) |
---|
864 | myPrefs.set( i, 2 ); |
---|
865 | else if( !qstrcmp( val , "preferred" ) ) |
---|
866 | myPrefs.set( i, 1 ); |
---|
867 | else if( !qstrcmp( val , "tolerated" ) ) |
---|
868 | myPrefs.set( i, 0 ); |
---|
869 | } |
---|
870 | continue; |
---|
871 | } |
---|
872 | |
---|
873 | switch( myPrefs.type( i ) ) |
---|
874 | { |
---|
875 | case QVariant :: Int: { |
---|
876 | int64_t val; |
---|
877 | if( tr_bencGetInt( b, &val ) ) |
---|
878 | myPrefs.set( i, (int)val ); |
---|
879 | break; |
---|
880 | } |
---|
881 | case QVariant :: Double: { |
---|
882 | double val; |
---|
883 | if( tr_bencGetReal( b, &val ) ) |
---|
884 | myPrefs.set( i, val ); |
---|
885 | break; |
---|
886 | } |
---|
887 | case QVariant :: Bool: { |
---|
888 | bool val; |
---|
889 | if( tr_bencGetBool( b, &val ) ) |
---|
890 | myPrefs.set( i, (bool)val ); |
---|
891 | break; |
---|
892 | } |
---|
893 | case TrTypes :: FilterModeType: |
---|
894 | case TrTypes :: SortModeType: |
---|
895 | case QVariant :: String: { |
---|
896 | const char * val; |
---|
897 | if( tr_bencGetStr( b, &val ) ) |
---|
898 | myPrefs.set( i, QString(val) ); |
---|
899 | break; |
---|
900 | } |
---|
901 | default: |
---|
902 | break; |
---|
903 | } |
---|
904 | } |
---|
905 | |
---|
906 | bool b; |
---|
907 | double x; |
---|
908 | if( tr_bencDictFindBool( d, "seedRatioLimited", &b ) ) |
---|
909 | myPrefs.set( Prefs::RATIO_ENABLED, b ? true : false ); |
---|
910 | if( tr_bencDictFindReal( d, "seedRatioLimit", &x ) ) |
---|
911 | myPrefs.set( Prefs::RATIO, x ); |
---|
912 | |
---|
913 | /* Use the C API to get settings that, for security reasons, aren't supported by RPC */ |
---|
914 | if( mySession != 0 ) |
---|
915 | { |
---|
916 | myPrefs.set( Prefs::RPC_ENABLED, tr_sessionIsRPCEnabled ( mySession ) ); |
---|
917 | myPrefs.set( Prefs::RPC_AUTH_REQUIRED, tr_sessionIsRPCPasswordEnabled ( mySession ) ); |
---|
918 | myPrefs.set( Prefs::RPC_PASSWORD, tr_sessionGetRPCPassword ( mySession ) ); |
---|
919 | myPrefs.set( Prefs::RPC_PORT, tr_sessionGetRPCPort ( mySession ) ); |
---|
920 | myPrefs.set( Prefs::RPC_USERNAME, tr_sessionGetRPCUsername ( mySession ) ); |
---|
921 | myPrefs.set( Prefs::RPC_WHITELIST_ENABLED, tr_sessionGetRPCWhitelistEnabled ( mySession ) ); |
---|
922 | myPrefs.set( Prefs::RPC_WHITELIST, tr_sessionGetRPCWhitelist ( mySession ) ); |
---|
923 | } |
---|
924 | |
---|
925 | if( tr_bencDictFindInt( d, "blocklist-size", &i ) && i!=blocklistSize( ) ) |
---|
926 | setBlocklistSize( i ); |
---|
927 | |
---|
928 | if( tr_bencDictFindStr( d, "version", &str ) && ( mySessionVersion != str ) ) |
---|
929 | mySessionVersion = str; |
---|
930 | |
---|
931 | //std::cerr << "Session :: updateInfo end" << std::endl; |
---|
932 | connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(updatePref(int)) ); |
---|
933 | |
---|
934 | emit sessionUpdated( ); |
---|
935 | } |
---|
936 | |
---|
937 | void |
---|
938 | Session :: setBlocklistSize( int64_t i ) |
---|
939 | { |
---|
940 | myBlocklistSize = i; |
---|
941 | |
---|
942 | emit blocklistUpdated( i ); |
---|
943 | } |
---|
944 | |
---|
945 | void |
---|
946 | Session :: addTorrent( const AddData& addMe ) |
---|
947 | { |
---|
948 | const QByteArray b64 = addMe.toBase64(); |
---|
949 | |
---|
950 | tr_benc top, *args; |
---|
951 | tr_bencInitDict( &top, 2 ); |
---|
952 | tr_bencDictAddStr( &top, "method", "torrent-add" ); |
---|
953 | args = tr_bencDictAddDict( &top, "arguments", 2 ); |
---|
954 | tr_bencDictAddBool( args, "paused", !myPrefs.getBool( Prefs::START ) ); |
---|
955 | switch( addMe.type ) { |
---|
956 | case AddData::MAGNET: tr_bencDictAddStr( args, "filename", addMe.magnet.toUtf8().constData() ); break; |
---|
957 | case AddData::URL: tr_bencDictAddStr( args, "filename", addMe.url.toString().toUtf8().constData() ); break; |
---|
958 | case AddData::FILENAME: /* fall-through */ |
---|
959 | case AddData::METAINFO: tr_bencDictAddRaw( args, "metainfo", b64.constData(), b64.size() ); break; |
---|
960 | default: std::cerr << "Unhandled AddData type: " << addMe.type << std::endl; |
---|
961 | } |
---|
962 | exec( &top ); |
---|
963 | tr_bencFree( &top ); |
---|
964 | } |
---|
965 | |
---|
966 | void |
---|
967 | Session :: addNewlyCreatedTorrent( const QString& filename, const QString& localPath ) |
---|
968 | { |
---|
969 | const QByteArray b64 = AddData(filename).toBase64(); |
---|
970 | const QByteArray localPathUtf8 = localPath.toUtf8(); |
---|
971 | |
---|
972 | tr_benc top, *args; |
---|
973 | tr_bencInitDict( &top, 2 ); |
---|
974 | tr_bencDictAddStr( &top, "method", "torrent-add" ); |
---|
975 | args = tr_bencDictAddDict( &top, "arguments", 3 ); |
---|
976 | tr_bencDictAddStr( args, "download-dir", localPathUtf8.constData() ); |
---|
977 | tr_bencDictAddBool( args, "paused", !myPrefs.getBool( Prefs::START ) ); |
---|
978 | tr_bencDictAddRaw( args, "metainfo", b64.constData(), b64.size() ); |
---|
979 | exec( &top ); |
---|
980 | tr_bencFree( &top ); |
---|
981 | } |
---|
982 | |
---|
983 | void |
---|
984 | Session :: removeTorrents( const QSet<int>& ids, bool deleteFiles ) |
---|
985 | { |
---|
986 | if( !ids.isEmpty( ) ) |
---|
987 | { |
---|
988 | tr_benc top, *args; |
---|
989 | tr_bencInitDict( &top, 2 ); |
---|
990 | tr_bencDictAddStr( &top, "method", "torrent-remove" ); |
---|
991 | args = tr_bencDictAddDict( &top, "arguments", 2 ); |
---|
992 | addOptionalIds( args, ids ); |
---|
993 | tr_bencDictAddInt( args, "delete-local-data", deleteFiles ); |
---|
994 | exec( &top ); |
---|
995 | tr_bencFree( &top ); |
---|
996 | } |
---|
997 | } |
---|
998 | |
---|
999 | void |
---|
1000 | Session :: verifyTorrents( const QSet<int>& ids ) |
---|
1001 | { |
---|
1002 | if( !ids.isEmpty( ) ) |
---|
1003 | { |
---|
1004 | tr_benc top, *args; |
---|
1005 | tr_bencInitDict( &top, 2 ); |
---|
1006 | tr_bencDictAddStr( &top, "method", "torrent-verify" ); |
---|
1007 | args = tr_bencDictAddDict( &top, "arguments", 1 ); |
---|
1008 | addOptionalIds( args, ids ); |
---|
1009 | exec( &top ); |
---|
1010 | tr_bencFree( &top ); |
---|
1011 | } |
---|
1012 | } |
---|
1013 | |
---|
1014 | void |
---|
1015 | Session :: reannounceTorrents( const QSet<int>& ids ) |
---|
1016 | { |
---|
1017 | if( !ids.isEmpty( ) ) |
---|
1018 | { |
---|
1019 | tr_benc top, *args; |
---|
1020 | tr_bencInitDict( &top, 2 ); |
---|
1021 | tr_bencDictAddStr( &top, "method", "torrent-reannounce" ); |
---|
1022 | args = tr_bencDictAddDict( &top, "arguments", 1 ); |
---|
1023 | addOptionalIds( args, ids ); |
---|
1024 | exec( &top ); |
---|
1025 | tr_bencFree( &top ); |
---|
1026 | } |
---|
1027 | } |
---|
1028 | |
---|
1029 | /*** |
---|
1030 | **** |
---|
1031 | ***/ |
---|
1032 | |
---|
1033 | void |
---|
1034 | Session :: launchWebInterface( ) |
---|
1035 | { |
---|
1036 | QUrl url; |
---|
1037 | if( !mySession ) // remote session |
---|
1038 | { |
---|
1039 | url = myUrl; |
---|
1040 | url.setPath( "/transmission/web/" ); |
---|
1041 | } |
---|
1042 | else // local session |
---|
1043 | { |
---|
1044 | url.setScheme( "http" ); |
---|
1045 | url.setHost( "localhost" ); |
---|
1046 | url.setPort( myPrefs.getInt( Prefs::RPC_PORT ) ); |
---|
1047 | } |
---|
1048 | QDesktopServices :: openUrl( url ); |
---|
1049 | } |
---|