Compare commits
11 Commits
ngircd-lin
...
master
Author | SHA1 | Date |
---|---|---|
Cadey Ratio | d7b47df5c4 | |
Cadey Ratio | 1f74e4e3d2 | |
Cadey Ratio | fa56644a7e | |
Cadey Ratio | ac061dff7d | |
Cadey Ratio | aa777a6ab6 | |
Cadey Ratio | b00c7c10d7 | |
Cadey Ratio | 6f9a472818 | |
Cadey Ratio | 559df11d41 | |
Cadey Ratio | fdfb591c13 | |
Cadey Ratio | f953cad787 | |
Cadey Ratio | bb14de2846 |
|
@ -2,4 +2,10 @@ FROM xena/lua:5.3
|
||||||
WORKDIR /ketracel
|
WORKDIR /ketracel
|
||||||
COPY . .
|
COPY . .
|
||||||
ENV PATH $PATH:/root/.luarocks/bin
|
ENV PATH $PATH:/root/.luarocks/bin
|
||||||
RUN ./scripts/build_docker.sh
|
RUN apk --no-cache add ngircd \
|
||||||
|
&& luarocks-5.3 install --local moonscript \
|
||||||
|
&& luarocks-5.3 install --local busted \
|
||||||
|
&& luarocks-5.3 install --local --only-deps ./ketracel*.rockspec \
|
||||||
|
&& ./scripts/test.sh \
|
||||||
|
&& ./scripts/build_docker.sh \
|
||||||
|
&& apk del ngircd
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
export LUA_PATH='/root/.luarocks/share/lua/5.3/?.lua;/root/.luarocks/share/lua/5.3/?/init.lua'
|
export LUA_PATH='/root/.luarocks/share/lua/5.3/?.lua;/root/.luarocks/share/lua/5.3/?/init.lua'
|
||||||
export LUA_CPATH='/root/.luarocks/lib/lua/5.3/?.so'
|
export LUA_CPATH='/root/.luarocks/lib/lua/5.3/?.so'
|
||||||
lua5.3 -l ketracel
|
lua5.3 -l ketracel.main
|
||||||
|
|
|
@ -16,11 +16,19 @@ dependencies = {
|
||||||
"lua ~> 5.3",
|
"lua ~> 5.3",
|
||||||
"irc-engine",
|
"irc-engine",
|
||||||
"luasocket",
|
"luasocket",
|
||||||
|
"ln",
|
||||||
|
"uuid",
|
||||||
}
|
}
|
||||||
build = {
|
build = {
|
||||||
type = "builtin",
|
type = "builtin",
|
||||||
modules = {
|
modules = {
|
||||||
["ketracel"] = "src/ketracel.lua",
|
["ketracel.bots.commands"] = "src/ketracel/bots/commands.lua",
|
||||||
|
["ketracel.bots.ketracel"] = "src/ketracel/bots/ketracel.lua",
|
||||||
|
["ketracel.main"] = "src/ketracel/main.lua",
|
||||||
|
["ketracel.server"] = "src/ketracel/server.lua",
|
||||||
|
["irce.modules.ngircd"] = "src/irce/modules/ngircd/init.lua",
|
||||||
|
["irce.modules.ngircd.channel"] = "src/irce/modules/ngircd/channel.lua",
|
||||||
|
["irce.modules.ngircd.modes"] = "src/irce/modules/ngircd/modes.lua",
|
||||||
["irce.modules.oper"] = "src/irce/modules/oper.lua",
|
["irce.modules.oper"] = "src/irce/modules/oper.lua",
|
||||||
},
|
},
|
||||||
install = {
|
install = {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
moonc-5.3 `find -type f | grep -v spec | grep 'moon$'`
|
||||||
|
ngircd -f `pwd`/spec/ngircd.conf
|
||||||
|
|
||||||
|
function trap_ctrlc () {
|
||||||
|
killall ngircd
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
trap "trap_ctrlc" 2
|
||||||
|
|
||||||
|
cd src
|
||||||
|
export KETRACEL_DEBUG=yes
|
||||||
|
export KETRACEL_SPASS=hunter2
|
||||||
|
lua5.3 -l set_paths ketracel/main.lua
|
||||||
|
trap_ctrlc
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
tup
|
tup
|
||||||
cd src
|
cd src
|
||||||
godotenv -f ../.env lua5.3 -l set_paths ketracel.lua
|
godotenv -f ../.env lua5.3 -l set_paths ./ketracel/main.lua
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
moonc `find -type f | grep -v spec | grep 'moon$'`
|
||||||
|
busted -o TAP
|
|
@ -0,0 +1,46 @@
|
||||||
|
[Global]
|
||||||
|
Name = test.localhost
|
||||||
|
Info = oh god
|
||||||
|
Listen = 0.0.0.0
|
||||||
|
MotdPhrase = testing
|
||||||
|
Network = ShadowNET
|
||||||
|
Ports = 6667
|
||||||
|
ServerGID = 65534
|
||||||
|
ServerUID = 65534
|
||||||
|
|
||||||
|
[Limits]
|
||||||
|
MaxJoins = 50
|
||||||
|
MaxNickLength = 31
|
||||||
|
MaxListSize = 100
|
||||||
|
PingTimeout = 120
|
||||||
|
PongTimeout = 20
|
||||||
|
|
||||||
|
[Options]
|
||||||
|
AllowedChannelTypes = #&+
|
||||||
|
AllowRemoteOper = yes
|
||||||
|
CloakUserToNick = yes
|
||||||
|
DNS = no
|
||||||
|
Ident = no
|
||||||
|
MorePrivacy = no
|
||||||
|
NoticeBeforeRegistration = yes
|
||||||
|
OperCanUseMode = yes
|
||||||
|
OperChanPAutoOp = yes
|
||||||
|
PAM = no
|
||||||
|
PAMIsOptional = yes
|
||||||
|
RequireAuthPing = yes
|
||||||
|
|
||||||
|
[Channel]
|
||||||
|
Name = #lobby
|
||||||
|
Topic = Welcome to the new ShadowNET!
|
||||||
|
Modes = tn
|
||||||
|
|
||||||
|
[Operator]
|
||||||
|
Name = Cadey
|
||||||
|
Password = hunter2
|
||||||
|
|
||||||
|
[Server]
|
||||||
|
Name = ketracel.akua
|
||||||
|
Passive = yes
|
||||||
|
MyPassword = hunter2
|
||||||
|
PeerPassword = hunter2
|
||||||
|
ServiceMask = Ketracel,*Serv
|
|
@ -0,0 +1,27 @@
|
||||||
|
Channel = require "irce.modules.ngircd.channel"
|
||||||
|
|
||||||
|
describe "Channel", ->
|
||||||
|
it "requires a channel name", ->
|
||||||
|
assert.has.errors -> Channel {}
|
||||||
|
|
||||||
|
it "lets you create a channel", ->
|
||||||
|
assert.truthy Channel name: "#butts"
|
||||||
|
|
||||||
|
it "lets you set modes", ->
|
||||||
|
with Channel name: "#butts"
|
||||||
|
\add_mode "p"
|
||||||
|
assert .modes[1] == "p"
|
||||||
|
\del_mode "p"
|
||||||
|
assert #.modes == 0
|
||||||
|
|
||||||
|
it "requires channel membership to give hats", ->
|
||||||
|
with Channel name: "#butts"
|
||||||
|
assert.has.errors -> \add_hat "cadey", "@"
|
||||||
|
assert.has.errors -> \del_hat "cadey", "@"
|
||||||
|
|
||||||
|
it "lets you give people hats", ->
|
||||||
|
with Channel name: "#butts", members: {cadey: {}}
|
||||||
|
\add_hat "cadey", "@"
|
||||||
|
assert .members.cadey[1] == "o"
|
||||||
|
\del_hat "cadey", "@"
|
||||||
|
assert #.members.cadey == 0
|
|
@ -0,0 +1,87 @@
|
||||||
|
irce = require "irce"
|
||||||
|
socket = require "socket"
|
||||||
|
test = require "ketracel.test"
|
||||||
|
Server = require("ketracel.server").Server
|
||||||
|
uuid = require "uuid"
|
||||||
|
ln = require "ln"
|
||||||
|
|
||||||
|
describe "ngircd protocol support", ->
|
||||||
|
local server
|
||||||
|
local client
|
||||||
|
|
||||||
|
setup ->
|
||||||
|
file = io.popen "ngircd -n -f ./spec/ngircd.conf", "r"
|
||||||
|
server = Server
|
||||||
|
server: "127.0.0.1"
|
||||||
|
sname: "ketracel.akua"
|
||||||
|
spass: "hunter2"
|
||||||
|
sreal: "Ketracel"
|
||||||
|
nicklen: "31"
|
||||||
|
debug: os.getenv "DEBUG"
|
||||||
|
client = test.Client "test_user"
|
||||||
|
|
||||||
|
teardown ->
|
||||||
|
with io.popen "killall ngircd", "r"
|
||||||
|
\close!
|
||||||
|
|
||||||
|
it "actually is running ngircd", ->
|
||||||
|
with io.popen "pstree"
|
||||||
|
data = \read "*all"
|
||||||
|
assert.truthy string.find data, "ngircd"
|
||||||
|
|
||||||
|
it "sees end of burst", ->
|
||||||
|
server\wait_for "376"
|
||||||
|
|
||||||
|
it "can use the Client class", ->
|
||||||
|
client\wait_for "005"
|
||||||
|
|
||||||
|
it "sees the client", ->
|
||||||
|
server\wait_for "NICK", (source, user) ->
|
||||||
|
user.nick == "test_user"
|
||||||
|
|
||||||
|
local channame
|
||||||
|
|
||||||
|
it "sees the client join a new channel", ->
|
||||||
|
channame = uuid()
|
||||||
|
client.irc\JOIN "#" .. channame
|
||||||
|
server\wait_for "JOIN", (who, chan) ->
|
||||||
|
chan.name == "#" .. channame
|
||||||
|
client\wait_for "JOIN", (sender, channel) ->
|
||||||
|
channel\sub(2) == channame
|
||||||
|
|
||||||
|
it "sees the client part the channel", ->
|
||||||
|
client.irc\PART "#" .. channame
|
||||||
|
server\wait_for "PART", (who, chan) ->
|
||||||
|
chan.name == "#" .. channame
|
||||||
|
|
||||||
|
it "sees nickchanges", ->
|
||||||
|
client.irc\send_raw "NICK newnick"
|
||||||
|
server\wait_for "NICKCHG", (sender, clinfo) ->
|
||||||
|
clinfo.nick == "newnick"
|
||||||
|
|
||||||
|
it "sees quits", ->
|
||||||
|
cli = test.Client "quitter"
|
||||||
|
cli\wait_for "005"
|
||||||
|
cli.irc\QUIT "bye"
|
||||||
|
server\wait_for "QUIT", (sender, msg) ->
|
||||||
|
sender == "quitter"
|
||||||
|
|
||||||
|
it "sees a privmsg", ->
|
||||||
|
client.irc\JOIN "#ketracel"
|
||||||
|
client.irc\PRIVMSG "#ketracel", "hi"
|
||||||
|
server\wait_for "PRIVMSG", (sender, params) ->
|
||||||
|
params[1] == "#ketracel" and params[2] == "hi"
|
||||||
|
|
||||||
|
describe "ketracel bot", ->
|
||||||
|
it "has a working VHOST command", ->
|
||||||
|
client.irc\PRIVMSG "Ketracel", "VHOST my.cool.vhost"
|
||||||
|
server\wait_for "PRIVMSG", (sender, params) ->
|
||||||
|
params[1] == "Ketracel" and params[2] == "VHOST my.cool.vhost"
|
||||||
|
client\wait_for "396"
|
||||||
|
client\wait_for "NOTICE", (sender, origin, message, pm) ->
|
||||||
|
message\find "my.cool.vhost"
|
||||||
|
|
||||||
|
it "replies to unknown commands", ->
|
||||||
|
client.irc\PRIVMSG "KETRACEL", uuid()
|
||||||
|
server\wait_for "PRIVMSG"
|
||||||
|
client\wait_for "NOTICE"
|
|
@ -0,0 +1,20 @@
|
||||||
|
modes = require "irce.modules.ngircd.modes"
|
||||||
|
|
||||||
|
describe "mode conversion", ->
|
||||||
|
it "has modes2prefix", ->
|
||||||
|
assert.truthy modes.mode2prefix
|
||||||
|
|
||||||
|
it "has prefix2modes", ->
|
||||||
|
assert.truthy modes.prefix2mode
|
||||||
|
|
||||||
|
it "has convert", ->
|
||||||
|
assert.truthy modes.convert
|
||||||
|
|
||||||
|
describe "convert", ->
|
||||||
|
for k, v in pairs modes.mode2prefix
|
||||||
|
msg = string.format "%s: %s", k, v
|
||||||
|
it msg, ->
|
||||||
|
assert.equal(modes.convert(k), v)
|
||||||
|
msg = string.format "%s: %s", v, k
|
||||||
|
it msg, ->
|
||||||
|
assert.equal(modes.convert(v), k)
|
|
@ -1,40 +0,0 @@
|
||||||
irce = require "irce"
|
|
||||||
moon = require "moon"
|
|
||||||
stringx = require "pl.stringx"
|
|
||||||
|
|
||||||
{
|
|
||||||
hooks:
|
|
||||||
["376"]: (state) =>
|
|
||||||
self\NICK "Ketracel", "white", "the.dominion", "+io", "Ketracel White"
|
|
||||||
self\NJOIN "#ketracel", "@Ketracel"
|
|
||||||
|
|
||||||
--["NJOIN"]: (state, chan) =>
|
|
||||||
-- self\NJOIN chan, "Ketracel"
|
|
||||||
|
|
||||||
["PRIVMSG"]: (state, sender, params) =>
|
|
||||||
cmdchar = params[2]\sub 1, 1
|
|
||||||
destsigil = params[1]\sub 1, 1
|
|
||||||
|
|
||||||
if params[1]\lower! == "ketracel"
|
|
||||||
sp = stringx.split params[2]
|
|
||||||
cmd = sp[1]
|
|
||||||
table.remove sp, 1
|
|
||||||
self\handle("Ketracel command", sender[1], params[1], cmd, sp)
|
|
||||||
|
|
||||||
if cmdchar == "?" and destsigil == "#"
|
|
||||||
sp = stringx.split params[2]
|
|
||||||
cmd = string.sub sp[1], 2
|
|
||||||
table.remove sp, 1
|
|
||||||
self\handle("Ketracel command", sender[1], params[1], cmd, sp)
|
|
||||||
|
|
||||||
["Ketracel command"]: (state, sender, target, cmd, args) =>
|
|
||||||
switch string.upper cmd
|
|
||||||
when "VHOST"
|
|
||||||
if #args > 0
|
|
||||||
self\VHOST sender, args[1]
|
|
||||||
self\PRIVMSG "Ketracel", sender, "your vhost is now " ..args[1]
|
|
||||||
else
|
|
||||||
self\PRIVMSG "Ketracel", sender, "usage: VHOST <your.vhost>"
|
|
||||||
else
|
|
||||||
self\PRIVMSG "Ketracel", sender, "i don't know " .. cmd
|
|
||||||
}
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
modeconv = require "irce.modules.ngircd.modes"
|
||||||
|
|
||||||
|
class Channel
|
||||||
|
new: (data) =>
|
||||||
|
assert data.name
|
||||||
|
data.members = {} unless data.members
|
||||||
|
data.modes = {} unless data.modes
|
||||||
|
data.topic = "" unless data.topic
|
||||||
|
for k, v in pairs data
|
||||||
|
self[k] = v
|
||||||
|
|
||||||
|
add_hat: (who, mode) =>
|
||||||
|
hat = modeconv.convert mode
|
||||||
|
usermodes = assert @members[who\lower!]
|
||||||
|
for _, chhat in pairs usermodes
|
||||||
|
return if chhat == hat
|
||||||
|
|
||||||
|
usermodes[#usermodes+1] = hat
|
||||||
|
|
||||||
|
del_hat: (who, mode) =>
|
||||||
|
hat = modeconv.convert mode
|
||||||
|
usermodes = assert @members[who\lower!]
|
||||||
|
|
||||||
|
for i, v in pairs usermodes
|
||||||
|
if v == hat
|
||||||
|
table.remove usermodes, i
|
||||||
|
return
|
||||||
|
|
||||||
|
add_mode: (mode) =>
|
||||||
|
for _, chmd in pairs @modes
|
||||||
|
return if chmd == mode
|
||||||
|
|
||||||
|
@modes[#@modes+1] = mode
|
||||||
|
|
||||||
|
del_mode: (mode) =>
|
||||||
|
for i, v in pairs @modes
|
||||||
|
if v == mode
|
||||||
|
table.remove @modes, i
|
||||||
|
return
|
||||||
|
|
||||||
|
string.format "desync detected: mode %s isn't set on %s", mode, @name
|
||||||
|
|
||||||
|
Channel
|
|
@ -2,6 +2,8 @@ irce = require "irce"
|
||||||
util = require "irce.util"
|
util = require "irce.util"
|
||||||
stringx = require "pl.stringx"
|
stringx = require "pl.stringx"
|
||||||
moon = require "moon"
|
moon = require "moon"
|
||||||
|
ln = require "ln"
|
||||||
|
modeconv = require "irce.modules.ngircd.modes"
|
||||||
|
|
||||||
{
|
{
|
||||||
init: (state) =>
|
init: (state) =>
|
||||||
|
@ -11,10 +13,10 @@ moon = require "moon"
|
||||||
|
|
||||||
senders:
|
senders:
|
||||||
["REGISTER"]: (state, password, software, version, sname, real, nicklen) =>
|
["REGISTER"]: (state, password, software, version, sname, real, nicklen) =>
|
||||||
assert self\PASS password, software, version
|
assert @PASS password, software, version
|
||||||
assert self\SERVER sname, real
|
assert @SERVER sname, real
|
||||||
assert self\NICKLEN nicklen
|
assert @NICKLEN nicklen
|
||||||
assert self\EMOTD!
|
assert @EMOTD!
|
||||||
string.format ":%s PING :%s", sname, sname
|
string.format ":%s PING :%s", sname, sname
|
||||||
|
|
||||||
["PASS"]: (state, password, software, version) =>
|
["PASS"]: (state, password, software, version) =>
|
||||||
|
@ -43,35 +45,124 @@ moon = require "moon"
|
||||||
|
|
||||||
["NICK"]: (state, nick, user, host, modes, real) =>
|
["NICK"]: (state, nick, user, host, modes, real) =>
|
||||||
state.clients[string.lower nick] =
|
state.clients[string.lower nick] =
|
||||||
:nick, :user, :host, :modes, :real, metadata: {}
|
:nick, :user, :host, modes: string.sub(modes, 2), :real, metadata: {}
|
||||||
string.format ":%s NICK %s 1 %s %s 1 %s :%s", state.sname, nick, user, host, modes, real
|
string.format ":%s NICK %s 1 %s %s 1 %s :%s", state.sname, nick, user, host, modes, real
|
||||||
|
|
||||||
["NJOIN"]: (state, channame, who) =>
|
["CHANINFO"]: (state, channame) =>
|
||||||
string.format ":%s NJOIN %s :%s", state.sname, channame, who
|
if state.channels[channame] == nil
|
||||||
|
state.channels[channame] =
|
||||||
|
name: channame
|
||||||
|
mode: "tn"
|
||||||
|
topic: ""
|
||||||
|
members: {}
|
||||||
|
|
||||||
|
string.format ":%s CHANINFO %s +tn", state.sname, channame
|
||||||
|
|
||||||
|
["NJOIN"]: (state, channame, who, prefix) =>
|
||||||
|
if state.channels[channame] == nil
|
||||||
|
state.channels[channame] =
|
||||||
|
name: channame,
|
||||||
|
mode: ""
|
||||||
|
topic: ""
|
||||||
|
members: {}
|
||||||
|
|
||||||
|
pfxarr = {}
|
||||||
|
if prefix
|
||||||
|
for i = 1, #prefix
|
||||||
|
pfxarr[i] = string.sub prefix, i, i
|
||||||
|
state.channels[channame].members[string.lower who] = pfxarr
|
||||||
|
string.format ":%s NJOIN %s :%s%s", state.sname, channame, prefix or "", who
|
||||||
|
|
||||||
["METADATA"]: (state, nick, key, val) =>
|
["METADATA"]: (state, nick, key, val) =>
|
||||||
state.clients[string.lower nick].metadata[key] = val
|
state.clients[string.lower nick].metadata[key] = val
|
||||||
string.format ":%s METADATA %s %s :%s", state.sname, nick, key, val
|
string.format ":%s METADATA %s %s :%s", state.sname, nick, key, val
|
||||||
|
|
||||||
["VHOST"]: (state, nick, vhost) =>
|
["VHOST"]: (state, nick, vhost) =>
|
||||||
self\METADATA nick, "cloakhost", vhost
|
@METADATA nick, "cloakhost", vhost
|
||||||
string.format ":%s MODE %s +x", state.sname, nick
|
string.format ":%s MODE %s +x", state.sname, nick
|
||||||
|
|
||||||
["PRIVMSG"]: (state, nick, target, message) =>
|
["PRIVMSG"]: (state, nick, target, message) =>
|
||||||
string.format ":%s PRIVMSG %s :%s", nick, target, message
|
string.format ":%s PRIVMSG %s :%s", nick, target, message
|
||||||
|
|
||||||
|
["NOTICE"]: (state, nick, target, message) =>
|
||||||
|
string.format ":%s NOTICE %s :%s", nick, target, message
|
||||||
|
|
||||||
|
["PART"]: (state, nick, chan, why) =>
|
||||||
|
state.channels[chan].members[nick] = nil
|
||||||
|
if #state.channels[chan].members == 0
|
||||||
|
state.channels[chan] = nil
|
||||||
|
|
||||||
|
string.format ":%s PART %s :%s", nick, chan, why
|
||||||
|
|
||||||
handlers:
|
handlers:
|
||||||
|
["461"]: (state, sender, params) =>
|
||||||
|
@handle "DIE", string.format("%s: %s", sender[1], params[1])
|
||||||
|
|
||||||
["ERROR"]: (state, sender, params) =>
|
["ERROR"]: (state, sender, params) =>
|
||||||
error string.format "%s: %s", sender[1], params[1]
|
error string.format "%s: %s", sender[1], params[1]
|
||||||
|
|
||||||
["PING"]: (state, sender, params) =>
|
["PING"]: (state, sender, params) =>
|
||||||
self\send "PONG", params[1]
|
@send "PONG", params[1]
|
||||||
sender, params[1]
|
sender, params[1]
|
||||||
|
|
||||||
["PONG"]: (state, sender, params) =>
|
["PONG"]: (state, sender, params) =>
|
||||||
sender, params[1]
|
sender, params[1]
|
||||||
|
|
||||||
|
["JOIN"]: (state, sender, params) =>
|
||||||
|
chan = params[1]
|
||||||
|
mode = {}
|
||||||
|
bell = string.find chan, "\x07"
|
||||||
|
if bell
|
||||||
|
sp = {string.sub(chan, 1, bell - 1), string.sub(chan, bell + 1)}
|
||||||
|
chan = sp[1]
|
||||||
|
mode = {modeconv.convert sp[2]}
|
||||||
|
nick = string.lower sender[1]
|
||||||
|
|
||||||
|
if not state.channels[chan]
|
||||||
|
state.channels[chan] = {name: chan, mode: "", members: {}, topic: ""}
|
||||||
|
state.channels[chan].members[nick] = mode
|
||||||
|
|
||||||
|
sender[1], state.channels[chan]
|
||||||
|
|
||||||
|
["PART"]: (state, sender, params) =>
|
||||||
|
chan = params[1]
|
||||||
|
nick = string.lower sender[1]
|
||||||
|
cinfo = state.channels[chan]
|
||||||
|
state.channels[chan].members[nick] = nil
|
||||||
|
if #state.channels[chan].members == 0
|
||||||
|
state.channels[chan] = nil
|
||||||
|
|
||||||
|
sender[1], cinfo
|
||||||
|
|
||||||
|
["QUIT"]: (state, sender, params) =>
|
||||||
|
nick = string.lower sender[1]
|
||||||
|
state.clients[nick] = nil
|
||||||
|
|
||||||
|
for k, v in pairs state.channels
|
||||||
|
v.members[nick] = nil
|
||||||
|
|
||||||
|
sender[1], params[1]
|
||||||
|
|
||||||
["NICK"]: (state, sender, params) =>
|
["NICK"]: (state, sender, params) =>
|
||||||
|
if #params == 1
|
||||||
|
oldnick = sender[1]
|
||||||
|
oldnicksmall = string.lower oldnick
|
||||||
|
newnick = params[1]
|
||||||
|
cli = state.clients[oldnicksmall]
|
||||||
|
cli.nick = newnick
|
||||||
|
state.clients[string.lower oldnicksmall] = nil
|
||||||
|
nick = string.lower newnick
|
||||||
|
state.clients[string.lower newnick] = cli
|
||||||
|
|
||||||
|
for k, v in pairs state.channels
|
||||||
|
for kk, vv in pairs v.members
|
||||||
|
if kk == oldnicksmall
|
||||||
|
v.members[nick] = v.members[oldnicksmall]
|
||||||
|
v.members[oldnicksmall] = nil
|
||||||
|
|
||||||
|
@handle "NICKCHG", sender, state.clients[nick]
|
||||||
|
return
|
||||||
|
|
||||||
nick = params[1]
|
nick = params[1]
|
||||||
user = params[3]
|
user = params[3]
|
||||||
host = params[4]
|
host = params[4]
|
||||||
|
@ -82,7 +173,7 @@ moon = require "moon"
|
||||||
state.clients[string.lower nick] =
|
state.clients[string.lower nick] =
|
||||||
:nick, :user, :host, :modes, :real, :metadata
|
:nick, :user, :host, :modes, :real, :metadata
|
||||||
|
|
||||||
sender, state.clients[nick]
|
sender, state.clients[string.lower nick]
|
||||||
|
|
||||||
["METADATA"]: (state, sender, params) =>
|
["METADATA"]: (state, sender, params) =>
|
||||||
nick = params[1]
|
nick = params[1]
|
||||||
|
@ -96,6 +187,13 @@ moon = require "moon"
|
||||||
chan = params[1]
|
chan = params[1]
|
||||||
whose = stringx.split tostring(params[2]), ","
|
whose = stringx.split tostring(params[2]), ","
|
||||||
|
|
||||||
|
if state.channels[chan] == nil
|
||||||
|
state.channels[chan] =
|
||||||
|
name: chan
|
||||||
|
mode: ""
|
||||||
|
topic: ""
|
||||||
|
members: {}
|
||||||
|
|
||||||
for k, v in pairs whose
|
for k, v in pairs whose
|
||||||
pfxlen = string.find v, "%a+"
|
pfxlen = string.find v, "%a+"
|
||||||
nick = string.lower string.sub v, pfxlen
|
nick = string.lower string.sub v, pfxlen
|
||||||
|
@ -103,7 +201,7 @@ moon = require "moon"
|
||||||
pfxarr = {}
|
pfxarr = {}
|
||||||
|
|
||||||
for i = 1, #prefix
|
for i = 1, #prefix
|
||||||
pfxarr[i] = string.sub prefix, i, i
|
pfxarr[i] = modeconv.convert string.sub prefix, i, i
|
||||||
|
|
||||||
state.channels[chan].members[nick] = pfxarr
|
state.channels[chan].members[nick] = pfxarr
|
||||||
|
|
||||||
|
@ -127,19 +225,24 @@ moon = require "moon"
|
||||||
|
|
||||||
state.channels[name] =
|
state.channels[name] =
|
||||||
:name, :mode, :topic, :key, :limit, members: {}
|
:name, :mode, :topic, :key, :limit, members: {}
|
||||||
|
state.channels[name]
|
||||||
|
|
||||||
["PRIVMSG"]: (state, sender, params) =>
|
["PRIVMSG"]: (state, sender, params) =>
|
||||||
|
if params[2] == "?state"
|
||||||
|
moon.p state
|
||||||
|
return sender, params
|
||||||
|
|
||||||
if sender[1] == "Cadey" and stringx.startswith params[2], "?eval"
|
if sender[1] == "Cadey" and stringx.startswith params[2], "?eval"
|
||||||
code = string.sub(params[2], 7)
|
code = string.sub(params[2], 7)
|
||||||
print string.format "%s %s %s - evaling", params[1], sender[1], code
|
print string.format "%s %s %s - evaling", params[1], sender[1], code
|
||||||
fun, err = load(code, sender[1].."-"..params[1], "t", {
|
fun, err = load(code, sender[1].."-"..params[1], "t", {
|
||||||
state: state, :string,
|
state: state, :string, irc: @, :_VERSION
|
||||||
})
|
})
|
||||||
if err ~= nil
|
if err ~= nil
|
||||||
error err
|
error err
|
||||||
result = fun!
|
result = fun!
|
||||||
if result ~= nil
|
if result ~= nil
|
||||||
self\PRIVMSG state.sname, params[1], tostring result
|
@PRIVMSG state.sname, params[1], tostring result
|
||||||
|
|
||||||
sender, params
|
sender, params
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
mode2prefix =
|
||||||
|
q: "~"
|
||||||
|
a: "&"
|
||||||
|
o: "@"
|
||||||
|
h: "%"
|
||||||
|
v: "+"
|
||||||
|
|
||||||
|
prefix2mode =
|
||||||
|
["~"]: "q"
|
||||||
|
["&"]: "a"
|
||||||
|
["@"]: "o"
|
||||||
|
["%"]: "h"
|
||||||
|
["+"]: "v"
|
||||||
|
|
||||||
|
convert = (mode_or_prefix) ->
|
||||||
|
mode2prefix[mode_or_prefix] or prefix2mode[mode_or_prefix]
|
||||||
|
|
||||||
|
{
|
||||||
|
:mode2prefix
|
||||||
|
:prefix2mode
|
||||||
|
:convert
|
||||||
|
}
|
|
@ -1,43 +0,0 @@
|
||||||
irce = require "irce"
|
|
||||||
socket = require "socket"
|
|
||||||
|
|
||||||
config =
|
|
||||||
server: os.getenv("IRC_HOST") or "127.0.0.1"
|
|
||||||
sname: os.getenv("KETRACEL_SNAME") or "ketracel.akua"
|
|
||||||
spass: os.getenv("KETRACEL_SPASS") or error("need KETRACEL_SPASS")
|
|
||||||
sreal: os.getenv("KETRACEL_SREAL") or "The favorite of the Jem'Hadar"
|
|
||||||
debug: os.getenv("KETRACEL_DEBUG")
|
|
||||||
nicklen: os.getenv("KETRACEL_NICKLEN") or "31"
|
|
||||||
|
|
||||||
irc = irce.new!
|
|
||||||
running = true
|
|
||||||
|
|
||||||
-- load IRC modules
|
|
||||||
assert irc\load_module require "irce.modules.ngircd"
|
|
||||||
assert irc\load_module require "bots.ketracel"
|
|
||||||
|
|
||||||
client = socket.tcp!
|
|
||||||
client\settimeout 1
|
|
||||||
|
|
||||||
irc\set_send_func (message) =>
|
|
||||||
client\send message
|
|
||||||
|
|
||||||
if config.debug
|
|
||||||
irc\set_callback irce.RAW, (send, message) =>
|
|
||||||
print string.format "%s %s", (send and ">" or "<"), message
|
|
||||||
|
|
||||||
print "Ketracel loaded using " .. irce._VERSION .. " running on " .. _VERSION
|
|
||||||
|
|
||||||
-- connect to irc server
|
|
||||||
assert client\connect config.server, 6667
|
|
||||||
|
|
||||||
assert irc\REGISTER config.spass, "ketracel", "0.0.1", config.sname, config.sreal, config.nicklen
|
|
||||||
|
|
||||||
if config.oper
|
|
||||||
irc\OPER config.nick, config.oper
|
|
||||||
print "IRC operator status requested for " .. config.nick
|
|
||||||
|
|
||||||
while running
|
|
||||||
irc\process client\receive!
|
|
||||||
|
|
||||||
client\close!
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
include_rules
|
||||||
|
.gitignore
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
ln = require "ln"
|
||||||
|
stringx = require "pl.stringx"
|
||||||
|
|
||||||
|
class CommandRouter
|
||||||
|
new: (bot, cmdchar = "?") =>
|
||||||
|
@bot = bot
|
||||||
|
@cmdchar = cmdchar
|
||||||
|
@commands = {}
|
||||||
|
|
||||||
|
register: (verb, action) =>
|
||||||
|
self.commands[verb] = action
|
||||||
|
|
||||||
|
run: (sender, target, verb, args) =>
|
||||||
|
verb = string.upper verb
|
||||||
|
cmd = self.commands[verb]
|
||||||
|
if cmd == nil
|
||||||
|
@bot.irc\NOTICE @bot.name, sender, "unknown command verb " .. verb
|
||||||
|
return
|
||||||
|
|
||||||
|
cmd sender, target, verb, args
|
||||||
|
|
||||||
|
privmsg: (sender, params) =>
|
||||||
|
cmdchar = params[2]\sub 1, 1
|
||||||
|
destsigil = params[1]\sub 1, 1
|
||||||
|
|
||||||
|
if params[1]\lower! == @bot.name\lower!
|
||||||
|
sp = stringx.split params[2]
|
||||||
|
cmd = sp[1]
|
||||||
|
table.remove sp, 1
|
||||||
|
@run sender[1], params[1], cmd, sp
|
||||||
|
|
||||||
|
if cmdchar == @cmdchar and destsigil == "#"
|
||||||
|
sp = stringx.split params[2]
|
||||||
|
cmd = string.sub sp[1], (#@cmdchar + 1)
|
||||||
|
table.remove sp, 1
|
||||||
|
@run sender[1], params[1], cmd, sp
|
||||||
|
|
||||||
|
CommandRouter
|
|
@ -0,0 +1,48 @@
|
||||||
|
irce = require "irce"
|
||||||
|
ln = require "ln"
|
||||||
|
moon = require "moon"
|
||||||
|
stringx = require "pl.stringx"
|
||||||
|
CommandRouter = require "ketracel.bots.commands"
|
||||||
|
|
||||||
|
class Ketracel
|
||||||
|
new: (irc) =>
|
||||||
|
@name = "Ketracel"
|
||||||
|
@irc = irc
|
||||||
|
router = CommandRouter self
|
||||||
|
router\register "DIE", (sender, target, verb, args) -> @die sender, target, verb, args
|
||||||
|
router\register "VHOST", (...) -> @set_vhost ...
|
||||||
|
router\register "STATE", ->
|
||||||
|
router\register "EVAL", ->
|
||||||
|
@router = router
|
||||||
|
|
||||||
|
burst: =>
|
||||||
|
@irc\NICK @name, "white", "the.dominion", "+io", "Ketracel White"
|
||||||
|
|
||||||
|
njoin: (chan) =>
|
||||||
|
@irc\NJOIN chan, "Ketracel"
|
||||||
|
|
||||||
|
die: (sender, target, verb, args) =>
|
||||||
|
@irc\handle "DIE", string.format("%s asked me to die in %s", sender, target)
|
||||||
|
|
||||||
|
set_vhost: (sender, target, verb, args) =>
|
||||||
|
if #args > 0
|
||||||
|
ln.log :sender, vhost: args[1], action: "setting vhost"
|
||||||
|
@irc\VHOST sender, args[1]
|
||||||
|
@irc\NOTICE "Ketracel", sender, "your vhost is now " ..args[1]
|
||||||
|
else
|
||||||
|
@irc\NOTICE "Ketracel", sender, "usage: VHOST <your.vhost>"
|
||||||
|
|
||||||
|
{
|
||||||
|
init: (state) =>
|
||||||
|
state.bot = Ketracel self
|
||||||
|
|
||||||
|
hooks:
|
||||||
|
["376"]: (state) =>
|
||||||
|
state.bot\burst!
|
||||||
|
|
||||||
|
["NJOIN"]: (state, chan) =>
|
||||||
|
state.bot\njoin chan
|
||||||
|
|
||||||
|
["PRIVMSG"]: (state, sender, params) =>
|
||||||
|
state.bot.router\privmsg sender, params
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
irce = require "irce"
|
||||||
|
ln = require "ln"
|
||||||
|
socket = require "socket"
|
||||||
|
server = require "ketracel.server"
|
||||||
|
|
||||||
|
config =
|
||||||
|
server: os.getenv("IRC_HOST") or "127.0.0.1"
|
||||||
|
sname: os.getenv("KETRACEL_SNAME") or "ketracel.akua"
|
||||||
|
spass: os.getenv("KETRACEL_SPASS") or error("need KETRACEL_SPASS")
|
||||||
|
sreal: os.getenv("KETRACEL_SREAL") or "The favorite of the Jem'Hadar"
|
||||||
|
debug: os.getenv("KETRACEL_DEBUG")
|
||||||
|
nicklen: os.getenv("KETRACEL_NICKLEN") or "31"
|
||||||
|
|
||||||
|
with server.Server config
|
||||||
|
\run!
|
|
@ -0,0 +1,59 @@
|
||||||
|
irce = require "irce"
|
||||||
|
ln = require "ln"
|
||||||
|
socket = require "socket"
|
||||||
|
|
||||||
|
class Server
|
||||||
|
new: (config) =>
|
||||||
|
@config = config
|
||||||
|
sock = socket.tcp!
|
||||||
|
irc = irce.new!
|
||||||
|
|
||||||
|
irc\load_module require "irce.modules.ngircd"
|
||||||
|
irc\load_module require "ketracel.bots.ketracel"
|
||||||
|
|
||||||
|
irc\set_send_func (message) =>
|
||||||
|
sock\send message
|
||||||
|
|
||||||
|
if config.debug
|
||||||
|
ln.log {"msg": "debug enabled"}, config
|
||||||
|
irc\set_callback irce.RAW, (send, message) =>
|
||||||
|
sigil = send and ">" or "<"
|
||||||
|
print string.format "%s %s", (send and ">" or "<"), message
|
||||||
|
|
||||||
|
ln.log msg: "Ketracel loaded", irce: irce._VERSION, lua: _VERSION
|
||||||
|
|
||||||
|
assert sock\connect config.server, 6667
|
||||||
|
assert irc\REGISTER config.spass, "ketracel", "0.0.1", config.sname, config.sreal, config.nicklen
|
||||||
|
|
||||||
|
@irc = irc
|
||||||
|
@socket = sock
|
||||||
|
|
||||||
|
wait_for: (event, checker) =>
|
||||||
|
running = true
|
||||||
|
|
||||||
|
@irc\set_callback event, (...) =>
|
||||||
|
if checker and not checker(...)
|
||||||
|
return
|
||||||
|
print "! got event " .. event if os.getenv "DEBUG"
|
||||||
|
running = false
|
||||||
|
|
||||||
|
while running
|
||||||
|
@irc\process @socket\receive!
|
||||||
|
|
||||||
|
@irc\clear_callback event
|
||||||
|
|
||||||
|
run: =>
|
||||||
|
running = true
|
||||||
|
|
||||||
|
@irc\set_callback "DIE", (why) =>
|
||||||
|
ln.err why, {msg: "told to die"}
|
||||||
|
running = false
|
||||||
|
|
||||||
|
while running
|
||||||
|
@irc\process @socket\receive!
|
||||||
|
|
||||||
|
@socket\close!
|
||||||
|
|
||||||
|
{
|
||||||
|
:Server
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
irce = require "irce"
|
||||||
|
socket = require "socket"
|
||||||
|
|
||||||
|
get_client_modules = (irc) ->
|
||||||
|
irc\load_module require "irce.modules.base"
|
||||||
|
irc\load_module require "irce.modules.message"
|
||||||
|
irc\load_module require "irce.modules.channel"
|
||||||
|
|
||||||
|
class Client
|
||||||
|
new: (nick) =>
|
||||||
|
@nick = nick
|
||||||
|
sock = socket.tcp!
|
||||||
|
irc = irce.new!
|
||||||
|
get_client_modules irc
|
||||||
|
irc\set_send_func (message) =>
|
||||||
|
print string.format "[client %s] > %s", nick, message if os.getenv "DEBUG"
|
||||||
|
sock\send message
|
||||||
|
|
||||||
|
sock\connect "127.0.0.1", 6667
|
||||||
|
irc\NICK nick
|
||||||
|
irc\USER nick, nick
|
||||||
|
|
||||||
|
@socket = sock
|
||||||
|
@irc = irc
|
||||||
|
|
||||||
|
wait_for: (event, checker) =>
|
||||||
|
running = true
|
||||||
|
nick = @nick
|
||||||
|
@irc\set_callback event, (...) =>
|
||||||
|
if checker and not checker ...
|
||||||
|
return
|
||||||
|
print string.format "[client %s] ! got event %s", nick, event if os.getenv "DEBUG"
|
||||||
|
running = false
|
||||||
|
while running
|
||||||
|
msg = assert @socket\receive!
|
||||||
|
print string.format "[client %s] < %s", nick, msg if os.getenv "DEBUG"
|
||||||
|
@irc\process msg
|
||||||
|
|
||||||
|
@irc\clear_callback event
|
||||||
|
|
||||||
|
quit: =>
|
||||||
|
@irc\QUIT "bye"
|
||||||
|
@socket\close!
|
||||||
|
|
||||||
|
{
|
||||||
|
:Client
|
||||||
|
}
|
Loading…
Reference in New Issue