source: trunk/qt/session.cc @ 8401

Last change on this file since 8401 was 8401, checked in by charles, 7 years ago

(trunk qt) #2077: doesn't show/modify the "Stop seeding torrents at ratio"

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