summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Hurst <ark@mansus.space>2025-07-17 10:35:37 +0200
committerJulian Hurst <ark@mansus.space>2025-07-17 10:35:37 +0200
commit121339364c5422565630f540bc251de3b0433bbb (patch)
treee4301ad63e1e5cd82ad0c6eaf3e9b526b56f919e
parentf2e59b061764f6098c07c9ae1132a26f8f063b91 (diff)
parentd92eff17ca73ba9e61edd028de46dcbc078097c0 (diff)
downloadimp-121339364c5422565630f540bc251de3b0433bbb.tar.gz
Merge remote-tracking branch 'origin/add'
-rw-r--r--imp.ha90
1 files changed, 89 insertions, 1 deletions
diff --git a/imp.ha b/imp.ha
index 73c11a9..9c679fe 100644
--- a/imp.ha
+++ b/imp.ha
@@ -5,7 +5,11 @@ use os::exec;
use io;
use strings;
use memio;
+use bufio;
use format::ini;
+use encoding::utf8;
+use unix::tty;
+use errors;
let verbose: bool = false;
@@ -32,6 +36,8 @@ export fn main() void = {
('v', "Verbose mode"),
('l', "List the accounts"),
('p', "Display the account passwords"),
+ ('c', "Print ini config from parsed accounts"),
+ ('a', "Add an account"),
('f', "file", "The accounts file to use (IMP_FILE by default)"),
('g', "groups...", "Filters by a comma-separated list of groups"),
('m', "matches...", "Filters by a comma-separated list of matches"),
@@ -53,11 +59,18 @@ export fn main() void = {
let accfilter = filter {...};
+ let add = false;
+ let printconf = false;
+
for (let i = 0z; i < len(cmd.opts); i += 1) {
let opt = cmd.opts[i];
switch (opt.0) {
case 'v' =>
verbose = true;
+ case 'a' =>
+ add = true;
+ case 'c' =>
+ printconf = true;
case 'p' =>
displaypass = true;
case 'l' =>
@@ -112,9 +125,35 @@ export fn main() void = {
fmt::fatal("Insufficient memory");
};
+ if (add) {
+ const acc = account {
+ ...
+ };
+ const n = getinput("name: ")!;
+ const u = getinput("user: ")!;
+ const p = getinput("pass: ", true)!;
+ const cp = getinput("confirm pass: ", true)!;
+ if (p != cp) {
+ fmt::fatal("Passwords don't match");
+ };
+ if (n == "" || u == "" || p == "") {
+ free(n);
+ free(u);
+ free(p);
+ } else {
+ acc.name = n;
+ acc.user = u;
+ acc.pass = p;
+ append(accounts, acc)!;
+ };
+ };
+
accounts = accs_filter(accounts, accfilter);
defer accounts_free(accounts);
- if (list) {
+
+ if (printconf) {
+ printaccs(os::stdout, accounts);
+ } else if (list) {
for (let i = 0z; i < len(accounts); i += 1) {
let acc = accounts[i];
fmt::println(acc.name)!;
@@ -271,6 +310,24 @@ fn parse(data: []u8) ([]account | format::ini::error | nomem) = {
return accounts;
};
+// Returns the accounts as an ini string. The return value must be freed.
+fn printaccs(h: io::handle, accs: []account) void = {
+ for (let i = 0z; i < len(accs); i += 1) {
+ const acc = accs[i];
+ fmt::fprintf(h, "[{}]\nuser={}\npass={}\n", acc.name, acc.user,
+ acc.pass)!;
+ if (acc.notes != "") {
+ fmt::fprintf(h, "notes={}\n", acc.notes)!;
+ };
+ if (acc.url != "") {
+ fmt::fprintf(h, "match={}\n", acc.url)!;
+ };
+ if (i < len(accs) - 1) {
+ fmt::fprint(h, "\n")!;
+ };
+ };
+};
+
fn setfieldaccount(acc: *account, key: str, val: str) void = {
key = strings::trim(key, ' ');
defer free(key);
@@ -329,3 +386,34 @@ fn decrypt(file: str) ([]u8 | os::exec::error | io::error | nomem) = {
return out;
};
+
+fn readin(termf: io::file) (str | io::error | utf8::invalid | nomem) = {
+ const scanner = bufio::newscanner(termf);
+ defer bufio::finish(&scanner);
+ const line = match (bufio::scan_line(&scanner)?) {
+ case io::EOF =>
+ yield "";
+ case let line: const str =>
+ yield line;
+ };
+ return strings::dup(line)?;
+};
+
+// Gets user input from the tty (supports pipes)
+fn getinput(text: str = "", noecho: bool = false) (str | tty::error | io::error
+ | utf8::invalid | errors::error | nomem) = {
+
+ let termf = tty::open()?;
+ defer io::close(termf)!;
+
+ fmt::fprintf(termf, "{}", text)!;
+
+ if (noecho) {
+ const termios = tty::termios_query(termf)?;
+ tty::noecho(&termios)?;
+ defer tty::termios_restore(&termios);
+ defer fmt::fprintln(termf)!;
+ return readin(termf)?;
+ };
+ return readin(termf)?;
+};