1
/***************************************************************************
2
* Copyright (C) 2005 - 2008 by *
3
* Last.fm Ltd <client@last.fm> *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 2 of the License, or *
8
* (at your option) any later version. *
10
* This program is distributed in the hope that it will be useful, *
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU General Public License *
16
* along with this program; if not, write to the *
17
* Free Software Foundation, Inc., *
18
* 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. *
19
***************************************************************************/
21
#include "ITunesPluginInstaller.h"
23
#include "MooseCommon.h"
24
#include "UnicornCommon.h"
25
#include "UnicornCommonMac.h"
27
#include "ITunesScript.h"
28
#include "LastMessageBox.h"
33
static const char* kBundleName = "AudioScrobbler.bundle";
34
static const char* kPListFile = "Contents/Info.plist";
37
ITunesPluginInstaller::ITunesPluginInstaller()
38
: k_shippedPluginDir( qApp->applicationDirPath() + "/PlugIns/" + kBundleName + "/" ),
39
k_iTunesPluginDir( QDir::homePath() + "/Library/iTunes/iTunes Plug-ins/" + kBundleName + "/" ),
40
m_needsTwiddlyBootstrap( false )
45
ITunesPluginInstaller::install()
47
qDebug() << "Found installed iTunes plugin?" << isPluginInstalled();
49
QString installedVersion;
50
QString shippedVersion;
52
disableLegacyHelperApp();
54
if ( isPluginInstalled() )
56
installedVersion = pListVersion( k_iTunesPluginDir + kPListFile );
57
qDebug() << "Found installed iTunes plugin version:" << installedVersion;
60
//TODO don't bootstrap if installation fails
61
m_needsTwiddlyBootstrap = true;
63
shippedVersion = pListVersion( k_shippedPluginDir + kPListFile );
64
if ( shippedVersion.isEmpty() )
66
qDebug() << "Could not locate shipped iTunes plugin!";
70
qDebug() << "Found shipped iTunes plugin version:" << shippedVersion;
72
if ( installedVersion != shippedVersion )
74
qDebug() << "Installing shipped iTunes plugin...";
76
if ( !removeInstalledPlugin() )
78
qDebug() << "Removing installed plugin from" << k_iTunesPluginDir << "failed!";
82
qDebug() << "Successfully removed installed plugin.";
84
if ( installPlugin() )
86
qDebug() << "Successfully installed the plugin.";
89
qDebug() << "Installing the plugin failed!";
93
qDebug() << "Installed iTunes plugin is up-to-date.";
99
ITunesPluginInstaller::isPluginInstalled()
101
return QDir( k_iTunesPluginDir ).exists();
106
ITunesPluginInstaller::pListVersion( const QString& file )
109
if ( !f.open( QIODevice::ReadOnly ) )
112
const QString key( "<key>CFBundleVersion</key>" );
113
const QString begin( "<string>" );
114
const QString end( "</string>" );
118
QString line = f.readLine();
119
if ( line.contains( key ) && !f.atEnd() )
121
QString versionLine = QString( ( f.readLine() ) ).trimmed();
122
QString version = versionLine.section( begin, 1 );
123
version = version.left( version.length() - end.length() );
136
deleteDir( QString path )
138
if ( !path.endsWith( "/" ) )
144
const QStringList files = d.entryList( QDir::Files );
145
foreach( QString file, files )
147
if ( !d.remove( file ) )
151
// Remove all dirs (recursive)
152
const QStringList dirs = d.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
153
foreach( QString dir, dirs )
155
if ( !deleteDir( path + dir ) )
159
return d.rmdir( path );
164
ITunesPluginInstaller::removeInstalledPlugin()
166
if ( !isPluginInstalled() )
169
return deleteDir( k_iTunesPluginDir );
174
copyDir( QString path, QString dest )
176
if ( !path.endsWith( '/' ) )
178
if ( !dest.endsWith( '/' ) )
181
QDir( dest ).mkpath( "." );
184
const QStringList files = d.entryList( QDir::Files );
185
foreach( QString file, files )
187
QFile f( path + file );
188
if ( !f.copy( dest + file ) )
192
const QStringList dirs = d.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
193
foreach( QString dir, dirs )
195
if ( !copyDir( path + dir, dest + dir ) )
204
ITunesPluginInstaller::installPlugin()
206
return copyDir( k_shippedPluginDir, k_iTunesPluginDir );
211
ITunesPluginInstaller::disableLegacyHelperApp()
213
qDebug() << "Disabling old LastFmHelper";
215
// EVEN MORE LEGACY: disable oldest helper auto-launch!
216
QString oldplist = QDir::homePath() + "/Library/LaunchAgents/fm.last.lastfmhelper.plist";
217
if ( QFile::exists( oldplist ) )
219
QProcess::execute( "/bin/launchctl", QStringList() << "unload" << oldplist );
220
QFile::remove( oldplist );
223
// REMOVE LastFmHelper from loginwindow.plist
224
CFArrayRef prefCFArrayRef = (CFArrayRef)CFPreferencesCopyValue( CFSTR( "AutoLaunchedApplicationDictionary" ),
225
CFSTR( "loginwindow" ),
226
kCFPreferencesCurrentUser,
227
kCFPreferencesAnyHost );
228
if ( prefCFArrayRef == NULL ) return;
229
CFMutableArrayRef tCFMutableArrayRef = CFArrayCreateMutableCopy( NULL, 0, prefCFArrayRef );
230
if ( tCFMutableArrayRef == NULL ) return;
232
for ( int i = CFArrayGetCount( prefCFArrayRef ) - 1; i >= 0 ; i-- )
234
CFDictionaryRef dict = (CFDictionaryRef)CFArrayGetValueAtIndex( prefCFArrayRef, i );
235
QString path = UnicornUtils::CFStringToQString( (CFStringRef) CFDictionaryGetValue( dict, CFSTR( "Path" ) ) );
237
if ( path.toLower().contains( "lastfmhelper" ) )
239
// Better make sure LastFmHelper is really dead
240
QProcess::execute( "/usr/bin/killall", QStringList() << "LastFmHelper" );
242
qDebug() << "Removing helper from LoginItems at position" << i;
243
CFArrayRemoveValueAtIndex( tCFMutableArrayRef, (CFIndex)i );
247
CFPreferencesSetValue( CFSTR( "AutoLaunchedApplicationDictionary" ),
249
CFSTR( "loginwindow" ),
250
kCFPreferencesCurrentUser,
251
kCFPreferencesAnyHost );
252
CFPreferencesSynchronize( CFSTR( "loginwindow" ),
253
kCFPreferencesCurrentUser,
254
kCFPreferencesAnyHost );
256
CFRelease( prefCFArrayRef );
257
CFRelease( tCFMutableArrayRef );
262
ITunesPluginInstaller::uninstall()
264
QDir d = k_iTunesPluginDir + "Contents/Resources";
266
// always use absolute paths to tools! - muesli
267
QProcess::startDetached( "/bin/sh",
268
QStringList() << d.filePath( "uninstall.sh" ),