Revert "Merge pull request #5527 from nextcloud/feature/file-provider-try-2"
authorClaudio Cambra <claudio.cambra@nextcloud.com>
Tue, 6 Jun 2023 14:01:52 +0000 (22:01 +0800)
committerClaudio Cambra <developer@claudiocambra.com>
Wed, 7 Jun 2023 10:00:56 +0000 (18:00 +0800)
This reverts commit c4d12115a9a9fd9c10627c434f16d7f280d82ca9, reversing
changes made to 9b77da6569ec49b8a14db8f5df367a7948f34702.

Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
74 files changed:
.gitignore
CMakeLists.txt
shell_integration/MacOSX/CMakeLists.txt
shell_integration/MacOSX/Nextcloud.xcworkspace/contents.xcworkspacedata [deleted file]
shell_integration/MacOSX/Nextcloud.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist [deleted file]
shell_integration/MacOSX/Nextcloud.xcworkspace/xcshareddata/OwnCloud.xccheckout [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager+Directories.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager+LocalFiles.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudItemMetadataTable+NKFile.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudItemMetadataTable.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudLocalFileMetadataTable.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/NKError+Extensions.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Progress+Extensions.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator+SyncEngine.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExt.entitlements [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+Thumbnailing.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderItem.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderMaterialisedEnumerationObserver.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderSocketLineProcessor.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Info.plist [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/LocalFilesUtils.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/NextcloudAccount.swift [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.h [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.m [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSyncExt.entitlements [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSyncSocketLineProcessor.h [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSyncSocketLineProcessor.m [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/Info.plist [deleted file]
shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/SyncClient.h [deleted file]
shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/LineProcessor.h [deleted file]
shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/LocalSocketClient.h [deleted file]
shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/LocalSocketClient.m [deleted file]
shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/NCDesktopClientSocketKit.h [deleted file]
shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj [deleted file]
shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata [deleted file]
shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist [deleted file]
shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/xcshareddata/xcschemes/FinderSyncExt.xcscheme [deleted file]
shell_integration/MacOSX/NextcloudIntegration/desktopclient/Info.plist [deleted file]
shell_integration/MacOSX/NextcloudIntegration/desktopclient/main.m [deleted file]
shell_integration/MacOSX/OwnCloud.xcworkspace/contents.xcworkspacedata [new file with mode: 0644]
shell_integration/MacOSX/OwnCloud.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist [new file with mode: 0644]
shell_integration/MacOSX/OwnCloud.xcworkspace/xcshareddata/OwnCloud.xccheckout [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/FinderSync.h [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/FinderSync.m [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/FinderSyncExt.entitlements [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/Info.plist [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LineProcessor.h [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LineProcessor.m [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LocalSocketClient.h [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LocalSocketClient.m [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/SyncClient.h [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj/project.pbxproj [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj/xcshareddata/xcschemes/FinderSyncExt.xcscheme [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/desktopclient/Info.plist [new file with mode: 0644]
shell_integration/MacOSX/OwnCloudFinderSync/desktopclient/main.m [new file with mode: 0644]
src/gui/CMakeLists.txt
src/gui/application.cpp
src/gui/application.h
src/gui/macOS/fileprovider.h [deleted file]
src/gui/macOS/fileprovider_mac.mm [deleted file]
src/gui/macOS/fileproviderdomainmanager.h [deleted file]
src/gui/macOS/fileproviderdomainmanager_mac.mm [deleted file]
src/gui/macOS/fileprovidersocketcontroller.cpp [deleted file]
src/gui/macOS/fileprovidersocketcontroller.h [deleted file]
src/gui/macOS/fileprovidersocketserver.cpp [deleted file]
src/gui/macOS/fileprovidersocketserver.h [deleted file]
src/gui/macOS/fileprovidersocketserver_mac.mm [deleted file]
src/libsync/configfile.cpp
src/libsync/configfile.h

index 85a87ed91464e2f5c5e003d552db89f43034b5d5..249c4a2c7c346f5c45b96fa8390bb59e0b7a8129 100644 (file)
@@ -88,7 +88,6 @@ dlldata.c
 # macOS specific
 xcuserdata/
 **/.DS_Store
-**/Carthage/
 
 # Visual C++ cache files
 ipch/
index d38c8169c5b26248205d5dd108dd37e0f97611d1..ba0195b57efd5c6733d84571878b8383b15e3ac1 100644 (file)
@@ -187,11 +187,6 @@ else()
     unset(CMAKE_CXX_CLANG_TIDY)
 endif()
 
-if (APPLE)
-    # build macOS File Provider module
-    option(BUILD_FILE_PROVIDER_MODULE "BUILD_FILE_PROVIDER_MODULE" ON)
-endif()
-
 # When this option is enabled, 5xx errors are not added to the blacklist
 # Normally you don't want to enable this option because if a particular file
 # triggers a bug on the server, you want the file to be blacklisted.
index 85d901920db6d4dacec306e779429d0238e7c01a..99116c76d987b950888ff7418420265ee4644cd3 100644 (file)
@@ -1,55 +1,26 @@
 if(APPLE)
-    set(OC_OEM_SHARE_ICNS "${CMAKE_BINARY_DIR}/src/gui/${APPLICATION_ICON_NAME}.icns")
+  set(OC_OEM_SHARE_ICNS "${CMAKE_BINARY_DIR}/src/gui/${APPLICATION_ICON_NAME}.icns")
 
-    if (CMAKE_BUILD_TYPE MATCHES "Debug" OR CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
-        set(XCODE_TARGET_CONFIGURATION "Debug")
-    else()
-        set(XCODE_TARGET_CONFIGURATION "Release")
-    endif()
+  # The bundle identifier and application group need to have compatible values with the client
+  # to be able to open a Mach port across the extension's sandbox boundary.
+  # Pass the info through the xcodebuild command line and make sure that the project uses
+  # those user-defined settings to build the plist.
+  add_custom_target( mac_overlayplugin ALL
+    xcodebuild ARCHS=${CMAKE_OSX_ARCHITECTURES} ONLY_ACTIVE_ARCH=NO
+    -project ${CMAKE_SOURCE_DIR}/shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj
+    -target FinderSyncExt -configuration Release "SYMROOT=${CMAKE_CURRENT_BINARY_DIR}"
+    "OC_OEM_SHARE_ICNS=${OC_OEM_SHARE_ICNS}"
+    "OC_APPLICATION_NAME=${APPLICATION_NAME}"
+    "OC_APPLICATION_REV_DOMAIN=${APPLICATION_REV_DOMAIN}"
+    "OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}"
+    COMMENT building Mac Overlay icons
+    VERBATIM)
+  add_dependencies(mac_overlayplugin nextcloud) # for the ownCloud.icns to be generated
 
-    # The bundle identifier and application group need to have compatible values with the client
-    # to be able to open a Mach port across the extension's sandbox boundary.
-    # Pass the info through the xcodebuild command line and make sure that the project uses
-    # those user-defined settings to build the plist.
-    add_custom_target( mac_overlayplugin ALL
-        xcodebuild ARCHS=${CMAKE_OSX_ARCHITECTURES} ONLY_ACTIVE_ARCH=NO
-        -project ${CMAKE_SOURCE_DIR}/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj
-        -target FinderSyncExt -configuration ${XCODE_TARGET_CONFIGURATION} "SYMROOT=${CMAKE_CURRENT_BINARY_DIR}"
-        "OC_OEM_SHARE_ICNS=${OC_OEM_SHARE_ICNS}"
-        "OC_APPLICATION_NAME=${APPLICATION_NAME}"
-        "OC_APPLICATION_REV_DOMAIN=${APPLICATION_REV_DOMAIN}"
-        "OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}"
-        COMMENT building Mac Overlay icons
-        VERBATIM)
-
-    if (BUILD_FILE_PROVIDER_MODULE)
-        add_custom_target( mac_fileproviderplugin ALL
-            xcodebuild ARCHS=${CMAKE_OSX_ARCHITECTURES} ONLY_ACTIVE_ARCH=NO
-            -project ${CMAKE_SOURCE_DIR}/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj
-            -target FileProviderExt -configuration ${XCODE_TARGET_CONFIGURATION} "SYMROOT=${CMAKE_CURRENT_BINARY_DIR}"
-            "OC_APPLICATION_EXECUTABLE_NAME=${APPLICATION_EXECUTABLE}"
-            "OC_APPLICATION_VENDOR=${APPLICATION_VENDOR}"
-            "OC_APPLICATION_NAME=${APPLICATION_NAME}"
-            "OC_APPLICATION_REV_DOMAIN=${APPLICATION_REV_DOMAIN}"
-            "OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}"
-            COMMENT building macOS File Provider extension
-            VERBATIM)
-
-        add_dependencies(mac_overlayplugin mac_fileproviderplugin nextcloud) # for the ownCloud.icns to be generated
-    else()
-        add_dependencies(mac_overlayplugin nextcloud) # for the ownCloud.icns to be generated
-    endif()
-
-    if (BUILD_OWNCLOUD_OSX_BUNDLE)
-        install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Release/FinderSyncExt.appex
-            DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/PlugIns
-            USE_SOURCE_PERMISSIONS)
-
-        if (BUILD_FILE_PROVIDER_MODULE)
-            install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Release/FileProviderExt.appex
-                DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/PlugIns
-                USE_SOURCE_PERMISSIONS)
-        endif()
-    endif()
+  if (BUILD_OWNCLOUD_OSX_BUNDLE)
+    install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Release/FinderSyncExt.appex
+      DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/PlugIns
+      USE_SOURCE_PERMISSIONS)
+  endif()
 endif()
 
diff --git a/shell_integration/MacOSX/Nextcloud.xcworkspace/contents.xcworkspacedata b/shell_integration/MacOSX/Nextcloud.xcworkspace/contents.xcworkspacedata
deleted file mode 100644 (file)
index ed78110..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "group:NextcloudIntegration/NextcloudIntegration.xcodeproj">
-   </FileRef>
-</Workspace>
diff --git a/shell_integration/MacOSX/Nextcloud.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/shell_integration/MacOSX/Nextcloud.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
deleted file mode 100644 (file)
index 18d9810..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>IDEDidComputeMac32BitWarning</key>
-       <true/>
-</dict>
-</plist>
diff --git a/shell_integration/MacOSX/Nextcloud.xcworkspace/xcshareddata/OwnCloud.xccheckout b/shell_integration/MacOSX/Nextcloud.xcworkspace/xcshareddata/OwnCloud.xccheckout
deleted file mode 100644 (file)
index 9512111..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>IDESourceControlProjectFavoriteDictionaryKey</key>
-       <false/>
-       <key>IDESourceControlProjectIdentifier</key>
-       <string>5264E8F5-AB49-45F3-868F-647EEFAB70E0</string>
-       <key>IDESourceControlProjectName</key>
-       <string>OwnCloud</string>
-       <key>IDESourceControlProjectOriginsDictionary</key>
-       <dict>
-               <key>D67321A19EF879CA55BF889202BA8C23AC9AA2B5</key>
-               <string>ssh://github.com/owncloud/client.git</string>
-       </dict>
-       <key>IDESourceControlProjectPath</key>
-       <string>shell_integration/MacOSX/OwnCloud.xcworkspace</string>
-       <key>IDESourceControlProjectRelativeInstallPathDictionary</key>
-       <dict>
-               <key>D67321A19EF879CA55BF889202BA8C23AC9AA2B5</key>
-               <string>../../..</string>
-       </dict>
-       <key>IDESourceControlProjectURL</key>
-       <string>ssh://github.com/owncloud/client.git</string>
-       <key>IDESourceControlProjectVersion</key>
-       <integer>111</integer>
-       <key>IDESourceControlProjectWCCIdentifier</key>
-       <string>D67321A19EF879CA55BF889202BA8C23AC9AA2B5</string>
-       <key>IDESourceControlProjectWCConfigurations</key>
-       <array>
-               <dict>
-                       <key>IDESourceControlRepositoryExtensionIdentifierKey</key>
-                       <string>public.vcs.git</string>
-                       <key>IDESourceControlWCCIdentifierKey</key>
-                       <string>D67321A19EF879CA55BF889202BA8C23AC9AA2B5</string>
-                       <key>IDESourceControlWCCName</key>
-                       <string>client</string>
-               </dict>
-       </array>
-</dict>
-</plist>
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager+Directories.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager+Directories.swift
deleted file mode 100644 (file)
index 386791e..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import OSLog
-
-extension NextcloudFilesDatabaseManager {
-    func directoryMetadata(account: String, serverUrl: String) -> NextcloudItemMetadataTable? {
-        // We want to split by "/" (e.g. cloud.nc.com/files/a/b) but we need to be mindful of "https://c.nc.com"
-        let problematicSeparator = "://"
-        let placeholderSeparator = "__TEMP_REPLACE__"
-        let serverUrlWithoutPrefix = serverUrl.replacingOccurrences(of: problematicSeparator, with: placeholderSeparator)
-        var splitServerUrl = serverUrlWithoutPrefix.split(separator: "/")
-        let directoryItemFileName = String(splitServerUrl.removeLast())
-        let directoryItemServerUrl = splitServerUrl.joined(separator: "/").replacingOccurrences(of: placeholderSeparator, with: problematicSeparator)
-
-        if let metadata = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@ AND directory == true", account, directoryItemServerUrl, directoryItemFileName).first {
-            return NextcloudItemMetadataTable(value: metadata)
-        }
-
-        return nil
-    }
-
-    func childItemsForDirectory(_ directoryMetadata: NextcloudItemMetadataTable) -> [NextcloudItemMetadataTable] {
-        let directoryServerUrl = directoryMetadata.serverUrl + "/" + directoryMetadata.fileName
-        let metadatas = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("serverUrl BEGINSWITH %@", directoryServerUrl)
-        return sortedItemMetadatas(metadatas)
-    }
-
-    func childDirectoriesForDirectory(_ directoryMetadata: NextcloudItemMetadataTable) -> [NextcloudItemMetadataTable] {
-        let directoryServerUrl = directoryMetadata.serverUrl + "/" + directoryMetadata.fileName
-        let metadatas = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("serverUrl BEGINSWITH %@ AND directory == true", directoryServerUrl)
-        return sortedItemMetadatas(metadatas)
-    }
-
-    func parentDirectoryMetadataForItem(_ itemMetadata: NextcloudItemMetadataTable) -> NextcloudItemMetadataTable? {
-        return directoryMetadata(account: itemMetadata.account, serverUrl: itemMetadata.serverUrl)
-    }
-
-    func directoryMetadata(ocId: String) -> NextcloudItemMetadataTable? {
-        if let metadata = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("ocId == %@ AND directory == true", ocId).first {
-            return NextcloudItemMetadataTable(value: metadata)
-        }
-
-        return nil
-    }
-
-    func directoryMetadatas(account: String) -> [NextcloudItemMetadataTable] {
-        let metadatas = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("account == %@ AND directory == true", account)
-        return sortedItemMetadatas(metadatas)
-    }
-
-    func directoryMetadatas(account: String, parentDirectoryServerUrl: String) -> [NextcloudItemMetadataTable] {
-        let metadatas = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("account == %@ AND parentDirectoryServerUrl == %@ AND directory == true", account, parentDirectoryServerUrl)
-        return sortedItemMetadatas(metadatas)
-    }
-
-    // Deletes all metadatas related to the info of the directory provided
-    func deleteDirectoryAndSubdirectoriesMetadata(ocId: String) -> [NextcloudItemMetadataTable]? {
-        let database = ncDatabase()
-        guard let directoryMetadata = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@ AND directory == true", ocId).first else {
-            Logger.ncFilesDatabase.error("Could not find directory metadata for ocId \(ocId, privacy: .public). Not proceeding with deletion")
-            return nil
-        }
-
-        let directoryMetadataCopy = NextcloudItemMetadataTable(value: directoryMetadata)
-        let directoryUrlPath = directoryMetadata.serverUrl + "/" + directoryMetadata.fileName
-        let directoryAccount = directoryMetadata.account
-        let directoryEtag = directoryMetadata.etag
-
-        Logger.ncFilesDatabase.debug("Deleting root directory metadata in recursive delete. ocID: \(directoryMetadata.ocId, privacy: .public), etag: \(directoryEtag, privacy: .public), serverUrl: \(directoryUrlPath, privacy: .public)")
-
-        guard deleteItemMetadata(ocId: directoryMetadata.ocId) else {
-            Logger.ncFilesDatabase.debug("Failure to delete root directory metadata in recursive delete. ocID: \(directoryMetadata.ocId, privacy: .public), etag: \(directoryEtag, privacy: .public), serverUrl: \(directoryUrlPath, privacy: .public)")
-            return nil
-        }
-
-        var deletedMetadatas: [NextcloudItemMetadataTable] = [directoryMetadataCopy]
-
-        let results = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryAccount, directoryUrlPath)
-
-        for result in results {
-            let successfulItemMetadataDelete = deleteItemMetadata(ocId: result.ocId)
-            if (successfulItemMetadataDelete) {
-                deletedMetadatas.append(NextcloudItemMetadataTable(value: result))
-            }
-
-            if localFileMetadataFromOcId(result.ocId) != nil {
-                deleteLocalFileMetadata(ocId: result.ocId)
-            }
-        }
-
-        Logger.ncFilesDatabase.debug("Completed deletions in directory recursive delete. ocID: \(directoryMetadata.ocId, privacy: .public), etag: \(directoryEtag, privacy: .public), serverUrl: \(directoryUrlPath, privacy: .public)")
-
-        return deletedMetadatas
-    }
-
-    func renameDirectoryAndPropagateToChildren(ocId: String, newServerUrl: String, newFileName: String) -> [NextcloudItemMetadataTable]? {
-
-        let database = ncDatabase()
-
-        guard let directoryMetadata = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@ AND directory == true", ocId).first else {
-            Logger.ncFilesDatabase.error("Could not find a directory with ocID \(ocId, privacy: .public), cannot proceed with recursive renaming")
-            return nil
-        }
-
-        let oldItemServerUrl = directoryMetadata.serverUrl
-        let oldDirectoryServerUrl = oldItemServerUrl + "/" + directoryMetadata.fileName
-        let newDirectoryServerUrl = newServerUrl + "/" + newFileName
-        let childItemResults = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryMetadata.account, oldDirectoryServerUrl)
-
-        renameItemMetadata(ocId: ocId, newServerUrl: newServerUrl, newFileName: newFileName)
-        Logger.ncFilesDatabase.debug("Renamed root renaming directory")
-
-        do {
-            try database.write {
-                for childItem in childItemResults {
-                    let oldServerUrl = childItem.serverUrl
-                    let movedServerUrl = oldServerUrl.replacingOccurrences(of: oldDirectoryServerUrl, with: newDirectoryServerUrl)
-                    childItem.serverUrl = movedServerUrl
-                    database.add(childItem, update: .all)
-                    Logger.ncFilesDatabase.debug("Moved childItem at \(oldServerUrl) to \(movedServerUrl)")
-                }
-            }
-        } catch let error {
-            Logger.ncFilesDatabase.error("Could not rename directory metadata with ocId: \(ocId, privacy: .public) to new serverUrl: \(newServerUrl), received error: \(error.localizedDescription, privacy: .public)")
-
-            return nil
-        }
-
-        let updatedChildItemResults = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryMetadata.account, newDirectoryServerUrl)
-        return sortedItemMetadatas(updatedChildItemResults)
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager+LocalFiles.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager+LocalFiles.swift
deleted file mode 100644 (file)
index 2241d20..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import RealmSwift
-import OSLog
-
-extension NextcloudFilesDatabaseManager {
-    func localFileMetadataFromOcId(_ ocId: String) -> NextcloudLocalFileMetadataTable? {
-        if let metadata = ncDatabase().objects(NextcloudLocalFileMetadataTable.self).filter("ocId == %@", ocId).first {
-            return NextcloudLocalFileMetadataTable(value: metadata)
-        }
-
-        return nil
-    }
-
-    func addLocalFileMetadataFromItemMetadata(_ itemMetadata: NextcloudItemMetadataTable) {
-        let database = ncDatabase()
-
-        do {
-            try database.write {
-                let newLocalFileMetadata = NextcloudLocalFileMetadataTable()
-
-                newLocalFileMetadata.ocId = itemMetadata.ocId
-                newLocalFileMetadata.fileName = itemMetadata.fileName
-                newLocalFileMetadata.account = itemMetadata.account
-                newLocalFileMetadata.etag = itemMetadata.etag
-                newLocalFileMetadata.exifDate = Date()
-                newLocalFileMetadata.exifLatitude = "-1"
-                newLocalFileMetadata.exifLongitude = "-1"
-
-                database.add(newLocalFileMetadata, update: .all)
-                Logger.ncFilesDatabase.debug("Added local file metadata from item metadata. ocID: \(itemMetadata.ocId, privacy: .public), etag: \(itemMetadata.etag, privacy: .public), fileName: \(itemMetadata.fileName, privacy: .public)")
-            }
-        } catch let error {
-            Logger.ncFilesDatabase.error("Could not add local file metadata from item metadata. ocID: \(itemMetadata.ocId, privacy: .public), etag: \(itemMetadata.etag, privacy: .public), fileName: \(itemMetadata.fileName, privacy: .public), received error: \(error.localizedDescription, privacy: .public)")
-        }
-    }
-
-    func deleteLocalFileMetadata(ocId: String) {
-        let database = ncDatabase()
-
-        do {
-            try database.write {
-                let results = database.objects(NextcloudLocalFileMetadataTable.self).filter("ocId == %@", ocId)
-                database.delete(results)
-            }
-        } catch let error {
-            Logger.ncFilesDatabase.error("Could not delete local file metadata with ocId: \(ocId, privacy: .public), received error: \(error.localizedDescription, privacy: .public)")
-        }
-    }
-
-    private func sortedLocalFileMetadatas(_ metadatas: Results<NextcloudLocalFileMetadataTable>) -> [NextcloudLocalFileMetadataTable] {
-        let sortedMetadatas = metadatas.sorted(byKeyPath: "fileName", ascending: true)
-        return Array(sortedMetadatas.map { NextcloudLocalFileMetadataTable(value: $0) })
-    }
-
-    func localFileMetadatas(account: String) -> [NextcloudLocalFileMetadataTable] {
-        let results = ncDatabase().objects(NextcloudLocalFileMetadataTable.self).filter("account == %@", account)
-        return sortedLocalFileMetadatas(results)
-    }
-
-    func localFileItemMetadatas(account: String) -> [NextcloudItemMetadataTable] {
-        let localFileMetadatas = localFileMetadatas(account: account)
-        let localFileMetadatasOcIds = Array(localFileMetadatas.map { $0.ocId })
-
-        var itemMetadatas: [NextcloudItemMetadataTable] = []
-
-        for ocId in localFileMetadatasOcIds {
-            guard let itemMetadata = itemMetadataFromOcId(ocId) else {
-                Logger.ncFilesDatabase.error("Could not find matching item metadata for local file metadata with ocId: \(ocId, privacy: .public) with request from account: \(account)")
-                continue;
-            }
-
-            itemMetadatas.append(NextcloudItemMetadataTable(value: itemMetadata))
-        }
-
-        return itemMetadatas
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager.swift
deleted file mode 100644 (file)
index 158f281..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import RealmSwift
-import FileProvider
-import NextcloudKit
-import OSLog
-
-class NextcloudFilesDatabaseManager : NSObject {
-    static let shared = {
-        return NextcloudFilesDatabaseManager();
-    }()
-
-    let relativeDatabaseFolderPath = "Database/"
-    let databaseFilename = "fileproviderextdatabase.realm"
-    let relativeDatabaseFilePath: String
-    var databasePath: URL?
-
-    let schemaVersion: UInt64 = 100
-
-    override init() {
-        self.relativeDatabaseFilePath = self.relativeDatabaseFolderPath + self.databaseFilename
-
-        guard let fileProviderDataDirUrl = pathForFileProviderExtData() else {
-            super.init()
-            return
-        }
-
-        self.databasePath = fileProviderDataDirUrl.appendingPathComponent(self.relativeDatabaseFilePath)
-
-        // Disable file protection for directory DB
-        // https://docs.mongodb.com/realm/sdk/ios/examples/configure-and-open-a-realm/#std-label-ios-open-a-local-realm
-        let dbFolder = fileProviderDataDirUrl.appendingPathComponent(self.relativeDatabaseFolderPath)
-        let dbFolderPath = dbFolder.path
-        do {
-            try FileManager.default.createDirectory(at: dbFolder, withIntermediateDirectories: true)
-            try FileManager.default.setAttributes([FileAttributeKey.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication], ofItemAtPath: dbFolderPath)
-        } catch let error {
-            Logger.ncFilesDatabase.error("Could not set permission level for File Provider database folder, received error: \(error.localizedDescription, privacy: .public)")
-        }
-
-        let config = Realm.Configuration(
-            fileURL: self.databasePath,
-            schemaVersion: self.schemaVersion,
-            objectTypes: [NextcloudItemMetadataTable.self, NextcloudLocalFileMetadataTable.self]
-        )
-
-        Realm.Configuration.defaultConfiguration = config
-
-        do {
-            _ = try Realm()
-            Logger.ncFilesDatabase.info("Successfully started Realm db for FileProviderExt")
-        } catch let error as NSError {
-            Logger.ncFilesDatabase.error("Error opening Realm db: \(error.localizedDescription, privacy: .public)")
-        }
-
-        super.init()
-    }
-
-    func ncDatabase() -> Realm {
-        let realm = try! Realm()
-        realm.refresh()
-        return realm
-    }
-
-    func anyItemMetadatasForAccount(_ account: String) -> Bool {
-        return !ncDatabase().objects(NextcloudItemMetadataTable.self).filter("account == %@", account).isEmpty
-    }
-
-    func itemMetadataFromOcId(_ ocId: String) -> NextcloudItemMetadataTable? {
-        // Realm objects are live-fire, i.e. they will be changed and invalidated according to changes in the db
-        // Let's therefore create a copy
-        if let itemMetadata = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("ocId == %@", ocId).first {
-            return NextcloudItemMetadataTable(value: itemMetadata)
-        }
-
-        return nil
-    }
-
-    func sortedItemMetadatas(_ metadatas: Results<NextcloudItemMetadataTable>) -> [NextcloudItemMetadataTable] {
-        let sortedMetadatas = metadatas.sorted(byKeyPath: "fileName", ascending: true)
-        return Array(sortedMetadatas.map { NextcloudItemMetadataTable(value: $0) })
-    }
-
-    func itemMetadatas(account: String) -> [NextcloudItemMetadataTable] {
-        let metadatas = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("account == %@", account)
-        return sortedItemMetadatas(metadatas)
-    }
-
-    func itemMetadatas(account: String, serverUrl: String) -> [NextcloudItemMetadataTable] {
-        let metadatas = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl == %@", account, serverUrl)
-        return sortedItemMetadatas(metadatas)
-    }
-
-    func itemMetadatas(account: String, serverUrl: String, status: NextcloudItemMetadataTable.Status) -> [NextcloudItemMetadataTable] {
-        let metadatas = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl == %@ AND status == %@", account, serverUrl, status.rawValue)
-        return sortedItemMetadatas(metadatas)
-    }
-
-    func itemMetadataFromFileProviderItemIdentifier(_ identifier: NSFileProviderItemIdentifier) -> NextcloudItemMetadataTable? {
-        let ocId = identifier.rawValue
-        return itemMetadataFromOcId(ocId)
-    }
-
-    private func processItemMetadatasToDelete(existingMetadatas: Results<NextcloudItemMetadataTable>,
-                                              updatedMetadatas: [NextcloudItemMetadataTable]) -> [NextcloudItemMetadataTable] {
-
-        var deletedMetadatas: [NextcloudItemMetadataTable] = []
-
-        for existingMetadata in existingMetadatas {
-            guard !updatedMetadatas.contains(where: { $0.ocId == existingMetadata.ocId }),
-                    let metadataToDelete = itemMetadataFromOcId(existingMetadata.ocId) else { continue }
-
-            deletedMetadatas.append(metadataToDelete)
-
-            Logger.ncFilesDatabase.debug("Deleting item metadata during update. ocID: \(existingMetadata.ocId, privacy: .public), etag: \(existingMetadata.etag, privacy: .public), fileName: \(existingMetadata.fileName, privacy: .public)")
-        }
-
-        return deletedMetadatas
-    }
-
-    private func processItemMetadatasToUpdate(existingMetadatas: Results<NextcloudItemMetadataTable>,
-                                              updatedMetadatas: [NextcloudItemMetadataTable],
-                                              updateDirectoryEtags: Bool) -> (newMetadatas: [NextcloudItemMetadataTable], updatedMetadatas: [NextcloudItemMetadataTable], directoriesNeedingRename: [NextcloudItemMetadataTable]) {
-
-        var returningNewMetadatas: [NextcloudItemMetadataTable] = []
-        var returningUpdatedMetadatas: [NextcloudItemMetadataTable] = []
-        var directoriesNeedingRename: [NextcloudItemMetadataTable] = []
-
-        for updatedMetadata in updatedMetadatas {
-            if let existingMetadata = existingMetadatas.first(where: { $0.ocId == updatedMetadata.ocId }) {
-
-                if existingMetadata.status == NextcloudItemMetadataTable.Status.normal.rawValue &&
-                    !existingMetadata.isInSameDatabaseStoreableRemoteState(updatedMetadata) {
-
-                    if updatedMetadata.directory {
-
-                        if updatedMetadata.serverUrl != existingMetadata.serverUrl || updatedMetadata.fileName != existingMetadata.fileName {
-
-                            directoriesNeedingRename.append(NextcloudItemMetadataTable(value: updatedMetadata))
-                            updatedMetadata.etag = "" // Renaming doesn't change the etag so reset manually
-
-                        } else if !updateDirectoryEtags {
-                            updatedMetadata.etag = existingMetadata.etag
-                        }
-                    }
-
-                    returningUpdatedMetadatas.append(updatedMetadata)
-
-
-                    Logger.ncFilesDatabase.debug("Updated existing item metadata. ocID: \(updatedMetadata.ocId, privacy: .public), etag: \(updatedMetadata.etag, privacy: .public), fileName: \(updatedMetadata.fileName, privacy: .public)")
-                } else {
-                    Logger.ncFilesDatabase.debug("Skipping item metadata update; same as existing, or still downloading/uploading. ocID: \(updatedMetadata.ocId, privacy: .public), etag: \(updatedMetadata.etag, privacy: .public), fileName: \(updatedMetadata.fileName, privacy: .public)")
-                }
-
-            } else { // This is a new metadata
-                if !updateDirectoryEtags && updatedMetadata.directory {
-                    updatedMetadata.etag = ""
-                }
-                
-                returningNewMetadatas.append(updatedMetadata)
-
-                Logger.ncFilesDatabase.debug("Created new item metadata during update. ocID: \(updatedMetadata.ocId, privacy: .public), etag: \(updatedMetadata.etag, privacy: .public), fileName: \(updatedMetadata.fileName, privacy: .public)")
-            }
-        }
-
-        return (returningNewMetadatas, returningUpdatedMetadatas, directoriesNeedingRename)
-    }
-
-    func updateItemMetadatas(account: String, serverUrl: String, updatedMetadatas: [NextcloudItemMetadataTable], updateDirectoryEtags: Bool) -> (newMetadatas: [NextcloudItemMetadataTable]?, updatedMetadatas: [NextcloudItemMetadataTable]?, deletedMetadatas: [NextcloudItemMetadataTable]?) {
-        let database = ncDatabase()
-
-        do {
-            let existingMetadatas = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl == %@ AND status == %@", account, serverUrl, NextcloudItemMetadataTable.Status.normal.rawValue)
-
-            let metadatasToDelete = processItemMetadatasToDelete(existingMetadatas: existingMetadatas,
-                                                                 updatedMetadatas: updatedMetadatas)
-
-            let metadatasToChange = processItemMetadatasToUpdate(existingMetadatas: existingMetadatas,
-                                                                 updatedMetadatas: updatedMetadatas,
-                                                                 updateDirectoryEtags: updateDirectoryEtags)
-
-            var metadatasToUpdate = metadatasToChange.updatedMetadatas
-            let metadatasToCreate = metadatasToChange.newMetadatas
-            let directoriesNeedingRename = metadatasToChange.directoriesNeedingRename
-
-            let metadatasToAdd = Array(metadatasToUpdate.map { NextcloudItemMetadataTable(value: $0) }) +
-                                 Array(metadatasToCreate.map { NextcloudItemMetadataTable(value: $0) })
-
-            for metadata in directoriesNeedingRename {
-
-                if let updatedDirectoryChildren = renameDirectoryAndPropagateToChildren(ocId: metadata.ocId, newServerUrl: metadata.serverUrl, newFileName: metadata.fileName) {
-                    metadatasToUpdate += updatedDirectoryChildren
-                }
-            }
-
-            try database.write {
-                for metadata in metadatasToDelete {
-                    // Can't pass copies, we need the originals from the database
-                    database.delete(ncDatabase().objects(NextcloudItemMetadataTable.self).filter("ocId == %@", metadata.ocId))
-                }
-
-                for metadata in metadatasToAdd {
-                    database.add(metadata, update: .all)
-                }
-
-            }
-
-            return (newMetadatas: metadatasToCreate, updatedMetadatas: metadatasToUpdate, deletedMetadatas: metadatasToDelete)
-        } catch let error {
-            Logger.ncFilesDatabase.error("Could not update any item metadatas, received error: \(error.localizedDescription, privacy: .public)")
-            return (nil, nil, nil)
-        }
-    }
-
-    func setStatusForItemMetadata(_ metadata: NextcloudItemMetadataTable, status: NextcloudItemMetadataTable.Status, completionHandler: @escaping(_ updatedMetadata: NextcloudItemMetadataTable?) -> Void) {
-        let database = ncDatabase()
-
-        do {
-            try database.write {
-                guard let result = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@", metadata.ocId).first else {
-                    Logger.ncFilesDatabase.debug("Did not update status for item metadata as it was not found. ocID: \(metadata.ocId, privacy: .public)")
-                    return
-                }
-
-                result.status = status.rawValue
-                database.add(result, update: .all)
-                Logger.ncFilesDatabase.debug("Updated status for item metadata. ocID: \(metadata.ocId, privacy: .public), etag: \(metadata.etag, privacy: .public), fileName: \(metadata.fileName, privacy: .public)")
-
-                completionHandler(NextcloudItemMetadataTable(value: result))
-            }
-        } catch let error {
-            Logger.ncFilesDatabase.error("Could not update status for item metadata with ocID: \(metadata.ocId, privacy: .public), etag: \(metadata.etag, privacy: .public), fileName: \(metadata.fileName, privacy: .public), received error: \(error.localizedDescription, privacy: .public)")
-            completionHandler(nil)
-        }
-    }
-
-    func addItemMetadata(_ metadata: NextcloudItemMetadataTable) {
-        let database = ncDatabase()
-
-        do {
-            try database.write {
-                database.add(metadata, update: .all)
-                Logger.ncFilesDatabase.debug("Added item metadata. ocID: \(metadata.ocId, privacy: .public), etag: \(metadata.etag, privacy: .public), fileName: \(metadata.fileName, privacy: .public)")
-            }
-        } catch let error {
-            Logger.ncFilesDatabase.error("Could not add item metadata. ocID: \(metadata.ocId, privacy: .public), etag: \(metadata.etag, privacy: .public), fileName: \(metadata.fileName, privacy: .public), received error: \(error.localizedDescription, privacy: .public)")
-        }
-    }
-
-    @discardableResult func deleteItemMetadata(ocId: String) -> Bool {
-        let database = ncDatabase()
-
-        do {
-            try database.write {
-                let results = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@", ocId)
-
-                Logger.ncFilesDatabase.debug("Deleting item metadata. \(ocId, privacy: .public)")
-                database.delete(results)
-            }
-
-            return true
-        } catch let error {
-            Logger.ncFilesDatabase.error("Could not delete item metadata with ocId: \(ocId, privacy: .public), received error: \(error.localizedDescription, privacy: .public)")
-            return false
-        }
-    }
-
-    func renameItemMetadata(ocId: String, newServerUrl: String, newFileName: String) {
-        let database = ncDatabase()
-
-        do {
-            try database.write {
-                guard let itemMetadata = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@", ocId).first else {
-                    Logger.ncFilesDatabase.debug("Could not find an item with ocID \(ocId, privacy: .public) to rename to \(newFileName, privacy: .public)")
-                    return
-                }
-
-                let oldFileName = itemMetadata.fileName
-                let oldServerUrl = itemMetadata.serverUrl
-
-                itemMetadata.fileName = newFileName
-                itemMetadata.fileNameView = newFileName
-                itemMetadata.serverUrl = newServerUrl
-
-                database.add(itemMetadata, update: .all)
-
-                Logger.ncFilesDatabase.debug("Renamed item \(oldFileName, privacy: .public) to \(newFileName, privacy: .public), moved from serverUrl: \(oldServerUrl, privacy: .public) to serverUrl: \(newServerUrl, privacy: .public)")
-            }
-        } catch let error {
-            Logger.ncFilesDatabase.error("Could not rename filename of item metadata with ocID: \(ocId, privacy: .public) to proposed name \(newFileName, privacy: .public) at proposed serverUrl \(newServerUrl, privacy: .public), received error: \(error.localizedDescription, privacy: .public)")
-        }
-    }
-
-    func parentItemIdentifierFromMetadata(_ metadata: NextcloudItemMetadataTable) -> NSFileProviderItemIdentifier? {
-        let homeServerFilesUrl = metadata.urlBase + "/remote.php/dav/files/" + metadata.userId
-
-        if metadata.serverUrl == homeServerFilesUrl {
-            return .rootContainer
-        }
-
-        guard let itemParentDirectory = parentDirectoryMetadataForItem(metadata) else {
-            Logger.ncFilesDatabase.error("Could not get item parent directory metadata for metadata. ocID: \(metadata.ocId, privacy: .public), etag: \(metadata.etag, privacy: .public), fileName: \(metadata.fileName, privacy: .public)")
-            return nil
-        }
-
-        if let parentDirectoryMetadata = itemMetadataFromOcId(itemParentDirectory.ocId) {
-            return NSFileProviderItemIdentifier(parentDirectoryMetadata.ocId)
-        }
-
-        Logger.ncFilesDatabase.error("Could not get item parent directory item metadata for metadata. ocID: \(metadata.ocId, privacy: .public), etag: \(metadata.etag, privacy: .public), fileName: \(metadata.fileName, privacy: .public)")
-        return nil
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudItemMetadataTable+NKFile.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudItemMetadataTable+NKFile.swift
deleted file mode 100644 (file)
index 29683e7..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import NextcloudKit
-
-extension NextcloudItemMetadataTable {
-    static func fromNKFile(_ file: NKFile, account: String) -> NextcloudItemMetadataTable {
-        let metadata = NextcloudItemMetadataTable()
-
-        metadata.account = account
-        metadata.checksums = file.checksums
-        metadata.commentsUnread = file.commentsUnread
-        metadata.contentType = file.contentType
-        if let date = file.creationDate {
-            metadata.creationDate = date as Date
-        } else {
-            metadata.creationDate = file.date as Date
-        }
-        metadata.dataFingerprint = file.dataFingerprint
-        metadata.date = file.date as Date
-        metadata.directory = file.directory
-        metadata.downloadURL = file.downloadURL
-        metadata.e2eEncrypted = file.e2eEncrypted
-        metadata.etag = file.etag
-        metadata.favorite = file.favorite
-        metadata.fileId = file.fileId
-        metadata.fileName = file.fileName
-        metadata.fileNameView = file.fileName
-        metadata.hasPreview = file.hasPreview
-        metadata.iconName = file.iconName
-        metadata.mountType = file.mountType
-        metadata.name = file.name
-        metadata.note = file.note
-        metadata.ocId = file.ocId
-        metadata.ownerId = file.ownerId
-        metadata.ownerDisplayName = file.ownerDisplayName
-        metadata.lock = file.lock
-        metadata.lockOwner = file.lockOwner
-        metadata.lockOwnerEditor = file.lockOwnerEditor
-        metadata.lockOwnerType = file.lockOwnerType
-        metadata.lockOwnerDisplayName = file.lockOwnerDisplayName
-        metadata.lockTime = file.lockTime
-        metadata.lockTimeOut = file.lockTimeOut
-        metadata.path = file.path
-        metadata.permissions = file.permissions
-        metadata.quotaUsedBytes = file.quotaUsedBytes
-        metadata.quotaAvailableBytes = file.quotaAvailableBytes
-        metadata.richWorkspace = file.richWorkspace
-        metadata.resourceType = file.resourceType
-        metadata.serverUrl = file.serverUrl
-        metadata.sharePermissionsCollaborationServices = file.sharePermissionsCollaborationServices
-        for element in file.sharePermissionsCloudMesh {
-            metadata.sharePermissionsCloudMesh.append(element)
-        }
-        for element in file.shareType {
-            metadata.shareType.append(element)
-        }
-        metadata.size = file.size
-        metadata.classFile = file.classFile
-        //FIXME: iOS 12.0,* don't detect UTI text/markdown, text/x-markdown
-        if (metadata.contentType == "text/markdown" || metadata.contentType == "text/x-markdown") && metadata.classFile == NKCommon.TypeClassFile.unknow.rawValue {
-            metadata.classFile = NKCommon.TypeClassFile.document.rawValue
-        }
-        if let date = file.uploadDate {
-            metadata.uploadDate = date as Date
-        } else {
-            metadata.uploadDate = file.date as Date
-        }
-        metadata.urlBase = file.urlBase
-        metadata.user = file.user
-        metadata.userId = file.userId
-
-        // Support for finding the correct filename for e2ee files should go here
-
-        return metadata
-    }
-
-    static func metadatasFromDirectoryReadNKFiles(_ files: [NKFile],
-                                                  account: String,
-                                                  completionHandler: @escaping (_ directoryMetadata: NextcloudItemMetadataTable,
-                                                                                _ childDirectoriesMetadatas: [NextcloudItemMetadataTable],
-                                                                                _ metadatas: [NextcloudItemMetadataTable]) -> Void) {
-
-        var directoryMetadataSet = false
-        var directoryMetadata = NextcloudItemMetadataTable()
-        var childDirectoriesMetadatas: [NextcloudItemMetadataTable] = []
-        var metadatas: [NextcloudItemMetadataTable] = []
-
-        let conversionQueue = DispatchQueue(label: "nkFileToMetadataConversionQueue", qos: .userInitiated, attributes: .concurrent)
-        let appendQueue = DispatchQueue(label: "metadataAppendQueue", qos: .userInitiated) // Serial queue
-        let dispatchGroup = DispatchGroup()
-
-        for file in files {
-            if metadatas.isEmpty && !directoryMetadataSet {
-                let metadata = NextcloudItemMetadataTable.fromNKFile(file, account: account)
-                directoryMetadata = metadata;
-                directoryMetadataSet = true;
-            } else {
-                conversionQueue.async(group: dispatchGroup) {
-                    let metadata = NextcloudItemMetadataTable.fromNKFile(file, account: account)
-
-                    appendQueue.async(group: dispatchGroup) {
-                        metadatas.append(metadata)
-                        if metadata.directory {
-                            childDirectoriesMetadatas.append(metadata)
-                        }
-                    }
-                }
-            }
-        }
-
-        dispatchGroup.notify(queue: DispatchQueue.main) {
-            completionHandler(directoryMetadata, childDirectoriesMetadatas, metadatas)
-        }
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudItemMetadataTable.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudItemMetadataTable.swift
deleted file mode 100644 (file)
index 44b1ddf..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import RealmSwift
-import FileProvider
-import NextcloudKit
-
-class NextcloudItemMetadataTable: Object {
-    enum Status: Int {
-        case downloadError = -4
-        case downloading = -3
-        case inDownload = -2
-        case waitDownload = -1
-
-        case normal = 0
-
-        case waitUpload = 1
-        case inUpload = 2
-        case uploading = 3
-        case uploadError = 4
-    }
-
-    enum SharePermissions: Int {
-        case readShare = 1
-        case updateShare = 2
-        case createShare = 4
-        case deleteShare = 8
-        case shareShare = 16
-
-        case maxFileShare = 19
-        case maxFolderShare = 31
-    }
-
-    @Persisted(primaryKey: true) var ocId: String
-    @Persisted var account = ""
-    @Persisted var assetLocalIdentifier = ""
-    @Persisted var checksums = ""
-    @Persisted var chunk: Bool = false
-    @Persisted var classFile = ""
-    @Persisted var commentsUnread: Bool = false
-    @Persisted var contentType = ""
-    @Persisted var creationDate = Date()
-    @Persisted var dataFingerprint = ""
-    @Persisted var date = Date()
-    @Persisted var directory: Bool = false
-    @Persisted var deleteAssetLocalIdentifier: Bool = false
-    @Persisted var downloadURL = ""
-    @Persisted var e2eEncrypted: Bool = false
-    @Persisted var edited: Bool = false
-    @Persisted var etag = ""
-    @Persisted var etagResource = ""
-    @Persisted var favorite: Bool = false
-    @Persisted var fileId = ""
-    @Persisted var fileName = ""
-    @Persisted var fileNameView = ""
-    @Persisted var hasPreview: Bool = false
-    @Persisted var iconName = ""
-    @Persisted var iconUrl = ""
-    @Persisted var isExtractFile: Bool = false
-    @Persisted var livePhoto: Bool = false
-    @Persisted var mountType = ""
-    @Persisted var name = "" // for unifiedSearch is the provider.id
-    @Persisted var note = ""
-    @Persisted var ownerId = ""
-    @Persisted var ownerDisplayName = ""
-    @Persisted var lock = false
-    @Persisted var lockOwner = ""
-    @Persisted var lockOwnerEditor = ""
-    @Persisted var lockOwnerType = 0
-    @Persisted var lockOwnerDisplayName = ""
-    @Persisted var lockTime: Date?
-    @Persisted var lockTimeOut: Date?
-    @Persisted var path = ""
-    @Persisted var permissions = ""
-    @Persisted var quotaUsedBytes: Int64 = 0
-    @Persisted var quotaAvailableBytes: Int64 = 0
-    @Persisted var resourceType = ""
-    @Persisted var richWorkspace: String?
-    @Persisted var serverUrl = "" // For parent directory!!
-    @Persisted var session = ""
-    @Persisted var sessionError = ""
-    @Persisted var sessionSelector = ""
-    @Persisted var sessionTaskIdentifier: Int = 0
-    @Persisted var sharePermissionsCollaborationServices: Int = 0
-    let sharePermissionsCloudMesh = List<String>() // TODO: Find a way to compare these in remote state check
-    let shareType = List<Int>()
-    @Persisted var size: Int64 = 0
-    @Persisted var status: Int = 0
-    @Persisted var subline: String?
-    @Persisted var trashbinFileName = ""
-    @Persisted var trashbinOriginalLocation = ""
-    @Persisted var trashbinDeletionTime = Date()
-    @Persisted var uploadDate = Date()
-    @Persisted var url = ""
-    @Persisted var urlBase = ""
-    @Persisted var user = ""
-    @Persisted var userId = ""
-
-    var fileExtension: String {
-        (fileNameView as NSString).pathExtension
-    }
-
-    var fileNoExtension: String {
-        (fileNameView as NSString).deletingPathExtension
-    }
-
-    var isRenameable: Bool {
-        return lock
-    }
-
-    var isPrintable: Bool {
-        if isDocumentViewableOnly {
-            return false
-        }
-        if ["application/pdf", "com.adobe.pdf"].contains(contentType) || contentType.hasPrefix("text/") || classFile == NKCommon.TypeClassFile.image.rawValue {
-            return true
-        }
-        return false
-    }
-
-    var isDocumentViewableOnly: Bool {
-        return sharePermissionsCollaborationServices == SharePermissions.readShare.rawValue &&
-            classFile == NKCommon.TypeClassFile.document.rawValue
-    }
-
-    var isCopyableInPasteboard: Bool {
-        !isDocumentViewableOnly && !directory
-    }
-
-    var isModifiableWithQuickLook: Bool {
-        if directory || isDocumentViewableOnly {
-            return false
-        }
-        return contentType == "com.adobe.pdf" || contentType == "application/pdf" || classFile == NKCommon.TypeClassFile.image.rawValue
-    }
-
-    var isSettableOnOffline: Bool {
-        return session.isEmpty && !isDocumentViewableOnly
-    }
-
-    var canOpenIn: Bool {
-        return session.isEmpty && !isDocumentViewableOnly && !directory
-    }
-
-    var isDownloadUpload: Bool {
-        return status == Status.inDownload.rawValue ||
-            status == Status.downloading.rawValue ||
-            status == Status.inUpload.rawValue ||
-            status == Status.uploading.rawValue
-    }
-
-    var isDownload: Bool {
-        status == Status.inDownload.rawValue || status == Status.downloading.rawValue
-    }
-
-    var isUpload: Bool {
-        status == Status.inUpload.rawValue || status == Status.uploading.rawValue
-    }
-
-    override func isEqual(_ object: Any?) -> Bool {
-        if let object = object as? NextcloudItemMetadataTable {
-            return self.fileId == object.fileId &&
-                   self.account == object.account &&
-                   self.path == object.path &&
-                   self.fileName == object.fileName
-        }
-
-        return false
-    }
-
-    func isInSameDatabaseStoreableRemoteState(_ comparingMetadata: NextcloudItemMetadataTable) -> Bool {
-        return comparingMetadata.etag == self.etag &&
-            comparingMetadata.fileNameView == self.fileNameView &&
-            comparingMetadata.date == self.date &&
-            comparingMetadata.permissions == self.permissions &&
-            comparingMetadata.hasPreview == self.hasPreview &&
-            comparingMetadata.note == self.note &&
-            comparingMetadata.lock == self.lock &&
-            comparingMetadata.sharePermissionsCollaborationServices == self.sharePermissionsCollaborationServices &&
-            comparingMetadata.favorite == self.favorite
-    }
-
-    /// Returns false if the user is lokced out of the file. I.e. The file is locked but by somone else
-    func canUnlock(as user: String) -> Bool {
-        return !lock || (lockOwner == user && lockOwnerType == 0)
-    }
-
-    func thumbnailUrl(size: CGSize) -> URL? {
-        guard hasPreview else {
-            return nil
-        }
-
-        let urlBase = urlBase.urlEncoded!
-        let webdavUrl = urlBase + NextcloudAccount.webDavFilesUrlSuffix + user // Leave the leading slash
-        let serverFileRelativeUrl = serverUrl.replacingOccurrences(of: webdavUrl, with: "") + "/" + fileName
-
-        let urlString = "\(urlBase)/index.php/core/preview.png?file=\(serverFileRelativeUrl)&x=\(size.width)&y=\(size.height)&a=1&mode=cover"
-
-        return URL(string: urlString)
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudLocalFileMetadataTable.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudLocalFileMetadataTable.swift
deleted file mode 100644 (file)
index 7eda481..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import RealmSwift
-
-class NextcloudLocalFileMetadataTable: Object {
-    @Persisted(primaryKey: true) var ocId: String
-    @Persisted var account = ""
-    @Persisted var etag = ""
-    @Persisted var exifDate: Date?
-    @Persisted var exifLatitude = ""
-    @Persisted var exifLongitude = ""
-    @Persisted var exifLensModel: String?
-    @Persisted var favorite: Bool = false
-    @Persisted var fileName = ""
-    @Persisted var offline: Bool = false
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift
deleted file mode 100644 (file)
index 9711949..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import OSLog
-
-extension Logger {
-    private static var subsystem = Bundle.main.bundleIdentifier!
-
-    static let desktopClientConnection = Logger(subsystem: subsystem, category: "desktopclientconnection")
-    static let enumeration = Logger(subsystem: subsystem, category: "enumeration")
-    static let fileProviderExtension = Logger(subsystem: subsystem, category: "fileproviderextension")
-    static let fileTransfer = Logger(subsystem: subsystem, category: "filetransfer")
-    static let localFileOps = Logger(subsystem: subsystem, category: "localfileoperations")
-    static let ncFilesDatabase = Logger(subsystem: subsystem, category: "nextcloudfilesdatabase")
-    static let materialisedFileHandling = Logger(subsystem: subsystem, category: "materialisedfilehandling")
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/NKError+Extensions.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/NKError+Extensions.swift
deleted file mode 100644 (file)
index f9ca668..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import FileProvider
-import NextcloudKit
-
-extension NKError {
-    static var noChangesErrorCode: Int {
-        return -200
-    }
-
-    var isCouldntConnectError: Bool {
-        return errorCode == -9999 ||
-            errorCode == -1001 ||
-            errorCode == -1004 ||
-            errorCode == -1005 ||
-            errorCode == -1009 ||
-            errorCode == -1012 ||
-            errorCode == -1200 ||
-            errorCode == -1202 ||
-            errorCode == 500 ||
-            errorCode == 503 ||
-            errorCode == 200
-    }
-
-    var isUnauthenticatedError: Bool {
-        return errorCode == -1013
-    }
-
-    var isGoingOverQuotaError: Bool {
-        return errorCode == 507
-    }
-
-    var isNotFoundError: Bool {
-        return errorCode == 404
-    }
-
-    var isNoChangesError: Bool {
-        return errorCode == NKError.noChangesErrorCode
-    }
-
-    var fileProviderError: NSFileProviderError {
-        if isNotFoundError {
-            return NSFileProviderError(.noSuchItem)
-        } else if isCouldntConnectError {
-            // Provide something the file provider can do something with
-            return NSFileProviderError(.serverUnreachable)
-        } else if isUnauthenticatedError {
-            return NSFileProviderError(.notAuthenticated)
-        } else if isGoingOverQuotaError {
-            return NSFileProviderError(.insufficientQuota)
-        } else {
-            return NSFileProviderError(.cannotSynchronize)
-        }
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Progress+Extensions.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Progress+Extensions.swift
deleted file mode 100644 (file)
index e15e2e0..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import Alamofire
-
-extension Progress {
-    func setHandlersFromAfRequest(_ request: Request) {
-        self.cancellationHandler = { request.cancel() }
-        self.pausingHandler = { request.suspend() }
-        self.resumingHandler = { request.resume() }
-    }
-
-    func copyCurrentStateToProgress(_ otherProgress: Progress, includeHandlers: Bool = false) {
-        if includeHandlers {
-            otherProgress.cancellationHandler = self.cancellationHandler
-            otherProgress.pausingHandler = self.pausingHandler
-            otherProgress.resumingHandler = self.resumingHandler
-        }
-        
-        otherProgress.totalUnitCount = self.totalUnitCount
-        otherProgress.completedUnitCount = self.completedUnitCount
-        otherProgress.estimatedTimeRemaining = self.estimatedTimeRemaining
-        otherProgress.localizedDescription = self.localizedAdditionalDescription
-        otherProgress.localizedAdditionalDescription = self.localizedAdditionalDescription
-        otherProgress.isCancellable = self.isCancellable
-        otherProgress.isPausable = self.isPausable
-        otherProgress.fileCompletedCount = self.fileCompletedCount
-        otherProgress.fileURL = self.fileURL
-        otherProgress.fileTotalCount = self.fileTotalCount
-        otherProgress.fileCompletedCount = self.fileCompletedCount
-        otherProgress.fileOperationKind = self.fileOperationKind
-        otherProgress.kind = self.kind
-        otherProgress.throughput = self.throughput
-
-        for (key, object) in self.userInfo {
-            otherProgress.setUserInfoObject(object, forKey: key)
-        }
-    }
-
-    func copyOfCurrentState(includeHandlers: Bool = false) -> Progress {
-        let newProgress = Progress()
-        copyCurrentStateToProgress(newProgress, includeHandlers: includeHandlers)
-        return newProgress
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator+SyncEngine.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator+SyncEngine.swift
deleted file mode 100644 (file)
index fdd81f8..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import FileProvider
-import NextcloudKit
-import OSLog
-
-extension FileProviderEnumerator {
-    func fullRecursiveScan(ncAccount: NextcloudAccount,
-                           ncKit: NextcloudKit,
-                           scanChangesOnly: Bool,
-                           completionHandler: @escaping(_ metadatas: [NextcloudItemMetadataTable],
-                                                        _ newMetadatas: [NextcloudItemMetadataTable],
-                                                        _ updatedMetadatas: [NextcloudItemMetadataTable],
-                                                        _ deletedMetadatas: [NextcloudItemMetadataTable],
-                                                        _ error: NKError?) -> Void) {
-
-        let rootContainerDirectoryMetadata = NextcloudItemMetadataTable()
-        rootContainerDirectoryMetadata.directory = true
-        rootContainerDirectoryMetadata.ocId = NSFileProviderItemIdentifier.rootContainer.rawValue
-
-        // Create a serial dispatch queue
-        let dispatchQueue = DispatchQueue(label: "recursiveChangeEnumerationQueue", qos: .userInitiated)
-
-        dispatchQueue.async {
-            let results = self.scanRecursively(rootContainerDirectoryMetadata,
-                                               ncAccount: ncAccount,
-                                               ncKit: ncKit,
-                                               scanChangesOnly: scanChangesOnly)
-
-            // Run a check to ensure files deleted in one location are not updated in another (e.g. when moved)
-            // The recursive scan provides us with updated/deleted metadatas only on a folder by folder basis;
-            // so we need to check we are not simultaneously marking a moved file as deleted and updated
-            var checkedDeletedMetadatas = results.deletedMetadatas
-
-            for updatedMetadata in results.updatedMetadatas {
-                guard let matchingDeletedMetadataIdx = checkedDeletedMetadatas.firstIndex(where: { $0.ocId == updatedMetadata.ocId } ) else {
-                    continue;
-                }
-
-                checkedDeletedMetadatas.remove(at: matchingDeletedMetadataIdx)
-            }
-
-            DispatchQueue.main.async {
-                completionHandler(results.metadatas, results.newMetadatas, results.updatedMetadatas, checkedDeletedMetadatas, results.error)
-            }
-        }
-    }
-
-    private func scanRecursively(_ directoryMetadata: NextcloudItemMetadataTable,
-                                 ncAccount: NextcloudAccount,
-                                 ncKit: NextcloudKit,
-                                 scanChangesOnly: Bool) -> (metadatas: [NextcloudItemMetadataTable],
-                                                            newMetadatas: [NextcloudItemMetadataTable],
-                                                            updatedMetadatas: [NextcloudItemMetadataTable],
-                                                            deletedMetadatas: [NextcloudItemMetadataTable],
-                                                            error: NKError?) {
-
-        if self.isInvalidated {
-            return ([], [], [], [], nil)
-        }
-
-        assert(directoryMetadata.directory, "Can only recursively scan a directory.")
-
-        // Will include results of recursive calls
-        var allMetadatas: [NextcloudItemMetadataTable] = []
-        var allNewMetadatas: [NextcloudItemMetadataTable] = []
-        var allUpdatedMetadatas: [NextcloudItemMetadataTable] = []
-        var allDeletedMetadatas: [NextcloudItemMetadataTable] = []
-
-        let dbManager = NextcloudFilesDatabaseManager.shared
-        let dispatchGroup = DispatchGroup() // TODO: Maybe own thread?
-
-        dispatchGroup.enter()
-
-        var criticalError: NKError?
-        let itemServerUrl = directoryMetadata.ocId == NSFileProviderItemIdentifier.rootContainer.rawValue ?
-            ncAccount.davFilesUrl : directoryMetadata.serverUrl + "/" + directoryMetadata.fileName
-
-        Logger.enumeration.debug("About to read: \(itemServerUrl, privacy: .public)")
-
-        FileProviderEnumerator.readServerUrl(itemServerUrl, ncAccount: ncAccount, ncKit: ncKit, stopAtMatchingEtags: scanChangesOnly) { metadatas, newMetadatas, updatedMetadatas, deletedMetadatas, readError in
-
-            if readError != nil {
-                let nkReadError = NKError(error: readError!)
-
-                // Is the error is that we have found matching etags on this item, then ignore it
-                // if we are doing a full rescan
-                guard nkReadError.isNoChangesError && scanChangesOnly else {
-                    Logger.enumeration.error("Finishing enumeration of changes at \(itemServerUrl, privacy: .public) with \(readError!.localizedDescription, privacy: .public)")
-
-                    if nkReadError.isNotFoundError {
-                        Logger.enumeration.info("404 error means item no longer exists. Deleting metadata and reporting as deletion without error")
-
-                        if let deletedMetadatas = dbManager.deleteDirectoryAndSubdirectoriesMetadata(ocId: directoryMetadata.ocId) {
-                            allDeletedMetadatas += deletedMetadatas
-                        } else {
-                            Logger.enumeration.error("An error occurred while trying to delete directory and children not found in recursive scan")
-                        }
-
-                    } else if nkReadError.isNoChangesError { // All is well, just no changed etags
-                        Logger.enumeration.info("Error was to say no changed files -- not bad error. No need to check children.")
-
-                    } else if nkReadError.isUnauthenticatedError || nkReadError.isCouldntConnectError {
-                        // If it is a critical error then stop, if not then continue
-                        Logger.enumeration.error("Error will affect next enumerated items, so stopping enumeration.")
-                        criticalError = nkReadError
-
-                    }
-
-                    dispatchGroup.leave()
-                    return
-                }
-            }
-
-            Logger.enumeration.info("Finished reading serverUrl: \(itemServerUrl, privacy: .public) for user: \(ncAccount.ncKitAccount, privacy: .public)")
-
-            if let metadatas = metadatas {
-                allMetadatas += metadatas
-            } else {
-                Logger.enumeration.warning("WARNING: Nil metadatas received for reading of changes at \(itemServerUrl, privacy: .public) for user: \(ncAccount.ncKitAccount, privacy: .public)")
-            }
-
-            if let newMetadatas = newMetadatas {
-                allNewMetadatas += newMetadatas
-            } else {
-                Logger.enumeration.warning("WARNING: Nil new metadatas received for reading of changes at \(itemServerUrl, privacy: .public) for user: \(ncAccount.ncKitAccount, privacy: .public)")
-            }
-
-            if let updatedMetadatas = updatedMetadatas {
-                allUpdatedMetadatas += updatedMetadatas
-            } else {
-                Logger.enumeration.warning("WARNING: Nil updated metadatas received for reading of changes at \(itemServerUrl, privacy: .public) for user: \(ncAccount.ncKitAccount, privacy: .public)")
-            }
-
-            if let deletedMetadatas = deletedMetadatas {
-                allDeletedMetadatas += deletedMetadatas
-            } else {
-                Logger.enumeration.warning("WARNING: Nil deleted metadatas received for reading of changes at \(itemServerUrl, privacy: .public) for user: \(ncAccount.ncKitAccount, privacy: .public)")
-            }
-
-            dispatchGroup.leave()
-        }
-
-        dispatchGroup.wait()
-
-        guard criticalError == nil else {
-            return ([], [], [], [], error: criticalError)
-        }
-
-        var childDirectoriesToScan: [NextcloudItemMetadataTable] = []
-        var candidateMetadatas: [NextcloudItemMetadataTable]
-
-        if scanChangesOnly {
-            candidateMetadatas = allUpdatedMetadatas + allNewMetadatas
-        } else {
-            candidateMetadatas = allMetadatas
-        }
-
-        for candidateMetadata in candidateMetadatas {
-            if candidateMetadata.directory {
-                childDirectoriesToScan.append(candidateMetadata)
-            }
-        }
-
-        if childDirectoriesToScan.isEmpty {
-            return (metadatas: allMetadatas, newMetadatas: allNewMetadatas, updatedMetadatas: allUpdatedMetadatas, deletedMetadatas: allDeletedMetadatas, nil)
-        }
-
-        for childDirectory in childDirectoriesToScan {
-            let childScanResult = scanRecursively(childDirectory,
-                                                  ncAccount: ncAccount,
-                                                  ncKit: ncKit,
-                                                  scanChangesOnly: scanChangesOnly)
-
-            allMetadatas += childScanResult.metadatas
-            allNewMetadatas += childScanResult.newMetadatas
-            allUpdatedMetadatas += childScanResult.updatedMetadatas
-            allDeletedMetadatas += childScanResult.deletedMetadatas
-        }
-
-        return (metadatas: allMetadatas, newMetadatas: allNewMetadatas, updatedMetadatas: allUpdatedMetadatas, deletedMetadatas: allDeletedMetadatas, nil)
-    }
-
-    static func handleDepth1ReadFileOrFolder(serverUrl: String,
-                                             ncAccount: NextcloudAccount,
-                                             files: [NKFile],
-                                             error: NKError,
-                                             completionHandler: @escaping (_ metadatas: [NextcloudItemMetadataTable]?,
-                                                                           _ newMetadatas: [NextcloudItemMetadataTable]?,
-                                                                           _ updatedMetadatas: [NextcloudItemMetadataTable]?,
-                                                                           _ deletedMetadatas: [NextcloudItemMetadataTable]?,
-                                                                           _ readError: Error?) -> Void) {
-
-        guard error == .success else {
-            Logger.enumeration.error("1 depth readFileOrFolder of url: \(serverUrl, privacy: .public) did not complete successfully, received error: \(error.errorDescription, privacy: .public)")
-            completionHandler(nil, nil, nil, nil, error.error)
-            return
-        }
-
-        Logger.enumeration.debug("Starting async conversion of NKFiles for serverUrl: \(serverUrl, privacy: .public) for user: \(ncAccount.ncKitAccount, privacy: .public)")
-
-        let dbManager = NextcloudFilesDatabaseManager.shared
-
-        DispatchQueue.global(qos: .userInitiated).async {
-            NextcloudItemMetadataTable.metadatasFromDirectoryReadNKFiles(files, account: ncAccount.ncKitAccount) { directoryMetadata, childDirectoriesMetadata, metadatas in
-
-                // STORE DATA FOR CURRENTLY SCANNED DIRECTORY
-                // We have now scanned this directory's contents, so update with etag in order to not check again if not needed
-                // unless it's the root container
-                if serverUrl != ncAccount.davFilesUrl {
-                    dbManager.addItemMetadata(directoryMetadata)
-                }
-
-                // Don't update the etags for folders as we haven't checked their contents.
-                // When we do a recursive check, if we update the etags now, we will think
-                // that our local copies are up to date -- instead, leave them as the old.
-                // They will get updated when they are the subject of a readServerUrl call.
-                // (See above)
-                let changedMetadatas = dbManager.updateItemMetadatas(account: ncAccount.ncKitAccount, serverUrl: serverUrl, updatedMetadatas: metadatas, updateDirectoryEtags: false)
-
-                DispatchQueue.main.async {
-                    completionHandler(metadatas, changedMetadatas.newMetadatas, changedMetadatas.updatedMetadatas, changedMetadatas.deletedMetadatas, nil)
-                }
-            }
-        }
-    }
-
-    static func readServerUrl(_ serverUrl: String,
-                              ncAccount: NextcloudAccount,
-                              ncKit: NextcloudKit,
-                              stopAtMatchingEtags: Bool = false,
-                              depth: String = "1",
-                              completionHandler: @escaping (_ metadatas: [NextcloudItemMetadataTable]?,
-                                                            _ newMetadatas: [NextcloudItemMetadataTable]?,
-                                                            _ updatedMetadatas: [NextcloudItemMetadataTable]?,
-                                                            _ deletedMetadatas: [NextcloudItemMetadataTable]?,
-                                                            _ readError: Error?) -> Void) {
-
-        let dbManager = NextcloudFilesDatabaseManager.shared
-        let ncKitAccount = ncAccount.ncKitAccount
-
-        Logger.enumeration.debug("Starting to read serverUrl: \(serverUrl, privacy: .public) for user: \(ncAccount.ncKitAccount, privacy: .public) at depth \(depth, privacy: .public). NCKit info: userId: \(ncKit.nkCommonInstance.user, privacy: .public), password is empty: \(ncKit.nkCommonInstance.password == "" ? "EMPTY PASSWORD" : "NOT EMPTY PASSWORD"), urlBase: \(ncKit.nkCommonInstance.urlBase, privacy: .public), ncVersion: \(ncKit.nkCommonInstance.nextcloudVersion, privacy: .public)")
-
-        ncKit.readFileOrFolder(serverUrlFileName: serverUrl, depth: depth, showHiddenFiles: true) { _, files, _, error in
-            guard error == .success else {
-                Logger.enumeration.error("\(depth, privacy: .public) depth readFileOrFolder of url: \(serverUrl, privacy: .public) did not complete successfully, received error: \(error.errorDescription, privacy: .public)")
-                completionHandler(nil, nil, nil, nil, error.error)
-                return
-            }
-
-            guard let receivedFile = files.first else {
-                Logger.enumeration.error("Received no items from readFileOrFolder of \(serverUrl, privacy: .public), not much we can do...")
-                completionHandler(nil, nil, nil, nil, error.error)
-                return
-            }
-
-            guard receivedFile.directory else {
-                Logger.enumeration.debug("Read item is a file. Converting NKfile for serverUrl: \(serverUrl, privacy: .public) for user: \(ncAccount.ncKitAccount, privacy: .public)")
-                let itemMetadata = NextcloudItemMetadataTable.fromNKFile(receivedFile, account: ncKitAccount)
-                dbManager.addItemMetadata(itemMetadata) // TODO: Return some value when it is an update
-                completionHandler([itemMetadata], nil, nil, nil, error.error)
-                return
-            }
-
-            if stopAtMatchingEtags,
-               let directoryMetadata = dbManager.directoryMetadata(account: ncKitAccount, serverUrl: serverUrl) {
-
-                let directoryEtag = directoryMetadata.etag
-
-                guard directoryEtag == "" || directoryEtag != receivedFile.etag else {
-                    Logger.enumeration.debug("Read server url called with flag to stop enumerating at matching etags. Returning and providing soft error.")
-
-                    let description = "Fetched directory etag is same as that stored locally. Not fetching child items."
-                    let nkError = NKError(errorCode: NKError.noChangesErrorCode, errorDescription: description)
-
-                    let metadatas = dbManager.itemMetadatas(account: ncKitAccount, serverUrl: serverUrl)
-
-                    completionHandler(metadatas, nil, nil, nil, nkError.error)
-                    return
-                }
-            }
-
-            if depth == "0" {
-                if serverUrl != ncAccount.davFilesUrl {
-                    let metadata = NextcloudItemMetadataTable.fromNKFile(receivedFile, account: ncKitAccount)
-                    let isNew = dbManager.itemMetadataFromOcId(metadata.ocId) == nil
-                    let updatedMetadatas = isNew ? [] : [metadata]
-                    let newMetadatas = isNew ? [metadata] : []
-
-                    dbManager.addItemMetadata(metadata)
-
-                    DispatchQueue.main.async {
-                        completionHandler([metadata], newMetadatas, updatedMetadatas, nil, nil)
-                    }
-                }
-            } else {
-                handleDepth1ReadFileOrFolder(serverUrl: serverUrl, ncAccount: ncAccount, files: files, error: error, completionHandler: completionHandler)
-            }
-        }
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift
deleted file mode 100644 (file)
index a9dfacc..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import FileProvider
-import NextcloudKit
-import OSLog
-
-class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
-    
-    private let enumeratedItemIdentifier: NSFileProviderItemIdentifier
-    private var enumeratedItemMetadata: NextcloudItemMetadataTable?
-    private var enumeratingSystemIdentifier: Bool {
-        return FileProviderEnumerator.isSystemIdentifier(enumeratedItemIdentifier)
-    }
-    private let anchor = NSFileProviderSyncAnchor(Date().description.data(using: .utf8)!) // TODO: actually use this in NCKit and server requests
-    private static let maxItemsPerFileProviderPage = 100
-    let ncAccount: NextcloudAccount
-    let ncKit: NextcloudKit
-    var serverUrl: String = ""
-    var isInvalidated = false
-
-    private static func isSystemIdentifier(_ identifier: NSFileProviderItemIdentifier) -> Bool {
-        return identifier == .rootContainer ||
-            identifier == .trashContainer ||
-            identifier == .workingSet
-    }
-    
-    init(enumeratedItemIdentifier: NSFileProviderItemIdentifier, ncAccount: NextcloudAccount, ncKit: NextcloudKit) {
-        self.enumeratedItemIdentifier = enumeratedItemIdentifier
-        self.ncAccount = ncAccount
-        self.ncKit = ncKit
-
-        if FileProviderEnumerator.isSystemIdentifier(enumeratedItemIdentifier) {
-            Logger.enumeration.debug("Providing enumerator for a system defined container: \(enumeratedItemIdentifier.rawValue, privacy: .public)")
-            self.serverUrl = ncAccount.davFilesUrl
-        } else {
-            Logger.enumeration.debug("Providing enumerator for item with identifier: \(enumeratedItemIdentifier.rawValue, privacy: .public)")
-            let dbManager = NextcloudFilesDatabaseManager.shared
-
-            enumeratedItemMetadata = dbManager.itemMetadataFromFileProviderItemIdentifier(enumeratedItemIdentifier)
-            if enumeratedItemMetadata != nil {
-                self.serverUrl = enumeratedItemMetadata!.serverUrl + "/" + enumeratedItemMetadata!.fileName
-            } else {
-                Logger.enumeration.error("Could not find itemMetadata for file with identifier: \(enumeratedItemIdentifier.rawValue, privacy: .public)")
-            }
-        }
-
-        Logger.enumeration.info("Set up enumerator for user: \(self.ncAccount.ncKitAccount, privacy: .public) with serverUrl: \(self.serverUrl, privacy: .public)")
-        super.init()
-    }
-
-    func invalidate() {
-        Logger.enumeration.debug("Enumerator is being invalidated for item with identifier: \(self.enumeratedItemIdentifier.rawValue, privacy: .public)")
-        self.isInvalidated = true
-    }
-
-    // MARK: - Protocol methods
-
-    func enumerateItems(for observer: NSFileProviderEnumerationObserver, startingAt page: NSFileProviderPage) {
-        Logger.enumeration.debug("Received enumerate items request for enumerator with user: \(self.ncAccount.ncKitAccount, privacy: .public) with serverUrl: \(self.serverUrl, privacy: .public)")
-        /*
-         - inspect the page to determine whether this is an initial or a follow-up request (TODO)
-         
-         If this is an enumerator for a directory, the root container or all directories:
-         - perform a server request to fetch directory contents
-         If this is an enumerator for the working set:
-         - perform a server request to update your local database
-         - fetch the working set from your local database
-         
-         - inform the observer about the items returned by the server (possibly multiple times)
-         - inform the observer that you are finished with this page
-         */
-
-        if enumeratedItemIdentifier == .trashContainer {
-            Logger.enumeration.debug("Enumerating trash set for user: \(self.ncAccount.ncKitAccount, privacy: .public) with serverUrl: \(self.serverUrl, privacy: .public)")
-            // TODO!
-
-            observer.finishEnumerating(upTo: nil)
-            return
-        }
-
-        // Handle the working set as if it were the root container
-        // If we do a full server scan per the recommendations of the File Provider documentation,
-        // we will be stuck for a huge period of time without being able to access files as the
-        // entire server gets scanned. Instead, treat the working set as the root container here.
-        // Then, when we enumerate changes, we'll go through everything -- while we can still
-        // navigate a little bit in Finder, file picker, etc
-
-        guard serverUrl != "" else {
-            Logger.enumeration.error("Enumerator has empty serverUrl -- can't enumerate that! For identifier: \(self.enumeratedItemIdentifier.rawValue, privacy: .public)")
-            observer.finishEnumeratingWithError(NSFileProviderError(.noSuchItem))
-            return
-        }
-
-        // TODO: Make better use of pagination and handle paging properly
-        if page == NSFileProviderPage.initialPageSortedByDate as NSFileProviderPage ||
-            page == NSFileProviderPage.initialPageSortedByName as NSFileProviderPage {
-
-            Logger.enumeration.debug("Enumerating initial page for user: \(self.ncAccount.ncKitAccount, privacy: .public) with serverUrl: \(self.serverUrl, privacy: .public)")
-
-            FileProviderEnumerator.readServerUrl(serverUrl, ncAccount: ncAccount, ncKit: ncKit) { metadatas, _, _, _, readError in
-
-                guard readError == nil else {
-                    Logger.enumeration.error("Finishing enumeration for user: \(self.ncAccount.ncKitAccount, privacy: .public) with serverUrl: \(self.serverUrl, privacy: .public) with error \(readError!.localizedDescription, privacy: .public)")
-
-                    let nkReadError = NKError(error: readError!)
-                    observer.finishEnumeratingWithError(nkReadError.fileProviderError)
-                    return
-                }
-
-                guard let metadatas = metadatas else {
-                    Logger.enumeration.error("Finishing enumeration for user: \(self.ncAccount.ncKitAccount, privacy: .public) with serverUrl: \(self.serverUrl, privacy: .public) with invalid metadatas.")
-                    observer.finishEnumeratingWithError(NSFileProviderError(.cannotSynchronize))
-                    return
-                }
-
-                Logger.enumeration.info("Finished reading serverUrl: \(self.serverUrl, privacy: .public) for user: \(self.ncAccount.ncKitAccount, privacy: .public). Processed \(metadatas.count) metadatas")
-
-                FileProviderEnumerator.completeEnumerationObserver(observer, ncKit: self.ncKit, numPage: 1, itemMetadatas: metadatas)
-            }
-
-            return;
-        }
-
-        let numPage = Int(String(data: page.rawValue, encoding: .utf8)!)!
-        Logger.enumeration.debug("Enumerating page \(numPage, privacy: .public) for user: \(self.ncAccount.ncKitAccount, privacy: .public) with serverUrl: \(self.serverUrl, privacy: .public)")
-        // TODO: Handle paging properly
-        // FileProviderEnumerator.completeObserver(observer, ncKit: ncKit, numPage: numPage, itemMetadatas: nil)
-        observer.finishEnumerating(upTo: nil)
-    }
-    
-    func enumerateChanges(for observer: NSFileProviderChangeObserver, from anchor: NSFileProviderSyncAnchor) {
-        Logger.enumeration.debug("Received enumerate changes request for enumerator for user: \(self.ncAccount.ncKitAccount, privacy: .public) with serverUrl: \(self.serverUrl, privacy: .public)")
-        /*
-         - query the server for updates since the passed-in sync anchor (TODO)
-         
-         If this is an enumerator for the working set:
-         - note the changes in your local database
-         
-         - inform the observer about item deletions and updates (modifications + insertions)
-         - inform the observer when you have finished enumerating up to a subsequent sync anchor
-         */
-
-        if enumeratedItemIdentifier == .workingSet {
-            Logger.enumeration.debug("Enumerating changes in working set for user: \(self.ncAccount.ncKitAccount, privacy: .public)")
-
-            // Unlike when enumerating items we can't progressively enumerate items as we need to wait to resolve which items are truly deleted and which
-            // have just been moved elsewhere.
-            fullRecursiveScan(ncAccount: self.ncAccount,
-                              ncKit: self.ncKit,
-                              scanChangesOnly: true) { _, newMetadatas, updatedMetadatas, deletedMetadatas, error in
-
-                if self.isInvalidated {
-                    Logger.enumeration.info("Enumerator invalidated during working set change scan. For user: \(self.ncAccount.ncKitAccount, privacy: .public)")
-                    observer.finishEnumeratingWithError(NSFileProviderError(.cannotSynchronize))
-                    return
-                }
-
-                guard error == nil else {
-                    Logger.enumeration.info("Finished recursive change enumeration of working set for user: \(self.ncAccount.ncKitAccount, privacy: .public) with error: \(error!.errorDescription, privacy: .public)")
-                    observer.finishEnumeratingWithError(error!.fileProviderError)
-                    return
-                }
-
-                Logger.enumeration.info("Finished recursive change enumeration of working set for user: \(self.ncAccount.ncKitAccount, privacy: .public). Enumerating items.")
-
-                FileProviderEnumerator.completeChangesObserver(observer,
-                                                               anchor: anchor,
-                                                               ncKit: self.ncKit,
-                                                               newMetadatas: newMetadatas,
-                                                               updatedMetadatas: updatedMetadatas,
-                                                               deletedMetadatas: deletedMetadatas)
-            }
-            return
-        } else if enumeratedItemIdentifier == .trashContainer {
-            Logger.enumeration.debug("Enumerating changes in trash set for user: \(self.ncAccount.ncKitAccount, privacy: .public)")
-            // TODO!
-
-            observer.finishEnumeratingChanges(upTo: anchor, moreComing: false)
-            return
-        }
-
-        Logger.enumeration.info("Enumerating changes for user: \(self.ncAccount.ncKitAccount, privacy: .public) with serverUrl: \(self.serverUrl, privacy: .public)")
-
-        // No matter what happens here we finish enumeration in some way, either from the error
-        // handling below or from the completeChangesObserver
-        // TODO: Move to the sync engine extension
-        FileProviderEnumerator.readServerUrl(serverUrl, ncAccount: ncAccount, ncKit: ncKit, stopAtMatchingEtags: true) { _, newMetadatas, updatedMetadatas, deletedMetadatas, readError in
-
-            // If we get a 404 we might add more deleted metadatas
-            var currentDeletedMetadatas: [NextcloudItemMetadataTable] = []
-            if let notNilDeletedMetadatas = deletedMetadatas {
-                currentDeletedMetadatas = notNilDeletedMetadatas
-            }
-
-            guard readError == nil else {
-                Logger.enumeration.error("Finishing enumeration of changes for user: \(self.ncAccount.ncKitAccount, privacy: .public) with serverUrl: \(self.serverUrl, privacy: .public) with error: \(readError!.localizedDescription, privacy: .public)")
-
-                let nkReadError = NKError(error: readError!)
-                let fpError = nkReadError.fileProviderError
-
-                if nkReadError.isNotFoundError {
-                    Logger.enumeration.info("404 error means item no longer exists. Deleting metadata and reporting \(self.serverUrl, privacy: .public) as deletion without error")
-
-                    guard let itemMetadata = self.enumeratedItemMetadata else {
-                        Logger.enumeration.error("Invalid enumeratedItemMetadata, could not delete metadata nor report deletion")
-                        observer.finishEnumeratingWithError(fpError)
-                        return
-                    }
-
-                    let dbManager = NextcloudFilesDatabaseManager.shared
-                    if itemMetadata.directory {
-                        if let deletedDirectoryMetadatas = dbManager.deleteDirectoryAndSubdirectoriesMetadata(ocId: itemMetadata.ocId) {
-                            currentDeletedMetadatas += deletedDirectoryMetadatas
-                        } else {
-                            Logger.enumeration.error("Something went wrong when recursively deleting directory not found.")
-                        }
-                    } else {
-                        dbManager.deleteItemMetadata(ocId: itemMetadata.ocId)
-                    }
-
-                    FileProviderEnumerator.completeChangesObserver(observer, anchor: anchor, ncKit: self.ncKit, newMetadatas: nil, updatedMetadatas: nil, deletedMetadatas: [itemMetadata])
-                    return
-                } else if nkReadError.isNoChangesError { // All is well, just no changed etags
-                    Logger.enumeration.info("Error was to say no changed files -- not bad error. Finishing change enumeration.")
-                    observer.finishEnumeratingChanges(upTo: anchor, moreComing: false)
-                    return;
-                }
-
-                observer.finishEnumeratingWithError(fpError)
-                return
-            }
-
-            Logger.enumeration.info("Finished reading serverUrl: \(self.serverUrl, privacy: .public) for user: \(self.ncAccount.ncKitAccount, privacy: .public)")
-
-            FileProviderEnumerator.completeChangesObserver(observer, anchor: anchor, ncKit: self.ncKit, newMetadatas: newMetadatas, updatedMetadatas: updatedMetadatas, deletedMetadatas: deletedMetadatas)
-        }
-    }
-
-    func currentSyncAnchor(completionHandler: @escaping (NSFileProviderSyncAnchor?) -> Void) {
-        completionHandler(anchor)
-    }
-
-    // MARK: - Helper methods
-
-    private static func metadatasToFileProviderItems(_ itemMetadatas: [NextcloudItemMetadataTable], ncKit: NextcloudKit, completionHandler: @escaping(_ items: [NSFileProviderItem]) -> Void) {
-        var items: [NSFileProviderItem] = []
-
-        let conversionQueue = DispatchQueue(label: "metadataToItemConversionQueue", qos: .userInitiated, attributes: .concurrent)
-        let appendQueue = DispatchQueue(label: "enumeratorItemAppendQueue", qos: .userInitiated) // Serial queue
-        let dispatchGroup = DispatchGroup()
-
-        for itemMetadata in itemMetadatas {
-            conversionQueue.async(group: dispatchGroup) {
-                if itemMetadata.e2eEncrypted {
-                    Logger.enumeration.info("Skipping encrypted metadata in enumeration: \(itemMetadata.ocId, privacy: .public) \(itemMetadata.fileName, privacy: .public)")
-                    return
-                }
-
-                if let parentItemIdentifier = NextcloudFilesDatabaseManager.shared.parentItemIdentifierFromMetadata(itemMetadata) {
-                    let item = FileProviderItem(metadata: itemMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: ncKit)
-                    Logger.enumeration.debug("Will enumerate item with ocId: \(itemMetadata.ocId, privacy: .public) and name: \(itemMetadata.fileName, privacy: .public)")
-
-                    appendQueue.async(group: dispatchGroup) {
-                        items.append(item)
-                    }
-                } else {
-                    Logger.enumeration.error("Could not get valid parentItemIdentifier for item with ocId: \(itemMetadata.ocId, privacy: .public) and name: \(itemMetadata.fileName, privacy: .public), skipping enumeration")
-                }
-            }
-        }
-
-        dispatchGroup.notify(queue: DispatchQueue.main) {
-            completionHandler(items)
-        }
-    }
-
-    private static func fileProviderPageforNumPage(_ numPage: Int) -> NSFileProviderPage {
-        return NSFileProviderPage("\(numPage)".data(using: .utf8)!)
-    }
-
-    private static func completeEnumerationObserver(_ observer: NSFileProviderEnumerationObserver, ncKit: NextcloudKit, numPage: Int, itemMetadatas: [NextcloudItemMetadataTable]) {
-
-        metadatasToFileProviderItems(itemMetadatas, ncKit: ncKit) { items in
-            observer.didEnumerate(items)
-            Logger.enumeration.info("Did enumerate \(items.count) items")
-
-            // TODO: Handle paging properly
-            /*
-             if items.count == maxItemsPerFileProviderPage {
-             let nextPage = numPage + 1
-             let providerPage = NSFileProviderPage("\(nextPage)".data(using: .utf8)!)
-             observer.finishEnumerating(upTo: providerPage)
-             } else {
-             observer.finishEnumerating(upTo: nil)
-             }
-             */
-            observer.finishEnumerating(upTo: fileProviderPageforNumPage(numPage))
-        }
-    }
-
-    private static func completeChangesObserver(_ observer: NSFileProviderChangeObserver, anchor: NSFileProviderSyncAnchor, ncKit: NextcloudKit, newMetadatas: [NextcloudItemMetadataTable]?, updatedMetadatas: [NextcloudItemMetadataTable]?, deletedMetadatas: [NextcloudItemMetadataTable]?) {
-
-        guard newMetadatas != nil || updatedMetadatas != nil || deletedMetadatas != nil else {
-            Logger.enumeration.error("Received invalid newMetadatas, updatedMetadatas or deletedMetadatas. Finished enumeration of changes with error.")
-            observer.finishEnumeratingWithError(NSFileProviderError(.noSuchItem))
-            return
-        }
-
-        // Observer does not care about new vs updated, so join
-        var allUpdatedMetadatas: [NextcloudItemMetadataTable] = []
-        var allDeletedMetadatas: [NextcloudItemMetadataTable] = []
-
-        if let newMetadatas = newMetadatas {
-            allUpdatedMetadatas += newMetadatas
-        }
-
-        if let updatedMetadatas = updatedMetadatas {
-            allUpdatedMetadatas += updatedMetadatas
-        }
-
-        if let deletedMetadatas = deletedMetadatas {
-            allDeletedMetadatas = deletedMetadatas
-        }
-
-        let allFpItemDeletionsIdentifiers = Array(allDeletedMetadatas.map { NSFileProviderItemIdentifier($0.ocId) })
-        if !allFpItemDeletionsIdentifiers.isEmpty {
-            observer.didDeleteItems(withIdentifiers: allFpItemDeletionsIdentifiers)
-        }
-
-        metadatasToFileProviderItems(allUpdatedMetadatas, ncKit: ncKit) { updatedItems in
-
-            if !updatedItems.isEmpty {
-                observer.didUpdate(updatedItems)
-            }
-
-            Logger.enumeration.info("Processed \(updatedItems.count) new or updated metadatas, \(allDeletedMetadatas.count) deleted metadatas.")
-            observer.finishEnumeratingChanges(upTo: anchor, moreComing: false)
-        }
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExt.entitlements b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExt.entitlements
deleted file mode 100644 (file)
index eab912d..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>com.apple.security.app-sandbox</key>
-       <true/>
-       <key>com.apple.security.application-groups</key>
-       <array>
-               <string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
-       </array>
-       <key>com.apple.security.network.client</key>
-       <true/>
-       <key>com.apple.security.network.server</key>
-       <true/>
-</dict>
-</plist>
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+ClientInterface.swift
deleted file mode 100644 (file)
index dd3bef8..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import FileProvider
-import OSLog
-import NCDesktopClientSocketKit
-import NextcloudKit
-
-extension FileProviderExtension {
-    func sendFileProviderDomainIdentifier() {
-        let command = "FILE_PROVIDER_DOMAIN_IDENTIFIER_REQUEST_REPLY"
-        let argument = domain.identifier.rawValue
-        let message = command + ":" + argument + "\n"
-        socketClient?.sendMessage(message)
-    }
-
-    private func signalEnumeratorAfterAccountSetup() {
-        guard let fpManager = NSFileProviderManager(for: domain) else {
-            Logger.fileProviderExtension.error("Could not get file provider manager for domain \(self.domain.displayName, privacy: .public), cannot notify after account setup")
-            return
-        }
-
-        assert(ncAccount != nil)
-
-        fpManager.signalErrorResolved(NSFileProviderError(.notAuthenticated)) { error in
-            if error != nil {
-                Logger.fileProviderExtension.error("Error resolving not authenticated, received error: \(error!.localizedDescription)")
-            }
-        }
-
-        Logger.fileProviderExtension.debug("Signalling enumerators for user \(self.ncAccount!.username) at server \(self.ncAccount!.serverUrl, privacy: .public)")
-
-        fpManager.signalEnumerator(for: .workingSet) { error in
-            if error != nil {
-                Logger.fileProviderExtension.error("Error signalling enumerator for working set, received error: \(error!.localizedDescription, privacy: .public)")
-            }
-        }
-    }
-
-    func setupDomainAccount(user: String, serverUrl: String, password: String) {
-        ncAccount = NextcloudAccount(user: user, serverUrl: serverUrl, password: password)
-        ncKit.setup(user: ncAccount!.username,
-                    userId: ncAccount!.username,
-                    password: ncAccount!.password,
-                    urlBase: ncAccount!.serverUrl,
-                    userAgent: "Nextcloud-macOS/FileProviderExt",
-                    nextcloudVersion: 25,
-                    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)")
-
-        signalEnumeratorAfterAccountSetup()
-    }
-
-    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)")
-        ncAccount = nil
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+Thumbnailing.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+Thumbnailing.swift
deleted file mode 100644 (file)
index 7abc460..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import FileProvider
-import NextcloudKit
-import OSLog
-
-extension FileProviderExtension: NSFileProviderThumbnailing {
-    func fetchThumbnails(for itemIdentifiers: [NSFileProviderItemIdentifier],
-                         requestedSize size: CGSize,
-                         perThumbnailCompletionHandler: @escaping (NSFileProviderItemIdentifier,
-                                                                   Data?,
-                                                                   Error?) -> Void,
-                         completionHandler: @escaping (Error?) -> Void) -> Progress {
-
-        let progress = Progress(totalUnitCount: Int64(itemIdentifiers.count))
-        var progressCounter: Int64 = 0
-
-        func finishCurrent() {
-            progressCounter += 1
-
-            if progressCounter == progress.totalUnitCount {
-                completionHandler(nil)
-            }
-        }
-
-        for itemIdentifier in itemIdentifiers {
-            Logger.fileProviderExtension.debug("Fetching thumbnail for item with identifier:\(itemIdentifier.rawValue, privacy: .public)")
-            guard let metadata = NextcloudFilesDatabaseManager.shared.itemMetadataFromFileProviderItemIdentifier(itemIdentifier),
-                  let thumbnailUrl = metadata.thumbnailUrl(size: size) else {
-                Logger.fileProviderExtension.debug("Did not fetch thumbnail URL")
-                finishCurrent()
-                continue
-            }
-
-            Logger.fileProviderExtension.debug("Fetching thumbnail for file:\(metadata.fileName) at:\(thumbnailUrl.absoluteString, privacy: .public)")
-
-            self.ncKit.getPreview(url: thumbnailUrl) { _, data, error in
-                if error == .success && data != nil {
-                    perThumbnailCompletionHandler(itemIdentifier, data, nil)
-                } else {
-                    perThumbnailCompletionHandler(itemIdentifier, nil, NSFileProviderError(.serverUnreachable))
-                }
-                finishCurrent()
-            }
-        }
-
-        return progress
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift
deleted file mode 100644 (file)
index e4912db..0000000
+++ /dev/null
@@ -1,633 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import FileProvider
-import OSLog
-import NCDesktopClientSocketKit
-import NextcloudKit
-
-class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKCommonDelegate {
-    let domain: NSFileProviderDomain
-    let ncKit = NextcloudKit()
-    lazy var ncKitBackground: NKBackground = {
-        let nckb = NKBackground(nkCommonInstance: ncKit.nkCommonInstance)
-        return nckb
-    }()
-
-    let appGroupIdentifier: String? = Bundle.main.object(forInfoDictionaryKey: "SocketApiPrefix") as? String
-    var ncAccount: NextcloudAccount?
-    lazy var socketClient: LocalSocketClient? = {
-        guard let containerUrl = pathForAppGroupContainer() else {
-            Logger.fileProviderExtension.critical("Could not start file provider socket client properly as could not get container url")
-            return nil;
-        }
-
-        let socketPath = containerUrl.appendingPathComponent(".fileprovidersocket", conformingTo: .archive)
-        let lineProcessor = FileProviderSocketLineProcessor(delegate: self)
-
-        return LocalSocketClient(socketPath: socketPath.path, lineProcessor: lineProcessor)
-    }()
-
-    let urlSessionIdentifier: String = "com.nextcloud.session.upload.fileproviderext"
-    let urlSessionMaximumConnectionsPerHost = 5
-    lazy var urlSession: URLSession = {
-        let configuration = URLSessionConfiguration.background(withIdentifier: urlSessionIdentifier)
-        configuration.allowsCellularAccess = true
-        configuration.sessionSendsLaunchEvents = true
-        configuration.isDiscretionary = false
-        configuration.httpMaximumConnectionsPerHost = urlSessionMaximumConnectionsPerHost
-        configuration.requestCachePolicy = NSURLRequest.CachePolicy.reloadIgnoringLocalCacheData
-        configuration.sharedContainerIdentifier = appGroupIdentifier
-
-        let session = URLSession(configuration: configuration, delegate: ncKitBackground, delegateQueue: OperationQueue.main)
-        return session
-    }()
-
-    required init(domain: NSFileProviderDomain) {
-        self.domain = domain
-        // The containing application must create a domain using `NSFileProviderManager.add(_:, completionHandler:)`. The system will then launch the application extension process, call `FileProviderExtension.init(domain:)` to instantiate the extension for that domain, and call methods on the instance.
-
-        super.init()
-        self.socketClient?.start()
-    }
-    
-    func invalidate() {
-        // TODO: cleanup any resources
-        Logger.fileProviderExtension.debug("Extension for domain \(self.domain.displayName, privacy: .public) is being torn down")
-    }
-
-    // MARK: NSFileProviderReplicatedExtension protocol methods
-    
-    func item(for identifier: NSFileProviderItemIdentifier, request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) -> Progress {
-        // resolve the given identifier to a record in the model
-
-        Logger.fileProviderExtension.debug("Received item request for item with identifier: \(identifier.rawValue, privacy: .public)")
-        if identifier == .rootContainer {
-            guard let ncAccount = ncAccount else {
-                Logger.fileProviderExtension.error("Not providing item: \(identifier.rawValue, privacy: .public) as account not set up yet")
-                completionHandler(nil, NSFileProviderError(.notAuthenticated))
-                return Progress()
-            }
-
-            let metadata = NextcloudItemMetadataTable()
-
-            metadata.account = ncAccount.ncKitAccount
-            metadata.directory = true
-            metadata.ocId = NSFileProviderItemIdentifier.rootContainer.rawValue
-            metadata.fileName = "root"
-            metadata.fileNameView = "root"
-            metadata.serverUrl = ncAccount.serverUrl
-            metadata.classFile = NKCommon.TypeClassFile.directory.rawValue
-
-            completionHandler(FileProviderItem(metadata: metadata, parentItemIdentifier: NSFileProviderItemIdentifier.rootContainer, ncKit: ncKit), nil)
-            return Progress()
-        }
-
-        let dbManager = NextcloudFilesDatabaseManager.shared
-        
-        guard let metadata = dbManager.itemMetadataFromFileProviderItemIdentifier(identifier),
-              let parentItemIdentifier = dbManager.parentItemIdentifierFromMetadata(metadata) else {
-            completionHandler(nil, NSFileProviderError(.noSuchItem))
-            return Progress()
-        }
-
-        completionHandler(FileProviderItem(metadata: metadata, parentItemIdentifier: parentItemIdentifier, ncKit: ncKit), nil)
-        return Progress()
-    }
-    
-    func fetchContents(for itemIdentifier: NSFileProviderItemIdentifier, version requestedVersion: NSFileProviderItemVersion?, request: NSFileProviderRequest, completionHandler: @escaping (URL?, NSFileProviderItem?, Error?) -> Void) -> Progress {
-
-        Logger.fileProviderExtension.debug("Received request to fetch contents of item with identifier: \(itemIdentifier.rawValue, privacy: .public)")
-
-        guard requestedVersion == nil else {
-            // TODO: Add proper support for file versioning
-            Logger.fileProviderExtension.error("Can't return contents for specific version as this is not supported.")
-            completionHandler(nil, nil, NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError, userInfo:[:]))
-            return Progress()
-        }
-
-        guard ncAccount != nil else {
-            Logger.fileProviderExtension.error("Not fetching contents item: \(itemIdentifier.rawValue, privacy: .public) as account not set up yet")
-            completionHandler(nil, nil, NSFileProviderError(.notAuthenticated))
-            return Progress()
-        }
-
-        let dbManager = NextcloudFilesDatabaseManager.shared
-        let ocId = itemIdentifier.rawValue
-        guard let metadata = dbManager.itemMetadataFromOcId(ocId) else {
-            Logger.fileProviderExtension.error("Could not acquire metadata of item with identifier: \(itemIdentifier.rawValue, privacy: .public)")
-            completionHandler(nil, nil, NSFileProviderError(.noSuchItem))
-            return Progress()
-        }
-
-        guard !metadata.isDocumentViewableOnly else {
-            Logger.fileProviderExtension.error("Could not get contents of item as is readonly: \(itemIdentifier.rawValue, privacy: .public) \(metadata.fileName, privacy: .public)")
-            completionHandler(nil, nil, NSFileProviderError(.cannotSynchronize))
-            return Progress()
-        }
-
-        let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
-
-        Logger.fileProviderExtension.debug("Fetching file with name \(metadata.fileName, privacy: .public) at URL: \(serverUrlFileName, privacy: .public)")
-
-        let progress = Progress()
-
-        // TODO: Handle folders nicely
-        do {
-            let fileNameLocalPath = try localPathForNCFile(ocId: metadata.ocId, fileNameView: metadata.fileNameView, domain: self.domain)
-
-            dbManager.setStatusForItemMetadata(metadata, status: NextcloudItemMetadataTable.Status.downloading) { updatedMetadata in
-
-                guard let updatedMetadata = updatedMetadata else {
-                    Logger.fileProviderExtension.error("Could not acquire updated metadata of item with identifier: \(itemIdentifier.rawValue, privacy: .public), unable to update item status to downloading")
-                    completionHandler(nil, nil, NSFileProviderError(.noSuchItem))
-                    return
-                }
-
-                self.ncKit.download(serverUrlFileName: serverUrlFileName,
-                                    fileNameLocalPath: fileNameLocalPath.path,
-                                    requestHandler: { request in
-                    progress.setHandlersFromAfRequest(request)
-                }, taskHandler: { task in
-                    NSFileProviderManager(for: self.domain)?.register(task, forItemWithIdentifier: itemIdentifier, completionHandler: { _ in })
-                }, progressHandler: { downloadProgress in
-                    downloadProgress.copyCurrentStateToProgress(progress)
-                }) { _, etag, date, _, _, _, error in
-                    if error == .success {
-                        Logger.fileTransfer.debug("Acquired contents of item with identifier: \(itemIdentifier.rawValue, privacy: .public) and filename: \(updatedMetadata.fileName, privacy: .public)")
-
-                        updatedMetadata.status = NextcloudItemMetadataTable.Status.normal.rawValue
-                        updatedMetadata.sessionError = ""
-                        updatedMetadata.date = (date ?? NSDate()) as Date
-                        updatedMetadata.etag = etag ?? ""
-
-                        dbManager.addLocalFileMetadataFromItemMetadata(updatedMetadata)
-                        dbManager.addItemMetadata(updatedMetadata)
-
-                        guard let parentItemIdentifier = dbManager.parentItemIdentifierFromMetadata(updatedMetadata) else {
-                            completionHandler(nil, nil, NSFileProviderError(.noSuchItem))
-                            return
-                        }
-
-                        let fpItem = FileProviderItem(metadata: updatedMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: self.ncKit)
-
-                        completionHandler(fileNameLocalPath, fpItem, nil)
-                    } else {
-                        Logger.fileTransfer.error("Could not acquire contents of item with identifier: \(itemIdentifier.rawValue, privacy: .public) and fileName: \(updatedMetadata.fileName, privacy: .public)")
-
-                        updatedMetadata.status = NextcloudItemMetadataTable.Status.downloadError.rawValue
-                        updatedMetadata.sessionError = error.errorDescription
-
-                        dbManager.addItemMetadata(updatedMetadata)
-
-                        completionHandler(nil, nil, error.fileProviderError)
-                    }
-                }
-            }
-        } catch let error {
-            Logger.fileProviderExtension.error("Could not find local path for file \(metadata.fileName, privacy: .public), received error: \(error.localizedDescription, privacy: .public)")
-            completionHandler(nil, nil, NSFileProviderError(.cannotSynchronize))
-        }
-
-        return progress
-    }
-    
-    func createItem(basedOn itemTemplate: NSFileProviderItem, fields: NSFileProviderItemFields, contents url: URL?, options: NSFileProviderCreateItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, NSFileProviderItemFields, Bool, Error?) -> Void) -> Progress {
-        // TODO: a new item was created on disk, process the item's creation
-
-        Logger.fileProviderExtension.debug("Received create item request for item with identifier: \(itemTemplate.itemIdentifier.rawValue, privacy: .public) and filename: \(itemTemplate.filename, privacy: .public)")
-
-        guard itemTemplate.contentType != .symbolicLink else {
-            Logger.fileProviderExtension.error("Cannot create item, symbolic links not supported.")
-            completionHandler(itemTemplate, NSFileProviderItemFields(), false, NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError, userInfo:[:]))
-            return Progress()
-        }
-
-        guard let ncAccount = ncAccount else {
-            Logger.fileProviderExtension.error("Not creating item: \(itemTemplate.itemIdentifier.rawValue, privacy: .public) as account not set up yet")
-            completionHandler(itemTemplate, NSFileProviderItemFields(), false, NSFileProviderError(.notAuthenticated))
-            return Progress()
-        }
-
-        let dbManager = NextcloudFilesDatabaseManager.shared
-        let parentItemIdentifier = itemTemplate.parentItemIdentifier
-        let itemTemplateIsFolder = itemTemplate.contentType == .folder ||
-                                   itemTemplate.contentType == .directory
-
-        if options.contains(.mayAlreadyExist) {
-            // TODO: This needs to be properly handled with a check in the db
-            Logger.fileProviderExtension.info("Not creating item: \(itemTemplate.itemIdentifier.rawValue, privacy: .public) as it may already exist")
-            completionHandler(itemTemplate, NSFileProviderItemFields(), false, NSFileProviderError(.noSuchItem))
-            return Progress()
-        }
-
-        var parentItemServerUrl: String
-
-        if parentItemIdentifier == .rootContainer {
-            parentItemServerUrl = ncAccount.davFilesUrl
-        } else {
-            guard let parentItemMetadata = dbManager.directoryMetadata(ocId: parentItemIdentifier.rawValue) else {
-                Logger.fileProviderExtension.error("Not creating item: \(itemTemplate.itemIdentifier.rawValue, privacy: .public), could not find metadata for parentItemIdentifier \(parentItemIdentifier.rawValue, privacy: .public)")
-                completionHandler(itemTemplate, NSFileProviderItemFields(), false, NSFileProviderError(.noSuchItem))
-                return Progress()
-            }
-
-            parentItemServerUrl = parentItemMetadata.serverUrl + "/" + parentItemMetadata.fileName
-        }
-
-        let fileNameLocalPath = url?.path ?? ""
-        let newServerUrlFileName = parentItemServerUrl + "/" + itemTemplate.filename
-
-        Logger.fileProviderExtension.debug("About to upload item with identifier: \(itemTemplate.itemIdentifier.rawValue, privacy: .public) of type: \(itemTemplate.contentType?.identifier ?? "UNKNOWN") (is folder: \(itemTemplateIsFolder ? "yes" : "no") and filename: \(itemTemplate.filename) to server url: \(newServerUrlFileName, privacy: .public) with contents located at: \(fileNameLocalPath, privacy: .public)")
-
-        if itemTemplateIsFolder {
-            self.ncKit.createFolder(serverUrlFileName: newServerUrlFileName) { account, ocId, _, error in
-                guard error == .success else {
-                    Logger.fileTransfer.error("Could not create new folder with name: \(itemTemplate.filename, privacy: .public), received error: \(error.errorDescription, privacy: .public)")
-                    completionHandler(itemTemplate, [], false, error.fileProviderError)
-                    return
-                }
-
-                // Read contents after creation
-                self.ncKit.readFileOrFolder(serverUrlFileName: newServerUrlFileName, depth: "0", showHiddenFiles: true) { account, files, _, error in
-                    guard error == .success else {
-                        Logger.fileTransfer.error("Could not read new folder with name: \(itemTemplate.filename, privacy: .public), received error: \(error.errorDescription, privacy: .public)")
-                        return
-                    }
-
-                    DispatchQueue.global().async {
-                        NextcloudItemMetadataTable.metadatasFromDirectoryReadNKFiles(files, account: account) { directoryMetadata, childDirectoriesMetadata, metadatas in
-
-                            dbManager.addItemMetadata(directoryMetadata)
-
-                            let fpItem = FileProviderItem(metadata: directoryMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: self.ncKit)
-
-                            completionHandler(fpItem, [], true, nil)
-                        }
-                    }
-                }
-            }
-
-            return Progress()
-        }
-
-        let progress = Progress()
-
-        self.ncKit.upload(serverUrlFileName: newServerUrlFileName,
-                          fileNameLocalPath: fileNameLocalPath,
-                          requestHandler: { request in
-            progress.setHandlersFromAfRequest(request)
-        }, taskHandler: { task in
-            NSFileProviderManager(for: self.domain)?.register(task, forItemWithIdentifier: itemTemplate.itemIdentifier, completionHandler: { _ in })
-        }, progressHandler: { uploadProgress in
-            uploadProgress.copyCurrentStateToProgress(progress)
-        }) { account, ocId, etag, date, size, _, _, error  in
-            guard error == .success, let ocId = ocId else {
-                Logger.fileTransfer.error("Could not upload item with filename: \(itemTemplate.filename, privacy: .public), received error: \(error.errorDescription, privacy: .public)")
-                completionHandler(itemTemplate, [], false, error.fileProviderError)
-                return
-            }
-
-            Logger.fileTransfer.info("Successfully uploaded item with identifier: \(ocId, privacy: .public) and filename: \(itemTemplate.filename, privacy: .public)")
-
-            if size != itemTemplate.documentSize as? Int64 {
-                Logger.fileTransfer.warning("Created item upload reported as successful, but there are differences between the received file size (\(size, privacy: .public)) and the original file size (\(itemTemplate.documentSize??.int64Value ?? 0))")
-            }
-
-            let newMetadata = NextcloudItemMetadataTable()
-            newMetadata.date = (date ?? NSDate()) as Date
-            newMetadata.etag = etag ?? ""
-            newMetadata.account = account
-            newMetadata.fileName = itemTemplate.filename
-            newMetadata.fileNameView = itemTemplate.filename
-            newMetadata.ocId = ocId
-            newMetadata.size = size
-            newMetadata.contentType = itemTemplate.contentType?.preferredMIMEType ?? ""
-            newMetadata.directory = itemTemplateIsFolder
-            newMetadata.serverUrl = parentItemServerUrl
-            newMetadata.session = ""
-            newMetadata.sessionError = ""
-            newMetadata.sessionTaskIdentifier = 0
-            newMetadata.status = NextcloudItemMetadataTable.Status.normal.rawValue
-
-            dbManager.addLocalFileMetadataFromItemMetadata(newMetadata)
-            dbManager.addItemMetadata(newMetadata)
-
-            let fpItem = FileProviderItem(metadata: newMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: self.ncKit)
-
-            completionHandler(fpItem, [], false, nil)
-        }
-
-        return progress
-    }
-    
-    func modifyItem(_ item: NSFileProviderItem, baseVersion version: NSFileProviderItemVersion, changedFields: NSFileProviderItemFields, contents newContents: URL?, options: NSFileProviderModifyItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, NSFileProviderItemFields, Bool, Error?) -> Void) -> Progress {
-        // An item was modified on disk, process the item's modification
-        // TODO: Handle finder things like tags, other possible item changed fields
-
-        Logger.fileProviderExtension.debug("Received modify item request for item with identifier: \(item.itemIdentifier.rawValue, privacy: .public) and filename: \(item.filename, privacy: .public)")
-
-        guard let ncAccount = ncAccount else {
-            Logger.fileProviderExtension.error("Not modifying item: \(item.itemIdentifier.rawValue, privacy: .public) as account not set up yet")
-            completionHandler(item, [], false, NSFileProviderError(.notAuthenticated))
-            return Progress()
-        }
-
-        let dbManager = NextcloudFilesDatabaseManager.shared
-        let parentItemIdentifier = item.parentItemIdentifier
-        let itemTemplateIsFolder = item.contentType == .folder ||
-                                   item.contentType == .directory
-
-        if options.contains(.mayAlreadyExist) {
-            // TODO: This needs to be properly handled with a check in the db
-            Logger.fileProviderExtension.warning("Modification for item: \(item.itemIdentifier.rawValue, privacy: .public) may already exist")
-        }
-
-        var parentItemServerUrl: String
-
-        if parentItemIdentifier == .rootContainer {
-            parentItemServerUrl = ncAccount.davFilesUrl
-        } else {
-            guard let parentItemMetadata = dbManager.directoryMetadata(ocId: parentItemIdentifier.rawValue) else {
-                Logger.fileProviderExtension.error("Not modifying item: \(item.itemIdentifier.rawValue, privacy: .public), could not find metadata for parentItemIdentifier \(parentItemIdentifier.rawValue, privacy: .public)")
-                completionHandler(item, [], false, NSFileProviderError(.noSuchItem))
-                return Progress()
-            }
-
-            parentItemServerUrl = parentItemMetadata.serverUrl + "/" + parentItemMetadata.fileName
-        }
-
-        let fileNameLocalPath = newContents?.path ?? ""
-        let newServerUrlFileName = parentItemServerUrl + "/" + item.filename
-
-        Logger.fileProviderExtension.debug("About to upload modified item with identifier: \(item.itemIdentifier.rawValue, privacy: .public) of type: \(item.contentType?.identifier ?? "UNKNOWN") (is folder: \(itemTemplateIsFolder ? "yes" : "no") and filename: \(item.filename, privacy: .public) to server url: \(newServerUrlFileName, privacy: .public) with contents located at: \(fileNameLocalPath, privacy: .public)")
-
-        var modifiedItem = item
-
-        // Create a serial dispatch queue
-        // We want to wait for network operations to finish before we fire off subsequent network
-        // operations, or we might cause explosions (e.g. trying to modify items that have just been
-        // moved elsewhere)
-        let dispatchQueue = DispatchQueue(label: "modifyItemQueue", qos: .userInitiated)
-
-        if changedFields.contains(.filename) || changedFields.contains(.parentItemIdentifier) {
-            dispatchQueue.async {
-                let ocId = item.itemIdentifier.rawValue
-                Logger.fileProviderExtension.debug("Changed fields for item \(ocId, privacy: .public) with filename \(item.filename, privacy: .public) includes filename or parentitemidentifier...")
-
-                guard let metadata = dbManager.itemMetadataFromOcId(ocId) else {
-                    Logger.fileProviderExtension.error("Could not acquire metadata of item with identifier: \(item.itemIdentifier.rawValue, privacy: .public)")
-                    completionHandler(item, [], false, NSFileProviderError(.noSuchItem))
-                    return
-                }
-
-                var renameError: NSFileProviderError?
-                let oldServerUrlFileName = metadata.serverUrl + "/" + metadata.fileName
-
-                let moveFileOrFolderDispatchGroup = DispatchGroup() // Make this block wait until done
-                moveFileOrFolderDispatchGroup.enter()
-
-                self.ncKit.moveFileOrFolder(serverUrlFileNameSource: oldServerUrlFileName,
-                                            serverUrlFileNameDestination: newServerUrlFileName,
-                                            overwrite: false) { account, error in
-                    guard error == .success else {
-                        Logger.fileTransfer.error("Could not move file or folder: \(oldServerUrlFileName, privacy: .public) to \(newServerUrlFileName, privacy: .public), received error: \(error.errorDescription, privacy: .public)")
-                        renameError = error.fileProviderError
-                        moveFileOrFolderDispatchGroup.leave()
-                        return
-                    }
-
-                    // Remember that a folder metadata's serverUrl is its direct server URL, while for
-                    // an item metadata the server URL is the parent folder's URL
-                    if itemTemplateIsFolder {
-                        _ = dbManager.renameDirectoryAndPropagateToChildren(ocId: ocId, newServerUrl: newServerUrlFileName, newFileName: item.filename)
-                        self.signalEnumerator { error in
-                            if error != nil {
-                                Logger.fileTransfer.error("Error notifying change in moved directory: \(error)")
-                            }
-                        }
-                    } else {
-                        dbManager.renameItemMetadata(ocId: ocId, newServerUrl: parentItemServerUrl, newFileName: item.filename)
-                    }
-
-                    guard let newMetadata = dbManager.itemMetadataFromOcId(ocId) else {
-                        Logger.fileTransfer.error("Could not acquire metadata of item with identifier: \(ocId, privacy: .public), cannot correctly inform of modification")
-                        renameError = NSFileProviderError(.noSuchItem)
-                        moveFileOrFolderDispatchGroup.leave()
-                        return
-                    }
-
-                    modifiedItem = FileProviderItem(metadata: newMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: self.ncKit)
-                    moveFileOrFolderDispatchGroup.leave()
-                }
-
-                moveFileOrFolderDispatchGroup.wait()
-
-                guard renameError == nil else {
-                    Logger.fileTransfer.error("Stopping rename of item with ocId \(ocId, privacy: .public) due to error: \(renameError!.localizedDescription, privacy: .public)")
-                    completionHandler(modifiedItem, [], false, renameError)
-                    return
-                }
-
-                guard !itemTemplateIsFolder else {
-                    Logger.fileTransfer.debug("Only handling renaming for folders. ocId: \(ocId, privacy: .public)")
-                    completionHandler(modifiedItem, [], false, nil)
-                    return
-                }
-            }
-
-            // Return the progress if item is folder here while the async block runs
-            guard !itemTemplateIsFolder else {
-                return Progress()
-            }
-        }
-
-        guard !itemTemplateIsFolder else {
-            Logger.fileTransfer.debug("System requested modification for folder with ocID \(item.itemIdentifier.rawValue, privacy: .public) (\(newServerUrlFileName, privacy: .public)) of something other than folder name.")
-            completionHandler(modifiedItem, [], false, nil)
-            return Progress()
-        }
-
-        let progress = Progress()
-
-        if changedFields.contains(.contents) {
-            dispatchQueue.async {
-                Logger.fileProviderExtension.debug("Item modification for \(item.itemIdentifier.rawValue, privacy: .public) \(item.filename, privacy: .public) includes contents")
-
-                guard newContents != nil else {
-                    Logger.fileProviderExtension.warning("WARNING. Could not upload modified contents as was provided nil contents url. ocId: \(item.itemIdentifier.rawValue, privacy: .public)")
-                    completionHandler(modifiedItem, [], false, NSFileProviderError(.noSuchItem))
-                    return
-                }
-
-                let ocId = item.itemIdentifier.rawValue
-                guard let metadata = dbManager.itemMetadataFromOcId(ocId) else {
-                    Logger.fileProviderExtension.error("Could not acquire metadata of item with identifier: \(ocId, privacy: .public)")
-                    completionHandler(item, NSFileProviderItemFields(), false, NSFileProviderError(.noSuchItem))
-                    return
-                }
-
-                dbManager.setStatusForItemMetadata(metadata, status: NextcloudItemMetadataTable.Status.uploading) { updatedMetadata in
-
-                    if updatedMetadata == nil {
-                        Logger.fileProviderExtension.warning("Could not acquire updated metadata of item with identifier: \(ocId, privacy: .public), unable to update item status to uploading")
-                    }
-
-                    self.ncKit.upload(serverUrlFileName: newServerUrlFileName,
-                                      fileNameLocalPath: fileNameLocalPath,
-                                      requestHandler: { request in
-                        progress.setHandlersFromAfRequest(request)
-                    }, taskHandler: { task in
-                        NSFileProviderManager(for: self.domain)?.register(task, forItemWithIdentifier: item.itemIdentifier, completionHandler: { _ in })
-                    }, progressHandler: { uploadProgress in
-                        uploadProgress.copyCurrentStateToProgress(progress)
-                    }) { account, ocId, etag, date, size, _, _, error  in
-                        if error == .success, let ocId = ocId {
-                            Logger.fileProviderExtension.info("Successfully uploaded item with identifier: \(ocId, privacy: .public) and filename: \(item.filename, privacy: .public)")
-
-                            if size != item.documentSize as? Int64 {
-                                Logger.fileTransfer.warning("Created item upload reported as successful, but there are differences between the received file size (\(size, privacy: .public)) and the original file size (\(item.documentSize??.int64Value ?? 0))")
-                            }
-
-                            let newMetadata = NextcloudItemMetadataTable()
-                            newMetadata.date = (date ?? NSDate()) as Date
-                            newMetadata.etag = etag ?? ""
-                            newMetadata.account = account
-                            newMetadata.fileName = item.filename
-                            newMetadata.fileNameView = item.filename
-                            newMetadata.ocId = ocId
-                            newMetadata.size = size
-                            newMetadata.contentType = item.contentType?.preferredMIMEType ?? ""
-                            newMetadata.directory = itemTemplateIsFolder
-                            newMetadata.serverUrl = parentItemServerUrl
-                            newMetadata.session = ""
-                            newMetadata.sessionError = ""
-                            newMetadata.sessionTaskIdentifier = 0
-                            newMetadata.status = NextcloudItemMetadataTable.Status.normal.rawValue
-
-                            dbManager.addLocalFileMetadataFromItemMetadata(newMetadata)
-                            dbManager.addItemMetadata(newMetadata)
-
-                            modifiedItem = FileProviderItem(metadata: newMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: self.ncKit)
-                            completionHandler(modifiedItem, [], false, nil)
-                        } else {
-                            Logger.fileTransfer.error("Could not upload item \(item.itemIdentifier.rawValue, privacy: .public) with filename: \(item.filename, privacy: .public), received error: \(error.errorDescription, privacy: .public)")
-
-                            metadata.status = NextcloudItemMetadataTable.Status.uploadError.rawValue
-                            metadata.sessionError = error.errorDescription
-
-                            dbManager.addItemMetadata(metadata)
-
-                            completionHandler(modifiedItem, [], false, error.fileProviderError)
-                            return
-                        }
-                    }
-                }
-            }
-        } else {
-            Logger.fileProviderExtension.debug("Nothing more to do with \(item.itemIdentifier.rawValue, privacy: .public) \(item.filename, privacy: .public), modifications complete")
-            completionHandler(modifiedItem, [], false, nil)
-        }
-
-        return progress
-    }
-    
-    func deleteItem(identifier: NSFileProviderItemIdentifier, baseVersion version: NSFileProviderItemVersion, options: NSFileProviderDeleteItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (Error?) -> Void) -> Progress {
-
-        Logger.fileProviderExtension.debug("Received delete item request for item with identifier: \(identifier.rawValue, privacy: .public)")
-
-        guard ncAccount != nil else {
-            Logger.fileProviderExtension.error("Not deleting item: \(identifier.rawValue, privacy: .public) as account not set up yet")
-            completionHandler(NSFileProviderError(.notAuthenticated))
-            return Progress()
-        }
-
-        let dbManager = NextcloudFilesDatabaseManager.shared
-        let ocId = identifier.rawValue
-        guard let itemMetadata = dbManager.itemMetadataFromOcId(ocId) else {
-            completionHandler(NSFileProviderError(.noSuchItem))
-            return Progress()
-        }
-
-        let serverFileNameUrl = itemMetadata.serverUrl + "/" + itemMetadata.fileName
-        guard serverFileNameUrl != "" else {
-            completionHandler(NSFileProviderError(.noSuchItem))
-            return Progress()
-        }
-
-        self.ncKit.deleteFileOrFolder(serverUrlFileName: serverFileNameUrl) { account, error in
-            guard error == .success else {
-                Logger.fileTransfer.error("Could not delete item with ocId \(identifier.rawValue, privacy: .public) at \(serverFileNameUrl, privacy: .public), received error: \(error.errorDescription, privacy: .public)")
-                completionHandler(error.fileProviderError)
-                return
-            }
-
-            Logger.fileTransfer.info("Successfully deleted item with identifier: \(identifier.rawValue, privacy: .public) at: \(serverFileNameUrl, privacy: .public)")
-
-            if itemMetadata.directory {
-                _ = dbManager.deleteDirectoryAndSubdirectoriesMetadata(ocId: ocId)
-            } else {
-                dbManager.deleteItemMetadata(ocId: ocId)
-                if dbManager.localFileMetadataFromOcId(ocId) != nil {
-                    dbManager.deleteLocalFileMetadata(ocId: ocId)
-                }
-            }
-
-            completionHandler(nil)
-        }
-
-        return Progress()
-    }
-    
-    func enumerator(for containerItemIdentifier: NSFileProviderItemIdentifier, request: NSFileProviderRequest) throws -> NSFileProviderEnumerator {
-
-        guard let ncAccount = ncAccount else {
-            Logger.fileProviderExtension.error("Not providing enumerator for container with identifier \(containerItemIdentifier.rawValue, privacy: .public) yet as account not set up")
-            throw NSFileProviderError(.notAuthenticated)
-        }
-
-        return FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier, ncAccount: ncAccount, ncKit: ncKit)
-    }
-
-    func materializedItemsDidChange(completionHandler: @escaping () -> Void) {
-        guard let ncAccount = self.ncAccount else {
-            Logger.fileProviderExtension.error("Not purging stale local file metadatas, account not set up")
-            completionHandler()
-            return
-        }
-
-        guard let fpManager = NSFileProviderManager(for: domain) else {
-            Logger.fileProviderExtension.error("Could not get file provider manager for domain: \(self.domain.displayName, privacy: .public)")
-            completionHandler()
-            return
-        }
-
-        let materialisedEnumerator = fpManager.enumeratorForMaterializedItems()
-        let materialisedObserver = FileProviderMaterialisedEnumerationObserver(ncKitAccount: ncAccount.ncKitAccount) { _ in
-            completionHandler()
-        }
-        let startingPage = NSFileProviderPage(NSFileProviderPage.initialPageSortedByName as Data)
-
-        materialisedEnumerator.enumerateItems(for: materialisedObserver, startingAt: startingPage)
-    }
-
-    func signalEnumerator(completionHandler: @escaping(_ error: Error?) -> Void) {
-        guard let fpManager = NSFileProviderManager(for: self.domain) else {
-            Logger.fileProviderExtension.error("Could not get file provider manager for domain, could not signal enumerator. This might lead to future conflicts.")
-            return
-        }
-
-        fpManager.signalEnumerator(for: .workingSet, completionHandler: completionHandler)
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderItem.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderItem.swift
deleted file mode 100644 (file)
index 9a3c3e7..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import FileProvider
-import UniformTypeIdentifiers
-import NextcloudKit
-
-class FileProviderItem: NSObject, NSFileProviderItem {
-
-    enum FileProviderItemTransferError: Error {
-        case downloadError
-        case uploadError
-    }
-
-    let metadata: NextcloudItemMetadataTable
-    let parentItemIdentifier: NSFileProviderItemIdentifier
-    let ncKit: NextcloudKit
-    
-    var itemIdentifier: NSFileProviderItemIdentifier {
-        return NSFileProviderItemIdentifier(metadata.ocId)
-    }
-    
-    var capabilities: NSFileProviderItemCapabilities {
-        guard !metadata.directory else {
-            return [ .allowsAddingSubItems,
-                     .allowsContentEnumerating,
-                     .allowsReading,
-                     .allowsDeleting,
-                     .allowsRenaming ]
-        }
-        guard !metadata.lock else {
-            return [ .allowsReading ]
-        }
-        return [ .allowsWriting,
-                 .allowsReading,
-                 .allowsDeleting,
-                 .allowsRenaming,
-                 .allowsReparenting ]
-    }
-    
-    var itemVersion: NSFileProviderItemVersion {
-        NSFileProviderItemVersion(contentVersion: metadata.etag.data(using: .utf8)!,
-                                  metadataVersion: metadata.etag.data(using: .utf8)!)
-    }
-    
-    var filename: String {
-        return metadata.fileNameView
-    }
-    
-    var contentType: UTType {
-        if self.itemIdentifier == .rootContainer || metadata.directory {
-            return .folder
-        }
-
-        let internalType = ncKit.nkCommonInstance.getInternalType(fileName: metadata.fileNameView,
-                                                                  mimeType: "",
-                                                                  directory: metadata.directory)
-        return UTType(filenameExtension: internalType.ext) ?? .content
-    }
-
-    var documentSize: NSNumber? {
-        return NSNumber(value: metadata.size)
-    }
-
-    var creationDate: Date? {
-        return metadata.creationDate as Date
-    }
-
-    var lastUsedDate: Date? {
-        return metadata.date as Date
-    }
-
-    var contentModificationDate: Date? {
-        return metadata.date as Date
-    }
-
-    var isDownloaded: Bool {
-        return metadata.directory || NextcloudFilesDatabaseManager.shared.localFileMetadataFromOcId(metadata.ocId) != nil
-    }
-
-    var isDownloading: Bool {
-        return metadata.status == NextcloudItemMetadataTable.Status.downloading.rawValue
-    }
-
-    var downloadingError: Error? {
-        if metadata.status == NextcloudItemMetadataTable.Status.downloadError.rawValue {
-            return FileProviderItemTransferError.downloadError
-        }
-        return nil
-    }
-
-    var isUploaded: Bool {
-        return NextcloudFilesDatabaseManager.shared.localFileMetadataFromOcId(metadata.ocId) != nil
-    }
-
-    var isUploading: Bool {
-        return metadata.status == NextcloudItemMetadataTable.Status.uploading.rawValue
-    }
-
-    var uploadingError: Error? {
-        if metadata.status == NextcloudItemMetadataTable.Status.uploadError.rawValue {
-            return FileProviderItemTransferError.uploadError
-        } else {
-            return nil
-        }
-    }
-
-    var childItemCount: NSNumber? {
-        if metadata.directory {
-            return NSNumber(integerLiteral: NextcloudFilesDatabaseManager.shared.childItemsForDirectory(metadata).count)
-        } else {
-            return nil
-        }
-    }
-
-    required init(metadata: NextcloudItemMetadataTable, parentItemIdentifier: NSFileProviderItemIdentifier, ncKit: NextcloudKit) {
-        self.metadata = metadata
-        self.parentItemIdentifier = parentItemIdentifier
-        self.ncKit = ncKit
-        super.init()
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderMaterialisedEnumerationObserver.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderMaterialisedEnumerationObserver.swift
deleted file mode 100644 (file)
index 168de66..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import FileProvider
-import OSLog
-
-class FileProviderMaterialisedEnumerationObserver : NSObject, NSFileProviderEnumerationObserver {
-    let ncKitAccount: String
-    let completionHandler: (_ deletedOcIds: Set<String>) -> Void
-    var allEnumeratedItemIds: Set<String> = Set<String>()
-
-    required init(ncKitAccount: String, completionHandler: @escaping(_ deletedOcIds: Set<String>) -> Void) {
-        self.ncKitAccount = ncKitAccount
-        self.completionHandler = completionHandler
-        super.init()
-    }
-
-    func didEnumerate(_ updatedItems: [NSFileProviderItemProtocol]) {
-        let updatedItemsIds = Array(updatedItems.map { $0.itemIdentifier.rawValue })
-
-        for updatedItemsId in updatedItemsIds {
-            allEnumeratedItemIds.insert(updatedItemsId)
-        }
-    }
-
-    func finishEnumerating(upTo nextPage: NSFileProviderPage?) {
-        Logger.materialisedFileHandling.debug("Handling enumerated materialised items.")
-        FileProviderMaterialisedEnumerationObserver.handleEnumeratedItems(self.allEnumeratedItemIds,
-                                                                          account: self.ncKitAccount,
-                                                                          completionHandler: self.completionHandler)
-    }
-
-    func finishEnumeratingWithError(_ error: Error) {
-        Logger.materialisedFileHandling.error("Ran into error when enumerating materialised items: \(error.localizedDescription, privacy: .public). Handling items enumerated so far")
-        FileProviderMaterialisedEnumerationObserver.handleEnumeratedItems(self.allEnumeratedItemIds,
-                                                                          account: self.ncKitAccount,
-                                                                          completionHandler: self.completionHandler)
-    }
-
-    static func handleEnumeratedItems(_ itemIds: Set<String>, account: String, completionHandler: @escaping(_ deletedOcIds: Set<String>) -> Void) {
-        let dbManager = NextcloudFilesDatabaseManager.shared
-        let databaseLocalFileMetadatas = dbManager.localFileMetadatas(account: account)
-        var noLongerMaterialisedIds = Set<String>()
-
-        DispatchQueue.global(qos: .background).async {
-            for localFile in databaseLocalFileMetadatas {
-                let localFileOcId = localFile.ocId
-
-                guard itemIds.contains(localFileOcId) else {
-                    noLongerMaterialisedIds.insert(localFileOcId)
-                    continue;
-                }
-            }
-
-            DispatchQueue.main.async {
-                Logger.materialisedFileHandling.info("Cleaning up local file metadatas for unmaterialised items")
-                for itemId in noLongerMaterialisedIds {
-                    dbManager.deleteLocalFileMetadata(ocId: itemId)
-                }
-
-                completionHandler(noLongerMaterialisedIds)
-            }
-        }
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderSocketLineProcessor.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderSocketLineProcessor.swift
deleted file mode 100644 (file)
index cf6ff8c..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import NCDesktopClientSocketKit
-import OSLog
-
-class FileProviderSocketLineProcessor: NSObject, LineProcessor {
-    var delegate: FileProviderExtension
-
-    required init(delegate: FileProviderExtension) {
-        self.delegate = delegate
-    }
-
-    func process(_ line: String) {
-        if (line.contains("~")) { // We use this as the separator specifically in ACCOUNT_DETAILS
-            Logger.desktopClientConnection.debug("Processing file provider line with potentially sensitive user data")
-        } else {
-            Logger.desktopClientConnection.debug("Processing file provider line: \(line, privacy: .public)")
-        }
-
-        let splitLine = line.split(separator: ":", maxSplits: 1)
-        guard let commandSubsequence = splitLine.first else {
-            Logger.desktopClientConnection.error("Input line did not have a first element")
-            return;
-        }
-        let command = String(commandSubsequence);
-
-        Logger.desktopClientConnection.debug("Received command: \(command, privacy: .public)")
-        if (command == "SEND_FILE_PROVIDER_DOMAIN_IDENTIFIER") {
-            delegate.sendFileProviderDomainIdentifier()
-        } else if (command == "ACCOUNT_NOT_AUTHENTICATED") {
-            delegate.removeAccountConfig()
-        } else if (command == "ACCOUNT_DETAILS") {
-            guard let accountDetailsSubsequence = splitLine.last else { return }
-            let splitAccountDetails = accountDetailsSubsequence.split(separator: "~", maxSplits: 2)
-
-            let user = String(splitAccountDetails[0])
-            let serverUrl = String(splitAccountDetails[1])
-            let password = String(splitAccountDetails[2])
-
-            delegate.setupDomainAccount(user: user, serverUrl: serverUrl, password: password)
-        }
-    }
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Info.plist b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Info.plist
deleted file mode 100644 (file)
index e5ab2fb..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>CFBundleName</key>
-       <string>$(PRODUCT_NAME)</string>
-       <key>CFBundleDisplayName</key>
-       <string>$(OC_APPLICATION_NAME) File Provider Extension</string>
-       <key>CFBundleIdentifier</key>
-       <string>$(OC_APPLICATION_REV_DOMAIN).$(PRODUCT_NAME)</string>
-       <key>NSExtension</key>
-       <dict>
-               <key>NSExtensionFileProviderDocumentGroup</key>
-               <string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
-               <key>NSExtensionFileProviderSupportsEnumeration</key>
-               <true/>
-               <key>NSExtensionPointIdentifier</key>
-               <string>com.apple.fileprovider-nonui</string>
-               <key>NSExtensionPrincipalClass</key>
-               <string>$(PRODUCT_MODULE_NAME).FileProviderExtension</string>
-       </dict>
-       <key>SocketApiPrefix</key>
-       <string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
-</dict>
-</plist>
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/LocalFilesUtils.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/LocalFilesUtils.swift
deleted file mode 100644 (file)
index 1e68cf8..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import FileProvider
-import OSLog
-
-func pathForAppGroupContainer() -> URL? {
-    guard let appGroupIdentifier = Bundle.main.object(forInfoDictionaryKey: "SocketApiPrefix") as? String else {
-        Logger.localFileOps.critical("Could not get container url as missing SocketApiPrefix info in app Info.plist")
-        return nil
-    }
-
-    return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier)
-}
-
-func pathForFileProviderExtData() -> URL? {
-    let containerUrl = pathForAppGroupContainer()
-    return containerUrl?.appendingPathComponent("FileProviderExt/")
-}
-
-func pathForFileProviderTempFilesForDomain(_ domain: NSFileProviderDomain) throws -> URL? {
-    guard let fpManager = NSFileProviderManager(for: domain) else {
-        Logger.localFileOps.error("Unable to get file provider manager for domain: \(domain.displayName, privacy: .public)")
-        throw NSFileProviderError(.providerNotFound)
-    }
-
-    let fileProviderDataUrl = try fpManager.temporaryDirectoryURL()
-    return fileProviderDataUrl.appendingPathComponent("TemporaryNextcloudFiles/")
-}
-
-func localPathForNCFile(ocId: String, fileNameView: String, domain: NSFileProviderDomain) throws -> URL {
-    guard let fileProviderFilesPathUrl = try pathForFileProviderTempFilesForDomain(domain) else {
-        Logger.localFileOps.error("Unable to get path for file provider temp files for domain: \(domain.displayName, privacy: .public)")
-        throw URLError(.badURL)
-    }
-
-    let filePathUrl = fileProviderFilesPathUrl.appendingPathComponent(fileNameView)
-    let filePath = filePathUrl.path
-
-    if !FileManager.default.fileExists(atPath: filePath) {
-        FileManager.default.createFile(atPath: filePath, contents: nil)
-    }
-
-    return filePathUrl
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/NextcloudAccount.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/NextcloudAccount.swift
deleted file mode 100644 (file)
index 0dc628d..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-import Foundation
-import FileProvider
-
-class NextcloudAccount: NSObject {
-    static let webDavFilesUrlSuffix: String = "/remote.php/dav/files/"
-    let username, password, ncKitAccount, serverUrl, davFilesUrl: String
-
-    init(user: String, serverUrl: String, password: String) {
-        self.username = user
-        self.password = password
-        self.ncKitAccount = user + " " + serverUrl
-        self.serverUrl = serverUrl
-        self.davFilesUrl = serverUrl + NextcloudAccount.webDavFilesUrlSuffix + user
-
-        super.init()
-    }
-}
-
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.h b/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.h
deleted file mode 100644 (file)
index 8d73f92..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) by Jocelyn Turcotte <jturcotte@woboq.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-
-#import <Cocoa/Cocoa.h>
-#import <FinderSync/FinderSync.h>
-#import <NCDesktopClientSocketKit/LocalSocketClient.h>
-
-#import "SyncClient.h"
-#import "FinderSyncSocketLineProcessor.h"
-
-@interface FinderSync : FIFinderSync <SyncClientDelegate>
-{
-    NSMutableSet *_registeredDirectories;
-    NSString *_shareMenuTitle;
-    NSMutableDictionary *_strings;
-    NSMutableArray *_menuItems;
-    NSCondition *_menuIsComplete;
-}
-
-@property FinderSyncSocketLineProcessor *lineProcessor;
-@property LocalSocketClient *localSocketClient;
-
-@end
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.m b/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.m
deleted file mode 100644 (file)
index 3e8123e..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) by Jocelyn Turcotte <jturcotte@woboq.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-
-#import "FinderSync.h"
-
-
-@implementation FinderSync
-
-- (instancetype)init
-{
-       self = [super init];
-
-    if (self) {
-        FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
-        NSBundle *extBundle = [NSBundle bundleForClass:[self class]];
-        // This was added to the bundle's Info.plist to get it from the build system
-        NSString *socketApiPrefix = [extBundle objectForInfoDictionaryKey:@"SocketApiPrefix"];
-
-        NSImage *ok = [extBundle imageForResource:@"ok.icns"];
-        NSImage *ok_swm = [extBundle imageForResource:@"ok_swm.icns"];
-        NSImage *sync = [extBundle imageForResource:@"sync.icns"];
-        NSImage *warning = [extBundle imageForResource:@"warning.icns"];
-        NSImage *error = [extBundle imageForResource:@"error.icns"];
-
-        [syncController setBadgeImage:ok label:@"Up to date" forBadgeIdentifier:@"OK"];
-        [syncController setBadgeImage:sync label:@"Synchronizing" forBadgeIdentifier:@"SYNC"];
-        [syncController setBadgeImage:sync label:@"Synchronizing" forBadgeIdentifier:@"NEW"];
-        [syncController setBadgeImage:warning label:@"Ignored" forBadgeIdentifier:@"IGNORE"];
-        [syncController setBadgeImage:error label:@"Error" forBadgeIdentifier:@"ERROR"];
-        [syncController setBadgeImage:ok_swm label:@"Shared" forBadgeIdentifier:@"OK+SWM"];
-        [syncController setBadgeImage:sync label:@"Synchronizing" forBadgeIdentifier:@"SYNC+SWM"];
-        [syncController setBadgeImage:sync label:@"Synchronizing" forBadgeIdentifier:@"NEW+SWM"];
-        [syncController setBadgeImage:warning label:@"Ignored" forBadgeIdentifier:@"IGNORE+SWM"];
-        [syncController setBadgeImage:error label:@"Error" forBadgeIdentifier:@"ERROR+SWM"];
-
-        // The Mach port name needs to:
-        // - Be prefixed with the code signing Team ID
-        // - Then infixed with the sandbox App Group
-        // - The App Group itself must be a prefix of (or equal to) the application bundle identifier
-        // We end up in the official signed client with: 9B5WD74GWJ.com.owncloud.desktopclient.socket
-        // With ad-hoc signing (the '-' signing identity) we must drop the Team ID.
-        // When the code isn't sandboxed (e.g. the OC client or the legacy overlay icon extension)
-        // the OS doesn't seem to put any restriction on the port name, so we just follow what
-        // the sandboxed App Extension needs.
-        // https://developer.apple.com/library/mac/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24
-
-        NSURL *container = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:socketApiPrefix];
-        NSURL *socketPath = [container URLByAppendingPathComponent:@".socket" isDirectory:NO];
-
-        NSLog(@"Socket path: %@", socketPath.path);
-
-        if (socketPath.path) {
-            self.lineProcessor = [[FinderSyncSocketLineProcessor alloc] initWithDelegate:self];
-            self.localSocketClient = [[LocalSocketClient alloc] initWithSocketPath:socketPath.path
-                                                                     lineProcessor:self.lineProcessor];
-            [self.localSocketClient start];
-            [self.localSocketClient askOnSocket:@"" query:@"GET_STRINGS"];
-        } else {
-            NSLog(@"No socket path. Not initiating local socket client.");
-            self.localSocketClient = nil;
-        }
-    }
-
-    return self;
-}
-
-#pragma mark - Primary Finder Sync protocol methods
-
-- (void)requestBadgeIdentifierForURL:(NSURL *)url
-{
-       BOOL isDir;
-       if ([[NSFileManager defaultManager] fileExistsAtPath:[url path] isDirectory: &isDir] == NO) {
-               NSLog(@"ERROR: Could not determine file type of %@", [url path]);
-               isDir = NO;
-       }
-
-       NSString* normalizedPath = [[url path] decomposedStringWithCanonicalMapping];
-       [self.localSocketClient askForIcon:normalizedPath isDirectory:isDir];
-}
-
-#pragma mark - Menu and toolbar item support
-
-- (NSString*) selectedPathsSeparatedByRecordSeparator
-{
-       FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
-       NSMutableString *string = [[NSMutableString alloc] init];
-       [syncController.selectedItemURLs enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
-               if (string.length > 0) {
-                       [string appendString:@"\x1e"]; // record separator
-               }
-               NSString* normalizedPath = [[obj path] decomposedStringWithCanonicalMapping];
-               [string appendString:normalizedPath];
-       }];
-       return string;
-}
-
-- (void)waitForMenuToArrive
-{
-    [self->_menuIsComplete lock];
-    [self->_menuIsComplete wait];
-    [self->_menuIsComplete unlock];
-}
-
-- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu
-{
-    if(![self.localSocketClient isConnected]) {
-        return nil;
-    }
-    
-       FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
-       NSMutableSet *rootPaths = [[NSMutableSet alloc] init];
-       [syncController.directoryURLs enumerateObjectsUsingBlock: ^(id obj, BOOL *stop) {
-               [rootPaths addObject:[obj path]];
-       }];
-
-       // The server doesn't support sharing a root directory so do not show the option in this case.
-       // It is still possible to get a problematic sharing by selecting both the root and a child,
-       // but this is so complicated to do and meaningless that it's not worth putting this check
-       // also in shareMenuAction.
-       __block BOOL onlyRootsSelected = YES;
-       [syncController.selectedItemURLs enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
-               if (![rootPaths member:[obj path]]) {
-                       onlyRootsSelected = NO;
-                       *stop = YES;
-               }
-       }];
-
-       NSString *paths = [self selectedPathsSeparatedByRecordSeparator];
-       [self.localSocketClient askOnSocket:paths query:@"GET_MENU_ITEMS"];
-    
-    // Since the LocalSocketClient communicates asynchronously. wait here until the menu
-    // is delivered by another thread
-    [self waitForMenuToArrive];
-
-       id contextMenuTitle = [_strings objectForKey:@"CONTEXT_MENU_TITLE"];
-       if (contextMenuTitle && !onlyRootsSelected) {
-               NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
-               NSMenu *subMenu = [[NSMenu alloc] initWithTitle:@""];
-               NSMenuItem *subMenuItem = [menu addItemWithTitle:contextMenuTitle action:nil keyEquivalent:@""];
-               subMenuItem.submenu = subMenu;
-               subMenuItem.image = [[NSBundle mainBundle] imageForResource:@"app.icns"];
-
-               // There is an annoying bug in macOS (at least 10.13.3), it does not use/copy over the representedObject of a menu item
-               // So we have to use tag instead.
-               int idx = 0;
-               for (NSArray* item in _menuItems) {
-                       NSMenuItem *actionItem = [subMenu addItemWithTitle:[item valueForKey:@"text"]
-                                                                                                               action:@selector(subMenuActionClicked:)
-                                                                                                keyEquivalent:@""];
-                       [actionItem setTag:idx];
-                       [actionItem setTarget:self];
-                       NSString *flags = [item valueForKey:@"flags"]; // e.g. "d"
-                       if ([flags rangeOfString:@"d"].location != NSNotFound) {
-                               [actionItem setEnabled:false];
-                       }
-                       idx++;
-               }
-               return menu;
-       }
-       return nil;
-}
-
-- (void)subMenuActionClicked:(id)sender {
-       long idx = [(NSMenuItem*)sender tag];
-       NSString *command = [[_menuItems objectAtIndex:idx] valueForKey:@"command"];
-       NSString *paths = [self selectedPathsSeparatedByRecordSeparator];
-       [self.localSocketClient askOnSocket:paths query:command];
-}
-
-#pragma mark - SyncClientProxyDelegate implementation
-
-- (void)setResultForPath:(NSString*)path result:(NSString*)result
-{
-       NSString *normalizedPath = [path decomposedStringWithCanonicalMapping];
-       [[FIFinderSyncController defaultController] setBadgeIdentifier:result forURL:[NSURL fileURLWithPath:normalizedPath]];
-}
-
-- (void)reFetchFileNameCacheForPath:(NSString*)path
-{
-    
-}
-
-- (void)registerPath:(NSString*)path
-{
-       assert(_registeredDirectories);
-       [_registeredDirectories addObject:[NSURL fileURLWithPath:path]];
-       [FIFinderSyncController defaultController].directoryURLs = _registeredDirectories;
-}
-
-- (void)unregisterPath:(NSString*)path
-{
-       [_registeredDirectories removeObject:[NSURL fileURLWithPath:path]];
-       [FIFinderSyncController defaultController].directoryURLs = _registeredDirectories;
-}
-
-- (void)setString:(NSString*)key value:(NSString*)value
-{
-       [_strings setObject:value forKey:key];
-}
-
-- (void)resetMenuItems
-{
-       _menuItems = [[NSMutableArray alloc] init];
-}
-- (void)addMenuItem:(NSDictionary *)item {
-    NSLog(@"Adding menu item.");
-       [_menuItems addObject:item];
-}
-
-- (void)menuHasCompleted
-{
-    NSLog(@"Emitting menu is complete signal now.");
-    [self->_menuIsComplete signal];
-}
-
-- (void)connectionDidDie
-{
-       [_strings removeAllObjects];
-       [_registeredDirectories removeAllObjects];
-       // For some reason the FIFinderSync cache doesn't seem to be cleared for the root item when
-       // we reset the directoryURLs (seen on macOS 10.12 at least).
-       // First setting it to the FS root and then setting it to nil seems to work around the issue.
-       [FIFinderSyncController defaultController].directoryURLs = [NSSet setWithObject:[NSURL fileURLWithPath:@"/"]];
-       // This will tell Finder that this extension isn't attached to any directory
-       // until we can reconnect to the sync client.
-       [FIFinderSyncController defaultController].directoryURLs = nil;
-}
-
-@end
-
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSyncExt.entitlements b/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSyncExt.entitlements
deleted file mode 100644 (file)
index 5d2a36d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>com.apple.security.app-sandbox</key>
-       <true/>
-       <key>com.apple.security.application-groups</key>
-       <array>
-               <string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
-       </array>
-</dict>
-</plist>
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSyncSocketLineProcessor.h b/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSyncSocketLineProcessor.h
deleted file mode 100644 (file)
index 0ff77c8..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#import <NCDesktopClientSocketKit/LineProcessor.h>
-
-#import "SyncClient.h"
-
-#ifndef FinderSyncSocketLineProcessor_h
-#define FinderSyncSocketLineProcessor_h
-
-/// This class is in charge of dispatching all work that must be done on the UI side of the extension.
-/// Tasks are dispatched on the main UI thread for this reason.
-///
-/// These tasks are parsed from byte data (UTF8 strings) acquired from the socket; look at the
-/// LocalSocketClient for more detail on how data is read from and written to the socket.
-
-@interface FinderSyncSocketLineProcessor : NSObject<LineProcessor>
-
-@property(nonatomic, weak) id<SyncClientDelegate> delegate;
-
-- (instancetype)initWithDelegate:(id<SyncClientDelegate>)delegate;
-
-@end
-#endif /* LineProcessor_h */
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSyncSocketLineProcessor.m b/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSyncSocketLineProcessor.m
deleted file mode 100644 (file)
index 7952e5d..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#import <Foundation/Foundation.h>
-#import "FinderSyncSocketLineProcessor.h"
-
-@implementation FinderSyncSocketLineProcessor
-
--(instancetype)initWithDelegate:(id<SyncClientDelegate>)delegate
-{
-    NSLog(@"Init line processor with delegate.");
-    self = [super init];
-    if (self) {
-        self.delegate = delegate;
-    }
-    return self;
-}
-
--(void)process:(NSString*)line
-{
-    NSLog(@"Processing line: %@", line);
-    NSArray *split = [line componentsSeparatedByString:@":"];
-    NSString *command = [split objectAtIndex:0];
-    
-    NSLog(@"Command: %@", command);
-    
-    if([command isEqualToString:@"STATUS"]) {
-        NSString *result = [split objectAtIndex:1];
-        NSArray *pathSplit = [split subarrayWithRange:NSMakeRange(2, [split count] - 2)]; // Get everything after location 2
-        NSString *path = [pathSplit componentsJoinedByString:@":"];
-        
-        dispatch_async(dispatch_get_main_queue(), ^{
-            NSLog(@"Setting result %@ for path %@", result, path);
-            [self.delegate setResultForPath:path result:result];
-        });
-    } else if([command isEqualToString:@"UPDATE_VIEW"]) {
-        NSString *path = [split objectAtIndex:1];
-        
-        dispatch_async(dispatch_get_main_queue(), ^{
-            NSLog(@"Re-fetching filename cache for path %@", path);
-            [self.delegate reFetchFileNameCacheForPath:path];
-        });
-    } else if([command isEqualToString:@"REGISTER_PATH"]) {
-        NSString *path = [split objectAtIndex:1];
-        
-        dispatch_async(dispatch_get_main_queue(), ^{
-            NSLog(@"Registering path %@", path);
-            [self.delegate registerPath:path];
-        });
-    } else if([command isEqualToString:@"UNREGISTER_PATH"]) {
-        NSString *path = [split objectAtIndex:1];
-        
-        dispatch_async(dispatch_get_main_queue(), ^{
-            NSLog(@"Unregistering path %@", path);
-            [self.delegate unregisterPath:path];
-        });
-    } else if([command isEqualToString:@"GET_STRINGS"]) {
-        // BEGIN and END messages, do nothing.
-        return;
-    } else if([command isEqualToString:@"STRING"]) {
-        NSString *key = [split objectAtIndex:1];
-        NSString *value = [split objectAtIndex:2];
-        
-        dispatch_async(dispatch_get_main_queue(), ^{
-            NSLog(@"Setting string %@ to value %@", key, value);
-            [self.delegate setString:key value:value];
-        });
-    } else if([command isEqualToString:@"GET_MENU_ITEMS"]) {
-        if([[split objectAtIndex:1] isEqualToString:@"BEGIN"]) {
-            dispatch_async(dispatch_get_main_queue(), ^{
-                NSLog(@"Resetting menu items.");
-                [self.delegate resetMenuItems];
-            });
-        } else {
-            NSLog(@"Emitting menu has completed signal.");
-            [self.delegate menuHasCompleted];
-        }
-    } else if([command isEqualToString:@"MENU_ITEM"]) {
-        NSDictionary *item = @{@"command": [split objectAtIndex:1], @"flags": [split objectAtIndex:2], @"text": [split objectAtIndex:3]};
-        
-        dispatch_async(dispatch_get_main_queue(), ^{
-            NSLog(@"Adding menu item with command %@, flags %@, and text %@", [split objectAtIndex:1], [split objectAtIndex:2], [split objectAtIndex:3]);
-            [self.delegate addMenuItem:item];
-        });
-    } else {
-        // LOG UNKOWN COMMAND
-        NSLog(@"Unkown command: %@", command);
-    }
-}
-
-@end
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/Info.plist b/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/Info.plist
deleted file mode 100644 (file)
index 2a669ce..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>en</string>
-       <key>CFBundleDisplayName</key>
-       <string>$(OC_APPLICATION_NAME) Extensions</string>
-       <key>CFBundleExecutable</key>
-       <string>$(EXECUTABLE_NAME)</string>
-       <key>CFBundleIdentifier</key>
-       <string>$(OC_APPLICATION_REV_DOMAIN).$(PRODUCT_NAME:rfc1034identifier)</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundleName</key>
-       <string>$(PRODUCT_NAME)</string>
-       <key>CFBundlePackageType</key>
-       <string>XPC!</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-       <key>LSMinimumSystemVersion</key>
-       <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
-       <key>LSUIElement</key>
-       <true/>
-       <key>NSExtension</key>
-       <dict>
-               <key>NSExtensionAttributes</key>
-               <dict/>
-               <key>NSExtensionPointIdentifier</key>
-               <string>com.apple.FinderSync</string>
-               <key>NSExtensionPrincipalClass</key>
-               <string>FinderSync</string>
-       </dict>
-       <key>NSPrincipalClass</key>
-       <string>NSApplication</string>
-       <key>SocketApiPrefix</key>
-       <string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
-</dict>
-</plist>
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/SyncClient.h b/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/SyncClient.h
deleted file mode 100644 (file)
index f8c495a..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) by Jocelyn Turcotte <jturcotte@woboq.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#import <Foundation/Foundation.h>
-
-@protocol SyncClientDelegate <NSObject>
-- (void)setResultForPath:(NSString *)path result:(NSString *)result;
-- (void)reFetchFileNameCacheForPath:(NSString *)path;
-- (void)registerPath:(NSString *)path;
-- (void)unregisterPath:(NSString *)path;
-- (void)setString:(NSString *)key value:(NSString *)value;
-- (void)resetMenuItems;
-- (void)addMenuItem:(NSDictionary *)item;
-- (void)menuHasCompleted;
-- (void)connectionDidDie;
-@end
diff --git a/shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/LineProcessor.h b/shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/LineProcessor.h
deleted file mode 100644 (file)
index 75cf619..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef LineProcessor_h
-#define LineProcessor_h
-
-@protocol LineProcessor<NSObject>
-
-- (void)process:(NSString*)line;
-
-@end
-
-#endif /* LineProcessor_h */
diff --git a/shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/LocalSocketClient.h b/shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/LocalSocketClient.h
deleted file mode 100644 (file)
index 208659a..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#import <NCDesktopClientSocketKit/LineProcessor.h>
-
-#ifndef LocalSocketClient_h
-#define LocalSocketClient_h
-#define BUF_SIZE 4096
-
-/// Class handling asynchronous communication with a server over a local UNIX socket.
-///
-/// The implementation uses a `DispatchQueue` and `DispatchSource`s to handle asynchronous communication and thread
-/// safety. The delegate that handles the line-decoding is **not invoked on the UI thread**, but the (random) thread associated
-/// with the `DispatchQueue`.
-///
-/// If any UI work needs to be done, the `LineProcessor` class dispatches this work on the main queue (so the UI thread) itself.
-///
-/// Other than the `init(withSocketPath:, lineProcessor)` and the `start()` method, all work is done "on the dispatch
-/// queue". The `localSocketQueue` is a serial dispatch queue (so a maximum of 1, and only 1, task is run at any
-/// moment), which guarantees safe access to instance variables. Both `askOnSocket(_:, query:)` and
-/// `askForIcon(_:, isDirectory:)` will internally dispatch the work on the `DispatchQueue`.
-///
-/// Sending and receiving data to and from the socket, is handled by two `DispatchSource`s. These will run an event
-/// handler when data can be read from resp. written to the socket. These handlers will also be run on the
-/// `DispatchQueue`.
-
-@interface LocalSocketClient : NSObject
-
-- (instancetype)initWithSocketPath:(NSString*)socketPath
-                     lineProcessor:(id<LineProcessor>)lineProcessor;
-
-@property (readonly) BOOL isConnected;
-
-- (void)start;
-- (void)restart;
-- (void)closeConnection;
-
-- (void)sendMessage:(NSString*)message;
-- (void)askOnSocket:(NSString*)path
-              query:(NSString*)verb;
-- (void)askForIcon:(NSString*)path
-       isDirectory:(BOOL)isDirectory;
-
-@end
-#endif /* LocalSocketClient_h */
diff --git a/shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/LocalSocketClient.m b/shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/LocalSocketClient.m
deleted file mode 100644 (file)
index 7e62fc0..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#import <Foundation/Foundation.h>
-
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <stdio.h>
-#include <string.h>
-
-#import "LocalSocketClient.h"
-
-@interface LocalSocketClient()
-{
-    NSString* _socketPath;
-    id<LineProcessor> _lineProcessor;
-
-    int _sock;
-    dispatch_queue_t _localSocketQueue;
-    dispatch_source_t _readSource;
-    dispatch_source_t _writeSource;
-    NSMutableData* _inBuffer;
-    NSMutableData* _outBuffer;
-}
-@end
-
-@implementation LocalSocketClient
-
-- (instancetype)initWithSocketPath:(NSString*)socketPath
-                     lineProcessor:(id<LineProcessor>)lineProcessor
-{
-    NSLog(@"Initiating local socket client pointing to %@", socketPath);
-    self = [super init];
-    
-    if(self) {
-        _socketPath = socketPath;
-        _lineProcessor = lineProcessor;
-        
-        _sock = -1;
-        _localSocketQueue = dispatch_queue_create("localSocketQueue", DISPATCH_QUEUE_SERIAL);
-        
-        _inBuffer = [NSMutableData data];
-        _outBuffer = [NSMutableData data];
-    }
-        
-    return self;
-}
-
-- (BOOL)isConnected
-{
-    NSLog(@"Checking is connected: %@", _sock != -1 ? @"YES" : @"NO");
-    return _sock != -1;
-}
-
-- (void)start
-{
-    if([self isConnected]) {
-        NSLog(@"Socket client already connected. Not starting.");
-        return;
-    }
-    
-    struct sockaddr_un localSocketAddr;
-    unsigned long socketPathByteCount = [_socketPath lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; // add 1 for the NUL terminator char
-    int maxByteCount = sizeof(localSocketAddr.sun_path);
-    
-    if(socketPathByteCount > maxByteCount) {
-        // LOG THAT THE SOCKET PATH IS TOO LONG HERE
-        NSLog(@"Socket path '%@' is too long: maximum socket path length is %i, this path is of length %lu", _socketPath, maxByteCount, socketPathByteCount);
-        return;
-    }
-    
-    NSLog(@"Opening local socket...");
-    
-    // LOG THAT THE SOCKET IS BEING OPENED HERE
-    _sock = socket(AF_LOCAL, SOCK_STREAM, 0);
-    
-    if(_sock == -1) {
-        NSLog(@"Cannot open socket: '%@'", [self strErr]);
-        [self restart];
-        return;
-    }
-    
-    NSLog(@"Local socket opened. Connecting to '%@' ...", _socketPath);
-    
-    localSocketAddr.sun_family = AF_LOCAL & 0xff;
-    
-    const char* pathBytes = [_socketPath UTF8String];
-    strcpy(localSocketAddr.sun_path, pathBytes);
-    
-    int connectionStatus = connect(_sock, (struct sockaddr*)&localSocketAddr, sizeof(localSocketAddr));
-    
-    if(connectionStatus == -1) {
-        NSLog(@"Could not connect to '%@': '%@'", _socketPath, [self strErr]);
-        [self restart];
-        return;
-    }
-    
-    int flags = fcntl(_sock, F_GETFL, 0);
-    
-    if(fcntl(_sock, F_SETFL, flags | O_NONBLOCK) == -1) {
-        NSLog(@"Could not set socket to non-blocking mode: '%@'", [self strErr]);
-        [self restart];
-        return;
-    }
-    
-    NSLog(@"Connected to socket. Setting up dispatch sources...");
-    
-    _readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, _sock, 0, _localSocketQueue);
-    dispatch_source_set_event_handler(_readSource, ^(void){ [self readFromSocket]; });
-    dispatch_source_set_cancel_handler(_readSource, ^(void){
-        self->_readSource = nil;
-        [self closeConnection];
-    });
-    
-    _writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, _sock, 0, _localSocketQueue);
-    dispatch_source_set_event_handler(_writeSource, ^(void){ [self writeToSocket]; });
-    dispatch_source_set_cancel_handler(_writeSource, ^(void){
-        self->_writeSource = nil;
-        [self closeConnection];
-    });
-    
-    // These dispatch sources are suspended upon creation.
-    // We resume the writeSource when we actually have something to write, suspending it again once our outBuffer is empty.
-    // We start the readSource now.
-    
-    NSLog(@"Starting to read from socket");
-    
-    dispatch_resume(_readSource);
-}
-
-- (void)restart
-{
-    NSLog(@"Restarting connection to socket.");
-    [self closeConnection];
-    dispatch_async(dispatch_get_main_queue(), ^(void){
-        [NSTimer scheduledTimerWithTimeInterval:5 repeats:NO block:^(NSTimer* timer) {
-            [self start];
-        }];
-    });
-}
-
-- (void)closeConnection
-{
-    NSLog(@"Closing connection.");
-    
-    if(_readSource) {
-        // Since dispatch_source_cancel works asynchronously, if we deallocate the dispatch source here then we can
-        // cause a crash. So instead we strongly hold a reference to the read source and deallocate it asynchronously
-        // with the handler.
-        __block dispatch_source_t previousReadSource = _readSource;
-        dispatch_source_set_cancel_handler(_readSource, ^{
-            previousReadSource = nil;
-        });
-        dispatch_source_cancel(_readSource);
-        // The readSource is still alive due to the other reference and will be deallocated by the cancel handler
-        _readSource = nil;
-    }
-    
-    if(_writeSource) {
-        // Same deal with the write source
-        __block dispatch_source_t previousWriteSource = _writeSource;
-        dispatch_source_set_cancel_handler(_writeSource, ^{
-            previousWriteSource = nil;
-        });
-        dispatch_source_cancel(_writeSource);
-        _writeSource = nil;
-    }
-
-    [_inBuffer setLength:0];
-    [_outBuffer setLength: 0];
-    
-    if(_sock != -1) {
-        close(_sock);
-        _sock = -1;
-    }
-}
-
-- (NSString*)strErr
-{
-    int err = errno;
-    const char *errStr = strerror(err);
-    NSString *errorStr = [NSString stringWithUTF8String:errStr];
-    
-    if([errorStr length] == 0) {
-        return errorStr;
-    } else {
-        return [NSString stringWithFormat:@"Unknown error code: %i\10", err];
-    }
-}
-
-- (void)sendMessage:(NSString *)message
-{
-    dispatch_async(_localSocketQueue, ^(void) {
-        if(![self isConnected]) {
-            return;
-        }
-
-        BOOL writeSourceIsSuspended = [self->_outBuffer length] == 0;
-
-        [self->_outBuffer appendData:[message dataUsingEncoding:NSUTF8StringEncoding]];
-
-        NSLog(@"Writing to out buffer: '%@'", message);
-        NSLog(@"Out buffer now %li bytes", [self->_outBuffer length]);
-
-        if(writeSourceIsSuspended) {
-            NSLog(@"Resuming write dispatch source.");
-            dispatch_resume(self->_writeSource);
-        }
-    });
-}
-
-- (void)askOnSocket:(NSString *)path query:(NSString *)verb
-{
-    NSString *line = [NSString stringWithFormat:@"%@:%@\n", verb, path];
-    [self sendMessage:line];
-}
-
-- (void)writeToSocket
-{
-    if(![self isConnected]) {
-        return;
-    }
-    
-    if([_outBuffer length] == 0) {
-        NSLog(@"Empty out buffer, suspending write dispatch source.");
-        dispatch_suspend(_writeSource);
-        return;
-    }
-    
-    NSLog(@"About to write %li bytes from outbuffer to socket.", [_outBuffer length]);
-    
-    long bytesWritten = write(_sock, [_outBuffer bytes], [_outBuffer length]);
-    char lineWritten[[_outBuffer length]];
-    memcpy(lineWritten, [_outBuffer bytes], [_outBuffer length]);
-    NSLog(@"Wrote %li bytes to socket. Line written was: '%@'", bytesWritten, [NSString stringWithUTF8String:lineWritten]);
-    
-    if(bytesWritten == 0) {
-        // 0 means we reached "end of file" and thus the socket was closed\10. So let's restart it
-        NSLog(@"Socket was closed. Restarting...");
-        [self restart];
-    } else if(bytesWritten == -1) {
-        int err = errno; // Make copy before it gets nuked by something else
-        
-        if(err == EAGAIN || err == EWOULDBLOCK)  {
-            // No free space in the OS' buffer, nothing to do here
-            NSLog(@"No free space in OS buffer. Ending write.");
-            return;
-        } else {
-            NSLog(@"Error writing to local socket: '%@'", [self strErr]);
-            [self restart];
-        }
-    } else if(bytesWritten > 0) {
-        [_outBuffer replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
-        
-        NSLog(@"Out buffer cleared. Now count is %li bytes.", [_outBuffer length]);
-        
-        if([_outBuffer length] == 0) {
-            NSLog(@"Out buffer has been emptied, suspending write dispatch source.");
-            dispatch_suspend(_writeSource);
-        }
-    }
-}
-
-- (void)askForIcon:(NSString*)path isDirectory:(BOOL)isDirectory;
-{
-    NSLog(@"Asking for icon.");
-    
-    NSString *verb;
-    if(isDirectory) {
-        verb = @"RETRIEVE_FOLDER_STATUS";
-    } else {
-        verb = @"RETRIEVE_FILE_STATUS";
-    }
-    
-    [self askOnSocket:path query:verb];
-}
-
-- (void)readFromSocket
-{
-    if(![self isConnected]) {
-        return;
-    }
-    
-    NSLog(@"Reading from socket.");
-    
-    int bufferLength = BUF_SIZE / 2;
-    char buffer[bufferLength];
-    
-    while(true) {
-        long bytesRead = read(_sock, buffer, bufferLength);
-        
-        NSLog(@"Read %li bytes from socket.", bytesRead);
-        
-        if(bytesRead == 0) {
-            // 0 means we reached "end of file" and thus the socket was closed\10. So let's restart it
-            NSLog(@"Socket was closed. Restarting...");
-            [self restart];
-            return;
-        } else if(bytesRead == -1) {
-            int err = errno;
-            if(err == EAGAIN) {
-                NSLog(@"No error and no data. Stopping.");
-                return; // No error, no data, so let's stop
-            } else {
-                NSLog(@"Error reading from local socket: '%@'", [self strErr]);
-                [self closeConnection];
-                return;
-            }
-        } else {
-            [_inBuffer appendBytes:buffer length:bytesRead];
-            [self processInBuffer];
-        }
-    }
-}
-
-- (void)processInBuffer
-{
-    NSLog(@"Processing in buffer. In buffer length %li", [_inBuffer length]);
-    UInt8 separator[] = {0xa}; // Byte value for "\n"
-    while(true) {
-        NSRange firstSeparatorIndex = [_inBuffer rangeOfData:[NSData dataWithBytes:separator length:1] options:0 range:NSMakeRange(0, [_inBuffer length])];
-        
-        if(firstSeparatorIndex.location == NSNotFound) {
-            NSLog(@"No separator found. Stopping.");
-            return; // No separator, nope out
-        } else {
-            unsigned char *buffer = [_inBuffer mutableBytes];
-            buffer[firstSeparatorIndex.location] = 0; // Add NULL terminator, so we can use C string methods
-            
-            NSString *newLine = [NSString stringWithUTF8String:[_inBuffer bytes]];
-
-            [_inBuffer replaceBytesInRange:NSMakeRange(0, firstSeparatorIndex.location + 1) withBytes:NULL length:0];
-            [_lineProcessor process:newLine];
-        }
-    }
-}
-    
-@end
diff --git a/shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/NCDesktopClientSocketKit.h b/shell_integration/MacOSX/NextcloudIntegration/NCDesktopClientSocketKit/NCDesktopClientSocketKit.h
deleted file mode 100644 (file)
index 8626125..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-//  NCDesktopClientSocketKit.h
-//  NCDesktopClientSocketKit
-//
-//  Created by Claudio Cambra on 23/12/22.
-//
-
-#import <Foundation/Foundation.h>
-
-//! Project version number for NCDesktopClientSocketKit.
-FOUNDATION_EXPORT double NCDesktopClientSocketKitVersionNumber;
-
-//! Project version string for NCDesktopClientSocketKit.
-FOUNDATION_EXPORT const unsigned char NCDesktopClientSocketKitVersionString[];
-
-// In this header, you should import all the public headers of your framework using statements like #import <NCDesktopClientSocketKit/PublicHeader.h>
-
-#import <NCDesktopClientSocketKit/LocalSocketClient.h>
-#import <NCDesktopClientSocketKit/LineProcessor.h>
diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj
deleted file mode 100644 (file)
index 0f850fb..0000000
+++ /dev/null
@@ -1,1261 +0,0 @@
-// !$*UTF8*$!
-{
-       archiveVersion = 1;
-       classes = {
-       };
-       objectVersion = 52;
-       objects = {
-
-/* Begin PBXBuildFile section */
-               5307A6E62965C6FA001E0C6A /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5307A6E52965C6FA001E0C6A /* NextcloudKit */; };
-               5307A6E82965DAD8001E0C6A /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5307A6E72965DAD8001E0C6A /* NextcloudKit */; };
-               5307A6EB2965DB8D001E0C6A /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 5307A6EA2965DB8D001E0C6A /* RealmSwift */; };
-               5307A6F229675346001E0C6A /* NextcloudFilesDatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5307A6F129675346001E0C6A /* NextcloudFilesDatabaseManager.swift */; };
-               5318AD9129BF42FB00CBB71C /* NextcloudItemMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9029BF42FB00CBB71C /* NextcloudItemMetadataTable.swift */; };
-               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 */; };
-               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 */; };
-               5352E85B29B7BFE6002CE85C /* Progress+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352E85A29B7BFE6002CE85C /* Progress+Extensions.swift */; };
-               535AE30E29C0A2CC0042A9BA /* Logger+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535AE30D29C0A2CC0042A9BA /* Logger+Extensions.swift */; };
-               536EFBF7295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536EFBF6295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift */; };
-               536EFC36295E3C1100F4CB13 /* NextcloudAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536EFC35295E3C1100F4CB13 /* NextcloudAccount.swift */; };
-               538E396A27F4765000FA63D5 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */; };
-               538E396D27F4765000FA63D5 /* FileProviderExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538E396C27F4765000FA63D5 /* FileProviderExtension.swift */; };
-               538E396F27F4765000FA63D5 /* FileProviderItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538E396E27F4765000FA63D5 /* FileProviderItem.swift */; };
-               538E397127F4765000FA63D5 /* FileProviderEnumerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538E397027F4765000FA63D5 /* FileProviderEnumerator.swift */; };
-               538E397627F4765000FA63D5 /* FileProviderExt.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 538E396727F4765000FA63D5 /* FileProviderExt.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
-               53903D1E2956164F00D0B308 /* NCDesktopClientSocketKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 53903D0E2956164F00D0B308 /* NCDesktopClientSocketKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               53903D212956164F00D0B308 /* NCDesktopClientSocketKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */; };
-               53903D222956164F00D0B308 /* NCDesktopClientSocketKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
-               53903D2A295616F000D0B308 /* LocalSocketClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 539158B227BEC98A00816F56 /* LocalSocketClient.m */; };
-               53903D2B2956173000D0B308 /* NCDesktopClientSocketKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */; };
-               53903D2C2956173000D0B308 /* NCDesktopClientSocketKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
-               53903D302956173F00D0B308 /* NCDesktopClientSocketKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */; };
-               53903D312956173F00D0B308 /* NCDesktopClientSocketKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
-               53903D352956184400D0B308 /* LocalSocketClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 539158B127BE891500816F56 /* LocalSocketClient.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               53903D37295618A400D0B308 /* LineProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 53903D36295618A400D0B308 /* LineProcessor.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               539158AC27BE71A900816F56 /* FinderSyncSocketLineProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 539158AB27BE71A900816F56 /* FinderSyncSocketLineProcessor.m */; };
-               53D056312970594F00988392 /* LocalFilesUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53D056302970594F00988392 /* LocalFilesUtils.swift */; };
-               53ED472029C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED471F29C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift */; };
-               53ED472829C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED472729C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift */; };
-               53ED473029C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED472F29C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift */; };
-               C2B573BA1B1CD91E00303B36 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C2B573B91B1CD91E00303B36 /* main.m */; };
-               C2B573D21B1CD94B00303B36 /* main.m in Resources */ = {isa = PBXBuildFile; fileRef = C2B573B91B1CD91E00303B36 /* main.m */; };
-               C2B573DE1B1CD9CE00303B36 /* FinderSync.m in Sources */ = {isa = PBXBuildFile; fileRef = C2B573DD1B1CD9CE00303B36 /* FinderSync.m */; };
-               C2B573E21B1CD9CE00303B36 /* FinderSyncExt.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = C2B573D71B1CD9CE00303B36 /* FinderSyncExt.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
-               C2B573F31B1DAD6400303B36 /* error.iconset in Resources */ = {isa = PBXBuildFile; fileRef = C2B573EB1B1DAD6400303B36 /* error.iconset */; };
-               C2B573F41B1DAD6400303B36 /* ok_swm.iconset in Resources */ = {isa = PBXBuildFile; fileRef = C2B573EC1B1DAD6400303B36 /* ok_swm.iconset */; };
-               C2B573F51B1DAD6400303B36 /* ok.iconset in Resources */ = {isa = PBXBuildFile; fileRef = C2B573ED1B1DAD6400303B36 /* ok.iconset */; };
-               C2B573F71B1DAD6400303B36 /* sync.iconset in Resources */ = {isa = PBXBuildFile; fileRef = C2B573EF1B1DAD6400303B36 /* sync.iconset */; };
-               C2B573F91B1DAD6400303B36 /* warning.iconset in Resources */ = {isa = PBXBuildFile; fileRef = C2B573F11B1DAD6400303B36 /* warning.iconset */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXContainerItemProxy section */
-               538E397427F4765000FA63D5 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = C2B573951B1CD88000303B36 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 538E396627F4765000FA63D5;
-                       remoteInfo = FileProviderExt;
-               };
-               53903D1F2956164F00D0B308 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = C2B573951B1CD88000303B36 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 53903D0B2956164F00D0B308;
-                       remoteInfo = NCDesktopClientSocketKit;
-               };
-               53903D2D2956173000D0B308 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = C2B573951B1CD88000303B36 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 53903D0B2956164F00D0B308;
-                       remoteInfo = NCDesktopClientSocketKit;
-               };
-               53903D322956173F00D0B308 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = C2B573951B1CD88000303B36 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 53903D0B2956164F00D0B308;
-                       remoteInfo = NCDesktopClientSocketKit;
-               };
-               C2B573DF1B1CD9CE00303B36 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = C2B573951B1CD88000303B36 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = C2B573D61B1CD9CE00303B36;
-                       remoteInfo = FinderSyncExt;
-               };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXCopyFilesBuildPhase section */
-               53903D232956165000D0B308 /* Embed Frameworks */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 2147483647;
-                       dstPath = "";
-                       dstSubfolderSpec = 10;
-                       files = (
-                               53903D222956164F00D0B308 /* NCDesktopClientSocketKit.framework in Embed Frameworks */,
-                       );
-                       name = "Embed Frameworks";
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               53903D2F2956173000D0B308 /* Embed Frameworks */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 2147483647;
-                       dstPath = "";
-                       dstSubfolderSpec = 10;
-                       files = (
-                               53903D2C2956173000D0B308 /* NCDesktopClientSocketKit.framework in Embed Frameworks */,
-                       );
-                       name = "Embed Frameworks";
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               53903D342956173F00D0B308 /* Embed Frameworks */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 2147483647;
-                       dstPath = "";
-                       dstSubfolderSpec = 10;
-                       files = (
-                               53903D312956173F00D0B308 /* NCDesktopClientSocketKit.framework in Embed Frameworks */,
-                       );
-                       name = "Embed Frameworks";
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               C2B573E11B1CD9CE00303B36 /* Embed App Extensions */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 8;
-                       dstPath = "";
-                       dstSubfolderSpec = 13;
-                       files = (
-                               C2B573E21B1CD9CE00303B36 /* FinderSyncExt.appex in Embed App Extensions */,
-                               538E397627F4765000FA63D5 /* FileProviderExt.appex in Embed App Extensions */,
-                       );
-                       name = "Embed App Extensions";
-                       runOnlyForDeploymentPostprocessing = 1;
-               };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
-               5307A6F129675346001E0C6A /* NextcloudFilesDatabaseManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudFilesDatabaseManager.swift; sourceTree = "<group>"; };
-               5318AD9029BF42FB00CBB71C /* NextcloudItemMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudItemMetadataTable.swift; sourceTree = "<group>"; };
-               5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudLocalFileMetadataTable.swift; sourceTree = "<group>"; };
-               5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderMaterialisedEnumerationObserver.swift; sourceTree = "<group>"; };
-               5318AD9829BF58D000CBB71C /* NKError+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NKError+Extensions.swift"; sourceTree = "<group>"; };
-               5352B36529DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudFilesDatabaseManager+Directories.swift"; sourceTree = "<group>"; };
-               5352B36729DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudFilesDatabaseManager+LocalFiles.swift"; sourceTree = "<group>"; };
-               5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+Thumbnailing.swift"; sourceTree = "<group>"; };
-               5352E85A29B7BFE6002CE85C /* Progress+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Progress+Extensions.swift"; sourceTree = "<group>"; };
-               535AE30D29C0A2CC0042A9BA /* Logger+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+Extensions.swift"; sourceTree = "<group>"; };
-               536EFBF6295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderSocketLineProcessor.swift; sourceTree = "<group>"; };
-               536EFC35295E3C1100F4CB13 /* NextcloudAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudAccount.swift; sourceTree = "<group>"; };
-               538E396727F4765000FA63D5 /* FileProviderExt.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = FileProviderExt.appex; sourceTree = BUILT_PRODUCTS_DIR; };
-               538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; };
-               538E396C27F4765000FA63D5 /* FileProviderExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderExtension.swift; sourceTree = "<group>"; };
-               538E396E27F4765000FA63D5 /* FileProviderItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderItem.swift; sourceTree = "<group>"; };
-               538E397027F4765000FA63D5 /* FileProviderEnumerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderEnumerator.swift; sourceTree = "<group>"; };
-               538E397227F4765000FA63D5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               538E397327F4765000FA63D5 /* FileProviderExt.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FileProviderExt.entitlements; sourceTree = "<group>"; };
-               53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NCDesktopClientSocketKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
-               53903D0E2956164F00D0B308 /* NCDesktopClientSocketKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NCDesktopClientSocketKit.h; sourceTree = "<group>"; };
-               53903D36295618A400D0B308 /* LineProcessor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LineProcessor.h; sourceTree = "<group>"; };
-               539158A927BE606500816F56 /* FinderSyncSocketLineProcessor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinderSyncSocketLineProcessor.h; sourceTree = "<group>"; };
-               539158AA27BE67CC00816F56 /* SyncClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SyncClient.h; sourceTree = "<group>"; };
-               539158AB27BE71A900816F56 /* FinderSyncSocketLineProcessor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FinderSyncSocketLineProcessor.m; sourceTree = "<group>"; };
-               539158B127BE891500816F56 /* LocalSocketClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalSocketClient.h; sourceTree = "<group>"; };
-               539158B227BEC98A00816F56 /* LocalSocketClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocalSocketClient.m; sourceTree = "<group>"; };
-               53D056302970594F00988392 /* LocalFilesUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalFilesUtils.swift; sourceTree = "<group>"; };
-               53ED471F29C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderEnumerator+SyncEngine.swift"; sourceTree = "<group>"; };
-               53ED472729C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudItemMetadataTable+NKFile.swift"; sourceTree = "<group>"; };
-               53ED472F29C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+ClientInterface.swift"; sourceTree = "<group>"; };
-               C2B573B11B1CD91E00303B36 /* desktopclient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = desktopclient.app; sourceTree = BUILT_PRODUCTS_DIR; };
-               C2B573B51B1CD91E00303B36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               C2B573B91B1CD91E00303B36 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
-               C2B573D71B1CD9CE00303B36 /* FinderSyncExt.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = FinderSyncExt.appex; sourceTree = BUILT_PRODUCTS_DIR; };
-               C2B573DA1B1CD9CE00303B36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               C2B573DB1B1CD9CE00303B36 /* FinderSyncExt.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = FinderSyncExt.entitlements; sourceTree = "<group>"; };
-               C2B573DC1B1CD9CE00303B36 /* FinderSync.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinderSync.h; sourceTree = "<group>"; };
-               C2B573DD1B1CD9CE00303B36 /* FinderSync.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FinderSync.m; sourceTree = "<group>"; };
-               C2B573EB1B1DAD6400303B36 /* error.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = error.iconset; path = ../../icons/nopadding/error.iconset; sourceTree = SOURCE_ROOT; };
-               C2B573EC1B1DAD6400303B36 /* ok_swm.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = ok_swm.iconset; path = ../../icons/nopadding/ok_swm.iconset; sourceTree = SOURCE_ROOT; };
-               C2B573ED1B1DAD6400303B36 /* ok.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = ok.iconset; path = ../../icons/nopadding/ok.iconset; sourceTree = SOURCE_ROOT; };
-               C2B573EF1B1DAD6400303B36 /* sync.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = sync.iconset; path = ../../icons/nopadding/sync.iconset; sourceTree = SOURCE_ROOT; };
-               C2B573F11B1DAD6400303B36 /* warning.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = warning.iconset; path = ../../icons/nopadding/warning.iconset; sourceTree = SOURCE_ROOT; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
-               538E396427F4765000FA63D5 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5307A6EB2965DB8D001E0C6A /* RealmSwift in Frameworks */,
-                               5307A6E82965DAD8001E0C6A /* NextcloudKit in Frameworks */,
-                               538E396A27F4765000FA63D5 /* UniformTypeIdentifiers.framework in Frameworks */,
-                               53903D302956173F00D0B308 /* NCDesktopClientSocketKit.framework in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               53903D092956164F00D0B308 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               C2B573AE1B1CD91E00303B36 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5307A6E62965C6FA001E0C6A /* NextcloudKit in Frameworks */,
-                               53903D212956164F00D0B308 /* NCDesktopClientSocketKit.framework in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               C2B573D41B1CD9CE00303B36 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               53903D2B2956173000D0B308 /* NCDesktopClientSocketKit.framework in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
-               5318AD8F29BF406500CBB71C /* Database */ = {
-                       isa = PBXGroup;
-                       children = (
-                               5307A6F129675346001E0C6A /* NextcloudFilesDatabaseManager.swift */,
-                               5352B36529DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift */,
-                               5352B36729DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift */,
-                               5318AD9029BF42FB00CBB71C /* NextcloudItemMetadataTable.swift */,
-                               53ED472729C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift */,
-                               5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */,
-                       );
-                       path = Database;
-                       sourceTree = "<group>";
-               };
-               5352E85929B7BFB4002CE85C /* Extensions */ = {
-                       isa = PBXGroup;
-                       children = (
-                               535AE30D29C0A2CC0042A9BA /* Logger+Extensions.swift */,
-                               5318AD9829BF58D000CBB71C /* NKError+Extensions.swift */,
-                               5352E85A29B7BFE6002CE85C /* Progress+Extensions.swift */,
-                       );
-                       path = Extensions;
-                       sourceTree = "<group>";
-               };
-               538E396827F4765000FA63D5 /* Frameworks */ = {
-                       isa = PBXGroup;
-                       children = (
-                               538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */,
-                       );
-                       name = Frameworks;
-                       sourceTree = "<group>";
-               };
-               538E396B27F4765000FA63D5 /* FileProviderExt */ = {
-                       isa = PBXGroup;
-                       children = (
-                               5318AD8F29BF406500CBB71C /* Database */,
-                               5352E85929B7BFB4002CE85C /* Extensions */,
-                               538E397027F4765000FA63D5 /* FileProviderEnumerator.swift */,
-                               53ED471F29C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift */,
-                               538E396C27F4765000FA63D5 /* FileProviderExtension.swift */,
-                               53ED472F29C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift */,
-                               5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */,
-                               538E396E27F4765000FA63D5 /* FileProviderItem.swift */,
-                               5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */,
-                               536EFBF6295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift */,
-                               53D056302970594F00988392 /* LocalFilesUtils.swift */,
-                               536EFC35295E3C1100F4CB13 /* NextcloudAccount.swift */,
-                               538E397327F4765000FA63D5 /* FileProviderExt.entitlements */,
-                               538E397227F4765000FA63D5 /* Info.plist */,
-                       );
-                       path = FileProviderExt;
-                       sourceTree = "<group>";
-               };
-               53903D0D2956164F00D0B308 /* NCDesktopClientSocketKit */ = {
-                       isa = PBXGroup;
-                       children = (
-                               53903D0E2956164F00D0B308 /* NCDesktopClientSocketKit.h */,
-                               539158B127BE891500816F56 /* LocalSocketClient.h */,
-                               539158B227BEC98A00816F56 /* LocalSocketClient.m */,
-                               53903D36295618A400D0B308 /* LineProcessor.h */,
-                       );
-                       path = NCDesktopClientSocketKit;
-                       sourceTree = "<group>";
-               };
-               C2B573941B1CD88000303B36 = {
-                       isa = PBXGroup;
-                       children = (
-                               C2B573B31B1CD91E00303B36 /* desktopclient */,
-                               C2B573D81B1CD9CE00303B36 /* FinderSyncExt */,
-                               538E396B27F4765000FA63D5 /* FileProviderExt */,
-                               53903D0D2956164F00D0B308 /* NCDesktopClientSocketKit */,
-                               538E396827F4765000FA63D5 /* Frameworks */,
-                               C2B573B21B1CD91E00303B36 /* Products */,
-                       );
-                       sourceTree = "<group>";
-               };
-               C2B573B21B1CD91E00303B36 /* Products */ = {
-                       isa = PBXGroup;
-                       children = (
-                               C2B573B11B1CD91E00303B36 /* desktopclient.app */,
-                               C2B573D71B1CD9CE00303B36 /* FinderSyncExt.appex */,
-                               538E396727F4765000FA63D5 /* FileProviderExt.appex */,
-                               53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */,
-                       );
-                       name = Products;
-                       sourceTree = "<group>";
-               };
-               C2B573B31B1CD91E00303B36 /* desktopclient */ = {
-                       isa = PBXGroup;
-                       children = (
-                               C2B573B41B1CD91E00303B36 /* Supporting Files */,
-                       );
-                       path = desktopclient;
-                       sourceTree = "<group>";
-               };
-               C2B573B41B1CD91E00303B36 /* Supporting Files */ = {
-                       isa = PBXGroup;
-                       children = (
-                               C2B573B51B1CD91E00303B36 /* Info.plist */,
-                               C2B573B91B1CD91E00303B36 /* main.m */,
-                       );
-                       name = "Supporting Files";
-                       sourceTree = "<group>";
-               };
-               C2B573D81B1CD9CE00303B36 /* FinderSyncExt */ = {
-                       isa = PBXGroup;
-                       children = (
-                               539158AA27BE67CC00816F56 /* SyncClient.h */,
-                               C2B573DC1B1CD9CE00303B36 /* FinderSync.h */,
-                               C2B573DD1B1CD9CE00303B36 /* FinderSync.m */,
-                               539158A927BE606500816F56 /* FinderSyncSocketLineProcessor.h */,
-                               539158AB27BE71A900816F56 /* FinderSyncSocketLineProcessor.m */,
-                               C2B573D91B1CD9CE00303B36 /* Supporting Files */,
-                       );
-                       path = FinderSyncExt;
-                       sourceTree = "<group>";
-               };
-               C2B573D91B1CD9CE00303B36 /* Supporting Files */ = {
-                       isa = PBXGroup;
-                       children = (
-                               C2B573EB1B1DAD6400303B36 /* error.iconset */,
-                               C2B573EC1B1DAD6400303B36 /* ok_swm.iconset */,
-                               C2B573ED1B1DAD6400303B36 /* ok.iconset */,
-                               C2B573EF1B1DAD6400303B36 /* sync.iconset */,
-                               C2B573F11B1DAD6400303B36 /* warning.iconset */,
-                               C2B573DA1B1CD9CE00303B36 /* Info.plist */,
-                               C2B573DB1B1CD9CE00303B36 /* FinderSyncExt.entitlements */,
-                       );
-                       name = "Supporting Files";
-                       sourceTree = "<group>";
-               };
-/* End PBXGroup section */
-
-/* Begin PBXHeadersBuildPhase section */
-               53903D072956164F00D0B308 /* Headers */ = {
-                       isa = PBXHeadersBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               53903D352956184400D0B308 /* LocalSocketClient.h in Headers */,
-                               53903D37295618A400D0B308 /* LineProcessor.h in Headers */,
-                               53903D1E2956164F00D0B308 /* NCDesktopClientSocketKit.h in Headers */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-/* End PBXHeadersBuildPhase section */
-
-/* Begin PBXNativeTarget section */
-               538E396627F4765000FA63D5 /* FileProviderExt */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 538E397927F4765000FA63D5 /* Build configuration list for PBXNativeTarget "FileProviderExt" */;
-                       buildPhases = (
-                               538E396327F4765000FA63D5 /* Sources */,
-                               538E396427F4765000FA63D5 /* Frameworks */,
-                               538E396527F4765000FA63D5 /* Resources */,
-                               53903D342956173F00D0B308 /* Embed Frameworks */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                               53903D332956173F00D0B308 /* PBXTargetDependency */,
-                       );
-                       name = FileProviderExt;
-                       packageProductDependencies = (
-                               5307A6E72965DAD8001E0C6A /* NextcloudKit */,
-                               5307A6EA2965DB8D001E0C6A /* RealmSwift */,
-                       );
-                       productName = FileProviderExt;
-                       productReference = 538E396727F4765000FA63D5 /* FileProviderExt.appex */;
-                       productType = "com.apple.product-type.app-extension";
-               };
-               53903D0B2956164F00D0B308 /* NCDesktopClientSocketKit */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 53903D282956165000D0B308 /* Build configuration list for PBXNativeTarget "NCDesktopClientSocketKit" */;
-                       buildPhases = (
-                               53903D072956164F00D0B308 /* Headers */,
-                               53903D082956164F00D0B308 /* Sources */,
-                               53903D092956164F00D0B308 /* Frameworks */,
-                               53903D0A2956164F00D0B308 /* Resources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = NCDesktopClientSocketKit;
-                       productName = NCDesktopClientSocketKit;
-                       productReference = 53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */;
-                       productType = "com.apple.product-type.framework";
-               };
-               C2B573B01B1CD91E00303B36 /* desktopclient */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = C2B573CC1B1CD91E00303B36 /* Build configuration list for PBXNativeTarget "desktopclient" */;
-                       buildPhases = (
-                               C2B573AD1B1CD91E00303B36 /* Sources */,
-                               C2B573AE1B1CD91E00303B36 /* Frameworks */,
-                               C2B573AF1B1CD91E00303B36 /* Resources */,
-                               C2B573E11B1CD9CE00303B36 /* Embed App Extensions */,
-                               53903D232956165000D0B308 /* Embed Frameworks */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                               C2B573E01B1CD9CE00303B36 /* PBXTargetDependency */,
-                               538E397527F4765000FA63D5 /* PBXTargetDependency */,
-                               53903D202956164F00D0B308 /* PBXTargetDependency */,
-                       );
-                       name = desktopclient;
-                       packageProductDependencies = (
-                               5307A6E52965C6FA001E0C6A /* NextcloudKit */,
-                       );
-                       productName = desktopclient;
-                       productReference = C2B573B11B1CD91E00303B36 /* desktopclient.app */;
-                       productType = "com.apple.product-type.application";
-               };
-               C2B573D61B1CD9CE00303B36 /* FinderSyncExt */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = C2B573E31B1CD9CE00303B36 /* Build configuration list for PBXNativeTarget "FinderSyncExt" */;
-                       buildPhases = (
-                               C2B573D31B1CD9CE00303B36 /* Sources */,
-                               C2B573D41B1CD9CE00303B36 /* Frameworks */,
-                               C2B573D51B1CD9CE00303B36 /* Resources */,
-                               5B3335471CA058E200E11A45 /* ShellScript */,
-                               53903D2F2956173000D0B308 /* Embed Frameworks */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                               53903D2E2956173000D0B308 /* PBXTargetDependency */,
-                       );
-                       name = FinderSyncExt;
-                       productName = FinderSyncExt;
-                       productReference = C2B573D71B1CD9CE00303B36 /* FinderSyncExt.appex */;
-                       productType = "com.apple.product-type.app-extension";
-               };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-               C2B573951B1CD88000303B36 /* Project object */ = {
-                       isa = PBXProject;
-                       attributes = {
-                               LastSwiftUpdateCheck = 1420;
-                               LastUpgradeCheck = 1240;
-                               TargetAttributes = {
-                                       538E396627F4765000FA63D5 = {
-                                               CreatedOnToolsVersion = 13.3;
-                                       };
-                                       53903D0B2956164F00D0B308 = {
-                                               CreatedOnToolsVersion = 14.2;
-                                               ProvisioningStyle = Manual;
-                                       };
-                                       C2B573B01B1CD91E00303B36 = {
-                                               CreatedOnToolsVersion = 6.3.1;
-                                               DevelopmentTeam = 9B5WD74GWJ;
-                                               ProvisioningStyle = Manual;
-                                       };
-                                       C2B573D61B1CD9CE00303B36 = {
-                                               CreatedOnToolsVersion = 6.3.1;
-                                               DevelopmentTeam = 9B5WD74GWJ;
-                                               ProvisioningStyle = Manual;
-                                               SystemCapabilities = {
-                                                       com.apple.ApplicationGroups.Mac = {
-                                                               enabled = 1;
-                                                       };
-                                               };
-                                       };
-                               };
-                       };
-                       buildConfigurationList = C2B573981B1CD88000303B36 /* Build configuration list for PBXProject "NextcloudIntegration" */;
-                       compatibilityVersion = "Xcode 3.2";
-                       developmentRegion = English;
-                       hasScannedForEncodings = 0;
-                       knownRegions = (
-                               English,
-                               en,
-                               Base,
-                       );
-                       mainGroup = C2B573941B1CD88000303B36;
-                       packageReferences = (
-                               5307A6E42965C6FA001E0C6A /* XCRemoteSwiftPackageReference "NextcloudKit" */,
-                               5307A6E92965DB57001E0C6A /* XCRemoteSwiftPackageReference "realm-swift" */,
-                       );
-                       productRefGroup = C2B573B21B1CD91E00303B36 /* Products */;
-                       projectDirPath = "";
-                       projectRoot = "";
-                       targets = (
-                               C2B573B01B1CD91E00303B36 /* desktopclient */,
-                               C2B573D61B1CD9CE00303B36 /* FinderSyncExt */,
-                               538E396627F4765000FA63D5 /* FileProviderExt */,
-                               53903D0B2956164F00D0B308 /* NCDesktopClientSocketKit */,
-                       );
-               };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
-               538E396527F4765000FA63D5 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               53903D0A2956164F00D0B308 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               C2B573AF1B1CD91E00303B36 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               C2B573D21B1CD94B00303B36 /* main.m in Resources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               C2B573D51B1CD9CE00303B36 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               C2B573F91B1DAD6400303B36 /* warning.iconset in Resources */,
-                               C2B573F31B1DAD6400303B36 /* error.iconset in Resources */,
-                               C2B573F71B1DAD6400303B36 /* sync.iconset in Resources */,
-                               C2B573F41B1DAD6400303B36 /* ok_swm.iconset in Resources */,
-                               C2B573F51B1DAD6400303B36 /* ok.iconset in Resources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
-               5B3335471CA058E200E11A45 /* ShellScript */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                       );
-                       outputPaths = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "if [[ ${OC_OEM_SHARE_ICNS} ]]; then\n  cp ${OC_OEM_SHARE_ICNS} ${BUILT_PRODUCTS_DIR}/FinderSyncExt.appex/Contents/Resources/app.icns\nfi";
-                       showEnvVarsInLog = 0;
-               };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
-               538E396327F4765000FA63D5 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5352E85B29B7BFE6002CE85C /* Progress+Extensions.swift in Sources */,
-                               536EFC36295E3C1100F4CB13 /* NextcloudAccount.swift in Sources */,
-                               53ED473029C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift in Sources */,
-                               538E396D27F4765000FA63D5 /* FileProviderExtension.swift in Sources */,
-                               536EFBF7295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift in Sources */,
-                               53ED472029C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift in Sources */,
-                               5318AD9929BF58D000CBB71C /* NKError+Extensions.swift in Sources */,
-                               53ED472829C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift in Sources */,
-                               5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */,
-                               535AE30E29C0A2CC0042A9BA /* Logger+Extensions.swift in Sources */,
-                               5307A6F229675346001E0C6A /* NextcloudFilesDatabaseManager.swift in Sources */,
-                               53D056312970594F00988392 /* LocalFilesUtils.swift in Sources */,
-                               538E396F27F4765000FA63D5 /* FileProviderItem.swift in Sources */,
-                               5352B36829DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift in Sources */,
-                               5318AD9129BF42FB00CBB71C /* NextcloudItemMetadataTable.swift in Sources */,
-                               5352B36629DC14970011CE03 /* NextcloudFilesDatabaseManager+Directories.swift in Sources */,
-                               5318AD9729BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift in Sources */,
-                               5352B36C29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift in Sources */,
-                               538E397127F4765000FA63D5 /* FileProviderEnumerator.swift in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               53903D082956164F00D0B308 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               53903D2A295616F000D0B308 /* LocalSocketClient.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               C2B573AD1B1CD91E00303B36 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               C2B573BA1B1CD91E00303B36 /* main.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               C2B573D31B1CD9CE00303B36 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               539158AC27BE71A900816F56 /* FinderSyncSocketLineProcessor.m in Sources */,
-                               C2B573DE1B1CD9CE00303B36 /* FinderSync.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXTargetDependency section */
-               538E397527F4765000FA63D5 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 538E396627F4765000FA63D5 /* FileProviderExt */;
-                       targetProxy = 538E397427F4765000FA63D5 /* PBXContainerItemProxy */;
-               };
-               53903D202956164F00D0B308 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 53903D0B2956164F00D0B308 /* NCDesktopClientSocketKit */;
-                       targetProxy = 53903D1F2956164F00D0B308 /* PBXContainerItemProxy */;
-               };
-               53903D2E2956173000D0B308 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 53903D0B2956164F00D0B308 /* NCDesktopClientSocketKit */;
-                       targetProxy = 53903D2D2956173000D0B308 /* PBXContainerItemProxy */;
-               };
-               53903D332956173F00D0B308 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 53903D0B2956164F00D0B308 /* NCDesktopClientSocketKit */;
-                       targetProxy = 53903D322956173F00D0B308 /* PBXContainerItemProxy */;
-               };
-               C2B573E01B1CD9CE00303B36 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = C2B573D61B1CD9CE00303B36 /* FinderSyncExt */;
-                       targetProxy = C2B573DF1B1CD9CE00303B36 /* PBXContainerItemProxy */;
-               };
-/* End PBXTargetDependency section */
-
-/* Begin XCBuildConfiguration section */
-               538E397727F4765000FA63D5 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
-                               CLANG_ENABLE_MODULES = YES;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_ENTITLEMENTS = FileProviderExt/FileProviderExt.entitlements;
-                               CODE_SIGN_IDENTITY = "Apple Development";
-                               "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
-                               CODE_SIGN_INJECT_BASE_ENTITLEMENTS = YES;
-                               CODE_SIGN_STYLE = Manual;
-                               COPY_PHASE_STRIP = NO;
-                               CURRENT_PROJECT_VERSION = 1;
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               DEVELOPMENT_TEAM = "";
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GENERATE_INFOPLIST_FILE = YES;
-                               INFOPLIST_FILE = FileProviderExt/Info.plist;
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@executable_path/../../../../Frameworks",
-                               );
-                               MACOSX_DEPLOYMENT_TARGET = 11.0;
-                               MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
-                               MTL_FAST_MATH = YES;
-                               ONLY_ACTIVE_ARCH = YES;
-                               PRODUCT_BUNDLE_IDENTIFIER = "$(OC_APPLICATION_REV_DOMAIN).$(PRODUCT_NAME)";
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               PROVISIONING_PROFILE_SPECIFIER = "";
-                               SDKROOT = macosx;
-                               SKIP_INSTALL = YES;
-                               SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
-                               SWIFT_EMIT_LOC_STRINGS = YES;
-                               SWIFT_OPTIMIZATION_LEVEL = "-Onone";
-                               SWIFT_VERSION = 5.0;
-                       };
-                       name = Debug;
-               };
-               538E397827F4765000FA63D5 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
-                               CLANG_ENABLE_MODULES = YES;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_ENTITLEMENTS = FileProviderExt/FileProviderExt.entitlements;
-                               CODE_SIGN_IDENTITY = "Apple Development";
-                               "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
-                               CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
-                               CODE_SIGN_STYLE = Manual;
-                               COPY_PHASE_STRIP = NO;
-                               CURRENT_PROJECT_VERSION = 1;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               DEVELOPMENT_TEAM = "";
-                               ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GENERATE_INFOPLIST_FILE = YES;
-                               INFOPLIST_FILE = FileProviderExt/Info.plist;
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@executable_path/../../../../Frameworks",
-                               );
-                               MACOSX_DEPLOYMENT_TARGET = 11.0;
-                               MTL_ENABLE_DEBUG_INFO = NO;
-                               MTL_FAST_MATH = YES;
-                               PRODUCT_BUNDLE_IDENTIFIER = "$(OC_APPLICATION_REV_DOMAIN).$(PRODUCT_NAME)";
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               PROVISIONING_PROFILE_SPECIFIER = "";
-                               SDKROOT = macosx;
-                               SKIP_INSTALL = YES;
-                               SWIFT_COMPILATION_MODE = wholemodule;
-                               SWIFT_EMIT_LOC_STRINGS = YES;
-                               SWIFT_OPTIMIZATION_LEVEL = "-O";
-                               SWIFT_VERSION = 5.0;
-                       };
-                       name = Release;
-               };
-               53903D242956165000D0B308 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               APPLICATION_EXTENSION_API_ONLY = YES;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
-                               CLANG_ENABLE_MODULES = YES;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "-";
-                               CODE_SIGN_STYLE = Manual;
-                               COPY_PHASE_STRIP = NO;
-                               CURRENT_PROJECT_VERSION = 1;
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               DEFINES_MODULE = YES;
-                               DEVELOPMENT_TEAM = "";
-                               DYLIB_COMPATIBILITY_VERSION = 1;
-                               DYLIB_CURRENT_VERSION = 1;
-                               DYLIB_INSTALL_NAME_BASE = "@rpath";
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GENERATE_INFOPLIST_FILE = YES;
-                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
-                               IPHONEOS_DEPLOYMENT_TARGET = 16.2;
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "@executable_path/Frameworks",
-                                       "@loader_path/Frameworks",
-                               );
-                               "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/Frameworks",
-                               );
-                               MACOSX_DEPLOYMENT_TARGET = 10.14;
-                               MARKETING_VERSION = 1.0;
-                               MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
-                               MTL_FAST_MATH = YES;
-                               ONLY_ACTIVE_ARCH = YES;
-                               PRODUCT_BUNDLE_IDENTIFIER = com.owncloud.NCDesktopClientSocketKit;
-                               PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
-                               PROVISIONING_PROFILE_SPECIFIER = "";
-                               SDKROOT = auto;
-                               SKIP_INSTALL = YES;
-                               SUPPORTED_PLATFORMS = macosx;
-                               SUPPORTS_MACCATALYST = NO;
-                               SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
-                               SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
-                               SWIFT_EMIT_LOC_STRINGS = YES;
-                               SWIFT_OPTIMIZATION_LEVEL = "-Onone";
-                               SWIFT_VERSION = 5.0;
-                               VERSIONING_SYSTEM = "apple-generic";
-                               VERSION_INFO_PREFIX = "";
-                       };
-                       name = Debug;
-               };
-               53903D252956165000D0B308 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               APPLICATION_EXTENSION_API_ONLY = YES;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
-                               CLANG_ENABLE_MODULES = YES;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "-";
-                               CODE_SIGN_STYLE = Manual;
-                               COPY_PHASE_STRIP = NO;
-                               CURRENT_PROJECT_VERSION = 1;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               DEFINES_MODULE = YES;
-                               DEVELOPMENT_TEAM = "";
-                               DYLIB_COMPATIBILITY_VERSION = 1;
-                               DYLIB_CURRENT_VERSION = 1;
-                               DYLIB_INSTALL_NAME_BASE = "@rpath";
-                               ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GENERATE_INFOPLIST_FILE = YES;
-                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
-                               IPHONEOS_DEPLOYMENT_TARGET = 16.2;
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "@executable_path/Frameworks",
-                                       "@loader_path/Frameworks",
-                               );
-                               "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/Frameworks",
-                               );
-                               MACOSX_DEPLOYMENT_TARGET = 10.14;
-                               MARKETING_VERSION = 1.0;
-                               MTL_ENABLE_DEBUG_INFO = NO;
-                               MTL_FAST_MATH = YES;
-                               PRODUCT_BUNDLE_IDENTIFIER = com.owncloud.NCDesktopClientSocketKit;
-                               PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
-                               PROVISIONING_PROFILE_SPECIFIER = "";
-                               SDKROOT = auto;
-                               SKIP_INSTALL = YES;
-                               SUPPORTED_PLATFORMS = macosx;
-                               SUPPORTS_MACCATALYST = NO;
-                               SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
-                               SWIFT_COMPILATION_MODE = wholemodule;
-                               SWIFT_EMIT_LOC_STRINGS = YES;
-                               SWIFT_OPTIMIZATION_LEVEL = "-O";
-                               SWIFT_VERSION = 5.0;
-                               VERSIONING_SYSTEM = "apple-generic";
-                               VERSION_INFO_PREFIX = "";
-                       };
-                       name = Release;
-               };
-               C2B573991B1CD88000303B36 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_BOOL_CONVERSION = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_CONSTANT_CONVERSION = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN_ENUM_CONVERSION = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_INT_CONVERSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_NO_COMMON_BLOCKS = YES;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                               GCC_WARN_UNDECLARED_SELECTOR = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
-                               GCC_WARN_UNUSED_FUNCTION = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                       };
-                       name = Debug;
-               };
-               C2B5739A1B1CD88000303B36 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_BOOL_CONVERSION = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_CONSTANT_CONVERSION = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN_ENUM_CONVERSION = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_INT_CONVERSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_NO_COMMON_BLOCKS = YES;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                               GCC_WARN_UNDECLARED_SELECTOR = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
-                               GCC_WARN_UNUSED_FUNCTION = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                       };
-                       name = Release;
-               };
-               C2B573CD1B1CD91E00303B36 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_ENABLE_MODULES = YES;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_WARN_BOOL_CONVERSION = YES;
-                               CLANG_WARN_CONSTANT_CONVERSION = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN_ENUM_CONVERSION = YES;
-                               CLANG_WARN_INT_CONVERSION = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               CODE_SIGN_IDENTITY = "-";
-                               CODE_SIGN_STYLE = Manual;
-                               COMBINE_HIDPI_IMAGES = YES;
-                               COPY_PHASE_STRIP = NO;
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_NO_COMMON_BLOCKS = YES;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_UNDECLARED_SELECTOR = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               INFOPLIST_FILE = desktopclient/Info.plist;
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                               );
-                               MACOSX_DEPLOYMENT_TARGET = 10.14;
-                               MTL_ENABLE_DEBUG_INFO = YES;
-                               ONLY_ACTIVE_ARCH = YES;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               PROVISIONING_PROFILE = "";
-                               SDKROOT = macosx;
-                               SWIFT_OBJC_BRIDGING_HEADER = "desktopclient/desktopclient-Bridging-Header.h";
-                               SWIFT_OPTIMIZATION_LEVEL = "-Onone";
-                               SWIFT_VERSION = 5.0;
-                       };
-                       name = Debug;
-               };
-               C2B573CE1B1CD91E00303B36 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_ENABLE_MODULES = YES;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_WARN_BOOL_CONVERSION = YES;
-                               CLANG_WARN_CONSTANT_CONVERSION = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN_ENUM_CONVERSION = YES;
-                               CLANG_WARN_INT_CONVERSION = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               CODE_SIGN_IDENTITY = "-";
-                               CODE_SIGN_STYLE = Manual;
-                               COMBINE_HIDPI_IMAGES = YES;
-                               COPY_PHASE_STRIP = NO;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               ENABLE_NS_ASSERTIONS = NO;
-                               ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_NO_COMMON_BLOCKS = YES;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_UNDECLARED_SELECTOR = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               INFOPLIST_FILE = desktopclient/Info.plist;
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                               );
-                               MACOSX_DEPLOYMENT_TARGET = 10.14;
-                               MTL_ENABLE_DEBUG_INFO = NO;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               PROVISIONING_PROFILE = "";
-                               SDKROOT = macosx;
-                               SWIFT_OBJC_BRIDGING_HEADER = "desktopclient/desktopclient-Bridging-Header.h";
-                               SWIFT_VERSION = 5.0;
-                       };
-                       name = Release;
-               };
-               C2B573E41B1CD9CE00303B36 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_ENABLE_MODULES = YES;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_WARN_BOOL_CONVERSION = YES;
-                               CLANG_WARN_CONSTANT_CONVERSION = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN_ENUM_CONVERSION = YES;
-                               CLANG_WARN_INT_CONVERSION = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               CODE_SIGN_ENTITLEMENTS = FinderSyncExt/FinderSyncExt.entitlements;
-                               CODE_SIGN_IDENTITY = "-";
-                               CODE_SIGN_STYLE = Manual;
-                               COMBINE_HIDPI_IMAGES = YES;
-                               COPY_PHASE_STRIP = NO;
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_NO_COMMON_BLOCKS = YES;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_UNDECLARED_SELECTOR = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               GENERATE_INFOPLIST_FILE = YES;
-                               INFOPLIST_FILE = FinderSyncExt/Info.plist;
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@executable_path/../../../../Frameworks",
-                               );
-                               MACOSX_DEPLOYMENT_TARGET = 10.14;
-                               MTL_ENABLE_DEBUG_INFO = YES;
-                               OC_APPLICATION_NAME = ownCloud;
-                               OC_APPLICATION_REV_DOMAIN = com.owncloud.desktopclient;
-                               OC_OEM_SHARE_ICNS = "";
-                               OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX = "";
-                               ONLY_ACTIVE_ARCH = YES;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               PROVISIONING_PROFILE = "";
-                               SDKROOT = macosx;
-                               SKIP_INSTALL = YES;
-                       };
-                       name = Debug;
-               };
-               C2B573E51B1CD9CE00303B36 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_ENABLE_MODULES = YES;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_WARN_BOOL_CONVERSION = YES;
-                               CLANG_WARN_CONSTANT_CONVERSION = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN_ENUM_CONVERSION = YES;
-                               CLANG_WARN_INT_CONVERSION = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               CODE_SIGN_ENTITLEMENTS = FinderSyncExt/FinderSyncExt.entitlements;
-                               CODE_SIGN_IDENTITY = "-";
-                               CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
-                               CODE_SIGN_STYLE = Manual;
-                               COMBINE_HIDPI_IMAGES = YES;
-                               COPY_PHASE_STRIP = NO;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               ENABLE_NS_ASSERTIONS = NO;
-                               ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_NO_COMMON_BLOCKS = YES;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_UNDECLARED_SELECTOR = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               GENERATE_INFOPLIST_FILE = YES;
-                               INFOPLIST_FILE = FinderSyncExt/Info.plist;
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@executable_path/../../../../Frameworks",
-                               );
-                               MACOSX_DEPLOYMENT_TARGET = 10.14;
-                               MTL_ENABLE_DEBUG_INFO = NO;
-                               OC_APPLICATION_NAME = ownCloud;
-                               OC_APPLICATION_REV_DOMAIN = com.owncloud.desktopclient;
-                               OC_OEM_SHARE_ICNS = "";
-                               OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX = "";
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               PROVISIONING_PROFILE = "";
-                               SDKROOT = macosx;
-                               SKIP_INSTALL = YES;
-                       };
-                       name = Release;
-               };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
-               538E397927F4765000FA63D5 /* Build configuration list for PBXNativeTarget "FileProviderExt" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               538E397727F4765000FA63D5 /* Debug */,
-                               538E397827F4765000FA63D5 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               53903D282956165000D0B308 /* Build configuration list for PBXNativeTarget "NCDesktopClientSocketKit" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               53903D242956165000D0B308 /* Debug */,
-                               53903D252956165000D0B308 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               C2B573981B1CD88000303B36 /* Build configuration list for PBXProject "NextcloudIntegration" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               C2B573991B1CD88000303B36 /* Debug */,
-                               C2B5739A1B1CD88000303B36 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               C2B573CC1B1CD91E00303B36 /* Build configuration list for PBXNativeTarget "desktopclient" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               C2B573CD1B1CD91E00303B36 /* Debug */,
-                               C2B573CE1B1CD91E00303B36 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               C2B573E31B1CD9CE00303B36 /* Build configuration list for PBXNativeTarget "FinderSyncExt" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               C2B573E41B1CD9CE00303B36 /* Debug */,
-                               C2B573E51B1CD9CE00303B36 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-/* End XCConfigurationList section */
-
-/* Begin XCRemoteSwiftPackageReference section */
-               5307A6E42965C6FA001E0C6A /* XCRemoteSwiftPackageReference "NextcloudKit" */ = {
-                       isa = XCRemoteSwiftPackageReference;
-                       repositoryURL = "https://github.com/nextcloud/NextcloudKit";
-                       requirement = {
-                               branch = develop;
-                               kind = branch;
-                       };
-               };
-               5307A6E92965DB57001E0C6A /* XCRemoteSwiftPackageReference "realm-swift" */ = {
-                       isa = XCRemoteSwiftPackageReference;
-                       repositoryURL = "https://github.com/realm/realm-swift.git";
-                       requirement = {
-                               kind = exactVersion;
-                               version = 10.33.0;
-                       };
-               };
-/* End XCRemoteSwiftPackageReference section */
-
-/* Begin XCSwiftPackageProductDependency section */
-               5307A6E52965C6FA001E0C6A /* NextcloudKit */ = {
-                       isa = XCSwiftPackageProductDependency;
-                       package = 5307A6E42965C6FA001E0C6A /* XCRemoteSwiftPackageReference "NextcloudKit" */;
-                       productName = NextcloudKit;
-               };
-               5307A6E72965DAD8001E0C6A /* NextcloudKit */ = {
-                       isa = XCSwiftPackageProductDependency;
-                       package = 5307A6E42965C6FA001E0C6A /* XCRemoteSwiftPackageReference "NextcloudKit" */;
-                       productName = NextcloudKit;
-               };
-               5307A6EA2965DB8D001E0C6A /* RealmSwift */ = {
-                       isa = XCSwiftPackageProductDependency;
-                       package = 5307A6E92965DB57001E0C6A /* XCRemoteSwiftPackageReference "realm-swift" */;
-                       productName = RealmSwift;
-               };
-/* End XCSwiftPackageProductDependency section */
-       };
-       rootObject = C2B573951B1CD88000303B36 /* Project object */;
-}
diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata
deleted file mode 100644 (file)
index 919434a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "self:">
-   </FileRef>
-</Workspace>
diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
deleted file mode 100644 (file)
index 18d9810..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>IDEDidComputeMac32BitWarning</key>
-       <true/>
-</dict>
-</plist>
diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/xcshareddata/xcschemes/FinderSyncExt.xcscheme b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/xcshareddata/xcschemes/FinderSyncExt.xcscheme
deleted file mode 100644 (file)
index 174aab5..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1240"
-   wasCreatedForAppExtension = "YES"
-   version = "2.0">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "C2B573D61B1CD9CE00303B36"
-               BuildableName = "FinderSyncExt.appex"
-               BlueprintName = "FinderSyncExt"
-               ReferencedContainer = "container:NextcloudIntegration.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "C2B573B01B1CD91E00303B36"
-               BuildableName = "desktopclient.app"
-               BlueprintName = "desktopclient"
-               ReferencedContainer = "container:NextcloudIntegration.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "C2B573D61B1CD9CE00303B36"
-            BuildableName = "FinderSyncExt.appex"
-            BlueprintName = "FinderSyncExt"
-            ReferencedContainer = "container:NextcloudIntegration.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <Testables>
-         <TestableReference
-            skipped = "NO"
-            parallelizable = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "53903D142956164F00D0B308"
-               BuildableName = "NCDesktopClientSocketKitTests.xctest"
-               BlueprintName = "NCDesktopClientSocketKitTests"
-               ReferencedContainer = "container:NextcloudIntegration.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = ""
-      selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
-      launchStyle = "0"
-      askForAppToLaunch = "Yes"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES"
-      launchAutomaticallySubstyle = "2">
-      <BuildableProductRunnable
-         runnableDebuggingMode = "0">
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "C2B573B01B1CD91E00303B36"
-            BuildableName = "desktopclient.app"
-            BlueprintName = "desktopclient"
-            ReferencedContainer = "container:NextcloudIntegration.xcodeproj">
-         </BuildableReference>
-      </BuildableProductRunnable>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES"
-      askForAppToLaunch = "Yes"
-      launchAutomaticallySubstyle = "2">
-      <BuildableProductRunnable
-         runnableDebuggingMode = "0">
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "C2B573B01B1CD91E00303B36"
-            BuildableName = "desktopclient.app"
-            BlueprintName = "desktopclient"
-            ReferencedContainer = "container:NextcloudIntegration.xcodeproj">
-         </BuildableReference>
-      </BuildableProductRunnable>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/shell_integration/MacOSX/NextcloudIntegration/desktopclient/Info.plist b/shell_integration/MacOSX/NextcloudIntegration/desktopclient/Info.plist
deleted file mode 100644 (file)
index bbaa296..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>en</string>
-       <key>CFBundleExecutable</key>
-       <string>$(EXECUTABLE_NAME)</string>
-       <key>CFBundleIconFile</key>
-       <string></string>
-       <key>CFBundleIdentifier</key>
-       <string>com.owncloud.$(PRODUCT_NAME:rfc1034identifier)</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundleName</key>
-       <string>$(PRODUCT_NAME)</string>
-       <key>CFBundlePackageType</key>
-       <string>APPL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-       <key>LSMinimumSystemVersion</key>
-       <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
-       <key>NSPrincipalClass</key>
-       <string>NSApplication</string>
-</dict>
-</plist>
diff --git a/shell_integration/MacOSX/NextcloudIntegration/desktopclient/main.m b/shell_integration/MacOSX/NextcloudIntegration/desktopclient/main.m
deleted file mode 100644 (file)
index 6f580d2..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-//  main.m
-//  desktopclient
-//
-//  Created by Jocelyn Turcotte on 01/06/15.
-//
-//
-
-// This is fake application bundle with the same bundle ID as the real desktop client.
-// Xcode needs a wrapping application to allow the extension to be debugged.
-
-#import <Cocoa/Cocoa.h>
-
-int main(int argc, const char * argv[]) {
-    return NSApplicationMain(argc, argv);
-}
diff --git a/shell_integration/MacOSX/OwnCloud.xcworkspace/contents.xcworkspacedata b/shell_integration/MacOSX/OwnCloud.xcworkspace/contents.xcworkspacedata
new file mode 100644 (file)
index 0000000..ed88ebf
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/shell_integration/MacOSX/OwnCloud.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/shell_integration/MacOSX/OwnCloud.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644 (file)
index 0000000..18d9810
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>IDEDidComputeMac32BitWarning</key>
+       <true/>
+</dict>
+</plist>
diff --git a/shell_integration/MacOSX/OwnCloud.xcworkspace/xcshareddata/OwnCloud.xccheckout b/shell_integration/MacOSX/OwnCloud.xcworkspace/xcshareddata/OwnCloud.xccheckout
new file mode 100644 (file)
index 0000000..9512111
--- /dev/null
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>IDESourceControlProjectFavoriteDictionaryKey</key>
+       <false/>
+       <key>IDESourceControlProjectIdentifier</key>
+       <string>5264E8F5-AB49-45F3-868F-647EEFAB70E0</string>
+       <key>IDESourceControlProjectName</key>
+       <string>OwnCloud</string>
+       <key>IDESourceControlProjectOriginsDictionary</key>
+       <dict>
+               <key>D67321A19EF879CA55BF889202BA8C23AC9AA2B5</key>
+               <string>ssh://github.com/owncloud/client.git</string>
+       </dict>
+       <key>IDESourceControlProjectPath</key>
+       <string>shell_integration/MacOSX/OwnCloud.xcworkspace</string>
+       <key>IDESourceControlProjectRelativeInstallPathDictionary</key>
+       <dict>
+               <key>D67321A19EF879CA55BF889202BA8C23AC9AA2B5</key>
+               <string>../../..</string>
+       </dict>
+       <key>IDESourceControlProjectURL</key>
+       <string>ssh://github.com/owncloud/client.git</string>
+       <key>IDESourceControlProjectVersion</key>
+       <integer>111</integer>
+       <key>IDESourceControlProjectWCCIdentifier</key>
+       <string>D67321A19EF879CA55BF889202BA8C23AC9AA2B5</string>
+       <key>IDESourceControlProjectWCConfigurations</key>
+       <array>
+               <dict>
+                       <key>IDESourceControlRepositoryExtensionIdentifierKey</key>
+                       <string>public.vcs.git</string>
+                       <key>IDESourceControlWCCIdentifierKey</key>
+                       <string>D67321A19EF879CA55BF889202BA8C23AC9AA2B5</string>
+                       <key>IDESourceControlWCCName</key>
+                       <string>client</string>
+               </dict>
+       </array>
+</dict>
+</plist>
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/FinderSync.h b/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/FinderSync.h
new file mode 100644 (file)
index 0000000..4cf5765
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) by Jocelyn Turcotte <jturcotte@woboq.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#import <Cocoa/Cocoa.h>
+#import <FinderSync/FinderSync.h>
+#import "SyncClient.h"
+#import "LineProcessor.h"
+#import "LocalSocketClient.h"
+
+@interface FinderSync : FIFinderSync <SyncClientDelegate>
+{
+    NSMutableSet *_registeredDirectories;
+    NSString *_shareMenuTitle;
+    NSMutableDictionary *_strings;
+    NSMutableArray *_menuItems;
+    NSCondition *_menuIsComplete;
+}
+
+@property LineProcessor *lineProcessor;
+@property LocalSocketClient *localSocketClient;
+
+@end
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/FinderSync.m b/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/FinderSync.m
new file mode 100644 (file)
index 0000000..84a124f
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) by Jocelyn Turcotte <jturcotte@woboq.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#import "FinderSync.h"
+
+
+@implementation FinderSync
+
+- (instancetype)init
+{
+       self = [super init];
+
+    if (self) {
+        FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
+        NSBundle *extBundle = [NSBundle bundleForClass:[self class]];
+        // This was added to the bundle's Info.plist to get it from the build system
+        NSString *socketApiPrefix = [extBundle objectForInfoDictionaryKey:@"SocketApiPrefix"];
+        
+        NSImage *ok = [extBundle imageForResource:@"ok.icns"];
+        NSImage *ok_swm = [extBundle imageForResource:@"ok_swm.icns"];
+        NSImage *sync = [extBundle imageForResource:@"sync.icns"];
+        NSImage *warning = [extBundle imageForResource:@"warning.icns"];
+        NSImage *error = [extBundle imageForResource:@"error.icns"];
+        
+        [syncController setBadgeImage:ok label:@"Up to date" forBadgeIdentifier:@"OK"];
+        [syncController setBadgeImage:sync label:@"Synchronizing" forBadgeIdentifier:@"SYNC"];
+        [syncController setBadgeImage:sync label:@"Synchronizing" forBadgeIdentifier:@"NEW"];
+        [syncController setBadgeImage:warning label:@"Ignored" forBadgeIdentifier:@"IGNORE"];
+        [syncController setBadgeImage:error label:@"Error" forBadgeIdentifier:@"ERROR"];
+        [syncController setBadgeImage:ok_swm label:@"Shared" forBadgeIdentifier:@"OK+SWM"];
+        [syncController setBadgeImage:sync label:@"Synchronizing" forBadgeIdentifier:@"SYNC+SWM"];
+        [syncController setBadgeImage:sync label:@"Synchronizing" forBadgeIdentifier:@"NEW+SWM"];
+        [syncController setBadgeImage:warning label:@"Ignored" forBadgeIdentifier:@"IGNORE+SWM"];
+        [syncController setBadgeImage:error label:@"Error" forBadgeIdentifier:@"ERROR+SWM"];
+        
+        // The Mach port name needs to:
+        // - Be prefixed with the code signing Team ID
+        // - Then infixed with the sandbox App Group
+        // - The App Group itself must be a prefix of (or equal to) the application bundle identifier
+        // We end up in the official signed client with: 9B5WD74GWJ.com.owncloud.desktopclient.socket
+        // With ad-hoc signing (the '-' signing identity) we must drop the Team ID.
+        // When the code isn't sandboxed (e.g. the OC client or the legacy overlay icon extension)
+        // the OS doesn't seem to put any restriction on the port name, so we just follow what
+        // the sandboxed App Extension needs.
+        // https://developer.apple.com/library/mac/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24
+        
+        NSURL *container = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:socketApiPrefix];
+        NSURL *socketPath = [container URLByAppendingPathComponent:@".socket" isDirectory:NO];
+        
+        NSLog(@"Socket path: %@", socketPath.path);
+        
+        if (socketPath.path) {
+            self.lineProcessor = [[LineProcessor alloc] initWithDelegate:self];
+            self.localSocketClient = [[LocalSocketClient alloc] init:socketPath.path
+                                                       lineProcessor:self.lineProcessor];
+            [self.localSocketClient start];
+        } else {
+            NSLog(@"No socket path. Not initiating local socket client.");
+            self.localSocketClient = nil;
+        }
+        _registeredDirectories = [[NSMutableSet alloc] init];
+        _strings = [[NSMutableDictionary alloc] init];
+        _menuIsComplete = [[NSCondition alloc] init];
+    }
+
+    return self;
+}
+
+#pragma mark - Primary Finder Sync protocol methods
+
+- (void)requestBadgeIdentifierForURL:(NSURL *)url
+{
+       BOOL isDir;
+       if ([[NSFileManager defaultManager] fileExistsAtPath:[url path] isDirectory: &isDir] == NO) {
+               NSLog(@"ERROR: Could not determine file type of %@", [url path]);
+               isDir = NO;
+       }
+
+       NSString* normalizedPath = [[url path] decomposedStringWithCanonicalMapping];
+       [self.localSocketClient askForIcon:normalizedPath isDirectory:isDir];
+}
+
+#pragma mark - Menu and toolbar item support
+
+- (NSString*) selectedPathsSeparatedByRecordSeparator
+{
+       FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
+       NSMutableString *string = [[NSMutableString alloc] init];
+       [syncController.selectedItemURLs enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
+               if (string.length > 0) {
+                       [string appendString:@"\x1e"]; // record separator
+               }
+               NSString* normalizedPath = [[obj path] decomposedStringWithCanonicalMapping];
+               [string appendString:normalizedPath];
+       }];
+       return string;
+}
+
+- (void)waitForMenuToArrive
+{
+    [self->_menuIsComplete lock];
+    [self->_menuIsComplete wait];
+    [self->_menuIsComplete unlock];
+}
+
+- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu
+{
+    if(![self.localSocketClient isConnected]) {
+        return nil;
+    }
+    
+       FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
+       NSMutableSet *rootPaths = [[NSMutableSet alloc] init];
+       [syncController.directoryURLs enumerateObjectsUsingBlock: ^(id obj, BOOL *stop) {
+               [rootPaths addObject:[obj path]];
+       }];
+
+       // The server doesn't support sharing a root directory so do not show the option in this case.
+       // It is still possible to get a problematic sharing by selecting both the root and a child,
+       // but this is so complicated to do and meaningless that it's not worth putting this check
+       // also in shareMenuAction.
+       __block BOOL onlyRootsSelected = YES;
+       [syncController.selectedItemURLs enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
+               if (![rootPaths member:[obj path]]) {
+                       onlyRootsSelected = NO;
+                       *stop = YES;
+               }
+       }];
+
+       NSString *paths = [self selectedPathsSeparatedByRecordSeparator];
+       [self.localSocketClient askOnSocket:paths query:@"GET_MENU_ITEMS"];
+    
+    // Since the LocalSocketClient communicates asynchronously. wait here until the menu
+    // is delivered by another thread
+    [self waitForMenuToArrive];
+
+       id contextMenuTitle = [_strings objectForKey:@"CONTEXT_MENU_TITLE"];
+       if (contextMenuTitle && !onlyRootsSelected) {
+               NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
+               NSMenu *subMenu = [[NSMenu alloc] initWithTitle:@""];
+               NSMenuItem *subMenuItem = [menu addItemWithTitle:contextMenuTitle action:nil keyEquivalent:@""];
+               subMenuItem.submenu = subMenu;
+               subMenuItem.image = [[NSBundle mainBundle] imageForResource:@"app.icns"];
+
+               // There is an annoying bug in macOS (at least 10.13.3), it does not use/copy over the representedObject of a menu item
+               // So we have to use tag instead.
+               int idx = 0;
+               for (NSArray* item in _menuItems) {
+                       NSMenuItem *actionItem = [subMenu addItemWithTitle:[item valueForKey:@"text"]
+                                                                                                               action:@selector(subMenuActionClicked:)
+                                                                                                keyEquivalent:@""];
+                       [actionItem setTag:idx];
+                       [actionItem setTarget:self];
+                       NSString *flags = [item valueForKey:@"flags"]; // e.g. "d"
+                       if ([flags rangeOfString:@"d"].location != NSNotFound) {
+                               [actionItem setEnabled:false];
+                       }
+                       idx++;
+               }
+               return menu;
+       }
+       return nil;
+}
+
+- (void)subMenuActionClicked:(id)sender {
+       long idx = [(NSMenuItem*)sender tag];
+       NSString *command = [[_menuItems objectAtIndex:idx] valueForKey:@"command"];
+       NSString *paths = [self selectedPathsSeparatedByRecordSeparator];
+       [self.localSocketClient askOnSocket:paths query:command];
+}
+
+#pragma mark - SyncClientProxyDelegate implementation
+
+- (void)setResultForPath:(NSString*)path result:(NSString*)result
+{
+       NSString *normalizedPath = [path decomposedStringWithCanonicalMapping];
+       [[FIFinderSyncController defaultController] setBadgeIdentifier:result forURL:[NSURL fileURLWithPath:normalizedPath]];
+}
+
+- (void)reFetchFileNameCacheForPath:(NSString*)path
+{
+    
+}
+
+- (void)registerPath:(NSString*)path
+{
+       assert(_registeredDirectories);
+       [_registeredDirectories addObject:[NSURL fileURLWithPath:path]];
+       [FIFinderSyncController defaultController].directoryURLs = _registeredDirectories;
+}
+
+- (void)unregisterPath:(NSString*)path
+{
+       [_registeredDirectories removeObject:[NSURL fileURLWithPath:path]];
+       [FIFinderSyncController defaultController].directoryURLs = _registeredDirectories;
+}
+
+- (void)setString:(NSString*)key value:(NSString*)value
+{
+       [_strings setObject:value forKey:key];
+}
+
+- (void)resetMenuItems
+{
+       _menuItems = [[NSMutableArray alloc] init];
+}
+- (void)addMenuItem:(NSDictionary *)item {
+    NSLog(@"Adding menu item.");
+       [_menuItems addObject:item];
+}
+
+- (void)menuHasCompleted
+{
+    NSLog(@"Emitting menu is complete signal now.");
+    [self->_menuIsComplete signal];
+}
+
+- (void)connectionDidDie
+{
+       [_strings removeAllObjects];
+       [_registeredDirectories removeAllObjects];
+       // For some reason the FIFinderSync cache doesn't seem to be cleared for the root item when
+       // we reset the directoryURLs (seen on macOS 10.12 at least).
+       // First setting it to the FS root and then setting it to nil seems to work around the issue.
+       [FIFinderSyncController defaultController].directoryURLs = [NSSet setWithObject:[NSURL fileURLWithPath:@"/"]];
+       // This will tell Finder that this extension isn't attached to any directory
+       // until we can reconnect to the sync client.
+       [FIFinderSyncController defaultController].directoryURLs = nil;
+}
+
+@end
+
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/FinderSyncExt.entitlements b/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/FinderSyncExt.entitlements
new file mode 100644 (file)
index 0000000..5d2a36d
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.security.app-sandbox</key>
+       <true/>
+       <key>com.apple.security.application-groups</key>
+       <array>
+               <string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
+       </array>
+</dict>
+</plist>
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/Info.plist b/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/Info.plist
new file mode 100644 (file)
index 0000000..88bb87e
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SocketApiPrefix</key>
+       <string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleDisplayName</key>
+       <string>$(OC_APPLICATION_NAME) Extensions</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIdentifier</key>
+       <string>$(OC_APPLICATION_REV_DOMAIN).$(PRODUCT_NAME:rfc1034identifier)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>XPC!</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+       <key>LSUIElement</key>
+       <true/>
+       <key>NSExtension</key>
+       <dict>
+               <key>NSExtensionAttributes</key>
+               <dict/>
+               <key>NSExtensionPointIdentifier</key>
+               <string>com.apple.FinderSync</string>
+               <key>NSExtensionPrincipalClass</key>
+               <string>FinderSync</string>
+       </dict>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LineProcessor.h b/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LineProcessor.h
new file mode 100644 (file)
index 0000000..137ce62
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#import "SyncClient.h"
+
+#ifndef LineProcessor_h
+#define LineProcessor_h
+
+/// This class is in charge of dispatching all work that must be done on the UI side of the extension.
+/// Tasks are dispatched on the main UI thread for this reason.
+///
+/// These tasks are parsed from byte data (UTF9 strings) acquired from the socket; look at the
+/// LocalSocketClient for more detail on how data is read from and written to the socket.
+
+@interface LineProcessor : NSObject
+@property(nonatomic, weak)id<SyncClientDelegate> delegate;
+
+- (instancetype)initWithDelegate:(id<SyncClientDelegate>)delegate;
+- (void)process:(NSString*)line;
+
+@end
+#endif /* LineProcessor_h */
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LineProcessor.m b/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LineProcessor.m
new file mode 100644 (file)
index 0000000..56ec704
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#import <Foundation/Foundation.h>
+#import "LineProcessor.h"
+
+@implementation LineProcessor
+
+-(instancetype)initWithDelegate:(id<SyncClientDelegate>)delegate
+{
+    NSLog(@"Init line processor with delegate.");
+    self = [super init];
+    if (self) {
+        self.delegate = delegate;
+    }
+    return self;
+}
+
+-(void)process:(NSString*)line
+{
+    NSLog(@"Processing line: %@", line);
+    NSArray *split = [line componentsSeparatedByString:@":"];
+    NSString *command = [split objectAtIndex:0];
+    
+    NSLog(@"Command: %@", command);
+    
+    if([command isEqualToString:@"STATUS"]) {
+        NSString *result = [split objectAtIndex:1];
+        NSArray *pathSplit = [split subarrayWithRange:NSMakeRange(2, [split count] - 2)]; // Get everything after location 2
+        NSString *path = [pathSplit componentsJoinedByString:@":"];
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSLog(@"Setting result %@ for path %@", result, path);
+            [self.delegate setResultForPath:path result:result];
+        });
+    } else if([command isEqualToString:@"UPDATE_VIEW"]) {
+        NSString *path = [split objectAtIndex:1];
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSLog(@"Re-fetching filename cache for path %@", path);
+            [self.delegate reFetchFileNameCacheForPath:path];
+        });
+    } else if([command isEqualToString:@"REGISTER_PATH"]) {
+        NSString *path = [split objectAtIndex:1];
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSLog(@"Registering path %@", path);
+            [self.delegate registerPath:path];
+        });
+    } else if([command isEqualToString:@"UNREGISTER_PATH"]) {
+        NSString *path = [split objectAtIndex:1];
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSLog(@"Unregistering path %@", path);
+            [self.delegate unregisterPath:path];
+        });
+    } else if([command isEqualToString:@"GET_STRINGS"]) {
+        // BEGIN and END messages, do nothing.
+        return;
+    } else if([command isEqualToString:@"STRING"]) {
+        NSString *key = [split objectAtIndex:1];
+        NSString *value = [split objectAtIndex:2];
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSLog(@"Setting string %@ to value %@", key, value);
+            [self.delegate setString:key value:value];
+        });
+    } else if([command isEqualToString:@"GET_MENU_ITEMS"]) {
+        if([[split objectAtIndex:1] isEqualToString:@"BEGIN"]) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                NSLog(@"Resetting menu items.");
+                [self.delegate resetMenuItems];
+            });
+        } else {
+            NSLog(@"Emitting menu has completed signal.");
+            [self.delegate menuHasCompleted];
+        }
+    } else if([command isEqualToString:@"MENU_ITEM"]) {
+        NSDictionary *item = @{@"command": [split objectAtIndex:1], @"flags": [split objectAtIndex:2], @"text": [split objectAtIndex:3]};
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSLog(@"Adding menu item with command %@, flags %@, and text %@", [split objectAtIndex:1], [split objectAtIndex:2], [split objectAtIndex:3]);
+            [self.delegate addMenuItem:item];
+        });
+    } else {
+        // LOG UNKOWN COMMAND
+        NSLog(@"Unkown command: %@", command);
+    }
+}
+
+@end
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LocalSocketClient.h b/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LocalSocketClient.h
new file mode 100644 (file)
index 0000000..4a858cd
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#import "LineProcessor.h"
+
+#ifndef LocalSocketClient_h
+#define LocalSocketClient_h
+#define BUF_SIZE 4096
+
+/// Class handling asynchronous communication with a server over a local UNIX socket.
+///
+/// The implementation uses a `DispatchQueue` and `DispatchSource`s to handle asynchronous communication and thread
+/// safety. The delegate that handles the line-decoding is **not invoked on the UI thread**, but the (random) thread associated
+/// with the `DispatchQueue`.
+///
+/// If any UI work needs to be done, the `LineProcessor` class dispatches this work on the main queue (so the UI thread) itself.
+///
+/// Other than the `init(withSocketPath:, lineProcessor)` and the `start()` method, all work is done "on the dispatch
+/// queue". The `localSocketQueue` is a serial dispatch queue (so a maximum of 1, and only 1, task is run at any
+/// moment), which guarantees safe access to instance variables. Both `askOnSocket(_:, query:)` and
+/// `askForIcon(_:, isDirectory:)` will internally dispatch the work on the `DispatchQueue`.
+///
+/// Sending and receiving data to and from the socket, is handled by two `DispatchSource`s. These will run an event
+/// handler when data can be read from resp. written to the socket. These handlers will also be run on the
+/// `DispatchQueue`.
+
+@interface LocalSocketClient : NSObject
+
+@property NSString* socketPath;
+@property LineProcessor* lineProcessor;
+@property int sock;
+@property dispatch_queue_t localSocketQueue;
+@property dispatch_source_t readSource;
+@property dispatch_source_t writeSource;
+@property NSMutableData* inBuffer;
+@property NSMutableData* outBuffer;
+
+- (instancetype)init:(NSString*)socketPath lineProcessor:(LineProcessor*)lineProcessor;
+- (BOOL)isConnected;
+- (void)start;
+- (void)restart;
+- (void)closeConnection;
+- (NSString*)strErr;
+- (void)askOnSocket:(NSString*)path query:(NSString*)verb;
+- (void)askForIcon:(NSString*)path isDirectory:(BOOL)isDirectory;
+- (void)readFromSocket;
+- (void)writeToSocket;
+- (void)processInBuffer;
+
+@end
+#endif /* LocalSocketClient_h */
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LocalSocketClient.m b/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/LocalSocketClient.m
new file mode 100644 (file)
index 0000000..ab43a5d
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#import <Foundation/Foundation.h>
+#import "LocalSocketClient.h"
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <string.h>
+
+@implementation LocalSocketClient
+
+- (instancetype)init:(NSString*)socketPath lineProcessor:(LineProcessor*)lineProcessor
+{
+    NSLog(@"Initiating local socket client.");
+    self = [super init];
+    
+    if(self) {
+        self.socketPath = socketPath;
+        self.lineProcessor = lineProcessor;
+        
+        self.sock = -1;
+        self.localSocketQueue = dispatch_queue_create("localSocketQueue", DISPATCH_QUEUE_SERIAL);
+        
+        self.inBuffer = [NSMutableData data];
+        self.outBuffer = [NSMutableData data];
+    }
+        
+    return self;
+}
+
+- (BOOL)isConnected
+{
+    NSLog(@"Checking is connected: %@", self.sock != -1 ? @"YES" : @"NO");
+    return self.sock != -1;
+}
+
+- (void)start
+{
+    if([self isConnected]) {
+        NSLog(@"Socket client already connected. Not starting.");
+        return;
+    }
+    
+    struct sockaddr_un localSocketAddr;
+    unsigned long socketPathByteCount = [self.socketPath lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; // add 1 for the NUL terminator char
+    int maxByteCount = sizeof(localSocketAddr.sun_path);
+    
+    if(socketPathByteCount > maxByteCount) {
+        // LOG THAT THE SOCKET PATH IS TOO LONG HERE
+        NSLog(@"Socket path '%@' is too long: maximum socket path length is %i, this path is of length %lu", self.socketPath, maxByteCount, socketPathByteCount);
+        return;
+    }
+    
+    NSLog(@"Opening local socket...");
+    
+    // LOG THAT THE SOCKET IS BEING OPENED HERE
+    self.sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+    
+    if(self.sock == -1) {
+        NSLog(@"Cannot open socket: '%@'", [self strErr]);
+        [self restart];
+        return;
+    }
+    
+    NSLog(@"Local socket opened. Connecting to '%@' ...", self.socketPath);
+    
+    localSocketAddr.sun_family = AF_LOCAL & 0xff;
+    
+    const char* pathBytes = [self.socketPath UTF8String];
+    strcpy(localSocketAddr.sun_path, pathBytes);
+    
+    int connectionStatus = connect(self.sock, (struct sockaddr*)&localSocketAddr, sizeof(localSocketAddr));
+    
+    if(connectionStatus == -1) {
+        NSLog(@"Could not connect to '%@': '%@'", self.socketPath, [self strErr]);
+        [self restart];
+        return;
+    }
+    
+    int flags = fcntl(self.sock, F_GETFL, 0);
+    
+    if(fcntl(self.sock, F_SETFL, flags | O_NONBLOCK) == -1) {
+        NSLog(@"Could not set socket to non-blocking mode: '%@'", [self strErr]);
+        [self restart];
+        return;
+    }
+    
+    NSLog(@"Connected to socket. Setting up dispatch sources...");
+    
+    self.readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, self.sock, 0, self.localSocketQueue);
+    dispatch_source_set_event_handler(self.readSource, ^(void){ [self readFromSocket]; });
+    dispatch_source_set_cancel_handler(self.readSource, ^(void){
+        self.readSource = nil;
+        [self closeConnection];
+    });
+    
+    self.writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, self.sock, 0, self.localSocketQueue);
+    dispatch_source_set_event_handler(self.writeSource, ^(void){ [self writeToSocket]; });
+    dispatch_source_set_cancel_handler(self.writeSource, ^(void){
+        self.writeSource = nil;
+        [self closeConnection];
+    });
+    
+    // These dispatch sources are suspended upon creation.
+    // We resume the writeSource when we actually have something to write, suspending it again once our outBuffer is empty.
+    // We start the readSource now.
+    
+    NSLog(@"Starting to read from socket");
+    
+    dispatch_resume(self.readSource);
+    [self askOnSocket:@"" query:@"GET_STRINGS"];
+}
+
+- (void)restart
+{
+    NSLog(@"Restarting connection to socket.");
+    [self closeConnection];
+    dispatch_async(dispatch_get_main_queue(), ^(void){
+        [NSTimer scheduledTimerWithTimeInterval:5 repeats:NO block:^(NSTimer* timer) {
+            [self start];
+        }];
+    });
+}
+
+- (void)closeConnection
+{
+    NSLog(@"Closing connection.");
+    
+    if(self.readSource) {
+        // Since dispatch_source_cancel works asynchronously, if we deallocate the dispatch source here then we can
+        // cause a crash. So instead we strongly hold a reference to the read source and deallocate it asynchronously
+        // with the handler.
+        __block dispatch_source_t previousReadSource = self.readSource;
+        dispatch_source_set_cancel_handler(self.readSource, ^{
+            previousReadSource = nil;
+        });
+        dispatch_source_cancel(self.readSource);
+        // The readSource is still alive due to the other reference and will be deallocated by the cancel handler
+        self.readSource = nil;
+    }
+    
+    if(self.writeSource) {
+        // Same deal with the write source
+        __block dispatch_source_t previousWriteSource = self.writeSource;
+        dispatch_source_set_cancel_handler(self.writeSource, ^{
+            previousWriteSource = nil;
+        });
+        dispatch_source_cancel(self.writeSource);
+        self.writeSource = nil;
+    }
+
+    [self.inBuffer setLength:0];
+    [self.outBuffer setLength: 0];
+    
+    if(self.sock != -1) {
+        close(self.sock);
+        self.sock = -1;
+    }
+}
+
+- (NSString*)strErr
+{
+    int err = errno;
+    const char *errStr = strerror(err);
+    NSString *errorStr = [NSString stringWithUTF8String:errStr];
+    
+    if([errorStr length] == 0) {
+        return errorStr;
+    } else {
+        return [NSString stringWithFormat:@"Unknown error code: %i\10", err];
+    }
+}
+
+- (void)askOnSocket:(NSString *)path query:(NSString *)verb
+{
+    NSString *line = [NSString stringWithFormat:@"%@:%@\n", verb, path];
+    dispatch_async(self.localSocketQueue, ^(void) {
+        if(![self isConnected]) {
+            return;
+        }
+        
+        BOOL writeSourceIsSuspended = [self.outBuffer length] == 0;
+        
+        [self.outBuffer appendData:[line dataUsingEncoding:NSUTF8StringEncoding]];
+        
+        NSLog(@"Writing to out buffer: '%@'", line);
+        NSLog(@"Out buffer now %li bytes", [self.outBuffer length]);
+        
+        if(writeSourceIsSuspended) {
+            NSLog(@"Resuming write dispatch source.");
+            dispatch_resume(self.writeSource);
+        }
+    });
+}
+
+- (void)writeToSocket
+{
+    if(![self isConnected]) {
+        return;
+    }
+    
+    if([self.outBuffer length] == 0) {
+        NSLog(@"Empty out buffer, suspending write dispatch source.");
+        dispatch_suspend(self.writeSource);
+        return;
+    }
+    
+    NSLog(@"About to write %li bytes from outbuffer to socket.", [self.outBuffer length]);
+    
+    long bytesWritten = write(self.sock, [self.outBuffer bytes], [self.outBuffer length]);
+    char lineWritten[[self.outBuffer length]];
+    memcpy(lineWritten, [self.outBuffer bytes], [self.outBuffer length]);
+    NSLog(@"Wrote %li bytes to socket. Line written was: '%@'", bytesWritten, [NSString stringWithUTF8String:lineWritten]);
+    
+    if(bytesWritten == 0) {
+        // 0 means we reached "end of file" and thus the socket was closed\10. So let's restart it
+        NSLog(@"Socket was closed. Restarting...");
+        [self restart];
+    } else if(bytesWritten == -1) {
+        int err = errno; // Make copy before it gets nuked by something else
+        
+        if(err == EAGAIN || err == EWOULDBLOCK)  {
+            // No free space in the OS' buffer, nothing to do here
+            NSLog(@"No free space in OS buffer. Ending write.");
+            return;
+        } else {
+            NSLog(@"Error writing to local socket: '%@'", [self strErr]);
+            [self restart];
+        }
+    } else if(bytesWritten > 0) {
+        [self.outBuffer replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
+        
+        NSLog(@"Out buffer cleared. Now count is %li bytes.", [self.outBuffer length]);
+        
+        if([self.outBuffer length] == 0) {
+            NSLog(@"Out buffer has been emptied, suspending write dispatch source.");
+            dispatch_suspend(self.writeSource);
+        }
+    }
+}
+
+- (void)askForIcon:(NSString*)path isDirectory:(BOOL)isDirectory;
+{
+    NSLog(@"Asking for icon.");
+    
+    NSString *verb;
+    if(isDirectory) {
+        verb = @"RETRIEVE_FOLDER_STATUS";
+    } else {
+        verb = @"RETRIEVE_FILE_STATUS";
+    }
+    
+    [self askOnSocket:path query:verb];
+}
+
+- (void)readFromSocket
+{
+    if(![self isConnected]) {
+        return;
+    }
+    
+    NSLog(@"Reading from socket.");
+    
+    int bufferLength = BUF_SIZE / 2;
+    char buffer[bufferLength];
+    
+    while(true) {
+        long bytesRead = read(self.sock, buffer, bufferLength);
+        
+        NSLog(@"Read %li bytes from socket.", bytesRead);
+        
+        if(bytesRead == 0) {
+            // 0 means we reached "end of file" and thus the socket was closed\10. So let's restart it
+            NSLog(@"Socket was closed. Restarting...");
+            [self restart];
+            return;
+        } else if(bytesRead == -1) {
+            int err = errno;
+            if(err == EAGAIN) {
+                NSLog(@"No error and no data. Stopping.");
+                return; // No error, no data, so let's stop
+            } else {
+                NSLog(@"Error reading from local socket: '%@'", [self strErr]);
+                [self closeConnection];
+                return;
+            }
+        } else {
+            [self.inBuffer appendBytes:buffer length:bytesRead];
+            [self processInBuffer];
+        }
+    }
+}
+
+- (void)processInBuffer
+{
+    NSLog(@"Processing in buffer. In buffer length %li", [self.inBuffer length]);
+    UInt8 separator[] = {0xa}; // Byte value for "\n"
+    while(true) {
+        NSRange firstSeparatorIndex = [self.inBuffer rangeOfData:[NSData dataWithBytes:separator length:1] options:0 range:NSMakeRange(0, [self.inBuffer length])];
+        
+        if(firstSeparatorIndex.location == NSNotFound) {
+            NSLog(@"No separator found. Stopping.");
+            return; // No separator, nope out
+        } else {
+            unsigned char *buffer = [self.inBuffer mutableBytes];
+            buffer[firstSeparatorIndex.location] = 0; // Add NULL terminator, so we can use C string methods
+            
+            NSString *newLine = [NSString stringWithUTF8String:[self.inBuffer bytes]];
+
+            [self.inBuffer replaceBytesInRange:NSMakeRange(0, firstSeparatorIndex.location + 1) withBytes:NULL length:0];
+            [self.lineProcessor process:newLine];
+        }
+    }
+}
+    
+@end
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/SyncClient.h b/shell_integration/MacOSX/OwnCloudFinderSync/FinderSyncExt/SyncClient.h
new file mode 100644 (file)
index 0000000..f8c495a
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) by Jocelyn Turcotte <jturcotte@woboq.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#import <Foundation/Foundation.h>
+
+@protocol SyncClientDelegate <NSObject>
+- (void)setResultForPath:(NSString *)path result:(NSString *)result;
+- (void)reFetchFileNameCacheForPath:(NSString *)path;
+- (void)registerPath:(NSString *)path;
+- (void)unregisterPath:(NSString *)path;
+- (void)setString:(NSString *)key value:(NSString *)value;
+- (void)resetMenuItems;
+- (void)addMenuItem:(NSDictionary *)item;
+- (void)menuHasCompleted;
+- (void)connectionDidDie;
+@end
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj/project.pbxproj b/shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..ad6d849
--- /dev/null
@@ -0,0 +1,600 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 46;
+       objects = {
+
+/* Begin PBXBuildFile section */
+               539158AC27BE71A900816F56 /* LineProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 539158AB27BE71A900816F56 /* LineProcessor.m */; };
+               539158B327BEC98A00816F56 /* LocalSocketClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 539158B227BEC98A00816F56 /* LocalSocketClient.m */; };
+               C2B573BA1B1CD91E00303B36 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C2B573B91B1CD91E00303B36 /* main.m */; };
+               C2B573D21B1CD94B00303B36 /* main.m in Resources */ = {isa = PBXBuildFile; fileRef = C2B573B91B1CD91E00303B36 /* main.m */; };
+               C2B573DE1B1CD9CE00303B36 /* FinderSync.m in Sources */ = {isa = PBXBuildFile; fileRef = C2B573DD1B1CD9CE00303B36 /* FinderSync.m */; };
+               C2B573E21B1CD9CE00303B36 /* FinderSyncExt.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = C2B573D71B1CD9CE00303B36 /* FinderSyncExt.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+               C2B573F31B1DAD6400303B36 /* error.iconset in Resources */ = {isa = PBXBuildFile; fileRef = C2B573EB1B1DAD6400303B36 /* error.iconset */; };
+               C2B573F41B1DAD6400303B36 /* ok_swm.iconset in Resources */ = {isa = PBXBuildFile; fileRef = C2B573EC1B1DAD6400303B36 /* ok_swm.iconset */; };
+               C2B573F51B1DAD6400303B36 /* ok.iconset in Resources */ = {isa = PBXBuildFile; fileRef = C2B573ED1B1DAD6400303B36 /* ok.iconset */; };
+               C2B573F71B1DAD6400303B36 /* sync.iconset in Resources */ = {isa = PBXBuildFile; fileRef = C2B573EF1B1DAD6400303B36 /* sync.iconset */; };
+               C2B573F91B1DAD6400303B36 /* warning.iconset in Resources */ = {isa = PBXBuildFile; fileRef = C2B573F11B1DAD6400303B36 /* warning.iconset */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+               C2B573DF1B1CD9CE00303B36 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = C2B573951B1CD88000303B36 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = C2B573D61B1CD9CE00303B36;
+                       remoteInfo = FinderSyncExt;
+               };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+               C2B573E11B1CD9CE00303B36 /* Embed App Extensions */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = "";
+                       dstSubfolderSpec = 13;
+                       files = (
+                               C2B573E21B1CD9CE00303B36 /* FinderSyncExt.appex in Embed App Extensions */,
+                       );
+                       name = "Embed App Extensions";
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+               539158A927BE606500816F56 /* LineProcessor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LineProcessor.h; sourceTree = "<group>"; };
+               539158AA27BE67CC00816F56 /* SyncClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SyncClient.h; sourceTree = "<group>"; };
+               539158AB27BE71A900816F56 /* LineProcessor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LineProcessor.m; sourceTree = "<group>"; };
+               539158B127BE891500816F56 /* LocalSocketClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalSocketClient.h; sourceTree = "<group>"; };
+               539158B227BEC98A00816F56 /* LocalSocketClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocalSocketClient.m; sourceTree = "<group>"; };
+               C2B573B11B1CD91E00303B36 /* desktopclient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = desktopclient.app; sourceTree = BUILT_PRODUCTS_DIR; };
+               C2B573B51B1CD91E00303B36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+               C2B573B91B1CD91E00303B36 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+               C2B573D71B1CD9CE00303B36 /* FinderSyncExt.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = FinderSyncExt.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+               C2B573DA1B1CD9CE00303B36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+               C2B573DB1B1CD9CE00303B36 /* FinderSyncExt.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = FinderSyncExt.entitlements; sourceTree = "<group>"; };
+               C2B573DC1B1CD9CE00303B36 /* FinderSync.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinderSync.h; sourceTree = "<group>"; };
+               C2B573DD1B1CD9CE00303B36 /* FinderSync.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FinderSync.m; sourceTree = "<group>"; };
+               C2B573EB1B1DAD6400303B36 /* error.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = error.iconset; path = ../../icons/nopadding/error.iconset; sourceTree = SOURCE_ROOT; };
+               C2B573EC1B1DAD6400303B36 /* ok_swm.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = ok_swm.iconset; path = ../../icons/nopadding/ok_swm.iconset; sourceTree = SOURCE_ROOT; };
+               C2B573ED1B1DAD6400303B36 /* ok.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = ok.iconset; path = ../../icons/nopadding/ok.iconset; sourceTree = SOURCE_ROOT; };
+               C2B573EF1B1DAD6400303B36 /* sync.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = sync.iconset; path = ../../icons/nopadding/sync.iconset; sourceTree = SOURCE_ROOT; };
+               C2B573F11B1DAD6400303B36 /* warning.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = warning.iconset; path = ../../icons/nopadding/warning.iconset; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               C2B573AE1B1CD91E00303B36 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               C2B573D41B1CD9CE00303B36 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               C2B573941B1CD88000303B36 = {
+                       isa = PBXGroup;
+                       children = (
+                               C2B573B31B1CD91E00303B36 /* desktopclient */,
+                               C2B573D81B1CD9CE00303B36 /* FinderSyncExt */,
+                               C2B573B21B1CD91E00303B36 /* Products */,
+                       );
+                       sourceTree = "<group>";
+               };
+               C2B573B21B1CD91E00303B36 /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               C2B573B11B1CD91E00303B36 /* desktopclient.app */,
+                               C2B573D71B1CD9CE00303B36 /* FinderSyncExt.appex */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               C2B573B31B1CD91E00303B36 /* desktopclient */ = {
+                       isa = PBXGroup;
+                       children = (
+                               C2B573B41B1CD91E00303B36 /* Supporting Files */,
+                       );
+                       path = desktopclient;
+                       sourceTree = "<group>";
+               };
+               C2B573B41B1CD91E00303B36 /* Supporting Files */ = {
+                       isa = PBXGroup;
+                       children = (
+                               C2B573B51B1CD91E00303B36 /* Info.plist */,
+                               C2B573B91B1CD91E00303B36 /* main.m */,
+                       );
+                       name = "Supporting Files";
+                       sourceTree = "<group>";
+               };
+               C2B573D81B1CD9CE00303B36 /* FinderSyncExt */ = {
+                       isa = PBXGroup;
+                       children = (
+                               539158AA27BE67CC00816F56 /* SyncClient.h */,
+                               C2B573DC1B1CD9CE00303B36 /* FinderSync.h */,
+                               C2B573DD1B1CD9CE00303B36 /* FinderSync.m */,
+                               539158A927BE606500816F56 /* LineProcessor.h */,
+                               539158AB27BE71A900816F56 /* LineProcessor.m */,
+                               539158B127BE891500816F56 /* LocalSocketClient.h */,
+                               539158B227BEC98A00816F56 /* LocalSocketClient.m */,
+                               C2B573D91B1CD9CE00303B36 /* Supporting Files */,
+                       );
+                       path = FinderSyncExt;
+                       sourceTree = "<group>";
+               };
+               C2B573D91B1CD9CE00303B36 /* Supporting Files */ = {
+                       isa = PBXGroup;
+                       children = (
+                               C2B573EB1B1DAD6400303B36 /* error.iconset */,
+                               C2B573EC1B1DAD6400303B36 /* ok_swm.iconset */,
+                               C2B573ED1B1DAD6400303B36 /* ok.iconset */,
+                               C2B573EF1B1DAD6400303B36 /* sync.iconset */,
+                               C2B573F11B1DAD6400303B36 /* warning.iconset */,
+                               C2B573DA1B1CD9CE00303B36 /* Info.plist */,
+                               C2B573DB1B1CD9CE00303B36 /* FinderSyncExt.entitlements */,
+                       );
+                       name = "Supporting Files";
+                       sourceTree = "<group>";
+               };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+               C2B573B01B1CD91E00303B36 /* desktopclient */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = C2B573CC1B1CD91E00303B36 /* Build configuration list for PBXNativeTarget "desktopclient" */;
+                       buildPhases = (
+                               C2B573AD1B1CD91E00303B36 /* Sources */,
+                               C2B573AE1B1CD91E00303B36 /* Frameworks */,
+                               C2B573AF1B1CD91E00303B36 /* Resources */,
+                               C2B573E11B1CD9CE00303B36 /* Embed App Extensions */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               C2B573E01B1CD9CE00303B36 /* PBXTargetDependency */,
+                       );
+                       name = desktopclient;
+                       productName = desktopclient;
+                       productReference = C2B573B11B1CD91E00303B36 /* desktopclient.app */;
+                       productType = "com.apple.product-type.application";
+               };
+               C2B573D61B1CD9CE00303B36 /* FinderSyncExt */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = C2B573E31B1CD9CE00303B36 /* Build configuration list for PBXNativeTarget "FinderSyncExt" */;
+                       buildPhases = (
+                               C2B573D31B1CD9CE00303B36 /* Sources */,
+                               C2B573D41B1CD9CE00303B36 /* Frameworks */,
+                               C2B573D51B1CD9CE00303B36 /* Resources */,
+                               5B3335471CA058E200E11A45 /* ShellScript */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = FinderSyncExt;
+                       productName = FinderSyncExt;
+                       productReference = C2B573D71B1CD9CE00303B36 /* FinderSyncExt.appex */;
+                       productType = "com.apple.product-type.app-extension";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               C2B573951B1CD88000303B36 /* Project object */ = {
+                       isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 1240;
+                               TargetAttributes = {
+                                       C2B573B01B1CD91E00303B36 = {
+                                               CreatedOnToolsVersion = 6.3.1;
+                                               DevelopmentTeam = 9B5WD74GWJ;
+                                               ProvisioningStyle = Manual;
+                                       };
+                                       C2B573D61B1CD9CE00303B36 = {
+                                               CreatedOnToolsVersion = 6.3.1;
+                                               DevelopmentTeam = 9B5WD74GWJ;
+                                               ProvisioningStyle = Manual;
+                                               SystemCapabilities = {
+                                                       com.apple.ApplicationGroups.Mac = {
+                                                               enabled = 1;
+                                                       };
+                                               };
+                                       };
+                               };
+                       };
+                       buildConfigurationList = C2B573981B1CD88000303B36 /* Build configuration list for PBXProject "OwnCloudFinderSync" */;
+                       compatibilityVersion = "Xcode 3.2";
+                       developmentRegion = English;
+                       hasScannedForEncodings = 0;
+                       knownRegions = (
+                               English,
+                               en,
+                               Base,
+                       );
+                       mainGroup = C2B573941B1CD88000303B36;
+                       productRefGroup = C2B573B21B1CD91E00303B36 /* Products */;
+                       projectDirPath = "";
+                       projectRoot = "";
+                       targets = (
+                               C2B573B01B1CD91E00303B36 /* desktopclient */,
+                               C2B573D61B1CD9CE00303B36 /* FinderSyncExt */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+               C2B573AF1B1CD91E00303B36 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               C2B573D21B1CD94B00303B36 /* main.m in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               C2B573D51B1CD9CE00303B36 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               C2B573F91B1DAD6400303B36 /* warning.iconset in Resources */,
+                               C2B573F31B1DAD6400303B36 /* error.iconset in Resources */,
+                               C2B573F71B1DAD6400303B36 /* sync.iconset in Resources */,
+                               C2B573F41B1DAD6400303B36 /* ok_swm.iconset in Resources */,
+                               C2B573F51B1DAD6400303B36 /* ok.iconset in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+               5B3335471CA058E200E11A45 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "if [[ ${OC_OEM_SHARE_ICNS} ]]; then\n  cp ${OC_OEM_SHARE_ICNS} ${BUILT_PRODUCTS_DIR}/FinderSyncExt.appex/Contents/Resources/app.icns\nfi";
+                       showEnvVarsInLog = 0;
+               };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               C2B573AD1B1CD91E00303B36 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               C2B573BA1B1CD91E00303B36 /* main.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               C2B573D31B1CD9CE00303B36 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               539158B327BEC98A00816F56 /* LocalSocketClient.m in Sources */,
+                               539158AC27BE71A900816F56 /* LineProcessor.m in Sources */,
+                               C2B573DE1B1CD9CE00303B36 /* FinderSync.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+               C2B573E01B1CD9CE00303B36 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = C2B573D61B1CD9CE00303B36 /* FinderSyncExt */;
+                       targetProxy = C2B573DF1B1CD9CE00303B36 /* PBXContainerItemProxy */;
+               };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+               C2B573991B1CD88000303B36 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+                               CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_STRICT_PROTOTYPES = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               ENABLE_TESTABILITY = YES;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                       };
+                       name = Debug;
+               };
+               C2B5739A1B1CD88000303B36 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+                               CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_STRICT_PROTOTYPES = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                       };
+                       name = Release;
+               };
+               C2B573CD1B1CD91E00303B36 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_IDENTITY = "-";
+                               CODE_SIGN_STYLE = Manual;
+                               COMBINE_HIDPI_IMAGES = YES;
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INFOPLIST_FILE = desktopclient/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               PROVISIONING_PROFILE = "";
+                               SDKROOT = macosx;
+                       };
+                       name = Debug;
+               };
+               C2B573CE1B1CD91E00303B36 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_IDENTITY = "-";
+                               CODE_SIGN_STYLE = Manual;
+                               COMBINE_HIDPI_IMAGES = YES;
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               ENABLE_NS_ASSERTIONS = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INFOPLIST_FILE = desktopclient/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               PROVISIONING_PROFILE = "";
+                               SDKROOT = macosx;
+                       };
+                       name = Release;
+               };
+               C2B573E41B1CD9CE00303B36 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_ENTITLEMENTS = FinderSyncExt/FinderSyncExt.entitlements;
+                               CODE_SIGN_IDENTITY = "-";
+                               CODE_SIGN_STYLE = Manual;
+                               COMBINE_HIDPI_IMAGES = YES;
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INFOPLIST_FILE = FinderSyncExt/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks";
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               OC_APPLICATION_NAME = ownCloud;
+                               OC_APPLICATION_REV_DOMAIN = com.owncloud.desktopclient;
+                               OC_OEM_SHARE_ICNS = "";
+                               OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX = "";
+                               ONLY_ACTIVE_ARCH = YES;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               PROVISIONING_PROFILE = "";
+                               SDKROOT = macosx;
+                               SKIP_INSTALL = YES;
+                       };
+                       name = Debug;
+               };
+               C2B573E51B1CD9CE00303B36 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_ENTITLEMENTS = FinderSyncExt/FinderSyncExt.entitlements;
+                               CODE_SIGN_IDENTITY = "-";
+                               CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
+                               CODE_SIGN_STYLE = Manual;
+                               COMBINE_HIDPI_IMAGES = YES;
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               ENABLE_NS_ASSERTIONS = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INFOPLIST_FILE = FinderSyncExt/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks";
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               OC_APPLICATION_NAME = ownCloud;
+                               OC_APPLICATION_REV_DOMAIN = com.owncloud.desktopclient;
+                               OC_OEM_SHARE_ICNS = "";
+                               OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX = "";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               PROVISIONING_PROFILE = "";
+                               SDKROOT = macosx;
+                               SKIP_INSTALL = YES;
+                       };
+                       name = Release;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               C2B573981B1CD88000303B36 /* Build configuration list for PBXProject "OwnCloudFinderSync" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               C2B573991B1CD88000303B36 /* Debug */,
+                               C2B5739A1B1CD88000303B36 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               C2B573CC1B1CD91E00303B36 /* Build configuration list for PBXNativeTarget "desktopclient" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               C2B573CD1B1CD91E00303B36 /* Debug */,
+                               C2B573CE1B1CD91E00303B36 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               C2B573E31B1CD9CE00303B36 /* Build configuration list for PBXNativeTarget "FinderSyncExt" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               C2B573E41B1CD9CE00303B36 /* Debug */,
+                               C2B573E51B1CD9CE00303B36 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = C2B573951B1CD88000303B36 /* Project object */;
+}
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj/xcshareddata/xcschemes/FinderSyncExt.xcscheme b/shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj/xcshareddata/xcschemes/FinderSyncExt.xcscheme
new file mode 100644 (file)
index 0000000..63ec0b6
--- /dev/null
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1240"
+   wasCreatedForAppExtension = "YES"
+   version = "2.0">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "C2B573D61B1CD9CE00303B36"
+               BuildableName = "FinderSyncExt.appex"
+               BlueprintName = "FinderSyncExt"
+               ReferencedContainer = "container:OwnCloudFinderSync.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "C2B573B01B1CD91E00303B36"
+               BuildableName = "desktopclient.app"
+               BlueprintName = "desktopclient"
+               ReferencedContainer = "container:OwnCloudFinderSync.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "C2B573D61B1CD9CE00303B36"
+            BuildableName = "FinderSyncExt.appex"
+            BlueprintName = "FinderSyncExt"
+            ReferencedContainer = "container:OwnCloudFinderSync.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <Testables>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = ""
+      selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
+      launchStyle = "0"
+      askForAppToLaunch = "Yes"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES"
+      launchAutomaticallySubstyle = "2">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "C2B573B01B1CD91E00303B36"
+            BuildableName = "desktopclient.app"
+            BlueprintName = "desktopclient"
+            ReferencedContainer = "container:OwnCloudFinderSync.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES"
+      askForAppToLaunch = "Yes"
+      launchAutomaticallySubstyle = "2">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "C2B573B01B1CD91E00303B36"
+            BuildableName = "desktopclient.app"
+            BlueprintName = "desktopclient"
+            ReferencedContainer = "container:OwnCloudFinderSync.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/desktopclient/Info.plist b/shell_integration/MacOSX/OwnCloudFinderSync/desktopclient/Info.plist
new file mode 100644 (file)
index 0000000..bbaa296
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.owncloud.$(PRODUCT_NAME:rfc1034identifier)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/shell_integration/MacOSX/OwnCloudFinderSync/desktopclient/main.m b/shell_integration/MacOSX/OwnCloudFinderSync/desktopclient/main.m
new file mode 100644 (file)
index 0000000..6f580d2
--- /dev/null
@@ -0,0 +1,16 @@
+//
+//  main.m
+//  desktopclient
+//
+//  Created by Jocelyn Turcotte on 01/06/15.
+//
+//
+
+// This is fake application bundle with the same bundle ID as the real desktop client.
+// Xcode needs a wrapping application to allow the extension to be debugged.
+
+#import <Cocoa/Cocoa.h>
+
+int main(int argc, const char * argv[]) {
+    return NSApplicationMain(argc, argv);
+}
index e4af0e33a6fefd9b48412bf1bb9a4d5f2f57761a..42745aa9a0f709980c62895ed60b101a44981775 100644 (file)
@@ -285,19 +285,6 @@ IF( APPLE )
     list(APPEND client_SRCS cocoainitializer_mac.mm)
     list(APPEND client_SRCS systray.mm)
 
