diff src/main/kotlin/name/blackcap/passman/RenameSubcommand.kt @ 11:c69665ff37d0

Add merge subcommand (untested).
author David Barts <n5jrn@me.com>
date Sat, 21 Jan 2023 15:39:42 -0800
parents
children 4dae7a15ee48
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/kotlin/name/blackcap/passman/RenameSubcommand.kt	Sat Jan 21 15:39:42 2023 -0800
@@ -0,0 +1,96 @@
+package name.blackcap.passman
+
+import org.apache.commons.cli.*
+import kotlin.system.exitProcess
+
+class RenameSubcommand(): Subcommand() {
+    private companion object {
+        const val FORCE = "force"
+        const val HELP = "help"
+    }
+    private lateinit var commandLine: CommandLine
+    private lateinit var source: String
+    private lateinit var destination: String
+    private lateinit var db: Database
+
+    override fun run(args: Array<String>) {
+        parseArguments(args)
+        db = Database.open()
+        renameIt()
+    }
+
+    private fun parseArguments(args: Array<String>) {
+        val options = Options().apply {
+            addOption("f", FORCE, false, "If destination exists exists, force overwrite.")
+            addOption("h", HELP, false, "Print this help message.")
+        }
+        try {
+            commandLine = DefaultParser().parse(options, args)
+        } catch (e: ParseException) {
+            die(e.message ?: "syntax error", 2)
+        }
+        if (commandLine.hasOption(HELP)) {
+            HelpFormatter().printHelp("$SHORTNAME rename [options] source destination", options)
+            exitProcess(0)
+        }
+        if (commandLine.args.size < 2) {
+            die("expecting source and destination", 2)
+        }
+        if (commandLine.args.size > 2) {
+            die("unexpected trailing arguments", 2)
+        }
+        source = commandLine.args[0]
+        destination = commandLine.args[1]
+    }
+
+    private fun renameIt(): Unit {
+        val sid = db.makeKey(source)
+        val did = db.makeKey(destination)
+
+        if(!recordExists(sid)) {
+            die("no record matches ${see(source)}")
+        }
+        if (recordExists(did)) {
+            if (commandLine.hasOption(FORCE)) {
+                deleteRecord(did)
+            } else {
+                die("record matching ${see(destination)} already exists")
+            }
+        }
+
+        db.connection.prepareStatement("select username, password, notes, created, modified, accessed from passwords where id = ?").use { sourceStmt ->
+            sourceStmt.setLong(1, did)
+            val result = sourceStmt.executeQuery()
+            result.next()
+            db.connection.prepareStatement("insert into passwords (id, name, username, password, notes, created, modified, accessed) values (?, ?, ?, ?, ?, ?, ?, ?)").run {
+                setLong(1, did)
+                setEncryptedString(2, destination, db.encryption)
+                setBytes(3, result.getBytes(1))
+                setBytes(4, result.getBytes(2))
+                setBytesOrNull(5, result.getBytes(3))
+                setLong(6, result.getLong(4))
+                setLong(7, System.currentTimeMillis())
+                setLongOrNull(8, result.getLong(6))
+                executeUpdate()
+            }
+        }
+
+        deleteRecord(sid)
+    }
+
+    private fun recordExists(id: Long): Boolean {
+        db.connection.prepareStatement("select count(*) from passwords where id = ?").use {
+            it.setLong(1, id)
+            val result = it.executeQuery()
+            result.next()
+            return result.getInt(1) > 0
+        }
+    }
+
+    private fun deleteRecord(id: Long): Unit {
+        db.connection.prepareStatement("delete from passwords where id = ?").use {
+            it.setLong(1, id);
+            it.executeUpdate()
+        }
+    }
+}
\ No newline at end of file