Mercurial > cgi-bin > hgweb.cgi > PassMan
annotate src/main/kotlin/name/blackcap/passman/ExportSubcommand.kt @ 22:07406c4af4a5
More interactive mode stuff.
author | David Barts <n5jrn@me.com> |
---|---|
date | Tue, 02 Jul 2024 17:34:52 -0700 |
parents | ea65ab890f66 |
children |
rev | line source |
---|---|
16 | 1 package name.blackcap.passman |
2 | |
3 import com.opencsv.CSVWriterBuilder | |
4 import com.opencsv.ICSVWriter | |
5 import java.io.FileOutputStream | |
6 import java.io.IOException | |
7 import java.io.OutputStreamWriter | |
8 import java.sql.ResultSet | |
9 import java.text.SimpleDateFormat | |
10 import java.util.* | |
11 | |
12 class ExportSubcommand() : Subcommand() { | |
13 private companion object { | |
14 const val NULL = "null" | |
15 } | |
16 private lateinit var csvDateFormat: SimpleDateFormat | |
17 private lateinit var db: Database | |
18 private val options = ImportExportArguments() | |
19 private lateinit var csvFile: String | |
20 | |
22 | 21 override fun run(args: Array<String>) { |
16 | 22 parseArguments(args) |
21
ea65ab890f66
More work to support interactive feature.
David Barts <n5jrn@me.com>
parents:
16
diff
changeset
|
23 db = Database.default |
16 | 24 try { |
25 doExport() | |
26 } catch (e: IOException) { | |
21
ea65ab890f66
More work to support interactive feature.
David Barts <n5jrn@me.com>
parents:
16
diff
changeset
|
27 throw SubcommandException(message = e.message ?: "I/O error", cause = e) |
16 | 28 } |
29 } | |
30 | |
31 private fun parseArguments(args: Array<String>) { | |
32 val params = parseInto("export", args, options) | |
33 when (params.size) { | |
21
ea65ab890f66
More work to support interactive feature.
David Barts <n5jrn@me.com>
parents:
16
diff
changeset
|
34 0 -> throw SubcommandException(message = "expecting CSV file name", status = 2) |
16 | 35 1 -> csvFile = params[0] |
21
ea65ab890f66
More work to support interactive feature.
David Barts <n5jrn@me.com>
parents:
16
diff
changeset
|
36 else -> throw SubcommandException(message = "unexpected trailing arguments", status = 2) |
16 | 37 } |
38 csvDateFormat = SimpleDateFormat(options.format).apply { | |
39 timeZone = TimeZone.getTimeZone(options.zone) | |
40 isLenient = false | |
41 } | |
42 } | |
43 | |
44 private fun doExport() { | |
45 val csvWriter = CSVWriterBuilder(OutputStreamWriter(FileOutputStream(csvFile), options.charset)) | |
46 .withEscapeChar(options.escape) | |
47 .withQuoteChar(options.quote) | |
48 .withSeparator(options.separator) | |
49 .withLineEnd(ICSVWriter.RFC4180_LINE_END) | |
50 .build() | |
51 | |
52 try { | |
53 db.connection.prepareStatement("select name, username, password, notes, created, modified, accessed from passwords").use { | |
54 val results = it.executeQuery() | |
55 while (results.next()) { | |
56 val entry = arrayOf<String>( | |
57 results.getDecryptedString(1, db.encryption)!!, | |
58 results.getDecryptedString(2, db.encryption)!!, | |
59 results.getDecryptedString(3, db.encryption)!!, | |
60 results.getDecryptedString(4, db.encryption) ?: NULL, | |
61 results.getTimeString(5), | |
62 results.getTimeString(6), | |
63 results.getTimeString(7) | |
64 ) | |
65 csvWriter.writeNext(entry) | |
66 } | |
67 } | |
68 } finally { | |
69 csvWriter.close() | |
70 } | |
71 } | |
72 | |
73 private fun ResultSet.getTimeString(columnIndex: Int): String { | |
74 val value = getDate(columnIndex) | |
75 return if (value == null) NULL else csvDateFormat.format(value) | |
76 } | |
21
ea65ab890f66
More work to support interactive feature.
David Barts <n5jrn@me.com>
parents:
16
diff
changeset
|
77 } |