feat: supports importing hosts from MobaXterm (#293)

This commit is contained in:
hstyi
2025-02-22 14:04:31 +08:00
committed by GitHub
parent 034ee3791d
commit 51c355c113

View File

@@ -359,8 +359,9 @@ class NewHostTree : JXTree() {
val newHost = newMenu.add(I18n.getString("termora.welcome.contextmenu.new.host")) val newHost = newMenu.add(I18n.getString("termora.welcome.contextmenu.new.host"))
val importMenu = JMenu(I18n.getString("termora.welcome.contextmenu.import")) val importMenu = JMenu(I18n.getString("termora.welcome.contextmenu.import"))
val csvMenu = importMenu.add("CSV") val csvMenu = importMenu.add("CSV")
val XshellMenu = importMenu.add("Xshell") val xShellMenu = importMenu.add("Xshell")
val windTermMenu = importMenu.add("WindTerm") val windTermMenu = importMenu.add("WindTerm")
val mobaXtermMenu = importMenu.add("MobaXterm")
val open = popupMenu.add(I18n.getString("termora.welcome.contextmenu.connect")) val open = popupMenu.add(I18n.getString("termora.welcome.contextmenu.connect"))
val openWith = popupMenu.add(JMenu(I18n.getString("termora.welcome.contextmenu.connect-with"))) as JMenu val openWith = popupMenu.add(JMenu(I18n.getString("termora.welcome.contextmenu.connect-with"))) as JMenu
@@ -388,7 +389,8 @@ class NewHostTree : JXTree() {
popupMenu.add(showMoreInfo) popupMenu.add(showMoreInfo)
val property = popupMenu.add(I18n.getString("termora.welcome.contextmenu.property")) val property = popupMenu.add(I18n.getString("termora.welcome.contextmenu.property"))
XshellMenu.addActionListener { importHosts(lastNode, ImportType.Xshell) } xShellMenu.addActionListener { importHosts(lastNode, ImportType.Xshell) }
mobaXtermMenu.addActionListener { importHosts(lastNode, ImportType.MobaXterm) }
csvMenu.addActionListener { importHosts(lastNode, ImportType.CSV) } csvMenu.addActionListener { importHosts(lastNode, ImportType.CSV) }
windTermMenu.addActionListener { importHosts(lastNode, ImportType.WindTerm) } windTermMenu.addActionListener { importHosts(lastNode, ImportType.WindTerm) }
open.addActionListener { openHosts(it, false) } open.addActionListener { openHosts(it, false) }
@@ -638,6 +640,9 @@ class NewHostTree : JXTree() {
when (type) { when (type) {
ImportType.WindTerm -> chooser.fileFilter = FileNameExtensionFilter("WindTerm (*.sessions)", "sessions") ImportType.WindTerm -> chooser.fileFilter = FileNameExtensionFilter("WindTerm (*.sessions)", "sessions")
ImportType.CSV -> chooser.fileFilter = FileNameExtensionFilter("CSV (*.csv)", "csv") ImportType.CSV -> chooser.fileFilter = FileNameExtensionFilter("CSV (*.csv)", "csv")
ImportType.MobaXterm -> chooser.fileFilter =
FileNameExtensionFilter("MobaXterm (*.mobaconf,*.ini)", "ini", "mobaconf")
ImportType.Xshell -> { ImportType.Xshell -> {
chooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY chooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
chooser.dialogTitle = "Xshell Sessions" chooser.dialogTitle = "Xshell Sessions"
@@ -704,6 +709,7 @@ class NewHostTree : JXTree() {
val nodes = when (type) { val nodes = when (type) {
ImportType.WindTerm -> parseFromWindTerm(folder, file) ImportType.WindTerm -> parseFromWindTerm(folder, file)
ImportType.MobaXterm -> parseFromMobaXterm(folder, file)
ImportType.Xshell -> parseFromXshell(folder, file) ImportType.Xshell -> parseFromXshell(folder, file)
ImportType.CSV -> file.bufferedReader().use { parseFromCSV(folder, it) } ImportType.CSV -> file.bufferedReader().use { parseFromCSV(folder, it) }
} }
@@ -752,6 +758,46 @@ class NewHostTree : JXTree() {
return parseFromCSV(folder, StringReader(sw.toString())) return parseFromCSV(folder, StringReader(sw.toString()))
} }
private fun parseFromMobaXterm(folder: HostTreeNode, file: File): List<HostTreeNode> {
val ini = Ini()
ini.config.isEscapeKeyOnly = true
ini.load(file)
val bookmarks = mutableListOf<String>()
for (key in ini.keys) {
if (key.startsWith("Bookmarks")) {
bookmarks.add(key)
}
}
val sw = StringWriter()
CSVPrinter(sw, CSVFormat.EXCEL.builder().setHeader(*CSV_HEADERS).get()).use { printer ->
for (bookmark in bookmarks) {
val properties = (ini[bookmark] ?: continue).toProperties()
// 删除不必要元素
properties.remove("ImgNum")
val folders = FilenameUtils.separatorsToUnix(
(properties.remove("SubRep")
?: StringUtils.EMPTY).toString()
)
for (key in properties.stringPropertyNames()) {
val segments = properties.getProperty(key).split("%")
if (segments.isEmpty()) continue
// ssh: #109#0
// telnet: #98#1
if (segments.first() != "#109#0") continue
val hostname = segments.getOrNull(1) ?: StringUtils.EMPTY
val port = segments.getOrNull(2) ?: 22
printer.printRecord(folders, key, hostname, port, StringUtils.EMPTY, "SSH")
}
}
}
return parseFromCSV(folder, StringReader(sw.toString()))
}
private fun parseFromXshell(folder: HostTreeNode, dir: File): List<HostTreeNode> { private fun parseFromXshell(folder: HostTreeNode, dir: File): List<HostTreeNode> {
val files = FileUtils.listFiles(dir, arrayOf("xsh"), true) val files = FileUtils.listFiles(dir, arrayOf("xsh"), true)
if (files.isEmpty()) { if (files.isEmpty()) {
@@ -859,6 +905,7 @@ class NewHostTree : JXTree() {
WindTerm, WindTerm,
CSV, CSV,
Xshell, Xshell,
MobaXterm
} }
private class MoveHostTransferable(val nodes: List<HostTreeNode>) : Transferable { private class MoveHostTransferable(val nodes: List<HostTreeNode>) : Transferable {