aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Hotline/Application-macOS.swift3
-rw-r--r--Hotline/Info.plist35
-rw-r--r--Hotline/Models/Bookmark.swift39
-rw-r--r--Hotline/Utility/FoundationExtensions.swift30
-rw-r--r--Hotline/macOS/TrackerView.swift29
5 files changed, 136 insertions, 0 deletions
diff --git a/Hotline/Application-macOS.swift b/Hotline/Application-macOS.swift
index 9aec187..016cb60 100644
--- a/Hotline/Application-macOS.swift
+++ b/Hotline/Application-macOS.swift
@@ -22,6 +22,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
AppLaunchState.shared.launchState = .launched
+ let blah = NSFileTypeForHFSTypeCode("HTbm".fourCharCode())
+ print("FILETYPE: \(blah)", blah!, "'HTbm'")
+
CKContainer.default().accountStatus { status, error in
switch status {
case .noAccount:
diff --git a/Hotline/Info.plist b/Hotline/Info.plist
index 8b58335..ac7a2c9 100644
--- a/Hotline/Info.plist
+++ b/Hotline/Info.plist
@@ -2,6 +2,19 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeName</key>
+ <string>Hotline Bookmark</string>
+ <key>LSHandlerRank</key>
+ <string>Alternate</string>
+ <key>LSItemContentTypes</key>
+ <array>
+ <string>'HTbm'</string>
+ </array>
+ </dict>
+ </array>
<key>CFBundleURLTypes</key>
<array>
<dict>
@@ -25,5 +38,27 @@
</array>
</dict>
</array>
+ <key>UTImportedTypeDeclarations</key>
+ <array>
+ <dict>
+ <key>UTTypeConformsTo</key>
+ <array/>
+ <key>UTTypeDescription</key>
+ <string>Hotline Bookmark</string>
+ <key>UTTypeIconFiles</key>
+ <array/>
+ <key>UTTypeIdentifier</key>
+ <string>'HTbm'</string>
+ <key>UTTypeTagSpecification</key>
+ <dict>
+ <key>public.filename-extension</key>
+ <array>
+ <string>.htbm</string>
+ </array>
+ <key>public.mime-type</key>
+ <array/>
+ </dict>
+ </dict>
+ </array>
</dict>
</plist>
diff --git a/Hotline/Models/Bookmark.swift b/Hotline/Models/Bookmark.swift
index c713bb0..234a196 100644
--- a/Hotline/Models/Bookmark.swift
+++ b/Hotline/Models/Bookmark.swift
@@ -96,6 +96,45 @@ 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 {
+ return nil
+ }
+
+ print("Bookmark: Parsing Hotline bookmark file...")
+
+ 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 = addressHost
+ self.address = addressHost
+ self.port = addressPort
+ self.login = loginString.isEmpty ? nil : loginString
+ self.password = passwordString.isEmpty ? nil : passwordString
+ }
+
static func populateDefaults(force: Bool = false, context: ModelContext) {
if force || Bookmark.fetchCount(context: context) == 0 {
Bookmark.add(Bookmark.DefaultBookmarks, context: context)
diff --git a/Hotline/Utility/FoundationExtensions.swift b/Hotline/Utility/FoundationExtensions.swift
index 14e76d5..0c8966a 100644
--- a/Hotline/Utility/FoundationExtensions.swift
+++ b/Hotline/Utility/FoundationExtensions.swift
@@ -202,6 +202,19 @@ extension Array where Element == UInt8 {
return str
}
+ mutating func consumeLongPString() -> String? {
+ let (str, len) = self.readLongPString(at: 0)
+ guard let str = str else {
+ return nil
+ }
+ if len == 0 {
+ return ""
+ }
+
+ self.removeFirst(len)
+ return str
+ }
+
mutating func consumeString(_ length: Int) -> String? {
guard let val = self.readString(at: 0, length: length) else {
return nil
@@ -388,6 +401,23 @@ extension Array where Element == UInt8 {
mutating func appendData(_ data: [UInt8]) {
self.append(contentsOf: data)
}
+
+ mutating func hotlineEncrypt() {
+ for i in (0..<self.count).reversed() {
+ self[i] = 0xFF - self[i]
+ }
+ }
+
+ func hotlineEncrypted() -> [UInt8] {
+ var cpy = [UInt8](self)
+
+
+
+ for i in (0..<cpy.count).reversed() {
+ cpy[i] = 0xFF - cpy[i]
+ }
+ return cpy
+ }
}
extension Data {
diff --git a/Hotline/macOS/TrackerView.swift b/Hotline/macOS/TrackerView.swift
index 104e15d..5a9db9b 100644
--- a/Hotline/macOS/TrackerView.swift
+++ b/Hotline/macOS/TrackerView.swift
@@ -1,5 +1,6 @@
import SwiftUI
import SwiftData
+import UniformTypeIdentifiers
struct TrackerView: View {
// @Environment(BookmarksOld.self) private var bookmarks: BookmarksOld
@@ -12,6 +13,7 @@ struct TrackerView: View {
@State private var trackerSheetPresented: Bool = false
@State private var trackerSheetBookmark: Bookmark? = nil
@State private var attemptedPrepopulate: Bool = false
+ @State private var fileDropActive = false
@Query(sort: \Bookmark.order) private var bookmarks: [Bookmark]
@State private var selection: Bookmark? = nil
@@ -137,6 +139,33 @@ struct TrackerView: View {
}
return .ignored
}
+ .onDrop(of: [UTType.fileURL], isTargeted: $fileDropActive) { providers, dropPoint in
+ for provider in providers {
+ let _ = provider.loadDataRepresentation(for: UTType.fileURL) { dataRepresentation, err in
+ // HOTLINE CREATOR CODE: 1213484099
+ // HOTLINE BOOKMARK TYPE CODE: 1213489773
+
+ if let filePathData = dataRepresentation,
+ let filePath = String(data: filePathData, encoding: .utf8),
+ let fileURL = URL(string: filePath) {
+
+ print("Hotline Bookmark: Dropped from ", fileURL.path(percentEncoded: false))
+
+ DispatchQueue.main.async {
+ if let newBookmark = Bookmark(fileURL: fileURL) {
+ print("Hotline Bookmark: Added bookmark.")
+ Bookmark.add(newBookmark, context: modelContext)
+ }
+ else {
+ print("Hotline Bookmark: Failed to parse.")
+ }
+ }
+ }
+ }
+ }
+
+ return true
+ }
.sheet(item: $trackerSheetBookmark) { item in
TrackerBookmarkSheet(item)
}