You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

509 lines
13 KiB

--[[
userbouquets - Manage user defined bouquets
Copyright (C) 2016 Sven Hoefer <svenhoefer@svenhoefer.com>
License: WTFPLv2
]]
-- ----------------------------------------------------------------------------
version = 0.12
function script_path()
local str = debug.getinfo(2, "S").source:sub(2)
return str:match("(.*/)")
end
function capitalize(s)
return s:gsub("^%l", string.upper)
end
function add_slash(dir)
-- add trailing slash if needed
if string.sub(dir, -1) ~= "/" then
dir = dir .. "/"
end
return dir
end
function remove_slash(dir)
-- remove trailing slash if needed
if string.sub(dir, -1) == "/" then
dir = dir:sub(1, -2)
end
return dir
end
function showhint(caption, text, icon, timeout)
local caption = caption or "Info"
local text = text or ""
local icon = icon or "information"
local h = hintbox.new{caption=caption, text=text, icon=icon}
h:paint()
delay(5)
h:hide()
end
function delay(timeout)
local timeout = timeout or 2
local i = 0
repeat
i = i + 1
msg, data = n:GetInput(500)
until msg == RC.ok or msg == RC.home or i == (timeout * 2)
end
function check_content(dir)
dir = add_slash(dir)
if not fh:exist(dir .. bouquets_xml, "f") or not fh:exist(dir .. ubouquets_xml, "f")
then
return false
end
return true
end
function check_owner(dir)
dir = add_slash(dir)
if dir == owner_dir
then
return true
end
return false
end
function check_active(dir)
dir = add_slash(dir)
local bouquets_target = fh:readlink(zapit_dir .. bouquets_xml)
if bouquets_target == dir .. bouquets_xml
then
return true
end
return false
end
function get_active_icon(dir)
if check_active(dir) then
return "checkmark"
end
return ""
end
function get_username(dir)
dir = remove_slash(dir)
local name = string.match(dir, "[^/]+$")
if name == "owner" then
name = locale[lang].owner
end
return capitalize(name:gsub("_", " "))
end
function activate(dir)
dir = add_slash(dir)
if check_active(dir) then
showhint(get_username(dir), locale[lang].already_active)
return
end
if not check_content(dir) then
showhint(get_username(dir), locale[lang].content_failed)
return
end
if get_pin(dir) then
fh:ln(dir .. bouquets_xml, zapit_dir .. bouquets_xml, "sf")
fh:ln(dir .. ubouquets_xml, zapit_dir .. ubouquets_xml, "sf")
os.execute("pzapit -c")
end
return MENU_RETURN.EXIT -- force rebuild menu
end
function remove(dir)
dir = add_slash(dir)
if check_owner(dir) then
showhint(get_username(dir), locale[lang].cant_remove_owner)
return
end
if check_active(dir) then
showhint(get_username(dir), locale[lang].cant_remove_active)
return
end
if get_pin(owner_dir) then
fh:rmdir(dir)
showhint(get_username(dir), locale[lang].removed)
end
end
function get_pin(dir)
local pin = read_pin(dir)
if pin == "0000" or pin == "" or pin == nil then
return true
end
local input = input_pin(dir)
if input == pin then
return true
end
showhint(locale[lang].panic, locale[lang].pin_wrong)
return false
end
function set_pin(dir)
dir = add_slash(dir)
local input = input_pin(dir, "new")
--[[
TODO: check input
]]
local f = io.open(dir .. passwd, "w")
f:write(input .. "\n")
f:close()
end
function read_pin(dir)
dir = add_slash(dir)
local f = io.open(dir .. passwd, "rb")
local pin = f:read()
f:close()
--[[
TODO: check pin
]]
return pin
end
function input_pin(dir, new)
dir = remove_slash(dir)
local heading = get_username(dir) .. " - "
if new == "new" then
heading = heading .. locale[lang].pin_new
else
heading = heading .. locale[lang].pin
end
local input = stringinput.exec {
caption=heading,
value="",
valid_chars="0123456789",
pin=1,
size=4
}
return input
end
function pin(dir)
--[[
if check_active(dir) then
showhint(get_username(dir), locale[lang].cant_change_pin)
return
end
]]
if get_pin(dir) then
set_pin(dir)
showhint(get_username(dir), locale[lang].pin_changed)
end
end
function create(id, value)
local user = value
user = add_slash(user)
fh:mkdir(users_dir .. user)
if check_content(owner_dir) then
fh:cp(owner_dir .. bouquets_xml, users_dir .. user, "a")
fh:cp(owner_dir .. ubouquets_xml, users_dir .. user, "a")
end
fh:touch(users_dir .. user .. passwd)
user_new = nil
return MENU_RETURN.EXIT -- force rebuild menu
end
function reset(id, value)
if not check_content(owner_dir) then
showhint(locale[lang].panic, locale[lang].cant_reset_plugin)
return
end
local res = messagebox.exec{title=locale[lang].reset, text=locale[lang].reset_confirm, buttons={ "yes", "no" } }
if res == "yes" then
if not get_pin(owner_dir) then
return
end
os.remove(zapit_dir .. bouquets_xml)
fh:cp(owner_dir .. bouquets_xml, zapit_dir .. bouquets_xml, "f")
os.remove(zapit_dir .. ubouquets_xml)
fh:cp(owner_dir .. ubouquets_xml, zapit_dir .. ubouquets_xml, "f")
fh:rmdir(data_dir)
repaint_menu = false
return MENU_RETURN.EXIT_ALL
end
end
function info()
showhint(locale[lang].caption, locale[lang].info)
end
-- ----------------------------------------------------------------------------
n = neutrino()
m = nil -- the menu
fh = filehelpers.new()
data_dir = "/var/tuxbox/plugins/userbouquets/"
owner_dir = data_dir .. "owner/"
users_dir = data_dir .. "users/"
user_new = nil
zapit_dir = "/var/tuxbox/config/zapit/"
bouquets_xml = "bouquets.xml"
ubouquets_xml = "ubouquets.xml"
passwd = ".passwd"
locale = {}
locale["deutsch"] = {
activate = "Aktivieren",
active = "aktiv",
already_active = "Benutzer ist bereits aktiviert.",
apiversion_failed = "Ihre Lua-API ist zu alt. Bitte Neutrino aktualisieren.",
back = "Zurück",
back_hint = "Zurück zum vorherigen Menü.",
cant_change_pin = "PIN kann beim aktiven Benutzer nicht geändert werden",
cant_remove_active = "Der aktive Benutzer kann nicht entfernt werden.",
cant_remove_owner = "Der Eigentümer darf nicht entfernt werden.",
cant_reset_plugin = "Plugin kann nicht zurückgesetzt werden",
caption = "Benutzer-Bouquets" .. " v" .. version,
content_failed = "Fehler! Verzeichnisinhalt nicht korrekt.",
create = "Neuen Benutzer anlegen",
create_hint = "Erstellt einen neuen Benutzer basierend auf den Eigentümer-Daten",
info = "Ben Uwe lebt!",
no_users = "Keine Benutzer angelegt",
owner = "Eigentümer",
panic = "Panik!",
pin = "PIN",
pin_change = "PIN ändern",
pin_changed = "PIN geändert",
pin_new = "Neue PIN",
pin_wrong = "PIN falsch",
remove = "Entfernen",
removed = "Benutzer wurde entfernt.",
reset = "Plugin zurücksetzen",
reset_confirm = "Es werden alle Benutzer-Bouquets und Plugin-Daten gelöscht.\n \nFortfahren?",
reset_hint = "Entferne Benutzer-Bouquets und Plugin-Daten",
selection = "Aktivieren, entfernen oder PIN ändern?",
selection_hint = "Aktion für den Benutzer wählen",
start_confirm = "Dieses Plugin erlaubt es, die Senderlisten bouquets.xml und\nubouquets.xml je nach Benutzer einzustellen.\nSie können dann unabhängig voneinander verwaltet werden.\n \nLöschen Sie das Plugin nicht, bevor sie es nicht zurückgesetzt haben!\n \nFortfahren?",
users = "Benutzer",
}
locale["english"] = {
activate = "Activate",
active = "active",
already_active = "User is already activated.",
apiversion_failed = "Your Lua-API is too old. Please update Neutrino.",
back = "Back",
back_hint = "Return to previous menu",
cant_change_pin = "PIN can not be changed while user is active",
cant_remove_active = "The active user can not be removed.",
cant_remove_owner = "The owner may not be removed.",
cant_reset_plugin = "Can't reset plugin.",
caption = "Userbouquets" .. " v" .. version,
content_failed = "Error! Directory content not correct.",
create = "Create new user",
create_hint = "Create new user based apon owner data",
info = "Ben Uwe lives!",
no_users = "No users created",
owner = "Owner",
panic = "Panic!",
pin = "PIN",
pin_change = "Change PIN",
pin_changed = "PIN changed",
pin_new = "New PIN",
pin_wrong = "Wrong PIN",
remove = "Remove",
removed = "User was removed.",
reset = "Reset plugin",
reset_confirm = "All user bouquets and plugin data will be removed.\n \nContinue?",
reset_hint = "Remove user bouquets and plugin data",
selection = "Activate, remove or change PIN?",
selection_hint = "Select action for this user",
start_confirm = "This plugin allows to adjust the channellists bouquets.xml and\nubouquets.xml depending on users.\nThey can be managed independently.\n \nDon't remove this plugin before you don't have executed the built-in reset!\n \nContinue?",
users = "Users",
}
local neutrino_conf = configfile.new()
neutrino_conf:loadConfig("/var/tuxbox/config/neutrino.conf")
lang = neutrino_conf:getString("language", "english")
if locale[lang] == nil then
lang = "english"
end
timing_menu = neutrino_conf:getString("timing.menu", "0")
-- ----------------------------------------------------------------------------
function init()
if not check_content(owner_dir) then
local res = messagebox.exec{title=locale[lang].caption, text=locale[lang].start_confirm, buttons={ "yes", "no" } }
if res == "no" then
return false
end
fh:mkdir(owner_dir)
fh:mkdir(users_dir)
fh:cp(zapit_dir .. bouquets_xml, owner_dir, "a")
fh:cp(zapit_dir .. bouquets_xml, zapit_dir .. bouquets_xml .. ".bak", "a")
fh:cp(zapit_dir .. ubouquets_xml, owner_dir, "a")
fh:cp(zapit_dir .. ubouquets_xml, zapit_dir .. ubouquets_xml .. ".bak", "a")
fh:touch(owner_dir .. passwd)
activate(owner_dir)
end
return true
end
function paint_menu()
m = menu.new{name=locale[lang].caption, icon="settings"}
m:addKey{directkey=RC.home, id="home", action="exit_menu"}
m:addKey{directkey=RC.setup, id="setup", action="exit_menu"}
m:addKey{directkey=RC.info, id="info", action="info"}
m:addItem{type="separator"}
m:addItem{type="forwarder", id="home", action="exit_menu", name=locale[lang].back, icon="home", directkey=RC.home, hint_icon="hint_back", hint=locale[lang].back_hint};
m:addItem{type="separatorline"}
m:addItem {
type="forwarder",
action="selection",
enabled=check_content(owner_dir),
id=owner_dir,
name=get_username(owner_dir),
right_icon=get_active_icon(owner_dir),
directkey=RC.red,
hint_icon="hint_service",
hint=locale[lang].selection_hint
}
m:addItem{type="separator"}
user_new = ""
m:addItem {
type="keyboardinput",
action="create",
id="dummy",
value=user_new,
name=locale[lang].create,
directkey=RC.green,
hint_icon="hint_bedit",
hint=locale[lang].create_hint
}
m:addItem{type="separatorline", name=locale[lang].users}
local i = 0
local d = io.popen('find "' .. users_dir .. '" -type d -maxdepth 1 -mindepth 1')
for user_dir in d:lines() do
i = i + 1
m:addItem {
type="forwarder",
action="selection",
enabled=check_content(user_dir),
id=user_dir,
name=get_username(user_dir),
right_icon=get_active_icon(user_dir),
directkey=RC[""..i..""];
hint_icon="hint_service",
hint=locale[lang].selection_hint
}
end
if i == 0 then
m:addItem {
type="forwarder",
enabled=false,
name=locale[lang].no_users,
}
end
m:addItem{type="separatorline"}
m:addItem{type="separator"}
m:addItem {
type="forwarder",
action="reset",
name=locale[lang].reset,
directkey=RC.blue,
hint_icon="hint_delete",
hint=locale[lang].reset_hint
}
m:exec()
--[[
msg, data = n:GetInput(50)
if msg == RC.timeout then
repaint_menu = false
end
]]
end
function hide_menu()
if m ~= nil then
m:hide()
end
end
function exit_menu(id)
repaint_menu = false
if id == "setup" then
return MENU_RETURN.EXIT_ALL
end
return MENU_RETURN.EXIT
end
function selection(dir)
hide_menu()
local dx = n:scale2Res(500)
local dy = n:scale2Res(150)
local x = SCREEN.OFF_X + (((SCREEN.END_X - SCREEN.OFF_X) - dx) / 2)
local y = SCREEN.OFF_Y + (((SCREEN.END_Y - SCREEN.OFF_Y) - dy) / 2)
local t = get_username(dir)
if check_active(dir) then
t = t .. " (" .. locale[lang].active .. ")"
end
local chooser = cwindow.new{x=x, y=y, dx=dx, dy=dy, title=t, icon="settings", has_shadow=true, show_footer=true, btnGreen=locale[lang].activate, btnYellow=locale[lang].remove, btnBlue=locale[lang].pin_change}
ctext.new{parent=chooser, x=n:scale2Res(10), y=0, dx=dx-n:scale2Res(2*10), dy=dy-chooser:headerHeight(), text=locale[lang].selection, font_text=FONT.MENU, mode="ALIGN_CENTER"}
chooser:paint()
local i = 0
local d = 500 -- ms
local t = (timing_menu * 1000) / d
if t == 0 then
t = -1 -- no timeout
end
repeat
i = i + 1
msg, data = n:GetInput(d)
if (msg == RC.ok) or (msg == RC.green) then
activate(dir)
msg = RC.home
elseif (msg == RC.yellow) then
remove(dir)
msg = RC.home
elseif (msg == RC.blue) then
chooser:hide()
pin(dir)
chooser:paint()
end
until msg == RC.home or msg == RC.setup or i == t;
chooser:hide()
chooser = nil
if msg == RC.setup then
repaint_menu = false
return MENU_RETURN.EXIT_ALL
end
return MENU_RETURN.EXIT
end
-- ---------------------------------------------------------------------------
if APIVERSION.MAJOR .. APIVERSION.MINOR < "156" then
local apiversion = "Lua-Api v" .. APIVERSION.MAJOR .. "." .. APIVERSION.MINOR .. "\n \n"
showhint(locale[lang].panic, apiversion .. locale[lang].apiversion_failed)
return
end
if init() then
repaint_menu = true
while repaint_menu do
paint_menu()
end
end