Updates
[amarok.git] / src / portabledevices / kioslaves / pmpkioslave.cpp
blob29b1b61ef8cb82d776325674ee349d7b4ea89c93
1 /*
2 * Copyright (c) 2007 Jeff Mitchell <kde-dev@emailgoeshere.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "pmpbackend.h"
20 #include "pmpdevice.h"
21 #include "pmpkioslave.h"
23 #include <QCoreApplication>
24 #include <QString>
25 #include <QTimer>
27 #include <kapplication.h>
28 #include <kcomponentdata.h>
29 #include <kdebug.h>
30 #include <kdirnotify.h>
31 #include <kio/ioslave_defaults.h>
32 #include <klocale.h>
33 #include <solid/device.h>
34 #include <solid/deviceinterface.h>
35 #include <solid/genericinterface.h>
36 #include <solid/portablemediaplayer.h>
38 using namespace KIO;
40 extern "C" int KDE_EXPORT kdemain( int argc, char **argv )
42 QCoreApplication app( argc, argv );
43 KComponentData( "kio_pmp", "kdelibs4" );
44 (void) KGlobal::locale();
46 fprintf(stderr, "ENTERED kdemain of pmp slave\n" );
48 if( argc != 4 )
50 fprintf(stderr, "Usage: kio_pmp protocol domain-socket1 domain-socket2\n" );
51 exit( -1 );
54 PMPProtocol slave( argv[1], argv[2], argv[3] );
55 slave.dispatchLoop();
56 return 0;
59 PMPProtocol::PMPProtocol( const QByteArray &protocol, const QByteArray &pool,
60 const QByteArray &app )
61 : SlaveBase( protocol, pool, app )
62 , m_devices()
63 , m_mtpInitialized( false )
67 PMPProtocol::~PMPProtocol()
69 foreach( QString udi, m_devices.keys() )
70 delete m_devices[udi];
73 void
74 PMPProtocol::setHost( const QString &host, quint16 port,
75 const QString &user, const QString &pass )
77 Q_UNUSED( port );
78 Q_UNUSED( user );
79 Q_UNUSED( pass );
80 if( !host.isEmpty() )
82 error( KIO::ERR_CANNOT_OPEN_FOR_READING,
83 i18n("portable media player : Setting a hostname is not supported. \
84 Use a URL of the form pmp:/<udi> or pmp:///<udi>" ) );
88 void
89 PMPProtocol::del( const KUrl &url, bool isfile )
91 kDebug() << endl << endl << "Entering del with url = " << url << endl << endl;
92 if( getBackendForUrl( url ) )
93 getBackendForUrl( url )->del( url, isfile );
95 emit finished();
96 kDebug() << endl << endl << "Leaving del with url = " << url << endl << endl;
99 void
100 PMPProtocol::get( const KUrl &url )
102 kDebug() << endl << endl << "Entering get with url = " << url << endl << endl;
103 if( getBackendForUrl( url ) )
104 getBackendForUrl( url )->get( url );
106 emit finished();
107 kDebug() << endl << endl << "Leaving get with url = " << url << endl << endl;
110 void
111 PMPProtocol::listDir( const KUrl &url )
113 kDebug() << endl << endl << "Entering listDir with url = " << url << endl;
114 kDebug() << "path = " << url.path() << ", path.isEmpty = " << (url.path().isEmpty() ? "true" : "false" ) << endl;
115 if( url.isEmpty() )
117 listEntry( UDSEntry(), true );
118 emit finished();
119 return;
121 if( url.path().isEmpty() || url.path() == "/" )
123 QList<Solid::Device> deviceList = Solid::Device::listFromQuery( "is PortableMediaPlayer" );
124 foreach( Solid::Device device, deviceList )
126 UDSEntry entry;
127 if( !m_devices.contains( transUdi( device.udi() ) ) )
129 m_devices[transUdi( device.udi() )] = new PMPDevice( this, device );
130 m_devices[transUdi( device.udi() )]->initialize();
132 QString name = m_devices[transUdi( device.udi() )]->backend()->getFriendlyName();
133 kDebug() << "Friendly name returned from device is: " << name << endl;
134 if( name.isEmpty() )
136 name = m_devices[transUdi( device.udi() )]->backend()->getModelName();
137 kDebug() << "Model name returned from device is: " << name << endl;
139 if( name.isEmpty() )
141 name = getSolidFriendlyName( device );
142 kDebug() << "Friendly name returned from Solid is: " << name << endl;
144 entry.insert( KIO::UDSEntry::UDS_NAME, name.isEmpty() ? QString( "Portable Media Player at " + device.udi() ) : name );
145 entry.insert( KIO::UDSEntry::UDS_URL,"pmp:///" + transUdi( device.udi() ) );
146 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
147 entry.insert( KIO::UDSEntry::UDS_HIDDEN, 0 );
148 listEntry( entry, false );
150 listEntry( UDSEntry(), true );
151 emit finished();
152 return;
154 else
156 if( getBackendForUrl( url ) )
157 getBackendForUrl( url )->listDir( url );
160 emit finished();
161 kDebug() << endl << endl << "Leaving listDir with url = " << url << endl << endl;
164 void
165 PMPProtocol::rename( const KUrl &src, const KUrl &dest, bool overwrite )
167 kDebug() << "srcUrl = " << src.url() << ", destUrl = " << dest.url() << endl;
168 QString srcPath = src.path( KUrl::RemoveTrailingSlash );
169 QString destPath = dest.path( KUrl::RemoveTrailingSlash );
170 while( srcPath[0] == '/' )
171 srcPath.remove( 0, 1 );
172 while( destPath[0] == '/' )
173 destPath.remove( 0, 1 );
174 //Check to see if they're trying to set a friendly name
175 //i.e. only top-level paths
176 kDebug() << endl << "srcPath = " << srcPath << ", destPath = " << destPath << endl;
177 kDebug() << endl << "src.directory() = " << src.directory() << ", dest.directory() = " << dest.directory() << endl;
178 if( srcPath.indexOf( '/' ) == -1 && destPath.indexOf( '/' ) == -1 )
180 QString srcName = udiFromUrl( src );
181 QString dstName = udiFromUrl( dest );
182 kDebug() << "srcName = " << srcName << ", dstName (friendly name) = " << dstName << endl;
183 kDebug() << "m_devices keys: " << endl;
184 foreach( QString key, m_devices.keys() )
185 kDebug() << "key = " << key << endl;
186 if( m_devices.contains( dstName ) )
187 warning( i18n( "Destination name cannot be the same as a Solid UDI!" ) );
188 else if ( getBackendForUrl( src ) )
190 getBackendForUrl( src )->setFriendlyName( dstName );
192 emit finished();
193 org::kde::KDirNotify::emitFilesAdded( "pmp:///" );
194 //Why doesn't this work...
195 //QTimer::singleShot( 500, this, SLOT( refreshRootDir() ) );
196 return;
198 if( udiFromUrl( src ) != udiFromUrl( dest ) )
200 //this shouldn't ever happen...
201 warning( i18n( "Could not rename file, files cannot be renamed across devices!" ) );
202 emit finished();
203 return;
205 if( getBackendForUrl( src ) )
206 getBackendForUrl( src )->rename( src, dest, overwrite );
208 emit finished();
211 void
212 PMPProtocol::stat( const KUrl &url )
214 kDebug() << endl << endl << "Entering stat with url = " << url << endl << endl;
215 if( url.path().isEmpty() || url.path() == "/" )
217 KIO::UDSEntry entry;
218 entry.insert( KIO::UDSEntry::UDS_NAME, "Available Devices" );
219 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
220 entry.insert( KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH );
221 statEntry( entry );
222 emit finished();
223 return;
225 else if( getBackendForUrl( url ) )
226 getBackendForUrl( url )->stat( url );
228 emit finished();
229 kDebug() << endl << endl << "Leaving stat with url = " << url << endl << endl;
232 QString
233 PMPProtocol::getSolidFriendlyName( const Solid::Device & device ) const
235 kDebug() << "Looking for a friendly name for " << device.udi() << "..." << endl;
236 //NOTE/TODO: The following is hal-dependent.
237 const Solid::GenericInterface *gi = device.as<Solid::GenericInterface>();
238 if( !gi )
240 kDebug() << "Couldn't get the device as a generic interface." << endl;
241 return QString();
243 if( !gi->propertyExists( "portable_audio_player.access_method.drivers" ) )
245 kDebug() << "No access_method.drivers property detected." << endl;
246 return QString();
248 QVariant possibleLibraries = gi->property( "portable_audio_player.access_method.drivers" );
249 if( !possibleLibraries.isValid() || possibleLibraries.isNull() || !possibleLibraries.canConvert( QVariant::StringList ) )
250 return QString();
251 QStringList libraries = possibleLibraries.toStringList();
252 foreach( QString library, libraries )
254 QVariant possibleName = gi->property( "portable_audio_player." + library + ".name" );
255 if( possibleName.isValid() && !possibleName.isNull() && possibleName.canConvert( QVariant::String ) )
257 QString name = possibleName.toString();
258 if( !name.isEmpty() )
259 return name;
262 return QString();
265 QString
266 PMPProtocol::udiFromUrl( const KUrl &url )
268 if( url.isEmpty() )
270 error( KIO::ERR_CANNOT_OPEN_FOR_READING, i18n( "portable media player : Empty UDI passed in" ) );
271 return QString::null;
274 QString path = url.path( KUrl::RemoveTrailingSlash );
275 while( path[0] == '/' )
276 path.remove( 0, 1 );
278 int index = path.indexOf( '/' );
279 //if not found, use the path as is; if it is truncate so we only get the udi
280 QString udi = ( index == -1 ? path : path.left( index ) );
281 //translate the udi to its required format
282 udi = transUdi( udi );
284 return udi;
287 PMPBackend*
288 PMPProtocol::getBackendForUrl( const KUrl &url )
290 if( !m_devices.contains( udiFromUrl( url ) ) )
292 m_devices[udiFromUrl( url )] = new PMPDevice( this, Solid::Device( untransUdi( udiFromUrl( url ) ) ) );
293 if( m_devices[udiFromUrl( url )]->isValid() )
294 m_devices[udiFromUrl( url )]->initialize();
295 else
297 delete m_devices[udiFromUrl( url )];
298 m_devices.remove( udiFromUrl( url ) );
299 return 0;
302 return m_devices[udiFromUrl( url )]->backend();
305 #include "pmpkioslave.moc"