source: trunk/qt/session.cc @ 8323

Last change on this file since 8323 was 8323, checked in by charles, 13 years ago

(trunk qt) Remember between runs whether we were running a local or remote session. Add a gui dialog for switching sessions during runtime.

File size: 24.8 KB
Line 
1/*
2 * This file Copyright (C) 2009 Charles Kerr <charles@transmissionbt.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id:$
11 */
12
13#include <cassert>
14#include <iostream>
15
16#include <QApplication>
17#include <QByteArray>
18#include <QCoreApplication>
19#include <QDesktopServices>
20#include <QMessageBox>
21#include <QSet>
22#include <QStyle>
23#include <QTextStream>
24
25#include <libtransmission/transmission.h>
26#include <libtransmission/bencode.h>
27#include <libtransmission/json.h>
28#include <libtransmission/rpcimpl.h>
29#include <libtransmission/utils.h> /* tr_free */
30#include <libtransmission/version.h> /* LONG_VERSION */
31
32#include "prefs.h"
33#include "qticonloader.h"
34#include "session.h"
35#include "session-dialog.h"
36#include "torrent.h"
37
38// #define DEBUG_HTTP
39
40namespace
41{
42    enum
43    {
44        TAG_SOME_TORRENTS,
45        TAG_ALL_TORRENTS,
46        TAG_SESSION_STATS,
47        TAG_SESSION_INFO,
48        TAG_BLOCKLIST_UPDATE,
49        TAG_ADD_TORRENT,
50        TAG_PORT_TEST
51    };
52}
53
54/***
55****
56***/
57
58namespace
59{
60    typedef Torrent::KeyList KeyList;
61    const KeyList& getInfoKeys( ) { return Torrent::getInfoKeys( ); }
62    const KeyList& getStatKeys( ) { return Torrent::getStatKeys( ); }
63    const KeyList& getExtraStatKeys( ) { return Torrent::getExtraStatKeys( ); }
64
65    void
66    addList( tr_benc * list, const KeyList& strings )
67    {
68        tr_bencListReserve( list, strings.size( ) );
69        foreach( const char * str, strings )
70            tr_bencListAddStr( list, str );
71    }
72}
73
74/***
75****
76***/
77
78void
79Session :: sessionSet( const char * key, const QVariant& value )
80{
81    tr_benc top;
82    tr_bencInitDict( &top, 2 );
83    tr_bencDictAddStr( &top, "method", "session-set" );
84    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 1 ) );
85    switch( value.type( ) ) {
86        case QVariant::Bool:   tr_bencDictAddBool ( args, key, value.toBool() ); break;
87        case QVariant::Int:    tr_bencDictAddInt  ( args, key, value.toInt() ); break;
88        case QVariant::Double: tr_bencDictAddReal ( args, key, value.toDouble() ); break;
89        case QVariant::String: tr_bencDictAddStr  ( args, key, value.toString().toUtf8() ); break;
90        default: assert( "unknown type" );
91    }
92std::cerr << tr_bencToJSON(&top) << std::endl;
93    exec( &top );
94    tr_bencFree( &top );
95}
96
97void
98Session :: portTest( )
99{
100    tr_benc top;
101    tr_bencInitDict( &top, 2 );
102    tr_bencDictAddStr( &top, "method", "port-test" );
103    tr_bencDictAddInt( &top, "tag", TAG_PORT_TEST );
104    exec( &top );
105    tr_bencFree( &top );
106}
107
108void
109Session :: updatePref( int key )
110{
111    if( myPrefs.isCore( key ) ) switch( key )
112    {
113        case Prefs :: ALT_SPEED_LIMIT_UP:
114        case Prefs :: ALT_SPEED_LIMIT_DOWN:
115        case Prefs :: ALT_SPEED_LIMIT_ENABLED:
116        case Prefs :: ALT_SPEED_LIMIT_TIME_BEGIN:
117        case Prefs :: ALT_SPEED_LIMIT_TIME_END:
118        case Prefs :: ALT_SPEED_LIMIT_TIME_ENABLED:
119        case Prefs :: ALT_SPEED_LIMIT_TIME_DAY:
120        case Prefs :: BLOCKLIST_ENABLED:
121        case Prefs :: BLOCKLIST_DATE:
122        case Prefs :: DOWNLOAD_DIR:
123        case Prefs :: PEER_LIMIT_GLOBAL:
124        case Prefs :: PEER_LIMIT_TORRENT:
125        case Prefs :: SEED_RATIO_LIMIT:
126        case Prefs :: SEED_RATIO_LIMITED:
127        case Prefs :: USPEED_ENABLED:
128        case Prefs :: USPEED:
129        case Prefs :: DSPEED_ENABLED:
130        case Prefs :: DSPEED:
131        case Prefs :: PEX_ENABLED:
132        case Prefs :: PORT_FORWARDING:
133        case Prefs :: PEER_PORT:
134        case Prefs :: PEER_PORT_RANDOM_ON_START:
135        case Prefs :: RATIO:
136        case Prefs :: RATIO_ENABLED:
137            sessionSet( myPrefs.keyStr(key), myPrefs.variant(key) );
138            break;
139
140        case Prefs :: RPC_AUTH_REQUIRED:
141            if( mySession )
142                tr_sessionSetRPCEnabled( mySession, myPrefs.getBool(key) );
143            break;
144        case Prefs :: RPC_ENABLED:
145            if( mySession )
146                tr_sessionSetRPCEnabled( mySession, myPrefs.getBool(key) );
147            break;
148        case Prefs :: RPC_PASSWORD:
149            if( mySession )
150                tr_sessionSetRPCPassword( mySession, myPrefs.getString(key).toUtf8().constData() );
151            break;
152        case Prefs :: RPC_PORT:
153            if( mySession )
154                tr_sessionSetRPCPort( mySession, myPrefs.getInt(key) );
155            break;
156        case Prefs :: RPC_USERNAME:
157            if( mySession )
158                tr_sessionSetRPCUsername( mySession, myPrefs.getString(key).toUtf8().constData() );
159            break;
160        case Prefs :: RPC_WHITELIST_ENABLED:
161            if( mySession )
162                tr_sessionSetRPCWhitelistEnabled( mySession, myPrefs.getBool(key) );
163            break;
164        case Prefs :: RPC_WHITELIST:
165            if( mySession )
166                tr_sessionSetRPCWhitelist( mySession, myPrefs.getString(key).toUtf8().constData() );
167            break;
168
169        default:
170            std::cerr << "unhandled pref: " << key << std::endl;
171    }
172}
173
174/***
175****
176***/
177
178Session :: Session( const char * configDir, Prefs& prefs ):
179    myBlocklistSize( -1 ),
180    myPrefs( prefs ),
181    mySession( 0 ),
182    myConfigDir( configDir )
183{
184    myStats.ratio = TR_RATIO_NA;
185    myStats.uploadedBytes = 0;
186    myStats.downloadedBytes = 0;
187    myStats.filesAdded = 0;
188    myStats.sessionCount = 0;
189    myStats.secondsActive = 0;
190    myCumulativeStats = myStats;
191
192    connect( &myHttp, SIGNAL(requestStarted(int)), this, SLOT(onRequestStarted(int)));
193    connect( &myHttp, SIGNAL(requestFinished(int,bool)), this, SLOT(onRequestFinished(int,bool)));
194    connect( &myHttp, SIGNAL(dataReadProgress(int,int)), this, SIGNAL(dataReadProgress()));
195    connect( &myHttp, SIGNAL(dataSendProgress(int,int)), this, SIGNAL(dataSendProgress()));
196    connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(updatePref(int)) );
197
198    myBuffer.open( QIODevice::ReadWrite );
199}
200
201Session :: ~Session( )
202{
203    stop( );
204}
205
206/***
207****
208***/
209
210void
211Session :: stop( )
212{
213    myHttp.abort( );
214    myUrl.clear( );
215
216    if( mySession )
217    {
218        tr_sessionClose( mySession );
219        mySession = 0;
220    }
221}
222
223void
224Session :: restart( )
225{
226    stop( );
227    start( );
228}
229
230void
231Session :: start( )
232{
233    if( myPrefs.get<bool>(Prefs::SESSION_IS_REMOTE) )
234    {
235        const int port( myPrefs.get<int>(Prefs::SESSION_REMOTE_PORT) );
236        const bool auth( myPrefs.get<bool>(Prefs::SESSION_REMOTE_AUTH) );
237        const QString host( myPrefs.get<QString>(Prefs::SESSION_REMOTE_HOST) );
238        const QString user( myPrefs.get<QString>(Prefs::SESSION_REMOTE_USERNAME) );
239        const QString pass( myPrefs.get<QString>(Prefs::SESSION_REMOTE_PASSWORD) );
240
241        QUrl url;
242        url.setScheme( "http" );
243        url.setHost( host );
244        url.setPort( port );
245        if( auth ) {
246            url.setUserName( user );
247            url.setPassword( pass );
248        }
249        myUrl = url;
250
251        myHttp.setHost( host, port );
252        myHttp.setUser( user, pass );
253    }
254    else
255    {
256        tr_benc settings;
257        tr_bencInitDict( &settings, 0 );
258        tr_sessionGetDefaultSettings( &settings );
259        tr_sessionLoadSettings( &settings, myConfigDir.toUtf8().constData(), "qt" );
260        mySession = tr_sessionInit( "qt", myConfigDir.toUtf8().constData(), true, &settings );
261        tr_bencFree( &settings );
262
263        tr_ctor * ctor = tr_ctorNew( mySession );
264        int torrentCount;
265        tr_torrent ** torrents = tr_sessionLoadTorrents( mySession, ctor, &torrentCount );
266        tr_free( torrents );
267        tr_ctorFree( ctor );
268    }
269
270    emit sourceChanged( );
271}
272
273bool
274Session :: isServer( ) const
275{
276    return mySession != 0;
277}
278
279bool
280Session :: isLocal( ) const
281{
282    if( mySession != 0 )
283        return true;
284
285    if( myUrl.host() == "127.0.0.1" )
286        return true;
287
288    if( !myUrl.host().compare( "localhost", Qt::CaseInsensitive ) )
289        return true;
290
291    return false;
292}
293
294/***
295****
296***/
297
298namespace
299{
300    tr_benc *
301    buildRequest( const char * method, tr_benc& top, int tag=-1 )
302    {
303        tr_bencInitDict( &top, 3 );
304        tr_bencDictAddStr( &top, "method", method );
305        if( tag >= 0 )
306            tr_bencDictAddInt( &top, "tag", tag );
307        return tr_bencDictAddDict( &top, "arguments", 0 );
308    }
309
310    void
311    addOptionalIds( tr_benc * args, const QSet<int>& ids )
312    {
313        if( !ids.isEmpty( ) )
314        {
315            tr_benc * idList( tr_bencDictAddList( args, "ids", ids.size( ) ) );
316            foreach( int i, ids )
317                tr_bencListAddInt( idList, i );
318        }
319    }
320}
321
322const int Session :: ADD_TORRENT_TAG = TAG_ADD_TORRENT;
323
324void
325Session :: torrentSet( const QSet<int>& ids, const QString& key, double value )
326{
327    tr_benc top;
328    tr_bencInitDict( &top, 2 );
329    tr_bencDictAddStr( &top, "method", "torrent-set" );
330    tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 );
331    tr_bencDictAddReal( args, key.toUtf8().constData(), value );
332    addOptionalIds( args, ids );
333    std::cerr << tr_bencToJSON(&top) << std::endl;
334    exec( &top );
335    tr_bencFree( &top );
336}
337
338void
339Session :: torrentSet( const QSet<int>& ids, const QString& key, int value )
340{
341    tr_benc top;
342    tr_bencInitDict( &top, 2 );
343    tr_bencDictAddStr( &top, "method", "torrent-set" );
344    tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 );
345    tr_bencDictAddInt( args, key.toUtf8().constData(), value );
346    addOptionalIds( args, ids );
347    std::cerr << tr_bencToJSON(&top) << std::endl;
348    exec( &top );
349    tr_bencFree( &top );
350}
351
352void
353Session :: torrentSet( const QSet<int>& ids, const QString& key, bool value )
354{
355    tr_benc top;
356    tr_bencInitDict( &top, 2 );
357    tr_bencDictAddStr( &top, "method", "torrent-set" );
358    tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 );
359    tr_bencDictAddBool( args, key.toUtf8().constData(), value );
360    addOptionalIds( args, ids );
361    std::cerr << tr_bencToJSON(&top) << std::endl;
362    exec( &top );
363    tr_bencFree( &top );
364}
365
366void
367Session :: torrentSet( const QSet<int>& ids, const QString& key, const QList<int>& value )
368{
369    tr_benc top;
370    tr_bencInitDict( &top, 2 );
371    tr_bencDictAddStr( &top, "method", "torrent-set" );
372    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
373    addOptionalIds( args, ids );
374    tr_benc * list( tr_bencDictAddList( args, key.toUtf8().constData(), value.size( ) ) );
375    foreach( int i, value )
376        tr_bencListAddInt( list, i );
377    std::cerr << tr_bencToJSON(&top) << std::endl;
378    exec( &top );
379    tr_bencFree( &top );
380}
381
382
383void
384Session :: refreshTorrents( const QSet<int>& ids )
385{
386    if( ids.empty( ) )
387    {
388        refreshAllTorrents( );
389    }
390    else
391    {
392        tr_benc top;
393        tr_bencInitDict( &top, 3 );
394        tr_bencDictAddStr( &top, "method", "torrent-get" );
395        tr_bencDictAddInt( &top, "tag", TAG_SOME_TORRENTS );
396        tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
397        addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) );
398        addOptionalIds( args, ids );
399        exec( &top );
400        tr_bencFree( &top );
401    }
402}
403
404void
405Session :: refreshExtraStats( const QSet<int>& ids )
406{
407    tr_benc top;
408    tr_bencInitDict( &top, 3 );
409    tr_bencDictAddStr( &top, "method", "torrent-get" );
410    tr_bencDictAddInt( &top, "tag", TAG_SOME_TORRENTS );
411    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
412    addOptionalIds( args, ids );
413    addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) + getExtraStatKeys( ));
414    exec( &top );
415    tr_bencFree( &top );
416}
417
418void
419Session :: sendTorrentRequest( const char * request, const QSet<int>& ids )
420{
421    tr_benc top;
422    tr_benc * args( buildRequest( request, top ) );
423    addOptionalIds( args, ids );
424    exec( &top );
425    tr_bencFree( &top );
426
427    refreshTorrents( ids );
428}
429
430void
431Session :: pauseTorrents( const QSet<int>& ids )
432{
433    sendTorrentRequest( "torrent-stop", ids );
434}
435
436void
437Session :: startTorrents( const QSet<int>& ids )
438{
439    sendTorrentRequest( "torrent-start", ids );
440}
441
442void
443Session :: refreshActiveTorrents( )
444{
445    tr_benc top;
446    tr_bencInitDict( &top, 3 );
447    tr_bencDictAddStr( &top, "method", "torrent-get" );
448    tr_bencDictAddInt( &top, "tag", TAG_SOME_TORRENTS );
449    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
450    tr_bencDictAddStr( args, "ids", "recently-active" );
451    addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) );
452    exec( &top );
453    tr_bencFree( &top );
454}
455
456void
457Session :: refreshAllTorrents( )
458{
459    tr_benc top;
460    tr_bencInitDict( &top, 3 );
461    tr_bencDictAddStr( &top, "method", "torrent-get" );
462    tr_bencDictAddInt( &top, "tag", TAG_ALL_TORRENTS );
463    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 1 ) );
464    addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) );
465    exec( &top );
466    tr_bencFree( &top );
467}
468
469void
470Session :: initTorrents( const QSet<int>& ids )
471{
472    tr_benc top;
473    const int tag( ids.isEmpty() ? TAG_ALL_TORRENTS : TAG_SOME_TORRENTS );
474    tr_benc * args( buildRequest( "torrent-get", top, tag ) );
475    addOptionalIds( args, ids );
476    addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys()+getInfoKeys() );
477    exec( &top );
478    tr_bencFree( &top );
479}
480
481void
482Session :: refreshSessionStats( )
483{
484    tr_benc top;
485    tr_bencInitDict( &top, 2 );
486    tr_bencDictAddStr( &top, "method", "session-stats" );
487    tr_bencDictAddInt( &top, "tag", TAG_SESSION_STATS );
488    exec( &top );
489    tr_bencFree( &top );
490}
491
492void
493Session :: refreshSessionInfo( )
494{
495    tr_benc top;
496    tr_bencInitDict( &top, 2 );
497    tr_bencDictAddStr( &top, "method", "session-get" );
498    tr_bencDictAddInt( &top, "tag", TAG_SESSION_INFO );
499    exec( &top );
500    tr_bencFree( &top );
501}
502
503void
504Session :: updateBlocklist( )
505{
506    tr_benc top;
507    tr_bencInitDict( &top, 2 );
508    tr_bencDictAddStr( &top, "method", "blocklist-update" );
509    tr_bencDictAddInt( &top, "tag", TAG_BLOCKLIST_UPDATE );
510    exec( &top );
511    tr_bencFree( &top );
512}
513
514/***
515****
516***/
517
518void
519Session :: exec( const tr_benc * request )
520{
521    char * str( tr_bencToJSON( request ) );
522    exec( str );
523    tr_free( str );
524}
525
526void
527Session :: localSessionCallback( tr_session * session, const char * json, size_t len, void * self )
528{
529    Q_UNUSED( session );
530
531    ((Session*)self)->parseResponse( json, len );
532}
533
534void
535Session :: exec( const char * request )
536{
537    if( mySession  )
538    {
539        tr_rpc_request_exec_json( mySession, request, strlen( request ), localSessionCallback, this );
540    }
541    else if( !myUrl.isEmpty( ) )
542    {
543        const QByteArray data( request, strlen( request ) );
544        static const QString path( "/transmission/rpc" );
545        QHttpRequestHeader header( "POST", path );
546        header.setValue( "User-Agent", QCoreApplication::instance()->applicationName() + "/" + LONG_VERSION_STRING );
547        header.setValue( "Content-Type", "application/json; charset=UTF-8" );
548        myHttp.request( header, data, &myBuffer );
549#ifdef DEBUG_HTTP
550        std::cerr << "sending " << qPrintable(header.toString()) << "\nBody:\n" << request << std::endl;
551#endif
552    }
553}
554
555void
556Session :: onRequestStarted( int id )
557{
558    Q_UNUSED( id );
559
560    assert( myBuffer.atEnd( ) );
561}
562
563void
564Session :: onRequestFinished( int id, bool error )
565{
566    Q_UNUSED( id );
567
568#ifdef DEBUG_HTTP
569    std::cerr << "http request " << id << " ended.. response header: "
570              << qPrintable( myHttp.lastResponse().toString() )
571              << std::endl
572              << "json: " << myBuffer.buffer( ).constData( )
573              << std::endl;
574#endif
575
576    if( error )
577        std::cerr << "http error: " << qPrintable(myHttp.errorString()) << std::endl;
578    else {
579        const QByteArray& response( myBuffer.buffer( ) );
580        const char * json( response.constData( ) );
581        int jsonLength( response.size( ) );
582        if( jsonLength>0 && json[jsonLength-1] == '\n' ) --jsonLength;
583
584        parseResponse( json, jsonLength );
585    }
586
587    myBuffer.buffer( ).clear( );
588    myBuffer.reset( );
589    assert( myBuffer.bytesAvailable( ) < 1 );
590}
591
592void
593Session :: parseResponse( const char * json, size_t jsonLength )
594{
595    tr_benc top;
596    const uint8_t * end( 0 );
597    const int err( tr_jsonParse( json, jsonLength, &top, &end ) );
598    if( !err )
599    {
600        int64_t tag;
601        const char * str;
602        tr_benc *args, *torrents;
603        if( tr_bencDictFindInt( &top, "tag", &tag ) )
604        {
605            switch( tag )
606            {
607                case TAG_SOME_TORRENTS:
608                case TAG_ALL_TORRENTS:
609                    if( tr_bencDictFindDict( &top, "arguments", &args ) ) {
610                        if( tr_bencDictFindList( args, "torrents", &torrents ) )
611                            emit torrentsUpdated( torrents, tag==TAG_ALL_TORRENTS );
612                        if( tr_bencDictFindList( args, "removed", &torrents ) )
613                            emit torrentsRemoved( torrents );
614                    }
615                    break;
616
617                case TAG_SESSION_STATS:
618                    if( tr_bencDictFindDict( &top, "arguments", &args ) )
619                        updateStats( args );
620                    break;
621
622                case TAG_SESSION_INFO:
623                    if( tr_bencDictFindDict( &top, "arguments", &args ) )
624                        updateInfo( args );
625                    break;
626
627                case TAG_BLOCKLIST_UPDATE: {
628                    int64_t intVal = 0;
629                    if( tr_bencDictFindDict( &top, "arguments", &args ) )
630                        if( tr_bencDictFindInt( args, "blocklist-size", &intVal ) )
631                            setBlocklistSize( intVal );
632                    break;
633                }
634
635                case TAG_PORT_TEST: {
636                    tr_bool isOpen = 0;
637                    if( tr_bencDictFindDict( &top, "arguments", &args ) )
638                        tr_bencDictFindBool( args, "port-is-open", &isOpen );
639                    emit portTested( (bool)isOpen );
640                }
641
642                case TAG_ADD_TORRENT:
643                    str = "";
644                    if( tr_bencDictFindStr( &top, "result", &str ) && strcmp( str, "success" ) ) {
645                        QMessageBox * d = new QMessageBox( QMessageBox::Information,
646                                                           tr( "Add Torrent" ),
647                                                           QString::fromUtf8(str),
648                                                           QMessageBox::Close,
649                                                           QApplication::activeWindow());
650                        QPixmap pixmap; 
651                        QIcon icon = QtIconLoader :: icon( "dialog-information" );
652                        if( !icon.isNull( ) ) {
653                            const int size = QApplication::style()->pixelMetric( QStyle::PM_LargeIconSize );
654                            d->setIconPixmap( icon.pixmap( size, size ) );
655                        }
656                        connect( d, SIGNAL(rejected()), d, SLOT(deleteLater()) );
657                        d->show( );
658                    }
659                    break;
660
661                default:
662                    break;
663            }
664        }
665        tr_bencFree( &top );
666    }
667}
668
669void
670Session :: updateStats( tr_benc * d, struct tr_session_stats * stats )
671{
672    int64_t i;
673
674    if( tr_bencDictFindInt( d, "uploadedBytes", &i ) )
675        stats->uploadedBytes = i;
676    if( tr_bencDictFindInt( d, "downloadedBytes", &i ) )
677        stats->downloadedBytes = i;
678    if( tr_bencDictFindInt( d, "filesAdded", &i ) )
679        stats->filesAdded = i;
680    if( tr_bencDictFindInt( d, "sessionCount", &i ) )
681        stats->sessionCount = i;
682    if( tr_bencDictFindInt( d, "secondsActive", &i ) )
683        stats->secondsActive = i;
684
685    stats->ratio = tr_getRatio( stats->uploadedBytes, stats->downloadedBytes );
686
687}
688
689void
690Session :: updateStats( tr_benc * d )
691{
692    tr_benc * c;
693
694    if( tr_bencDictFindDict( d, "current-stats", &c ) )
695        updateStats( c, &myStats );
696
697    if( tr_bencDictFindDict( d, "cumulative-stats", &c ) )
698        updateStats( c, &myCumulativeStats );
699
700    emit statsUpdated( );
701}
702
703void
704Session :: updateInfo( tr_benc * d )
705{
706    int64_t i;
707    const char * str;
708    disconnect( &myPrefs, SIGNAL(changed(int)), this, SLOT(updatePref(int)) );
709
710    for( int i=Prefs::FIRST_CORE_PREF; i<=Prefs::LAST_CORE_PREF; ++i )
711    {
712        const tr_benc * b( tr_bencDictFind( d, myPrefs.keyStr( i ) ) );
713
714        if( !b )
715            continue;
716
717        switch( myPrefs.type( i ) )
718        {
719            case QVariant :: Int: {
720                int64_t val;
721                if( tr_bencGetInt( b, &val ) )
722                    myPrefs.set( i, (int)val );
723                break;
724            }
725            case QVariant :: Double: {
726                double val;
727                if( tr_bencGetReal( b, &val ) )
728                    myPrefs.set( i, val );
729                break;
730            }
731            case QVariant :: Bool: {
732                tr_bool val;
733                if( tr_bencGetBool( b, &val ) )
734                    myPrefs.set( i, (bool)val );
735                break;
736            }
737            case TrTypes :: FilterModeType:
738            case TrTypes :: SortModeType:
739            case QVariant :: String: {
740                const char * val;
741                if( tr_bencGetStr( b, &val ) )
742                    myPrefs.set( i, QString(val) );
743                break;
744            }
745            default:
746                break;
747        }
748    }
749
750    /* Use the C API to get settings that, for security reasons, aren't supported by RPC */
751    if( mySession != 0 )
752    {
753        myPrefs.set( Prefs::RPC_ENABLED,           tr_sessionIsRPCEnabled           ( mySession ) );
754        myPrefs.set( Prefs::RPC_AUTH_REQUIRED,     tr_sessionIsRPCPasswordEnabled   ( mySession ) );
755        myPrefs.set( Prefs::RPC_PASSWORD,          tr_sessionGetRPCPassword         ( mySession ) );
756        myPrefs.set( Prefs::RPC_PORT,              tr_sessionGetRPCPort             ( mySession ) );
757        myPrefs.set( Prefs::RPC_USERNAME,          tr_sessionGetRPCUsername         ( mySession ) );
758        myPrefs.set( Prefs::RPC_WHITELIST_ENABLED, tr_sessionGetRPCWhitelistEnabled ( mySession ) );
759        myPrefs.set( Prefs::RPC_WHITELIST,         tr_sessionGetRPCWhitelist        ( mySession ) );
760    }
761
762    if( tr_bencDictFindInt( d, "blocklist-size", &i ) && i!=blocklistSize( ) )
763        setBlocklistSize( i );
764
765    if( tr_bencDictFindStr( d, "version", &str ) && ( mySessionVersion != str ) )
766        mySessionVersion = str;
767
768    //std::cerr << "Session :: updateInfo end" << std::endl;
769    connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(updatePref(int)) );
770
771    emit sessionUpdated( );
772}
773
774void
775Session :: setBlocklistSize( int64_t i )
776{
777    myBlocklistSize = i;
778
779    emit blocklistUpdated( i );
780}
781
782void
783Session :: addTorrent( QString filename )
784{
785    QFile file( filename );
786    file.open( QIODevice::ReadOnly );
787    const QByteArray raw( file.readAll( ) );
788    file.close( );
789
790    if( !raw.isEmpty( ) )
791    {
792        int b64len = 0;
793        char * b64 = tr_base64_encode( raw.constData(), raw.size(), &b64len );
794
795        tr_benc top, *args;
796        tr_bencInitDict( &top, 2 );
797        tr_bencDictAddStr( &top, "method", "torrent-add" );
798        args = tr_bencDictAddDict( &top, "arguments", 3 );
799        tr_bencDictAddStr( args, "download-dir", qPrintable(myPrefs.getString(Prefs::DOWNLOAD_DIR)) );
800        tr_bencDictAddRaw( args, "metainfo", b64, b64len  );
801        tr_bencDictAddInt( args, "paused", !myPrefs.getBool( Prefs::START ) );
802        exec( &top );
803
804        tr_free( b64 );
805        tr_bencFree( &top );
806    }
807}
808
809void
810Session :: removeTorrents( const QSet<int>& ids, bool deleteFiles )
811{
812    if( !ids.isEmpty( ) )
813    {
814        tr_benc top, *args;
815        tr_bencInitDict( &top, 2 );
816        tr_bencDictAddStr( &top, "method", "torrent-remove" );
817        args = tr_bencDictAddDict( &top, "arguments", 2 );
818        addOptionalIds( args, ids );
819        tr_bencDictAddInt( args, "delete-local-data", deleteFiles );
820        exec( &top );
821        tr_bencFree( &top );
822    }
823}
824
825void
826Session :: verifyTorrents( const QSet<int>& ids )
827{
828    if( !ids.isEmpty( ) )
829    {
830        tr_benc top, *args;
831        tr_bencInitDict( &top, 2 );
832        tr_bencDictAddStr( &top, "method", "torrent-verify" );
833        args = tr_bencDictAddDict( &top, "arguments", 1 );
834        addOptionalIds( args, ids );
835        exec( &top );
836        tr_bencFree( &top );
837    }
838}
839
840void
841Session :: reannounceTorrents( const QSet<int>& ids )
842{
843    if( !ids.isEmpty( ) )
844    {
845        tr_benc top, *args;
846        tr_bencInitDict( &top, 2 );
847        tr_bencDictAddStr( &top, "method", "torrent-reannounce" );
848        args = tr_bencDictAddDict( &top, "arguments", 1 );
849        addOptionalIds( args, ids );
850        exec( &top );
851        tr_bencFree( &top );
852    }
853}
854
855/***
856****
857***/
858
859void
860Session :: launchWebInterface( )
861{
862    QUrl url;
863    if( !mySession) // remote session
864        url = myUrl;
865    else { // local session
866        url.setHost( "localhost" );
867        url.setPort( myPrefs.getInt( Prefs::RPC_PORT ) );
868    }
869    std::cerr << qPrintable(url.toString()) << std::endl;
870    QDesktopServices :: openUrl( url );
871}
Note: See TracBrowser for help on using the repository browser.