#!/usr/bin/env lua basepath = (debug.getinfo(1, "S").source:sub(2):match("(.*[/\\])") or "./"):sub(1,-2) local entryBackups = {} local function makeEntryBackup(id) if entryBackups[id] ~= nil then return end env.run({"entry_backup",id}) entryBackups[id] = true end local function eprint(text) io.stderr:write(text .. "\n") end local function input(id,text) if text == nil then text = "" end io.stderr:write("[" ..id.. "] " .. text) local input = os.getenv("prpw_" .. id) if input ~= nil then eprint(input) return input else return io.read() end end local function yn(id,question) io.stderr:write(question .. " - y/n: ") local inp = false while true do inp = string.lower(input(id)) if ( inp == "y" or inp == "n" ) then break end end return (inp == "y") end local function menu(id,choices) for i,v in ipairs(choices) do eprint(tostring(i).. ": " ..tostring(v)) end local choice = false while true do choice = tonumber(input("menu_" ..id,"Choice: ")) if not ( choice == nil or choice < 1 or choice > #choices or math.floor(choice) ~= choice ) then break end end return choice end local function emenu(id,title,choices,functions,lastSelection) if lastSelection == nil then lastSelection = "<- BACK" end table.insert(choices,lastSelection) while true do eprint(title) i = menu(id,choices) if i == #choices then return end eprint("") functions[i]() eprint("") end end local function fieldPrint(entry,field) io.write(env.run({"field_get",entry.attrs.id,field.attrs.name})) eprint("") end local function fieldPrintType(entry,field) eprint(env.run({"field_get_type",entry.attrs.id,field.attrs.name})) end local function fieldSetText(entry,field) local text = input("field_set_text","Text: ") makeEntryBackup(entry.attrs.id) env.run({"field_set",entry.attrs.id,field.attrs.name,text}) env.run({"save"}) end local function fieldSetType(entry,field) local tp = input("field_set_type","Type: ") makeEntryBackup(entry.attrs.id) env.run({"field_set_type",entry.attrs.id,field.attrs.name,tp}) env.run({"save"}) end local function fieldRemove(entry,field) if not yn("field_remove","Do you want to remove the field '" ..field.attrs.name.. "'?") then return end makeEntryBackup(entry.attrs.id) env.run({"field_remove",entry.attrs.id,field.attrs.name}) env.run({"save"}) end local function fieldImportFile(entry,field) local fpath = input("field_import_file","File path: ") local fh = io.open(fpath,"r") if fh == nil then eprint("Error opening file, make sure to remove any \" or '.") return end local bytes = fh:read("*a") fh:close() local base64 = require("base64") bytes = base64.encode(bytes) makeEntryBackup(entry.attrs.id) env.run({"field_set",entry.attrs.id,field.attrs.name,bytes}) bytes = nil collectgarbage("collect") env.run({"save"}) end local function fieldExportFile(entry,field) local fpath = input("field_export_file","File path: ") local fh = io.open(fpath,"r") if fh ~= nil then fh:close() eprint("Error: file already exists.") return end fh = io.open(fpath,"w") if fh == nil then eprint("Error opening file, make sure to remove any \" or '.") return end local bytes = env.run({"field_get",entry.attrs.id,field.attrs.name}) local base64 = require("base64") bytes = base64.decode(bytes) fh:write(bytes) fh:close() bytes = nil collectgarbage("collect") end local function fieldRename(entry,field) local fieldName = input("field_rename","New field name: ") makeEntryBackup(entry.attrs.id) env.run({"field_rename",entry.attrs.id,field.attrs.name,fieldName}) env.run({"save"}) end local function fieldActions(entry,field) emenu( "field_action", "Field '" ..field.attrs.name.. "':", { "Print value + exit", "Print value", "Print type", "Set value", "Set type", "Import file", "Export file", "Rename", "Remove" }, { function() fieldPrint(entry,field); os.exit(0) end, function() fieldPrint(entry,field) end, function() fieldPrintType(entry,field) end, function() fieldSetText(entry,field) end, function() fieldSetType(entry,field) end, function() fieldImportFile(entry,field) end, function() fieldExportFile(entry,field) end, function() fieldRename(entry,field) end, function() fieldRemove(entry,field) end } ) end local function fieldsActions(entry) local fields = env.run({"field_list",entry.attrs.id}) local funcs = {} for i,field in pairs(fields) do fields[i] = field.attrs.name; table.insert(funcs,function() fieldActions(entry,field) end) end emenu("field_select","Fields:",fields,funcs) end local function fieldAdd(entry) local fieldName = input("field_add","Field name: ") makeEntryBackup(entry.attrs.id) env.run({"field_set",entry.attrs.id,fieldName,""}) env.run({"save"}) end local function entryRename(entry) local entryName = input("entry_rename","New entry name: ") makeEntryBackup(entry.attrs.id) env.run({"entry_rename",entry.attrs.id,entryName}) env.run({"save"}) end local function entryRemove(entry) if not yn("entry_remove","Do you want to remove the entry '" ..entry.attrs.name.. "'?") then return end env.run({"entry_remove",entry.attrs.id}) env.run({"save"}) end local function manageEntry(entry) emenu( "manage_entry", "Entry - " ..entry.attrs.name.. ":", { "Field add", "Fields", "Entry rename", "Entry remove" }, { function() fieldAdd(entry) end, function() fieldsActions(entry) end, function() entryRename(entry) end, function() entryRemove(entry) end } ) end local function searchByName() local entries = {} local entriesMenu = {} local name = string.lower(input("search_by_name","Name: ")) for i,entry in pairs(env.xmlFindTags(env.db,"entries")[1].children) do if string.find(string.lower(entry.attrs.name),name) ~= nil then table.insert(entries,function() manageEntry(entry) end) local username = nil pcall(function() username = env.run({"field_get",entry.attrs.id,"username"}) end) local output = entry.attrs.name if username ~= nil then output = output .. " (" .. username .. ")" end table.insert(entriesMenu,output) end end emenu("entry_select","Found entries:",entriesMenu,entries) end local function search() emenu( "search_entry_by", "Search entry by ...", { "Name", "All non-secret field contents", "Field content", "List all" }, { searchByName, searchByFields, -- todo searchByField, -- todo listAll -- todo } ) end local function main(arg) package.path = basepath .. "/lib/?.lua;" .. basepath .. "/lib/?/main.lua;" .. package.path require("prpw") env.cli = false env.run({"open",arg[1]}) if flag_copyonly then search() return end emenu( "entries_action", "Action:", { "Search entry", "Create entry" }, { search, createEntry -- todo }, "<- EXIT" ) end main(arg)