84 lines
3.6 KiB
Swift
84 lines
3.6 KiB
Swift
import Foundation
|
|
import AppKit
|
|
|
|
enum SSHService {
|
|
static func sshArguments(for profile: ConnectionProfile, key: StoredSSHKey?) -> [String] {
|
|
var args: [String] = []
|
|
args += ["-p", "\(profile.port)"]
|
|
if let key, !key.privateKeyPath.isEmpty {
|
|
args += ["-i", key.privateKeyPath]
|
|
}
|
|
if !profile.extraArgs.isEmpty {
|
|
args += profile.extraArgs.split(separator: " ").map(String.init)
|
|
}
|
|
args.append("\(profile.username)@\(profile.host)")
|
|
return args
|
|
}
|
|
|
|
static func sshCommandString(for profile: ConnectionProfile, key: StoredSSHKey?) -> String {
|
|
let escaped = sshArguments(for: profile, key: key).map { $0.contains(" ") ? "'\($0)'" : $0 }
|
|
return "ssh " + escaped.joined(separator: " ")
|
|
}
|
|
|
|
/// Öffnet die SSH-Session in Terminal.app — ohne AppleScript (das scheiterte
|
|
/// still an fehlender Automation-Berechtigung), sondern über eine .command-Datei.
|
|
static func openInTerminal(profile: ConnectionProfile, key: StoredSSHKey?) {
|
|
let cmd = sshCommandString(for: profile, key: key)
|
|
let dir = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
|
|
.appendingPathComponent("RemminaMac", isDirectory: true)
|
|
try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
|
|
let url = dir.appendingPathComponent("launch-\(profile.id.uuidString).command")
|
|
// exec bash hält das Fenster nach Sitzungsende offen
|
|
try? "#!/bin/bash\n\(cmd)\nexec bash\n".write(to: url, atomically: true, encoding: .utf8)
|
|
try? FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: url.path)
|
|
NSWorkspace.shared.open(url)
|
|
}
|
|
|
|
static func copyCommandToClipboard(profile: ConnectionProfile, key: StoredSSHKey?) {
|
|
let cmd = sshCommandString(for: profile, key: key)
|
|
NSPasteboard.general.clearContents()
|
|
NSPasteboard.general.setString(cmd, forType: .string)
|
|
}
|
|
}
|
|
|
|
enum RDPService {
|
|
static var freeRDPPath: String? {
|
|
for candidate in ["/opt/homebrew/bin/xfreerdp", "/usr/local/bin/xfreerdp", "/usr/bin/xfreerdp"] {
|
|
if FileManager.default.isExecutableFile(atPath: candidate) { return candidate }
|
|
}
|
|
return nil
|
|
}
|
|
|
|
static func connect(profile: ConnectionProfile) {
|
|
if let freerdp = freeRDPPath {
|
|
let task = Process()
|
|
task.executableURL = URL(fileURLWithPath: freerdp)
|
|
var args = ["/v:\(profile.host):\(profile.port)", "/u:\(profile.username)"]
|
|
if profile.resolution.lowercased() != "automatisch" {
|
|
let size = profile.resolution.replacingOccurrences(of: " ", with: "")
|
|
args.append("/size:\(size)")
|
|
} else {
|
|
args.append("/f")
|
|
}
|
|
if !profile.extraArgs.isEmpty {
|
|
args += profile.extraArgs.split(separator: " ").map(String.init)
|
|
}
|
|
task.arguments = args
|
|
try? task.run()
|
|
} else {
|
|
// Fallback: Microsoft Remote Desktop URL-Scheme
|
|
let addr = "full address=s:\(profile.host):\(profile.port)"
|
|
if let encoded = addr.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
|
|
let url = URL(string: "rdc://?\(encoded)") {
|
|
NSWorkspace.shared.open(url)
|
|
}
|
|
}
|
|
}
|
|
|
|
static func connectVNC(profile: ConnectionProfile) {
|
|
if let url = URL(string: "vnc://\(profile.host):\(profile.port)") {
|
|
NSWorkspace.shared.open(url)
|
|
}
|
|
}
|
|
}
|