1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-30 17:20:26 +02:00

Merge branch 'master' of github.com:tomahawk-player/tomahawk

This commit is contained in:
Dominik Schmidt
2011-02-14 21:27:16 +01:00
246 changed files with 20684 additions and 251 deletions

View File

@@ -2,6 +2,31 @@ SET( OS_SPECIFIC_LINK_LIBRARIES
${OS_SPECIFIC_LINK_LIBRARIES}
${COREAUDIO_LIBRARY}
${COREFOUNDATION_LIBRARY}
/System/Library/Frameworks/AppKit.framework
/System/Library/Frameworks/Carbon.framework
/System/Library/Frameworks/DiskArbitration.framework
/System/Library/Frameworks/Foundation.framework
/System/Library/Frameworks/IOKit.framework
rtaudio
tomahawklib
)
if (APPLE)
# find_library(GROWL Growl)
# option(ENABLE_SPARKLE "Sparkle updating" ON)
# find_library(SPARKLE Sparkle)
# if (ENABLE_SPARKLE AND SPARKLE)
# set(HAVE_SPARKLE ON)
# endif (ENABLE_SPARKLE AND SPARKLE)
# Uses Darwin kernel version.
# 9.8.0 -> 10.5/Leopard
# 10.4.0 -> 10.6/Snow Leopard
string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${CMAKE_HOST_SYSTEM_VERSION})
if (DARWIN_VERSION GREATER 9)
SET(SNOW_LEOPARD 1)
elseif (DARWIN_VERSION GREATER 8)
SET(LEOPARD 1)
endif (DARWIN_VERSION GREATER 9)
endif (APPLE)

View File

