1
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
3
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
4
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
5
* Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
7
* Tomahawk is free software: you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation, either version 3 of the License, or
10
* (at your option) any later version.
12
* Tomahawk is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
21
#include "TwitterSip.h"
23
#include "utils/TomahawkUtils.h"
24
#include "TomahawkSettings.h"
25
#include "database/Database.h"
26
#include "database/DatabaseImpl.h"
27
#include "network/Servent.h"
30
#include "utils/Logger.h"
31
#include "accounts/twitter/TomahawkOAuthTwitter.h"
32
#include "accounts/twitter/TwitterAccount.h"
34
#include <QTweetLib/qtweetaccountverifycredentials.h>
35
#include <QTweetLib/qtweetuser.h>
36
#include <QTweetLib/qtweetstatus.h>
37
#include <QTweetLib/qtweetusershow.h>
42
#include <QNetworkAccessManager>
43
#include <QNetworkRequest>
44
#include <QNetworkReply>
45
#include <QStringList>
47
static QString s_gotTomahawkRegex = QString( "^(@[a-zA-Z0-9]+ )?(Got Tomahawk\\?) (\\{[a-fA-F0-9\\-]+\\}) (.*)$" );
49
TwitterSipPlugin::TwitterSipPlugin( Tomahawk::Accounts::Account* account )
50
: SipPlugin( account )
51
, m_checkTimer( this )
52
, m_connectTimer( this )
53
, m_dmPollTimer( this )
54
, m_cachedFriendsSinceId( 0 )
55
, m_cachedMentionsSinceId( 0 )
56
, m_cachedDirectMessagesSinceId( 0 )
59
, m_state( Tomahawk::Accounts::Account::Disconnected )
61
qDebug() << Q_FUNC_INFO;
63
connect( account, SIGNAL( nowAuthenticated( const QWeakPointer< TomahawkOAuthTwitter > &, const QTweetUser & ) ), SLOT( accountAuthenticated( const QWeakPointer< TomahawkOAuthTwitter > &, const QTweetUser & ) ) );
65
m_configuration = account->configuration();
66
qDebug() << "SIP configuration:" << m_configuration << m_configuration[ "cachedpeers" ];
67
if ( Database::instance()->impl()->dbid() != m_account->configuration()[ "saveddbid" ].toString() )
69
m_configuration[ "cachedpeers" ] = QVariantHash();
70
m_configuration[ "saveddbid" ] = Database::instance()->impl()->dbid();
74
m_checkTimer.setInterval( 180000 );
75
m_checkTimer.setSingleShot( false );
76
connect( &m_checkTimer, SIGNAL( timeout() ), SLOT( checkTimerFired() ) );
78
m_dmPollTimer.setInterval( 60000 );
79
m_dmPollTimer.setSingleShot( false );
80
connect( &m_dmPollTimer, SIGNAL( timeout() ), SLOT( pollDirectMessages() ) );
82
m_connectTimer.setInterval( 180000 );
83
m_connectTimer.setSingleShot( false );
84
connect( &m_connectTimer, SIGNAL( timeout() ), SLOT( connectTimerFired() ) );
89
TwitterSipPlugin::isValid() const
91
return m_account->enabled() && m_account->isAuthenticated() && !m_cachedTwitterAuth.isNull();
95
Tomahawk::Accounts::Account::ConnectionState
96
TwitterSipPlugin::connectionState() const
102
TwitterSipPlugin::inviteString() const
104
return tr( "Enter Twitter username" );
109
TwitterSipPlugin::checkSettings()
111
configurationChanged();
116
TwitterSipPlugin::connectPlugin()
118
tDebug() << Q_FUNC_INFO;
119
if ( !m_account->enabled() )
121
tDebug() << Q_FUNC_INFO << "account isn't enabled";
125
m_cachedPeers = m_configuration[ "cachedpeers" ].toHash();
126
QStringList peerList = m_cachedPeers.keys();
127
qStableSort( peerList.begin(), peerList.end() );
129
if ( !m_account->isAuthenticated() )
131
tDebug() << Q_FUNC_INFO << "account isn't authenticated, attempting";
132
m_account->authenticate();
135
m_state = Tomahawk::Accounts::Account::Connecting;
136
emit stateChanged( m_state );
141
TwitterSipPlugin::disconnectPlugin()
143
tDebug() << Q_FUNC_INFO;
145
m_connectTimer.stop();
146
m_dmPollTimer.stop();
147
if( !m_friendsTimeline.isNull() )
148
delete m_friendsTimeline.data();
149
if( !m_mentions.isNull() )
150
delete m_mentions.data();
151
if( !m_directMessages.isNull() )
152
delete m_directMessages.data();
153
if( !m_directMessageNew.isNull() )
154
delete m_directMessageNew.data();
155
if( !m_directMessageDestroy.isNull() )
156
delete m_directMessageDestroy.data();
158
m_cachedTwitterAuth.clear();
160
m_configuration[ "cachedpeers" ] = m_cachedPeers;
162
m_cachedPeers.empty();
163
m_state = Tomahawk::Accounts::Account::Disconnected;
164
emit stateChanged( m_state );
168
TwitterSipPlugin::accountAuthenticated( const QWeakPointer< TomahawkOAuthTwitter > &twitterAuth, const QTweetUser &user )
172
if ( !m_account->enabled() || !m_account->isAuthenticated() )
175
m_cachedTwitterAuth = twitterAuth;
177
m_friendsTimeline = QWeakPointer<QTweetFriendsTimeline>( new QTweetFriendsTimeline( m_cachedTwitterAuth.data(), this ) );
178
m_mentions = QWeakPointer<QTweetMentions>( new QTweetMentions( m_cachedTwitterAuth.data(), this ) );
179
m_directMessages = QWeakPointer<QTweetDirectMessages>( new QTweetDirectMessages( m_cachedTwitterAuth.data(), this ) );
180
m_directMessageNew = QWeakPointer<QTweetDirectMessageNew>( new QTweetDirectMessageNew( m_cachedTwitterAuth.data(), this ) );
181
m_directMessageDestroy = QWeakPointer<QTweetDirectMessageDestroy>( new QTweetDirectMessageDestroy( m_cachedTwitterAuth.data(), this ) );
182
connect( m_friendsTimeline.data(), SIGNAL( parsedStatuses(const QList< QTweetStatus > &) ), SLOT( friendsTimelineStatuses(const QList<QTweetStatus> &) ) );
183
connect( m_mentions.data(), SIGNAL( parsedStatuses(const QList< QTweetStatus > &) ), SLOT( mentionsStatuses(const QList<QTweetStatus> &) ) );
184
connect( m_directMessages.data(), SIGNAL( parsedDirectMessages(const QList<QTweetDMStatus> &)), SLOT( directMessages(const QList<QTweetDMStatus> &) ) );
185
connect( m_directMessageNew.data(), SIGNAL( parsedDirectMessage(const QTweetDMStatus &)), SLOT( directMessagePosted(const QTweetDMStatus &) ) );
186
connect( m_directMessageNew.data(), SIGNAL( error(QTweetNetBase::ErrorCode, const QString &) ), SLOT( directMessagePostError(QTweetNetBase::ErrorCode, const QString &) ) );
187
connect( m_directMessageDestroy.data(), SIGNAL( parsedDirectMessage(const QTweetDMStatus &) ), SLOT( directMessageDestroyed(const QTweetDMStatus &) ) );
188
m_state = Tomahawk::Accounts::Account::Connected;
189
emit stateChanged( m_state );
190
QStringList peerList = m_cachedPeers.keys();
191
qStableSort( peerList.begin(), peerList.end() );
192
registerOffers( peerList );
193
m_connectTimer.start();
194
m_checkTimer.start();
195
m_dmPollTimer.start();
197
QMetaObject::invokeMethod( this, "checkTimerFired", Qt::AutoConnection );
198
QTimer::singleShot( 20000, this, SLOT( connectTimerFired() ) );
203
TwitterSipPlugin::checkTimerFired()
208
if ( m_cachedFriendsSinceId == 0 )
209
m_cachedFriendsSinceId = m_configuration[ "cachedfriendssinceid" ].toLongLong();
211
qDebug() << "TwitterSipPlugin looking at friends timeline since id " << m_cachedFriendsSinceId;
213
if ( !m_friendsTimeline.isNull() )
214
m_friendsTimeline.data()->fetch( m_cachedFriendsSinceId, 0, 800 );
216
if ( m_cachedMentionsSinceId == 0 )
217
m_cachedMentionsSinceId = m_configuration[ "cachedmentionssinceid" ].toLongLong();
219
qDebug() << "TwitterSipPlugin looking at mentions timeline since id " << m_cachedMentionsSinceId;
221
if ( !m_mentions.isNull() )
222
m_mentions.data()->fetch( m_cachedMentionsSinceId, 0, 800 );
227
TwitterSipPlugin::registerOffers( const QStringList &peerList )
232
foreach( QString screenName, peerList )
234
QVariantHash peerData = m_cachedPeers[screenName].toHash();
236
if ( peerData.contains( "onod" ) && peerData["onod"] != Database::instance()->impl()->dbid() )
238
m_cachedPeers.remove( screenName );
239
m_configuration[ "cachedpeers" ] = m_cachedPeers;
243
if ( Servent::instance()->connectedToSession( peerData["node"].toString() ) )
245
peerData["lastseen"] = QDateTime::currentMSecsSinceEpoch();
246
m_cachedPeers[screenName] = peerData;
247
m_configuration[ "cachedpeers" ] = m_cachedPeers;
249
qDebug() << Q_FUNC_INFO << " already connected";
252
else if ( QDateTime::currentMSecsSinceEpoch() - peerData["lastseen"].toLongLong() > 1209600000 ) // 2 weeks
254
qDebug() << Q_FUNC_INFO << " aging peer " << screenName << " out of cache";
255
m_cachedPeers.remove( screenName );
256
m_configuration[ "cachedpeers" ] = m_cachedPeers;
258
m_cachedAvatars.remove( screenName );
262
if ( !peerData.contains( "host" ) || !peerData.contains( "port" ) || !peerData.contains( "pkey" ) )
264
qDebug() << "TwitterSipPlugin does not have host, port and/or pkey values for " << screenName << " (this is usually *not* a bug or problem but a normal part of the process)";
268
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, peerData ) );
274
TwitterSipPlugin::connectTimerFired()
276
tDebug() << Q_FUNC_INFO << " beginning";
277
if ( !isValid() || m_cachedPeers.isEmpty() )
280
tDebug() << Q_FUNC_INFO << " is not valid";
281
if ( m_cachedPeers.isEmpty() )
282
tDebug() << Q_FUNC_INFO << " has empty cached peers";
286
tDebug() << Q_FUNC_INFO << " continuing";
287
QString myScreenName = m_configuration[ "screenname" ].toString();
288
QStringList peerList = m_cachedPeers.keys();
289
qStableSort( peerList.begin(), peerList.end() );
290
registerOffers( peerList );
294
TwitterSipPlugin::parseGotTomahawk( const QRegExp ®ex, const QString &screenName, const QString &text )
296
QString myScreenName = m_configuration[ "screenname" ].toString();
297
qDebug() << "TwitterSipPlugin found an exact matching Got Tomahawk? mention or direct message from user " << screenName << ", now parsing";
298
regex.exactMatch( text );
299
if ( text.startsWith( '@' ) && regex.captureCount() >= 2 && regex.cap( 1 ) != QString( '@' + myScreenName ) )
301
qDebug() << "TwitterSipPlugin skipping mention because it's directed @someone that isn't us";
306
for ( int i = 0; i < regex.captureCount(); ++i )
308
if ( regex.cap( i ) == QString( "Got Tomahawk?" ) )
310
QString nodeCap = regex.cap( i + 1 );
312
node = nodeCap.mid( 1 );
315
if ( node.isEmpty() )
317
qDebug() << "TwitterSipPlugin could not parse node out of the tweet";
321
qDebug() << "TwitterSipPlugin parsed node " << node << " out of the tweet";
323
if ( node == Database::instance()->impl()->dbid() )
325
qDebug() << "My dbid found; ignoring";
329
QVariantHash peerData;
330
if( m_cachedPeers.contains( screenName ) )
332
peerData = m_cachedPeers[screenName].toHash();
333
//force a re-send of info but no need to re-register
334
peerData["resend"] = QVariant::fromValue< bool >( true );
335
if ( peerData["node"].toString() != node )
336
peerData["rekey"] = QVariant::fromValue< bool >( true );
338
peerData["node"] = QVariant::fromValue< QString >( node );
339
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, peerData ) );
343
TwitterSipPlugin::friendsTimelineStatuses( const QList< QTweetStatus > &statuses )
345
tDebug() << Q_FUNC_INFO;
346
QRegExp regex( s_gotTomahawkRegex, Qt::CaseSensitive, QRegExp::RegExp2 );
348
QHash< QString, QTweetStatus > latestHash;
349
foreach ( QTweetStatus status, statuses )
351
if ( !regex.exactMatch( status.text() ) )
354
if ( !latestHash.contains( status.user().screenName() ) )
355
latestHash[status.user().screenName()] = status;
358
if ( status.id() > latestHash[status.user().screenName()].id() )
359
latestHash[status.user().screenName()] = status;
363
foreach( QTweetStatus status, latestHash.values() )
365
if ( status.id() > m_cachedFriendsSinceId )
366
m_cachedFriendsSinceId = status.id();
368
tDebug() << "TwitterSipPlugin checking mention from " << status.user().screenName() << " with content " << status.text();
369
parseGotTomahawk( regex, status.user().screenName(), status.text() );
372
m_configuration[ "cachedfriendssinceid" ] = m_cachedFriendsSinceId;
377
TwitterSipPlugin::mentionsStatuses( const QList< QTweetStatus > &statuses )
379
tDebug() << Q_FUNC_INFO;
380
QRegExp regex( s_gotTomahawkRegex, Qt::CaseSensitive, QRegExp::RegExp2 );
382
QHash< QString, QTweetStatus > latestHash;
383
foreach ( QTweetStatus status, statuses )
385
if ( !regex.exactMatch( status.text() ) )
388
if ( !latestHash.contains( status.user().screenName() ) )
389
latestHash[status.user().screenName()] = status;
392
if ( status.id() > latestHash[status.user().screenName()].id() )
393
latestHash[status.user().screenName()] = status;
397
foreach( QTweetStatus status, latestHash.values() )
399
if ( status.id() > m_cachedMentionsSinceId )
400
m_cachedMentionsSinceId = status.id();
402
tDebug() << "TwitterSipPlugin checking mention from " << status.user().screenName() << " with content " << status.text();
403
parseGotTomahawk( regex, status.user().screenName(), status.text() );
406
m_configuration[ "cachedmentionssinceid" ] = m_cachedMentionsSinceId;
411
TwitterSipPlugin::pollDirectMessages()
416
if ( m_cachedDirectMessagesSinceId == 0 )
417
m_cachedDirectMessagesSinceId = m_configuration[ "cacheddirectmessagessinceid" ].toLongLong();
419
tDebug() << "TwitterSipPlugin looking for direct messages since id " << m_cachedDirectMessagesSinceId;
421
if ( !m_directMessages.isNull() )
422
m_directMessages.data()->fetch( m_cachedDirectMessagesSinceId, 0, 800 );
426
TwitterSipPlugin::directMessages( const QList< QTweetDMStatus > &messages )
428
tDebug() << Q_FUNC_INFO;
430
QRegExp regex( s_gotTomahawkRegex, Qt::CaseSensitive, QRegExp::RegExp2 );
431
QString myScreenName = m_configuration[ "screenname" ].toString();
433
QHash< QString, QTweetDMStatus > latestHash;
434
foreach ( QTweetDMStatus status, messages )
436
if ( !regex.exactMatch( status.text() ) )
438
QStringList splitList = status.text().split(':');
439
if ( splitList.length() != 5 )
441
if ( splitList[0] != "TOMAHAWKPEER" )
443
if ( !splitList[1].startsWith( "Host=" ) || !splitList[2].startsWith( "Port=" ) || !splitList[3].startsWith( "Node=" ) || !splitList[4].startsWith( "PKey=" ) )
445
int port = splitList[2].mid( 5 ).toInt();
450
if ( !latestHash.contains( status.senderScreenName() ) )
451
latestHash[status.senderScreenName()] = status;
454
if ( status.id() > latestHash[status.senderScreenName()].id() )
455
latestHash[status.senderScreenName()] = status;
459
foreach( QTweetDMStatus status, latestHash.values() )
461
qDebug() << "TwitterSipPlugin checking direct message from " << status.senderScreenName() << " with content " << status.text();
462
if ( status.id() > m_cachedDirectMessagesSinceId )
463
m_cachedDirectMessagesSinceId = status.id();
465
if ( regex.exactMatch( status.text() ) )
466
parseGotTomahawk( regex, status.sender().screenName(), status.text() );
469
QStringList splitList = status.text().split(':');
470
qDebug() << "TwitterSipPlugin found " << splitList.length() << " parts to the message; the parts are:";
471
foreach( QString part, splitList )
473
//validity is checked above
474
int port = splitList[2].mid( 5 ).toInt();
475
QString host = splitList[1].mid( 5 );
476
QString node = splitList[3].mid( 5 );
477
QString pkey = splitList[4].mid( 5 );
478
QStringList splitNode = node.split('*');
479
if ( splitNode.length() != 2 )
481
qDebug() << "Old-style node info found, ignoring";
484
qDebug() << "TwitterSipPlugin found a peerstart message from " << status.senderScreenName() << " with host " << host << " and port " << port << " and pkey " << pkey << " and node " << splitNode[0] << " destined for node " << splitNode[1];
487
QVariantHash peerData = ( m_cachedPeers.contains( status.senderScreenName() ) ) ?
488
m_cachedPeers[status.senderScreenName()].toHash() :
491
peerData["host"] = QVariant::fromValue< QString >( host );
492
peerData["port"] = QVariant::fromValue< int >( port );
493
peerData["pkey"] = QVariant::fromValue< QString >( pkey );
494
peerData["node"] = QVariant::fromValue< QString >( splitNode[0] );
495
peerData["dirty"] = QVariant::fromValue< bool >( true );
497
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, status.senderScreenName() ), Q_ARG( QVariantHash, peerData ) );
499
if ( Database::instance()->impl()->dbid().startsWith( splitNode[1] ) )
501
qDebug() << "TwitterSipPlugin found message destined for this node; destroying it";
502
if ( !m_directMessageDestroy.isNull() )
503
m_directMessageDestroy.data()->destroyMessage( status.id() );
508
m_configuration[ "cacheddirectmessagessinceid" ] = m_cachedDirectMessagesSinceId;
513
TwitterSipPlugin::registerOffer( const QString &screenName, const QVariantHash &peerData )
515
qDebug() << Q_FUNC_INFO;
517
bool peersChanged = false;
518
bool needToSend = false;
519
bool needToAddToCache = false;
521
QString friendlyName = QString( '@' + screenName );
523
if ( !m_cachedAvatars.contains( screenName ) )
524
QMetaObject::invokeMethod( this, "fetchAvatar", Q_ARG( QString, screenName ) );
526
QVariantHash _peerData( peerData );
528
if ( _peerData.contains( "dirty" ) )
531
_peerData.remove( "dirty" );
534
if ( _peerData.contains( "resend" ) )
538
_peerData.remove( "resend" );
541
if ( !_peerData.contains( "okey" ) ||
542
!_peerData.contains( "onod" ) ||
543
( _peerData.contains( "onod" ) && _peerData["onod"] != Database::instance()->impl()->dbid() ) )
545
QString okey = QUuid::createUuid().toString().split( '-' ).last();
547
_peerData["okey"] = QVariant::fromValue< QString >( okey );
548
_peerData["onod"] = QVariant::fromValue< QString >( Database::instance()->impl()->dbid() );
550
needToAddToCache = true;
554
if ( _peerData.contains( "rekey" ) || !m_keyCache.contains( _peerData["okey"].toString() ) )
556
_peerData.remove( "rekey" );
557
needToAddToCache = true;
560
if ( !_peerData.contains( "ohst" ) || !_peerData.contains( "oprt" ) ||
561
_peerData["ohst"].toString() != Servent::instance()->externalAddress() ||
562
_peerData["oprt"].toInt() != Servent::instance()->externalPort()
566
if( needToAddToCache && _peerData.contains( "node" ) )
568
qDebug() << "TwitterSipPlugin registering offer to " << friendlyName << " with node " << _peerData["node"].toString() << " and offeredkey " << _peerData["okey"].toString();
569
m_keyCache << Servent::instance()->createConnectionKey( friendlyName, _peerData["node"].toString(), _peerData["okey"].toString(), false );
572
if( needToSend && _peerData.contains( "node") )
574
qDebug() << "TwitterSipPlugin needs to send and has node";
575
_peerData["ohst"] = QVariant::fromValue< QString >( Servent::instance()->externalAddress() );
576
_peerData["oprt"] = QVariant::fromValue< int >( Servent::instance()->externalPort() );
578
if( !Servent::instance()->externalAddress().isEmpty() && !Servent::instance()->externalPort() == 0 )
579
QMetaObject::invokeMethod( this, "sendOffer", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, _peerData ) );
581
qDebug() << "TwitterSipPlugin did not send offer because external address is " << Servent::instance()->externalAddress() << " and external port is " << Servent::instance()->externalPort();
586
_peerData["lastseen"] = QString::number( QDateTime::currentMSecsSinceEpoch() );
587
m_cachedPeers[screenName] = QVariant::fromValue< QVariantHash >( _peerData );
588
m_configuration[ "cachedpeers" ] = m_cachedPeers;
592
if ( m_state == Tomahawk::Accounts::Account::Connected && _peerData.contains( "host" ) && _peerData.contains( "port" ) && _peerData.contains( "pkey" ) )
593
QMetaObject::invokeMethod( this, "makeConnection", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, _peerData ) );
598
TwitterSipPlugin::sendOffer( const QString &screenName, const QVariantHash &peerData )
600
qDebug() << Q_FUNC_INFO;
601
QString offerString = QString( "TOMAHAWKPEER:Host=%1:Port=%2:Node=%3*%4:PKey=%5" ).arg( peerData["ohst"].toString() )
602
.arg( peerData["oprt"].toString() )
603
.arg( Database::instance()->impl()->dbid() )
604
.arg( peerData["node"].toString().left( 8 ) )
605
.arg( peerData["okey"].toString() );
606
qDebug() << "TwitterSipPlugin sending message to " << screenName << ": " << offerString;
607
if( !m_directMessageNew.isNull() )
608
m_directMessageNew.data()->post( screenName, offerString );
612
TwitterSipPlugin::makeConnection( const QString &screenName, const QVariantHash &peerData )
614
qDebug() << Q_FUNC_INFO;
615
if ( !peerData.contains( "host" ) || !peerData.contains( "port" ) || !peerData.contains( "pkey" ) || !peerData.contains( "node" ) ||
616
peerData["host"].toString().isEmpty() || peerData["port"].toString().isEmpty() || peerData["pkey"].toString().isEmpty() || peerData["node"].toString().isEmpty() )
618
qDebug() << "TwitterSipPlugin could not find host and/or port and/or pkey and/or node for peer " << screenName;
622
if ( peerData["host"].toString() == Servent::instance()->externalAddress() &&
623
peerData["port"].toInt() == Servent::instance()->externalPort() )
625
qDebug() << "TwitterSipPlugin asked to make connection to our own host and port, ignoring " << screenName;
629
QString friendlyName = QString( '@' + screenName );
630
if ( !Servent::instance()->connectedToSession( peerData["node"].toString() ) )
631
Servent::instance()->connectToPeer( peerData["host"].toString(),
632
peerData["port"].toString().toInt(),
633
peerData["pkey"].toString(),
635
peerData["node"].toString() );
639
TwitterSipPlugin::directMessagePosted( const QTweetDMStatus& message )
641
qDebug() << Q_FUNC_INFO;
642
qDebug() << "TwitterSipPlugin sent message to " << message.recipientScreenName() << " containing: " << message.text();
647
TwitterSipPlugin::directMessagePostError( QTweetNetBase::ErrorCode errorCode, const QString &message )
649
Q_UNUSED( errorCode );
651
qDebug() << Q_FUNC_INFO;
652
qDebug() << "TwitterSipPlugin received an error posting direct message: " << m_directMessageNew.data()->lastErrorMessage();
656
TwitterSipPlugin::directMessageDestroyed( const QTweetDMStatus& message )
658
qDebug() << Q_FUNC_INFO;
659
qDebug() << "TwitterSipPlugin destroyed message " << message.text();
663
TwitterSipPlugin::fetchAvatar( const QString& screenName )
665
qDebug() << Q_FUNC_INFO;
669
QTweetUserShow *userShowFetch = new QTweetUserShow( m_cachedTwitterAuth.data(), this );
670
connect( userShowFetch, SIGNAL( parsedUserInfo( QTweetUser ) ), SLOT( avatarUserDataSlot( QTweetUser ) ) );
671
userShowFetch->fetch( screenName );
675
TwitterSipPlugin::avatarUserDataSlot( const QTweetUser &user )
677
tDebug() << Q_FUNC_INFO;
678
if ( !isValid() || user.profileImageUrl().isEmpty())
681
QNetworkRequest request( user.profileImageUrl() );
682
QNetworkReply *reply = m_cachedTwitterAuth.data()->networkAccessManager()->get( request );
683
reply->setProperty( "screenname", user.screenName() );
684
connect( reply, SIGNAL( finished() ), this, SLOT( profilePicReply() ) );
689
TwitterSipPlugin::profilePicReply()
691
tDebug() << Q_FUNC_INFO;
692
QNetworkReply *reply = qobject_cast< QNetworkReply* >( sender() );
693
if ( !reply || reply->error() != QNetworkReply::NoError || !reply->property( "screenname" ).isValid() )
695
tDebug() << Q_FUNC_INFO << " reply not valid or came back with error";
698
QString screenName = reply->property( "screenname" ).toString();
699
QString friendlyName = '@' + screenName;
700
QByteArray rawData = reply->readAll();
702
image.loadFromData( rawData, "PNG" );
703
QPixmap pixmap = QPixmap::fromImage( image );
704
m_cachedAvatars[screenName] = pixmap;
705
emit avatarReceived( friendlyName, QPixmap::fromImage( image ) );
709
TwitterSipPlugin::configurationChanged()
711
tDebug() << Q_FUNC_INFO;
712
if ( m_state != Tomahawk::Accounts::Account::Disconnected )
713
m_account->deauthenticate();
719
TwitterSipPlugin::syncConfig()
721
m_account->setConfiguration( m_configuration );