source: trunk/qt/session.cc @ 9243

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

(trunk qt) sync the Qt client's "New Torrent" dialog with the GTK+ client's rewrite

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