2023-11-21 12:38:01 +03:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "fileproviderxpc.h"
|
|
|
|
|
|
|
|
#include <QLoggingCategory>
|
|
|
|
|
2023-11-22 14:45:48 +03:00
|
|
|
#import <FileProvider/FileProvider.h>
|
|
|
|
|
|
|
|
#import "ClientCommunicationProtocol.h"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
static const auto clientCommunicationServiceName = "com.nextcloud.desktopclient.ClientCommunicationService";
|
|
|
|
static NSString *const nsClientCommunicationServiceName = [NSString stringWithUTF8String:clientCommunicationServiceName];
|
|
|
|
}
|
|
|
|
|
2023-11-21 12:38:01 +03:00
|
|
|
namespace OCC {
|
|
|
|
|
|
|
|
namespace Mac {
|
|
|
|
|
|
|
|
Q_LOGGING_CATEGORY(lcFileProviderXPC, "nextcloud.gui.macos.fileprovider.xpc", QtInfoMsg)
|
|
|
|
|
|
|
|
FileProviderXPC::FileProviderXPC(QObject *parent)
|
|
|
|
: QObject{parent}
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-11-22 14:45:48 +03:00
|
|
|
void FileProviderXPC::start()
|
|
|
|
{
|
|
|
|
qCInfo(lcFileProviderXPC) << "Starting file provider XPC";
|
2023-11-22 15:11:56 +03:00
|
|
|
|
|
|
|
dispatch_group_t group = dispatch_group_create();
|
2023-11-22 20:25:03 +03:00
|
|
|
__block NSMutableArray<NSFileProviderManager *> *managers = NSMutableArray.array;
|
2023-11-22 15:11:56 +03:00
|
|
|
|
|
|
|
dispatch_group_enter(group);
|
|
|
|
|
2023-11-22 14:45:48 +03:00
|
|
|
// Set up connections for each domain
|
|
|
|
[NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray<NSFileProviderDomain *> *const domains, NSError *const error){
|
|
|
|
if (error != nil) {
|
|
|
|
qCWarning(lcFileProviderXPC) << "Error getting domains" << error;
|
2023-11-22 15:11:56 +03:00
|
|
|
dispatch_group_leave(group);
|
2023-11-22 14:45:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-11-22 20:25:03 +03:00
|
|
|
for (NSFileProviderDomain *const domain in domains) {
|
|
|
|
qCInfo(lcFileProviderXPC) << "Got domain" << domain.identifier;
|
|
|
|
NSFileProviderManager *const manager = [NSFileProviderManager managerForDomain:domain];
|
|
|
|
[managers addObject:manager];
|
|
|
|
}
|
|
|
|
|
2023-11-22 15:11:56 +03:00
|
|
|
dispatch_group_leave(group);
|
|
|
|
}];
|
|
|
|
|
|
|
|
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
|
|
|
|
2023-11-22 20:25:03 +03:00
|
|
|
if (managers.count == 0) {
|
2023-11-22 15:11:56 +03:00
|
|
|
qCWarning(lcFileProviderXPC) << "No domains found";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
__block NSMutableArray<NSURL *> *urls = NSMutableArray.array;
|
|
|
|
|
2023-11-22 20:25:03 +03:00
|
|
|
for (NSFileProviderManager *const manager in managers) {
|
2023-11-22 15:11:56 +03:00
|
|
|
|
2023-11-22 20:25:03 +03:00
|
|
|
dispatch_group_enter(group);
|
2023-11-22 15:11:56 +03:00
|
|
|
|
|
|
|
[manager getUserVisibleURLForItemIdentifier:NSFileProviderRootContainerItemIdentifier
|
|
|
|
completionHandler:^(NSURL *const url, NSError *const error){
|
|
|
|
if (error != nil) {
|
|
|
|
qCWarning(lcFileProviderXPC) << "Error getting user visible url" << error;
|
|
|
|
dispatch_group_leave(group);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qCDebug(lcFileProviderXPC) << "Got user visible url" << url;
|
|
|
|
[urls addObject:url];
|
|
|
|
dispatch_group_leave(group);
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
|
|
|
|
|
|
|
if (urls.count == 0) {
|
|
|
|
qCWarning(lcFileProviderXPC) << "No urls found";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSMutableArray<NSDictionary<NSFileProviderServiceName, NSFileProviderService *> *> *const fpServices = NSMutableArray.array;
|
|
|
|
|
|
|
|
for (NSURL *const url in urls) {
|
|
|
|
dispatch_group_enter(group);
|
|
|
|
|
|
|
|
[NSFileManager.defaultManager getFileProviderServicesForItemAtURL:url
|
|
|
|
completionHandler:^(NSDictionary<NSFileProviderServiceName, NSFileProviderService *> *const services, NSError *const error){
|
|
|
|
if (error != nil) {
|
|
|
|
qCWarning(lcFileProviderXPC) << "Error getting file provider services" << error;
|
|
|
|
dispatch_group_leave(group);
|
|
|
|
return;
|
|
|
|
}
|
2023-11-22 14:45:48 +03:00
|
|
|
|
2023-11-22 20:25:03 +03:00
|
|
|
qCInfo(lcFileProviderXPC) << "Got file provider services for"
|
|
|
|
<< url.absoluteString
|
|
|
|
<< "has number of services:"
|
|
|
|
<< services.count;
|
2023-11-22 15:11:56 +03:00
|
|
|
[fpServices addObject:services];
|
|
|
|
dispatch_group_leave(group);
|
|
|
|
}];
|
|
|
|
}
|
2023-11-22 14:45:48 +03:00
|
|
|
|
2023-11-22 15:11:56 +03:00
|
|
|
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
|
|
|
|
|
|
|
if (fpServices.count == 0) {
|
|
|
|
qCWarning(lcFileProviderXPC) << "No file provider services found";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-05 17:39:05 +03:00
|
|
|
NSMutableArray<NSXPCConnection *> *const connections = NSMutableArray.array;
|
|
|
|
|
2023-11-22 15:11:56 +03:00
|
|
|
for (NSDictionary<NSFileProviderServiceName, NSFileProviderService *> *const services in fpServices) {
|
|
|
|
NSArray<NSFileProviderServiceName> *const serviceNamesArray = services.allKeys;
|
|
|
|
|
|
|
|
for (NSFileProviderServiceName serviceName in serviceNamesArray) {
|
2023-11-22 20:25:03 +03:00
|
|
|
qCInfo(lcFileProviderXPC) << "Got service" << serviceName;
|
2023-11-22 15:11:56 +03:00
|
|
|
|
|
|
|
if (![serviceName isEqualToString:nsClientCommunicationServiceName]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSFileProviderService *const service = services[serviceName];
|
|
|
|
dispatch_group_enter(group);
|
|
|
|
|
|
|
|
[service getFileProviderConnectionWithCompletionHandler:^(NSXPCConnection *const connection, NSError *const error){
|
2023-11-22 14:45:48 +03:00
|
|
|
if (error != nil) {
|
2023-11-22 15:11:56 +03:00
|
|
|
qCWarning(lcFileProviderXPC) << "Error getting file provider connection" << error;
|
|
|
|
dispatch_group_leave(group);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-11-22 20:25:03 +03:00
|
|
|
qCInfo(lcFileProviderXPC) << "Got file provider connection" << connection;
|
2023-11-22 15:11:56 +03:00
|
|
|
|
|
|
|
if (connection == nil) {
|
|
|
|
qCWarning(lcFileProviderXPC) << "Connection is nil";
|
|
|
|
dispatch_group_leave(group);
|
2023-11-22 14:45:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-05 17:39:05 +03:00
|
|
|
[connection retain];
|
|
|
|
[connections addObject:connection];
|
2023-11-22 15:11:56 +03:00
|
|
|
dispatch_group_leave(group);
|
2023-11-22 14:45:48 +03:00
|
|
|
}];
|
|
|
|
}
|
2023-11-22 15:11:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
2023-12-05 17:39:05 +03:00
|
|
|
|
2023-12-12 20:38:33 +03:00
|
|
|
NSMutableDictionary<NSString *, NSObject<ClientCommunicationProtocol>*> *const clientCommServices = NSMutableDictionary.dictionary;
|
|
|
|
|
2023-12-05 17:39:05 +03:00
|
|
|
for (NSXPCConnection * const connection in connections) {
|
|
|
|
Q_ASSERT(connection != nil);
|
|
|
|
connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ClientCommunicationProtocol)];
|
|
|
|
connection.interruptionHandler = ^{
|
|
|
|
qCInfo(lcFileProviderXPC) << "File provider connection interrupted";
|
|
|
|
};
|
|
|
|
connection.invalidationHandler = ^{
|
|
|
|
qCInfo(lcFileProviderXPC) << "File provider connection invalidated";
|
|
|
|
};
|
|
|
|
[connection resume];
|
|
|
|
|
|
|
|
const id remoteServiceObject = [connection remoteObjectProxyWithErrorHandler:^(NSError *const error){
|
|
|
|
qCWarning(lcFileProviderXPC) << "Error getting remote object proxy" << error;
|
|
|
|
}];
|
|
|
|
|
2023-12-11 15:37:29 +03:00
|
|
|
if (![remoteServiceObject conformsToProtocol:@protocol(ClientCommunicationProtocol)]) {
|
|
|
|
qCWarning(lcFileProviderXPC) << "Remote service object does not conform to protocol";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-05 17:39:05 +03:00
|
|
|
NSObject<ClientCommunicationProtocol> *const clientCommService = (NSObject<ClientCommunicationProtocol> *)remoteServiceObject;
|
|
|
|
if (clientCommService == nil) {
|
|
|
|
qCWarning(lcFileProviderXPC) << "Client communication service is nil";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
[clientCommService retain];
|
2023-12-12 20:38:33 +03:00
|
|
|
__block NSString *extensionNcAccount = @"";
|
|
|
|
dispatch_group_enter(group);
|
|
|
|
[clientCommService getExtensionAccountIdWithCompletionHandler:^(NSString *const extensionAccountId, NSError *const error){
|
|
|
|
if (error != nil) {
|
|
|
|
qCWarning(lcFileProviderXPC) << "Error getting extension account id" << error;
|
|
|
|
dispatch_group_leave(group);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
extensionNcAccount = [NSString stringWithString:extensionAccountId];
|
|
|
|
[extensionNcAccount retain];
|
|
|
|
dispatch_group_leave(group);
|
|
|
|
}];
|
|
|
|
|
|
|
|
dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // Do not edit the NSDictionary concurrently
|
|
|
|
|
|
|
|
if (extensionNcAccount == nil) {
|
|
|
|
qCWarning(lcFileProviderXPC) << "Extension account id is nil";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
qCInfo(lcFileProviderXPC) << "Got extension account id" << extensionNcAccount.UTF8String;
|
|
|
|
[clientCommServices setObject:clientCommService forKey:extensionNcAccount];
|
|
|
|
}
|
2023-12-05 17:39:05 +03:00
|
|
|
}
|
2023-11-22 14:45:48 +03:00
|
|
|
}
|
|
|
|
|
2023-11-21 12:38:01 +03:00
|
|
|
} // namespace OCC
|
|
|
|
|
|
|
|
} // namespace Mac
|