-    if (BUILD_FILE_PROVIDER_MODULE)
-        list(APPEND client_SRCS
-            macOS/fileprovider.h
-            macOS/fileprovider_mac.mm
-            macOS/fileproviderdomainmanager.h
-            macOS/fileproviderdomainmanager_mac.mm
-            macOS/fileprovidersocketcontroller.h
-            macOS/fileprovidersocketcontroller.cpp
-            macOS/fileprovidersocketserver.h
-            macOS/fileprovidersocketserver.cpp
-            macOS/fileprovidersocketserver_mac.mm)
-    endif()
-
     if(SPARKLE_FOUND AND BUILD_UPDATER)
         # Define this, we need to check in updater.cpp
         add_definitions(-DHAVE_SPARKLE)
@@ -670,12 +657,7 @@ endif()
 
 if (APPLE)
     find_package(Qt5 COMPONENTS MacExtras)
-
-    if (BUILD_FILE_PROVIDER_MODULE)
-        target_link_libraries(nextcloudCore PUBLIC Qt5::MacExtras "-framework UserNotifications -framework FileProvider")
-    else()
-        target_link_libraries(nextcloudCore PUBLIC Qt5::MacExtras "-framework UserNotifications")
-    endif()
+    target_link_libraries(nextcloudCore PUBLIC Qt5::MacExtras "-framework UserNotifications")
 endif()
 
 if(WITH_CRASHREPORTER)
