]> dgit.raspbian.org Git - nextcloud-desktop.git/blob
3d2f30a54a0c8138c61a02dc204fc9331c9069f1
[nextcloud-desktop.git] /
1 /*
2  * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12  * for more details.
13  */
14
15 import FileProvider
16 import Foundation
17 import NCDesktopClientSocketKit
18 import NextcloudKit
19 import NextcloudFileProviderKit
20 import OSLog
21
22 extension FileProviderExtension: NSFileProviderServicing {
23     /*
24      This FileProviderExtension extension contains everything needed to communicate with the client.
25      We have two systems for communicating between the extensions and the client.
26
27      Apple's XPC based File Provider APIs let us easily communicate client -> extension.
28      This is what ClientCommunicationService is for.
29
30      We also use sockets, because the File Provider XPC system does not let us easily talk from
31      extension->client.
32      We need this because the extension needs to be able to request account details. We can't
33      reliably do this via XPC because the extensions get torn down by the system, out of the control
34      of the app, and we can receive nil/no services from NSFileProviderManager. Once this is done
35      then XPC works ok.
36     */
37     func supportedServiceSources(
38         for itemIdentifier: NSFileProviderItemIdentifier,
39         completionHandler: @escaping ([NSFileProviderServiceSource]?, Error?) -> Void
40     ) -> Progress {
41         Logger.desktopClientConnection.debug("Serving supported service sources")
42         let clientCommService = ClientCommunicationService(fpExtension: self)
43         let fpuiExtService = FPUIExtensionServiceSource(fpExtension: self)
44         let services: [NSFileProviderServiceSource] = [clientCommService, fpuiExtService]
45         completionHandler(services, nil)
46         let progress = Progress()
47         progress.cancellationHandler = {
48             let error = NSError(domain: NSCocoaErrorDomain, code: NSUserCancelledError)
49             completionHandler(nil, error)
50         }
51         return progress
52     }
53
54     @objc func sendFileProviderDomainIdentifier() {
55         let command = "FILE_PROVIDER_DOMAIN_IDENTIFIER_REQUEST_REPLY"
56         let argument = domain.identifier.rawValue
57         let message = command + ":" + argument + "\n"
58         socketClient?.sendMessage(message)
59     }
60
61     private func signalEnumeratorAfterAccountSetup() {
62         guard let fpManager = NSFileProviderManager(for: domain) else {
63             Logger.fileProviderExtension.error(
64                 "Could not get file provider manager for domain \(self.domain.displayName, privacy: .public), cannot notify after account setup"
65             )
66             return
67         }
68
69         assert(ncAccount != nil)
70
71         fpManager.signalErrorResolved(NSFileProviderError(.notAuthenticated)) { error in
72             if error != nil {
73                 Logger.fileProviderExtension.error(
74                     "Error resolving not authenticated, received error: \(error!.localizedDescription)"
75                 )
76             }
77         }
78
79         Logger.fileProviderExtension.debug(
80             "Signalling enumerators for user \(self.ncAccount!.username) at server \(self.ncAccount!.serverUrl, privacy: .public)"
81         )
82
83         fpManager.signalEnumerator(for: .workingSet) { error in
84             if error != nil {
85                 Logger.fileProviderExtension.error(
86                     "Error signalling enumerator for working set, received error: \(error!.localizedDescription, privacy: .public)"
87                 )
88             }
89         }
90     }
91
92     @objc func setupDomainAccount(user: String, serverUrl: String, password: String) {
93         let newNcAccount = Account(user: user, serverUrl: serverUrl, password: password)
94         guard newNcAccount != ncAccount else { return }
95         ncAccount = newNcAccount
96         ncKit.setup(
97             user: ncAccount!.username,
98             userId: ncAccount!.username,
99             password: ncAccount!.password,
100             urlBase: ncAccount!.serverUrl,
101             userAgent: "Nextcloud-macOS/FileProviderExt",
102             nextcloudVersion: 25,
103             delegate: nil) // TODO: add delegate methods for self
104
105         Logger.fileProviderExtension.info(
106             "Nextcloud account set up in File Provider extension for user: \(user, privacy: .public) at server: \(serverUrl, privacy: .public)"
107         )
108
109         signalEnumeratorAfterAccountSetup()
110     }
111
112     @objc func removeAccountConfig() {
113         Logger.fileProviderExtension.info(
114             "Received instruction to remove account data for user \(self.ncAccount!.username, privacy: .public) at server \(self.ncAccount!.serverUrl, privacy: .public)"
115         )
116         ncAccount = nil
117     }
118 }