mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-07-31 03:10:12 +02:00
Beginning of tomahawk-side osx handling of binary resolvers
This commit is contained in:
@@ -143,5 +143,6 @@
|
||||
<file>data/images/process-stop.png</file>
|
||||
<file>data/icons/tomahawk-icon-128x128-grayscale.png</file>
|
||||
<file>data/images/collection.png</file>
|
||||
<file>data/misc/tomahawk_pubkey.pem</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -23,8 +23,6 @@
|
||||
#include "Pipeline.h"
|
||||
|
||||
#include <attica/downloaditem.h>
|
||||
#include <quazip.h>
|
||||
#include <quazipfile.h>
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QTemporaryFile>
|
||||
@@ -451,6 +449,7 @@ AtticaManager::installResolver( const Content& resolver, bool autoCreateAccount
|
||||
connect( job, SIGNAL( finished( Attica::BaseJob* ) ), this, SLOT( resolverDownloadFinished( Attica::BaseJob* ) ) );
|
||||
job->setProperty( "resolverId", resolver.id() );
|
||||
job->setProperty( "createAccount", autoCreateAccount );
|
||||
job->setProperty( "binarySignature", resolver.attribute("signature"));
|
||||
|
||||
job->start();
|
||||
}
|
||||
@@ -487,6 +486,7 @@ AtticaManager::resolverDownloadFinished ( BaseJob* j )
|
||||
connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) );
|
||||
reply->setProperty( "resolverId", job->property( "resolverId" ) );
|
||||
reply->setProperty( "createAccount", job->property( "createAccount" ) );
|
||||
reply->setProperty( "binarySignature", job->property( "binarySignature" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -513,23 +513,50 @@ AtticaManager::payloadFetched()
|
||||
f.write( reply->readAll() );
|
||||
f.close();
|
||||
|
||||
QString resolverId = reply->property( "resolverId" ).toString();
|
||||
QDir dir( extractPayload( f.fileName(), resolverId ) );
|
||||
QString resolverPath = dir.absoluteFilePath( m_resolverStates[ resolverId ].scriptPath );
|
||||
|
||||
if ( !resolverPath.isEmpty() )
|
||||
bool installedSuccessfully = false;
|
||||
const QString resolverId = reply->property( "resolverId" ).toString();
|
||||
if ( m_resolverStates[ resolverId ].binary )
|
||||
{
|
||||
// update with absolute, not relative, path
|
||||
m_resolverStates[ resolverId ].scriptPath = resolverPath;
|
||||
|
||||
if ( reply->property( "createAccount" ).toBool() )
|
||||
// First ensure the signature matches. If we can't verify it, abort!
|
||||
const QString signature = reply->property( "binarySignature" ).toString();
|
||||
// Must have a signature for binary resolvers...
|
||||
Q_ASSERT( !signature.isEmpty() );
|
||||
if ( signature.isEmpty() )
|
||||
return;
|
||||
if ( !TomahawkUtils::verifyFile( f.fileName(), signature ) )
|
||||
{
|
||||
// Do the install / add to tomahawk
|
||||
Tomahawk::Accounts::Account* resolver = Tomahawk::Accounts::ResolverAccountFactory::createFromPath( resolverPath, "resolveraccount", true );
|
||||
Tomahawk::Accounts::AccountManager::instance()->addAccount( resolver );
|
||||
TomahawkSettings::instance()->addAccount( resolver->accountId() );
|
||||
qWarning() << "FILE SIGNATURE FAILED FOR BINARY RESOLVER! WARNING! :" << f.fileName() << signature;
|
||||
return;
|
||||
}
|
||||
#ifdef Q_OS_MAC
|
||||
|
||||
#elif Q_OS_WIN
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
QDir dir( TomahawkUtils::extractScriptPayload( f.fileName(), resolverId ) );
|
||||
QString resolverPath = dir.absoluteFilePath( m_resolverStates[ resolverId ].scriptPath );
|
||||
|
||||
if ( !resolverPath.isEmpty() )
|
||||
{
|
||||
// update with absolute, not relative, path
|
||||
m_resolverStates[ resolverId ].scriptPath = resolverPath;
|
||||
|
||||
if ( reply->property( "createAccount" ).toBool() )
|
||||
{
|
||||
// Do the install / add to tomahawk
|
||||
Tomahawk::Accounts::Account* resolver = Tomahawk::Accounts::ResolverAccountFactory::createFromPath( resolverPath, "resolveraccount", true );
|
||||
Tomahawk::Accounts::AccountManager::instance()->addAccount( resolver );
|
||||
TomahawkSettings::instance()->addAccount( resolver->accountId() );
|
||||
}
|
||||
|
||||
installedSuccessfully = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( installedSuccessfully )
|
||||
{
|
||||
m_resolverStates[ resolverId ].state = Installed;
|
||||
TomahawkSettingsGui::instanceGui()->setAtticaResolverStates( m_resolverStates );
|
||||
emit resolverInstalled( resolverId );
|
||||
@@ -543,75 +570,6 @@ AtticaManager::payloadFetched()
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
AtticaManager::extractPayload( const QString& filename, const QString& resolverId ) const
|
||||
{
|
||||
// uses QuaZip to extract the temporary zip file to the user's tomahawk data/resolvers directory
|
||||
QuaZip zipFile( filename );
|
||||
if ( !zipFile.open( QuaZip::mdUnzip ) )
|
||||
{
|
||||
tLog() << "Failed to QuaZip open:" << zipFile.getZipError();
|
||||
return QString();
|
||||
}
|
||||
|
||||
if ( !zipFile.goToFirstFile() )
|
||||
{
|
||||
tLog() << "Failed to go to first file in zip archive: " << zipFile.getZipError();
|
||||
return QString();
|
||||
}
|
||||
|
||||
QDir resolverDir = TomahawkUtils::appDataDir();
|
||||
if ( !resolverDir.mkpath( QString( "atticaresolvers/%1" ).arg( resolverId ) ) )
|
||||
{
|
||||
tLog() << "Failed to mkdir resolver save dir: " << TomahawkUtils::appDataDir().absoluteFilePath( QString( "atticaresolvers/%1" ).arg( resolverId ) );
|
||||
return QString();
|
||||
}
|
||||
resolverDir.cd( QString( "atticaresolvers/%1" ).arg( resolverId ) );
|
||||
tDebug() << "Installing resolver to:" << resolverDir.absolutePath();
|
||||
|
||||
QuaZipFile fileInZip( &zipFile );
|
||||
do
|
||||
{
|
||||
QuaZipFileInfo info;
|
||||
zipFile.getCurrentFileInfo( &info );
|
||||
|
||||
if ( !fileInZip.open( QIODevice::ReadOnly ) )
|
||||
{
|
||||
tLog() << "Failed to open file inside zip archive:" << info.name << zipFile.getZipName() << "with error:" << zipFile.getZipError();
|
||||
continue;
|
||||
}
|
||||
|
||||
QFile out( resolverDir.absoluteFilePath( fileInZip.getActualFileName() ) );
|
||||
|
||||
QStringList parts = fileInZip.getActualFileName().split( "/" );
|
||||
if ( parts.size() > 1 )
|
||||
{
|
||||
QStringList dirs = parts.mid( 0, parts.size() - 1 );
|
||||
QString dirPath = dirs.join( "/" ); // QDir translates / to \ internally if necessary
|
||||
resolverDir.mkpath( dirPath );
|
||||
}
|
||||
|
||||
// make dir if there is one needed
|
||||
QDir d( fileInZip.getActualFileName() );
|
||||
|
||||
tDebug() << "Writing to output file..." << out.fileName();
|
||||
if ( !out.open( QIODevice::WriteOnly ) )
|
||||
{
|
||||
tLog() << "Failed to open resolver extract file:" << out.errorString() << info.name;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
out.write( fileInZip.readAll() );
|
||||
out.close();
|
||||
fileInZip.close();
|
||||
|
||||
} while ( zipFile.goToNextFile() );
|
||||
|
||||
return resolverDir.absolutePath();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::uninstallResolver( const QString& pathToResolver )
|
||||
{
|
||||
|
@@ -391,6 +391,7 @@ IF( APPLE )
|
||||
infosystem/infoplugins/mac/Adium.mm
|
||||
infosystem/infoplugins/mac/AdiumPlugin.cpp
|
||||
utils/TomahawkUtils_Mac.mm
|
||||
mac/FileHelpers.mm
|
||||
thirdparty/Qocoa/qsearchfield_mac.mm )
|
||||
|
||||
SET_SOURCE_FILES_PROPERTIES(utils/TomahawkUtils_Mac.mm PROPERTIES COMPILE_FLAGS "-fvisibility=default")
|
||||
@@ -400,10 +401,11 @@ IF( APPLE )
|
||||
# System
|
||||
${COREAUDIO_LIBRARY}
|
||||
${COREFOUNDATION_LIBRARY}
|
||||
${FOUNDATION_LIBRARY}
|
||||
${FOUNDATION_LIBRARY}
|
||||
${SCRIPTINGBRIDGE_LIBRARY}
|
||||
|
||||
/System/Library/Frameworks/AppKit.framework
|
||||
/System/Library/Frameworks/Security.framework
|
||||
)
|
||||
ELSE( APPLE )
|
||||
SET( libGuiSources ${libGuiSources} thirdparty/Qocoa/qsearchfield.cpp )
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@@ -39,6 +39,9 @@
|
||||
#include <QMutex>
|
||||
#include <QCryptographicHash>
|
||||
|
||||
#include <quazip.h>
|
||||
#include <quazipfile.h>
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
@@ -49,6 +52,10 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef QCA2_FOUND
|
||||
#include <QtCrypto>
|
||||
#endif
|
||||
|
||||
namespace TomahawkUtils
|
||||
{
|
||||
static quint64 s_infosystemRequestId = 0;
|
||||
@@ -676,4 +683,160 @@ SharedTimeLine::disconnectNotify( const char* signal )
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
verifyFile( const QString &filePath, const QString &signature )
|
||||
{
|
||||
QCA::Initializer init;
|
||||
|
||||
if( !QCA::isSupported( "sha1" ) )
|
||||
{
|
||||
qWarning() << "SHA1 not supported by QCA, aborting.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// The signature for the resolver.zip was created like so:
|
||||
// openssl dgst -sha1 -binary < "#{tarball}" | openssl dgst -dss1 -sign "#{ARGV[2]}" | openssl enc -base64
|
||||
// which means we need to decode it with QCA's DSA public key signature verification tools
|
||||
// The input data is:
|
||||
// file -> SHA1 binary format -> DSS1/DSA signed -> base64 encoded.
|
||||
|
||||
// Step 1: Load the public key
|
||||
// Public key is in :/data/misc/tomahawk_pubkey.pem
|
||||
QFile f( ":/data/misc/tomahawk_pubkey.pem" );
|
||||
if ( !f.open( QIODevice::ReadOnly ) )
|
||||
{
|
||||
qWarning() << "Unable to read public key from resources!";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString pubkeyData = QString::fromUtf8( f.readAll() );
|
||||
QCA::ConvertResult conversionResult;
|
||||
QCA::PublicKey publicKey = QCA::PublicKey::fromPEM( pubkeyData, &conversionResult );
|
||||
if ( QCA::ConvertGood != conversionResult)
|
||||
{
|
||||
qWarning() << "Public key reading/loading failed! Tried to load public key:" << pubkeyData;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !publicKey.canVerify() )
|
||||
{
|
||||
qWarning() << "Loaded Tomahawk public key but cannot use it to verify! What is up....";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 2: Get the SHA1 of the file contents
|
||||
QFile toVerify( filePath );
|
||||
if ( !toVerify.exists() || !toVerify.open( QIODevice::ReadOnly ) )
|
||||
{
|
||||
qWarning() << "Failed to open file we are trying to verify!" << filePath;
|
||||
return false;
|
||||
}
|
||||
|
||||
QCA::Hash fileHash = QCA::Hash( "sha1 ");
|
||||
//QCA::SecureArray fileData( toVerify.readAll() );
|
||||
//fileHash.update( fileData );
|
||||
const QByteArray fileHashData = QCA::Hash( "sha1" ).hash( toVerify.readAll() ).toByteArray();
|
||||
toVerify.close();
|
||||
|
||||
// Step 3: Base64 decode the signature
|
||||
QCA::Base64 decoder( QCA::Decode );
|
||||
const QByteArray decodedSignature = decoder.decode( QCA::SecureArray( signature.trimmed().toUtf8() ) ).toByteArray();
|
||||
if ( decodedSignature.isEmpty() )
|
||||
{
|
||||
qWarning() << "Got empty signature after we tried to decode it from Base64:" << signature.trimmed().toUtf8() << decodedSignature.toBase64();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 4: Do the actual verifying!
|
||||
const bool result = publicKey.verifyMessage( fileHashData, decodedSignature, QCA::EMSA1_SHA1, QCA::DERSequence );
|
||||
if ( !result )
|
||||
{
|
||||
qWarning() << "File" << filePath << "FAILED VERIFICATION against our input signature!";
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "Successfully verified signature of downloaded file:" << filePath;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
extractScriptPayload( const QString& filename, const QString& resolverId )
|
||||
{
|
||||
// uses QuaZip to extract the temporary zip file to the user's tomahawk data/resolvers directory
|
||||
QuaZip zipFile( filename );
|
||||
if ( !zipFile.open( QuaZip::mdUnzip ) )
|
||||
{
|
||||
tLog() << "Failed to QuaZip open:" << zipFile.getZipError();
|
||||
return QString();
|
||||
}
|
||||
|
||||
if ( !zipFile.goToFirstFile() )
|
||||
{
|
||||
tLog() << "Failed to go to first file in zip archive: " << zipFile.getZipError();
|
||||
return QString();
|
||||
}
|
||||
|
||||
QDir resolverDir = appDataDir();
|
||||
if ( !resolverDir.mkpath( QString( "atticaresolvers/%1" ).arg( resolverId ) ) )
|
||||
{
|
||||
tLog() << "Failed to mkdir resolver save dir: " << TomahawkUtils::appDataDir().absoluteFilePath( QString( "atticaresolvers/%1" ).arg( resolverId ) );
|
||||
return QString();
|
||||
}
|
||||
resolverDir.cd( QString( "atticaresolvers/%1" ).arg( resolverId ) );
|
||||
tDebug() << "Installing resolver to:" << resolverDir.absolutePath();
|
||||
|
||||
QuaZipFile fileInZip( &zipFile );
|
||||
do
|
||||
{
|
||||
QuaZipFileInfo info;
|
||||
zipFile.getCurrentFileInfo( &info );
|
||||
|
||||
if ( !fileInZip.open( QIODevice::ReadOnly ) )
|
||||
{
|
||||
tLog() << "Failed to open file inside zip archive:" << info.name << zipFile.getZipName() << "with error:" << zipFile.getZipError();
|
||||
continue;
|
||||
}
|
||||
|
||||
QFile out( resolverDir.absoluteFilePath( fileInZip.getActualFileName() ) );
|
||||
|
||||
QStringList parts = fileInZip.getActualFileName().split( "/" );
|
||||
if ( parts.size() > 1 )
|
||||
{
|
||||
QStringList dirs = parts.mid( 0, parts.size() - 1 );
|
||||
QString dirPath = dirs.join( "/" ); // QDir translates / to \ internally if necessary
|
||||
resolverDir.mkpath( dirPath );
|
||||
}
|
||||
|
||||
// make dir if there is one needed
|
||||
QDir d( fileInZip.getActualFileName() );
|
||||
|
||||
tDebug() << "Writing to output file..." << out.fileName();
|
||||
if ( !out.open( QIODevice::WriteOnly ) )
|
||||
{
|
||||
tLog() << "Failed to open resolver extract file:" << out.errorString() << info.name;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
out.write( fileInZip.readAll() );
|
||||
out.close();
|
||||
fileInZip.close();
|
||||
|
||||
} while ( zipFile.goToNextFile() );
|
||||
|
||||
return resolverDir.absolutePath();
|
||||
}
|
||||
|
||||
|
||||
#if !defined(Q_OS_MAC) // && !defined(Q_OS_WIN)
|
||||
void
|
||||
extractBinaryResolver( const QString& zipFilename, const QString& resolverId, QObject* )
|
||||
{
|
||||
// No support for binary resolvers on linux! Shouldn't even have been allowed to see/install..
|
||||
Q_ASSERT( false );
|
||||
}
|
||||
#endif
|
||||
|
||||
} // ns
|
||||
|
@@ -137,6 +137,13 @@ namespace TomahawkUtils
|
||||
DLLEXPORT QString md5( const QByteArray& data );
|
||||
DLLEXPORT bool removeDirectory( const QString& dir );
|
||||
|
||||
DLLEXPORT bool verifyFile( const QString& filePath, const QString& signature );
|
||||
DLLEXPORT QString extractScriptPayload( const QString& filename, const QString& resolverId );
|
||||
|
||||
// Extracting may be asynchronous, pass in a receiver object with the following slots:
|
||||
// extractSucceeded( const QString& path ) and extractFailed() to be notified/
|
||||
DLLEXPORT void extractBinaryResolver( const QString& zipFilename, const QString& resolverId, QObject* receiver );
|
||||
|
||||
/**
|
||||
* This helper is designed to help "update" an existing playlist with a newer revision of itself.
|
||||
* To avoid re-loading the whole playlist and re-resolving tracks that are the same in the old playlist,
|
||||
|
37
src/libtomahawk/utils/TomahawkUtils_Mac.h
Normal file
37
src/libtomahawk/utils/TomahawkUtils_Mac.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2012, Leo Franchi <lfranchi@kde.org
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TOMAHAWKUTILS_MAC_H
|
||||
#define TOMAHAWKUTILS_MAC_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#import "mac/FileHelpers.h"
|
||||
|
||||
@interface MoveDelegate : NSObject
|
||||
{
|
||||
QObject* receiver;
|
||||
QString path;
|
||||
}
|
||||
- (void)setReceiver:(QObject*)receiver;
|
||||
- (void)setMoveTo:(QString)path;
|
||||
- (void)moveFinished;
|
||||
- (void)moveFailedWithError:(NSError *)error;
|
||||
@end
|
||||
|
||||
#endif // TOMAHAWKUTILS_MAC_H
|
@@ -1,6 +1,54 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2012, Leo Franchi <lfranchi@kde.org
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TomahawkUtils.h"
|
||||
|
||||
#include "TomahawkUtils_Mac.h"
|
||||
#include "mac/FileHelpers.h"
|
||||
|
||||
#include <QTemporaryFile>
|
||||
|
||||
#import <AppKit/NSApplication.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@implementation MoveDelegate
|
||||
|
||||
|
||||
-(void) setReceiver:(QObject*) object
|
||||
{
|
||||
receiver = object;
|
||||
}
|
||||
|
||||
-(void) setMoveTo:(QString) p
|
||||
{
|
||||
path = p;
|
||||
}
|
||||
|
||||
- (void)moveFinished
|
||||
{
|
||||
QMetaObject::invokeMethod(receiver, "installSucceeded", Qt::DirectConnection, Q_ARG(QString, path));
|
||||
}
|
||||
|
||||
- (void)moveFailedWithError:(NSError *)error
|
||||
{
|
||||
QMetaObject::invokeMethod(receiver, "installFailed", Qt::DirectConnection);
|
||||
}
|
||||
@end
|
||||
|
||||
namespace TomahawkUtils
|
||||
{
|
||||
@@ -10,4 +58,35 @@ bringToFront() {
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
extractBinaryResolver( const QString& zipFilename, const QString& resolverId, QObject* receiver )
|
||||
{
|
||||
/**
|
||||
On OS X, we have to do the following:
|
||||
2) Extract file in temporary location
|
||||
3) Authenticate to be able to have write access to the /Applications folder
|
||||
4) Copy the contents of the zipfile to the Tomahawk.app/Contents/MacOS/ folder
|
||||
5) Call result slots on receiver object
|
||||
*/
|
||||
|
||||
MoveDelegate* del = [[MoveDelegate alloc] init];
|
||||
[del setReceiver: receiver];
|
||||
|
||||
// Unzip in temporary folder and copy the contents to MacOS/
|
||||
NSError* err = NULL;
|
||||
NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
|
||||
NSURL* tempDir = [manager URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:NULL create:YES error:&err];
|
||||
if ( err )
|
||||
{
|
||||
qDebug() << "GOT ERROR trying to create temp dir to unzip in...:" << err;
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Using temporary directory:" << [tempDir absoluteString];
|
||||
|
||||
|
||||
// [del setMoveTo: to];
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -121,7 +121,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
int
|
||||
main( int argc, char *argv[] )
|
||||
{
|
||||
#ifdef Q_WS_MAC
|
||||
#ifdef Q_WS_MAC
|
||||
// Do Mac specific startup to get media keys working.
|
||||
// This must go before QApplication initialisation.
|
||||
Tomahawk::macMain();
|
||||
|
Reference in New Issue
Block a user