@@ -28,6 +28,7 @@ SET( TOMAHAWK_INC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../include/" )
SET( tomahawkSources ${tomahawkSources}
sip/SipHandler.cpp
sip/twitter/tomahawkoauthtwitter.cpp
infosystem/infosystem.cpp
infosystem/infoplugins/echonestplugin.cpp
@@ -39,6 +40,7 @@ SET( tomahawkSources ${tomahawkSources}
musicscanner.cpp
scriptresolver.cpp
scrobbler.cpp
shortcuthandler.cpp
tomahawkapp.cpp
main.cpp
@@ -57,11 +59,18 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
tomahawkwindow.cpp
)
IF( APPLE )
SET( tomahawkHeaders ${tomahawkHeaders} mac/tomahawkapp_mac.h mac/macshortcuthandler.h )
SET( tomahawkSources ${tomahawkSources} mac/tomahawkapp_mac.mm mac/macshortcuthandler.cpp )
ENDIF( APPLE )
SET( tomahawkHeaders ${tomahawkHeaders}
"${TOMAHAWK_INC_DIR}/tomahawk/tomahawkapp.h"
"${TOMAHAWK_INC_DIR}/tomahawk/infosystem.h"
sip/SipHandler.h
sip/twitter/tomahawkoauthtwitter.h
infosystem/infoplugins/echonestplugin.h
infosystem/infoplugins/musixmatchplugin.h
@@ -72,6 +81,7 @@ SET( tomahawkHeaders ${tomahawkHeaders}
musicscanner.h
scriptresolver.h
scrobbler.h
shortcuthandler.h
)
SET( tomahawkHeadersGui ${tomahawkHeadersGui}
@@ -109,10 +119,12 @@ INCLUDE_DIRECTORIES(
topbar
utils
libtomahawk
mac
../alsa-playback
../rtaudio
../qxt/qxtweb-standalone/qxtweb
../thirdparty/qtweetlib/qtweetlib/src
/usr/include/taglib
/usr/local/include/taglib
@@ -132,12 +144,16 @@ IF( UNIX )
ENDIF( UNIX )
ADD_SUBDIRECTORY( sip/jabber )
ADD_SUBDIRECTORY( sip/twitter )
ADD_SUBDIRECTORY( sip/zeroconf )
kde4_add_app_icon( tomahawkSources "${CMAKE_CURRENT_SOURCE_DIR}/../data/icons/tomahawk-icon-*.png" )
qt4_add_resources( RC_SRCS "../resources.qrc" )
qt4_wrap_cpp( tomahawkMoc ${tomahawkHeaders} )
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/config.h)
SET( final_src ${final_src} ${tomahawkMoc} ${tomahawkSources} ${tomahawkHeaders} )
IF( "${gui}" STREQUAL "no" )
@@ -152,6 +168,8 @@ IF( UNIX AND NOT APPLE )
ENDIF( UNIX AND NOT APPLE )
IF( APPLE )
ADD_EXECUTABLE( tomahawk MACOSX_BUNDLE ${final_src} )
SET_TARGET_PROPERTIES(tomahawk PROPERTIES MACOSX_BUNDLE_INFO_PLIST "../admin/mac/Info.plist"
)
ENDIF( APPLE )
IF( WIN32 )
ADD_EXECUTABLE( tomahawk ${final_src} )
@@ -167,6 +185,7 @@ TARGET_LINK_LIBRARIES( tomahawk
qjson
tag
tomahawk_qtweetlib
)
INCLUDE( "CPack.txt" )

10
src/config.h.in Normal file
View File

@@ -0,0 +1,10 @@
#ifndef CONFIG_H_IN
#define CONFIG_H_IN
#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
#cmakedefine SNOW_LEOPARD
#cmakedefine LEOPARD
#cmakedefine HAVE_SPARKLE
#endif // CONFIG_H_IN

View File

@@ -308,6 +308,7 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
../../thirdparty/jdns
../../thirdparty/jdns/jdns
../../thirdparty/jdns/jdnsshared
../../thirdparty/qtweetlib/qtweetlib/src
playlist
)
@@ -371,6 +372,7 @@ target_link_libraries( tomahawklib
vorbisfile
ogg
FLAC++
tomahawk_qtweetlib
${CLUCENE_LIBRARY}
)

View File

@@ -62,6 +62,15 @@ AudioEngine::~AudioEngine()
delete m_audio;
}
void
AudioEngine::playPause()
{
if( m_audio->isPlaying() )
pause();
else
play();
}
void
AudioEngine::play()
@@ -141,6 +150,11 @@ AudioEngine::setVolume( int percentage )
emit volumeChanged( percentage );
}
void
AudioEngine::mute()
{
setVolume( 0 );
}
void
AudioEngine::onTrackAboutToClose()

View File

@@ -40,6 +40,7 @@ public:
PlaylistInterface* playlist() const { return m_playlist; }
public slots:
void playPause();
void play();
void pause();
void stop();
@@ -51,6 +52,7 @@ public slots:
void lowerVolume() { setVolume( volume() - AUDIO_VOLUME_STEP ); }
void raiseVolume() { setVolume( volume() + AUDIO_VOLUME_STEP ); }
void onVolumeChanged( float volume ) { emit volumeChanged( volume * 100 ); }
void mute();
void playItem( PlaylistInterface* playlist, const Tomahawk::result_ptr& result );
void setPlaylist( PlaylistInterface* playlist ) { m_playlist = playlist; }

View File

@@ -46,6 +46,11 @@ FuzzyIndex::beginIndexing()
{
m_mutex.lock();
delete m_luceneSearcher;
delete m_luceneReader;
m_luceneSearcher = 0;
m_luceneReader = 0;
try
{
IndexWriter luceneWriter = IndexWriter( m_luceneDir, m_analyzer, true );
@@ -71,11 +76,6 @@ FuzzyIndex::appendFields( const QString& table, const QMap< unsigned int, QStrin
{
try
{
delete m_luceneSearcher;
delete m_luceneReader;
m_luceneSearcher = 0;
m_luceneReader = 0;
bool create = !IndexReader::indexExists( TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ).toStdString().c_str() );
IndexWriter luceneWriter = IndexWriter( m_luceneDir, m_analyzer, create );
Document doc;

View File

@@ -123,15 +123,20 @@ Servent::startListening( QHostAddress ha, bool upnp, int port )
QString
Servent::createConnectionKey( const QString& name )
Servent::createConnectionKey( const QString& name, const QString &nodeid, const QString &key, bool onceOnly )
{
qDebug() << Q_FUNC_INFO;
Q_ASSERT( this->thread() == QThread::currentThread() );
QString key = uuid();
QString _key = ( key.isEmpty() ? uuid() : key );
ControlConnection* cc = new ControlConnection( this );
cc->setName( name.isEmpty() ? QString( "KEY(%1)" ).arg( key ) : name );
registerOffer( key, cc );
return key;
if( !nodeid.isEmpty() )
cc->setId( nodeid );
cc->setOnceOnly( onceOnly );
qDebug() << "Creating connection key with name of " << cc->name() << " and id of " << cc->id() << " and key of " << _key << "; key is once only? : " << (onceOnly ? "true" : "false");
registerOffer( _key, cc );
return _key;
}
@@ -141,9 +146,18 @@ Servent::setExternalAddress( QHostAddress ha, unsigned int port )
m_externalAddress = ha;
m_externalPort = port;
if( m_externalPort == 0 )
if( m_externalPort == 0 || m_externalAddress.toString().isEmpty() )
{
qDebug() << "No external access, LAN and outbound connections only!";
if( !TomahawkSettings::instance()->externalHostname().isEmpty() &&
!TomahawkSettings::instance()->externalPort() == 0 )
{
qDebug() << "UPnP failed, have external address/port -- falling back";
m_externalHostname = TomahawkSettings::instance()->externalHostname();
m_externalPort = TomahawkSettings::instance()->externalPort();
qDebug() << m_externalHostname << m_externalPort;
}
else
qDebug() << "No external access, LAN and outbound connections only!";
}
emit ready();
@@ -260,7 +274,7 @@ Servent::readyRead()
qDebug() << m;
if( !nodeid.isEmpty() && cc != 0 ) // only control connections send nodeid
if( !nodeid.isEmpty() ) // only control connections send nodeid
{
foreach( ControlConnection* con, m_controlconnections )
{

View File

@@ -78,7 +78,7 @@ public:
int port() const { return m_port; }
// creates new token that allows a controlconnection to be set up
QString createConnectionKey( const QString& name = "" );
QString createConnectionKey( const QString& name = "", const QString &nodeid = "", const QString &key = "", bool onceOnly = true );
void registerOffer( const QString& key, Connection* conn );

View File

@@ -14,10 +14,13 @@ public:
enum SipErrorCode { AuthError, ConnectionError }; // Placeholder for errors, to be defined
virtual ~SipPlugin() {}
virtual bool isValid() = 0;
virtual const QString name() = 0;
public slots:
virtual bool connect( bool startup = false ) = 0;
virtual void disconnect() = 0;
virtual bool connectPlugin( bool startup = false ) = 0;
virtual void disconnectPlugin() = 0;
virtual void addContact( const QString &jid, const QString& msg = QString() ) = 0;
virtual void sendMsg( const QString& to, const QString& msg ) = 0;

View File

@@ -327,13 +327,16 @@ TomahawkSettings::setExternalHostname(const QString& externalHostname)
int
TomahawkSettings::externalPort() const
{
return value( "network/external-port" ).toInt();
return value( "network/external-port", 50210 ).toInt();
}
void
TomahawkSettings::setExternalPort(int externalPort)
{
setValue( "network/external-port", externalPort);
if ( externalPort == 0 )
setValue( "network/external-port", 50210);
else
setValue( "network/external-port", externalPort);
}
@@ -378,6 +381,89 @@ TomahawkSettings::setLastFmUsername( const QString& username )
setValue( "lastfm/username", username );
}
QString
TomahawkSettings::twitterScreenName() const
{
return value( "twitter/ScreenName" ).toString();
}
void
TomahawkSettings::setTwitterScreenName( const QString& screenName )
{
setValue( "twitter/ScreenName", screenName );
}
QString
TomahawkSettings::twitterOAuthToken() const
{
return value( "twitter/OAuthToken" ).toString();
}
void
TomahawkSettings::setTwitterOAuthToken( const QString& oauthtoken )
{
setValue( "twitter/OAuthToken", oauthtoken );
}
QString
TomahawkSettings::twitterOAuthTokenSecret() const
{
return value( "twitter/OAuthTokenSecret" ).toString();
}
void
TomahawkSettings::setTwitterOAuthTokenSecret( const QString& oauthtokensecret )
{
setValue( "twitter/OAuthTokenSecret", oauthtokensecret );
}
qint64
TomahawkSettings::twitterCachedFriendsSinceId() const
{
return value( "twitter/CachedFriendsSinceID", 0 ).toLongLong();
}
void
TomahawkSettings::setTwitterCachedFriendsSinceId( qint64 cachedId )
{
setValue( "twitter/CachedFriendsSinceID", cachedId );
}
qint64
TomahawkSettings::twitterCachedMentionsSinceId() const
{
return value( "twitter/CachedMentionsSinceID", 0 ).toLongLong();
}
void
TomahawkSettings::setTwitterCachedMentionsSinceId( qint64 cachedId )
{
setValue( "twitter/CachedMentionsSinceID", cachedId );
}
qint64
TomahawkSettings::twitterCachedDirectMessagesSinceId() const
{
return value( "twitter/CachedDirectMessagesSinceID", 0 ).toLongLong();
}
void
TomahawkSettings::setTwitterCachedDirectMessagesSinceId( qint64 cachedId )
{
setValue( "twitter/CachedDirectMessagesSinceID", cachedId );
}
QHash<QString, QVariant>
TomahawkSettings::twitterCachedPeers() const
{
return value( "twitter/CachedPeers", QHash<QString, QVariant>() ).toHash();
}
void
TomahawkSettings::setTwitterCachedPeers( const QHash<QString, QVariant> &cachedPeers )
{
setValue( "twitter/CachedPeers", cachedPeers );
}
bool
TomahawkSettings::scrobblingEnabled() const

View File

@@ -95,7 +95,29 @@ public:
QByteArray lastFmSessionKey() const;
void setLastFmSessionKey( const QByteArray& key );
/// Twitter settings
QString twitterScreenName() const;
void setTwitterScreenName( const QString& screenName );
QString twitterOAuthToken() const;
void setTwitterOAuthToken( const QString& oauthtoken );
QString twitterOAuthTokenSecret() const;
void setTwitterOAuthTokenSecret( const QString& oauthtokensecret );
qint64 twitterCachedFriendsSinceId() const;
void setTwitterCachedFriendsSinceId( qint64 sinceid );
qint64 twitterCachedMentionsSinceId() const;
void setTwitterCachedMentionsSinceId( qint64 sinceid );
qint64 twitterCachedDirectMessagesSinceId() const;
void setTwitterCachedDirectMessagesSinceId( qint64 sinceid );
QHash<QString, QVariant> twitterCachedPeers() const;
void setTwitterCachedPeers( const QHash<QString, QVariant> &cachedPeers );
/// XMPP Component Settings
QString xmppBotServer() const;
void setXmppBotServer( const QString &server );

View File

@@ -0,0 +1,31 @@
#include "macshortcuthandler.h"
#include <QDebug>
#include <IOKit/hidsystem/ev_keymap.h>
using namespace Tomahawk;
MacShortcutHandler::MacShortcutHandler(QObject *parent) :
Tomahawk::ShortcutHandler(parent)
{
}
void
MacShortcutHandler::macMediaKeyPressed( int key )
{
switch (key) {
case NX_KEYTYPE_PLAY:
qDebug() << "emitting PlayPause pressed";
emit playPause();
break;
case NX_KEYTYPE_FAST:
qDebug() << "emitting next pressed";
emit next();
break;
case NX_KEYTYPE_REWIND:
qDebug() << "emitting prev pressed";
emit previous();
break;
}
}

View File

@@ -0,0 +1,22 @@
#ifndef MACSHORTCUTHANDLER_H
#define MACSHORTCUTHANDLER_H
#include "shortcuthandler.h"
#include <QObject>
namespace Tomahawk {
class MacShortcutHandler : public ShortcutHandler
{
Q_OBJECT
public:
explicit MacShortcutHandler(QObject *parent = 0);
void macMediaKeyPressed( int key );
};
}
#endif // MACSHORTCUTHANDLER_H

30
src/mac/tomahawkapp_mac.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef TOMAHAWKAPP_MAC_H
#define TOMAHAWKAPP_MAC_H
// this file and tomahawk_app.mm copied and inspired by mac_startup.* in clementine player,
// copyright David Sansome 2010
class QString;
namespace Tomahawk {
class MacShortcutHandler;
/// Interface between cocoa and tomahawk
class PlatformInterface {
public:
// Called when the application should show itself.
virtual void activate() = 0;
virtual bool loadUrl( const QString& url ) = 0;
virtual ~PlatformInterface() {}
};
void macMain();
void setShortcutHandler(Tomahawk::MacShortcutHandler* engine);
// used for opening files with tomahawk
void setApplicationHandler(PlatformInterface* handler);
};
#endif

205
src/mac/tomahawkapp_mac.mm Normal file
View File

@@ -0,0 +1,205 @@
#include "tomahawkapp_mac.h"
#include "tomahawkapp_macdelegate.h"
#include "macshortcuthandler.h"
#include <QDebug>
#import <AppKit/NSApplication.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSBundle.h>
#import <Foundation/NSError.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSPathUtilities.h>
#import <Foundation/NSThread.h>
#import <Foundation/NSTimer.h>
#import <Foundation/NSAppleEventManager.h>
#import <Foundation/NSURL.h>
#import <AppKit/NSEvent.h>
#import <AppKit/NSNibDeclarations.h>
// Capture global media keys on Mac (Cocoa only!)
// See: http://www.rogueamoeba.com/utm/2007/09/29/apple-keyboard-media-key-event-handling/
@interface MacApplication :NSApplication {
Tomahawk::MacShortcutHandler* shortcut_handler_;
Tomahawk::PlatformInterface* application_handler_;
}
- (Tomahawk::MacShortcutHandler*) shortcutHandler;
- (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler;
- (Tomahawk::PlatformInterface*) application_handler;
- (void) setApplicationHandler: (Tomahawk::PlatformInterface*)handler;
- (void) getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
- (void) mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat;
@end
@implementation AppDelegate
- (id) init {
if ((self = [super init])) {
application_handler_ = nil;
// dock_menu_ = nil;
}
return self;
}
- (id) initWithHandler: (Tomahawk::PlatformInterface*)handler {
application_handler_ = handler;
return self;
}
- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag {
if (application_handler_) {
application_handler_->activate();
}
return YES;
}
/*
- (void) setDockMenu: (NSMenu*)menu {
dock_menu_ = menu;
}
- (NSMenu*) applicationDockMenu: (NSApplication*)sender {
return dock_menu_;
}
*/
- (BOOL) application: (NSApplication*)app openFile:(NSString*)filename {
qDebug() << "Wants to open:" << [filename UTF8String];
if (application_handler_->loadUrl(QString::fromUtf8([filename UTF8String]))) {
return YES;
}
return NO;
}
@end
@implementation MacApplication
- (id) init {
if ((self = [super init])) {
[self setShortcutHandler:nil];
[self setApplicationHandler:nil];
}
return self;
}
- (Tomahawk::MacShortcutHandler*) shortcutHandler {
return shortcut_handler_;
}
- (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler {
qDebug() << "Setting shortcut handler of MacAPp";
shortcut_handler_ = handler;
}
- (Tomahawk::PlatformInterface*) application_handler {
return application_handler_;
}
- (void) setApplicationHandler: (Tomahawk::PlatformInterface*)handler {
AppDelegate* delegate = [[AppDelegate alloc] initWithHandler:handler];
[self setDelegate:delegate];
}
-(void) sendEvent: (NSEvent*)event {
if ([event type] == NSSystemDefined && [event subtype] == 8) {
int keycode = (([event data1] & 0xFFFF0000) >> 16);
int keyflags = ([event data1] & 0x0000FFFF);
int keystate = (((keyflags & 0xFF00) >> 8)) == 0xA;
int keyrepeat = (keyflags & 0x1);
[self mediaKeyEvent: keycode state: keystate repeat: keyrepeat];
}
[super sendEvent: event];
}
-(void) mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat {
if (!shortcut_handler_) {
return;
}
if (state == 0) {
shortcut_handler_->macMediaKeyPressed(key);
}
}
@end
void Tomahawk::macMain() {
[[NSAutoreleasePool alloc] init];
// Creates and sets the magic global variable so QApplication will find it.
[MacApplication sharedApplication];
#ifdef HAVE_SPARKLE
// Creates and sets the magic global variable for Sparkle.
[[SUUpdater sharedUpdater] setDelegate: NSApp];
#endif
}
void Tomahawk::setShortcutHandler(Tomahawk::MacShortcutHandler* handler) {
[NSApp setShortcutHandler: handler];
}
void Tomahawk::setApplicationHandler(Tomahawk::PlatformInterface* handler) {
[NSApp setApplicationHandler: handler];
}
void CheckForUpdates() {
#ifdef HAVE_SPARKLE
[[SUUpdater sharedUpdater] checkForUpdates: NSApp];
#endif
}
QString GetBundlePath() {
CFURLRef app_url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
CFStringRef mac_path = CFURLCopyFileSystemPath(app_url, kCFURLPOSIXPathStyle);
const char* path = CFStringGetCStringPtr(mac_path, CFStringGetSystemEncoding());
QString bundle_path = QString::fromUtf8(path);
CFRelease(app_url);
CFRelease(mac_path);
return bundle_path;
}
QString GetResourcesPath() {
QString bundle_path = GetBundlePath();
return bundle_path + "/Contents/Resources";
}
QString GetApplicationSupportPath() {
NSAutoreleasePool* pool = [NSAutoreleasePool alloc];
[pool init];
NSArray* paths = NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory,
NSUserDomainMask,
YES);
QString ret;
if ([paths count] > 0) {
NSString* user_path = [paths objectAtIndex:0];
ret = QString::fromUtf8([user_path UTF8String]);
} else {
ret = "~/Library/Application Support";
}
[pool drain];
return ret;
}
QString GetMusicDirectory() {
NSAutoreleasePool* pool = [NSAutoreleasePool alloc];
[pool init];
NSArray* paths = NSSearchPathForDirectoriesInDomains(
NSMusicDirectory,
NSUserDomainMask,
YES);
QString ret;
if ([paths count] > 0) {
NSString* user_path = [paths objectAtIndex:0];
ret = QString::fromUtf8([user_path UTF8String]);
} else {
ret = "~/Music";
}
[pool drain];
return ret;
}

View File

@@ -1,8 +1,24 @@
#include "tomahawk/tomahawkapp.h"
#ifdef Q_WS_MAC
#include "tomahawkapp_mac.h"
#include </System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Headers/AppleEvents.h>
static pascal OSErr appleEventHandler( const AppleEvent*, AppleEvent*, long );
#endif
#include <exception>
int main( int argc, char *argv[] )
{
#ifdef Q_WS_MAC
// Do Mac specific startup to get media keys working.
// This must go before QApplication initialisation.
Tomahawk::macMain();
// used for url handler
AEEventHandlerUPP h = AEEventHandlerUPP( appleEventHandler );
AEInstallEventHandler( 'GURL', 'GURL', h, 0, false );
#endif
try {
TomahawkApp a( argc, argv );
return a.exec();
@@ -10,3 +26,31 @@ int main( int argc, char *argv[] )
return 0;
}
}
#ifdef Q_WS_MAC
static pascal OSErr appleEventHandler( const AppleEvent* e, AppleEvent*, long )
{
OSType id = typeWildCard;
AEGetAttributePtr( e, keyEventIDAttr, typeType, 0, &id, sizeof(id), 0 );
switch (id)
{
case 'GURL':
{
DescType type;
Size size;
char buf[1024];
AEGetParamPtr( e, keyDirectObject, typeChar, &type, &buf, 1023, &size );
buf[size] = '\0';
QString url = QString::fromUtf8( buf );
static_cast<TomahawkApp*>(qApp)->loadUrl( url );
return noErr;
}
default:
return unimpErr;
}
}
#endif

View File

@@ -1,7 +1,3 @@
#include "settingsdialog.h"
#include "ui_settingsdialog.h"
#include "ui_proxydialog.h"
#include <QCryptographicHash>
#include <QDebug>
#include <QDesktopServices>
@@ -14,11 +10,18 @@
#include <lastfm/XmlQuery>
#endif
#include <qtweetaccountverifycredentials.h>
#include <qtweetstatusupdate.h>
#include "settingsdialog.h"
#include "ui_settingsdialog.h"
#include "ui_proxydialog.h"
#include "tomahawk/tomahawkapp.h"
#include "musicscanner.h"
#include "tomahawksettings.h"
#include "sip/SipHandler.h"
#include "sip/twitter/tomahawkoauthtwitter.h"
#include <database/database.h>
static QString
md5( const QByteArray& src )
@@ -47,19 +50,23 @@ SettingsDialog::SettingsDialog( QWidget *parent )
ui->jabberPassword->setText( s->jabberPassword() );
ui->jabberServer->setText( s->jabberServer() );
ui->jabberPort->setValue( s->jabberPort() );
ui->staticHostName->setText( s->externalHostname() );
ui->proxyButton->setVisible( false );
ui->staticPort->setValue( s->externalPort() );
if ( ui->jabberPort->text().toInt() != 5222 || !ui->jabberServer->text().isEmpty() )
ui->proxyButton->setVisible( false );
if ( s->twitterOAuthToken().isEmpty() || s->twitterOAuthTokenSecret().isEmpty() )
{
ui->checkBoxAdvanced->setChecked( true );
ui->twitterStatusLabel->setText("Status: No saved credentials");
ui->twitterAuthenticateButton->setText( "Authenticate" );
ui->twitterInstructionsBox->setVisible( false );
}
else
{
// hide advanved settings
ui->checkBoxAdvanced->setChecked( false );
ui->groupBoxJabberAdvanced->setVisible( false );
ui->groupBoxNetworkAdvanced->setVisible( false );
ui->twitterStatusLabel->setText("Status: Credentials saved");
ui->twitterAuthenticateButton->setText( "Re-authenticate" );
ui->twitterInstructionsBox->setVisible( true );
}
// MUSIC SCANNER
@@ -118,6 +125,7 @@ SettingsDialog::~SettingsDialog()
s->setJabberPort( ui->jabberPort->value() );
s->setExternalHostname( ui->staticHostName->text() );
s->setExternalPort( ui->staticPort->value() );
s->setScannerPath( ui->lineEditMusicPath->text() );
@@ -140,8 +148,8 @@ SettingsDialog::~SettingsDialog()
if( rejabber )
{
APP->sipHandler()->disconnect();
APP->sipHandler()->connect();
APP->sipHandler()->disconnectPlugins();
APP->sipHandler()->connectPlugins();
}
}
else
@@ -273,6 +281,91 @@ SettingsDialog::onLastFmFinished()
#endif
}
void
SettingsDialog::authenticateTwitter()
{
TomahawkOAuthTwitter *twitAuth = new TomahawkOAuthTwitter( this );
twitAuth->setNetworkAccessManager( TomahawkUtils::nam() );
twitAuth->authorizePin();
if ( !twitAuth->oauthToken().isEmpty() && !twitAuth->oauthTokenSecret().isEmpty() )
{
TomahawkSettings* s = TomahawkSettings::instance();
s->setTwitterOAuthToken( twitAuth->oauthToken() );
s->setTwitterOAuthTokenSecret( twitAuth->oauthTokenSecret() );
ui->twitterStatusLabel->setText("Status: Credentials saved");
ui->twitterAuthenticateButton->setText( "Re-authenticate" );
ui->twitterInstructionsBox->setVisible( true );
TomahawkSettings::instance()->setTwitterCachedFriendsSinceId( 0 );
TomahawkSettings::instance()->setTwitterCachedMentionsSinceId( 0 );
TomahawkApp::instance()->sipHandler()->connectPlugins( false, "SIPTWITTER" );
}
else
{
TomahawkSettings* s = TomahawkSettings::instance();
s->setTwitterOAuthToken( QString() );
s->setTwitterOAuthTokenSecret( QString() );
ui->twitterStatusLabel->setText("Status: No saved credentials");
ui->twitterAuthenticateButton->setText( "Authenticate" );
ui->twitterInstructionsBox->setVisible( false );
QMessageBox::critical( 0, QString("Tweetin' Error"), QString("There was an error validating your authentication") );
}
}
void
SettingsDialog::startPostGotTomahawkStatus()
{
qDebug() << "Posting Got Tomahawk status";
TomahawkSettings* s = TomahawkSettings::instance();
if ( s->twitterOAuthToken().isEmpty() || s->twitterOAuthTokenSecret().isEmpty() )
{
QMessageBox::critical( 0, QString("Tweetin' Error"), QString("Your saved credentials could not be loaded.\nYou may wish to try re-authenticating.") );
return;
}
TomahawkOAuthTwitter *twitAuth = new TomahawkOAuthTwitter( this );
twitAuth->setNetworkAccessManager( TomahawkUtils::nam() );
twitAuth->setOAuthToken( s->twitterOAuthToken().toLatin1() );
twitAuth->setOAuthTokenSecret( s->twitterOAuthTokenSecret().toLatin1() );
QTweetAccountVerifyCredentials *credVerifier = new QTweetAccountVerifyCredentials( twitAuth, this );
connect( credVerifier, SIGNAL( parsedUser(const QTweetUser &) ), SLOT( postGotTomahawkStatusAuthVerifyReply(const QTweetUser &) ) );
credVerifier->verify();
}
void
SettingsDialog::postGotTomahawkStatusAuthVerifyReply( const QTweetUser &user )
{
if ( user.id() == 0 )
{
QMessageBox::critical( 0, QString("Tweetin' Error"), QString("Your saved credentials could not be verified.\nYou may wish to try re-authenticating.") );
return;
}
TomahawkSettings* s = TomahawkSettings::instance();
s->setTwitterScreenName( user.screenName() );
TomahawkOAuthTwitter *twitAuth = new TomahawkOAuthTwitter( this );
twitAuth->setNetworkAccessManager( TomahawkUtils::nam() );
twitAuth->setOAuthToken( s->twitterOAuthToken().toLatin1() );
twitAuth->setOAuthTokenSecret( s->twitterOAuthTokenSecret().toLatin1() );
QTweetStatusUpdate *statUpdate = new QTweetStatusUpdate( twitAuth, this );
connect( statUpdate, SIGNAL( postedStatus(const QTweetStatus &) ), SLOT( postGotTomahawkStatusUpdateReply(const QTweetStatus &) ) );
connect( statUpdate, SIGNAL( error(QTweetNetBase::ErrorCode, const QString&) ), SLOT( postGotTomahawkStatusUpdateError(QTweetNetBase::ErrorCode, const QString &) ) );
QString uuid = QUuid::createUuid();
statUpdate->post( QString( "Got Tomahawk? {" ) + Database::instance()->dbid() + QString( "} (" ) + uuid.mid( 1, 8 ) + QString( ")" ) );
}
void
SettingsDialog::postGotTomahawkStatusUpdateReply( const QTweetStatus& status )
{
if ( status.id() == 0 )
QMessageBox::critical( 0, QString("Tweetin' Error"), QString("There was an error posting your status -- sorry!") );
else
QMessageBox::information( 0, QString("Tweeted!"), QString("Your tweet has been posted!") );
}
void
SettingsDialog::postGotTomahawkStatusUpdateError( QTweetNetBase::ErrorCode code, const QString& errorMsg )
{
qDebug() << Q_FUNC_INFO;
qDebug() << "Error posting Got Tomahawk message, error code is " << code << ", error message is " << errorMsg;
QMessageBox::critical( 0, QString("Tweetin' Error"), QString("There was an error posting your status -- sorry!") );
}
ProxyDialog::ProxyDialog( QWidget *parent )
: QDialog( parent )

View File

@@ -3,6 +3,10 @@
#include <QDialog>
#include <qtweetstatus.h>
#include <qtweetuser.h>
#include <qtweetnetbase.h>
class QNetworkReply;
namespace Ui
@@ -50,7 +54,13 @@ private slots:
void testLastFmLogin();
void onLastFmFinished();
void authenticateTwitter();
void startPostGotTomahawkStatus();
void postGotTomahawkStatusAuthVerifyReply( const QTweetUser &user );
void postGotTomahawkStatusUpdateReply( const QTweetStatus &status );
void postGotTomahawkStatusUpdateError( QTweetNetBase::ErrorCode, const QString &errorMsg );
void addScriptResolver();
void scriptSelectionChanged();
void removeScriptResolver();

View File

@@ -40,36 +40,30 @@
<number>16</number>
</property>
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="horizontalSpacing">
<number>16</number>
</property>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Jabber ID:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>jabberUsername</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<item>
<widget class="QLineEdit" name="jabberUsername">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -79,20 +73,23 @@
</property>
</widget>
</item>
<item row="3" column="0">
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Password:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>jabberPassword</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<item>
<widget class="QLineEdit" name="jabberPassword">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -108,22 +105,6 @@
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="checkBoxAdvanced">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Show Advanced Settings</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -227,72 +208,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBoxNetworkAdvanced">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Advanced Network Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<layout class="QHBoxLayout" name="staticHostNameHLayout">
<item>
<widget class="QLabel" name="staticHostNameLabel">
<property name="text">
<string>Static Host Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="staticHostName"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="proxySettingsHLayout">
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="proxyButton">
<property name="text">
<string>Proxy Settings...</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
@@ -306,50 +221,189 @@
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="checkBoxHttp">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Playdar HTTP API - NO AUTH</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxUpnp">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Use UPnP to establish port forward</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxJabberAutoConnect">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Connect automatically when Tomahawk starts</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabNetwork">
<attribute name="title">
<string>Network</string>
</attribute>
<widget class="QGroupBox" name="groupBoxNetworkAdvanced">
<property name="geometry">
<rect>
<x>20</x>
<y>10</y>
<width>551</width>
<height>341</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Advanced Network Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>If you're having difficulty connecting to peers, try setting this to your external IP address/host name and a port number (default 50210). Make sure to forward that port to this machine!</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="staticHostNameLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Static Host Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="staticHostName"/>
</item>
<item>
<widget class="QLabel" name="staticPortLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Static Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="staticPort">
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>50210</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="proxySettingsHLayout">
<item>
<spacer name="proxySettingsLeftSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="proxyButton">
<property name="text">
<string>Proxy Settings...</string>
</property>
</widget>
</item>
<item>
<spacer name="proxySettingsRightSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="checkBoxHttp">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Playdar HTTP API - NO AUTH</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxJabberAutoConnect">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Connect automatically when Tomahawk starts</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxUpnp">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Use UPnP to establish port forward</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QWidget" name="tabMusic">
<attribute name="title">
<string>Music</string>
<string>Local Music</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="margin">
@@ -412,6 +466,104 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tabTwitter">
<attribute name="title">
<string>Twitter</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<layout class="QVBoxLayout" name="twitterVertLayout">
<item>
<widget class="QLabel" name="twitterInfoLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Authenticating with Twitter allows you to discover and play music from your Twitter friends running Tomahawk.
This feature works best when you have set a static host name in the &quot;Network&quot; settings tab under Advanced Settings, but may work even if you do not. Please note: this discovery uses Direct Messages and will only work when both Twitter users have followed each other. Tomahawk will attempt to &quot;clean up&quot; after itself to keep your Direct Message inbox tidy, but may miss some.
When you press the button your web browser will launch and take you to Twitter.com to authenticate. You must copy and paste the PIN number into the dialog box that appears.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="twitterHorizontalLayout">
<item>
<widget class="QLabel" name="twitterStatusLabel">
<property name="text">
<string>Status: No saved credentials</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="twitterAuthenticateButton">
<property name="text">
<string>Authenticate with Twitter</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="twitterInstructionsBox">
<property name="title">
<string>Instructions</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<layout class="QVBoxLayout" name="twitterInstructionsVLayout">
<item>
<widget class="QLabel" name="twitterInstructionsInfoLabel">
<property name="text">
<string>How it works is simple: just press the button below to tweet &quot;Got Tomahawk?&quot; and some necessary information. Then be (very) patient. Twitter is an asynchronous protocol so it can take a bit!
If connections to peers seem to have been lost, just press the button again to re-post a tweet for resynchronization.
</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="twitterTweetGotTomahawkButton">
<property name="text">
<string>Press here to have Tomahawk post a tweet</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="twitterVertSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabLastfm">
<attribute name="title">
<string>Last.fm</string>
@@ -641,50 +793,34 @@
</hints>
</connection>
<connection>
<sender>checkBoxAdvanced</sender>
<signal>toggled(bool)</signal>
<receiver>proxyButton</receiver>
<slot>setVisible(bool)</slot>
<sender>twitterAuthenticateButton</sender>
<signal>pressed()</signal>
<receiver>SettingsDialog</receiver>
<slot>authenticateTwitter()</slot>
<hints>
<hint type="sourcelabel">
<x>310</x>
<y>110</y>
<x>459</x>
<y>205</y>
</hint>
<hint type="destinationlabel">
<x>368</x>
<y>194</y>
<x>310</x>
<y>216</y>
</hint>
</hints>
</connection>
<connection>
<sender>checkBoxAdvanced</sender>
<signal>toggled(bool)</signal>
<receiver>groupBoxJabberAdvanced</receiver>
<slot>setVisible(bool)</slot>
<sender>twitterTweetGotTomahawkButton</sender>
<signal>pressed()</signal>
<receiver>SettingsDialog</receiver>
<slot>startPostGotTomahawkStatus()</slot>
<hints>
<hint type="sourcelabel">
<x>310</x>
<y>115</y>
<y>313</y>
</hint>
<hint type="destinationlabel">
<x>310</x>
<y>174</y>
</hint>
</hints>
</connection>
<connection>
<sender>checkBoxAdvanced</sender>
<signal>toggled(bool)</signal>
<receiver>groupBoxNetworkAdvanced</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>310</x>
<y>115</y>
</hint>
<hint type="destinationlabel">
<x>310</x>
<y>262</y>
<y>216</y>
</hint>
</hints>
</connection>

13
src/shortcuthandler.cpp Normal file
View File

@@ -0,0 +1,13 @@
#include "shortcuthandler.h"
using namespace Tomahawk;
ShortcutHandler::ShortcutHandler( QObject *parent )
: QObject( parent )
{
}
ShortcutHandler::~ShortcutHandler()
{
}

34
src/shortcuthandler.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef SHORTCUTHANDLER_H
#define SHORTCUTHANDLER_H
#include <QObject>
namespace Tomahawk {
/**
Base class for various shortcut plugins on different platforms
*/
class ShortcutHandler : public QObject
{
Q_OBJECT
public:
virtual ~ShortcutHandler();
signals:
// add more as needed
void playPause();
void pause();
void stop();
void previous();
void next();
void volumeUp();
void volumeDown();
void mute();
protected:
explicit ShortcutHandler( QObject *parent = 0 );
};
}
#endif // SHORTCUTHANDLER_H

View File

@@ -13,14 +13,15 @@
SipHandler::SipHandler( QObject* parent )
: QObject( parent )
, m_connected( false )
{
m_connected = false;
loadPlugins( findPlugins() );
}
SipHandler::~SipHandler()
{
disconnectPlugins();
}
@@ -114,30 +115,39 @@ SipHandler::loadPlugin( QObject* plugin )
void
SipHandler::connect( bool startup )
SipHandler::connectPlugins( bool startup, const QString &pluginName )
{
foreach( SipPlugin* sip, m_plugins )
sip->connect( startup );
{
if ( pluginName.isEmpty() || ( !pluginName.isEmpty() && sip->name() == pluginName ) )
sip->connectPlugin( startup );
}
m_connected = true;
}
void
SipHandler::disconnect()
SipHandler::disconnectPlugins( const QString &pluginName )
{
foreach( SipPlugin* sip, m_plugins )
sip->disconnect();
SourceList::instance()->removeAllRemote();
m_connected = false;
{
if ( pluginName.isEmpty() || ( !pluginName.isEmpty() && sip->name() == pluginName ) )
sip->disconnectPlugin();
}
if( pluginName.isEmpty() )
{
SourceList::instance()->removeAllRemote();
m_connected = false;
}
}
void
SipHandler::toggleConnect()
{
if( m_connected )
disconnect();
disconnectPlugins();
else
connect();
connectPlugins();
}

View File

@@ -19,8 +19,8 @@ public:
public slots:
void addContact( const QString& id ) { qDebug() << Q_FUNC_INFO << id; }
void connect( bool startup = false );
void disconnect();
void connectPlugins( bool startup = false, const QString &pluginName = QString() );
void disconnectPlugins( const QString &pluginName = QString() );
void toggleConnect();
signals:

View File

@@ -12,9 +12,14 @@ JabberPlugin::setProxy( QNetworkProxy* proxy )
p->setProxy( proxy );
}
const QString
JabberPlugin::name()
{
return QString( MYNAME );
}
bool
JabberPlugin::connect( bool startup )
JabberPlugin::connectPlugin( bool startup )
{
qDebug() << "JabberPlugin::connect";
if ( startup && !TomahawkSettings::instance()->jabberAutoConnect() )

View File

@@ -6,6 +6,8 @@
#include "../sipdllmacro.h"
#define MYNAME "SIPJABBER"
class SIPDLLEXPORT JabberPlugin : public SipPlugin
{
Q_OBJECT
@@ -18,12 +20,16 @@ public:
virtual ~JabberPlugin() { delete p; }
//FIXME: Make this more correct
virtual bool isValid() { return true; }
virtual const QString name();
void setProxy( QNetworkProxy* proxy );
public slots:
virtual bool connect( bool startup );
virtual bool connectPlugin( bool startup );
void disconnect()
void disconnectPlugin()
{
QMetaObject::invokeMethod( p,
"disconnect",

View File

@@ -0,0 +1,45 @@
project( tomahawk )
include( ${QT_USE_FILE} )
add_definitions( ${QT_DEFINITIONS} )
add_definitions( -DQT_PLUGIN )
add_definitions( -DQT_SHARED )
add_definitions( -DSIPDLLEXPORT_PRO )
set( twitterSources
twitter.cpp
tomahawkoauthtwitter.cpp
)
set( twitterHeaders
twitter.h
tomahawkoauthtwitter.h
)
include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
${QT_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/thirdparty/qtweetlib/src
)
qt4_wrap_cpp( twitterMoc ${twitterHeaders} )
add_library( sip_twitter SHARED ${twitterSources} ${twitterMoc} )
IF( WIN32 )
SET( OS_SPECIFIC_LINK_LIBRARIES
${OS_SPECIFIC_LINK_LIBRARIES}
"winmm.dll"
"iphlpapi.a"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../build/src/libtomahawk/libtomahawklib.dll"
)
ENDIF( WIN32 )
target_link_libraries( sip_twitter
${QT_LIBRARIES}
${OS_SPECIFIC_LINK_LIBRARIES}
)
IF( APPLE )
SET( CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} "-undefined dynamic_lookup" )
ENDIF( APPLE )
install( TARGETS sip_twitter DESTINATION lib )

View File

@@ -0,0 +1,18 @@
#include "tomahawkoauthtwitter.h"
#include <QInputDialog>
TomahawkOAuthTwitter::TomahawkOAuthTwitter( QObject* parent )
: OAuthTwitter( parent )
{
}
int TomahawkOAuthTwitter::authorizationWidget()
{
bool ok;
int i = QInputDialog::getInt(0, QString( "Twitter PIN" ), QString( "After authenticating on Twitter's web site,\nenter the displayed PIN number here:" ), 0, 0, 2147483647, 1, &ok);
if (ok)
return i;
return 0;
}

View File

@@ -0,0 +1,21 @@
#ifndef TOMAHAWKOAUTHTWITTER
#define TOMAHAWKOAUTHTWITTER
#include <oauthtwitter.h>
#include "../sipdllmacro.h"
class SIPDLLEXPORT TomahawkOAuthTwitter : public OAuthTwitter
{
Q_OBJECT
public:
TomahawkOAuthTwitter( QObject *parent = 0 );
~TomahawkOAuthTwitter() {}
protected:
virtual int authorizationWidget();
};
#endif

548
src/sip/twitter/twitter.cpp Normal file
View File

@@ -0,0 +1,548 @@
#include "twitter.h"
#include <QtPlugin>
#include <QRegExp>
#include <QStringList>
#include <qtweetaccountverifycredentials.h>
#include <qtweetuser.h>
#include <qtweetstatus.h>
#include <utils/tomahawkutils.h>
#include <tomahawksettings.h>
#include <database/database.h>
#include <network/servent.h>
TwitterPlugin::TwitterPlugin()
: SipPlugin()
, m_isAuthed( false )
, m_isOnline( false )
, m_checkTimer( this )
, m_connectTimer( this )
, m_cachedFriendsSinceId( 0 )
, m_cachedMentionsSinceId( 0 )
, m_cachedDirectMessagesSinceId( 0 )
, m_cachedPeers()
, m_keyCache()
, m_finishedFriends( false )
, m_finishedMentions( false )
{
qDebug() << Q_FUNC_INFO;
m_checkTimer.setInterval( 60000 );
m_checkTimer.setSingleShot( false );
connect( &m_checkTimer, SIGNAL( timeout() ), SLOT( checkTimerFired() ) );
m_checkTimer.start();
m_connectTimer.setInterval( 60000 );
m_connectTimer.setSingleShot( false );
connect( &m_connectTimer, SIGNAL( timeout() ), SLOT( connectTimerFired() ) );
m_connectTimer.start();
}
bool
TwitterPlugin::isValid()
{
return m_isAuthed || !m_cachedPeers.isEmpty();
}
const QString
TwitterPlugin::name()
{
qDebug() << "TwitterPlugin returning plugin name " << QString( MYNAME );
return QString( MYNAME );
}
bool
TwitterPlugin::connectPlugin( bool /*startup*/ )
{
qDebug() << Q_FUNC_INFO;
TomahawkSettings *settings = TomahawkSettings::instance();
m_cachedPeers = settings->twitterCachedPeers();
QList<QString> peerlist = m_cachedPeers.keys();
qStableSort( peerlist.begin(), peerlist.end() );
foreach( QString screenName, peerlist )
{
QHash< QString, QVariant > cachedPeer = m_cachedPeers[screenName].toHash();
foreach( QString prop, cachedPeer.keys() )
qDebug() << "TwitterPlugin : " << screenName << ", key " << prop << ", value " << ( cachedPeer[prop].canConvert< QString >() ? cachedPeer[prop].toString() : QString::number( cachedPeer[prop].toInt() ) );
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&cachedPeer ) );
}
if ( settings->twitterOAuthToken().isEmpty() || settings->twitterOAuthTokenSecret().isEmpty() )
{
qDebug() << "TwitterPlugin has empty Twitter credentials; not connecting";
return m_cachedPeers.isEmpty();
}
delete m_twitterAuth.data();
m_twitterAuth = QWeakPointer<TomahawkOAuthTwitter>( new TomahawkOAuthTwitter( this ) );
m_twitterAuth.data()->setNetworkAccessManager( TomahawkUtils::nam() );
m_twitterAuth.data()->setOAuthToken( settings->twitterOAuthToken().toLatin1() );
m_twitterAuth.data()->setOAuthTokenSecret( settings->twitterOAuthTokenSecret().toLatin1() );
QTweetAccountVerifyCredentials *credVerifier = new QTweetAccountVerifyCredentials( m_twitterAuth.data(), this );
connect( credVerifier, SIGNAL( parsedUser(const QTweetUser &) ), SLOT( connectAuthVerifyReply(const QTweetUser &) ) );
credVerifier->verify();
return true;
}
void
TwitterPlugin::disconnectPlugin()
{
qDebug() << Q_FUNC_INFO;
if( !m_friendsTimeline.isNull() )
m_friendsTimeline.data()->deleteLater();
if( !m_twitterAuth.isNull() )
m_twitterAuth.data()->deleteLater();
m_cachedPeers.empty();
delete m_twitterAuth.data();
m_isOnline = false;
}
void
TwitterPlugin::connectAuthVerifyReply( const QTweetUser &user )
{
if ( user.id() == 0 )
{
qDebug() << "TwitterPlugin could not authenticate to Twitter";
m_isAuthed = false;
}
else
{
qDebug() << "TwitterPlugin successfully authenticated to Twitter as user " << user.screenName();
m_isAuthed = true;
if ( !m_twitterAuth.isNull() )
{
TomahawkSettings::instance()->setTwitterScreenName( user.screenName() );
m_friendsTimeline = QWeakPointer<QTweetFriendsTimeline>( new QTweetFriendsTimeline( m_twitterAuth.data(), this ) );
m_mentions = QWeakPointer<QTweetMentions>( new QTweetMentions( m_twitterAuth.data(), this ) );
m_directMessages = QWeakPointer<QTweetDirectMessages>( new QTweetDirectMessages( m_twitterAuth.data(), this ) );
m_directMessageNew = QWeakPointer<QTweetDirectMessageNew>( new QTweetDirectMessageNew( m_twitterAuth.data(), this ) );
m_directMessageDestroy = QWeakPointer<QTweetDirectMessageDestroy>( new QTweetDirectMessageDestroy( m_twitterAuth.data(), this ) );
connect( m_friendsTimeline.data(), SIGNAL( parsedStatuses(const QList< QTweetStatus > &) ), SLOT( friendsTimelineStatuses(const QList<QTweetStatus> &) ) );
connect( m_mentions.data(), SIGNAL( parsedStatuses(const QList< QTweetStatus > &) ), SLOT( mentionsStatuses(const QList<QTweetStatus> &) ) );
connect( m_directMessages.data(), SIGNAL( parsedDirectMessages(const QList<QTweetDMStatus> &)), SLOT( directMessages(const QList<QTweetDMStatus> &) ) );
connect( m_directMessageNew.data(), SIGNAL( parsedDirectMessage(const QTweetDMStatus &)), SLOT( directMessagePosted(const QTweetDMStatus &) ) );
connect( m_directMessageNew.data(), SIGNAL( error(QTweetNetBase::ErrorCode, const QString &) ), SLOT( directMessagePostError(QTweetNetBase::ErrorCode, const QString &) ) );
connect( m_directMessageDestroy.data(), SIGNAL( parsedDirectMessage(const QTweetDMStatus &) ), SLOT( directMessageDestroyed(const QTweetDMStatus &) ) );
m_isOnline = true;
QMetaObject::invokeMethod( this, "checkTimerFired", Qt::AutoConnection );
QTimer::singleShot( 20000, this, SLOT( connectTimerFired() ) );
}
else
{
qDebug() << "TwitterPlugin auth pointer was null!";
m_isAuthed = false;
}
}
}
void
TwitterPlugin::checkTimerFired()
{
if ( !isValid() )
return;
if ( m_cachedFriendsSinceId == 0 )
m_cachedFriendsSinceId = TomahawkSettings::instance()->twitterCachedFriendsSinceId();
qDebug() << "TwitterPlugin looking at friends timeline since id " << m_cachedFriendsSinceId;
if ( !m_friendsTimeline.isNull() )
m_friendsTimeline.data()->fetch( m_cachedFriendsSinceId, 0, 800 );
if ( m_cachedMentionsSinceId == 0 )
m_cachedMentionsSinceId = TomahawkSettings::instance()->twitterCachedMentionsSinceId();
qDebug() << "TwitterPlugin looking at mentions timeline since id " << m_cachedMentionsSinceId;
if ( !m_mentions.isNull() )
m_mentions.data()->fetch( m_cachedMentionsSinceId, 0, 800 );
}
void
TwitterPlugin::connectTimerFired()
{
qDebug() << Q_FUNC_INFO;
if ( !isValid() || m_cachedPeers.isEmpty() )
return;
QString myScreenName = TomahawkSettings::instance()->twitterScreenName();
QList<QString> peerlist = m_cachedPeers.keys();
qStableSort( peerlist.begin(), peerlist.end() );
foreach( QString screenName, peerlist )
{
QHash< QString, QVariant > peerData = m_cachedPeers[screenName].toHash();
if ( !peerData.contains( "host" ) || !peerData.contains( "port" ) || !peerData.contains( "pkey" ) )
{
qDebug() << "TwitterPlugin does not have host, port and/or pkey values for " << screenName;
continue;
}
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
}
}
void
TwitterPlugin::friendsTimelineStatuses( const QList< QTweetStatus > &statuses )
{
qDebug() << Q_FUNC_INFO;
QRegExp regex( QString( "^(@[a-zA-Z0-9]+ )?(Got Tomahawk\\?) (\\{[a-fA-F0-9\\-]+\\}) (.*)$" ), Qt::CaseSensitive, QRegExp::RegExp2 );
QString myScreenName = TomahawkSettings::instance()->twitterScreenName();
QHash< QString, QTweetStatus > latestHash;
foreach ( QTweetStatus status, statuses )
{
if ( !latestHash.contains( status.user().screenName() ) )
latestHash[status.user().screenName()] = status;
else
{
if ( status.id() > latestHash[status.user().screenName()].id() )
latestHash[status.user().screenName()] = status;
}
}
foreach( QTweetStatus status, latestHash.values() )
{
if ( status.id() > m_cachedFriendsSinceId )
m_cachedFriendsSinceId = status.id();
if ( regex.exactMatch( status.text() ) )
{
qDebug() << "TwitterPlugin found an exact tweet from friend " << status.user().screenName();
if ( status.text().startsWith( '@' ) && regex.captureCount() >= 2 && regex.cap( 1 ) != QString( '@' + myScreenName ) )
{
qDebug() << "TwitterPlugin skipping tweet because it's directed @someone that isn't us";
continue;
}
QString node;
for ( int i = 0; i < regex.captureCount(); ++i )
{
if ( regex.cap( i ) == QString( "Got Tomahawk?" ) )
{
QString nodeCap = regex.cap( i + 1 );
nodeCap.chop( 1 );
node = nodeCap.mid( 1 );
}
}
if ( node.isEmpty() )
{
qDebug() << "TwitterPlugin could not parse node out of the tweet";
continue;
}
else
qDebug() << "TwitterPlugin parsed node " << node << " out of the tweet";
if ( status.user().screenName() == myScreenName && node == Database::instance()->dbid() )
continue;
QHash< QString, QVariant > peerData;
if( m_cachedPeers.contains( status.user().screenName() ) )
{
peerData = m_cachedPeers[status.user().screenName()].toHash();
//force a re-send of info but no need to re-register
peerData["resend"] = QVariant::fromValue< bool >( true );
}
peerData["node"] = QVariant::fromValue< QString >( node );
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, status.user().screenName() ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
}
}
TomahawkSettings::instance()->setTwitterCachedFriendsSinceId( m_cachedFriendsSinceId );
m_finishedFriends = true;
QMetaObject::invokeMethod( this, "pollDirectMessages", Qt::AutoConnection );
}
void
TwitterPlugin::mentionsStatuses( const QList< QTweetStatus > &statuses )
{
qDebug() << Q_FUNC_INFO;
QRegExp regex( QString( "^(@[a-zA-Z0-9]+ )?(Got Tomahawk\\?) (\\{[a-fA-F0-9\\-]+\\}) (.*)$" ), Qt::CaseSensitive, QRegExp::RegExp2 );
QString myScreenName = TomahawkSettings::instance()->twitterScreenName();
QHash< QString, QTweetStatus > latestHash;
foreach ( QTweetStatus status, statuses )
{
if ( !latestHash.contains( status.user().screenName() ) )
latestHash[status.user().screenName()] = status;
else
{
if ( status.id() > latestHash[status.user().screenName()].id() )
latestHash[status.user().screenName()] = status;
}
}
foreach( QTweetStatus status, latestHash.values() )
{
if ( status.id() > m_cachedMentionsSinceId )
m_cachedMentionsSinceId = status.id();
if ( regex.exactMatch( status.text() ) )
{
qDebug() << "TwitterPlugin found an exact matching mention from user " << status.user().screenName();
if ( status.text().startsWith( '@' ) && regex.captureCount() >= 2 && regex.cap( 1 ) != QString( '@' + myScreenName ) )
{
qDebug() << "TwitterPlugin skipping mention because it's directed @someone that isn't us";
continue;
}
QString node;
for ( int i = 0; i < regex.captureCount(); ++i )
{
if ( regex.cap( i ) == QString( "Got Tomahawk?" ) )
{
QString nodeCap = regex.cap( i + 1 );
nodeCap.chop( 1 );
node = nodeCap.mid( 1 );
}
}
if ( node.isEmpty() )
{
qDebug() << "TwitterPlugin could not parse node out of the tweet";
continue;
}
else
qDebug() << "TwitterPlugin parsed node " << node << " out of the tweet";
if ( status.user().screenName() == myScreenName && node == Database::instance()->dbid() )
continue;
QHash< QString, QVariant > peerData;
if( m_cachedPeers.contains( status.user().screenName() ) )
{
peerData = m_cachedPeers[status.user().screenName()].toHash();
//force a re-send of info but no need to re-register
peerData["resend"] = QVariant::fromValue< bool >( true );
}
peerData["node"] = QVariant::fromValue< QString >( node );
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, status.user().screenName() ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
}
}
TomahawkSettings::instance()->setTwitterCachedMentionsSinceId( m_cachedMentionsSinceId );
m_finishedMentions = true;
QMetaObject::invokeMethod( this, "pollDirectMessages", Qt::AutoConnection );
}
void
TwitterPlugin::pollDirectMessages()
{
if ( !m_finishedMentions || !m_finishedFriends )
return;
m_finishedFriends = false;
m_finishedMentions = false;
if ( !isValid() )
return;
if ( m_cachedDirectMessagesSinceId == 0 )
m_cachedDirectMessagesSinceId = TomahawkSettings::instance()->twitterCachedDirectMessagesSinceId();
qDebug() << "TwitterPlugin looking for direct messages since id " << m_cachedDirectMessagesSinceId;
if ( !m_directMessages.isNull() )
m_directMessages.data()->fetch( m_cachedDirectMessagesSinceId, 0, 800 );
}
void
TwitterPlugin::directMessages( const QList< QTweetDMStatus > &messages )
{
qDebug() << Q_FUNC_INFO;
QHash< QString, QTweetDMStatus > latestHash;
foreach ( QTweetDMStatus status, messages )
{
if ( !latestHash.contains( status.senderScreenName() ) )
latestHash[status.senderScreenName()] = status;
else
{
if ( status.id() > latestHash[status.senderScreenName()].id() )
latestHash[status.senderScreenName()] = status;
}
}
foreach( QTweetDMStatus status, latestHash.values() )
{
qDebug() << "TwitterPlugin checking direct message from " << status.senderScreenName() << " with content " << status.text();
if ( status.id() > m_cachedDirectMessagesSinceId )
m_cachedDirectMessagesSinceId = status.id();
QStringList splitList = status.text().split(':');
qDebug() << "TwitterPlugin found " << splitList.length() << " parts to the message; the parts are:";
foreach( QString part, splitList )
qDebug() << part;
if ( splitList.length() != 5 )
continue;
if ( splitList[0] != "TOMAHAWKPEER" )
continue;
if ( !splitList[1].startsWith( "Host=" ) || !splitList[2].startsWith( "Port=" ) || !splitList[3].startsWith( "Node=" ) || !splitList[4].startsWith( "PKey=" ) )
continue;
int port = splitList[2].mid( 5 ).toInt();
if ( port == 0 )
continue;
QString host = splitList[1].mid( 5 );
QString node = splitList[3].mid( 5 );
QString pkey = splitList[4].mid( 5 );
qDebug() << "TwitterPlugin found a peerstart message from " << status.senderScreenName() << " with host " << host << " and port " << port << " and pkey " << pkey << " destined for node " << node;
if ( node != Database::instance()->dbid() )
{
qDebug() << "Not destined for this node; leaving it alone and not answering";
continue;
}
QHash< QString, QVariant > peerData = ( m_cachedPeers.contains( status.senderScreenName() ) ) ?
m_cachedPeers[status.senderScreenName()].toHash() :
QHash< QString, QVariant >();
peerData["host"] = QVariant::fromValue< QString >( host );
peerData["port"] = QVariant::fromValue< int >( port );
peerData["pkey"] = QVariant::fromValue< QString >( pkey );
peerData["dirty"] = QVariant::fromValue< bool >( true );
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, status.senderScreenName() ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
if ( !m_directMessageDestroy.isNull() )
m_directMessageDestroy.data()->destroyMessage( status.id() );
}
TomahawkSettings::instance()->setTwitterCachedDirectMessagesSinceId( m_cachedDirectMessagesSinceId );
}
void
TwitterPlugin::registerOffer( const QString &screenName, const QHash< QString, QVariant > &peerData )
{
qDebug() << Q_FUNC_INFO;
bool peersChanged = false;
bool needToSend = false;
bool needToAddToCache = false;
QString friendlyName = QString( '@' + screenName );
QHash< QString, QVariant > _peerData( peerData );
if ( _peerData.contains( "dirty" ) )
{
peersChanged = true;
_peerData.remove( "dirty" );
}
if ( _peerData.contains( "resend" ) )
{
needToSend = true;
peersChanged = true;
_peerData.remove( "resend" );
}
if ( !_peerData.contains( "okey" ) )
{
QString okey = QUuid::createUuid().toString().split( '-' ).last();
okey.chop( 1 );
_peerData["okey"] = QVariant::fromValue< QString >( okey );
peersChanged = true;
needToAddToCache = true;
needToSend = true;
}
if ( !m_keyCache.contains( _peerData["okey"].toString() ) )
needToAddToCache = true;
if ( !_peerData.contains( "ohst" ) || !_peerData.contains( "oprt" ) ||
_peerData["ohst"].toString() != Servent::instance()->externalAddress() ||
_peerData["oprt"].toInt() != Servent::instance()->externalPort()
)
needToSend = true;
if( needToAddToCache && _peerData.contains( "node" ) )
{
qDebug() << "TwitterPlugin registering offer to " << friendlyName << " with node " << _peerData["node"].toString() << " and offeredkey " << _peerData["okey"].toString();
m_keyCache << Servent::instance()->createConnectionKey( friendlyName, _peerData["node"].toString(), _peerData["okey"].toString(), false );
}
if( needToSend && _peerData.contains( "node") )
{
qDebug() << "TwitterPlugin needs to send and has node";
_peerData["ohst"] = QVariant::fromValue< QString >( Servent::instance()->externalAddress() );
_peerData["oprt"] = QVariant::fromValue< int >( Servent::instance()->externalPort() );
peersChanged = true;
if( !Servent::instance()->externalAddress().isEmpty() && !Servent::instance()->externalPort() == 0 )
QMetaObject::invokeMethod( this, "sendOffer", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&_peerData ) );
else
qDebug() << "TwitterPlugin did not send offer because external address is " << Servent::instance()->externalAddress() << " and external port is " << Servent::instance()->externalPort();
}
if ( m_isOnline && _peerData.contains( "host" ) && _peerData.contains( "port" ) && _peerData.contains( "pkey" ) )
QMetaObject::invokeMethod( this, "makeConnection", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&_peerData ) );
if ( peersChanged )
{
m_cachedPeers[screenName] = QVariant::fromValue< QHash< QString, QVariant > >( _peerData );
TomahawkSettings::instance()->setTwitterCachedPeers( m_cachedPeers );
}
}
void
TwitterPlugin::sendOffer( const QString &screenName, const QHash< QString, QVariant > &peerData )
{
qDebug() << Q_FUNC_INFO;
QString offerString = QString( "TOMAHAWKPEER:Host=%1:Port=%2:Node=%3:PKey=%4" ).arg( peerData["ohst"].toString() )
.arg( peerData["oprt"].toString() )
.arg( peerData["node"].toString() )
.arg( peerData["okey"].toString() );
qDebug() << "TwitterPlugin sending message to " << screenName << ": " << offerString;
if( !m_directMessageNew.isNull() )
m_directMessageNew.data()->post( screenName, offerString );
}
void
TwitterPlugin::makeConnection( const QString &screenName, const QHash< QString, QVariant > &peerData )
{
qDebug() << Q_FUNC_INFO;
if ( !peerData.contains( "host" ) || !peerData.contains( "port" ) || !peerData.contains( "pkey" ) || !peerData.contains( "node" ) )
{
qDebug() << "TwitterPlugin could not find host and/or port and/or pkey for peer " << screenName;
return;
}
QString friendlyName = QString( '@' + screenName );
if ( !Servent::instance()->connectedToSession( peerData["node"].toString() ) )
Servent::instance()->connectToPeer( peerData["host"].toString(),
peerData["port"].toString().toInt(),
peerData["pkey"].toString(),
friendlyName,
peerData["node"].toString() );
}
void
TwitterPlugin::directMessagePosted( const QTweetDMStatus& message )
{
qDebug() << Q_FUNC_INFO;
qDebug() << "TwitterPlugin sent message to " << message.recipientScreenName() << " containing: " << message.text();
}
void
TwitterPlugin::directMessagePostError( QTweetNetBase::ErrorCode errorCode, const QString &message )
{
qDebug() << Q_FUNC_INFO;
qDebug() << "TwitterPlugin received an error posting direct message: " << m_directMessageNew.data()->lastErrorMessage();
}
void
TwitterPlugin::directMessageDestroyed( const QTweetDMStatus& message )
{
qDebug() << Q_FUNC_INFO;
qDebug() << "TwitterPlugin destroyed message " << message.text();
}
Q_EXPORT_PLUGIN2( sip, TwitterPlugin )

88
src/sip/twitter/twitter.h Normal file
View File

@@ -0,0 +1,88 @@
#ifndef TWITTER_H
#define TWITTER_H
#include <QTimer>
#include <QWeakPointer>
#include <QSet>
#include <qtweetuser.h>
#include <qtweetnetbase.h>
#include <qtweetfriendstimeline.h>
#include <qtweetdirectmessages.h>
#include <qtweetdirectmessagenew.h>
#include <qtweetdirectmessagedestroy.h>
#include <qtweetmentions.h>
#include <qtweetdmstatus.h>
#include "../sipdllmacro.h"
#include "sip/SipPlugin.h"
#include "tomahawkoauthtwitter.h"
#define MYNAME "SIPTWITTER"
class SIPDLLEXPORT TwitterPlugin : public SipPlugin
{
Q_OBJECT
Q_INTERFACES( SipPlugin )
public:
TwitterPlugin();
virtual ~TwitterPlugin() {}
virtual bool isValid();
virtual const QString name();
public slots:
virtual bool connectPlugin( bool startup );
void disconnectPlugin();
void sendMsg( const QString& to, const QString& msg )
{
}
void broadcastMsg( const QString &msg )
{
}
void addContact( const QString &jid, const QString& msg = QString() )
{
}
private slots:
void connectAuthVerifyReply( const QTweetUser &user );
void checkTimerFired();
void connectTimerFired();
void friendsTimelineStatuses( const QList< QTweetStatus > &statuses );
void mentionsStatuses( const QList< QTweetStatus > &statuses );
void pollDirectMessages();
void directMessages( const QList< QTweetDMStatus > &messages );
void directMessagePosted( const QTweetDMStatus &message );
void directMessagePostError( QTweetNetBase::ErrorCode errorCode, const QString &message );
void directMessageDestroyed( const QTweetDMStatus &message );
void registerOffer( const QString &screenName, const QHash< QString, QVariant > &peerdata );
void sendOffer( const QString &screenName, const QHash< QString, QVariant > &peerdata );
void makeConnection( const QString &screenName, const QHash< QString, QVariant > &peerdata );
private:
QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth;
QWeakPointer< QTweetFriendsTimeline > m_friendsTimeline;
QWeakPointer< QTweetMentions > m_mentions;
QWeakPointer< QTweetDirectMessages > m_directMessages;
QWeakPointer< QTweetDirectMessageNew > m_directMessageNew;
QWeakPointer< QTweetDirectMessageDestroy > m_directMessageDestroy;
bool m_isAuthed;
bool m_isOnline;
QTimer m_checkTimer;
QTimer m_connectTimer;
qint64 m_cachedFriendsSinceId;
qint64 m_cachedMentionsSinceId;
qint64 m_cachedDirectMessagesSinceId;
QHash< QString, QVariant > m_cachedPeers;
QSet<QString> m_keyCache;
bool m_finishedFriends;
bool m_finishedMentions;
};
#endif

View File

@@ -2,9 +2,14 @@
#include <QtPlugin>
const QString
ZeroconfPlugin::name()
{
return QString( MYNAME );
}
bool
ZeroconfPlugin::connect( bool /*startup*/ )
ZeroconfPlugin::connectPlugin( bool /*startup*/ )
{
delete m_zeroconf;
m_zeroconf = new TomahawkZeroconf( Servent::instance()->port(), this );
@@ -12,15 +17,41 @@ ZeroconfPlugin::connect( bool /*startup*/ )
SLOT( lanHostFound( const QString&, int, const QString&, const QString& ) ) );
m_zeroconf->advertise();
m_isOnline = true;
foreach( QStringList *currNode, m_cachedNodes )
{
QStringList nodeSet = *currNode;
if ( !Servent::instance()->connectedToSession( nodeSet[3] ) )
Servent::instance()->connectToPeer( nodeSet[0], nodeSet[1].toInt(), "whitelist", nodeSet[2], nodeSet[3] );
delete currNode;
}
m_cachedNodes.empty();
return true;
}
void
ZeroconfPlugin::disconnectPlugin()
{
m_isOnline = false;
}
void
ZeroconfPlugin::lanHostFound( const QString& host, int port, const QString& name, const QString& nodeid )
{
qDebug() << "Found LAN host:" << host << port << nodeid;
//FIXME: This doesn't work...why? I never see Found LAN host in debug either, but somehow nodes are being connected...
if ( !m_isOnline )
{
qDebug() << "Not online, so not connecting";
QStringList *nodeSet = new QStringList();
*nodeSet << host << QString::number( port ) << name << nodeid;
m_cachedNodes.insert( nodeSet );
return;
}
if ( !Servent::instance()->connectedToSession( nodeid ) )
Servent::instance()->connectToPeer( host, port, "whitelist", name, nodeid );

View File

@@ -6,6 +6,8 @@
#include "../sipdllmacro.h"
#define MYNAME "SIPZEROCONF"
class SIPDLLEXPORT ZeroconfPlugin : public SipPlugin
{
Q_OBJECT
@@ -14,16 +16,19 @@ class SIPDLLEXPORT ZeroconfPlugin : public SipPlugin
public:
ZeroconfPlugin()
: m_zeroconf( 0 )
, m_isOnline( false )
, m_cachedNodes()
{}
virtual ~ZeroconfPlugin() {}
virtual bool isValid() { return true; }
virtual const QString name();
public slots:
virtual bool connect( bool startup );
virtual bool connectPlugin( bool startup );
void disconnect()
{
}
void disconnectPlugin();
void sendMsg( const QString& to, const QString& msg )
{
@@ -42,6 +47,8 @@ private slots:
private:
TomahawkZeroconf* m_zeroconf;
bool m_isOnline;
QSet< QStringList* > m_cachedNodes;
};
#endif

View File

@@ -5,6 +5,8 @@
#include <QMetaType>
#include <QTime>
#include <QNetworkReply>
#include <QFile>
#include <QFileInfo>
#include "artist.h"
#include "album.h"
@@ -22,8 +24,11 @@
#include "web/api_v1.h"
#include "scriptresolver.h"
#include "sourcelist.h"
#include "shortcuthandler.h"
#include "tomahawksettings.h"
#include "audio/audioengine.h"
#include "utils/xspfloader.h"
#ifndef TOMAHAWK_HEADLESS
#include "tomahawkwindow.h"
@@ -31,13 +36,15 @@
#include <QMessageBox>
#endif
#ifdef Q_WS_MAC
#include "mac/macshortcuthandler.h"
#endif
#include <iostream>
#include <fstream>
#define LOGFILE TomahawkUtils::appDataDir().filePath( "tomahawk.log" ).toLocal8Bit()
#define LOGFILE_SIZE 1024 * 512
#include "tomahawksettings.h"
#include <utils/xspfloader.h>
using namespace std;
ofstream logfile;
@@ -108,6 +115,7 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] )
, m_audioEngine( 0 )
, m_sipHandler( 0 )
, m_servent( 0 )
, m_shortcutHandler( 0 )
, m_mainwindow( 0 )
, m_infoSystem( 0 )
{
@@ -154,31 +162,49 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] )
qDebug() << "Init Echonest Factory.";
GeneratorFactory::registerFactory( "echonest", new EchonestFactory );
// Register shortcut handler for this platform
#ifdef Q_WS_MAC
m_shortcutHandler = new MacShortcutHandler( this );
Tomahawk::setShortcutHandler( static_cast<MacShortcutHandler*>( m_shortcutHandler) );
Tomahawk::setApplicationHandler( this );
#endif
// Connect up shortcuts
connect( m_shortcutHandler, SIGNAL( playPause() ), m_audioEngine, SLOT( playPause() ) );
connect( m_shortcutHandler, SIGNAL( pause() ), m_audioEngine, SLOT( pause() ) );
connect( m_shortcutHandler, SIGNAL( stop() ), m_audioEngine, SLOT( stop() ) );
connect( m_shortcutHandler, SIGNAL( previous() ), m_audioEngine, SLOT( previous() ) );
connect( m_shortcutHandler, SIGNAL( next() ), m_audioEngine, SLOT( next() ) );
connect( m_shortcutHandler, SIGNAL( volumeUp() ), m_audioEngine, SLOT( raiseVolume() ) );
connect( m_shortcutHandler, SIGNAL( volumeDown() ), m_audioEngine, SLOT( lowerVolume() ) );
connect( m_shortcutHandler, SIGNAL( mute() ), m_audioEngine, SLOT( mute() ) );
#ifndef NO_LIBLASTFM
qDebug() << "Init Scrobbler.";
m_scrobbler = new Scrobbler( this );
qDebug() << "Setting NAM.";
TomahawkUtils::setNam( new lastfm::NetworkAccessManager( this ) );
qDebug() << "Init Scrobbler.";
m_scrobbler = new Scrobbler( this );
qDebug() << "Setting NAM.";
TomahawkUtils::setNam( new lastfm::NetworkAccessManager( this ) );
connect( m_audioEngine, SIGNAL( started( const Tomahawk::result_ptr& ) ),
m_scrobbler, SLOT( trackStarted( const Tomahawk::result_ptr& ) ), Qt::QueuedConnection );
connect( m_audioEngine, SIGNAL( started( const Tomahawk::result_ptr& ) ),
m_scrobbler, SLOT( trackStarted( const Tomahawk::result_ptr& ) ), Qt::QueuedConnection );
connect( m_audioEngine, SIGNAL( paused() ),
m_scrobbler, SLOT( trackPaused() ), Qt::QueuedConnection );
connect( m_audioEngine, SIGNAL( paused() ),
m_scrobbler, SLOT( trackPaused() ), Qt::QueuedConnection );
connect( m_audioEngine, SIGNAL( resumed() ),
m_scrobbler, SLOT( trackResumed() ), Qt::QueuedConnection );
connect( m_audioEngine, SIGNAL( resumed() ),
m_scrobbler, SLOT( trackResumed() ), Qt::QueuedConnection );
connect( m_audioEngine, SIGNAL( stopped() ),
m_scrobbler, SLOT( trackStopped() ), Qt::QueuedConnection );
connect( m_audioEngine, SIGNAL( stopped() ),
m_scrobbler, SLOT( trackStopped() ), Qt::QueuedConnection );
#else
qDebug() << "Setting NAM.";
TomahawkUtils::setNam( new QNetworkAccessManager );
qDebug() << "Setting NAM.";
TomahawkUtils::setNam( new QNetworkAccessManager );
#endif
// Set up proxy
if( TomahawkSettings::instance()->proxyType() != QNetworkProxy::NoProxy &&
!TomahawkSettings::instance()->proxyHost().isEmpty() )
!TomahawkSettings::instance()->proxyHost().isEmpty() )
{
qDebug() << "Setting proxy to saved values";
TomahawkUtils::setProxy( new QNetworkProxy( static_cast<QNetworkProxy::ProxyType>(TomahawkSettings::instance()->proxyType()), TomahawkSettings::instance()->proxyHost(), TomahawkSettings::instance()->proxyPort(), TomahawkSettings::instance()->proxyUsername(), TomahawkSettings::instance()->proxyPassword() ) );
@@ -445,25 +471,30 @@ TomahawkApp::setupSIP()
{
qDebug() << Q_FUNC_INFO;
if( !arguments().contains( "--nosip" ) )
//FIXME: jabber autoconnect is really more, now that there is sip -- should be renamed and/or split out of jabber-specific settings
if( !arguments().contains( "--nosip" ) && TomahawkSettings::instance()->jabberAutoConnect() )
{
m_xmppBot = new XMPPBot( this );
qDebug() << "Connecting SIP classes";
m_sipHandler->connect( true );
m_sipHandler->connectPlugins( true );
// m_sipHandler->setProxy( *TomahawkUtils::proxy() );
}
}
void
TomahawkApp::messageReceived( const QString& msg )
void
TomahawkApp::activate()
{
qDebug() << "MESSAGE RECEIVED" << msg;
if( msg.isEmpty() ) {
return;
}
if( msg.contains( "tomahawk://" ) ) {
QString cmd = msg.mid( 11 );
#ifndef TOMAHAWK_HEADLESS
mainWindow()->show();
#endif
}
bool
TomahawkApp::loadUrl( const QString& url )
{
if( url.contains( "tomahawk://" ) ) {
QString cmd = url.mid( 11 );
qDebug() << "tomahawk!s" << cmd;
if( cmd.startsWith( "load/" ) ) {
cmd = cmd.mid( 5 );
@@ -474,7 +505,26 @@ TomahawkApp::messageReceived( const QString& msg )
l->load( QUrl( cmd.mid( 5 ) ) );
}
}
}
} else {
QFile f( url );
QFileInfo info( f );
if( f.exists() && info.suffix() == "xspf" ) {
XSPFLoader* l = new XSPFLoader( true, this );
qDebug() << "Loading spiff:" << url;
l->load( QUrl( url ) );
}
}
return true;
}
void
TomahawkApp::messageReceived( const QString& msg )
{
qDebug() << "MESSAGE RECEIVED" << msg;
if( msg.isEmpty() ) {
return;
}
loadUrl( msg );
}

View File

@@ -0,0 +1,25 @@
#import <AppKit/NSApplication.h>
#include "config.h"
// this file copied and inspired by mac_startup.* in clementine player,
// copyright David Sansome 2010
namespace Tomahawk {
class PlatformInterface;
}
#ifdef SNOW_LEOPARD
@interface AppDelegate : NSObject <NSApplicationDelegate> {
#else
@interface AppDelegate : NSObject {
#endif
Tomahawk::PlatformInterface* application_handler_;
//NSMenu* dock_menu_;
}
- (id) initWithHandler: (Tomahawk::PlatformInterface*)handler;
// NSApplicationDelegate
- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag;
//- (NSMenu*) applicationDockMenu: (NSApplication*)sender;
//- (void) setDockMenu: (NSMenu*)menu;
@end