OC-misc/minitel-chat/chatd.lua

95 lines
2.1 KiB
Lua

local net = require "net"
local event = require "event"
local syslog = require "syslog"
local serial = require "serialization"
local cfgfile = "/etc/chatd.cfg"
local clients = {}
local cfg = {}
cfg.port = 194
cfg.topic = "Welcome to the "..os.getenv("HOSTNAME").." chat server."
local timer = false
local function saveconfig()
local f = io.open(cfgfile,"wb")
if f then
f:write(serial.serialize(cfg))
f:close()
end
end
local function loadconfig()
local f = io.open(cfgfile,"rb")
if f then
local newcfg = serial.unserialize(f:read("*a"))
f:close()
for k,v in pairs(newcfg) do
cfg[k] = v
end
else
saveconfig()
end
end
local function log(msg,level)
syslog(msg,level,"chatd")
end
local function sendToAll(data)
for k,v in pairs(clients) do
v:write(data)
end
end
local function formatLine(...)
local tA = {...}
return string.format("%s"..("\t%s"):rep(#tA-1).."\n", ...)
end
local function clientLoop()
for sn, socket in pairs(clients) do
local line = socket.rbuffer:match("(.+)\n")
if line then
socket:read(line:len()+1)
local tCmd = {}
for w in line:gmatch("[^\t]+") do
tCmd[#tCmd+1] = w
end
if tCmd[1] == "nick" then
if socket.nick then
sendToAll(formatLine("nick",socket.nick,tCmd[2]))
else
log(tostring(socket.addr)..":"..tostring(socket.port).." connected as "..tCmd[2])
socket:write(formatLine("topic",cfg.topic))
sendToAll(formatLine("join",tCmd[2]))
end
socket.nick = tCmd[2]
elseif tCmd[1] == "msg" and socket.nick then
sendToAll(formatLine("msg",socket.nick,tCmd[2]))
end
end
if socket.state ~= "open" then
log(tostring(socket.addr)..":"..tostring(socket.port).." ("..tostring(socket.nick)..") quit")
clients[sn] = nil
if socket.nick then
sendToAll(formatLine("quit",socket.nick))
end
end
end
end
local function handleSocket(s)
clients[tostring(s.addr)..":"..tostring(s.port)] = s
end
function start()
loadconfig()
net.flisten(cfg.port,handleSocket)
timer = event.timer(1,clientLoop,math.huge)
end
function stop()
event.ignore("net_msg",handleSocket)
event.cancel(timer)
for k,v in pairs(clients) do
v:close()
end
end