source: trunk/qt/session.cc @ 8216

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

(qt) better integration of sort & filter modes into the preferences mechanism

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