source: trunk/qt/session.cc @ 8334

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

(trunk qt) remove debugging message from console

File size: 24.6 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    }
92    exec( &top );
93    tr_bencFree( &top );
94}
95
96void
97Session :: portTest( )
98{
99    tr_benc top;
100    tr_bencInitDict( &top, 2 );
101    tr_bencDictAddStr( &top, "method", "port-test" );
102    tr_bencDictAddInt( &top, "tag", TAG_PORT_TEST );
103    exec( &top );
104    tr_bencFree( &top );
105}
106
107void
108Session :: updatePref( int key )
109{
110    if( myPrefs.isCore( key ) ) switch( key )
111    {
112        case Prefs :: ALT_SPEED_LIMIT_UP:
113        case Prefs :: ALT_SPEED_LIMIT_DOWN:
114        case Prefs :: ALT_SPEED_LIMIT_ENABLED:
115        case Prefs :: ALT_SPEED_LIMIT_TIME_BEGIN:
116        case Prefs :: ALT_SPEED_LIMIT_TIME_END:
117        case Prefs :: ALT_SPEED_LIMIT_TIME_ENABLED:
118        case Prefs :: ALT_SPEED_LIMIT_TIME_DAY:
119        case Prefs :: BLOCKLIST_ENABLED:
120        case Prefs :: BLOCKLIST_DATE:
121        case Prefs :: DOWNLOAD_DIR:
122        case Prefs :: PEER_LIMIT_GLOBAL:
123        case Prefs :: PEER_LIMIT_TORRENT:
124        case Prefs :: SEED_RATIO_LIMIT:
125        case Prefs :: SEED_RATIO_LIMITED:
126        case Prefs :: USPEED_ENABLED:
127        case Prefs :: USPEED:
128        case Prefs :: DSPEED_ENABLED:
129        case Prefs :: DSPEED:
130        case Prefs :: PEX_ENABLED:
131        case Prefs :: PORT_FORWARDING:
132        case Prefs :: PEER_PORT:
133        case Prefs :: PEER_PORT_RANDOM_ON_START:
134        case Prefs :: RATIO:
135        case Prefs :: RATIO_ENABLED:
136            sessionSet( myPrefs.keyStr(key), myPrefs.variant(key) );
137            break;
138
139        case Prefs :: RPC_AUTH_REQUIRED:
140            if( mySession )
141                tr_sessionSetRPCEnabled( mySession, myPrefs.getBool(key) );
142            break;
143        case Prefs :: RPC_ENABLED:
144            if( mySession )
145                tr_sessionSetRPCEnabled( mySession, myPrefs.getBool(key) );
146            break;
147        case Prefs :: RPC_PASSWORD:
148            if( mySession )
149                tr_sessionSetRPCPassword( mySession, myPrefs.getString(key).toUtf8().constData() );
150            break;
151        case Prefs :: RPC_PORT:
152            if( mySession )
153                tr_sessionSetRPCPort( mySession, myPrefs.getInt(key) );
154            break;
155        case Prefs :: RPC_USERNAME:
156            if( mySession )
157                tr_sessionSetRPCUsername( mySession, myPrefs.getString(key).toUtf8().constData() );
158            break;
159        case Prefs :: RPC_WHITELIST_ENABLED:
160            if( mySession )
161                tr_sessionSetRPCWhitelistEnabled( mySession, myPrefs.getBool(key) );
162            break;
163        case Prefs :: RPC_WHITELIST:
164            if( mySession )
165                tr_sessionSetRPCWhitelist( mySession, myPrefs.getString(key).toUtf8().constData() );
166            break;
167
168        default:
169            std::cerr << "unhandled pref: " << key << std::endl;
170    }
171}
172
173/***
174****
175***/
176
177Session :: Session( const char * configDir, Prefs& prefs ):
178    myBlocklistSize( -1 ),
179    myPrefs( prefs ),
180    mySession( 0 ),
181    myConfigDir( configDir )
182{
183    myStats.ratio = TR_RATIO_NA;
184    myStats.uploadedBytes = 0;
185    myStats.downloadedBytes = 0;
186    myStats.filesAdded = 0;
187    myStats.sessionCount = 0;
188    myStats.secondsActive = 0;
189    myCumulativeStats = myStats;
190
191    connect( &myHttp, SIGNAL(requestStarted(int)), this, SLOT(onRequestStarted(int)));
192    connect( &myHttp, SIGNAL(requestFinished(int,bool)), this, SLOT(onRequestFinished(int,bool)));
193    connect( &myHttp, SIGNAL(dataReadProgress(int,int)), this, SIGNAL(dataReadProgress()));
194    connect( &myHttp, SIGNAL(dataSendProgress(int,int)), this, SIGNAL(dataSendProgress()));
195    connect( &myHttp, SIGNAL(authenticationRequired(QString, quint16, QAuthenticator*)), this, SIGNAL(httpAuthenticationRequired()) );
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    exec( &top );
334    tr_bencFree( &top );
335}
336
337void
338Session :: torrentSet( const QSet<int>& ids, const QString& key, int value )
339{
340    tr_benc top;
341    tr_bencInitDict( &top, 2 );
342    tr_bencDictAddStr( &top, "method", "torrent-set" );
343    tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 );
344    tr_bencDictAddInt( args, key.toUtf8().constData(), value );
345    addOptionalIds( args, ids );
346    exec( &top );
347    tr_bencFree( &top );
348}
349
350void
351Session :: torrentSet( const QSet<int>& ids, const QString& key, bool value )
352{
353    tr_benc top;
354    tr_bencInitDict( &top, 2 );
355    tr_bencDictAddStr( &top, "method", "torrent-set" );
356    tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 );
357    tr_bencDictAddBool( args, key.toUtf8().constData(), value );
358    addOptionalIds( args, ids );
359    exec( &top );
360    tr_bencFree( &top );
361}
362
363void
364Session :: torrentSet( const QSet<int>& ids, const QString& key, const QList<int>& value )
365{
366    tr_benc top;
367    tr_bencInitDict( &top, 2 );
368    tr_bencDictAddStr( &top, "method", "torrent-set" );
369    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
370    addOptionalIds( args, ids );
371    tr_benc * list( tr_bencDictAddList( args, key.toUtf8().constData(), value.size( ) ) );
372    foreach( int i, value )
373        tr_bencListAddInt( list, i );
374    exec( &top );
375    tr_bencFree( &top );
376}
377
378
379void
380Session :: refreshTorrents( const QSet<int>& ids )
381{
382    if( ids.empty( ) )
383    {
384        refreshAllTorrents( );
385    }
386    else
387    {
388        tr_benc top;
389        tr_bencInitDict( &top, 3 );
390        tr_bencDictAddStr( &top, "method", "torrent-get" );
391        tr_bencDictAddInt( &top, "tag", TAG_SOME_TORRENTS );
392        tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
393        addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) );
394        addOptionalIds( args, ids );
395        exec( &top );
396        tr_bencFree( &top );
397    }
398}
399
400void
401Session :: refreshExtraStats( const QSet<int>& ids )
402{
403    tr_benc top;
404    tr_bencInitDict( &top, 3 );
405    tr_bencDictAddStr( &top, "method", "torrent-get" );
406    tr_bencDictAddInt( &top, "tag", TAG_SOME_TORRENTS );
407    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
408    addOptionalIds( args, ids );
409    addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) + getExtraStatKeys( ));
410    exec( &top );
411    tr_bencFree( &top );
412}
413
414void
415Session :: sendTorrentRequest( const char * request, const QSet<int>& ids )
416{
417    tr_benc top;
418    tr_benc * args( buildRequest( request, top ) );
419    addOptionalIds( args, ids );
420    exec( &top );
421    tr_bencFree( &top );
422
423    refreshTorrents( ids );
424}
425
426void
427Session :: pauseTorrents( const QSet<int>& ids )
428{
429    sendTorrentRequest( "torrent-stop", ids );
430}
431
432void
433Session :: startTorrents( const QSet<int>& ids )
434{
435    sendTorrentRequest( "torrent-start", ids );
436}
437
438void
439Session :: refreshActiveTorrents( )
440{
441    tr_benc top;
442    tr_bencInitDict( &top, 3 );
443    tr_bencDictAddStr( &top, "method", "torrent-get" );
444    tr_bencDictAddInt( &top, "tag", TAG_SOME_TORRENTS );
445    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
446    tr_bencDictAddStr( args, "ids", "recently-active" );
447    addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) );
448    exec( &top );
449    tr_bencFree( &top );
450}
451
452void
453Session :: refreshAllTorrents( )
454{
455    tr_benc top;
456    tr_bencInitDict( &top, 3 );
457    tr_bencDictAddStr( &top, "method", "torrent-get" );
458    tr_bencDictAddInt( &top, "tag", TAG_ALL_TORRENTS );
459    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 1 ) );
460    addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) );
461    exec( &top );
462    tr_bencFree( &top );
463}
464
465void
466Session :: initTorrents( const QSet<int>& ids )
467{
468    tr_benc top;
469    const int tag( ids.isEmpty() ? TAG_ALL_TORRENTS : TAG_SOME_TORRENTS );
470    tr_benc * args( buildRequest( "torrent-get", top, tag ) );
471    addOptionalIds( args, ids );
472    addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys()+getInfoKeys() );
473    exec( &top );
474    tr_bencFree( &top );
475}
476
477void
478Session :: refreshSessionStats( )
479{
480    tr_benc top;
481    tr_bencInitDict( &top, 2 );
482    tr_bencDictAddStr( &top, "method", "session-stats" );
483    tr_bencDictAddInt( &top, "tag", TAG_SESSION_STATS );
484    exec( &top );
485    tr_bencFree( &top );
486}
487
488void
489Session :: refreshSessionInfo( )
490{
491    tr_benc top;
492    tr_bencInitDict( &top, 2 );
493    tr_bencDictAddStr( &top, "method", "session-get" );
494    tr_bencDictAddInt( &top, "tag", TAG_SESSION_INFO );
495    exec( &top );
496    tr_bencFree( &top );
497}
498
499void
500Session :: updateBlocklist( )
501{
502    tr_benc top;
503    tr_bencInitDict( &top, 2 );
504    tr_bencDictAddStr( &top, "method", "blocklist-update" );
505    tr_bencDictAddInt( &top, "tag", TAG_BLOCKLIST_UPDATE );
506    exec( &top );
507    tr_bencFree( &top );
508}
509
510/***
511****
512***/
513
514void
515Session :: exec( const tr_benc * request )
516{
517    char * str( tr_bencToJSON( request ) );
518    exec( str );
519    tr_free( str );
520}
521
522void
523Session :: localSessionCallback( tr_session * session, const char * json, size_t len, void * self )
524{
525    Q_UNUSED( session );
526
527    ((Session*)self)->parseResponse( json, len );
528}
529
530void
531Session :: exec( const char * request )
532{
533    if( mySession  )
534    {
535        tr_rpc_request_exec_json( mySession, request, strlen( request ), localSessionCallback, this );
536    }
537    else if( !myUrl.isEmpty( ) )
538    {
539        const QByteArray data( request, strlen( request ) );
540        static const QString path( "/transmission/rpc" );
541        QHttpRequestHeader header( "POST", path );
542        header.setValue( "User-Agent", QCoreApplication::instance()->applicationName() + "/" + LONG_VERSION_STRING );
543        header.setValue( "Content-Type", "application/json; charset=UTF-8" );
544        myHttp.request( header, data, &myBuffer );
545#ifdef DEBUG_HTTP
546        std::cerr << "sending " << qPrintable(header.toString()) << "\nBody:\n" << request << std::endl;
547#endif
548    }
549}
550
551void
552Session :: onRequestStarted( int id )
553{
554    Q_UNUSED( id );
555
556    assert( myBuffer.atEnd( ) );
557}
558
559void
560Session :: onRequestFinished( int id, bool error )
561{
562    Q_UNUSED( id );
563
564#ifdef DEBUG_HTTP
565    std::cerr << "http request " << id << " ended.. response header: "
566              << qPrintable( myHttp.lastResponse().toString() )
567              << std::endl
568              << "json: " << myBuffer.buffer( ).constData( )
569              << std::endl;
570#endif
571
572    if( error )
573        std::cerr << "http error: " << qPrintable(myHttp.errorString()) << std::endl;
574    else {
575        const QByteArray& response( myBuffer.buffer( ) );
576        const char * json( response.constData( ) );
577        int jsonLength( response.size( ) );
578        if( jsonLength>0 && json[jsonLength-1] == '\n' ) --jsonLength;
579
580        parseResponse( json, jsonLength );
581    }
582
583    myBuffer.buffer( ).clear( );
584    myBuffer.reset( );
585    assert( myBuffer.bytesAvailable( ) < 1 );
586}
587
588void
589Session :: parseResponse( const char * json, size_t jsonLength )
590{
591    tr_benc top;
592    const uint8_t * end( 0 );
593    const int err( tr_jsonParse( json, jsonLength, &top, &end ) );
594    if( !err )
595    {
596        int64_t tag;
597        const char * str;
598        tr_benc *args, *torrents;
599        if( tr_bencDictFindInt( &top, "tag", &tag ) )
600        {
601            switch( tag )
602            {
603                case TAG_SOME_TORRENTS:
604                case TAG_ALL_TORRENTS:
605                    if( tr_bencDictFindDict( &top, "arguments", &args ) ) {
606                        if( tr_bencDictFindList( args, "torrents", &torrents ) )
607                            emit torrentsUpdated( torrents, tag==TAG_ALL_TORRENTS );
608                        if( tr_bencDictFindList( args, "removed", &torrents ) )
609                            emit torrentsRemoved( torrents );
610                    }
611                    break;
612
613                case TAG_SESSION_STATS:
614                    if( tr_bencDictFindDict( &top, "arguments", &args ) )
615                        updateStats( args );
616                    break;
617
618                case TAG_SESSION_INFO:
619                    if( tr_bencDictFindDict( &top, "arguments", &args ) )
620                        updateInfo( args );
621                    break;
622
623                case TAG_BLOCKLIST_UPDATE: {
624                    int64_t intVal = 0;
625                    if( tr_bencDictFindDict( &top, "arguments", &args ) )
626                        if( tr_bencDictFindInt( args, "blocklist-size", &intVal ) )
627                            setBlocklistSize( intVal );
628                    break;
629                }
630
631                case TAG_PORT_TEST: {
632                    tr_bool isOpen = 0;
633                    if( tr_bencDictFindDict( &top, "arguments", &args ) )
634                        tr_bencDictFindBool( args, "port-is-open", &isOpen );
635                    emit portTested( (bool)isOpen );
636                }
637
638                case TAG_ADD_TORRENT:
639                    str = "";
640                    if( tr_bencDictFindStr( &top, "result", &str ) && strcmp( str, "success" ) ) {
641                        QMessageBox * d = new QMessageBox( QMessageBox::Information,
642                                                           tr( "Add Torrent" ),
643                                                           QString::fromUtf8(str),
644                                                           QMessageBox::Close,
645                                                           QApplication::activeWindow());
646                        QPixmap pixmap; 
647                        QIcon icon = QtIconLoader :: icon( "dialog-information" );
648                        if( !icon.isNull( ) ) {
649                            const int size = QApplication::style()->pixelMetric( QStyle::PM_LargeIconSize );
650                            d->setIconPixmap( icon.pixmap( size, size ) );
651                        }
652                        connect( d, SIGNAL(rejected()), d, SLOT(deleteLater()) );
653                        d->show( );
654                    }
655                    break;
656
657                default:
658                    break;
659            }
660        }
661        tr_bencFree( &top );
662    }
663}
664
665void
666Session :: updateStats( tr_benc * d, struct tr_session_stats * stats )
667{
668    int64_t i;
669
670    if( tr_bencDictFindInt( d, "uploadedBytes", &i ) )
671        stats->uploadedBytes = i;
672    if( tr_bencDictFindInt( d, "downloadedBytes", &i ) )
673        stats->downloadedBytes = i;
674    if( tr_bencDictFindInt( d, "filesAdded", &i ) )
675        stats->filesAdded = i;
676    if( tr_bencDictFindInt( d, "sessionCount", &i ) )
677        stats->sessionCount = i;
678    if( tr_bencDictFindInt( d, "secondsActive", &i ) )
679        stats->secondsActive = i;
680
681    stats->ratio = tr_getRatio( stats->uploadedBytes, stats->downloadedBytes );
682
683}
684
685void
686Session :: updateStats( tr_benc * d )
687{
688    tr_benc * c;
689
690    if( tr_bencDictFindDict( d, "current-stats", &c ) )
691        updateStats( c, &myStats );
692
693    if( tr_bencDictFindDict( d, "cumulative-stats", &c ) )
694        updateStats( c, &myCumulativeStats );
695
696    emit statsUpdated( );
697}
698
699void
700Session :: updateInfo( tr_benc * d )
701{
702    int64_t i;
703    const char * str;
704    disconnect( &myPrefs, SIGNAL(changed(int)), this, SLOT(updatePref(int)) );
705
706    for( int i=Prefs::FIRST_CORE_PREF; i<=Prefs::LAST_CORE_PREF; ++i )
707    {
708        const tr_benc * b( tr_bencDictFind( d, myPrefs.keyStr( i ) ) );
709
710        if( !b )
711            continue;
712
713        switch( myPrefs.type( i ) )
714        {
715            case QVariant :: Int: {
716                int64_t val;
717                if( tr_bencGetInt( b, &val ) )
718                    myPrefs.set( i, (int)val );
719                break;
720            }
721            case QVariant :: Double: {
722                double val;
723                if( tr_bencGetReal( b, &val ) )
724                    myPrefs.set( i, val );
725                break;
726            }
727            case QVariant :: Bool: {
728                tr_bool val;
729                if( tr_bencGetBool( b, &val ) )
730                    myPrefs.set( i, (bool)val );
731                break;
732            }
733            case TrTypes :: FilterModeType:
734            case TrTypes :: SortModeType:
735            case QVariant :: String: {
736                const char * val;
737                if( tr_bencGetStr( b, &val ) )
738                    myPrefs.set( i, QString(val) );
739                break;
740            }
741            default:
742                break;
743        }
744    }
745
746    /* Use the C API to get settings that, for security reasons, aren't supported by RPC */
747    if( mySession != 0 )
748    {
749        myPrefs.set( Prefs::RPC_ENABLED,           tr_sessionIsRPCEnabled           ( mySession ) );
750        myPrefs.set( Prefs::RPC_AUTH_REQUIRED,     tr_sessionIsRPCPasswordEnabled   ( mySession ) );
751        myPrefs.set( Prefs::RPC_PASSWORD,          tr_sessionGetRPCPassword         ( mySession ) );
752        myPrefs.set( Prefs::RPC_PORT,              tr_sessionGetRPCPort             ( mySession ) );
753        myPrefs.set( Prefs::RPC_USERNAME,          tr_sessionGetRPCUsername         ( mySession ) );
754        myPrefs.set( Prefs::RPC_WHITELIST_ENABLED, tr_sessionGetRPCWhitelistEnabled ( mySession ) );
755        myPrefs.set( Prefs::RPC_WHITELIST,         tr_sessionGetRPCWhitelist        ( mySession ) );
756    }
757
758    if( tr_bencDictFindInt( d, "blocklist-size", &i ) && i!=blocklistSize( ) )
759        setBlocklistSize( i );
760
761    if( tr_bencDictFindStr( d, "version", &str ) && ( mySessionVersion != str ) )
762        mySessionVersion = str;
763
764    //std::cerr << "Session :: updateInfo end" << std::endl;
765    connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(updatePref(int)) );
766
767    emit sessionUpdated( );
768}
769
770void
771Session :: setBlocklistSize( int64_t i )
772{
773    myBlocklistSize = i;
774
775    emit blocklistUpdated( i );
776}
777
778void
779Session :: addTorrent( QString filename )
780{
781    QFile file( filename );
782    file.open( QIODevice::ReadOnly );
783    const QByteArray raw( file.readAll( ) );
784    file.close( );
785
786    if( !raw.isEmpty( ) )
787    {
788        int b64len = 0;
789        char * b64 = tr_base64_encode( raw.constData(), raw.size(), &b64len );
790
791        tr_benc top, *args;
792        tr_bencInitDict( &top, 2 );
793        tr_bencDictAddStr( &top, "method", "torrent-add" );
794        args = tr_bencDictAddDict( &top, "arguments", 3 );
795        tr_bencDictAddStr( args, "download-dir", qPrintable(myPrefs.getString(Prefs::DOWNLOAD_DIR)) );
796        tr_bencDictAddRaw( args, "metainfo", b64, b64len  );
797        tr_bencDictAddInt( args, "paused", !myPrefs.getBool( Prefs::START ) );
798        exec( &top );
799
800        tr_free( b64 );
801        tr_bencFree( &top );
802    }
803}
804
805void
806Session :: removeTorrents( const QSet<int>& ids, bool deleteFiles )
807{
808    if( !ids.isEmpty( ) )
809    {
810        tr_benc top, *args;
811        tr_bencInitDict( &top, 2 );
812        tr_bencDictAddStr( &top, "method", "torrent-remove" );
813        args = tr_bencDictAddDict( &top, "arguments", 2 );
814        addOptionalIds( args, ids );
815        tr_bencDictAddInt( args, "delete-local-data", deleteFiles );
816        exec( &top );
817        tr_bencFree( &top );
818    }
819}
820
821void
822Session :: verifyTorrents( const QSet<int>& ids )
823{
824    if( !ids.isEmpty( ) )
825    {
826        tr_benc top, *args;
827        tr_bencInitDict( &top, 2 );
828        tr_bencDictAddStr( &top, "method", "torrent-verify" );
829        args = tr_bencDictAddDict( &top, "arguments", 1 );
830        addOptionalIds( args, ids );
831        exec( &top );
832        tr_bencFree( &top );
833    }
834}
835
836void
837Session :: reannounceTorrents( const QSet<int>& ids )
838{
839    if( !ids.isEmpty( ) )
840    {
841        tr_benc top, *args;
842        tr_bencInitDict( &top, 2 );
843        tr_bencDictAddStr( &top, "method", "torrent-reannounce" );
844        args = tr_bencDictAddDict( &top, "arguments", 1 );
845        addOptionalIds( args, ids );
846        exec( &top );
847        tr_bencFree( &top );
848    }
849}
850
851/***
852****
853***/
854
855void
856Session :: launchWebInterface( )
857{
858    QUrl url;
859    if( !mySession) // remote session
860        url = myUrl;
861    else { // local session
862        url.setHost( "localhost" );
863        url.setPort( myPrefs.getInt( Prefs::RPC_PORT ) );
864    }
865    QDesktopServices :: openUrl( url );
866}
Note: See TracBrowser for help on using the repository browser.