index 0db5f96d16d3be0ed2b0ee321ab450157f3ee1fc..304df1d8353271fb58a30fbc73692b13cbb67872 100644 (file)
@@ -51,8 +51,6 @@
 
 #if defined(Q_OS_WIN)
 #include <windows.h>
-#elif defined(Q_OS_MACOS)
-#include "macOS/fileprovider.h"
 #endif
 
 #if defined(WITH_CRASHREPORTER)
@@ -374,7 +372,7 @@ Application::Application(int &argc, char **argv)
     }
 
     _folderManager.reset(new FolderMan);
-#if defined(Q_OS_WIN)
+#ifdef Q_OS_WIN
     _shellExtensionsServer.reset(new ShellExtensionsServer);
 #endif
 
@@ -403,10 +401,6 @@ Application::Application(int &argc, char **argv)
         }
     }
 
-#if defined(Q_OS_MACOS)
-    _fileProvider.reset(new Mac::FileProvider);
-#endif
-
     FolderMan::instance()->setSyncEnabled(true);
 
     setQuitOnLastWindowClosed(false);
index bb9f97bef0b57a6a8d9ab6436c54fce0d8ea97c7..5a21cc8745db40a315a04dc20b00644c8f5c5b16 100644 (file)
@@ -49,12 +49,6 @@ class Folder;
 class ShellExtensionsServer;
 class SslErrorDialog;
 
