diff --git a/Sources/NextcloudKit/Models/NKDownloadLimit.swift b/Sources/NextcloudKit/Models/NKDownloadLimit.swift
new file mode 100644
index 0000000..b3722a4
--- /dev/null
+++ b/Sources/NextcloudKit/Models/NKDownloadLimit.swift
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: Nextcloud GmbH
+// SPDX-FileCopyrightText: 2024 Iva Horn
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import Foundation
+
+///
+/// Data model for a download limit as returned in the WebDAV response for file properties.
+///
+/// Each relates to a share of a file and is optionally provided by the [Files Download Limit](https://github.com/nextcloud/files_downloadlimit) app for Nextcloud server.
+///
+public class NKDownloadLimit: NSObject {
+ ///
+ /// The number of downloads which already happened.
+ ///
+ public let count: Int
+
+ ///
+ /// Total number of allowed downloas.
+ ///
+ public let limit: Int
+
+ ///
+ /// The token identifying the related share.
+ ///
+ public let token: String
+
+ init(count: Int, limit: Int, token: String) {
+ self.count = count
+ self.limit = limit
+ self.token = token
+ }
+}
diff --git a/Sources/NextcloudKit/Models/NKFile.swift b/Sources/NextcloudKit/Models/NKFile.swift
index 1da7b9d..dde57ee 100644
--- a/Sources/NextcloudKit/Models/NKFile.swift
+++ b/Sources/NextcloudKit/Models/NKFile.swift
@@ -16,6 +16,12 @@ public class NKFile: NSObject {
public var date = Date()
public var directory: Bool = false
public var downloadURL = ""
+
+ ///
+ /// Download limits for shares of this file.
+ ///
+ public var downloadLimits = [NKDownloadLimit]()
+
public var e2eEncrypted: Bool = false
public var etag = ""
public var favorite: Bool = false
diff --git a/Sources/NextcloudKit/Models/NKProperties.swift b/Sources/NextcloudKit/Models/NKProperties.swift
index 929d447..f5482f5 100644
--- a/Sources/NextcloudKit/Models/NKProperties.swift
+++ b/Sources/NextcloudKit/Models/NKProperties.swift
@@ -3,9 +3,18 @@
// SPDX-FileCopyrightText: 2023 Claudio Cambra
// SPDX-License-Identifier: GPL-3.0-or-later
+///
+/// Definition of properties used for decoding in ``NKDataFileXML``.
+///
public enum NKProperties: String, CaseIterable {
/// DAV
case displayname = ""
+
+ ///
+ /// Download limits for shares of a file as optionally provided by the [Files Download Limit](https://github.com/nextcloud/files_downloadlimit) app for Nextcloud server.
+ ///
+ case downloadLimit = ""
+
case getlastmodified = ""
case getetag = ""
case getcontenttype = ""
diff --git a/Sources/NextcloudKit/NKDataFileXML.swift b/Sources/NextcloudKit/NKDataFileXML.swift
index c01d18e..eef09d6 100644
--- a/Sources/NextcloudKit/NKDataFileXML.swift
+++ b/Sources/NextcloudKit/NKDataFileXML.swift
@@ -560,7 +560,23 @@ class NKDataFileXML: NSObject {
}
file.placePhotos = propstat["d:prop", "nc:metadata-photos-place"].text
-
+
+ for downloadLimit in propstat["d:prop", "nc:share-download-limits", "nc:share-download-limit"] {
+ guard let token = downloadLimit["nc:token"].text else {
+ continue
+ }
+
+ guard let limit = downloadLimit["nc:limit"].int else {
+ continue
+ }
+
+ guard let count = downloadLimit["nc:count"].int else {
+ continue
+ }
+
+ file.downloadLimits.append(NKDownloadLimit(count: count, limit: limit, token: token))
+ }
+
let results = self.nkCommonInstance.getInternalType(fileName: file.fileName, mimeType: file.contentType, directory: file.directory, account: nkSession.account)
file.contentType = results.mimeType
diff --git a/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift b/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift
new file mode 100644
index 0000000..448e86e
--- /dev/null
+++ b/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift
@@ -0,0 +1,90 @@
+// SPDX-FileCopyrightText: Nextcloud GmbH
+// SPDX-FileCopyrightText: 2024 Iva Horn
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import Alamofire
+import Foundation
+
+public extension NextcloudKit {
+ private func makeEndpoint(with token: String) -> String {
+ "ocs/v2.php/apps/files_downloadlimit/api/v1/\(token)/limit"
+ }
+
+ func removeShareDownloadLimit(account: String, token: String, completion: @escaping (_ error: NKError) -> Void) {
+ let endpoint = makeEndpoint(with: token)
+ let options = NKRequestOptions()
+
+ guard let nkSession = nkCommonInstance.getSession(account: account),
+ let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options),
+ let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else {
+ return options.queue.async {
+ completion(.urlError)
+ }
+ }
+
+ nkSession
+ .sessionData
+ .request(url, method: .delete, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil)
+ .validate(statusCode: 200..<300)
+ .response(queue: self.nkCommonInstance.backgroundQueue) { response in
+ if self.nkCommonInstance.levelLog > 0 {
+ debugPrint(response)
+ }
+
+ switch response.result {
+ case .failure(let error):
+ let error = NKError(error: error, afResponse: response, responseData: response.data)
+
+ options.queue.async {
+ completion(error)
+ }
+ case .success:
+ options.queue.async {
+ completion(.success)
+ }
+ }
+ }
+ }
+
+ func setShareDownloadLimit(account: String, token: String, limit: Int, completion: @escaping (_ error: NKError) -> Void) {
+ let endpoint = makeEndpoint(with: token)
+ let options = NKRequestOptions()
+ options.contentType = "application/json"
+
+ guard let nkSession = nkCommonInstance.getSession(account: account),
+ let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options),
+ let headers = nkCommonInstance.getStandardHeaders(account: account, options: options),
+ var urlRequest = try? URLRequest(url: url, method: .put, headers: headers) else {
+ return options.queue.async {
+ completion(.urlError)
+ }
+ }
+
+ urlRequest.httpBody = try? JSONEncoder().encode([
+ "limit": limit
+ ])
+
+ nkSession
+ .sessionData
+ .request(urlRequest)
+ .validate(statusCode: 200..<300)
+ .response(queue: self.nkCommonInstance.backgroundQueue) { response in
+ if self.nkCommonInstance.levelLog > 0 {
+ debugPrint(response)
+ }
+
+ switch response.result {
+ case .failure(let error):
+ let error = NKError(error: error, afResponse: response, responseData: response.data)
+
+ options.queue.async {
+ completion(error)
+ }
+ case .success:
+ options.queue.async {
+ completion(.success)
+ }
+ }
+ }
+ }
+}