diff src/main/kotlin/name/blackcap/passman/ExportSubcommand.kt @ 16:7a74ae668665

Add export subcommand.
author David Barts <n5jrn@me.com>
date Sun, 05 Feb 2023 10:50:39 -0800
parents
children ea65ab890f66
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/kotlin/name/blackcap/passman/ExportSubcommand.kt	Sun Feb 05 10:50:39 2023 -0800
@@ -0,0 +1,77 @@
+package name.blackcap.passman
+
+import com.opencsv.CSVWriterBuilder
+import com.opencsv.ICSVWriter
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.OutputStreamWriter
+import java.sql.ResultSet
+import java.text.SimpleDateFormat
+import java.util.*
+
+class ExportSubcommand() : Subcommand() {
+    private companion object {
+        const val NULL = "null"
+    }
+    private lateinit var csvDateFormat: SimpleDateFormat
+    private lateinit var db: Database
+    private val options = ImportExportArguments()
+    private lateinit var csvFile: String
+
+    override fun run(args: Array<String>) {
+        parseArguments(args)
+        db = Database.open()
+        try {
+            doExport()
+        } catch (e: IOException) {
+            die(e.message ?: "I/O error")
+        }
+    }
+
+    private fun parseArguments(args: Array<String>) {
+        val params = parseInto("export", args, options)
+        when (params.size) {
+            0 -> die("expecting CSV file name", 2)
+            1 -> csvFile = params[0]
+            else -> die("unexpected trailing arguments", 2)
+        }
+        csvDateFormat = SimpleDateFormat(options.format).apply {
+            timeZone = TimeZone.getTimeZone(options.zone)
+            isLenient = false
+        }
+    }
+
+    private fun doExport() {
+        val csvWriter = CSVWriterBuilder(OutputStreamWriter(FileOutputStream(csvFile), options.charset))
+            .withEscapeChar(options.escape)
+            .withQuoteChar(options.quote)
+            .withSeparator(options.separator)
+            .withLineEnd(ICSVWriter.RFC4180_LINE_END)
+            .build()
+
+        try {
+            db.connection.prepareStatement("select name, username, password, notes, created, modified, accessed from passwords").use {
+                val results = it.executeQuery()
+                while (results.next()) {
+                    val entry = arrayOf<String>(
+                        results.getDecryptedString(1, db.encryption)!!,
+                        results.getDecryptedString(2, db.encryption)!!,
+                        results.getDecryptedString(3, db.encryption)!!,
+                        results.getDecryptedString(4, db.encryption) ?: NULL,
+                        results.getTimeString(5),
+                        results.getTimeString(6),
+                        results.getTimeString(7)
+                        )
+                    csvWriter.writeNext(entry)
+                }
+            }
+        } finally {
+            csvWriter.close()
+        }
+    }
+
+    private fun ResultSet.getTimeString(columnIndex: Int): String {
+        val value = getDate(columnIndex)
+        return if (value == null) NULL else csvDateFormat.format(value)
+    }
+}
\ No newline at end of file