Files
qcma/cmaevent.cpp
codestation 92f4572814 Make sure that BaseWorker deletes the thread when is finished.
Implemented ClientManager so it can manage the usb and wireless threads.
Impelmented better mutex logic on CmaClient.
Execute the cma events in a different thread so the event listener is
available.
Code refactoring.
Fix memory leaks in threads.
Updated readme.
2013-08-25 01:40:14 -04:30

860 lines
28 KiB
C++

#include "cmaevent.h"
#include "utils.h"
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QSettings>
#include <QUrl>
Database *CmaEvent::db = NULL;
metadata_t CmaEvent::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL};
CmaEvent::CmaEvent(vita_device_t *s_device, QObject *parent) :
BaseWorker(parent), device(s_device), is_active(true)
{
}
void CmaEvent::process()
{
qDebug() << "Starting event_thread:" << QThread::currentThreadId();
while(true) {
sema.acquire();
if(!isActive()) {
break;
}
mutex.lock();
processEvent();
mutex.unlock();
}
qDebug("Finishing event_thread");
emit finished();
}
bool CmaEvent::isActive()
{
QMutexLocker locker(&active);
return is_active;
}
void CmaEvent::stop()
{
QMutexLocker locker(&active);
is_active = false;
sema.release();
}
void CmaEvent::setDevice(vita_device_t *device)
{
QMutexLocker locker(&mutex);
this->device = device;
}
void CmaEvent::setEvent(vita_event_t event)
{
mutex.lock();
this->t_event = event;
mutex.unlock();
sema.release();
}
void CmaEvent::processEvent()
{
qDebug() << "Starting event_thread:" << QThread::currentThreadId();
switch(t_event.Code) {
case PTP_EC_VITA_RequestSendNumOfObject:
vitaEventSendNumOfObject(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendObjectMetadata:
vitaEventSendObjectMetadata(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendObject:
vitaEventSendObject(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendHttpObjectFromURL:
vitaEventSendHttpObjectFromURL(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_Unknown1: // unimplemented
vitaEventUnimplementated(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendObjectStatus:
vitaEventSendObjectStatus(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendObjectThumb:
vitaEventSendObjectThumb(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestDeleteObject:
vitaEventDeleteObject(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestGetSettingInfo:
vitaEventGetSettingInfo(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendHttpObjectPropFromURL:
vitaEventSendHttpObjectPropFromURL(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendPartOfObject:
vitaEventSendPartOfObject(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestOperateObject:
vitaEventOperateObject(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestGetPartOfObject:
vitaEventGetPartOfObject(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendStorageSize:
vitaEventSendStorageSize(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestCheckExistance:
vitaEventCheckExistance(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestGetTreatObject:
vitaEventGetTreatObject(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendCopyConfirmationInfo:
vitaEventSendCopyConfirmationInfo(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendObjectMetadataItems:
vitaEventSendObjectMetadataItems(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendNPAccountInfo:
vitaEventSendNPAccountInfo(&t_event, t_event.Param1);
break;
default:
vitaEventUnimplementated(&t_event, t_event.Param1);
}
qDebug("Ended event, code: 0x%x, id: %d", t_event.Code, t_event.Param1);
}
quint16 CmaEvent::processAllObjects(CMAObject *parent, quint32 handle)
{
union {
unsigned char *fileData;
uint32_t *handles;
} data;
metadata_t remote_meta;
unsigned int length;
if(VitaMTP_GetObject(device, handle, &remote_meta, (void **)&data, &length) != PTP_RC_OK) {
qWarning("Cannot get object for handle %d", handle);
return PTP_RC_VITA_Invalid_Data;
}
CMAObject *object = db->pathToObject(remote_meta.name, parent->metadata.ohfi);
if(object) {
qDebug("Deleting %s", object->path.toStdString().c_str());
removeRecursively(object->path);
db->remove(object);
}
QDir dir(parent->path);
if(remote_meta.dataType & Folder) {
if(!dir.mkpath(remote_meta.name)) {
qWarning("Cannot create directory: %s", remote_meta.name);
free(data.fileData);
free(remote_meta.name);
return PTP_RC_VITA_Failed_Operate_Object;
}
} else {
QFile file(dir.absoluteFilePath(remote_meta.name));
if(!file.open(QIODevice::WriteOnly)) {
qWarning("Cannot write to %s", remote_meta.name);
free(data.fileData);
free(remote_meta.name);
return PTP_RC_VITA_Invalid_Permission;
} else {
file.write((const char *)data.fileData, remote_meta.size);
}
}
QFileInfo info(dir, remote_meta.name);
object = new CMAObject(parent);
object->initObject(info);
object->metadata.handle = remote_meta.handle;
db->append(parent->metadata.ohfi, object);
free(remote_meta.name);
qDebug("Added object %s with OHFI %i to database", object->metadata.path, object->metadata.ohfi);
if(remote_meta.dataType & Folder) {
for(unsigned int i = 0; i < length; i++) {
quint16 ret = processAllObjects(object, data.handles[i]);
if(ret != PTP_RC_OK) {
qDebug("Deleteting object with OHFI %d", object->metadata.ohfi);
db->remove(object);
free(data.fileData);
return ret;
}
}
}
free(data.fileData);
return PTP_RC_OK;
}
void CmaEvent::vitaEventGetTreatObject(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
treat_object_t treatObject;
if(VitaMTP_GetTreatObject(device, eventId, &treatObject) != PTP_RC_OK) {
qWarning("Cannot get information on object to get");
return;
}
QMutexLocker locker(&db->mutex);
CMAObject *parent = db->ohfiToObject(treatObject.ohfiParent);
if(parent == NULL) {
qWarning("Cannot find parent OHFI %d", treatObject.ohfiParent);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
return;
}
VitaMTP_ReportResult(device, eventId, processAllObjects(parent, treatObject.handle));
}
void CmaEvent::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
copy_confirmation_info_t *info;
if(VitaMTP_SendCopyConfirmationInfoInit(device, eventId, &info) != PTP_RC_OK) {
qWarning("Error recieving initial information.");
return;
}
QMutexLocker locker(&db->mutex);
quint64 size = 0;
for(quint32 i = 0; i < info->count; i++) {
CMAObject *object;
if((object = db->ohfiToObject(info->ohfi[i])) == NULL) {
qWarning("Cannot find OHFI %d", info->ohfi[i]);
free(info);
return;
}
size += object->metadata.size;
}
if(VitaMTP_SendCopyConfirmationInfo(device, eventId, info, size) != PTP_RC_OK) {
qWarning("Error sending copy confirmation");
} else {
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
free(info);
}
void CmaEvent::vitaEventSendObjectMetadataItems(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
quint32 ohfi;
if(VitaMTP_SendObjectMetadataItems(device, eventId, &ohfi) != PTP_RC_OK) {
qWarning("Cannot get OHFI for retreving metadata");
return;
}
QMutexLocker locker(&db->mutex);
CMAObject *object = db->ohfiToObject(ohfi);
if(object == NULL) {
qWarning("Cannot find OHFI %d in database", ohfi);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
return;
}
metadata_t *metadata = &object->metadata;
metadata->next_metadata = NULL;
qDebug("Sending metadata for OHFI %d (%s)", ohfi, metadata->path);
if(VitaMTP_SendObjectMetadata(device, eventId, metadata) != PTP_RC_OK) {
qWarning("Error sending metadata");
} else {
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
}
void CmaEvent::vitaEventSendNPAccountInfo(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
// AFAIK, Sony hasn't even implemented this in their CMA
qWarning("Event 0x%x unimplemented!", event->Code);
}
void CmaEvent::vitaEventUnimplementated(vita_event_t *event, int eventId)
{
qWarning("Unknown event not handled, code: 0x%x, id: %d", event->Code, eventId);
qWarning("Param1: 0x%08X, Param2: 0x%08X, Param3: 0x%08X", event->Param1, event->Param2, event->Param3);
}
void CmaEvent::vitaEventSendNumOfObject(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
QMutexLocker locker(&db->mutex);
uint ohfi = event->Param2;
int items = db->filterObjects(ohfi, NULL);
if(VitaMTP_SendNumOfObject(device, eventId, items) != PTP_RC_OK) {
qWarning("Error occured receiving object count for OHFI parent %d", ohfi);
} else {
qDebug("Returned count of %d objects for OHFI parent %d", items, ohfi);
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
}
void CmaEvent::vitaEventSendObjectMetadata(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
browse_info_t browse;
if(VitaMTP_GetBrowseInfo(device, eventId, &browse) != PTP_RC_OK) {
qWarning("GetBrowseInfo failed");
return;
}
QMutexLocker locker(&db->mutex);
metadata_t *meta;
int count = db->filterObjects(browse.ohfiParent, &meta); // if meta is null, will return empty XML
qDebug("Sending %i metadata filtered objects for OHFI %d", count, browse.ohfiParent);
if(VitaMTP_SendObjectMetadata(device, eventId, meta) != PTP_RC_OK) { // send all objects with OHFI parent
qWarning("Sending metadata for OHFI parent %d failed", browse.ohfiParent);
} else {
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
}
void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
int ohfi = event->Param2;
QMutexLocker locker(&db->mutex);
qDebug("Searching object with OHFI %d", ohfi);
Database::find_data iters;
if(!db->find(ohfi, iters)) {
qWarning("Failed to find OHFI %d", ohfi);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
return;
}
unsigned long len = 0;
CMAObject *object = *iters.it;
CMAObject *start = object;
uint parentHandle = event->Param3;
bool send_folder = object->metadata.dataType & Folder;
uint handle;
do {
uchar *data = NULL;
len = object->metadata.size;
QFile file(object->path);
// read the file to send if it's not a directory
// if it is a directory, data and len are not used by VitaMTP
if(object->metadata.dataType & File) {
if(!file.open(QIODevice::ReadOnly) || (data = file.map(0, file.size())) == NULL) {
qWarning("Failed to read %s", object->path.toStdString().c_str());
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Not_Exist_Object);
return;
}
}
// get the PTP object ID for the parent to put the object
// we know the parent has to be before the current node
// the first time this is called, parentHandle is left untouched
if(start != object) {
parentHandle = object->parent->metadata.handle;
}
// send the data over
qDebug("Sending %s of %lu bytes to device", object->metadata.name, len);
qDebug("OHFI %d with handle 0x%08X", ohfi, parentHandle);
if(VitaMTP_SendObject(device, &parentHandle, &handle, &object->metadata, data, NULL) != PTP_RC_OK) {
qWarning("Sending of %s failed.", object->metadata.name);
file.unmap(data);
return;
}
object->metadata.handle = handle;
if(object->metadata.dataType & File) {
file.unmap(data);
}
// break early if only a file needs to be sent
if(!send_folder) {
break;
}
object = *++iters.it;
} while(iters.it != iters.end && object->metadata.ohfiParent >= OHFI_OFFSET); // get everything under this "folder"
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, handle);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); // TODO: Send thumbnail
}
void CmaEvent::vitaEventSendHttpObjectFromURL(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
char *url;
if(VitaMTP_GetUrl(device, eventId, &url) != PTP_RC_OK) {
qWarning("Failed to recieve URL");
return;
}
QString urlpath = QSettings().value("urlPath").toString();
QString basename = QFileInfo(QUrl(url).path()).fileName();
QFile file(QDir(urlpath).absoluteFilePath(basename));
QByteArray data;
if(!file.open(QIODevice::ReadOnly)) {
if(basename == "psp2-updatelist.xml") {
qDebug("Found request for update list. Sending cached data");
QFile res(":/main/psp2-updatelist.xml");
res.open(QIODevice::ReadOnly);
data = res.readAll();
} else {
qWarning("Failed to download %s", url);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Download);
free(url);
return;
}
} else {
data = file.readAll();
}
qDebug("Sending %i bytes of data for HTTP request %s", data.size(), url);
if(VitaMTP_SendHttpObjectFromURL(device, eventId, data.data(), data.size()) != PTP_RC_OK) {
qWarning("Failed to send HTTP object");
} else {
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
free(url);
}
void CmaEvent::vitaEventSendObjectStatus(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
object_status_t objectstatus;
if(VitaMTP_SendObjectStatus(device, eventId, &objectstatus) != PTP_RC_OK) {
qWarning("Failed to get information for object status.");
return;
}
QMutexLocker locker(&db->mutex);
CMAObject *object = db->pathToObject(objectstatus.title, objectstatus.ohfiRoot);
if(object == NULL) { // not in database, don't return metadata
qDebug("Object %s not in database (OHFI: %i). Sending OK response for non-existence", objectstatus.title, objectstatus.ohfiRoot);
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
} else {
metadata_t *metadata = &object->metadata;
metadata->next_metadata = NULL;
qDebug("Sending metadata for OHFI %d", object->metadata.ohfi);
if(VitaMTP_SendObjectMetadata(device, eventId, metadata) != PTP_RC_OK) {
qWarning("Error sending metadata for %d", object->metadata.ohfi);
} else {
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
}
free(objectstatus.title);
}
void CmaEvent::vitaEventSendObjectThumb(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
QMutexLocker locker(&db->mutex);
int ohfi = event->Param2;
CMAObject *object = db->ohfiToObject(ohfi);
if(object == NULL) {
qWarning("Cannot find OHFI %d in database.", ohfi);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
return;
}
QByteArray data = getThumbnail(object->path, object->metadata.dataType, &g_thumbmeta);
if(data.size() == 0) {
qWarning("Cannot find/read thumbnail for %s", object->path.toStdString().c_str());
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data);
return;
}
// workaround for the vitamtp locale bug
char *locale = strdup(setlocale(LC_ALL, NULL));
setlocale(LC_ALL, "C");
if(VitaMTP_SendObjectThumb(device, eventId, (metadata_t *)&g_thumbmeta, (uchar *)data.data(), data.size()) != PTP_RC_OK) {
qWarning("Error sending thumbnail");
} else {
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
// restore locale
setlocale(LC_ALL, locale);
free(locale);
}
void CmaEvent::vitaEventDeleteObject(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
QMutexLocker locker(&db->mutex);
int ohfi = event->Param2;
CMAObject *object = db->ohfiToObject(ohfi);
if(object == NULL) {
qWarning("OHFI %d not found", ohfi);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
return;
}
qDebug("Deleting %s, OHFI: %i", object->metadata.path, object->metadata.ohfi);
removeRecursively(object->path);
db->remove(object);
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
void CmaEvent::vitaEventGetSettingInfo(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
settings_info_t *settingsinfo;
if(VitaMTP_GetSettingInfo(device, eventId, &settingsinfo) != PTP_RC_OK) {
qWarning("Failed to get setting info from Vita.");
return;
}
qDebug("Current account id: %s", settingsinfo->current_account.accountId);
if(QSettings().value("lastAccountId").toString() != settingsinfo->current_account.accountId) {
db->setUUID(settingsinfo->current_account.accountId);
// set the database to be updated ASAP
emit refreshDatabase();
}
// free all the information
VitaMTP_Data_Free_Settings(settingsinfo);
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
void CmaEvent::vitaEventSendHttpObjectPropFromURL(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
char *url;
if(VitaMTP_GetUrl(device, eventId, &url) != PTP_RC_OK) {
qWarning("Failed to get URL");
return;
}
QString urlpath = QSettings().value("urlPath").toString();
QString basename = QFileInfo(url).fileName();
QFileInfo file(QDir(urlpath).absoluteFilePath(basename));
if(!file.exists()) {
qWarning("The file %s is not accesible", url);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Download);
free(url);
return;
}
QString timestamp = file.lastModified().toString();
http_object_prop_t httpobjectprop;
httpobjectprop.timestamp = timestamp.toUtf8().data();
httpobjectprop.timestamp_len = timestamp.toUtf8().size();
if(VitaMTP_SendHttpObjectPropFromURL(device, eventId, &httpobjectprop) != PTP_RC_OK) {
qWarning("Failed to send object properties");
} else {
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
free(url);
}
void CmaEvent::vitaEventSendPartOfObject(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
send_part_init_t part_init;
if(VitaMTP_SendPartOfObjectInit(device, eventId, &part_init) != PTP_RC_OK) {
qWarning("Cannot get information on object to send");
return;
}
QMutexLocker locker(&db->mutex);
CMAObject *object = db->ohfiToObject(part_init.ohfi);
if(object == NULL) {
qWarning("Cannot find object for OHFI %d", part_init.ohfi);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Context);
return;
}
QFile file(object->path);
if(!file.open(QIODevice::ReadOnly)) {
qWarning("Cannot read %s", object->path.toStdString().c_str());
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Not_Exist_Object);
return;
} else {
file.seek(part_init.offset);
QByteArray data = file.read(part_init.size);
qDebug("Sending %s at file offset %zu for %zu bytes", object->metadata.path, part_init.offset, part_init.size);
if(VitaMTP_SendPartOfObject(device, eventId, (unsigned char *)data.data(), data.size()) != PTP_RC_OK) {
qWarning("Failed to send part of object OHFI %d", part_init.ohfi);
} else {
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
}
}
void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
operate_object_t operateobject;
if(VitaMTP_OperateObject(device, eventId, &operateobject) != PTP_RC_OK) {
qWarning("Cannot get information on object to operate");
return;
}
QMutexLocker locker(&db->mutex);
CMAObject *root = db->ohfiToObject(operateobject.ohfi);
// end for renaming only
if(root == NULL) {
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Not_Exist_Object);
return;
}
switch(operateobject.cmd) {
case VITA_OPERATE_CREATE_FOLDER: {
qDebug("Operate command %d: Create folder %s", operateobject.cmd, operateobject.title);
QDir dir(root->path);
if(!dir.mkdir(operateobject.title)) {
qWarning("Unable to create temporary folder: %s", operateobject.title);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object);
} else {
CMAObject *newobj = new CMAObject(root);
newobj->initObject(QFileInfo(dir, operateobject.title));
db->append(operateobject.ohfi, newobj);
qDebug("Created folder %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path);
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
}
break;
}
case VITA_OPERATE_CREATE_FILE: {
qDebug("Operate command %d: Create file %s", operateobject.cmd, operateobject.title);
QFile file(root->path + QDir::separator() + operateobject.title);
if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qWarning("Unable to create temporary file: %s", operateobject.title);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object);
} else {
CMAObject *newobj = new CMAObject(root);
newobj->initObject(file);
db->append(root->metadata.ohfi, newobj);
qDebug("Created file %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path);
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
}
break;
}
case VITA_OPERATE_RENAME: {
qDebug("Operate command %d: Rename %s to %s", operateobject.cmd, root->metadata.name, operateobject.title);
QString oldpath = root->path;
QString oldname = root->metadata.name;
//rename the current object
root->rename(operateobject.title);
Database::find_data iters;
db->find(root->metadata.ohfi, iters);
// rename the rest of the list only if has the renamed parent in some part of the chain
while(iters.it != iters.end) {
CMAObject *obj = *iters.it++;
if(obj->hasParent(root)) {
obj->refreshPath();
}
}
// rename in filesystem
if(!QFile(oldpath).rename(root->path)) {
qWarning("Unable to rename %s to %s", oldname.toStdString().c_str(), operateobject.title);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object);
break;
}
qDebug("Renamed OHFI %d from %s to %s", root->metadata.ohfi, oldname.toStdString().c_str(), root->metadata.name);
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, root->metadata.ohfi);
break;
}
default:
qWarning("Operate command %d: Not implemented", operateobject.cmd);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object);
break;
}
free(operateobject.title);
}
void CmaEvent::vitaEventGetPartOfObject(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
unsigned char *data;
send_part_init_t part_init;
if(VitaMTP_GetPartOfObject(device, eventId, &part_init, &data) != PTP_RC_OK) {
qWarning("Cannot get object from device");
return;
}
QMutexLocker locker(&db->mutex);
CMAObject *object = db->ohfiToObject(part_init.ohfi);
if(object == NULL) {
qWarning("Cannot find OHFI %d", part_init.ohfi);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
free(data);
return;
}
qDebug("Receiving %s at offset %zu for %zu bytes", object->metadata.path, part_init.offset, part_init.size);
QFile file(object->path);
if(!file.open(QIODevice::ReadWrite)) {
qWarning("Cannot write to file %s", object->path.toStdString().c_str());
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Permission);
} else {
file.seek(part_init.offset);
file.write((const char *)data, part_init.size);
object->updateObjectSize(part_init.size);
qDebug("Written %zu bytes to %s at offset %zu.", part_init.size, object->path.toStdString().c_str(), part_init.offset);
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
free(data);
}
void CmaEvent::vitaEventSendStorageSize(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
QMutexLocker locker(&db->mutex);
int ohfi = event->Param2;
CMAObject *object = db->ohfiToObject(ohfi);
if(object == NULL) {
qWarning("Error: Cannot find OHFI %d", ohfi);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
return;
} else {
QFile file(object->path);
if(!file.exists()) {
// create the directory if doesn't exist so the query don't fail
qDebug("Creating %s", object->path.toStdString().c_str());
if(!QDir(QDir::root()).mkpath(object->path)) {
qWarning("Create directory failed");
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Permission);
return;
}
}
}
quint64 total;
quint64 free;
if(!getDiskSpace(object->path, &free, &total)) {
qWarning("Cannot get disk space");
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Permission);
return;
}
qDebug("Storage stats for drive containing OHFI %d, free: %llu, total: %llu", ohfi, free, total);
if(VitaMTP_SendStorageSize(device, eventId, total, free) != PTP_RC_OK) {
qWarning("Send storage size failed");
} else {
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
}
void CmaEvent::vitaEventCheckExistance(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
int handle = event->Param2;
existance_object_t existance;
if(VitaMTP_CheckExistance(device, handle, &existance) != PTP_RC_OK) {
qWarning("Cannot read information on object to be sent");
return;
}
QMutexLocker locker(&db->mutex);
CMAObject *object = db->pathToObject(existance.name, 0);
if(object == NULL) {
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Different_Object);
} else {
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_VITA_Same_Object, object->metadata.ohfi);
}
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}