-#ifdef Q_OS_MACOS
-namespace Mac {
-class FileProvider;
-}
-#endif
-
 /**
  * @brief The Application class
  * @ingroup gui
@@ -158,10 +152,8 @@ private:
     QScopedPointer<CrashReporter::Handler> _crashHandler;
 #endif
     QScopedPointer<FolderMan> _folderManager;
-#if defined(Q_OS_WIN)
+#ifdef Q_OS_WIN
     QScopedPointer<ShellExtensionsServer> _shellExtensionsServer;
-#elif defined(Q_OS_MACOS)
-    QScopedPointer<Mac::FileProvider> _fileProvider;
 #endif
 };
 
diff --git a/src/gui/macOS/fileprovider.h b/src/gui/macOS/fileprovider.h
deleted file mode 100644 (file)
index d45ba98..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#pragma once
-
-#include <QObject>
-
-#include "fileproviderdomainmanager.h"
-#include "fileprovidersocketserver.h"
-
-namespace OCC {
-
-class Application;
-
-namespace Mac {
-
-// NOTE: For the file provider extension to work, the app bundle will
-// need to be correctly codesigned!
-
-class FileProvider : public QObject
-{
-    Q_OBJECT
-
-public:
-    static FileProvider *instance();
-    ~FileProvider() override;
-
-    static bool fileProviderAvailable();
-
-private:
-    std::unique_ptr<FileProviderDomainManager> _domainManager;
-    std::unique_ptr<FileProviderSocketServer> _socketServer;
-
-    static FileProvider *_instance;
-    explicit FileProvider(QObject * const parent = nullptr);
-
-    friend class OCC::Application;
-};
-
-} // namespace Mac
-} // namespace OCC
diff --git a/src/gui/macOS/fileprovider_mac.mm b/src/gui/macOS/fileprovider_mac.mm
deleted file mode 100644 (file)
index 56db4d2..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#import <Foundation/Foundation.h>
-
-#include <QLoggingCategory>
-
-#include "configfile.h"
-
-#include "fileprovider.h"
-
-namespace OCC {
-
-Q_LOGGING_CATEGORY(lcMacFileProvider, "nextcloud.gui.macfileprovider", QtInfoMsg)
-
-namespace Mac {
-
-FileProvider* FileProvider::_instance = nullptr;
-
-FileProvider::FileProvider(QObject * const parent)
-    : QObject(parent)
-{
-    Q_ASSERT(!_instance);
-
-    if (!fileProviderAvailable()) {
-        qCInfo(lcMacFileProvider) << "File provider system is not available on this version of macOS.";
-        deleteLater();
-        return;
-    } else if (!ConfigFile().macFileProviderModuleEnabled()) {
-        qCInfo(lcMacFileProvider) << "File provider module is not enabled in application config.";
-        deleteLater();
-        return;
-    }
-
-    qCInfo(lcMacFileProvider) << "Initialising file provider domain manager.";
-    _domainManager = std::make_unique<FileProviderDomainManager>(new FileProviderDomainManager(this));
-
-    if (_domainManager) {
-        qCDebug(lcMacFileProvider()) << "Initialized file provider domain manager";
-    }
-
-    qCDebug(lcMacFileProvider) << "Initialising file provider socket server.";
-    _socketServer = std::make_unique<FileProviderSocketServer>(new FileProviderSocketServer(this));
-
-    if (_socketServer) {
-        qCDebug(lcMacFileProvider) << "Initialised file provider socket server.";
-    }
-}
-
-FileProvider *FileProvider::instance()
-{
-    if (!fileProviderAvailable()) {
-        qCInfo(lcMacFileProvider) << "File provider system is not available on this version of macOS.";
-        return nullptr;
-    } else if (!ConfigFile().macFileProviderModuleEnabled()) {
-        qCInfo(lcMacFileProvider) << "File provider module is not enabled in application config.";
-        return nullptr;
-    }
-
-    if (!_instance) {
-        _instance = new FileProvider();
-    }
-    return _instance;
-}
-
-FileProvider::~FileProvider()
-{
-    _instance = nullptr;
-}
-
-bool FileProvider::fileProviderAvailable()
-{
-    if (@available(macOS 11.0, *)) {
-        return true;
-    }
-
-    return false;
-}
-
-} // namespace Mac
-} // namespace OCC
diff --git a/src/gui/macOS/fileproviderdomainmanager.h b/src/gui/macOS/fileproviderdomainmanager.h
deleted file mode 100644 (file)
index 3aa80d3..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#pragma once
-
-#include <QObject>
-
-#include "accountstate.h"
-
-namespace OCC {
-
-class Account;
-
-namespace Mac {
-
-class FileProviderDomainManager : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit FileProviderDomainManager(QObject * const parent = nullptr);
-    ~FileProviderDomainManager() override;
-
-    static AccountStatePtr accountStateFromFileProviderDomainIdentifier(const QString &domainIdentifier);
-
-private slots:
-    void setupFileProviderDomains();
-
-    void addFileProviderDomainForAccount(const OCC::AccountState * const accountState);
-    void removeFileProviderDomainForAccount(const OCC::AccountState * const accountState);
-    void disconnectFileProviderDomainForAccount(const OCC::AccountState * const accountState, const QString &reason);
-    void reconnectFileProviderDomainForAccount(const OCC::AccountState * const accountState);
-
-    void trySetupPushNotificationsForAccount(const OCC::Account * const account);
-    void setupPushNotificationsForAccount(const OCC::Account * const account);
-    void signalEnumeratorChanged(const OCC::Account * const account);
-
-    void slotAccountStateChanged(const OCC::AccountState * const accountState);
-    void slotEnumeratorSignallingTimerTimeout();
-
-private:
-    // Starts regular enumerator signalling if no push notifications available
-    QTimer _enumeratorSignallingTimer;
-
-    class MacImplementation;
-    std::unique_ptr<MacImplementation> d;
-};
-
-} // namespace Mac
-
-} // namespace OCC
diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm
deleted file mode 100644 (file)
index 29b3ee2..0000000
+++ /dev/null
@@ -1,636 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "configfile.h"
-#import <FileProvider/FileProvider.h>
-
-#include <QLoggingCategory>
-
-#include "config.h"
-#include "fileproviderdomainmanager.h"
-#include "pushnotifications.h"
-
-#include "gui/accountmanager.h"
-#include "libsync/account.h"
-
-// Ensure that conversion to/from domain identifiers and display names
-// are consistent throughout these classes
-namespace {
-
-QString domainIdentifierForAccount(const OCC::Account * const account)
-{
-    Q_ASSERT(account);
-    return account->userIdAtHostWithPort();
-}
-
-QString domainIdentifierForAccount(const OCC::AccountPtr account)
-{
-    return domainIdentifierForAccount(account.get());
-}
-
-QString domainDisplayNameForAccount(const OCC::Account * const account)
-{
-    Q_ASSERT(account);
-    return account->displayName();
-}
-
-QString domainDisplayNameForAccount(const OCC::AccountPtr account)
-{
-    return domainDisplayNameForAccount(account.get());
-}
-
-QString accountIdFromDomainId(const QString &domainId)
-{
-    return domainId;
-}
-
-QString accountIdFromDomainId(NSString * const domainId)
-{
-    return accountIdFromDomainId(QString::fromNSString(domainId));
-}
-
-API_AVAILABLE(macos(11.0))
-QString accountIdFromDomain(NSFileProviderDomain * const domain)
-{
-    return accountIdFromDomainId(domain.identifier);
-}
-
-bool accountFilesPushNotificationsReady(const OCC::AccountPtr &account)
-{
-    const auto pushNotifications = account->pushNotifications();
-    const auto pushNotificationsCapability = account->capabilities().availablePushNotifications() & OCC::PushNotificationType::Files;
-
-    return pushNotificationsCapability && pushNotifications && pushNotifications->isReady();
-}
-
-}
-
-namespace OCC {
-
-Q_LOGGING_CATEGORY(lcMacFileProviderDomainManager, "nextcloud.gui.macfileproviderdomainmanager", QtInfoMsg)
-
-namespace Mac {
-
-class API_AVAILABLE(macos(11.0)) FileProviderDomainManager::MacImplementation {
-
-  public:
-    MacImplementation() = default;
-    ~MacImplementation() = default;
-
-    void findExistingFileProviderDomains()
-    {
-        if (@available(macOS 11.0, *)) {
-            // Wait for this to finish
-            dispatch_group_t dispatchGroup = dispatch_group_create();
-            dispatch_group_enter(dispatchGroup);
-
-            [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray<NSFileProviderDomain *> * const domains, NSError * const error) {
-                if(error) {
-                    qCDebug(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";
-                    dispatch_group_leave(dispatchGroup);
-                    return;
-                }
-
-                for (NSFileProviderDomain * const domain in domains) {
-                    const auto accountId = accountIdFromDomain(domain);
-
-                    if (const auto accountState = AccountManager::instance()->accountFromUserId(accountId);
-                            accountState &&
-                            accountState->account() &&
-                            domainDisplayNameForAccount(accountState->account()) == QString::fromNSString(domain.displayName)) {
-
-                        qCDebug(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;
-                                return;
-                            }
-
-                            qCDebug(lcMacFileProviderDomainManager) << "Successfully reconnected file provider domain: "
-                                                                    << domain.displayName;
-                        }];
-
-                    } else {
-                        qCDebug(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;
-                            }
-                        }];
-                    }
-                }
-
-                dispatch_group_leave(dispatchGroup);
-            }];
-
-            dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER);
-        }
-    }
-
-    void addFileProviderDomain(const AccountState * const accountState)
-    {
-        if (@available(macOS 11.0, *)) {
-            Q_ASSERT(accountState);
-            const auto account = accountState->account();
-            Q_ASSERT(account);
-
-            const auto domainDisplayName = domainDisplayNameForAccount(account);
-            const auto domainId = domainIdentifierForAccount(account);
-
-            qCDebug(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;
-                return;
-            }
-
-            NSFileProviderDomain * const fileProviderDomain = [[NSFileProviderDomain alloc] initWithIdentifier:domainId.toNSString()
-                                                                                                   displayName:domainDisplayName.toNSString()];
-            [fileProviderDomain retain];
-
-            [NSFileProviderManager addDomain:fileProviderDomain completionHandler:^(NSError * const error) {
-                if(error) {
-                    qCDebug(lcMacFileProviderDomainManager) << "Error adding file provider domain: "
-                                                            << error.code
-                                                            << error.localizedDescription;
-                }
-
-                _registeredDomains.insert(domainId, fileProviderDomain);
-            }];
-        }
-    }
-
-    void removeFileProviderDomain(const AccountState * const accountState)
-    {
-        if (@available(macOS 11.0, *)) {
-            Q_ASSERT(accountState);
-            const auto account = accountState->account();
-            Q_ASSERT(account);
-
-            const auto domainId = domainIdentifierForAccount(account);
-            qCDebug(lcMacFileProviderDomainManager) << "Removing file provider domain with id: " << domainId;
-
-            if(!_registeredDomains.contains(domainId)) {
-                qCDebug(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;
-                }
-
-                NSFileProviderDomain * const domain = _registeredDomains.take(domainId);
-                [domain release];
-            }];
-        }
-    }
-
-    void removeAllFileProviderDomains()
-    {
-        if (@available(macOS 11.0, *)) {
-            qCDebug(lcMacFileProviderDomainManager) << "Removing all file provider domains.";
-
-            [NSFileProviderManager removeAllDomainsWithCompletionHandler:^(NSError * const error) {
-                if(error) {
-                    qCDebug(lcMacFileProviderDomainManager) << "Error removing all file provider domains: "
-                                                            << error.code
-                                                            << error.localizedDescription;
-                    return;
-                }
-
-                const auto registeredDomainPtrs = _registeredDomains.values();
-                for (NSFileProviderDomain * const domain : registeredDomainPtrs) {
-                    if (domain != nil) {
-                        [domain release];
-                    }
-                }
-                _registeredDomains.clear();
-            }];
-        }
-    }
-
-    void wipeAllFileProviderDomains()
-    {
-        if (@available(macOS 12.0, *)) {
-            qCDebug(lcMacFileProviderDomainManager) << "Removing and wiping all file provider domains";
-
-            [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray<NSFileProviderDomain *> * const domains, NSError * const error) {
-                if (error) {
-                    qCDebug(lcMacFileProviderDomainManager) << "Error removing and wiping file provider domains: "
-                                                            << error.code
-                                                            << error.localizedDescription;
-                    return;
-                }
-
-                for (NSFileProviderDomain * const domain in domains) {
-                    [NSFileProviderManager removeDomain:domain mode:NSFileProviderDomainRemovalModeRemoveAll completionHandler:^(NSURL * const preservedLocation, NSError * const error) {
-                        Q_UNUSED(preservedLocation)
-
-                        if (error) {
-                            qCDebug(lcMacFileProviderDomainManager) << "Error removing and wiping file provider domain: "
-                                                                    << domain.displayName
-                                                                    << error.code
-                                                                    << error.localizedDescription;
-                            return;
-                        }
-
-                        NSFileProviderDomain * const registeredDomainPtr = _registeredDomains.take(QString::fromNSString(domain.identifier));
-                        if (registeredDomainPtr != nil) {
-                            [domain release];
-                        }
-                    }];
-                }
-            }];
-        } else if (@available(macOS 11.0, *)) {
-            qCDebug(lcMacFileProviderDomainManager) << "Removing all file provider domains, can't specify wipe on macOS 11";
-            removeAllFileProviderDomains();
-        }
-    }
-
-    void disconnectFileProviderDomainForAccount(const AccountState * const accountState, const QString &message)
-    {
-        if (@available(macOS 11.0, *)) {
-            Q_ASSERT(accountState);
-            const auto account = accountState->account();
-            Q_ASSERT(account);
-
-            const auto domainId = domainIdentifierForAccount(account);
-            qCDebug(lcMacFileProviderDomainManager) << "Disconnecting file provider domain with id: " << domainId;
-
-            if(!_registeredDomains.contains(domainId)) {
-                qCDebug(lcMacFileProviderDomainManager) << "File provider domain not found for id: " << domainId;
-                return;
-            }
-
-            NSFileProviderDomain * const fileProviderDomain = _registeredDomains[domainId];
-            Q_ASSERT(fileProviderDomain != nil);
-
-            NSFileProviderManager * const fpManager = [NSFileProviderManager managerForDomain:fileProviderDomain];
-            [fpManager disconnectWithReason:message.toNSString()
-                                    options:NSFileProviderManagerDisconnectionOptionsTemporary
-                          completionHandler:^(NSError * const error) {
-                if (error) {
-                    qCDebug(lcMacFileProviderDomainManager) << "Error disconnecting file provider domain: "
-                                                            << fileProviderDomain.displayName
-                                                            << error.code
-                                                            << error.localizedDescription;
-                    return;
-                }
-
-                qCDebug(lcMacFileProviderDomainManager) << "Successfully disconnected file provider domain: "
-                                                        << fileProviderDomain.displayName;
-            }];
-        }
-    }
-
-    void reconnectFileProviderDomainForAccount(const AccountState * const accountState)
-    {
-        if (@available(macOS 11.0, *)) {
-            Q_ASSERT(accountState);
-            const auto account = accountState->account();
-            Q_ASSERT(account);
-
-            const auto domainId = domainIdentifierForAccount(account);
-            qCDebug(lcMacFileProviderDomainManager) << "Reconnecting file provider domain with id: " << domainId;
-
-            if(!_registeredDomains.contains(domainId)) {
-                qCDebug(lcMacFileProviderDomainManager) << "File provider domain not found for id: " << domainId;
-                return;
-            }
-
-            NSFileProviderDomain * const fileProviderDomain = _registeredDomains[domainId];
-            Q_ASSERT(fileProviderDomain != nil);
-
-            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;
-                    return;
-                }
-
-                qCDebug(lcMacFileProviderDomainManager) << "Successfully reconnected file provider domain: "
-                                                        << fileProviderDomain.displayName;
-
-                signalEnumeratorChanged(account.get());
-            }];
-        }
-    }
-
-    void signalEnumeratorChanged(const Account * const account)
-    {
-        if (@available(macOS 11.0, *)) {
-            Q_ASSERT(account);
-            const auto domainId = domainIdentifierForAccount(account);
-
-            qCDebug(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;
-                return;
-            }
-
-            NSFileProviderDomain * const fileProviderDomain = _registeredDomains[domainId];
-            Q_ASSERT(fileProviderDomain != nil);
-
-            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;
-                }
-            }];
-        }
-    }
-
-    QStringList configuredDomainIds() const {
-        return _registeredDomains.keys();
-    }
-
-private:
-    QHash<QString, NSFileProviderDomain*> _registeredDomains;
-};
-
-FileProviderDomainManager::FileProviderDomainManager(QObject * const parent)
-    : QObject(parent)
-{
-    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.";
-    }
-}
-
-FileProviderDomainManager::~FileProviderDomainManager() = default;
-
-void FileProviderDomainManager::setupFileProviderDomains()
-{
-    if (!d) {
-        return;
-    }
-
-    d->findExistingFileProviderDomains();
-
-    for(auto &accountState : AccountManager::instance()->accounts()) {
-        addFileProviderDomainForAccount(accountState.data());
-    }
-}
-
-void FileProviderDomainManager::addFileProviderDomainForAccount(const AccountState * const accountState)
-{
-    if (!d) {
-        return;
-    }
-
-    Q_ASSERT(accountState);
-    const auto account = accountState->account();
-    Q_ASSERT(account);
-
-    d->addFileProviderDomain(accountState);
-
-    // Disconnect the domain when something changes regarding authentication
-    connect(accountState, &AccountState::stateChanged, this, [this, accountState] {
-        slotAccountStateChanged(accountState);
-    });
-
-    // Setup push notifications
-    const auto accountCapabilities = account->capabilities().isValid();
-    if (!accountCapabilities) {
-        connect(account.get(), &Account::capabilitiesChanged, this, [this, account] {
-            trySetupPushNotificationsForAccount(account.get());
-        });
-        return;
-    }
-
-    trySetupPushNotificationsForAccount(account.get());
-}
-
-void FileProviderDomainManager::trySetupPushNotificationsForAccount(const Account * const account)
-{
-    if (!d) {
-        return;
-    }
-
-    Q_ASSERT(account);
-
-    const auto pushNotifications = account->pushNotifications();
-    const auto pushNotificationsCapability = account->capabilities().availablePushNotifications() & PushNotificationType::Files;
-
-    if (pushNotificationsCapability && pushNotifications && pushNotifications->isReady()) {
-        qCDebug(lcMacFileProviderDomainManager) << "Push notifications already ready, connecting them to enumerator signalling."
-                                                << account->displayName();
-        setupPushNotificationsForAccount(account);
-    } else if (pushNotificationsCapability) {
-        qCDebug(lcMacFileProviderDomainManager) << "Push notifications not yet ready, will connect to signalling when ready."
-                                                << account->displayName();
-        connect(account, &Account::pushNotificationsReady, this, &FileProviderDomainManager::setupPushNotificationsForAccount);
-    }
-}
-
-void FileProviderDomainManager::setupPushNotificationsForAccount(const Account * const account)
-{
-    if (!d) {
-        return;
-    }
-
-    Q_ASSERT(account);
-
-    qCDebug(lcMacFileProviderDomainManager) << "Setting up push notifications for file provider domain for account:"
-                                            << account->displayName();
-
-    connect(account->pushNotifications(), &PushNotifications::filesChanged, this, &FileProviderDomainManager::signalEnumeratorChanged);
-    disconnect(account, &Account::pushNotificationsReady, this, &FileProviderDomainManager::setupPushNotificationsForAccount);
-}
-
-void FileProviderDomainManager::signalEnumeratorChanged(const Account * const account)
-{
-    if (!d) {
-        return;
-    }
-
-    Q_ASSERT(account);
-    d->signalEnumeratorChanged(account);
-}
-
-void FileProviderDomainManager::removeFileProviderDomainForAccount(const AccountState * const accountState)
-{
-    if (!d) {
-        return;
-    }
-
-    Q_ASSERT(accountState);
-    const auto account = accountState->account();
-    Q_ASSERT(account);
-
-    d->removeFileProviderDomain(accountState);
-
-    if (accountFilesPushNotificationsReady(account)) {
-        const auto pushNotifications = account->pushNotifications();
-        disconnect(pushNotifications, &PushNotifications::filesChanged, this, &FileProviderDomainManager::signalEnumeratorChanged);
-    } else if (const auto hasFilesPushNotificationsCapability = account->capabilities().availablePushNotifications() & PushNotificationType::Files) {
-        disconnect(account.get(), &Account::pushNotificationsReady, this, &FileProviderDomainManager::setupPushNotificationsForAccount);
-    }
-}
-
-void FileProviderDomainManager::disconnectFileProviderDomainForAccount(const AccountState * const accountState, const QString &reason)
-{
-    if (!d) {
-        return;
-    }
-
-    Q_ASSERT(accountState);
-    const auto account = accountState->account();
-    Q_ASSERT(account);
-
-    d->disconnectFileProviderDomainForAccount(accountState, reason);
-}
-
-void FileProviderDomainManager::reconnectFileProviderDomainForAccount(const AccountState * const accountState)
-{
-    if (!d) {
-        return;
-    }
-
-    Q_ASSERT(accountState);
-    const auto account = accountState->account();
-
-    d->reconnectFileProviderDomainForAccount(accountState);
-}
-
-void FileProviderDomainManager::slotAccountStateChanged(const AccountState * const accountState)
-{
-    if (!d) {
-        return;
-    }
-
-    Q_ASSERT(accountState);
-    const auto state = accountState->state();
-
-    qCDebug(lcMacFileProviderDomainManager) << "Account state changed for account:"
-                                            << accountState->account()->displayName()
-                                            << "changing connection status of file provider domain.";
-
-    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:
-    {
-        // Disconnect File Provider domain while unauthenticated
-        const auto trReason = tr("This account is not authenticated. Please check your account state in the %1 application.").arg(APPLICATION_NAME);
-        disconnectFileProviderDomainForAccount(accountState, trReason);
-        break;
-    }
-    case AccountState::Connected:
-        // Provide credentials
-        reconnectFileProviderDomainForAccount(accountState);
-        break;
-    }
-}
-
-void FileProviderDomainManager::slotEnumeratorSignallingTimerTimeout()
-{
-    if (!d) {
-        return;
-    }
-
-    qCDebug(lcMacFileProviderDomainManager) << "Enumerator signalling timer timed out, notifying domains for accounts without push notifications";
-
-    const auto registeredDomainIds = d->configuredDomainIds();
-    for (const auto &domainId : registeredDomainIds) {
-        const auto accountUserId = accountIdFromDomainId(domainId);
-        const auto accountState = AccountManager::instance()->accountFromUserId(accountUserId);
-        const auto account = accountState->account();
-
-        if (!accountFilesPushNotificationsReady(account)) {
-            qCDebug(lcMacFileProviderDomainManager) << "Notifying domain for account:" << account->userIdAtHostWithPort();
-            d->signalEnumeratorChanged(account.get());
-        }
-    }
-}
-
-AccountStatePtr FileProviderDomainManager::accountStateFromFileProviderDomainIdentifier(const QString &domainIdentifier)
-{
-    if (domainIdentifier.isEmpty()) {
-        qCWarning(lcMacFileProviderDomainManager) << "Cannot return accountstateptr for empty domain identifier";
-        return AccountStatePtr();
-    }
-
-    const auto accountUserId = accountIdFromDomainId(domainIdentifier);
-    const auto accountForReceivedDomainIdentifier = AccountManager::instance()->accountFromUserId(accountUserId);
-    if (!accountForReceivedDomainIdentifier) {
-        qCWarning(lcMacFileProviderDomainManager) << "Could not find account matching user id matching file provider domain identifier:"
-                                                  << domainIdentifier;
-    }
-
-    return accountForReceivedDomainIdentifier;
-}
-
-} // namespace Mac
-
-} // namespace OCC
diff --git a/src/gui/macOS/fileprovidersocketcontroller.cpp b/src/gui/macOS/fileprovidersocketcontroller.cpp
deleted file mode 100644 (file)
index 9fa7f2b..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "fileprovidersocketcontroller.h"
-
-#include <QLocalSocket>
-#include <QLoggingCategory>
-
-#include "accountmanager.h"
-#include "fileproviderdomainmanager.h"
-
-namespace OCC {
-
-namespace Mac {
-
-Q_LOGGING_CATEGORY(lcFileProviderSocketController, "nextcloud.gui.macos.fileprovider.socketcontroller", QtInfoMsg)
-
-FileProviderSocketController::FileProviderSocketController(QLocalSocket * const socket, QObject * const parent)
-    : QObject{parent}
-    , _socket(socket)
-{
-    connect(socket, &QLocalSocket::readyRead,
-            this, &FileProviderSocketController::slotReadyRead);
-    connect(socket, &QLocalSocket::disconnected,
-            this, &FileProviderSocketController::slotOnDisconnected);
-    connect(socket, &QLocalSocket::destroyed,
-            this, &FileProviderSocketController::slotSocketDestroyed);
-}
-
-void FileProviderSocketController::slotOnDisconnected()
-{
-    qCInfo(lcFileProviderSocketController) << "File provider socket disconnected";
-    _socket->deleteLater();
-}
-
-void FileProviderSocketController::slotSocketDestroyed(const QObject * const object)
-{
-    Q_UNUSED(object)
-    qCInfo(lcFileProviderSocketController) << "File provider socket object has been destroyed, destroying controller";
-    Q_EMIT socketDestroyed(_socket);
-}
-
-void FileProviderSocketController::slotReadyRead()
-{
-    Q_ASSERT(_socket);
-    if (!_socket) {
-        qCWarning(lcFileProviderSocketController) << "Cannot read data on dead socket";
-        return;
-    }
-
-    while(_socket->canReadLine()) {
-        const auto line = QString::fromUtf8(_socket->readLine().trimmed()).normalized(QString::NormalizationForm_C);
-        qCDebug(lcFileProviderSocketController) << "Received message in file provider socket:" << line;
-
-        parseReceivedLine(line);
-    }
-}
-
-void FileProviderSocketController::parseReceivedLine(const QString &receivedLine)
-{
-    if (receivedLine.isEmpty()) {
-        qCWarning(lcFileProviderSocketController) << "Received empty line, can't parse.";
-        return;
-    }
-
-    const auto argPos = receivedLine.indexOf(QLatin1Char(':'));
-    if (argPos == -1) {
-        qCWarning(lcFileProviderSocketController) << "Received line:"
-                                                  << receivedLine
-                                                  << "is incorrectly structured. Can't parse.";
-        return;
-    }
-
-    const auto command = receivedLine.mid(0, argPos);
-    const auto argument = receivedLine.mid(argPos + 1);
-
-    if (command == QStringLiteral("FILE_PROVIDER_DOMAIN_IDENTIFIER_REQUEST_REPLY")) {
-        _accountState = FileProviderDomainManager::accountStateFromFileProviderDomainIdentifier(argument);
-        sendAccountDetails();
-        return;
-    }
-
-    qCWarning(lcFileProviderSocketController) << "Unknown command or reply:" << receivedLine;
-}
-
-void FileProviderSocketController::sendMessage(const QString &message) const
-{
-    if (!_socket) {
-        qCWarning(lcFileProviderSocketController) << "Not sending message on dead file provider socket:" << message;
-        return;
-    }
-
-    qCDebug(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();
-    const auto sent = _socket->write(bytesToSend);
-
-    if (sent != bytesToSend.length()) {
-        qCWarning(lcFileProviderSocketController) << "Could not send all data on file provider socket for:" << message;
-    }
-}
-
-
-void FileProviderSocketController::start()
-{
-    Q_ASSERT(_socket);
-    if (!_socket) {
-        qCWarning(lcFileProviderSocketController) << "Cannot start communication on dead socket";
-        return;
-    }
-
-    requestFileProviderDomainInfo();
-}
-
-void FileProviderSocketController::requestFileProviderDomainInfo() const
-{
-    Q_ASSERT(_socket);
-    if (!_socket) {
-        qCWarning(lcFileProviderSocketController) << "Cannot request file provider domain data on dead socket";
-        return;
-    }
-
-    const auto requestMessage = QStringLiteral("SEND_FILE_PROVIDER_DOMAIN_IDENTIFIER");
-    sendMessage(requestMessage);
-}
-
-void FileProviderSocketController::slotAccountStateChanged(const AccountState::State state)
-{
-    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:
-        // Notify File Provider that it should show the not authenticated message
-        sendNotAuthenticated();
-        break;
-    case AccountState::Connected:
-        // Provide credentials
-        sendAccountDetails();
-        break;
-    }
-}
-
-void FileProviderSocketController::sendNotAuthenticated() const
-{
-    Q_ASSERT(_accountState);
-    const auto account = _accountState->account();
-    Q_ASSERT(account);
-
-    qCDebug(lcFileProviderSocketController) << "About to send not authenticated message to file provider extension"
-                                            << account->displayName();
-
-    const auto message = QString(QStringLiteral("ACCOUNT_NOT_AUTHENTICATED"));
-    sendMessage(message);
-}
-
-void FileProviderSocketController::sendAccountDetails() const
-{
-    Q_ASSERT(_accountState);
-    const auto account = _accountState->account();
-    Q_ASSERT(account);
-
-    qCDebug(lcFileProviderSocketController) << "About to send account details to file provider extension"
-                                            << account->displayName();
-
-    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"
-                                                << account->displayName();
-        return;
-    }
-
-    const auto credentials = account->credentials();
-    Q_ASSERT(credentials);
-    const auto accountUser = credentials->user();
-    const auto accountUrl = account->url().toString();
-    const auto accountPassword = credentials->password();
-
-    // We cannot use colons as separators here due to "https://" in the url
-    const auto message = QString(QStringLiteral("ACCOUNT_DETAILS:") +
-                                 accountUser + "~" +
-                                 accountUrl + "~" +
-                                 accountPassword);
-    sendMessage(message);
-}
-
-}
-
-}
diff --git a/src/gui/macOS/fileprovidersocketcontroller.h b/src/gui/macOS/fileprovidersocketcontroller.h
deleted file mode 100644 (file)
index ca7c353..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#pragma once
-
-#include <QPointer>
-
-#include "accountstate.h"
-
-class QLocalSocket;
-
-namespace OCC {
-
-namespace Mac {
-
-class FileProviderSocketController : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit FileProviderSocketController(QLocalSocket * const socket, QObject * const parent = nullptr);
-
-signals:
-    void socketDestroyed(const QLocalSocket * const socket);
-
-public slots:
-    void sendMessage(const QString &message) const;
-    void start();
-
-private slots:
-    void slotOnDisconnected();
-    void slotSocketDestroyed(const QObject * const object);
-    void slotReadyRead();
-
-    void slotAccountStateChanged(const OCC::AccountState::State state);
-
-    void parseReceivedLine(const QString &receivedLine);
-    void requestFileProviderDomainInfo() const;
-    void sendAccountDetails() const;
-    void sendNotAuthenticated() const;
-
-private:
-    QPointer<QLocalSocket> _socket;
-    AccountStatePtr _accountState;
-};
-
-} // namespace Mac
-
-} // namespace OCC
diff --git a/src/gui/macOS/fileprovidersocketserver.cpp b/src/gui/macOS/fileprovidersocketserver.cpp
deleted file mode 100644 (file)
index 70b0161..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "fileprovidersocketserver.h"
-
-#include <QLocalSocket>
-#include <QLoggingCategory>
-
-#include "fileprovidersocketcontroller.h"
-
-namespace OCC {
-
-namespace Mac {
-
-Q_LOGGING_CATEGORY(lcFileProviderSocketServer, "nextcloud.gui.macos.fileprovider.socketserver", QtInfoMsg)
-
-FileProviderSocketServer::FileProviderSocketServer(QObject *parent)
-    : QObject{parent}
-{
-    _socketPath = fileProviderSocketPath();
-    startListening();
-}
-
-void FileProviderSocketServer::startListening()
-{
-    QLocalServer::removeServer(_socketPath);
-
-    const auto serverStarted = _socketServer.listen(_socketPath);
-    if (!serverStarted) {
-        qCWarning(lcFileProviderSocketServer) << "Could not start file provider socket server"
-                                              << _socketPath;
-    } else {
-        qCInfo(lcFileProviderSocketServer) << "File provider socket server started, listening"
-                                           << _socketPath;
-    }
-
-    connect(&_socketServer, &QLocalServer::newConnection,
-            this, &FileProviderSocketServer::slotNewConnection);
-}
-
-void FileProviderSocketServer::slotNewConnection()
-{
-    if (!_socketServer.hasPendingConnections()) {
-        return;
-    }
-
-    qCInfo(lcFileProviderSocketServer) << "New connection in file provider socket server";
-    const auto socket = _socketServer.nextPendingConnection();
-    if (!socket) {
-        return;
-    }
-
-    const FileProviderSocketControllerPtr socketController(new FileProviderSocketController(socket, this));
-    connect(socketController.data(), &FileProviderSocketController::socketDestroyed,
-            this, &FileProviderSocketServer::slotSocketDestroyed);
-    _socketControllers.insert(socket, socketController);
-
-    socketController->start();
-}
-
-void FileProviderSocketServer::slotSocketDestroyed(const QLocalSocket * const socket)
-{
-    const auto socketController = _socketControllers.take(socket);
-
-    if (socketController) {
-        const auto rawSocketControllerPtr = socketController.data();
-        delete rawSocketControllerPtr;
-    }
-}
-
-} // namespace Mac
-
-} // namespace OCC
diff --git a/src/gui/macOS/fileprovidersocketserver.h b/src/gui/macOS/fileprovidersocketserver.h
deleted file mode 100644 (file)
index 893de66..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#pragma once
-
-#include <QObject>
-#include <QLocalServer>
-
-namespace OCC {
-
-namespace Mac {
-
-class FileProviderSocketController;
-using FileProviderSocketControllerPtr = QPointer<FileProviderSocketController>;
-
-QString fileProviderSocketPath();
-
-class FileProviderSocketServer : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit FileProviderSocketServer(QObject *parent = nullptr);
-
-private slots:
-    void startListening();
-    void slotNewConnection();
-    void slotSocketDestroyed(const QLocalSocket * const socket);
-
-private:
-    QString _socketPath;
-    QLocalServer _socketServer;
-    QHash<const QLocalSocket*, FileProviderSocketControllerPtr> _socketControllers;
-};
-
-} // namespace Mac
-
-} // namespace OCC
diff --git a/src/gui/macOS/fileprovidersocketserver_mac.mm b/src/gui/macOS/fileprovidersocketserver_mac.mm
deleted file mode 100644 (file)
index 8377adb..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#import <Cocoa/Cocoa.h>
-#import <QString>
-
-#include "config.h"
-
-namespace OCC
-{
-
-namespace Mac
-{
-
-QString fileProviderSocketPath()
-{
-    // This must match the code signing Team setting of the extension
-    // Example for developer builds (with ad-hoc signing identity): "" "com.owncloud.desktopclient" ".fileprovidersocket"
-    // Example for official signed packages: "9B5WD74GWJ." "com.owncloud.desktopclient" ".fileprovidersocket"
-    NSString *appGroupId = @SOCKETAPI_TEAM_IDENTIFIER_PREFIX APPLICATION_REV_DOMAIN;
-
-    NSURL *container = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId];
-    NSURL *socketPath = [container URLByAppendingPathComponent:@".fileprovidersocket" isDirectory:false];
-    return QString::fromNSString(socketPath.path);
-}
-
-} // namespace Mac
-
-} // namespace OCC
index c6447ffe52c1c54082057fba1d18b7a6fb35c6e4..c47f00f1ad52f415a7b8775beaa259a5c6976a87 100644 (file)
@@ -106,8 +106,6 @@ static constexpr char certPath[] = "http_certificatePath";
 static constexpr char certPasswd[] = "http_certificatePasswd";
 
 static const QSet validUpdateChannels { QStringLiteral("stable"), QStringLiteral("beta") };
-
-static constexpr auto macFileProviderModuleEnabledC = "macFileProviderModuleEnabled";
 }
 
 namespace OCC {
@@ -1173,16 +1171,4 @@ void ConfigFile::setDiscoveredLegacyConfigPath(const QString &discoveredLegacyCo
     _discoveredLegacyConfigPath = discoveredLegacyConfigPath;
 }
 
-bool ConfigFile::macFileProviderModuleEnabled() const
-{
-    QSettings settings(configFile(), QSettings::IniFormat);
-    return settings.value(macFileProviderModuleEnabledC, false).toBool();
-}
-
-void ConfigFile::setMacFileProviderModuleEnabled(const bool moduleEnabled)
-{
-    QSettings settings(configFile(), QSettings::IniFormat);
-    settings.setValue(QLatin1String(macFileProviderModuleEnabledC), moduleEnabled);
-}
-
 }
index 5d0ee5460fcef8bb4bb1a104223bc3d9717a71d6..3fc7f5e4fa35961ef909ca170a530b0691848a3d 100644 (file)
@@ -223,9 +223,6 @@ public:
     [[nodiscard]] static QString discoveredLegacyConfigPath();
     static void setDiscoveredLegacyConfigPath(const QString &discoveredLegacyConfigPath);
 
-    [[nodiscard]] bool macFileProviderModuleEnabled() const;
-    void setMacFileProviderModuleEnabled(const bool moduleEnabled);
-
 protected:
     [[nodiscard]] QVariant getPolicySetting(const QString &policy, const QVariant &defaultValue = QVariant()) const;
     void storeData(const QString &group, const QString &key, const QVariant &value);
@@ -240,6 +237,7 @@ private:
 
     [[nodiscard]] QString keychainProxyPasswordKey() const;
 
+private:
     using SharedCreds = QSharedPointer<AbstractCredentials>;
 
     static QString _confDir;