1
0
mirror of https://github.com/20kdc/OC-KittenOS.git synced 2024-11-26 12:28:05 +11:00

Compare commits

..

No commits in common. "7d1f6d2caec190e14bd5db76054380d922f99eec" and "5ac8f9ff117f638e47c6058ea109de94629ee842" have entirely different histories.

9 changed files with 194 additions and 466 deletions

View File

@ -55,7 +55,7 @@ return {
}, },
["neo-everest"] = { ["neo-everest"] = {
desc = "KittenOS NEO / Everest (windowing)", desc = "KittenOS NEO / Everest (windowing)",
v = 9, v = 5,
deps = { deps = {
"neo" "neo"
}, },
@ -68,7 +68,7 @@ return {
}, },
["neo-icecap"] = { ["neo-icecap"] = {
desc = "KittenOS NEO / Icecap", desc = "KittenOS NEO / Icecap",
v = 9, v = 8,
deps = { deps = {
"neo" "neo"
}, },
@ -85,7 +85,7 @@ return {
}, },
["neo-secpolicy"] = { ["neo-secpolicy"] = {
desc = "KittenOS NEO / Secpolicy", desc = "KittenOS NEO / Secpolicy",
v = 9, v = 8,
deps = { deps = {
}, },
dirs = { dirs = {

View File

@ -3,16 +3,12 @@
local _, _, termId = ... local _, _, termId = ...
local ok = pcall(function () local ok = pcall(function ()
assert(string.sub(termId, 1, 12) == "x.neo.pub.t/") assert(string.sub(termId, 1, 8) == "x.svc.t/")
end) end)
local termClose
if not ok then if not ok then
termId = nil termId = nil
neo.executeAsync("svc-t", function (res) neo.executeAsync("svc-t", function (res)
termId = res.access termId = res.access
termClose = res.close
neo.scheduleTimer(0) neo.scheduleTimer(0)
end, "luashell") end, "luashell")
while not termId do while not termId do
@ -21,105 +17,25 @@ if not ok then
end end
TERM = neo.requireAccess(termId, "terminal") TERM = neo.requireAccess(termId, "terminal")
-- Using event makes it easier for stuff TERM.line("KittenOS NEO Lua Shell")
-- within the shell to not spectacularly explode.
event = require("event")(neo)
local alive = true
event.listen("k.procdie", function (_, _, pid)
if pid == TERM.pid then
alive = false
end
end)
TERM.write(([[
KittenOS NEO Shell Usage Notes
Prefixing = is an alias for 'return '.
io.read(): Reads a line.
print: 'print with table dumping' impl.
TERM: Your terminal. (see us-termi doc.)
os.execute(): launch terminal apps!
tries '*', 'sys-t-*', 'svc-t-*', 'app-*'
example: os.execute("luashell")
os.exit(): quit the shell
=listCmdApps(): -t- (terminal) apps
event: useful for setting up listeners
without breaking shell functionality
]]):gsub("[\r]*\n", "\r\n"))
function listCmdApps()
local apps = {}
for _, v in ipairs(neo.listApps()) do
if v:sub(4, 6) == "-t-" then
table.insert(apps, v)
end
end
return apps
end
local function vPrint(slike, ...)
local s = {...}
if #s > 1 then
for i = 1, #s do
if i ~= 1 then TERM.write("\t") end
vPrint(slike, s[i])
end
elseif slike and type(s[1]) == "string" then
TERM.write("\"" .. s[1] .. "\"")
elseif type(s[1]) ~= "table" then
TERM.write(tostring(s[1]))
else
TERM.write("{")
for k, v in pairs(s[1]) do
TERM.write("[")
vPrint(true, k)
TERM.write("] = ")
vPrint(true, v)
TERM.write(", ")
end
TERM.write("}")
end
end
print = function (...) print = function (...)
vPrint(false, ...) local n = {}
TERM.write("\r\n") local s = {...}
for i = 1, #s do
local v = s[i]
if v == nil then
v = "nil"
end
table.insert(n, tostring(v))
end
TERM.line(table.concat(n, " "))
end end
local ioBuffer = "" local alive = true
io = { run = function (x, ...)
read = function () local subPid = neo.executeAsync(x, ...)
while alive do
local pos = ioBuffer:find("\n")
if pos then
local line = ioBuffer:sub(1, pos):gsub("\r", "")
ioBuffer = ioBuffer:sub(pos + 1)
return line
end
local e = {event.pull()}
if e[1] == TERM.id then
if e[2] == "data" then
ioBuffer = ioBuffer .. e[3]
end
end
end
end,
write = function (s) TERM.write(s) end
}
local originalOS = os
os = setmetatable({}, {
__index = originalOS
})
function os.exit()
alive = false
end
function os.execute(x, ...)
local subPid = neo.executeAsync(x, TERM.id, ...)
if not subPid then if not subPid then
subPid = neo.executeAsync("sys-t-" .. x, TERM.id, ...) subPid = neo.executeAsync("sys-t-" .. x, TERM.id, ...)
end end
@ -133,32 +49,40 @@ function os.execute(x, ...)
error("cannot find " .. x) error("cannot find " .. x)
end end
while true do while true do
local e = {event.pull()} local e = {coroutine.yield()}
if e[1] == "k.procdie" then if e[1] == "k.procdie" then
if e[3] == subPid then if e[3] == TERM.pid then
alive = false
return
elseif e[3] == subPid then
return return
end end
end end
end end
end end
while alive do exit = function ()
TERM.write("> ") alive = false
local code = io.read()
if code then
local ok, err = pcall(function ()
if code:sub(1, 1) == "=" then
code = "return " .. code:sub(2)
end end
print(assert(load(code))())
while alive do
local e = {coroutine.yield()}
if e[1] == "k.procdie" then
if e[3] == TERM.pid then
alive = false
end
elseif e[1] == TERM.id then
if e[2] == "line" then
TERM.line("> " .. e[3])
local ok, err = pcall(function ()
if e[3]:sub(1, 1) == "=" then
e[3] = "return " .. e[3]:sub(2)
end
print(assert(load(e[3]))())
end) end)
if not ok then if not ok then
TERM.write(tostring(err) .. "\r\n") TERM.line(tostring(err))
end end
end end
end end
if termClose then
termClose()
end end

View File

@ -15,224 +15,66 @@ local function rW()
return string.format("%04x", math.random(0, 65535)) return string.format("%04x", math.random(0, 65535))
end end
local id = "neo.pub.t/" .. rW() .. rW() .. rW() .. rW() local id = "svc.t/" .. rW() .. rW() .. rW() .. rW()
local closeNow = false local closeNow = false
-- Terminus Registration State --
local tReg = neo.requireAccess("r." .. id, "registration") local tReg = neo.requireAccess("r." .. id, "registration")
local sendSigs = {}
-- Display State -- -- unicode.safeTextFormat'd lines
-- unicode.safeTextFormat'd lines.
-- The size of this must not go below 1.
local console = {} local console = {}
-- This must not go below 3.
local conW = 40
local conCX, conCY = 1, 1
for i = 1, 14 do for i = 1, 14 do
console[i] = (" "):rep(conW) console[i] = (" "):rep(40)
end end
-- Line Editing State -- local l15 = ""
-- Nil if line editing is off. --++++++++++++++++++++++++++++++++++++++++
-- In this case, the console height
-- must be adjusted accordingly. -- sW must not go below 3.
local leText = "" -- sH must not go below 2.
-- These are NOT nil'd out, local sW, sH = 40, 15
-- particularly not the history buffer. local cX = 1
local leCX = 1 local windows = neo.requireAccess("x.neo.pub.window", "windows")
local leHistory = { local window = windows(sW, sH, title)
-- Size = history buffer size
"", "", "", "" local function fmtLine(s)
} s = unicode.safeTextFormat(s)
local function cycleHistoryUp() local l = unicode.len(s)
local backupFirst = leHistory[1] return unicode.sub(s .. (" "):rep(sW - l), -sW)
for i = 1, #leHistory - 1 do
leHistory[i] = leHistory[i + 1]
end
leHistory[#leHistory] = backupFirst
end
local function cycleHistoryDown()
local backup = leHistory[1]
for i = 2, #leHistory do
backup, leHistory[i] = leHistory[i], backup
end
leHistory[1] = backup
end end
-- Window -- local function line(i)
local l, c = console[i] or l15
local window = neo.requireAccess("x.neo.pub.window", "window")(conW, #console + 1, title) l, c = unicode.safeTextFormat(l, cX)
l = require("lineedit").draw(sW, l, i == sH and c)
-- Core Terminal Functions -- if i ~= sH then
window.span(1, i, l, 0xFFFFFF, 0)
local function setSize(w, h)
conW = w
while #console < h do
table.insert(console, "")
end
while #console > h do
table.remove(console, 1)
end
for i = 1, #console do
console[i] = unicode.sub(console[i], 1, w) .. (" "):rep(w - unicode.len(console[i]))
end
if leText then
window.setSize(w, h + 1)
else else
window.setSize(w, h) window.span(1, i, l, 0, 0xFFFFFF)
end
conCX, conCY = 1, h
end
local function setLineEditing(state)
if state and not leText then
leText = ""
leCX = 1
setSize(conW, #console)
elseif leText and not state then
leText = nil
setSize(conW, #console)
end end
end end
local function draw(i) local function incoming(s)
if console[i] then local function shift(f)
window.span(1, i, console[i], 0, 0xFFFFFF)
elseif leText then
window.span(1, i, require("lineedit").draw(conW, unicode.safeTextFormat(leText, leCX)), 0xFFFFFF, 0)
end
end
local function drawDisplay()
for i = 1, #console do draw(i) end
end
-- Terminal Visual --
local function writeFF()
if conCY ~= #console then
conCY = conCY + 1
else
for i = 1, #console - 1 do for i = 1, #console - 1 do
console[i] = console[i + 1] console[i] = console[i + 1]
end end
console[#console] = (" "):rep(conW) console[#console] = f
end
-- Need to break this safely.
shift("")
for i = 1, unicode.len(s) do
local ch = unicode.sub(s, i, i)
if unicode.wlen(console[#console] .. ch) > sW then
shift(" ")
end
console[#console] = console[#console] .. ch
end
for i = 1, #console do
line(i)
end end
end end
local function writeData(data) local sendSigs = {}
-- handle data until completion
while #data > 0 do
local char = unicode.sub(data, 1, 1)
data = unicode.sub(data, 2)
-- handle character
if char == "\t" then
-- not ideal, but allowed
char = " "
end
if char == "\r" then
conCX = 1
elseif char == "\n" then
conCX = 1
writeFF()
elseif char == "\a" then
-- Bell (er...)
elseif char == "\b" then
conCX = math.max(1, conCX - 1)
elseif char == "\v" or char == "\f" then
writeFF()
else
local charL = unicode.wlen(char)
if (conCX + charL - 1) > conW then
conCX = 1
writeFF()
end
local spaces = (" "):rep(charL - 1)
console[conCY] = unicode.sub(console[conCY], 1, conCX - 1) .. char .. spaces .. unicode.sub(console[conCY], conCX + charL)
conCX = conCX + charL
end
end
end
-- The Terminus --
local tvBuildingCmd = ""
local tvBuildingUTF = ""
local tvSubnegotiation = false
local function incoming(s)
tvBuildingCmd = tvBuildingCmd .. s
-- Flush Cmd
while #tvBuildingCmd > 0 do
if tvBuildingCmd:byte() == 255 then
-- It's a command. Uhoh.
if #tvBuildingCmd < 2 then break end
local cmd = tvBuildingCmd:byte(2)
local param = tvBuildingCmd:byte(3)
local cmdLen = 2
-- Command Lengths
if cmd >= 251 and cmd <= 254 then cmdLen = 3 end
if #tvBuildingCmd < cmdLen then break end
if cmd == 240 then
-- SE
tvSubnegotiation = false
elseif cmd == 250 then
-- SB
tvSubnegotiation = true
elseif cmd == 251 and param == 1 then
-- WILL ECHO (respond with DO ECHO, disable line editing)
-- test using io.write("\xFF\xFB\x01")
for _, v in pairs(sendSigs) do
v("telnet", "\xFF\xFD\x01")
end
setLineEditing(false)
elseif cmd == 252 and param == 1 then
-- WON'T ECHO (respond with DON'T ECHO, enable line editing)
for _, v in pairs(sendSigs) do
v("telnet", "\xFF\xFE\x01")
end
setLineEditing(true)
elseif cmd == 251 or cmd == 252 then
-- WILL/WON'T (x) (respond with DON'T (X))
local res = "\xFF\xFE" .. string.char(param)
for _, v in pairs(sendSigs) do
v("telnet", res)
end
elseif cmd == 253 or cmd == 254 then
-- DO/DON'T (x) (respond with WON'T (X))
local res = "\xFF\xFC" .. string.char(param)
for _, v in pairs(sendSigs) do
v("telnet", res)
end
elseif cmd == 255 then
if not tvSubnegotiation then
tvBuildingUTF = tvBuildingUTF .. "\xFF"
end
end
tvBuildingCmd = tvBuildingCmd:sub(cmdLen + 1)
else
if not tvSubnegotiation then
tvBuildingUTF = tvBuildingUTF .. tvBuildingCmd:sub(1, 1)
end
tvBuildingCmd = tvBuildingCmd:sub(2)
end
end
-- Flush UTF
while #tvBuildingUTF > 0 do
local head = tvBuildingUTF:byte()
local len = 1
if head >= 192 and head < 224 then len = 2 end
if head >= 224 and head < 240 then len = 3 end
if head >= 240 and head < 248 then len = 4 end
if head >= 248 and head < 252 then len = 5 end
if head >= 252 and head < 254 then len = 6 end
if #tvBuildingUTF < len then break end
-- verified one full character...
local char = tvBuildingUTF:sub(1, len)
tvBuildingUTF = tvBuildingUTF:sub(len + 1)
writeData(char)
end
end
do do
tReg(function (_, pid, sendSig) tReg(function (_, pid, sendSig)
@ -240,12 +82,11 @@ do
return { return {
id = "x." .. id, id = "x." .. id,
pid = neo.pid, pid = neo.pid,
write = function (text) line = function (text)
incoming(tostring(text)) incoming(tostring(text))
drawDisplay()
end end
} }
end, true) end)
if retTbl then if retTbl then
coroutine.resume(coroutine.create(retTbl), { coroutine.resume(coroutine.create(retTbl), {
@ -258,72 +99,55 @@ do
end end
end end
local control = false -- This decides the history buffer size.
local history = {
"", "", "", ""
}
local function cycleHistoryUp()
local backupFirst = history[1]
for i = 1, #history - 1 do
history[i] = history[i + 1]
end
history[#history] = backupFirst
end
local function cycleHistoryDown()
local backup = history[1]
for i = 2, #history do
backup, history[i] = history[i], backup
end
history[1] = backup
end
local function key(a, c) local function key(a, c)
if control then if c == 200 then
if e[5] == 203 and conW > 8 then
setSize(conW - 1, #console)
return
elseif e[5] == 200 and #console > 1 then
setSize(conW, #console - 1)
return
elseif e[5] == 205 then
setSize(conW + 1, #console)
return
elseif e[5] == 208 then
setSize(conW, #console + 1)
return
end
end
-- so with the reserved ones dealt with...
if not leText then
-- Line Editing not active.
-- For now support a bare minimum.
for _, v in pairs(sendSigs) do
if control then
if a == 99 then
v("telnet", "\xFF\xF4")
end
elseif a == "\r" then
v("data", "\r\n")
elseif a then
v("data", a)
end
end
elseif not control then
-- Line Editing active and control isn't involved
if c == 200 or c == 208 then
-- History cursor up (history down) -- History cursor up (history down)
leText = leHistory[#leHistory] l15 = history[#history]
leCX = unicode.len(leText) + 1 cX = 1
if c == 208 then
cycleHistoryUp()
else
cycleHistoryDown() cycleHistoryDown()
end return
elseif c == 208 then
-- History cursor down (history up)
l15 = history[#history]
cX = 1
cycleHistoryUp()
return return
end end
local lT, lC, lX = require("lineedit").key(a, c, leText, leCX) local lT, lC, lX = require("lineedit").key(a, c, l15, cX)
leText = lT or leText l15 = lT or l15
leCX = lC or leCX cX = lC or cX
if lX == "nl" then if lX == "nl" then
cycleHistoryUp() cycleHistoryUp()
leHistory[#leHistory] = leText history[#history] = l15
-- the whole thing {
local fullText = leText .. "\r\n"
writeData(fullText)
drawDisplay()
for _, v in pairs(sendSigs) do for _, v in pairs(sendSigs) do
v("data", fullText) v("line", l15)
end
-- }
leText = ""
leCX = 1
end end
l15 = ""
cX = 1
end end
end end
local control = false
while not closeNow do while not closeNow do
local e = {coroutine.yield()} local e = {coroutine.yield()}
if e[1] == "k.procdie" then if e[1] == "k.procdie" then
@ -341,16 +165,32 @@ while not closeNow do
key(c, 0) key(c, 0)
end end
end end
draw(#console + 1) line(sH)
elseif e[3] == "key" then elseif e[3] == "key" then
if e[5] == 29 or e[5] == 157 then if e[5] == 29 or e[5] == 157 then
control = e[6] control = e[6]
elseif e[6] then elseif e[6] then
if not control then
key(e[4] ~= 0 and unicode.char(e[4]), e[5]) key(e[4] ~= 0 and unicode.char(e[4]), e[5])
draw(#console + 1) line(sH)
elseif e[5] == 203 and sW > 8 then
sW = sW - 1
window.setSize(sW, sH)
elseif e[5] == 200 and sH > 2 then
sH = sH - 1
table.remove(console, 1)
window.setSize(sW, sH)
elseif e[5] == 205 then
sW = sW + 1
window.setSize(sW, sH)
elseif e[5] == 208 then
sH = sH + 1
table.insert(console, 1, "")
window.setSize(sW, sH)
end
end end
elseif e[3] == "line" then elseif e[3] == "line" then
draw(e[4]) line(e[4])
end end
end end
end end

View File

@ -616,7 +616,7 @@ local function key(ku, ka, kc, down)
elseif kc == 56 then elseif kc == 56 then
isAltDown = down isAltDown = down
end end
if isAltDown and ka == 122 then if isAltDown and kc == 122 then
if focus and down then if focus and down then
local n = table.remove(surfaces, 1) local n = table.remove(surfaces, 1)
table.insert(surfaces, n) table.insert(surfaces, n)

View File

@ -81,12 +81,20 @@ local function getPfx(xd, pkg)
end end
end end
local function splitAC(ac) local endAcPattern = "/[a-z0-9/%.]*$"
local sb = ac:match("/[a-z0-9/%.]*$")
if sb then local function matchesSvc(xd, pkg, perm)
return ac:sub(1, #ac - #sb), sb local pfx = getPfx(xd, pkg)
if pfx then
local permAct = perm
local paP = permAct:match(endAcPattern)
if paP then
permAct = permAct:sub(1, #permAct - #paP)
end
if permAct == pfx then
return "allow"
end
end end
return ac
end end
donkonitDFProvider(function (pkg, pid, sendSig) donkonitDFProvider(function (pkg, pid, sendSig)
@ -122,8 +130,7 @@ donkonitDFProvider(function (pkg, pid, sendSig)
myApi = getPfx("", pkg), myApi = getPfx("", pkg),
lockPerm = function (perm) lockPerm = function (perm)
-- Are we allowed to? -- Are we allowed to?
local permPfx, detail = splitAC(perm) if not matchesSvc("x.", pkg, perm) then
if getPfx("x.", pkg) ~= permPfx then
return false, "You don't own this permission." return false, "You don't own this permission."
end end
local set = "perm|*|" .. perm local set = "perm|*|" .. perm
@ -216,11 +223,7 @@ local function secPolicyStage2(pid, proc, perm, req)
-- Push to ICECAP thread to avoid deadlock b/c wrong event-pull context -- Push to ICECAP thread to avoid deadlock b/c wrong event-pull context
neo.scheduleTimer(0) neo.scheduleTimer(0)
table.insert(todo, function () table.insert(todo, function ()
local fPerm = perm local ok, err = pcall(secpol, nexus, settings, proc.pkg, pid, perm, req, matchesSvc)
if fPerm:sub(1, 2) == "r." then
fPerm = splitAC(fPerm)
end
local ok, err = pcall(secpol, nexus, settings, proc.pkg, pid, fPerm, req, getPfx("", proc.pkg))
if not ok then if not ok then
neo.emergency("Used fallback policy because of run-err: " .. err) neo.emergency("Used fallback policy because of run-err: " .. err)
req(def) req(def)
@ -240,7 +243,11 @@ rootAccess.securityPolicy = function (pid, proc, perm, req)
end end
-- Do we need to start it? -- Do we need to start it?
if perm:sub(1, 6) == "x.svc." and not neo.usAccessExists(perm) then if perm:sub(1, 6) == "x.svc." and not neo.usAccessExists(perm) then
local appAct = splitAC(perm:sub(3)) local appAct = perm:sub(7)
local paP = appAct:match(endAcPattern)
if paP then
appAct = appAct:sub(1, #appAct - #paP)
end
-- Prepare for success -- Prepare for success
onReg[perm] = onReg[perm] or {} onReg[perm] = onReg[perm] or {}
local orp = onReg[perm] local orp = onReg[perm]

View File

@ -459,7 +459,7 @@ function retrieveAccess(perm, pkg, pid)
accesses[uid] = function (pkg, pid) accesses[uid] = function (pkg, pid)
return nil return nil
end end
return function (f, secret) return function (f)
-- Registration function -- Registration function
ensureType(f, "function") ensureType(f, "function")
local accessObjectCache = {} local accessObjectCache = {}
@ -481,10 +481,8 @@ function retrieveAccess(perm, pkg, pid)
end end
-- returns nil and fails -- returns nil and fails
end end
if not secret then
-- Announce registration -- Announce registration
distEvent(nil, "k.registration", uid) distEvent(nil, "k.registration", uid)
end
end, function () end, function ()
-- Registration becomes null (access is held but other processes cannot retrieve object) -- Registration becomes null (access is held but other processes cannot retrieve object)
if accesses[uid] then if accesses[uid] then

View File

@ -11,19 +11,13 @@
-- IRC is usually pretty safe, but no guarantees. -- IRC is usually pretty safe, but no guarantees.
-- Returns "allow", "deny", or "ask". -- Returns "allow", "deny", or "ask".
local function actualPolicy(pkg, pid, perm, pkgSvcPfx) local function actualPolicy(pkg, pid, perm, matchesSvc)
-- System stuff is allowed. -- System stuff is allowed.
if pkg:sub(1, 4) == "sys-" then if pkg:sub(1, 4) == "sys-" then
return "allow" return "allow"
end end
-- svc-t's job is solely to emulate terminals
-- TO INSTALL YOUR OWN TERMINAL EMULATOR:
-- perm|app-yourterm|r.neo.t
if pkg == "svc-t" and perm == "r.neo.pub.t" then
return "allow"
end
-- <The following is for apps & services> -- <The following is for apps & services>
-- x.neo.pub.* is open to all -- x.neo.pub (aka Icecap) is open to all
if perm:sub(1, 10) == "x.neo.pub." then if perm:sub(1, 10) == "x.neo.pub." then
return "allow" return "allow"
end end
@ -31,8 +25,7 @@ local function actualPolicy(pkg, pid, perm, pkgSvcPfx)
if perm == "s.h.component_added" or perm == "s.h.component_removed" or perm == "s.h.tablet_use" or perm == "c.tablet" then if perm == "s.h.component_added" or perm == "s.h.component_removed" or perm == "s.h.tablet_use" or perm == "c.tablet" then
return "allow" return "allow"
end end
-- Userlevel can register for itself if matchesSvc("r.", pkg, perm) then
if perm == "r." .. pkgSvcPfx then
return "allow" return "allow"
end end
-- Userlevel has no other registration rights -- Userlevel has no other registration rights
@ -51,8 +44,8 @@ local function actualPolicy(pkg, pid, perm, pkgSvcPfx)
return "ask" return "ask"
end end
return function (nexus, settings, pkg, pid, perm, rsp, pkgSvcPfx) return function (nexus, settings, pkg, pid, perm, rsp, matchesSvc)
local res = actualPolicy(pkg, pid, perm, pkgSvcPfx) local res = actualPolicy(pkg, pid, perm, matchesSvc)
if settings then if settings then
res = settings.getSetting("perm|" .. pkg .. "|" .. perm) or res = settings.getSetting("perm|" .. pkg .. "|" .. perm) or
settings.getSetting("perm|*|" .. perm) or res settings.getSetting("perm|*|" .. perm) or res

View File

@ -63,8 +63,7 @@ The security check may be aliased to
"r.*": Registers a service's API for "r.*": Registers a service's API for
retrieval via the "x." mechanism. retrieval via the "x." mechanism.
Returns a: Returns a:
function (function (pkg, pid, send), function (function (pkg, pid, send))
secret)
While the registration is locked on While the registration is locked on
success, attempting to use it will success, attempting to use it will
fail, as no handler has been given. fail, as no handler has been given.
@ -72,11 +71,6 @@ The security check may be aliased to
registration with a callback used registration with a callback used
for when a process tries to use the for when a process tries to use the
registered API. registered API.
Unless 'secret' is truthy, a
k.registration event is sent to all
processes; using the secret flag is
useful for a more ad-hoc security
approach.
What that API returns goes to the What that API returns goes to the
target process. target process.
The given "sendSig" function can be The given "sendSig" function can be

View File

@ -5,34 +5,20 @@ The "svc-t" program / "x.svc.t"
--- THEORETICAL TERMINALS MODEL --- --- THEORETICAL TERMINALS MODEL ---
The theoretical model for terminals The theoretical model for terminals
in KittenOS NEO is a TELNET client in KittenOS NEO is that of a stack
that only supports the ECHO option, of processes controlling a player's
and uses the non-standard behavior connection to a MUD, where text is
of treating ECHO ON as 'enable local provided to the server and to the
line editing'. player in a line-by-line format,
with no "flow control"/ttyattrs.
To prevent code size going too far,
the client is extremely restricted
in capabilities.
If you really want full support,
write a better terminal application.
Features that get added will be added
in accordance with ANSI/TELNET where
reasonable or in a compatible-ish
fashion where unreasonable.
The defaults will be set based on
whatever app-luashell requires, as
this is what is expected of modern
terminal systems regardless of what
the standards may have to say.
A process starting another process A process starting another process
connected to the same terminal is connected to the same terminal is
advised to wait for that process to advised to wait for that process to
die before continuing reading input. die before continuing in terminal
activities, unless some sort of
'in-band notification' functionality
is intended.
The controlling process is whichever The controlling process is whichever
process is supposed to be accepting process is supposed to be accepting
@ -46,8 +32,8 @@ The controlling process should show
acknowledgement that user input has acknowledgement that user input has
been received. been received.
For convenience, terminal echo is on User input IS NOT automatically
by default; this is easily remedied. echoed by the terminal.
--- ACTUAL USAGE OF TERMINALS --- --- ACTUAL USAGE OF TERMINALS ---
@ -56,15 +42,12 @@ Access control on terminals is looser
to be able to be 'sublet' in some to be able to be 'sublet' in some
cases, including events. cases, including events.
As such, the secret flag is set for
terminal registration.
A terminal program is given a string A terminal program is given a string
argument for the ID of the terminal argument for the ID of the terminal
to connect to. to connect to.
A terminal always has an ID beginning A terminal always has an ID beginning
with "x.neo.pub.t/". ALWAYS CHECK. with "x.svc.t/". ALWAYS CHECK THIS.
Requiring the responsible access Requiring the responsible access
connects to the terminal. All connects to the terminal. All
@ -97,22 +80,11 @@ In either case, when the access has
id = "x.svc.t/<...>" id = "x.svc.t/<...>"
pid = <The terminal's PID.> pid = <The terminal's PID.>
write = function (text): Writes the line = function (text): Shows a line.
TELNET data to the terminal.
User input is provided in events: When the user sends a line, an event
<id>, "data", <data> of: <id>, "line", <text>
is provided.
TELNET commands are provided in:
<id>, "telnet", <data>
There is a total of one TELNET
command per event, unpadded.
Notably, intermixing the data part
of the data/telnet events in order
produces the full terminal-to-server
TELNET stream.
-- This is released into -- This is released into
the public domain. the public domain.