2014-11-19 01:03:24 +00:00
|
|
|
/*
|
|
|
|
Cache for recently used devices.
|
|
|
|
Copyright (C) 2012 Philipp Schmidt <philschmidt@gmx.net>
|
|
|
|
|
|
|
|
This program 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 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "devicecache.h"
|
|
|
|
#include "kio_mtp_helpers.h"
|
|
|
|
|
|
|
|
// #include <libudev.h>
|
|
|
|
// #include <fcntl.h>
|
|
|
|
|
|
|
|
#include <Solid/Device>
|
2021-07-12 16:15:56 +03:00
|
|
|
#include <Solid/PortableMediaPlayer>
|
2014-11-19 01:03:24 +00:00
|
|
|
#include <Solid/DeviceNotifier>
|
|
|
|
|
2021-07-12 20:28:04 +03:00
|
|
|
static const QString solidMTPProtocol = QLatin1String("mtp");
|
|
|
|
|
2014-11-19 01:03:24 +00:00
|
|
|
/**
|
|
|
|
* Creates a Cached Device that has a predefined lifetime (default: 10000 msec)s
|
|
|
|
* The lifetime is reset every time the device is accessed. After it expires it
|
|
|
|
* will be released.
|
|
|
|
*
|
|
|
|
* @param device The LIBMTP_mtpdevice_t pointer to cache
|
|
|
|
* @param udi The UDI of the new device to cache
|
|
|
|
*/
|
2021-07-12 19:38:06 +03:00
|
|
|
CachedDevice::CachedDevice(LIBMTP_mtpdevice_t* device, LIBMTP_raw_device_t* rawdevice, const QString udi, qint32 timeout)
|
2014-11-19 01:03:24 +00:00
|
|
|
{
|
|
|
|
this->timeout = timeout;
|
|
|
|
this->mtpdevice = device;
|
|
|
|
this->rawdevice = *rawdevice;
|
|
|
|
this->udi = udi;
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
char *deviceName = LIBMTP_Get_Friendlyname(device);
|
|
|
|
char *deviceModel = LIBMTP_Get_Modelname(device);
|
2014-11-19 01:03:24 +00:00
|
|
|
|
|
|
|
// prefer friendly devicename over model
|
2021-07-12 19:38:06 +03:00
|
|
|
if (!deviceName) {
|
|
|
|
name = QString::fromUtf8(deviceModel);
|
|
|
|
} else {
|
|
|
|
name = QString::fromUtf8(deviceName);
|
|
|
|
}
|
2014-11-19 01:03:24 +00:00
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
kDebug(KIO_MTP) << "Created device" << name << "with udi" << udi << " and timeout" << timeout;
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CachedDevice::~CachedDevice()
|
|
|
|
{
|
2021-07-12 19:38:06 +03:00
|
|
|
LIBMTP_Release_Device(mtpdevice);
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LIBMTP_mtpdevice_t* CachedDevice::getDevice()
|
|
|
|
{
|
2021-07-13 02:02:54 +03:00
|
|
|
if (!mtpdevice->storage) {
|
2021-07-12 19:38:06 +03:00
|
|
|
kDebug(KIO_MTP) << "reopen mtpdevice if we have no storage found";
|
|
|
|
LIBMTP_Release_Device(mtpdevice);
|
|
|
|
mtpdevice = LIBMTP_Open_Raw_Device_Uncached(&rawdevice);
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
return mtpdevice;
|
|
|
|
}
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
const QString CachedDevice::getName() const
|
2014-11-19 01:03:24 +00:00
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
2021-07-12 19:38:06 +03:00
|
|
|
|
|
|
|
const QString CachedDevice::getUdi() const
|
2014-11-19 01:03:24 +00:00
|
|
|
{
|
|
|
|
return udi;
|
|
|
|
}
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
DeviceCache::DeviceCache(qint32 timeout, QObject*parent)
|
|
|
|
: QEventLoop(parent)
|
2014-11-19 01:03:24 +00:00
|
|
|
{
|
|
|
|
this->timeout = timeout;
|
|
|
|
|
|
|
|
notifier = Solid::DeviceNotifier::instance();
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
connect(notifier, SIGNAL(deviceAdded(QString)), this, SLOT(deviceAdded(QString)));
|
|
|
|
connect(notifier, SIGNAL(deviceRemoved(QString)), this, SLOT(deviceRemoved(QString)));
|
2014-11-19 01:03:24 +00:00
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
foreach (Solid::Device solidDevice, Solid::Device::listFromType(Solid::DeviceInterface::PortableMediaPlayer)) {
|
|
|
|
checkDevice(solidDevice);
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-12 20:28:04 +03:00
|
|
|
void DeviceCache::checkDevice(Solid::Device solidDevice)
|
2014-11-19 01:03:24 +00:00
|
|
|
{
|
2021-07-12 16:15:56 +03:00
|
|
|
Solid::PortableMediaPlayer *iface = solidDevice.as<Solid::PortableMediaPlayer>();
|
2021-07-12 19:38:06 +03:00
|
|
|
if (!iface) {
|
|
|
|
kWarning(KIO_MTP) << "Not portable media player device" << solidDevice.udi();
|
2021-07-12 16:15:56 +03:00
|
|
|
return;
|
2021-07-12 20:28:04 +03:00
|
|
|
} else if (!iface->supportedProtocols().contains(solidMTPProtocol)) {
|
|
|
|
kDebug(KIO_MTP) << "Not MTP device" << solidDevice.udi();
|
|
|
|
return;
|
2021-07-12 16:15:56 +03:00
|
|
|
}
|
2014-11-19 01:03:24 +00:00
|
|
|
|
2021-07-12 20:28:04 +03:00
|
|
|
const QByteArray solidSerial = iface->driverHandle(solidMTPProtocol).toByteArray();
|
2021-07-12 19:38:06 +03:00
|
|
|
if (solidSerial.isEmpty()) {
|
2021-07-12 20:28:04 +03:00
|
|
|
kWarning(KIO_MTP) << "No serial for device" << solidDevice.udi();
|
2021-07-12 16:15:56 +03:00
|
|
|
return;
|
|
|
|
}
|
2014-11-19 01:03:24 +00:00
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
if (!udiCache.contains(solidDevice.udi())) {
|
|
|
|
kDebug(KIO_MTP) << "New device, getting raw devices";
|
2014-11-19 01:03:24 +00:00
|
|
|
|
|
|
|
LIBMTP_raw_device_t *rawdevices = 0;
|
|
|
|
int numrawdevices;
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
LIBMTP_error_number_t err = LIBMTP_Detect_Raw_Devices(&rawdevices, &numrawdevices);
|
|
|
|
switch (err) {
|
|
|
|
case LIBMTP_ERROR_CONNECTING: {
|
|
|
|
kError(KIO_MTP) << "There has been an error connecting to the devices";
|
2014-11-19 01:03:24 +00:00
|
|
|
break;
|
2021-07-12 19:38:06 +03:00
|
|
|
}
|
|
|
|
case LIBMTP_ERROR_MEMORY_ALLOCATION: {
|
|
|
|
kError(KIO_MTP) << "Encountered a Memory Allocation Error";
|
2014-11-19 01:03:24 +00:00
|
|
|
break;
|
2021-07-12 19:38:06 +03:00
|
|
|
}
|
|
|
|
case LIBMTP_ERROR_NONE: {
|
|
|
|
kDebug(KIO_MTP) << "No Error, continuing";
|
2014-11-19 01:03:24 +00:00
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
for (int i = 0; i < numrawdevices; i++) {
|
2014-11-19 01:03:24 +00:00
|
|
|
LIBMTP_raw_device_t* rawDevice = &rawdevices[i];
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
LIBMTP_mtpdevice_t *mtpDevice = LIBMTP_Open_Raw_Device_Uncached(rawDevice);
|
2021-07-13 02:44:24 +03:00
|
|
|
if (mtpDevice == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-07-12 19:38:06 +03:00
|
|
|
const char* rawDeviceSerial = LIBMTP_Get_Serialnumber(mtpDevice);
|
2021-07-12 16:15:56 +03:00
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
kDebug(KIO_MTP) << "Checking for device match" << solidSerial << rawDeviceSerial;
|
|
|
|
if (solidSerial == rawDeviceSerial) {
|
2021-07-13 02:44:24 +03:00
|
|
|
kDebug(KIO_MTP) << "Found device matching the Solid description";
|
2021-07-12 19:38:06 +03:00
|
|
|
} else {
|
2021-07-12 21:02:40 +03:00
|
|
|
LIBMTP_Release_Device(mtpDevice);
|
2021-07-12 16:15:56 +03:00
|
|
|
continue;
|
|
|
|
}
|
2014-11-19 01:03:24 +00:00
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
if (!udiCache.contains(solidDevice.udi())) {
|
|
|
|
CachedDevice *cDev = new CachedDevice(mtpDevice, rawDevice, solidDevice.udi(), timeout);
|
|
|
|
udiCache.insert(solidDevice.udi(), cDev);
|
|
|
|
nameCache.insert(cDev->getName(), cDev);
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-12 01:48:49 +03:00
|
|
|
break;
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
case LIBMTP_ERROR_GENERAL:
|
2021-07-12 19:38:06 +03:00
|
|
|
default: {
|
|
|
|
kError(KIO_MTP) << "Unknown connection error";
|
2014-11-19 01:03:24 +00:00
|
|
|
break;
|
2021-07-12 19:38:06 +03:00
|
|
|
}
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
2021-07-13 02:44:24 +03:00
|
|
|
|
|
|
|
if (!udiCache.contains(solidDevice.udi())) {
|
|
|
|
kError(KIO_MTP) << "No device match found, device busy?";
|
|
|
|
}
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
::free(rawdevices);
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
void DeviceCache::deviceAdded(const QString& udi)
|
2014-11-19 01:03:24 +00:00
|
|
|
{
|
2021-07-12 19:38:06 +03:00
|
|
|
kDebug(KIO_MTP) << "New device attached with udi" << udi << ". Checking if PortableMediaPlayer...";
|
2014-11-19 01:03:24 +00:00
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
Solid::Device device(udi);
|
|
|
|
if (device.isDeviceInterface(Solid::DeviceInterface::PortableMediaPlayer)) {
|
|
|
|
kDebug(KIO_MTP) << "SOLID: New Device with udi" << udi;
|
2014-11-19 01:03:24 +00:00
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
checkDevice(device);
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
void DeviceCache::deviceRemoved(const QString& udi)
|
2014-11-19 01:03:24 +00:00
|
|
|
{
|
2021-07-12 19:38:06 +03:00
|
|
|
if (udiCache.contains(udi)) {
|
2021-07-13 02:02:54 +03:00
|
|
|
kDebug(KIO_MTP) << "SOLID: Device with udi" << udi << "removed.";
|
2014-11-19 01:03:24 +00:00
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
CachedDevice *cDev = udiCache.value(udi);
|
2014-11-19 01:03:24 +00:00
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
udiCache.remove(cDev->getUdi());
|
|
|
|
nameCache.remove(cDev->getName());
|
2014-11-19 01:03:24 +00:00
|
|
|
delete cDev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DeviceCache::~DeviceCache()
|
|
|
|
{
|
|
|
|
processEvents();
|
|
|
|
|
|
|
|
// Release devices
|
2021-07-12 19:38:06 +03:00
|
|
|
foreach (QString udi, udiCache.keys()) {
|
|
|
|
deviceRemoved(udi);
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QHash<QString, CachedDevice*> DeviceCache::getAll()
|
|
|
|
{
|
2021-07-12 19:38:06 +03:00
|
|
|
kDebug(KIO_MTP ) << "getAll()";
|
2014-11-19 01:03:24 +00:00
|
|
|
|
|
|
|
processEvents();
|
|
|
|
|
|
|
|
return nameCache;
|
|
|
|
}
|
|
|
|
|
2021-07-13 20:41:58 +03:00
|
|
|
bool DeviceCache::contains(const QString& string, bool isUdi)
|
2014-11-19 01:03:24 +00:00
|
|
|
{
|
|
|
|
processEvents();
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
if (isUdi) {
|
|
|
|
return udiCache.contains(string);
|
|
|
|
}
|
|
|
|
return nameCache.contains(string);
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
CachedDevice* DeviceCache::get(const QString& string, bool isUdi)
|
2014-11-19 01:03:24 +00:00
|
|
|
{
|
|
|
|
processEvents();
|
|
|
|
|
2021-07-12 19:38:06 +03:00
|
|
|
if (isUdi) {
|
|
|
|
return udiCache.value(string);
|
|
|
|
}
|
|
|
|
return nameCache.value(string);
|
2014-11-19 01:03:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int DeviceCache::size()
|
|
|
|
{
|
|
|
|
processEvents();
|
|
|
|
|
|
|
|
return nameCache.size();
|
|
|
|
}
|
|
|
|
|
2015-02-27 09:28:46 +00:00
|
|
|
#include "moc_devicecache.cpp"
|