aboutsummaryrefslogtreecommitdiff
path: root/Hotline/Models
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2024-05-23 12:50:16 -0700
committerDustin Mierau <dustin@mierau.me>2024-05-23 12:50:16 -0700
commit23b3f338f0818a53b2499692e999a0528e5d9753 (patch)
tree19f2d018824cdc41c0aa37dde6bde5d9054be9f2 /Hotline/Models
parent842611754debec7d1814e44e6a2cf302e84c0d66 (diff)
Add Bookmark exporting to Server window context menu.
Diffstat (limited to 'Hotline/Models')
-rw-r--r--Hotline/Models/Bookmark.swift100
1 files changed, 91 insertions, 9 deletions
diff --git a/Hotline/Models/Bookmark.swift b/Hotline/Models/Bookmark.swift
index 234a196..115e5a9 100644
--- a/Hotline/Models/Bookmark.swift
+++ b/Hotline/Models/Bookmark.swift
@@ -96,16 +96,11 @@ final class Bookmark {
self.serverDescription = server.description
}
- init?(fileURL bookmarkFileURL: URL) {
- guard let fileAttributes = try? FileManager.default.attributesOfItem(atPath: bookmarkFileURL.path(percentEncoded: false)),
- let fileSize = fileAttributes[FileAttributeKey.size] as? UInt64,
- fileSize <= 2000,
- let fileData = try? Data(contentsOf: bookmarkFileURL) else {
+ init?(fileData: Data, name: String? = nil) {
+ guard fileData.count <= 2000 else {
return nil
}
-
- print("Bookmark: Parsing Hotline bookmark file...")
-
+
var fileDataArray: [UInt8] = [UInt8](fileData)
guard let headerValue = fileDataArray.consumeUInt32(),
@@ -128,13 +123,100 @@ final class Bookmark {
let (addressHost, addressPort) = Server.parseServerAddressAndPort(addressString)
self.type = .server
- self.name = addressHost
+ if let name = name, !name.isEmpty {
+ self.name = name
+ }
+ else {
+ self.name = addressHost
+ }
self.address = addressHost
self.port = addressPort
self.login = loginString.isEmpty ? nil : loginString
self.password = passwordString.isEmpty ? nil : passwordString
}
+ convenience init?(fileURL bookmarkFileURL: URL) {
+ guard bookmarkFileURL.isFileURL,
+ let fileAttributes = try? FileManager.default.attributesOfItem(atPath: bookmarkFileURL.path(percentEncoded: false)),
+ let fileSize = fileAttributes[FileAttributeKey.size] as? UInt64,
+ fileSize <= 2000,
+ let fileData = try? Data(contentsOf: bookmarkFileURL) else {
+ return nil
+ }
+
+ print("Bookmark: Parsing Hotline bookmark file...")
+
+ let fileName = bookmarkFileURL.deletingPathExtension().lastPathComponent.trimmingCharacters(in: .whitespacesAndNewlines)
+
+ self.init(fileData: fileData, name: fileName)
+
+// var fileDataArray: [UInt8] = [UInt8](fileData)
+//
+// guard let headerValue = fileDataArray.consumeUInt32(),
+// headerValue.fourCharCode() == "HTsc",
+// let versionNumber = fileDataArray.consumeUInt16(),
+// versionNumber == 1,
+// fileDataArray.consume(128), // Skip 128 reserved bytes.
+// let loginLength = fileDataArray.consumeUInt16(),
+// let loginData: Data = fileDataArray.consumeBytes(32),
+// let passwordLength = fileDataArray.consumeUInt16(),
+// let passwordData: Data = fileDataArray.consumeBytes(32),
+// let addressLength = fileDataArray.consumeUInt16(),
+// let addressData: Data = fileDataArray.consumeBytes(256),
+// let addressString = String(data: addressData[0..<Int(addressLength)], encoding: .ascii),
+// let loginString = String(data: loginData[0..<Int(loginLength)], encoding: .ascii),
+// let passwordString = String(data: passwordData[0..<Int(passwordLength)], encoding: .ascii) else {
+// return nil
+// }
+//
+// let (addressHost, addressPort) = Server.parseServerAddressAndPort(addressString)
+//
+// self.type = .server
+// self.name = fileName.isEmpty ? addressHost : fileName
+// self.address = addressHost
+// self.port = addressPort
+// self.login = loginString.isEmpty ? nil : loginString
+// self.password = passwordString.isEmpty ? nil : passwordString
+ }
+
+ func bookmarkFileData() -> Data? {
+ guard let addressData = self.displayAddress.data(using: .ascii) else {
+ return nil
+ }
+
+ let loginData: Data = self.login?.data(using: .ascii) ?? Data()
+ let passwordData: Data = self.password?.data(using: .ascii) ?? Data()
+
+ var fileData: Data = Data()
+
+ fileData.appendUInt32("HTsc".fourCharCode()) // magic
+ fileData.appendUInt16(0x0001) // version
+ fileData.append(Data(repeating: 0x00, count: 128)) // reserved
+
+ fileData.appendUInt16(UInt16(loginData.count))
+ fileData.append(loginData)
+ if loginData.count < 32 {
+ // Pad login data to 32 bytes
+ fileData.append(Data(repeating: 0x00, count: 32 - loginData.count))
+ }
+
+ fileData.appendUInt16(UInt16(passwordData.count))
+ fileData.append(passwordData)
+ if passwordData.count < 32 {
+ // Pad password data to 32 bytes
+ fileData.append(Data(repeating: 0x00, count: 32 - passwordData.count))
+ }
+
+ fileData.appendUInt16(UInt16(addressData.count))
+ fileData.append(addressData)
+ if passwordData.count < 256 {
+ // Pad address data to 256 bytes
+ fileData.append(Data(repeating: 0x00, count: 256 - addressData.count))
+ }
+
+ return fileData
+ }
+
static func populateDefaults(force: Bool = false, context: ModelContext) {
if force || Bookmark.fetchCount(context: context) == 0 {
Bookmark.add(Bookmark.DefaultBookmarks, context: context)