source: trunk/qt/session.cc @ 8192

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

(trunk qt,gtk) include torrents-being-verified in the "active torrents" filter.

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