From 22c176af8ad33f9d505fa74aea36fb702f6294d3 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 21 Nov 2023 09:18:21 +0800 Subject: [PATCH 01/52] Add starter client communication service Signed-off-by: Claudio Cambra --- .../Services/ClientCommunicationService.h | 26 ++++++++++++++ .../Services/ClientCommunicationService.m | 36 +++++++++++++++++++ .../project.pbxproj | 14 ++++++++ 3 files changed, 76 insertions(+) create mode 100644 shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h create mode 100644 shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h new file mode 100644 index 0000000000000..7d0e065c18ae4 --- /dev/null +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * 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. + */ + + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ClientCommunicationService : NSObject + +@property (readonly) NSXPCListener *listener; + +@end + +NS_ASSUME_NONNULL_END diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m new file mode 100644 index 0000000000000..f2790399abb0b --- /dev/null +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * 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. + */ + +#import "ClientCommunicationService.h" + +@implementation ClientCommunicationService + +@synthesize serviceName = _serviceName; + +- (instancetype)init +{ + self = [super init]; + if (self) { + _serviceName = @"com.nextcloud.desktopclient.ClientCommunicationService"; + _listener = NSXPCListener.anonymousListener; + } + return self; +} + +- (nullable NSXPCListenerEndpoint *)makeListenerEndpointAndReturnError:(NSError * *)error +{ + return self.listener.endpoint; +} + +@end diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj index c592022afe4d6..0e023751c2733 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj +++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */; }; 5318AD9729BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */; }; 5318AD9929BF58D000CBB71C /* NKError+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9829BF58D000CBB71C /* NKError+Extensions.swift */; }; + 5350E4E22B0C459600F276CB /* ClientCommunicationService.m in Sources */ = {isa = PBXBuildFile; fileRef = 5350E4E12B0C459600F276CB /* ClientCommunicationService.m */; }; 5352B36629DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36529DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift */; }; 5352B36829DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36729DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift */; }; 5352B36C29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */; }; @@ -145,6 +146,8 @@ 5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudLocalFileMetadataTable.swift; sourceTree = ""; }; 5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderMaterialisedEnumerationObserver.swift; sourceTree = ""; }; 5318AD9829BF58D000CBB71C /* NKError+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NKError+Extensions.swift"; sourceTree = ""; }; + 5350E4E02B0C459600F276CB /* ClientCommunicationService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ClientCommunicationService.h; sourceTree = ""; }; + 5350E4E12B0C459600F276CB /* ClientCommunicationService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ClientCommunicationService.m; sourceTree = ""; }; 5352B36529DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudFilesDatabaseManager+Directories.swift"; sourceTree = ""; }; 5352B36729DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudFilesDatabaseManager+LocalFiles.swift"; sourceTree = ""; }; 5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+Thumbnailing.swift"; sourceTree = ""; }; @@ -238,6 +241,15 @@ path = Database; sourceTree = ""; }; + 5350E4C72B0C368B00F276CB /* Services */ = { + isa = PBXGroup; + children = ( + 5350E4E02B0C459600F276CB /* ClientCommunicationService.h */, + 5350E4E12B0C459600F276CB /* ClientCommunicationService.m */, + ); + path = Services; + sourceTree = ""; + }; 5352E85929B7BFB4002CE85C /* Extensions */ = { isa = PBXGroup; children = ( @@ -259,6 +271,7 @@ 538E396B27F4765000FA63D5 /* FileProviderExt */ = { isa = PBXGroup; children = ( + 5350E4C72B0C368B00F276CB /* Services */, 5318AD8F29BF406500CBB71C /* Database */, 5352E85929B7BFB4002CE85C /* Extensions */, 538E397027F4765000FA63D5 /* FileProviderEnumerator.swift */, @@ -584,6 +597,7 @@ 53ED472029C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift in Sources */, 5318AD9929BF58D000CBB71C /* NKError+Extensions.swift in Sources */, 53ED472829C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift in Sources */, + 5350E4E22B0C459600F276CB /* ClientCommunicationService.m in Sources */, 5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */, 535AE30E29C0A2CC0042A9BA /* Logger+Extensions.swift in Sources */, 5307A6F229675346001E0C6A /* NextcloudFilesDatabaseManager.swift in Sources */, From a2d69fcf7c7409e4352d0db8a03dd708ba544ac6 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 21 Nov 2023 10:40:54 +0800 Subject: [PATCH 02/52] Keep pointer to FileProviderExtension around in ClientCommunicationService Signed-off-by: Claudio Cambra --- .../FileProviderExtension+ClientInterface.swift | 4 ++-- .../FileProviderExt/FileProviderExtension.swift | 2 +- .../FileProviderExt/Services/ClientCommunicationService.h | 5 +++++ .../FileProviderExt/Services/ClientCommunicationService.m | 5 ++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift index 26c42aca87be0..aae7c7ee66ebb 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift @@ -19,7 +19,7 @@ import NextcloudKit import OSLog extension FileProviderExtension { - func sendFileProviderDomainIdentifier() { + @objc func sendFileProviderDomainIdentifier() { let command = "FILE_PROVIDER_DOMAIN_IDENTIFIER_REQUEST_REPLY" let argument = domain.identifier.rawValue let message = command + ":" + argument + "\n" @@ -75,7 +75,7 @@ extension FileProviderExtension { signalEnumeratorAfterAccountSetup() } - func removeAccountConfig() { + @objc func removeAccountConfig() { Logger.fileProviderExtension.info( "Received instruction to remove account data for user \(self.ncAccount!.username, privacy: .public) at server \(self.ncAccount!.serverUrl, privacy: .public)" ) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift index 2f6039a71d816..3bf1613420da5 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift @@ -17,7 +17,7 @@ import NCDesktopClientSocketKit import NextcloudKit import OSLog -class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKCommonDelegate { +@objc class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKCommonDelegate { let domain: NSFileProviderDomain let ncKit = NextcloudKit() let appGroupIdentifier = Bundle.main.object(forInfoDictionaryKey: "SocketApiPrefix") as? String diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h index 7d0e065c18ae4..3e7947388d866 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h @@ -17,9 +17,14 @@ NS_ASSUME_NONNULL_BEGIN +@class FileProviderExtension; + @interface ClientCommunicationService : NSObject @property (readonly) NSXPCListener *listener; +@property (readonly) FileProviderExtension *extension; + +- (instancetype)initWithFileProviderExtension:(FileProviderExtension *)extension; @end diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m index f2790399abb0b..9c1329983b90b 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m @@ -14,16 +14,19 @@ #import "ClientCommunicationService.h" +#import "FileProviderExt-Swift.h" + @implementation ClientCommunicationService @synthesize serviceName = _serviceName; -- (instancetype)init +- (instancetype)initWithFileProviderExtension:(FileProviderExtension *)extension { self = [super init]; if (self) { _serviceName = @"com.nextcloud.desktopclient.ClientCommunicationService"; _listener = NSXPCListener.anonymousListener; + _extension = extension; } return self; } From e763a9d29b1d6740857423037c55f90601c92886 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 21 Nov 2023 15:56:34 +0800 Subject: [PATCH 03/52] Add ClientCommunicationProtocol Signed-off-by: Claudio Cambra --- .../Services/ClientCommunicationProtocol.h | 27 +++++++++++++++++++ .../project.pbxproj | 2 ++ 2 files changed, 29 insertions(+) create mode 100644 shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h new file mode 100644 index 0000000000000..0d8c8b3f40138 --- /dev/null +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * 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. + */ + +#ifndef ClientCommunicationProtocol_h +#define ClientCommunicationProtocol_h + +@protocol ClientCommunicationProtocol + +- (void)configureAccountWithUser:(NSString *)user + serverUrl:(NSString *)serverUrl + password:(NSString *)password; +- (void)removeAccountConfig; + +@end + +#endif /* ClientCommunicationProtocol_h */ diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj index 0e023751c2733..b61fe06055d90 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj +++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj @@ -148,6 +148,7 @@ 5318AD9829BF58D000CBB71C /* NKError+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NKError+Extensions.swift"; sourceTree = ""; }; 5350E4E02B0C459600F276CB /* ClientCommunicationService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ClientCommunicationService.h; sourceTree = ""; }; 5350E4E12B0C459600F276CB /* ClientCommunicationService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ClientCommunicationService.m; sourceTree = ""; }; + 5350E4E72B0C514400F276CB /* ClientCommunicationProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ClientCommunicationProtocol.h; sourceTree = ""; }; 5352B36529DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudFilesDatabaseManager+Directories.swift"; sourceTree = ""; }; 5352B36729DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudFilesDatabaseManager+LocalFiles.swift"; sourceTree = ""; }; 5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+Thumbnailing.swift"; sourceTree = ""; }; @@ -246,6 +247,7 @@ children = ( 5350E4E02B0C459600F276CB /* ClientCommunicationService.h */, 5350E4E12B0C459600F276CB /* ClientCommunicationService.m */, + 5350E4E72B0C514400F276CB /* ClientCommunicationProtocol.h */, ); path = Services; sourceTree = ""; From dd39991f1c99188ff09d7686d5daec1f06204432 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 21 Nov 2023 15:57:04 +0800 Subject: [PATCH 04/52] Implement ClientCommunicationProtocol in ClientCommunicationService Signed-off-by: Claudio Cambra --- ...ileProviderExtension+ClientInterface.swift | 2 +- .../Services/ClientCommunicationService.h | 4 ++-- .../Services/ClientCommunicationService.m | 21 +++++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift index aae7c7ee66ebb..fe5c21ccae32b 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift @@ -57,7 +57,7 @@ extension FileProviderExtension { } } - func setupDomainAccount(user: String, serverUrl: String, password: String) { + @objc func setupDomainAccount(user: String, serverUrl: String, password: String) { ncAccount = NextcloudAccount(user: user, serverUrl: serverUrl, password: password) ncKit.setup( user: ncAccount!.username, diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h index 3e7947388d866..cda0d8b73c9dc 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h @@ -12,14 +12,14 @@ * for more details. */ - #import NS_ASSUME_NONNULL_BEGIN @class FileProviderExtension; +@protocol ClientCommunicationProtocol; -@interface ClientCommunicationService : NSObject +@interface ClientCommunicationService : NSObject @property (readonly) NSXPCListener *listener; @property (readonly) FileProviderExtension *extension; diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m index 9c1329983b90b..bff3d142d204c 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m @@ -14,6 +14,7 @@ #import "ClientCommunicationService.h" +#import "ClientCommunicationProtocol.h" #import "FileProviderExt-Swift.h" @implementation ClientCommunicationService @@ -36,4 +37,24 @@ - (nullable NSXPCListenerEndpoint *)makeListenerEndpointAndReturnError:(NSError return self.listener.endpoint; } +- (BOOL)listener:(NSXPCListener *)listener +shouldAcceptNewConnection:(NSXPCConnection *)newConnection +{ + return YES; +} + +- (void)configureAccountWithUser:(NSString *)user + serverUrl:(NSString *)serverUrl + password:(NSString *)password +{ + [self.extension setupDomainAccountWithUser:user + serverUrl:serverUrl + password:password]; +} + +- (void)removeAccountConfig +{ + [self.extension removeAccountConfig]; +} + @end From 026f08225308044057a83bf3b91fce90bb5dee10 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 21 Nov 2023 16:29:25 +0800 Subject: [PATCH 05/52] Reimplement ClientCommunicationService in Swift Signed-off-by: Claudio Cambra --- ...ce.h => FileProviderExt-Bridging-Header.h} | 19 ++---- .../Services/ClientCommunicationProtocol.h | 2 + .../Services/ClientCommunicationService.m | 60 ------------------- .../Services/ClientCommunicationService.swift | 49 +++++++++++++++ .../project.pbxproj | 16 ++--- 5 files changed, 64 insertions(+), 82 deletions(-) rename shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/{Services/ClientCommunicationService.h => FileProviderExt-Bridging-Header.h} (56%) delete mode 100644 shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m create mode 100644 shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExt-Bridging-Header.h similarity index 56% rename from shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h rename to shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExt-Bridging-Header.h index cda0d8b73c9dc..4bbab0d379bcd 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.h +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExt-Bridging-Header.h @@ -12,20 +12,9 @@ * for more details. */ -#import +#ifndef FileProviderExt_Bridging_Header_h +#define FileProviderExt_Bridging_Header_h -NS_ASSUME_NONNULL_BEGIN +#import "Services/ClientCommunicationProtocol.h" -@class FileProviderExtension; -@protocol ClientCommunicationProtocol; - -@interface ClientCommunicationService : NSObject - -@property (readonly) NSXPCListener *listener; -@property (readonly) FileProviderExtension *extension; - -- (instancetype)initWithFileProviderExtension:(FileProviderExtension *)extension; - -@end - -NS_ASSUME_NONNULL_END +#endif /* FileProviderExt_Bridging_Header_h */ diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h index 0d8c8b3f40138..584b2dfa67504 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h @@ -15,6 +15,8 @@ #ifndef ClientCommunicationProtocol_h #define ClientCommunicationProtocol_h +#import + @protocol ClientCommunicationProtocol - (void)configureAccountWithUser:(NSString *)user diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m deleted file mode 100644 index bff3d142d204c..0000000000000 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.m +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2023 by Claudio Cambra - * - * 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. - */ - -#import "ClientCommunicationService.h" - -#import "ClientCommunicationProtocol.h" -#import "FileProviderExt-Swift.h" - -@implementation ClientCommunicationService - -@synthesize serviceName = _serviceName; - -- (instancetype)initWithFileProviderExtension:(FileProviderExtension *)extension -{ - self = [super init]; - if (self) { - _serviceName = @"com.nextcloud.desktopclient.ClientCommunicationService"; - _listener = NSXPCListener.anonymousListener; - _extension = extension; - } - return self; -} - -- (nullable NSXPCListenerEndpoint *)makeListenerEndpointAndReturnError:(NSError * *)error -{ - return self.listener.endpoint; -} - -- (BOOL)listener:(NSXPCListener *)listener -shouldAcceptNewConnection:(NSXPCConnection *)newConnection -{ - return YES; -} - -- (void)configureAccountWithUser:(NSString *)user - serverUrl:(NSString *)serverUrl - password:(NSString *)password -{ - [self.extension setupDomainAccountWithUser:user - serverUrl:serverUrl - password:password]; -} - -- (void)removeAccountConfig -{ - [self.extension removeAccountConfig]; -} - -@end diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift new file mode 100644 index 0000000000000..631d8360d4ab6 --- /dev/null +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * 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. + */ + +import Foundation +import FileProvider + +class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCListenerDelegate, ClientCommunicationProtocol { + let listener = NSXPCListener.anonymous() + let serviceName = NSFileProviderServiceName("com.nextcloud.desktopclient.ClientCommunicationService") + let fpExtension: FileProviderExtension + + init(fpExtension: FileProviderExtension) { + self.fpExtension = fpExtension + super.init() + } + + func makeListenerEndpoint() throws -> NSXPCListenerEndpoint { + return listener.endpoint + } + + func listener(_ listener: NSXPCListener, + shouldAcceptNewConnection newConnection: NSXPCConnection) + -> Bool { + return true + } + + func configureAccount(withUser user: String, + serverUrl: String, + password: String) { + self.fpExtension.setupDomainAccount(user: user, + serverUrl: serverUrl, + password: password) + } + + func removeAccountConfig() { + self.fpExtension.removeAccountConfig() + } +} diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj index b61fe06055d90..e93e157378600 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj +++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -15,7 +15,7 @@ 5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */; }; 5318AD9729BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */; }; 5318AD9929BF58D000CBB71C /* NKError+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9829BF58D000CBB71C /* NKError+Extensions.swift */; }; - 5350E4E22B0C459600F276CB /* ClientCommunicationService.m in Sources */ = {isa = PBXBuildFile; fileRef = 5350E4E12B0C459600F276CB /* ClientCommunicationService.m */; }; + 5350E4E92B0C534A00F276CB /* ClientCommunicationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5350E4E82B0C534A00F276CB /* ClientCommunicationService.swift */; }; 5352B36629DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36529DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift */; }; 5352B36829DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36729DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift */; }; 5352B36C29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */; }; @@ -146,9 +146,9 @@ 5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudLocalFileMetadataTable.swift; sourceTree = ""; }; 5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderMaterialisedEnumerationObserver.swift; sourceTree = ""; }; 5318AD9829BF58D000CBB71C /* NKError+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NKError+Extensions.swift"; sourceTree = ""; }; - 5350E4E02B0C459600F276CB /* ClientCommunicationService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ClientCommunicationService.h; sourceTree = ""; }; - 5350E4E12B0C459600F276CB /* ClientCommunicationService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ClientCommunicationService.m; sourceTree = ""; }; 5350E4E72B0C514400F276CB /* ClientCommunicationProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ClientCommunicationProtocol.h; sourceTree = ""; }; + 5350E4E82B0C534A00F276CB /* ClientCommunicationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientCommunicationService.swift; sourceTree = ""; }; + 5350E4EA2B0C9CE100F276CB /* FileProviderExt-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FileProviderExt-Bridging-Header.h"; sourceTree = ""; }; 5352B36529DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudFilesDatabaseManager+Directories.swift"; sourceTree = ""; }; 5352B36729DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudFilesDatabaseManager+LocalFiles.swift"; sourceTree = ""; }; 5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+Thumbnailing.swift"; sourceTree = ""; }; @@ -245,9 +245,8 @@ 5350E4C72B0C368B00F276CB /* Services */ = { isa = PBXGroup; children = ( - 5350E4E02B0C459600F276CB /* ClientCommunicationService.h */, - 5350E4E12B0C459600F276CB /* ClientCommunicationService.m */, 5350E4E72B0C514400F276CB /* ClientCommunicationProtocol.h */, + 5350E4E82B0C534A00F276CB /* ClientCommunicationService.swift */, ); path = Services; sourceTree = ""; @@ -288,6 +287,7 @@ 536EFC35295E3C1100F4CB13 /* NextcloudAccount.swift */, 538E397327F4765000FA63D5 /* FileProviderExt.entitlements */, 538E397227F4765000FA63D5 /* Info.plist */, + 5350E4EA2B0C9CE100F276CB /* FileProviderExt-Bridging-Header.h */, ); path = FileProviderExt; sourceTree = ""; @@ -599,7 +599,6 @@ 53ED472029C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift in Sources */, 5318AD9929BF58D000CBB71C /* NKError+Extensions.swift in Sources */, 53ED472829C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift in Sources */, - 5350E4E22B0C459600F276CB /* ClientCommunicationService.m in Sources */, 5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */, 535AE30E29C0A2CC0042A9BA /* Logger+Extensions.swift in Sources */, 5307A6F229675346001E0C6A /* NextcloudFilesDatabaseManager.swift in Sources */, @@ -607,6 +606,7 @@ 538E396F27F4765000FA63D5 /* FileProviderItem.swift in Sources */, 5352B36829DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift in Sources */, 5318AD9129BF42FB00CBB71C /* NextcloudItemMetadataTable.swift in Sources */, + 5350E4E92B0C534A00F276CB /* ClientCommunicationService.swift in Sources */, 5352B36629DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift in Sources */, 5318AD9729BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift in Sources */, 5352B36C29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift in Sources */, @@ -721,6 +721,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "FileProviderExt/FileProviderExt-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; @@ -771,6 +772,7 @@ SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "FileProviderExt/FileProviderExt-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; }; From ac43369bedd8928f171c8bc0c447297ecb7faf98 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 21 Nov 2023 17:03:45 +0800 Subject: [PATCH 06/52] Properly implement listener should accept connection in ClientCommunicationService Signed-off-by: Claudio Cambra --- .../Services/ClientCommunicationService.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift index 631d8360d4ab6..07372cd691b5a 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift @@ -32,6 +32,11 @@ class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCLi func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool { + let clientCommProtocol = ClientCommunicationProtocol.self + let clientCommInterface = NSXPCInterface(with: clientCommProtocol) + newConnection.exportedInterface = clientCommInterface + newConnection.exportedObject = self + newConnection.resume() return true } From 5cc8b6e7c2a3c376786b736403ce6758b15f335e Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 21 Nov 2023 17:38:01 +0800 Subject: [PATCH 07/52] Add starter FileProviderXPC class on client side Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 4 +++- src/gui/macOS/fileproviderxpc.h | 33 +++++++++++++++++++++++++++ src/gui/macOS/fileproviderxpc_mac.mm | 34 ++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/gui/macOS/fileproviderxpc.h create mode 100644 src/gui/macOS/fileproviderxpc_mac.mm diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 1968683e23415..fe40d9ee413ca 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -294,7 +294,9 @@ IF( APPLE ) macOS/fileprovidersocketcontroller.cpp macOS/fileprovidersocketserver.h macOS/fileprovidersocketserver.cpp - macOS/fileprovidersocketserver_mac.mm) + macOS/fileprovidersocketserver_mac.mm + macOS/fileproviderxpc.h + macOS/fileproviderxpc_mac.mm) endif() if(SPARKLE_FOUND AND BUILD_UPDATER) diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h new file mode 100644 index 0000000000000..9b166e9d83c84 --- /dev/null +++ b/src/gui/macOS/fileproviderxpc.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * 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. + */ + +#pragma once + +#include + +namespace OCC { + +namespace Mac { + +class FileProviderXPC : public QObject +{ + Q_OBJECT + +public: + explicit FileProviderXPC(QObject *parent = nullptr); +}; + +} + +} diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm new file mode 100644 index 0000000000000..c8101b6a1f03e --- /dev/null +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022 by Claudio Cambra + * + * 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. + */ + +#pragma once + +#include "fileproviderxpc.h" + +#include + +namespace OCC { + +namespace Mac { + +Q_LOGGING_CATEGORY(lcFileProviderXPC, "nextcloud.gui.macos.fileprovider.xpc", QtInfoMsg) + +FileProviderXPC::FileProviderXPC(QObject *parent) + : QObject{parent} +{ +} + +} // namespace OCC + +} // namespace Mac From e8c1bbb953c9f5fe5fd14f3c48f997fd919e3ff0 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 22 Nov 2023 19:42:05 +0800 Subject: [PATCH 08/52] Add relative symlink to ClientCommunicationProtocol in srd/gui/macOS Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 3 +++ src/gui/macOS/ClientCommunicationProtocol.h | 1 + 2 files changed, 4 insertions(+) create mode 120000 src/gui/macOS/ClientCommunicationProtocol.h diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index fe40d9ee413ca..bf13b5318d379 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -286,6 +286,9 @@ IF( APPLE ) if (BUILD_FILE_PROVIDER_MODULE) list(APPEND client_SRCS + # Symlinks to files in shell_integration/MacOSX/NextcloudIntegration/ + macOS/ClientCommunicationProtocol.h + # End of symlink files macOS/fileprovider.h macOS/fileprovider_mac.mm macOS/fileproviderdomainmanager.h diff --git a/src/gui/macOS/ClientCommunicationProtocol.h b/src/gui/macOS/ClientCommunicationProtocol.h new file mode 120000 index 0000000000000..bc406ebc7f8bf --- /dev/null +++ b/src/gui/macOS/ClientCommunicationProtocol.h @@ -0,0 +1 @@ +../../../shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h \ No newline at end of file From 9dddaf4f9fe4efaf618f256b58760c79e2910c2c Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 22 Nov 2023 19:42:40 +0800 Subject: [PATCH 09/52] Fix logging for fileproviderdomainmanager Signed-off-by: Claudio Cambra --- .../macOS/fileproviderdomainmanager_mac.mm | 130 ++++++++++-------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm index 29b3ee244c27b..f81534c00db76 100644 --- a/src/gui/macOS/fileproviderdomainmanager_mac.mm +++ b/src/gui/macOS/fileproviderdomainmanager_mac.mm @@ -96,16 +96,16 @@ void findExistingFileProviderDomains() dispatch_group_enter(dispatchGroup); [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray * const domains, NSError * const error) { - if(error) { - qCDebug(lcMacFileProviderDomainManager) << "Could not get existing file provider domains: " - << error.code - << error.localizedDescription; + if (error) { + qCWarning(lcMacFileProviderDomainManager) << "Could not get existing file provider domains: " + << error.code + << error.localizedDescription; dispatch_group_leave(dispatchGroup); return; } if (domains.count == 0) { - qCDebug(lcMacFileProviderDomainManager) << "Found no existing file provider domains"; + qCInfo(lcMacFileProviderDomainManager) << "Found no existing file provider domains"; dispatch_group_leave(dispatchGroup); return; } @@ -118,33 +118,33 @@ void findExistingFileProviderDomains() accountState->account() && domainDisplayNameForAccount(accountState->account()) == QString::fromNSString(domain.displayName)) { - qCDebug(lcMacFileProviderDomainManager) << "Found existing file provider domain for account:" - << accountState->account()->displayName(); + qCInfo(lcMacFileProviderDomainManager) << "Found existing file provider domain for account:" + << accountState->account()->displayName(); [domain retain]; _registeredDomains.insert(accountId, domain); NSFileProviderManager * const fpManager = [NSFileProviderManager managerForDomain:domain]; [fpManager reconnectWithCompletionHandler:^(NSError * const error) { if (error) { - qCDebug(lcMacFileProviderDomainManager) << "Error reconnecting file provider domain: " - << domain.displayName - << error.code - << error.localizedDescription; + qCWarning(lcMacFileProviderDomainManager) << "Error reconnecting file provider domain: " + << domain.displayName + << error.code + << error.localizedDescription; return; } - qCDebug(lcMacFileProviderDomainManager) << "Successfully reconnected file provider domain: " + qCInfo(lcMacFileProviderDomainManager) << "Successfully reconnected file provider domain: " << domain.displayName; }]; } else { - qCDebug(lcMacFileProviderDomainManager) << "Found existing file provider domain with no known configured account:" - << domain.displayName; + qCInfo(lcMacFileProviderDomainManager) << "Found existing file provider domain with no known configured account:" + << domain.displayName; [NSFileProviderManager removeDomain:domain completionHandler:^(NSError * const error) { - if(error) { - qCDebug(lcMacFileProviderDomainManager) << "Error removing file provider domain: " - << error.code - << error.localizedDescription; + if (error) { + qCWarning(lcMacFileProviderDomainManager) << "Error removing file provider domain: " + << error.code + << error.localizedDescription; } }]; } @@ -167,10 +167,12 @@ void addFileProviderDomain(const AccountState * const accountState) const auto domainDisplayName = domainDisplayNameForAccount(account); const auto domainId = domainIdentifierForAccount(account); - qCDebug(lcMacFileProviderDomainManager) << "Adding new file provider domain with id: " << domainId; + qCInfo(lcMacFileProviderDomainManager) << "Adding new file provider domain with id: " + << domainId; - if(_registeredDomains.contains(domainId) && _registeredDomains.value(domainId) != nil) { - qCDebug(lcMacFileProviderDomainManager) << "File provider domain with id already exists: " << domainId; + if (_registeredDomains.contains(domainId) && _registeredDomains.value(domainId) != nil) { + qCDebug(lcMacFileProviderDomainManager) << "File provider domain with id already exists: " + << domainId; return; } @@ -180,9 +182,9 @@ void addFileProviderDomain(const AccountState * const accountState) [NSFileProviderManager addDomain:fileProviderDomain completionHandler:^(NSError * const error) { if(error) { - qCDebug(lcMacFileProviderDomainManager) << "Error adding file provider domain: " - << error.code - << error.localizedDescription; + qCWarning(lcMacFileProviderDomainManager) << "Error adding file provider domain: " + << error.code + << error.localizedDescription; } _registeredDomains.insert(domainId, fileProviderDomain); @@ -198,20 +200,22 @@ void removeFileProviderDomain(const AccountState * const accountState) Q_ASSERT(account); const auto domainId = domainIdentifierForAccount(account); - qCDebug(lcMacFileProviderDomainManager) << "Removing file provider domain with id: " << domainId; + qCInfo(lcMacFileProviderDomainManager) << "Removing file provider domain with id: " + << domainId; - if(!_registeredDomains.contains(domainId)) { - qCDebug(lcMacFileProviderDomainManager) << "File provider domain not found for id: " << domainId; + if (!_registeredDomains.contains(domainId)) { + qCWarning(lcMacFileProviderDomainManager) << "File provider domain not found for id: " + << domainId; return; } NSFileProviderDomain * const fileProviderDomain = _registeredDomains[domainId]; [NSFileProviderManager removeDomain:fileProviderDomain completionHandler:^(NSError *error) { - if(error) { - qCDebug(lcMacFileProviderDomainManager) << "Error removing file provider domain: " - << error.code - << error.localizedDescription; + if (error) { + qCWarning(lcMacFileProviderDomainManager) << "Error removing file provider domain: " + << error.code + << error.localizedDescription; } NSFileProviderDomain * const domain = _registeredDomains.take(domainId); @@ -247,13 +251,13 @@ void removeAllFileProviderDomains() void wipeAllFileProviderDomains() { if (@available(macOS 12.0, *)) { - qCDebug(lcMacFileProviderDomainManager) << "Removing and wiping all file provider domains"; + qCInfo(lcMacFileProviderDomainManager) << "Removing and wiping all file provider domains"; [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray * const domains, NSError * const error) { if (error) { - qCDebug(lcMacFileProviderDomainManager) << "Error removing and wiping file provider domains: " - << error.code - << error.localizedDescription; + qCWarning(lcMacFileProviderDomainManager) << "Error removing and wiping file provider domains: " + << error.code + << error.localizedDescription; return; } @@ -262,10 +266,10 @@ void wipeAllFileProviderDomains() Q_UNUSED(preservedLocation) if (error) { - qCDebug(lcMacFileProviderDomainManager) << "Error removing and wiping file provider domain: " - << domain.displayName - << error.code - << error.localizedDescription; + qCWarning(lcMacFileProviderDomainManager) << "Error removing and wiping file provider domain: " + << domain.displayName + << error.code + << error.localizedDescription; return; } @@ -277,7 +281,7 @@ void wipeAllFileProviderDomains() } }]; } else if (@available(macOS 11.0, *)) { - qCDebug(lcMacFileProviderDomainManager) << "Removing all file provider domains, can't specify wipe on macOS 11"; + qCInfo(lcMacFileProviderDomainManager) << "Removing all file provider domains, can't specify wipe on macOS 11"; removeAllFileProviderDomains(); } } @@ -290,10 +294,12 @@ void disconnectFileProviderDomainForAccount(const AccountState * const accountSt Q_ASSERT(account); const auto domainId = domainIdentifierForAccount(account); - qCDebug(lcMacFileProviderDomainManager) << "Disconnecting file provider domain with id: " << domainId; + qCInfo(lcMacFileProviderDomainManager) << "Disconnecting file provider domain with id: " + << domainId; if(!_registeredDomains.contains(domainId)) { - qCDebug(lcMacFileProviderDomainManager) << "File provider domain not found for id: " << domainId; + qCInfo(lcMacFileProviderDomainManager) << "File provider domain not found for id: " + << domainId; return; } @@ -305,15 +311,15 @@ void disconnectFileProviderDomainForAccount(const AccountState * const accountSt options:NSFileProviderManagerDisconnectionOptionsTemporary completionHandler:^(NSError * const error) { if (error) { - qCDebug(lcMacFileProviderDomainManager) << "Error disconnecting file provider domain: " - << fileProviderDomain.displayName - << error.code - << error.localizedDescription; + qCWarning(lcMacFileProviderDomainManager) << "Error disconnecting file provider domain: " + << fileProviderDomain.displayName + << error.code + << error.localizedDescription; return; } - qCDebug(lcMacFileProviderDomainManager) << "Successfully disconnected file provider domain: " - << fileProviderDomain.displayName; + qCInfo(lcMacFileProviderDomainManager) << "Successfully disconnected file provider domain: " + << fileProviderDomain.displayName; }]; } } @@ -326,10 +332,12 @@ void reconnectFileProviderDomainForAccount(const AccountState * const accountSta Q_ASSERT(account); const auto domainId = domainIdentifierForAccount(account); - qCDebug(lcMacFileProviderDomainManager) << "Reconnecting file provider domain with id: " << domainId; + qCInfo(lcMacFileProviderDomainManager) << "Reconnecting file provider domain with id: " + << domainId; if(!_registeredDomains.contains(domainId)) { - qCDebug(lcMacFileProviderDomainManager) << "File provider domain not found for id: " << domainId; + qCInfo(lcMacFileProviderDomainManager) << "File provider domain not found for id: " + << domainId; return; } @@ -339,15 +347,15 @@ void reconnectFileProviderDomainForAccount(const AccountState * const accountSta NSFileProviderManager * const fpManager = [NSFileProviderManager managerForDomain:fileProviderDomain]; [fpManager reconnectWithCompletionHandler:^(NSError * const error) { if (error) { - qCDebug(lcMacFileProviderDomainManager) << "Error reconnecting file provider domain: " - << fileProviderDomain.displayName - << error.code - << error.localizedDescription; + qCWarning(lcMacFileProviderDomainManager) << "Error reconnecting file provider domain: " + << fileProviderDomain.displayName + << error.code + << error.localizedDescription; return; } - qCDebug(lcMacFileProviderDomainManager) << "Successfully reconnected file provider domain: " - << fileProviderDomain.displayName; + qCInfo(lcMacFileProviderDomainManager) << "Successfully reconnected file provider domain: " + << fileProviderDomain.displayName; signalEnumeratorChanged(account.get()); }]; @@ -360,10 +368,12 @@ void signalEnumeratorChanged(const Account * const account) Q_ASSERT(account); const auto domainId = domainIdentifierForAccount(account); - qCDebug(lcMacFileProviderDomainManager) << "Signalling enumerator changed in file provider domain for account with id: " << domainId; + qCInfo(lcMacFileProviderDomainManager) << "Signalling enumerator changed in file provider domain for account with id: " + << domainId; if(!_registeredDomains.contains(domainId)) { - qCDebug(lcMacFileProviderDomainManager) << "File provider domain not found for id: " << domainId; + qCInfo(lcMacFileProviderDomainManager) << "File provider domain not found for id: " + << domainId; return; } @@ -373,8 +383,8 @@ void signalEnumeratorChanged(const Account * const account) NSFileProviderManager * const fpManager = [NSFileProviderManager managerForDomain:fileProviderDomain]; [fpManager signalEnumeratorForContainerItemIdentifier:NSFileProviderWorkingSetContainerItemIdentifier completionHandler:^(NSError * const error) { if (error != nil) { - qCDebug(lcMacFileProviderDomainManager) << "Error signalling enumerator changed for working set:" - << error.localizedDescription; + qCWarning(lcMacFileProviderDomainManager) << "Error signalling enumerator changed for working set:" + << error.localizedDescription; } }]; } From 25201116a01c7651ef7c36a3d88a33be11b1e028 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 22 Nov 2023 19:45:48 +0800 Subject: [PATCH 10/52] Implement connection begin in XPC Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovider.h | 2 + src/gui/macOS/fileprovider_mac.mm | 8 +++ src/gui/macOS/fileproviderxpc.h | 3 ++ src/gui/macOS/fileproviderxpc_mac.mm | 81 +++++++++++++++++++++++++++- 4 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileprovider.h b/src/gui/macOS/fileprovider.h index d45ba987d2a5b..a6a2466709af3 100644 --- a/src/gui/macOS/fileprovider.h +++ b/src/gui/macOS/fileprovider.h @@ -18,6 +18,7 @@ #include "fileproviderdomainmanager.h" #include "fileprovidersocketserver.h" +#include "fileproviderxpc.h" namespace OCC { @@ -41,6 +42,7 @@ class FileProvider : public QObject private: std::unique_ptr _domainManager; std::unique_ptr _socketServer; + std::unique_ptr _xpc; static FileProvider *_instance; explicit FileProvider(QObject * const parent = nullptr); diff --git a/src/gui/macOS/fileprovider_mac.mm b/src/gui/macOS/fileprovider_mac.mm index 56db4d2447b07..00cd3aa1258b8 100644 --- a/src/gui/macOS/fileprovider_mac.mm +++ b/src/gui/macOS/fileprovider_mac.mm @@ -56,6 +56,14 @@ if (_socketServer) { qCDebug(lcMacFileProvider) << "Initialised file provider socket server."; } + + _xpc = std::make_unique(new FileProviderXPC(this)); + if (_xpc) { + qCInfo(lcMacFileProvider) << "Initialised file provider XPC."; + _xpc->start(); + } else { + qCWarning(lcMacFileProvider) << "Could not initialise file provider XPC."; + } } FileProvider *FileProvider::instance() diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index 9b166e9d83c84..759a4a0593c83 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -26,6 +26,9 @@ class FileProviderXPC : public QObject public: explicit FileProviderXPC(QObject *parent = nullptr); + +public slots: + void start(); }; } diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index c8101b6a1f03e..ada31ad0d2605 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -12,12 +12,19 @@ * for more details. */ -#pragma once - #include "fileproviderxpc.h" #include +#import + +#import "ClientCommunicationProtocol.h" + +namespace { + static const auto clientCommunicationServiceName = "com.nextcloud.desktopclient.ClientCommunicationService"; + static NSString *const nsClientCommunicationServiceName = [NSString stringWithUTF8String:clientCommunicationServiceName]; +} + namespace OCC { namespace Mac { @@ -29,6 +36,76 @@ { } +void FileProviderXPC::start() +{ + qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; + // Set up connections for each domain + [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray *const domains, NSError *const error){ + if (error != nil) { + qCWarning(lcFileProviderXPC) << "Error getting domains" << error; + return; + } + + for (NSFileProviderDomain *const domain in domains) { + qCDebug(lcFileProviderXPC) << "Got domain" << domain.identifier; + + NSFileProviderManager *const manager = [NSFileProviderManager managerForDomain:domain]; + + [manager getUserVisibleURLForItemIdentifier:NSFileProviderRootContainerItemIdentifier + completionHandler:^(NSURL *const url, NSError *const error){ + if (error != nil) { + qCWarning(lcFileProviderXPC) << "Error getting user visible url" << error; + return; + } + + qCDebug(lcFileProviderXPC) << "Got user visible url" << url; + [NSFileManager.defaultManager getFileProviderServicesForItemAtURL:url + completionHandler:^(NSDictionary *const services, NSError *const error){ + if (error != nil) { + qCWarning(lcFileProviderXPC) << "Error getting file provider services" << error; + return; + } + + NSArray *const serviceNamesArray = services.allKeys; + for (NSFileProviderServiceName serviceName in serviceNamesArray) { + qCDebug(lcFileProviderXPC) << "Got service" << serviceName; + + if (![serviceName isEqualToString:nsClientCommunicationServiceName]) { + continue; + } + + NSFileProviderService *const service = services[serviceName]; + [service getFileProviderConnectionWithCompletionHandler:^(NSXPCConnection *const connection, NSError *const error){ + if (error != nil) { + qCWarning(lcFileProviderXPC) << "Error getting file provider connection" << error; + return; + } + + qCDebug(lcFileProviderXPC) << "Got file provider connection" << connection; + + if (connection == nil) { + qCWarning(lcFileProviderXPC) << "Connection is nil"; + return; + } + + connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ClientCommunicationProtocol)]; + [connection resume]; + const id clientCommService = (id)[connection remoteObjectProxyWithErrorHandler:^(NSError *const error){ + qCWarning(lcFileProviderXPC) << "Error getting remote object proxy" << error; + }]; + + if (clientCommService == nil) { + qCWarning(lcFileProviderXPC) << "Client communication service is nil"; + return; + } + }]; + } + }]; + }]; + } + }]; +} + } // namespace OCC } // namespace Mac From 0b505a9c2c4c0290bda850c1514ad88368c7222a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 22 Nov 2023 20:11:56 +0800 Subject: [PATCH 11/52] Flatten FileProviderXPC::start() Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 159 ++++++++++++++++++--------- 1 file changed, 110 insertions(+), 49 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index ada31ad0d2605..7b120b03e57a9 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -39,71 +39,132 @@ void FileProviderXPC::start() { qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; + + dispatch_group_t group = dispatch_group_create(); + __block NSArray *fpDomains = nil; + + dispatch_group_enter(group); + // Set up connections for each domain [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray *const domains, NSError *const error){ if (error != nil) { qCWarning(lcFileProviderXPC) << "Error getting domains" << error; + dispatch_group_leave(group); return; } - for (NSFileProviderDomain *const domain in domains) { - qCDebug(lcFileProviderXPC) << "Got domain" << domain.identifier; + fpDomains = domains; + dispatch_group_leave(group); + }]; + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + if (fpDomains == nil || fpDomains.count == 0) { + qCWarning(lcFileProviderXPC) << "No domains found"; + return; + } + + __block NSMutableArray *urls = NSMutableArray.array; + + for (NSFileProviderDomain *const domain in fpDomains) { + qCDebug(lcFileProviderXPC) << "Got domain" << domain.identifier; + dispatch_group_enter(group); + + NSFileProviderManager *const manager = [NSFileProviderManager managerForDomain:domain]; + + [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 *> *const fpServices = NSMutableArray.array; + + for (NSURL *const url in urls) { + dispatch_group_enter(group); + + [NSFileManager.defaultManager getFileProviderServicesForItemAtURL:url + completionHandler:^(NSDictionary *const services, NSError *const error){ + if (error != nil) { + qCWarning(lcFileProviderXPC) << "Error getting file provider services" << error; + dispatch_group_leave(group); + return; + } - NSFileProviderManager *const manager = [NSFileProviderManager managerForDomain:domain]; + [fpServices addObject:services]; + dispatch_group_leave(group); + }]; + } - [manager getUserVisibleURLForItemIdentifier:NSFileProviderRootContainerItemIdentifier - completionHandler:^(NSURL *const url, NSError *const error){ + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + if (fpServices.count == 0) { + qCWarning(lcFileProviderXPC) << "No file provider services found"; + return; + } + + for (NSDictionary *const services in fpServices) { + NSArray *const serviceNamesArray = services.allKeys; + + for (NSFileProviderServiceName serviceName in serviceNamesArray) { + qCDebug(lcFileProviderXPC) << "Got service" << serviceName; + + if (![serviceName isEqualToString:nsClientCommunicationServiceName]) { + continue; + } + + NSFileProviderService *const service = services[serviceName]; + dispatch_group_enter(group); + + [service getFileProviderConnectionWithCompletionHandler:^(NSXPCConnection *const connection, NSError *const error){ if (error != nil) { - qCWarning(lcFileProviderXPC) << "Error getting user visible url" << error; + qCWarning(lcFileProviderXPC) << "Error getting file provider connection" << error; + dispatch_group_leave(group); + return; + } + + qCDebug(lcFileProviderXPC) << "Got file provider connection" << connection; + + if (connection == nil) { + qCWarning(lcFileProviderXPC) << "Connection is nil"; + dispatch_group_leave(group); return; } - qCDebug(lcFileProviderXPC) << "Got user visible url" << url; - [NSFileManager.defaultManager getFileProviderServicesForItemAtURL:url - completionHandler:^(NSDictionary *const services, NSError *const error){ - if (error != nil) { - qCWarning(lcFileProviderXPC) << "Error getting file provider services" << error; - return; - } - - NSArray *const serviceNamesArray = services.allKeys; - for (NSFileProviderServiceName serviceName in serviceNamesArray) { - qCDebug(lcFileProviderXPC) << "Got service" << serviceName; - - if (![serviceName isEqualToString:nsClientCommunicationServiceName]) { - continue; - } - - NSFileProviderService *const service = services[serviceName]; - [service getFileProviderConnectionWithCompletionHandler:^(NSXPCConnection *const connection, NSError *const error){ - if (error != nil) { - qCWarning(lcFileProviderXPC) << "Error getting file provider connection" << error; - return; - } - - qCDebug(lcFileProviderXPC) << "Got file provider connection" << connection; - - if (connection == nil) { - qCWarning(lcFileProviderXPC) << "Connection is nil"; - return; - } - - connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ClientCommunicationProtocol)]; - [connection resume]; - const id clientCommService = (id)[connection remoteObjectProxyWithErrorHandler:^(NSError *const error){ - qCWarning(lcFileProviderXPC) << "Error getting remote object proxy" << error; - }]; - - if (clientCommService == nil) { - qCWarning(lcFileProviderXPC) << "Client communication service is nil"; - return; - } - }]; - } + connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ClientCommunicationProtocol)]; + [connection resume]; + const id clientCommService = (id)[connection remoteObjectProxyWithErrorHandler:^(NSError *const error){ + qCWarning(lcFileProviderXPC) << "Error getting remote object proxy" << error; + dispatch_group_leave(group); }]; + + if (clientCommService == nil) { + qCWarning(lcFileProviderXPC) << "Client communication service is nil"; + dispatch_group_leave(group); + return; + } + + dispatch_group_leave(group); }]; } - }]; + } + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); } } // namespace OCC From d4d0cf550e11dc4a6f25e64b1e686db82f44f0f9 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 23 Nov 2023 01:25:03 +0800 Subject: [PATCH 12/52] Fix retain issues with domains in FileProviderXPC Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 7b120b03e57a9..e4833e8ae13cc 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -41,7 +41,7 @@ qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; dispatch_group_t group = dispatch_group_create(); - __block NSArray *fpDomains = nil; + __block NSMutableArray *managers = NSMutableArray.array; dispatch_group_enter(group); @@ -53,24 +53,27 @@ return; } - fpDomains = domains; + for (NSFileProviderDomain *const domain in domains) { + qCInfo(lcFileProviderXPC) << "Got domain" << domain.identifier; + NSFileProviderManager *const manager = [NSFileProviderManager managerForDomain:domain]; + [managers addObject:manager]; + } + dispatch_group_leave(group); }]; dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - if (fpDomains == nil || fpDomains.count == 0) { + if (managers.count == 0) { qCWarning(lcFileProviderXPC) << "No domains found"; return; } __block NSMutableArray *urls = NSMutableArray.array; - for (NSFileProviderDomain *const domain in fpDomains) { - qCDebug(lcFileProviderXPC) << "Got domain" << domain.identifier; - dispatch_group_enter(group); + for (NSFileProviderManager *const manager in managers) { - NSFileProviderManager *const manager = [NSFileProviderManager managerForDomain:domain]; + dispatch_group_enter(group); [manager getUserVisibleURLForItemIdentifier:NSFileProviderRootContainerItemIdentifier completionHandler:^(NSURL *const url, NSError *const error){ @@ -106,6 +109,10 @@ return; } + qCInfo(lcFileProviderXPC) << "Got file provider services for" + << url.absoluteString + << "has number of services:" + << services.count; [fpServices addObject:services]; dispatch_group_leave(group); }]; @@ -122,7 +129,7 @@ NSArray *const serviceNamesArray = services.allKeys; for (NSFileProviderServiceName serviceName in serviceNamesArray) { - qCDebug(lcFileProviderXPC) << "Got service" << serviceName; + qCInfo(lcFileProviderXPC) << "Got service" << serviceName; if (![serviceName isEqualToString:nsClientCommunicationServiceName]) { continue; @@ -138,7 +145,7 @@ return; } - qCDebug(lcFileProviderXPC) << "Got file provider connection" << connection; + qCInfo(lcFileProviderXPC) << "Got file provider connection" << connection; if (connection == nil) { qCWarning(lcFileProviderXPC) << "Connection is nil"; From a6e3f181682c1099217c38472101ce0307d59fb9 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 23 Nov 2023 01:25:21 +0800 Subject: [PATCH 13/52] Ensure FileProvider components instantiated after account setup Signed-off-by: Claudio Cambra --- src/gui/application.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/application.cpp b/src/gui/application.cpp index c318868907887..ab80245bb24e6 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -349,10 +349,6 @@ Application::Application(int &argc, char **argv) connect(this, &SharedTools::QtSingleApplication::messageReceived, this, &Application::slotParseMessage); -#if defined(BUILD_FILE_PROVIDER_MODULE) - _fileProvider.reset(new Mac::FileProvider); -#endif - // create accounts and folders from a legacy desktop client or from the current config file setupAccountsAndFolders(); @@ -420,6 +416,10 @@ Application::Application(int &argc, char **argv) AccountSetupCommandLineManager::instance()->setupAccountFromCommandLine(); } AccountSetupCommandLineManager::destroy(); + +#if defined(BUILD_FILE_PROVIDER_MODULE) + _fileProvider.reset(new Mac::FileProvider); +#endif } Application::~Application() From 5f6f7f302afcefb30428e384a35ef8edb3375bd6 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 5 Dec 2023 16:05:25 +0800 Subject: [PATCH 14/52] Add extensionAccountId property to ClientCommunicationProtocol Signed-off-by: Claudio Cambra --- .../Services/ClientCommunicationProtocol.h | 1 + .../Services/ClientCommunicationService.swift | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h index 584b2dfa67504..766eab1f6778d 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h @@ -19,6 +19,7 @@ @protocol ClientCommunicationProtocol +- (void)getExtensionAccountIdWithCompletionHandler:(void(^)(NSString *extensionAccountId, NSError *error))completionHandler; - (void)configureAccountWithUser:(NSString *)user serverUrl:(NSString *)serverUrl password:(NSString *)password; diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift index 07372cd691b5a..2760e79064ae5 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift @@ -14,6 +14,7 @@ import Foundation import FileProvider +import OSLog class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCListenerDelegate, ClientCommunicationProtocol { let listener = NSXPCListener.anonymous() @@ -40,9 +41,18 @@ class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCLi return true } + //MARK: - Protocol methods + + func getExtensionAccountId(completionHandler: @escaping (String?, Error?) -> Void) { + let accountUserId = self.fpExtension.domain.identifier.rawValue + Logger.desktopClientConnection.info("Sending extension account ID \(accountUserId)") + completionHandler(accountUserId, nil) + } + func configureAccount(withUser user: String, serverUrl: String, password: String) { + Logger.desktopClientConnection.info("Received configure account information over client communication service") self.fpExtension.setupDomainAccount(user: user, serverUrl: serverUrl, password: password) From ee82968c697c9ccf8a47e39dd84843d1d52bf545 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 5 Dec 2023 22:39:05 +0800 Subject: [PATCH 15/52] Cache NSXPCConnections when starting FileProviderXPC Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 41 +++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index e4833e8ae13cc..09164772a642d 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -125,6 +125,8 @@ return; } + NSMutableArray *const connections = NSMutableArray.array; + for (NSDictionary *const services in fpServices) { NSArray *const serviceNamesArray = services.allKeys; @@ -153,25 +155,38 @@ return; } - connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ClientCommunicationProtocol)]; - [connection resume]; - const id clientCommService = (id)[connection remoteObjectProxyWithErrorHandler:^(NSError *const error){ - qCWarning(lcFileProviderXPC) << "Error getting remote object proxy" << error; - dispatch_group_leave(group); - }]; - - if (clientCommService == nil) { - qCWarning(lcFileProviderXPC) << "Client communication service is nil"; - dispatch_group_leave(group); - return; - } - + [connection retain]; + [connections addObject:connection]; dispatch_group_leave(group); }]; } } dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + 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; + }]; + + NSObject *const clientCommService = (NSObject *)remoteServiceObject; + if (clientCommService == nil) { + qCWarning(lcFileProviderXPC) << "Client communication service is nil"; + continue; + } + + [clientCommService retain]; + } } } // namespace OCC From 2d1e5ba1975876565edd75e89aee3db35544d5ee Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 11 Dec 2023 19:48:40 +0800 Subject: [PATCH 16/52] Ensure the listener is resumed once the endpoint is created in the extension Signed-off-by: Claudio Cambra --- .../Services/ClientCommunicationService.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift index 2760e79064ae5..1d846572a1150 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift @@ -22,26 +22,25 @@ class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCLi let fpExtension: FileProviderExtension init(fpExtension: FileProviderExtension) { + Logger.desktopClientConnection.debug("Instantiating client communication service") self.fpExtension = fpExtension super.init() } func makeListenerEndpoint() throws -> NSXPCListenerEndpoint { + listener.delegate = self + listener.resume() return listener.endpoint } - func listener(_ listener: NSXPCListener, - shouldAcceptNewConnection newConnection: NSXPCConnection) - -> Bool { - let clientCommProtocol = ClientCommunicationProtocol.self - let clientCommInterface = NSXPCInterface(with: clientCommProtocol) - newConnection.exportedInterface = clientCommInterface + func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool { + newConnection.exportedInterface = NSXPCInterface(with: ClientCommunicationProtocol.self) newConnection.exportedObject = self newConnection.resume() return true } - //MARK: - Protocol methods + //MARK: - Client Communication Protocol methods func getExtensionAccountId(completionHandler: @escaping (String?, Error?) -> Void) { let accountUserId = self.fpExtension.domain.identifier.rawValue From eb774adc95b37229f23b483a55a7789e8d375912 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 11 Dec 2023 20:37:29 +0800 Subject: [PATCH 17/52] Check for protocol type in fileproviderxpc start Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 09164772a642d..e62e13cb2e900 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -179,6 +179,11 @@ qCWarning(lcFileProviderXPC) << "Error getting remote object proxy" << error; }]; + if (![remoteServiceObject conformsToProtocol:@protocol(ClientCommunicationProtocol)]) { + qCWarning(lcFileProviderXPC) << "Remote service object does not conform to protocol"; + continue; + } + NSObject *const clientCommService = (NSObject *)remoteServiceObject; if (clientCommService == nil) { qCWarning(lcFileProviderXPC) << "Client communication service is nil"; From 6cb71694fdd4b9cd86f641228b019919e7d27ba9 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 13 Dec 2023 01:37:13 +0800 Subject: [PATCH 18/52] Log extension id sent over XPC publicly Signed-off-by: Claudio Cambra --- .../FileProviderExt/Services/ClientCommunicationService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift index 1d846572a1150..83d26ae3a84ce 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift @@ -44,7 +44,7 @@ class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCLi func getExtensionAccountId(completionHandler: @escaping (String?, Error?) -> Void) { let accountUserId = self.fpExtension.domain.identifier.rawValue - Logger.desktopClientConnection.info("Sending extension account ID \(accountUserId)") + Logger.desktopClientConnection.info("Sending extension account ID \(accountUserId, privacy: .public)") completionHandler(accountUserId, nil) } From 7716860bc99c597e1cea915aa02e900e602217c0 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 13 Dec 2023 01:38:33 +0800 Subject: [PATCH 19/52] Retrieve extension account ids over XPC, store client comm service per account Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index e62e13cb2e900..2961f81997f9c 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -164,6 +164,8 @@ dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + NSMutableDictionary*> *const clientCommServices = NSMutableDictionary.dictionary; + for (NSXPCConnection * const connection in connections) { Q_ASSERT(connection != nil); connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ClientCommunicationProtocol)]; @@ -191,6 +193,29 @@ } [clientCommService retain]; + __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]; + } } } From 59b8b8ef21cb5b1f7a8a6ba0ff0ab68e4efb4c65 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 27 Dec 2023 17:22:16 +0800 Subject: [PATCH 20/52] Upon acquisition of client communication services, send account configuration Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 2961f81997f9c..2a4f27766ba03 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -16,6 +16,8 @@ #include +#include "gui/accountmanager.h" + #import #import "ClientCommunicationProtocol.h" @@ -216,6 +218,32 @@ qCInfo(lcFileProviderXPC) << "Got extension account id" << extensionNcAccount.UTF8String; [clientCommServices setObject:clientCommService forKey:extensionNcAccount]; } + + for (NSString *const extensionNcAccount in clientCommServices) { + qCInfo(lcFileProviderXPC) << "Sending message to client communication service"; + + const auto qExtensionNcAccount = QString::fromNSString(extensionNcAccount); + const auto accountManager = AccountManager::instance(); + + Q_ASSERT(accountManager); + + const auto accountState = accountManager->accountFromUserId(qExtensionNcAccount); + if (!accountState) { + qCWarning(lcFileProviderXPC) << "Account state is null for received account" + << qExtensionNcAccount; + return; + } + + const auto account = accountState->account(); + const auto credentials = account->credentials(); + NSString *const user = credentials->user().toNSString(); + NSString *const serverUrl = account->url().toString().toNSString(); + NSString *const password = credentials->password().toNSString(); + + NSObject *const clientCommService = [clientCommServices objectForKey:extensionNcAccount]; + [clientCommService configureAccountWithUser:user + serverUrl:serverUrl + password:password]; } } From 8eaf4e6324397fe954c0cdc61b4fdc161719d1fe Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 27 Dec 2023 18:27:18 +0800 Subject: [PATCH 21/52] Move domain manager acquisition into separate function Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 2a4f27766ba03..b530f4aac4945 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -33,15 +33,11 @@ Q_LOGGING_CATEGORY(lcFileProviderXPC, "nextcloud.gui.macos.fileprovider.xpc", QtInfoMsg) -FileProviderXPC::FileProviderXPC(QObject *parent) - : QObject{parent} +namespace XPCUtils { -} -void FileProviderXPC::start() +NSArray *getDomainManagers() { - qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; - dispatch_group_t group = dispatch_group_create(); __block NSMutableArray *managers = NSMutableArray.array; @@ -68,9 +64,24 @@ if (managers.count == 0) { qCWarning(lcFileProviderXPC) << "No domains found"; - return; } + return managers.copy; +} + +} // namespace XPCUtils + +FileProviderXPC::FileProviderXPC(QObject *parent) + : QObject{parent} +{ +} + +void FileProviderXPC::start() +{ + qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; + + const auto managers = XPCUtils::getDomainManagers(); + dispatch_group_t group = dispatch_group_create(); __block NSMutableArray *urls = NSMutableArray.array; for (NSFileProviderManager *const manager in managers) { From 4a8d50144a24c16abf71c6aedf66160571b72ced Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 27 Dec 2023 18:31:55 +0800 Subject: [PATCH 22/52] Move domain url acquisition to separate function Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 32 +++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index b530f4aac4945..3f6a51b9ddebb 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -69,18 +69,8 @@ return managers.copy; } -} // namespace XPCUtils - -FileProviderXPC::FileProviderXPC(QObject *parent) - : QObject{parent} -{ -} - -void FileProviderXPC::start() +NSArray *getDomainUrlsForManagers(NSArray *managers) { - qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; - - const auto managers = XPCUtils::getDomainManagers(); dispatch_group_t group = dispatch_group_create(); __block NSMutableArray *urls = NSMutableArray.array; @@ -106,12 +96,28 @@ if (urls.count == 0) { qCWarning(lcFileProviderXPC) << "No urls found"; - return; } + return urls.copy; +} + +} // namespace XPCUtils + +FileProviderXPC::FileProviderXPC(QObject *parent) + : QObject{parent} +{ +} + +void FileProviderXPC::start() +{ + qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; + + const auto managers = XPCUtils::getDomainManagers(); + const auto domainUrls = XPCUtils::getDomainUrlsForManagers(managers); + dispatch_group_t group = dispatch_group_create(); NSMutableArray *> *const fpServices = NSMutableArray.array; - for (NSURL *const url in urls) { + for (NSURL *const url in domainUrls) { dispatch_group_enter(group); [NSFileManager.defaultManager getFileProviderServicesForItemAtURL:url From a0376a2dabaa873e75b0259512b1914a0578bce5 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 27 Dec 2023 18:42:34 +0800 Subject: [PATCH 23/52] Move acquisition of file provider services to different function Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 35 +++++++++++++++++----------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 3f6a51b9ddebb..1f3b3a797a9db 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -101,23 +101,12 @@ return urls.copy; } -} // namespace XPCUtils - -FileProviderXPC::FileProviderXPC(QObject *parent) - : QObject{parent} -{ -} - -void FileProviderXPC::start() +NSArray *> *getFileProviderServicesAtUrls(NSArray *urls) { - qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; - - const auto managers = XPCUtils::getDomainManagers(); - const auto domainUrls = XPCUtils::getDomainUrlsForManagers(managers); dispatch_group_t group = dispatch_group_create(); NSMutableArray *> *const fpServices = NSMutableArray.array; - for (NSURL *const url in domainUrls) { + for (NSURL *const url in urls) { dispatch_group_enter(group); [NSFileManager.defaultManager getFileProviderServicesForItemAtURL:url @@ -141,9 +130,27 @@ if (fpServices.count == 0) { qCWarning(lcFileProviderXPC) << "No file provider services found"; - return; } + return fpServices.copy; +} + +} // namespace XPCUtils + +FileProviderXPC::FileProviderXPC(QObject *parent) + : QObject{parent} +{ +} + +void FileProviderXPC::start() +{ + qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; + + const auto managers = XPCUtils::getDomainManagers(); + const auto domainUrls = XPCUtils::getDomainUrlsForManagers(managers); + const auto fpServices = XPCUtils::getFileProviderServicesAtUrls(domainUrls); + dispatch_group_t group = dispatch_group_create(); + NSMutableArray *const connections = NSMutableArray.array; for (NSDictionary *const services in fpServices) { From 5ee2cfa749bef49c2b086a1f3e346544cf881a2c Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 27 Dec 2023 18:58:07 +0800 Subject: [PATCH 24/52] Moved XPC Utils into separate file Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 4 +- src/gui/macOS/fileproviderxpc_mac.mm | 158 +----------------- src/gui/macOS/fileproviderxpc_mac_utils.h | 31 ++++ src/gui/macOS/fileproviderxpc_mac_utils.mm | 185 +++++++++++++++++++++ 4 files changed, 224 insertions(+), 154 deletions(-) create mode 100644 src/gui/macOS/fileproviderxpc_mac_utils.h create mode 100644 src/gui/macOS/fileproviderxpc_mac_utils.mm diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index bf13b5318d379..4a6e4d27fb1b1 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -299,7 +299,9 @@ IF( APPLE ) macOS/fileprovidersocketserver.cpp macOS/fileprovidersocketserver_mac.mm macOS/fileproviderxpc.h - macOS/fileproviderxpc_mac.mm) + macOS/fileproviderxpc_mac.mm + macOS/fileproviderxpc_mac_utils.h + macOS/fileproviderxpc_mac_utils.mm) endif() if(SPARKLE_FOUND AND BUILD_UPDATER) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 1f3b3a797a9db..b8cb5e0498209 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -17,126 +17,16 @@ #include #include "gui/accountmanager.h" - -#import +#include "gui/macOS/fileproviderxpc_mac_utils.h" #import "ClientCommunicationProtocol.h" -namespace { - static const auto clientCommunicationServiceName = "com.nextcloud.desktopclient.ClientCommunicationService"; - static NSString *const nsClientCommunicationServiceName = [NSString stringWithUTF8String:clientCommunicationServiceName]; -} - namespace OCC { namespace Mac { Q_LOGGING_CATEGORY(lcFileProviderXPC, "nextcloud.gui.macos.fileprovider.xpc", QtInfoMsg) -namespace XPCUtils -{ - -NSArray *getDomainManagers() -{ - dispatch_group_t group = dispatch_group_create(); - __block NSMutableArray *managers = NSMutableArray.array; - - dispatch_group_enter(group); - - // Set up connections for each domain - [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray *const domains, NSError *const error){ - if (error != nil) { - qCWarning(lcFileProviderXPC) << "Error getting domains" << error; - dispatch_group_leave(group); - return; - } - - for (NSFileProviderDomain *const domain in domains) { - qCInfo(lcFileProviderXPC) << "Got domain" << domain.identifier; - NSFileProviderManager *const manager = [NSFileProviderManager managerForDomain:domain]; - [managers addObject:manager]; - } - - dispatch_group_leave(group); - }]; - - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - - if (managers.count == 0) { - qCWarning(lcFileProviderXPC) << "No domains found"; - } - - return managers.copy; -} - -NSArray *getDomainUrlsForManagers(NSArray *managers) -{ - dispatch_group_t group = dispatch_group_create(); - __block NSMutableArray *urls = NSMutableArray.array; - - for (NSFileProviderManager *const manager in managers) { - - dispatch_group_enter(group); - - [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 urls.copy; -} - -NSArray *> *getFileProviderServicesAtUrls(NSArray *urls) -{ - dispatch_group_t group = dispatch_group_create(); - NSMutableArray *> *const fpServices = NSMutableArray.array; - - for (NSURL *const url in urls) { - dispatch_group_enter(group); - - [NSFileManager.defaultManager getFileProviderServicesForItemAtURL:url - completionHandler:^(NSDictionary *const services, NSError *const error){ - if (error != nil) { - qCWarning(lcFileProviderXPC) << "Error getting file provider services" << error; - dispatch_group_leave(group); - return; - } - - qCInfo(lcFileProviderXPC) << "Got file provider services for" - << url.absoluteString - << "has number of services:" - << services.count; - [fpServices addObject:services]; - dispatch_group_leave(group); - }]; - } - - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - - if (fpServices.count == 0) { - qCWarning(lcFileProviderXPC) << "No file provider services found"; - } - - return fpServices.copy; -} - -} // namespace XPCUtils - FileProviderXPC::FileProviderXPC(QObject *parent) : QObject{parent} { @@ -146,50 +36,12 @@ { qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; - const auto managers = XPCUtils::getDomainManagers(); - const auto domainUrls = XPCUtils::getDomainUrlsForManagers(managers); - const auto fpServices = XPCUtils::getFileProviderServicesAtUrls(domainUrls); + const auto managers = FileProviderXPCUtils::getDomainManagers(); + const auto domainUrls = FileProviderXPCUtils::getDomainUrlsForManagers(managers); + const auto fpServices = FileProviderXPCUtils::getFileProviderServicesAtUrls(domainUrls); + const auto connections = FileProviderXPCUtils::connectToFileProviderServices(fpServices); dispatch_group_t group = dispatch_group_create(); - NSMutableArray *const connections = NSMutableArray.array; - - for (NSDictionary *const services in fpServices) { - NSArray *const serviceNamesArray = services.allKeys; - - for (NSFileProviderServiceName serviceName in serviceNamesArray) { - qCInfo(lcFileProviderXPC) << "Got service" << serviceName; - - if (![serviceName isEqualToString:nsClientCommunicationServiceName]) { - continue; - } - - NSFileProviderService *const service = services[serviceName]; - dispatch_group_enter(group); - - [service getFileProviderConnectionWithCompletionHandler:^(NSXPCConnection *const connection, NSError *const error){ - if (error != nil) { - qCWarning(lcFileProviderXPC) << "Error getting file provider connection" << error; - dispatch_group_leave(group); - return; - } - - qCInfo(lcFileProviderXPC) << "Got file provider connection" << connection; - - if (connection == nil) { - qCWarning(lcFileProviderXPC) << "Connection is nil"; - dispatch_group_leave(group); - return; - } - - [connection retain]; - [connections addObject:connection]; - dispatch_group_leave(group); - }]; - } - } - - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - NSMutableDictionary*> *const clientCommServices = NSMutableDictionary.dictionary; for (NSXPCConnection * const connection in connections) { diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.h b/src/gui/macOS/fileproviderxpc_mac_utils.h new file mode 100644 index 0000000000000..5d740db5213f6 --- /dev/null +++ b/src/gui/macOS/fileproviderxpc_mac_utils.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * 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 + +#import +#import + +namespace OCC { +namespace Mac { +namespace FileProviderXPCUtils { + +NSArray *getDomainManagers(); +NSArray *getDomainUrlsForManagers(NSArray *managers); +NSArray *> *getFileProviderServicesAtUrls(NSArray *urls); +NSArray *connectToFileProviderServices(NSArray *> *fpServices); + +} +} +} \ No newline at end of file diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.mm b/src/gui/macOS/fileproviderxpc_mac_utils.mm new file mode 100644 index 0000000000000..4b4319e48c823 --- /dev/null +++ b/src/gui/macOS/fileproviderxpc_mac_utils.mm @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * 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_mac_utils.h" + +#include + +#include "gui/accountmanager.h" + +#import "ClientCommunicationProtocol.h" + +namespace { + +static const char *const clientCommunicationServiceName = "com.nextcloud.desktopclient.ClientCommunicationService"; +static NSString *const nsClientCommunicationServiceName = [NSString stringWithUTF8String:clientCommunicationServiceName]; + +} + +namespace OCC { + +namespace Mac { + +Q_LOGGING_CATEGORY(lcFileProviderXPCUtils, "nextcloud.gui.macos.fileprovider.xpc.utils", QtInfoMsg) + +namespace FileProviderXPCUtils { + +NSArray *getDomainManagers() +{ + dispatch_group_t group = dispatch_group_create(); + __block NSMutableArray *managers = NSMutableArray.array; + + dispatch_group_enter(group); + + // Set up connections for each domain + [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray *const domains, NSError *const error){ + if (error != nil) { + qCWarning(lcFileProviderXPCUtils) << "Error getting domains" << error; + dispatch_group_leave(group); + return; + } + + for (NSFileProviderDomain *const domain in domains) { + qCInfo(lcFileProviderXPCUtils) << "Got domain" << domain.identifier; + NSFileProviderManager *const manager = [NSFileProviderManager managerForDomain:domain]; + [managers addObject:manager]; + } + + dispatch_group_leave(group); + }]; + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + if (managers.count == 0) { + qCWarning(lcFileProviderXPCUtils) << "No domains found"; + } + + return managers.copy; +} + +NSArray *getDomainUrlsForManagers(NSArray *managers) +{ + dispatch_group_t group = dispatch_group_create(); + __block NSMutableArray *urls = NSMutableArray.array; + + for (NSFileProviderManager *const manager in managers) { + + dispatch_group_enter(group); + + [manager getUserVisibleURLForItemIdentifier:NSFileProviderRootContainerItemIdentifier + completionHandler:^(NSURL *const url, NSError *const error){ + if (error != nil) { + qCWarning(lcFileProviderXPCUtils) << "Error getting user visible url" << error; + dispatch_group_leave(group); + return; + } + + qCDebug(lcFileProviderXPCUtils) << "Got user visible url" << url; + [urls addObject:url]; + dispatch_group_leave(group); + }]; + } + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + if (urls.count == 0) { + qCWarning(lcFileProviderXPCUtils) << "No urls found"; + } + + return urls.copy; +} + +NSArray *> *getFileProviderServicesAtUrls(NSArray *urls) +{ + dispatch_group_t group = dispatch_group_create(); + NSMutableArray *> *const fpServices = NSMutableArray.array; + + for (NSURL *const url in urls) { + dispatch_group_enter(group); + + [NSFileManager.defaultManager getFileProviderServicesForItemAtURL:url + completionHandler:^(NSDictionary *const services, NSError *const error){ + if (error != nil) { + qCWarning(lcFileProviderXPCUtils) << "Error getting file provider services" << error; + dispatch_group_leave(group); + return; + } + + qCInfo(lcFileProviderXPCUtils) << "Got file provider services for" + << url.absoluteString + << "has number of services:" + << services.count; + [fpServices addObject:services]; + dispatch_group_leave(group); + }]; + } + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + if (fpServices.count == 0) { + qCWarning(lcFileProviderXPCUtils) << "No file provider services found"; + } + + return fpServices.copy; +} + +NSArray *connectToFileProviderServices(NSArray *> *fpServices) +{ + dispatch_group_t group = dispatch_group_create(); + NSMutableArray *const connections = NSMutableArray.array; + + for (NSDictionary *const services in fpServices) { + NSArray *const serviceNamesArray = services.allKeys; + + for (NSFileProviderServiceName serviceName in serviceNamesArray) { + qCInfo(lcFileProviderXPCUtils) << "Got service" << serviceName; + + if (![serviceName isEqualToString:nsClientCommunicationServiceName]) { + continue; + } + + NSFileProviderService *const service = services[serviceName]; + dispatch_group_enter(group); + + [service getFileProviderConnectionWithCompletionHandler:^(NSXPCConnection *const connection, NSError *const error){ + if (error != nil) { + qCWarning(lcFileProviderXPCUtils) << "Error getting file provider connection" << error; + dispatch_group_leave(group); + return; + } + + qCInfo(lcFileProviderXPCUtils) << "Got file provider connection" << connection; + + if (connection == nil) { + qCWarning(lcFileProviderXPCUtils) << "Connection is nil"; + dispatch_group_leave(group); + return; + } + + [connection retain]; + [connections addObject:connection]; + dispatch_group_leave(group); + }]; + } + } + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + return connections.copy; +} + +} + +} + +} \ No newline at end of file From 95bebc52140a74e3092683266705213ce7074aaf Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 27 Dec 2023 19:10:37 +0800 Subject: [PATCH 25/52] Clean up FileProviderXPC code, separate everything into single-responsibility methods Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovider_mac.mm | 3 ++- src/gui/macOS/fileproviderxpc.h | 11 ++++++++++- src/gui/macOS/fileproviderxpc_mac.mm | 16 +++++++++++++--- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/gui/macOS/fileprovider_mac.mm b/src/gui/macOS/fileprovider_mac.mm index 00cd3aa1258b8..c6a7f572ed638 100644 --- a/src/gui/macOS/fileprovider_mac.mm +++ b/src/gui/macOS/fileprovider_mac.mm @@ -60,7 +60,8 @@ _xpc = std::make_unique(new FileProviderXPC(this)); if (_xpc) { qCInfo(lcMacFileProvider) << "Initialised file provider XPC."; - _xpc->start(); + _xpc->connectToExtensions(); + _xpc->configureExtensions(); } else { qCWarning(lcMacFileProvider) << "Could not initialise file provider XPC."; } diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index 759a4a0593c83..a145b710498fe 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -16,6 +16,8 @@ #include +#import + namespace OCC { namespace Mac { @@ -28,7 +30,14 @@ class FileProviderXPC : public QObject explicit FileProviderXPC(QObject *parent = nullptr); public slots: - void start(); + void connectToExtensions(); + void configureExtensions(); + +private: + void setupConnections(); + void processConnections(NSArray *const services); + + NSArray *_clientCommServices; }; } diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index b8cb5e0498209..5d9ca2750dcd7 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -32,7 +32,7 @@ { } -void FileProviderXPC::start() +void FileProviderXPC::connectToExtensions() { qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; @@ -40,6 +40,11 @@ const auto domainUrls = FileProviderXPCUtils::getDomainUrlsForManagers(managers); const auto fpServices = FileProviderXPCUtils::getFileProviderServicesAtUrls(domainUrls); const auto connections = FileProviderXPCUtils::connectToFileProviderServices(fpServices); + processConnections(connections); +} + +void FileProviderXPC::processConnections(NSArray *const connections) +{ dispatch_group_t group = dispatch_group_create(); NSMutableDictionary*> *const clientCommServices = NSMutableDictionary.dictionary; @@ -95,7 +100,12 @@ [clientCommServices setObject:clientCommService forKey:extensionNcAccount]; } - for (NSString *const extensionNcAccount in clientCommServices) { + _clientCommServices = clientCommServices.copy; +} + +void FileProviderXPC::configureExtensions() +{ + for (NSString *const extensionNcAccount in _clientCommServices) { qCInfo(lcFileProviderXPC) << "Sending message to client communication service"; const auto qExtensionNcAccount = QString::fromNSString(extensionNcAccount); @@ -116,7 +126,7 @@ NSString *const serverUrl = account->url().toString().toNSString(); NSString *const password = credentials->password().toNSString(); - NSObject *const clientCommService = [clientCommServices objectForKey:extensionNcAccount]; + NSObject *const clientCommService = [_clientCommServices objectForKey:extensionNcAccount]; [clientCommService configureAccountWithUser:user serverUrl:serverUrl password:password]; From 6f5b07c1ae360447e92645b8e180f22ff2eab728 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 28 Dec 2023 11:04:59 +0800 Subject: [PATCH 26/52] Fix clientcommservices datatype Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index a145b710498fe..be8b612088a6d 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -36,8 +36,8 @@ public slots: private: void setupConnections(); void processConnections(NSArray *const services); - - NSArray *_clientCommServices; + + NSDictionary *_clientCommServices; }; } From 5ed456f30cbf67ebcc06d3c468b8028753067ad8 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 14:12:49 +0800 Subject: [PATCH 27/52] Implement NSFileProviderServicing in FileProviderExtension Signed-off-by: Claudio Cambra --- ...FileProviderExtension+ClientInterface.swift | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift index fe5c21ccae32b..37bbb0fdb73af 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift @@ -18,7 +18,23 @@ import NCDesktopClientSocketKit import NextcloudKit import OSLog -extension FileProviderExtension { +extension FileProviderExtension: NSFileProviderServicing { + func supportedServiceSources( + for itemIdentifier: NSFileProviderItemIdentifier, + completionHandler: @escaping ([NSFileProviderServiceSource]?, Error?) -> Void + ) -> Progress { + Logger.desktopClientConnection.debug("Serving supported service sources") + let clientCommService = ClientCommunicationService(fpExtension: self) + let services = [clientCommService] + completionHandler(services, nil) + let progress = Progress() + progress.cancellationHandler = { + let error = NSError(domain: NSCocoaErrorDomain, code: NSUserCancelledError) + completionHandler(nil, error) + } + return progress + } + @objc func sendFileProviderDomainIdentifier() { let command = "FILE_PROVIDER_DOMAIN_IDENTIFIER_REQUEST_REPLY" let argument = domain.identifier.rawValue From 595c23cf76e3aa603b2a5ed7762f8048d25896e2 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 14:41:02 +0800 Subject: [PATCH 28/52] Extract file provider connection configuration into separate util function Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 12 +++--------- src/gui/macOS/fileproviderxpc_mac_utils.h | 1 + src/gui/macOS/fileproviderxpc_mac_utils.mm | 12 ++++++++++++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 5d9ca2750dcd7..06c3629932779 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -50,15 +50,9 @@ NSMutableDictionary*> *const clientCommServices = NSMutableDictionary.dictionary; 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 auto remoteObjectInterfaceProtocol = @protocol(ClientCommunicationProtocol); + connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:remoteObjectInterfaceProtocol]; + FileProviderXPCUtils::configureFileProviderConnection(connection); const id remoteServiceObject = [connection remoteObjectProxyWithErrorHandler:^(NSError *const error){ qCWarning(lcFileProviderXPC) << "Error getting remote object proxy" << error; diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.h b/src/gui/macOS/fileproviderxpc_mac_utils.h index 5d740db5213f6..84f6995b01e4f 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.h +++ b/src/gui/macOS/fileproviderxpc_mac_utils.h @@ -25,6 +25,7 @@ NSArray *getDomainManagers(); NSArray *getDomainUrlsForManagers(NSArray *managers); NSArray *> *getFileProviderServicesAtUrls(NSArray *urls); NSArray *connectToFileProviderServices(NSArray *> *fpServices); +void configureFileProviderConnection(NSXPCConnection *connection); } } diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.mm b/src/gui/macOS/fileproviderxpc_mac_utils.mm index 4b4319e48c823..639ffe198135b 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.mm +++ b/src/gui/macOS/fileproviderxpc_mac_utils.mm @@ -178,6 +178,18 @@ return connections.copy; } +void configureFileProviderConnection(NSXPCConnection *const connection) +{ + Q_ASSERT(connection != nil); + connection.interruptionHandler = ^{ + qCInfo(lcFileProviderXPCUtils) << "File provider connection interrupted"; + }; + connection.invalidationHandler = ^{ + qCInfo(lcFileProviderXPCUtils) << "File provider connection invalidated"; + }; + [connection resume]; +} + } } From c9997ce5f97785394818b0d350fe92d0fd397b03 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 14:55:46 +0800 Subject: [PATCH 29/52] Extract remote service object acquisistion from connection into separate function Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 11 +---------- src/gui/macOS/fileproviderxpc_mac_utils.h | 1 + src/gui/macOS/fileproviderxpc_mac_utils.mm | 23 +++++++++++++++++++++- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 06c3629932779..e2a188f5b11fd 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -54,16 +54,7 @@ connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:remoteObjectInterfaceProtocol]; FileProviderXPCUtils::configureFileProviderConnection(connection); - const id remoteServiceObject = [connection remoteObjectProxyWithErrorHandler:^(NSError *const error){ - qCWarning(lcFileProviderXPC) << "Error getting remote object proxy" << error; - }]; - - if (![remoteServiceObject conformsToProtocol:@protocol(ClientCommunicationProtocol)]) { - qCWarning(lcFileProviderXPC) << "Remote service object does not conform to protocol"; - continue; - } - - NSObject *const clientCommService = (NSObject *)remoteServiceObject; + const auto clientCommService = FileProviderXPCUtils::getRemoteServiceObject(connection, remoteObjectInterfaceProtocol); if (clientCommService == nil) { qCWarning(lcFileProviderXPC) << "Client communication service is nil"; continue; diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.h b/src/gui/macOS/fileproviderxpc_mac_utils.h index 84f6995b01e4f..e60b3116b8e4c 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.h +++ b/src/gui/macOS/fileproviderxpc_mac_utils.h @@ -26,6 +26,7 @@ NSArray *getDomainUrlsForManagers(NSArray *man NSArray *> *getFileProviderServicesAtUrls(NSArray *urls); NSArray *connectToFileProviderServices(NSArray *> *fpServices); void configureFileProviderConnection(NSXPCConnection *connection); +NSObject *getRemoteServiceObject(NSXPCConnection *connection, Protocol *protocol); } } diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.mm b/src/gui/macOS/fileproviderxpc_mac_utils.mm index 639ffe198135b..36c60400338bb 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.mm +++ b/src/gui/macOS/fileproviderxpc_mac_utils.mm @@ -190,8 +190,29 @@ void configureFileProviderConnection(NSXPCConnection *const connection) [connection resume]; } +NSObject *getRemoteServiceObject(NSXPCConnection *const connection, Protocol *const protocol) +{ + Q_ASSERT(connection != nil); + Q_ASSERT(protocol != nil); + const id remoteServiceObject = [connection remoteObjectProxyWithErrorHandler:^(NSError *const error){ + qCWarning(lcFileProviderXPCUtils) << "Error getting remote object proxy" << error; + }]; + if (remoteServiceObject == nil) { + return nil; + } + if (![remoteServiceObject conformsToProtocol:@protocol(ClientCommunicationProtocol)]) { + qCWarning(lcFileProviderXPCUtils) << "Remote service object does not conform to protocol"; + return nil; + } + return remoteServiceObject; } } -} \ No newline at end of file +} + +} // namespace FileProviderXPCUtils + +} // namespace Mac + +} // namespace OCC From 8a8d3b3ef5d676fa5da550d690faf68f2b5bd45f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 14:56:20 +0800 Subject: [PATCH 30/52] Remove redundant static in anonymous fileproviderxpc utils namespace Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac_utils.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.mm b/src/gui/macOS/fileproviderxpc_mac_utils.mm index 36c60400338bb..99ee755f8e535 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.mm +++ b/src/gui/macOS/fileproviderxpc_mac_utils.mm @@ -22,8 +22,8 @@ namespace { -static const char *const clientCommunicationServiceName = "com.nextcloud.desktopclient.ClientCommunicationService"; -static NSString *const nsClientCommunicationServiceName = [NSString stringWithUTF8String:clientCommunicationServiceName]; +const char *const clientCommunicationServiceName = "com.nextcloud.desktopclient.ClientCommunicationService"; +NSString *const nsClientCommunicationServiceName = [NSString stringWithUTF8String:clientCommunicationServiceName]; } From 23a3a3e55499669cc591318292eafff4ba33f409 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 14:58:30 +0800 Subject: [PATCH 31/52] Extract account id acquisition from clientCommService into separate function Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 20 +------------------- src/gui/macOS/fileproviderxpc_mac_utils.h | 3 +++ src/gui/macOS/fileproviderxpc_mac_utils.mm | 22 ++++++++++++++++++---- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index e2a188f5b11fd..c7c4ae4cb115c 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -35,7 +35,6 @@ void FileProviderXPC::connectToExtensions() { qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; - const auto managers = FileProviderXPCUtils::getDomainManagers(); const auto domainUrls = FileProviderXPCUtils::getDomainUrlsForManagers(managers); const auto fpServices = FileProviderXPCUtils::getFileProviderServicesAtUrls(domainUrls); @@ -45,8 +44,6 @@ void FileProviderXPC::processConnections(NSArray *const connections) { - dispatch_group_t group = dispatch_group_create(); - NSMutableDictionary*> *const clientCommServices = NSMutableDictionary.dictionary; for (NSXPCConnection * const connection in connections) { @@ -59,24 +56,9 @@ qCWarning(lcFileProviderXPC) << "Client communication service is nil"; continue; } - [clientCommService retain]; - __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 + const auto extensionNcAccount = FileProviderXPCUtils::getExtensionAccountId(clientCommService); if (extensionNcAccount == nil) { qCWarning(lcFileProviderXPC) << "Extension account id is nil"; continue; diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.h b/src/gui/macOS/fileproviderxpc_mac_utils.h index e60b3116b8e4c..04512b30b9624 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.h +++ b/src/gui/macOS/fileproviderxpc_mac_utils.h @@ -17,6 +17,8 @@ #import #import +#import "ClientCommunicationProtocol.h" + namespace OCC { namespace Mac { namespace FileProviderXPCUtils { @@ -27,6 +29,7 @@ NSArray *> *get NSArray *connectToFileProviderServices(NSArray *> *fpServices); void configureFileProviderConnection(NSXPCConnection *connection); NSObject *getRemoteServiceObject(NSXPCConnection *connection, Protocol *protocol); +NSString *getExtensionAccountId(NSObject *clientCommService); } } diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.mm b/src/gui/macOS/fileproviderxpc_mac_utils.mm index 99ee755f8e535..4161855b200b6 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.mm +++ b/src/gui/macOS/fileproviderxpc_mac_utils.mm @@ -18,8 +18,6 @@ #include "gui/accountmanager.h" -#import "ClientCommunicationProtocol.h" - namespace { const char *const clientCommunicationServiceName = "com.nextcloud.desktopclient.ClientCommunicationService"; @@ -207,8 +205,24 @@ void configureFileProviderConnection(NSXPCConnection *const connection) return remoteServiceObject; } -} - +NSString *getExtensionAccountId(NSObject *const clientCommService) +{ + Q_ASSERT(clientCommService != nil); + __block NSString *extensionNcAccount; + dispatch_group_t group = dispatch_group_create(); + dispatch_group_enter(group); + [clientCommService getExtensionAccountIdWithCompletionHandler:^(NSString *const extensionAccountId, NSError *const error){ + if (error != nil) { + qCWarning(lcFileProviderXPCUtils) << "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); + return extensionNcAccount; } } // namespace FileProviderXPCUtils From 502d73814ef09dafe6bc37573f1c708fc71a2fd7 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 15:16:37 +0800 Subject: [PATCH 32/52] Cast clientCommServices to NSObject with correct protocol Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index c7c4ae4cb115c..fcda7898192ef 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -51,7 +51,7 @@ connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:remoteObjectInterfaceProtocol]; FileProviderXPCUtils::configureFileProviderConnection(connection); - const auto clientCommService = FileProviderXPCUtils::getRemoteServiceObject(connection, remoteObjectInterfaceProtocol); + const auto clientCommService = (NSObject *)FileProviderXPCUtils::getRemoteServiceObject(connection, remoteObjectInterfaceProtocol); if (clientCommService == nil) { qCWarning(lcFileProviderXPC) << "Client communication service is nil"; continue; From f728ec1b75f57b53a8366038e7dad4c61599bf07 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 15:28:28 +0800 Subject: [PATCH 33/52] Add method to unauthenticate file provider extension in FileProviderXPC Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc.h | 1 + src/gui/macOS/fileproviderxpc_mac.mm | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index be8b612088a6d..48eeb7c48c080 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -32,6 +32,7 @@ class FileProviderXPC : public QObject public slots: void connectToExtensions(); void configureExtensions(); + void unauthenticateExtension(const QString &extensionAccountId); private: void setupConnections(); diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index fcda7898192ef..f28d2235d7c06 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -100,6 +100,14 @@ } } +void FileProviderXPC::unauthenticateExtension(const QString &extensionAccountId) +{ + qCInfo(lcFileProviderXPC) << "Unauthenticating extension" << extensionAccountId; + NSString *const nsExtensionAccountId = extensionAccountId.toNSString(); + NSObject *const clientCommService = [_clientCommServices objectForKey:nsExtensionAccountId]; + [clientCommService removeAccountConfig]; +} + } // namespace OCC } // namespace Mac From 94bfa035c35c9c0af8a0bf3498e16be3beef2b8f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 15:47:22 +0800 Subject: [PATCH 34/52] Define NSDictionary types in _clientCommServices Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc.h | 4 +++- src/gui/macOS/fileproviderxpc_mac.mm | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index 48eeb7c48c080..9fb9cf8e86de8 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -18,6 +18,8 @@ #import +#import "ClientCommunicationProtocol.h" + namespace OCC { namespace Mac { @@ -38,7 +40,7 @@ public slots: void setupConnections(); void processConnections(NSArray *const services); - NSDictionary *_clientCommServices; + NSDictionary *_clientCommServices; }; } diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index f28d2235d7c06..025feb25ff75e 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -19,8 +19,6 @@ #include "gui/accountmanager.h" #include "gui/macOS/fileproviderxpc_mac_utils.h" -#import "ClientCommunicationProtocol.h" - namespace OCC { namespace Mac { From c1fa6621ae0ca107407cdc1e9333798c58afb54a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 15:49:20 +0800 Subject: [PATCH 35/52] Move extension authentication into separate method Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc.h | 3 +- src/gui/macOS/fileproviderxpc_mac.mm | 46 +++++++++++++++------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index 9fb9cf8e86de8..791ac886962a8 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -34,7 +34,8 @@ class FileProviderXPC : public QObject public slots: void connectToExtensions(); void configureExtensions(); - void unauthenticateExtension(const QString &extensionAccountId); + void authenticateExtension(const QString &extensionAccountId) const; + void unauthenticateExtension(const QString &extensionAccountId) const; private: void setupConnections(); diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 025feb25ff75e..a9e5b2ca83149 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -74,31 +74,35 @@ qCInfo(lcFileProviderXPC) << "Sending message to client communication service"; const auto qExtensionNcAccount = QString::fromNSString(extensionNcAccount); - const auto accountManager = AccountManager::instance(); - - Q_ASSERT(accountManager); - - const auto accountState = accountManager->accountFromUserId(qExtensionNcAccount); - if (!accountState) { - qCWarning(lcFileProviderXPC) << "Account state is null for received account" - << qExtensionNcAccount; - return; - } - - const auto account = accountState->account(); - const auto credentials = account->credentials(); - NSString *const user = credentials->user().toNSString(); - NSString *const serverUrl = account->url().toString().toNSString(); - NSString *const password = credentials->password().toNSString(); + authenticateExtension(qExtensionNcAccount); + } +} - NSObject *const clientCommService = [_clientCommServices objectForKey:extensionNcAccount]; - [clientCommService configureAccountWithUser:user - serverUrl:serverUrl - password:password]; +void FileProviderXPC::authenticateExtension(const QString &extensionAccountId) const +{ + const auto accountManager = AccountManager::instance(); + Q_ASSERT(accountManager); + const auto accountState = accountManager->accountFromUserId(extensionAccountId); + if (!accountState) { + qCWarning(lcFileProviderXPC) << "Account state is null for received account" + << extensionAccountId; + return; } + + const auto account = accountState->account(); + const auto credentials = account->credentials(); + NSString *const user = credentials->user().toNSString(); + NSString *const serverUrl = account->url().toString().toNSString(); + NSString *const password = credentials->password().toNSString(); + + const auto nsExtensionNcAccount = extensionAccountId.toNSString(); + NSObject *const clientCommService = [_clientCommServices objectForKey:nsExtensionNcAccount]; + [clientCommService configureAccountWithUser:user + serverUrl:serverUrl + password:password]; } -void FileProviderXPC::unauthenticateExtension(const QString &extensionAccountId) +void FileProviderXPC::unauthenticateExtension(const QString &extensionAccountId) const { qCInfo(lcFileProviderXPC) << "Unauthenticating extension" << extensionAccountId; NSString *const nsExtensionAccountId = extensionAccountId.toNSString(); From 0856138b2e1544ce9f450a1c4f312e530691d042 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 15:56:59 +0800 Subject: [PATCH 36/52] Implement recognition of account state changing in FileProviderXPC Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc.h | 3 +++ src/gui/macOS/fileproviderxpc_mac.mm | 29 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index 791ac886962a8..d31213e3b3cd3 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -37,6 +37,9 @@ public slots: void authenticateExtension(const QString &extensionAccountId) const; void unauthenticateExtension(const QString &extensionAccountId) const; +private slots: + void slotAccountStateChanged(AccountState::State state) const; + private: void setupConnections(); void processConnections(NSArray *const services); diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index a9e5b2ca83149..f4000ca96d550 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -89,6 +89,8 @@ return; } + connect(accountState.data(), &AccountState::stateChanged, this, &FileProviderXPC::slotAccountStateChanged, Qt::UniqueConnection); + const auto account = accountState->account(); const auto credentials = account->credentials(); NSString *const user = credentials->user().toNSString(); @@ -110,6 +112,33 @@ [clientCommService removeAccountConfig]; } +void FileProviderXPC::slotAccountStateChanged(const AccountState::State state) const +{ + const auto sender = dynamic_cast(QObject::sender()); + Q_ASSERT(sender); + const auto extensionAccountId = sender->account()->userIdAtHostWithPort(); + + switch(state) { + case AccountState::Disconnected: + case AccountState::ConfigurationError: + case AccountState::NetworkError: + case AccountState::ServiceUnavailable: + case AccountState::MaintenanceMode: + // Do nothing, File Provider will by itself figure out connection issue + break; + case AccountState::SignedOut: + case AccountState::AskingCredentials: + case AccountState::RedirectDetected: + // Notify File Provider that it should show the not authenticated message + unauthenticateExtension(extensionAccountId); + break; + case AccountState::Connected: + // Provide credentials + authenticateExtension(extensionAccountId); + break; + } +} + } // namespace OCC } // namespace Mac From fca6b37804cb07f01b4432ab4a9a63d12a8c152f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 16:02:53 +0800 Subject: [PATCH 37/52] Fix clang-tidy namespace concatenation warning Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc.h | 10 +++------- src/gui/macOS/fileproviderxpc_mac.mm | 8 ++------ src/gui/macOS/fileproviderxpc_mac_utils.h | 6 +----- src/gui/macOS/fileproviderxpc_mac_utils.mm | 14 ++------------ 4 files changed, 8 insertions(+), 30 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index d31213e3b3cd3..3ce162839519e 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -12,17 +12,15 @@ * for more details. */ -#pragma once - #include #import #import "ClientCommunicationProtocol.h" -namespace OCC { +#pragma once -namespace Mac { +namespace OCC::Mac { class FileProviderXPC : public QObject { @@ -47,6 +45,4 @@ private slots: NSDictionary *_clientCommServices; }; -} - -} +} // namespace OCC::Mac diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index f4000ca96d550..19db91e0eb601 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -19,9 +19,7 @@ #include "gui/accountmanager.h" #include "gui/macOS/fileproviderxpc_mac_utils.h" -namespace OCC { - -namespace Mac { +namespace OCC::Mac { Q_LOGGING_CATEGORY(lcFileProviderXPC, "nextcloud.gui.macos.fileprovider.xpc", QtInfoMsg) @@ -139,6 +137,4 @@ } } -} // namespace OCC - -} // namespace Mac +} // namespace OCC::Mac diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.h b/src/gui/macOS/fileproviderxpc_mac_utils.h index 04512b30b9624..2e4aed958a639 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.h +++ b/src/gui/macOS/fileproviderxpc_mac_utils.h @@ -19,9 +19,7 @@ #import "ClientCommunicationProtocol.h" -namespace OCC { -namespace Mac { -namespace FileProviderXPCUtils { +namespace OCC::Mac::FileProviderXPCUtils { NSArray *getDomainManagers(); NSArray *getDomainUrlsForManagers(NSArray *managers); @@ -31,6 +29,4 @@ void configureFileProviderConnection(NSXPCConnection *connection); NSObject *getRemoteServiceObject(NSXPCConnection *connection, Protocol *protocol); NSString *getExtensionAccountId(NSObject *clientCommService); -} -} } \ No newline at end of file diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.mm b/src/gui/macOS/fileproviderxpc_mac_utils.mm index 4161855b200b6..964d248221b60 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.mm +++ b/src/gui/macOS/fileproviderxpc_mac_utils.mm @@ -19,20 +19,14 @@ #include "gui/accountmanager.h" namespace { - const char *const clientCommunicationServiceName = "com.nextcloud.desktopclient.ClientCommunicationService"; NSString *const nsClientCommunicationServiceName = [NSString stringWithUTF8String:clientCommunicationServiceName]; - } -namespace OCC { - -namespace Mac { +namespace OCC::Mac::FileProviderXPCUtils { Q_LOGGING_CATEGORY(lcFileProviderXPCUtils, "nextcloud.gui.macos.fileprovider.xpc.utils", QtInfoMsg) -namespace FileProviderXPCUtils { - NSArray *getDomainManagers() { dispatch_group_t group = dispatch_group_create(); @@ -225,8 +219,4 @@ void configureFileProviderConnection(NSXPCConnection *const connection) return extensionNcAccount; } -} // namespace FileProviderXPCUtils - -} // namespace Mac - -} // namespace OCC +} // namespace OCC::Mac::FileProviderXPCUtils From 784cd129fb910cacbea95fddfb014538cdeb120d Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 16:28:26 +0800 Subject: [PATCH 38/52] Remove all obj-c classes from fileproviderxpc.h Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc.h | 10 ++---- src/gui/macOS/fileproviderxpc_mac.mm | 41 +++------------------- src/gui/macOS/fileproviderxpc_mac_utils.h | 1 + src/gui/macOS/fileproviderxpc_mac_utils.mm | 28 +++++++++++++++ 4 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index 3ce162839519e..79613edaca295 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -13,10 +13,9 @@ */ #include +#include -#import - -#import "ClientCommunicationProtocol.h" +#include "accountstate.h" #pragma once @@ -39,10 +38,7 @@ private slots: void slotAccountStateChanged(AccountState::State state) const; private: - void setupConnections(); - void processConnections(NSArray *const services); - - NSDictionary *_clientCommServices; + QHash _clientCommServices; }; } // namespace OCC::Mac diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 19db91e0eb601..29570e039b84d 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -35,44 +35,14 @@ const auto domainUrls = FileProviderXPCUtils::getDomainUrlsForManagers(managers); const auto fpServices = FileProviderXPCUtils::getFileProviderServicesAtUrls(domainUrls); const auto connections = FileProviderXPCUtils::connectToFileProviderServices(fpServices); - processConnections(connections); -} - -void FileProviderXPC::processConnections(NSArray *const connections) -{ - NSMutableDictionary*> *const clientCommServices = NSMutableDictionary.dictionary; - - for (NSXPCConnection * const connection in connections) { - const auto remoteObjectInterfaceProtocol = @protocol(ClientCommunicationProtocol); - connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:remoteObjectInterfaceProtocol]; - FileProviderXPCUtils::configureFileProviderConnection(connection); - - const auto clientCommService = (NSObject *)FileProviderXPCUtils::getRemoteServiceObject(connection, remoteObjectInterfaceProtocol); - if (clientCommService == nil) { - qCWarning(lcFileProviderXPC) << "Client communication service is nil"; - continue; - } - [clientCommService retain]; - - const auto extensionNcAccount = FileProviderXPCUtils::getExtensionAccountId(clientCommService); - if (extensionNcAccount == nil) { - qCWarning(lcFileProviderXPC) << "Extension account id is nil"; - continue; - } - qCInfo(lcFileProviderXPC) << "Got extension account id" << extensionNcAccount.UTF8String; - [clientCommServices setObject:clientCommService forKey:extensionNcAccount]; - } - - _clientCommServices = clientCommServices.copy; + _clientCommServices = FileProviderXPCUtils::processClientCommunicationConnections(connections); } void FileProviderXPC::configureExtensions() { - for (NSString *const extensionNcAccount in _clientCommServices) { + for (const auto &extensionNcAccount : _clientCommServices.keys()) { qCInfo(lcFileProviderXPC) << "Sending message to client communication service"; - - const auto qExtensionNcAccount = QString::fromNSString(extensionNcAccount); - authenticateExtension(qExtensionNcAccount); + authenticateExtension(extensionNcAccount); } } @@ -95,8 +65,7 @@ NSString *const serverUrl = account->url().toString().toNSString(); NSString *const password = credentials->password().toNSString(); - const auto nsExtensionNcAccount = extensionAccountId.toNSString(); - NSObject *const clientCommService = [_clientCommServices objectForKey:nsExtensionNcAccount]; + const auto clientCommService = (NSObject *)_clientCommServices.value(extensionAccountId); [clientCommService configureAccountWithUser:user serverUrl:serverUrl password:password]; @@ -106,7 +75,7 @@ { qCInfo(lcFileProviderXPC) << "Unauthenticating extension" << extensionAccountId; NSString *const nsExtensionAccountId = extensionAccountId.toNSString(); - NSObject *const clientCommService = [_clientCommServices objectForKey:nsExtensionAccountId]; + const auto clientCommService = (NSObject *)_clientCommServices.value(extensionAccountId); [clientCommService removeAccountConfig]; } diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.h b/src/gui/macOS/fileproviderxpc_mac_utils.h index 2e4aed958a639..ceda2b55f7388 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.h +++ b/src/gui/macOS/fileproviderxpc_mac_utils.h @@ -28,5 +28,6 @@ NSArray *connectToFileProviderServices(NSArray *clientCommService); +QHash processClientCommunicationConnections(NSArray *connections); } \ No newline at end of file diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.mm b/src/gui/macOS/fileproviderxpc_mac_utils.mm index 964d248221b60..3038e72eedd06 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.mm +++ b/src/gui/macOS/fileproviderxpc_mac_utils.mm @@ -219,4 +219,32 @@ void configureFileProviderConnection(NSXPCConnection *const connection) return extensionNcAccount; } +QHash processClientCommunicationConnections(NSArray *const connections) +{ + QHash clientCommServices; + + for (NSXPCConnection * const connection in connections) { + const auto remoteObjectInterfaceProtocol = @protocol(ClientCommunicationProtocol); + connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:remoteObjectInterfaceProtocol]; + configureFileProviderConnection(connection); + + const auto clientCommService = (NSObject *)getRemoteServiceObject(connection, remoteObjectInterfaceProtocol); + if (clientCommService == nil) { + qCWarning(lcFileProviderXPCUtils) << "Client communication service is nil"; + continue; + } + [clientCommService retain]; + + const auto extensionNcAccount = getExtensionAccountId(clientCommService); + if (extensionNcAccount == nil) { + qCWarning(lcFileProviderXPCUtils) << "Extension account id is nil"; + continue; + } + qCInfo(lcFileProviderXPCUtils) << "Got extension account id" << extensionNcAccount.UTF8String; + clientCommServices.insert(QString::fromNSString(extensionNcAccount), clientCommService); + } + + return clientCommServices; +} + } // namespace OCC::Mac::FileProviderXPCUtils From be3bd7bb3b72b037f93c6a5c498375e6e41a396b Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 16:30:59 +0800 Subject: [PATCH 39/52] Do not shadow sender() Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 29570e039b84d..e59a53fc30228 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -81,9 +81,9 @@ void FileProviderXPC::slotAccountStateChanged(const AccountState::State state) const { - const auto sender = dynamic_cast(QObject::sender()); - Q_ASSERT(sender); - const auto extensionAccountId = sender->account()->userIdAtHostWithPort(); + const auto slotSender = dynamic_cast(sender()); + Q_ASSERT(slotSender); + const auto extensionAccountId = slotSender->account()->userIdAtHostWithPort(); switch(state) { case AccountState::Disconnected: From 6d4e785ebb2427a91eeb31c86360898bfe475d2f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 16:31:58 +0800 Subject: [PATCH 40/52] Remove unused extension ID NSString Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index e59a53fc30228..a18bccdbccaef 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -74,7 +74,6 @@ void FileProviderXPC::unauthenticateExtension(const QString &extensionAccountId) const { qCInfo(lcFileProviderXPC) << "Unauthenticating extension" << extensionAccountId; - NSString *const nsExtensionAccountId = extensionAccountId.toNSString(); const auto clientCommService = (NSObject *)_clientCommServices.value(extensionAccountId); [clientCommService removeAccountConfig]; } From 43b7ae55df05759c29f86811935edd3f267447c4 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 17:04:45 +0800 Subject: [PATCH 41/52] Use accountStateFromFileProviderDomainIdentifier method in authenticateExtension Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index a18bccdbccaef..126242277070d 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -17,6 +17,7 @@ #include #include "gui/accountmanager.h" +#include "gui/macOS/fileproviderdomainmanager.h" #include "gui/macOS/fileproviderxpc_mac_utils.h" namespace OCC::Mac { @@ -48,9 +49,7 @@ void FileProviderXPC::authenticateExtension(const QString &extensionAccountId) const { - const auto accountManager = AccountManager::instance(); - Q_ASSERT(accountManager); - const auto accountState = accountManager->accountFromUserId(extensionAccountId); + const auto accountState = FileProviderDomainManager::accountStateFromFileProviderDomainIdentifier(extensionAccountId); if (!accountState) { qCWarning(lcFileProviderXPC) << "Account state is null for received account" << extensionAccountId; From 798f77fa2b3c63ea5e290864d2238e13a89a13c6 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 17:08:35 +0800 Subject: [PATCH 42/52] Improve domain discovery logging Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainmanager_mac.mm | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm index f81534c00db76..ce6d0548970e0 100644 --- a/src/gui/macOS/fileproviderdomainmanager_mac.mm +++ b/src/gui/macOS/fileproviderdomainmanager_mac.mm @@ -82,9 +82,9 @@ bool accountFilesPushNotificationsReady(const OCC::AccountPtr &account) namespace Mac { -class API_AVAILABLE(macos(11.0)) FileProviderDomainManager::MacImplementation { - - public: +class API_AVAILABLE(macos(11.0)) FileProviderDomainManager::MacImplementation +{ +public: MacImplementation() = default; ~MacImplementation() = default; @@ -139,7 +139,10 @@ void findExistingFileProviderDomains() } else { qCInfo(lcMacFileProviderDomainManager) << "Found existing file provider domain with no known configured account:" - << domain.displayName; + << domain.displayName + << accountState + << (accountState ? "NON-NULL ACCOUNTSTATE" : "NULL") + << (accountState && accountState->account() ? domainDisplayNameForAccount(accountState->account()) : "NULL"); [NSFileProviderManager removeDomain:domain completionHandler:^(NSError * const error) { if (error) { qCWarning(lcMacFileProviderDomainManager) << "Error removing file provider domain: " @@ -390,7 +393,8 @@ void signalEnumeratorChanged(const Account * const account) } } - QStringList configuredDomainIds() const { + QStringList configuredDomainIds() const + { return _registeredDomains.keys(); } From 58dc42a5212e9964e4e16b17672af8d15ce3c6e2 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 23 Jan 2024 18:05:40 +0800 Subject: [PATCH 43/52] Get services using better non-url based method if available (macOS 13.0+) Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 3 +- src/gui/macOS/fileproviderxpc_mac_utils.h | 1 + src/gui/macOS/fileproviderxpc_mac_utils.mm | 36 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 126242277070d..399c1af6d4bf9 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -33,8 +33,7 @@ { qCInfo(lcFileProviderXPC) << "Starting file provider XPC"; const auto managers = FileProviderXPCUtils::getDomainManagers(); - const auto domainUrls = FileProviderXPCUtils::getDomainUrlsForManagers(managers); - const auto fpServices = FileProviderXPCUtils::getFileProviderServicesAtUrls(domainUrls); + const auto fpServices = FileProviderXPCUtils::getFileProviderServices(managers); const auto connections = FileProviderXPCUtils::connectToFileProviderServices(fpServices); _clientCommServices = FileProviderXPCUtils::processClientCommunicationConnections(connections); } diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.h b/src/gui/macOS/fileproviderxpc_mac_utils.h index ceda2b55f7388..f66d585f6375a 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.h +++ b/src/gui/macOS/fileproviderxpc_mac_utils.h @@ -23,6 +23,7 @@ namespace OCC::Mac::FileProviderXPCUtils { NSArray *getDomainManagers(); NSArray *getDomainUrlsForManagers(NSArray *managers); +NSArray *> *getFileProviderServices(NSArray *managers); NSArray *> *getFileProviderServicesAtUrls(NSArray *urls); NSArray *connectToFileProviderServices(NSArray *> *fpServices); void configureFileProviderConnection(NSXPCConnection *connection); diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.mm b/src/gui/macOS/fileproviderxpc_mac_utils.mm index 3038e72eedd06..da1d9a6316dc7 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.mm +++ b/src/gui/macOS/fileproviderxpc_mac_utils.mm @@ -60,6 +60,42 @@ return managers.copy; } +// TODO: This should work for all service names, not just the communication service! +NSArray *> *getFileProviderServices(NSArray *managers) +{ + if (@available(macOS 13.0, *)) { + NSMutableArray *> *const fpServices = NSMutableArray.array; + dispatch_group_t group = dispatch_group_create(); + + for (NSFileProviderManager *const manager in managers) { + __block NSFileProviderService *acquiredService; + dispatch_group_enter(group); + [manager getServiceWithName:nsClientCommunicationServiceName + itemIdentifier:NSFileProviderRootContainerItemIdentifier + completionHandler:^(NSFileProviderService *const service, NSError *const error) { + if (error != nil) { + qCWarning(lcFileProviderXPCUtils) << "Error getting file provider service" << error; + dispatch_group_leave(group); + return; + } else if (service == nil) { + qCWarning(lcFileProviderXPCUtils) << "Service is nil"; + dispatch_group_leave(group); + return; + } + + [service retain]; + [fpServices addObject:@{acquiredService.name: acquiredService}]; + dispatch_group_leave(group); + }]; + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + } + return fpServices.copy; + } else { + const auto domainUrls = FileProviderXPCUtils::getDomainUrlsForManagers(managers); + return FileProviderXPCUtils::getFileProviderServicesAtUrls(domainUrls); + } +} + NSArray *getDomainUrlsForManagers(NSArray *managers) { dispatch_group_t group = dispatch_group_create(); From 423891230ebe4ea254265396812a48b030da2910 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 23 Jan 2024 18:20:07 +0800 Subject: [PATCH 44/52] Separate starting of domain manager tasks from constructor Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovider_mac.mm | 3 +- src/gui/macOS/fileproviderdomainmanager.h | 1 + .../macOS/fileproviderdomainmanager_mac.mm | 48 ++++++++++--------- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/gui/macOS/fileprovider_mac.mm b/src/gui/macOS/fileprovider_mac.mm index c6a7f572ed638..2ac897735f347 100644 --- a/src/gui/macOS/fileprovider_mac.mm +++ b/src/gui/macOS/fileprovider_mac.mm @@ -44,9 +44,10 @@ } qCInfo(lcMacFileProvider) << "Initialising file provider domain manager."; - _domainManager = std::make_unique(new FileProviderDomainManager(this)); + _domainManager = std::make_unique(this); if (_domainManager) { + _domainManager->start(); qCDebug(lcMacFileProvider()) << "Initialized file provider domain manager"; } diff --git a/src/gui/macOS/fileproviderdomainmanager.h b/src/gui/macOS/fileproviderdomainmanager.h index 3aa80d39be3c5..e27fdf7c60fb3 100644 --- a/src/gui/macOS/fileproviderdomainmanager.h +++ b/src/gui/macOS/fileproviderdomainmanager.h @@ -33,6 +33,7 @@ class FileProviderDomainManager : public QObject ~FileProviderDomainManager() override; static AccountStatePtr accountStateFromFileProviderDomainIdentifier(const QString &domainIdentifier); + void start(); private slots: void setupFileProviderDomains(); diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm index ce6d0548970e0..bbc0568120be8 100644 --- a/src/gui/macOS/fileproviderdomainmanager_mac.mm +++ b/src/gui/macOS/fileproviderdomainmanager_mac.mm @@ -407,29 +407,6 @@ QStringList configuredDomainIds() const { if (@available(macOS 11.0, *)) { d.reset(new FileProviderDomainManager::MacImplementation()); - - ConfigFile cfg; - std::chrono::milliseconds polltime = cfg.remotePollInterval(); - _enumeratorSignallingTimer.setInterval(polltime.count()); - connect(&_enumeratorSignallingTimer, &QTimer::timeout, - this, &FileProviderDomainManager::slotEnumeratorSignallingTimerTimeout); - _enumeratorSignallingTimer.start(); - - setupFileProviderDomains(); - - connect(AccountManager::instance(), &AccountManager::accountAdded, - this, &FileProviderDomainManager::addFileProviderDomainForAccount); - // If an account is deleted from the client, accountSyncConnectionRemoved will be - // emitted first. So we treat accountRemoved as only being relevant to client - // shutdowns. - connect(AccountManager::instance(), &AccountManager::accountSyncConnectionRemoved, - this, &FileProviderDomainManager::removeFileProviderDomainForAccount); - connect(AccountManager::instance(), &AccountManager::accountRemoved, - this, [this](const AccountState * const accountState) { - - const auto trReason = tr("%1 application has been closed. Reopen to reconnect.").arg(APPLICATION_NAME); - disconnectFileProviderDomainForAccount(accountState, trReason); - }); } else { qCWarning(lcMacFileProviderDomainManager()) << "Trying to run File Provider on system that does not support it."; } @@ -437,6 +414,31 @@ QStringList configuredDomainIds() const FileProviderDomainManager::~FileProviderDomainManager() = default; +void FileProviderDomainManager::start() +{ + ConfigFile cfg; + std::chrono::milliseconds polltime = cfg.remotePollInterval(); + _enumeratorSignallingTimer.setInterval(polltime.count()); + connect(&_enumeratorSignallingTimer, &QTimer::timeout, + this, &FileProviderDomainManager::slotEnumeratorSignallingTimerTimeout); + _enumeratorSignallingTimer.start(); + + setupFileProviderDomains(); + + connect(AccountManager::instance(), &AccountManager::accountAdded, + this, &FileProviderDomainManager::addFileProviderDomainForAccount); + // If an account is deleted from the client, accountSyncConnectionRemoved will be + // emitted first. So we treat accountRemoved as only being relevant to client + // shutdowns. + connect(AccountManager::instance(), &AccountManager::accountSyncConnectionRemoved, + this, &FileProviderDomainManager::removeFileProviderDomainForAccount); + connect(AccountManager::instance(), &AccountManager::accountRemoved, + this, [this](const AccountState * const accountState) { + const auto trReason = tr("%1 application has been closed. Reopen to reconnect.").arg(APPLICATION_NAME); + disconnectFileProviderDomainForAccount(accountState, trReason); + }); +} + void FileProviderDomainManager::setupFileProviderDomains() { if (!d) { From 45b123130f5b186709d13f19030810ff18b2a88f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 23 Jan 2024 18:20:34 +0800 Subject: [PATCH 45/52] Separate XPC init from file provider constructor Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovider.h | 3 +++ src/gui/macOS/fileprovider_mac.mm | 21 +++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/gui/macOS/fileprovider.h b/src/gui/macOS/fileprovider.h index a6a2466709af3..e9d89b7a5ba8a 100644 --- a/src/gui/macOS/fileprovider.h +++ b/src/gui/macOS/fileprovider.h @@ -39,6 +39,9 @@ class FileProvider : public QObject static bool fileProviderAvailable(); +private slots: + void configureXPC(); + private: std::unique_ptr _domainManager; std::unique_ptr _socketServer; diff --git a/src/gui/macOS/fileprovider_mac.mm b/src/gui/macOS/fileprovider_mac.mm index 2ac897735f347..922be29fe6f28 100644 --- a/src/gui/macOS/fileprovider_mac.mm +++ b/src/gui/macOS/fileprovider_mac.mm @@ -58,14 +58,7 @@ qCDebug(lcMacFileProvider) << "Initialised file provider socket server."; } - _xpc = std::make_unique(new FileProviderXPC(this)); - if (_xpc) { - qCInfo(lcMacFileProvider) << "Initialised file provider XPC."; - _xpc->connectToExtensions(); - _xpc->configureExtensions(); - } else { - qCWarning(lcMacFileProvider) << "Could not initialise file provider XPC."; - } + configureXPC(); } FileProvider *FileProvider::instance() @@ -98,5 +91,17 @@ return false; } +void FileProvider::configureXPC() +{ + _xpc = std::make_unique(new FileProviderXPC(this)); + if (_xpc) { + qCInfo(lcMacFileProvider) << "Initialised file provider XPC."; + _xpc->connectToExtensions(); + _xpc->configureExtensions(); + } else { + qCWarning(lcMacFileProvider) << "Could not initialise file provider XPC."; + } +} + } // namespace Mac } // namespace OCC From a01e55272a2e4433646791198d89bc29e41c362f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 23 Jan 2024 18:20:55 +0800 Subject: [PATCH 46/52] Only start XPC after file provider domains have been configured Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovider_mac.mm | 5 ++--- src/gui/macOS/fileproviderdomainmanager.h | 3 +++ src/gui/macOS/fileproviderdomainmanager_mac.mm | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/fileprovider_mac.mm b/src/gui/macOS/fileprovider_mac.mm index 922be29fe6f28..f45b915569467 100644 --- a/src/gui/macOS/fileprovider_mac.mm +++ b/src/gui/macOS/fileprovider_mac.mm @@ -47,18 +47,17 @@ _domainManager = std::make_unique(this); if (_domainManager) { + connect(_domainManager.get(), &FileProviderDomainManager::domainSetupComplete, this, &FileProvider::configureXPC); _domainManager->start(); qCDebug(lcMacFileProvider()) << "Initialized file provider domain manager"; } qCDebug(lcMacFileProvider) << "Initialising file provider socket server."; - _socketServer = std::make_unique(new FileProviderSocketServer(this)); + _socketServer = std::make_unique(this); if (_socketServer) { qCDebug(lcMacFileProvider) << "Initialised file provider socket server."; } - - configureXPC(); } FileProvider *FileProvider::instance() diff --git a/src/gui/macOS/fileproviderdomainmanager.h b/src/gui/macOS/fileproviderdomainmanager.h index e27fdf7c60fb3..33347dc5e1a30 100644 --- a/src/gui/macOS/fileproviderdomainmanager.h +++ b/src/gui/macOS/fileproviderdomainmanager.h @@ -35,6 +35,9 @@ class FileProviderDomainManager : public QObject static AccountStatePtr accountStateFromFileProviderDomainIdentifier(const QString &domainIdentifier); void start(); +signals: + void domainSetupComplete(); + private slots: void setupFileProviderDomains(); diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm index bbc0568120be8..d6c9acda6dc4b 100644 --- a/src/gui/macOS/fileproviderdomainmanager_mac.mm +++ b/src/gui/macOS/fileproviderdomainmanager_mac.mm @@ -450,6 +450,8 @@ QStringList configuredDomainIds() const for(auto &accountState : AccountManager::instance()->accounts()) { addFileProviderDomainForAccount(accountState.data()); } + + emit domainSetupComplete(); } void FileProviderDomainManager::addFileProviderDomainForAccount(const AccountState * const accountState) From a44454daf8bf08035fceb5714de0407f238dd627 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 23 Jan 2024 22:24:36 +0800 Subject: [PATCH 47/52] Simplify and clarify utility of socket system for file provider Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersocketcontroller.cpp | 13 +++++++++++-- src/gui/macOS/fileprovidersocketserver.h | 13 +++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileprovidersocketcontroller.cpp b/src/gui/macOS/fileprovidersocketcontroller.cpp index 4790123e35de7..68de9637068ab 100644 --- a/src/gui/macOS/fileprovidersocketcontroller.cpp +++ b/src/gui/macOS/fileprovidersocketcontroller.cpp @@ -112,7 +112,6 @@ void FileProviderSocketController::sendMessage(const QString &message) const } } - void FileProviderSocketController::start() { Q_ASSERT(_socket); @@ -121,6 +120,12 @@ void FileProviderSocketController::start() return; } + /* + * We have a new file provider extension connection. When this happens, we: + * 1. Request the file provider domain identifier + * 2. Receive the file provider domain identifier from the extension + * 3. Send the account details to the extension according to the domain identifier + */ requestFileProviderDomainInfo(); } @@ -181,7 +186,11 @@ void FileProviderSocketController::sendAccountDetails() const qCDebug(lcFileProviderSocketController) << "About to send account details to file provider extension" << account->displayName(); - connect(_accountState.data(), &AccountState::stateChanged, this, &FileProviderSocketController::slotAccountStateChanged, Qt::UniqueConnection); + // Even though we have XPC send over the account details and related calls when the account state changes, in the + // brief window where we start the file provider extension on app startup and the account state changes, we need to + // be able to send over the details when the account is done getting configured. + connect(_accountState.data(), &AccountState::stateChanged, + this, &FileProviderSocketController::slotAccountStateChanged, Qt::UniqueConnection); if (!_accountState->isConnected()) { qCDebug(lcFileProviderSocketController) << "Not sending account details yet as account is not connected" diff --git a/src/gui/macOS/fileprovidersocketserver.h b/src/gui/macOS/fileprovidersocketserver.h index 893de666e5a46..e650e0ca2b4ac 100644 --- a/src/gui/macOS/fileprovidersocketserver.h +++ b/src/gui/macOS/fileprovidersocketserver.h @@ -26,6 +26,19 @@ using FileProviderSocketControllerPtr = QPointer; QString fileProviderSocketPath(); +/* + * Establishes communication between the app and the file provider extension. + * This is done via a local socket server. + * Note that this should be used for extension->client communication. + * + * We can communicate bidirectionally, but the File Provider XPC API is a better interface for this as we cannot account + * for the lifetime of a file provider extension when using sockets, and cannot control this on the client side. + * Use FileProviderXPC for client->extension communication when possible. + * + * This socket system is critical for the file provider extensions to be able to request authentication details. + * + * TODO: This should rewritten to use XPC instead of sockets + */ class FileProviderSocketServer : public QObject { Q_OBJECT From 41133e4cd8f5be9646f5526d67ff08234ec4392c Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 23 Jan 2024 22:25:27 +0800 Subject: [PATCH 48/52] Clarify utility of xpc system for file provider Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index 79613edaca295..25efb05ad2894 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -21,6 +21,12 @@ namespace OCC::Mac { +/* + * Establishes communication between the app and the file provider extension. + * This is done via File Provider's XPC services API. + * Note that this is for client->extension communication, not the other way around. + * This is because the extension does not have a way to communicate with the client through the File Provider XPC API + */ class FileProviderXPC : public QObject { Q_OBJECT From b22f463ad59db19910d3c154718225931e8098bb Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 23 Jan 2024 22:37:49 +0800 Subject: [PATCH 49/52] Add explainer to client interface Signed-off-by: Claudio Cambra --- .../FileProviderExtension+ClientInterface.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift index 37bbb0fdb73af..aebb6ab012b62 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift @@ -19,6 +19,20 @@ import NextcloudKit import OSLog extension FileProviderExtension: NSFileProviderServicing { + /* + This FileProviderExtension extension contains everything needed to communicate with the client. + We have two systems for communicating between the extensions and the client. + + Apple's XPC based File Provider APIs let us easily communicate client -> extension. + This is what ClientCommunicationService is for. + + We also use sockets, because the File Provider XPC system does not let us easily talk from + extension->client. + We need this because the extension needs to be able to request account details. We can't + reliably do this via XPC because the extensions get torn down by the system, out of the control + of the app, and we can receive nil/no services from NSFileProviderManager. Once this is done + then XPC works ok. + */ func supportedServiceSources( for itemIdentifier: NSFileProviderItemIdentifier, completionHandler: @escaping ([NSFileProviderServiceSource]?, Error?) -> Void From 9611e47a3b665057448e840c0b4e73c8eface303 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 23 Jan 2024 22:58:11 +0800 Subject: [PATCH 50/52] Simplify xpc service acquisition completion handler Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac_utils.mm | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac_utils.mm b/src/gui/macOS/fileproviderxpc_mac_utils.mm index da1d9a6316dc7..eb385d1c42858 100644 --- a/src/gui/macOS/fileproviderxpc_mac_utils.mm +++ b/src/gui/macOS/fileproviderxpc_mac_utils.mm @@ -45,6 +45,7 @@ for (NSFileProviderDomain *const domain in domains) { qCInfo(lcFileProviderXPCUtils) << "Got domain" << domain.identifier; NSFileProviderManager *const manager = [NSFileProviderManager managerForDomain:domain]; + [manager retain]; [managers addObject:manager]; } @@ -68,23 +69,18 @@ dispatch_group_t group = dispatch_group_create(); for (NSFileProviderManager *const manager in managers) { - __block NSFileProviderService *acquiredService; dispatch_group_enter(group); [manager getServiceWithName:nsClientCommunicationServiceName itemIdentifier:NSFileProviderRootContainerItemIdentifier completionHandler:^(NSFileProviderService *const service, NSError *const error) { if (error != nil) { qCWarning(lcFileProviderXPCUtils) << "Error getting file provider service" << error; - dispatch_group_leave(group); - return; } else if (service == nil) { qCWarning(lcFileProviderXPCUtils) << "Service is nil"; - dispatch_group_leave(group); - return; + } else { + [service retain]; + [fpServices addObject:@{service.name: service}]; } - - [service retain]; - [fpServices addObject:@{acquiredService.name: acquiredService}]; dispatch_group_leave(group); }]; dispatch_group_wait(group, DISPATCH_TIME_FOREVER); From 71119fe65ab709682d3eabbd9dfd16dc60f617fd Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jan 2024 13:38:28 +0800 Subject: [PATCH 51/52] Improve socket controller logging Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersocketcontroller.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gui/macOS/fileprovidersocketcontroller.cpp b/src/gui/macOS/fileprovidersocketcontroller.cpp index 68de9637068ab..032ac22275031 100644 --- a/src/gui/macOS/fileprovidersocketcontroller.cpp +++ b/src/gui/macOS/fileprovidersocketcontroller.cpp @@ -101,7 +101,7 @@ void FileProviderSocketController::sendMessage(const QString &message) const return; } - qCDebug(lcFileProviderSocketController) << "Sending File Provider socket message:" << message; + qCInfo(lcFileProviderSocketController) << "Sending File Provider socket message:" << message; const auto lineEndChar = '\n'; const auto messageToSend = message.endsWith(lineEndChar) ? message : message + lineEndChar; const auto bytesToSend = messageToSend.toUtf8(); @@ -183,8 +183,8 @@ void FileProviderSocketController::sendAccountDetails() const const auto account = _accountState->account(); Q_ASSERT(account); - qCDebug(lcFileProviderSocketController) << "About to send account details to file provider extension" - << account->displayName(); + qCInfo(lcFileProviderSocketController) << "About to send account details to file provider extension" + << account->displayName(); // Even though we have XPC send over the account details and related calls when the account state changes, in the // brief window where we start the file provider extension on app startup and the account state changes, we need to @@ -193,8 +193,8 @@ void FileProviderSocketController::sendAccountDetails() const this, &FileProviderSocketController::slotAccountStateChanged, Qt::UniqueConnection); if (!_accountState->isConnected()) { - qCDebug(lcFileProviderSocketController) << "Not sending account details yet as account is not connected" - << account->displayName(); + qCWarning(lcFileProviderSocketController) << "Not sending account details yet as account is not connected" + << account->displayName(); return; } From 3334b4e49c3d4392cfdc9f510bd31eb59018fd22 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jan 2024 13:38:55 +0800 Subject: [PATCH 52/52] Do not reconfigure file provider extension account if we are receiving the same details again Signed-off-by: Claudio Cambra --- .../FileProviderExtension+ClientInterface.swift | 6 ++++-- .../FileProviderExt/NextcloudAccount.swift | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift index aebb6ab012b62..a357b79eae20a 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift @@ -88,7 +88,9 @@ extension FileProviderExtension: NSFileProviderServicing { } @objc func setupDomainAccount(user: String, serverUrl: String, password: String) { - ncAccount = NextcloudAccount(user: user, serverUrl: serverUrl, password: password) + let newNcAccount = NextcloudAccount(user: user, serverUrl: serverUrl, password: password) + guard newNcAccount != ncAccount else { return } + ncAccount = newNcAccount ncKit.setup( user: ncAccount!.username, userId: ncAccount!.username, @@ -96,7 +98,7 @@ extension FileProviderExtension: NSFileProviderServicing { urlBase: ncAccount!.serverUrl, userAgent: "Nextcloud-macOS/FileProviderExt", nextcloudVersion: 25, - delegate: nil) // TODO: add delegate methods for self + delegate: nil) // TODO: add delegate methods for self Logger.fileProviderExtension.info( "Nextcloud account set up in File Provider extension for user: \(user, privacy: .public) at server: \(serverUrl, privacy: .public)" diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/NextcloudAccount.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/NextcloudAccount.swift index 9e5b64656608d..cb3b7ea628f9c 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/NextcloudAccount.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/NextcloudAccount.swift @@ -15,7 +15,7 @@ import FileProvider import Foundation -class NextcloudAccount: NSObject { +struct NextcloudAccount: Equatable { static let webDavFilesUrlSuffix: String = "/remote.php/dav/files/" let username, password, ncKitAccount, serverUrl, davFilesUrl: String @@ -25,7 +25,5 @@ class NextcloudAccount: NSObject { ncKitAccount = user + " " + serverUrl self.serverUrl = serverUrl davFilesUrl = serverUrl + NextcloudAccount.webDavFilesUrlSuffix + user - - super.init() } }