many changes, intermediate commit

This commit is contained in:
Andreas Neue 2016-07-17 23:52:03 +02:00
parent 5316b76347
commit d628045cfe
8 changed files with 223 additions and 556 deletions

32
addr.go
View File

@ -1,32 +0,0 @@
package ircd
import (
"strings"
)
func AddrName(addr string) string {
parts := strings.SplitN(addr, "@", 2)
return parts[0]
}
func AddrHost(addr string) string {
parts := strings.SplitN(addr, "@", 2)
if len(parts) > 1 {
return parts[1]
}
return ""
}
func AddrSplit(addr string) (string, string) {
parts := strings.SplitN(addr, "@", 2)
if len(parts) > 1 {
return parts[0], parts[1]
}
return parts[0], ""
}
func AddrJoin(name string, host string) string {
return name + "@" + host
}
// vi:ts=4:sw=4:et

View File

@ -1,159 +0,0 @@
package ircd
import (
"time"
)
type ChangedByTS struct {
By string
Time int64
}
type ChannelModes string
type Channel struct {
Name string
server *Server
topic string
topicChanged ChangedByTS
flags string
keys map[int]string
args map[int]string
bans map[int]string
receive chan *Message
destroy chan bool
invites map[string]bool
clients map[string]ChannelModes
}
func NewChannel(srv *Server, name string) *Channel {
ch := &Channel{Name: name, server: srv, topic: "", flags: ""}
ch.receive = make(chan *Message, 1024)
ch.destroy = make(chan bool)
ch.clients = make(map[string]ChannelModes)
go ch.loop()
return ch
}
func (ch *Channel) Receive(msg *Message) {
ch.receive <- msg
}
func (ch *Channel) loop() {
for {
time.Sleep(1e6)
select {
case msg := <-ch.receive:
cmd := msg.Cmd
hook, exists := chCommandHooks[cmd]
if !exists {
ch.server.sendCommand(msg.Src, ERR_UNKNOWNCOMMAND, cmd,
"Unknown command.")
return
}
argc := len(msg.Args)
if argc < hook.MinArgs {
ch.server.sendCommand(msg.Src, ERR_NEEDMOREPARAMS, cmd,
"Not enough parameters.")
return
}
hook.HookFn(ch, msg)
case <-ch.destroy:
break
default:
continue
}
}
}
func (ch *Channel) recvMsg(msg *Message) {
}
func (ch *Channel) sendMsg(msg *Message) {
ch.server.sendMsg(msg)
}
func (ch *Channel) bcMsg(msg *Message, localEcho bool) {
msg.Ctx = ch.Name
for client, _ := range ch.clients {
if client != msg.Src || localEcho {
msg.Dst = client
ch.server.sendMsgToClient(msg)
}
}
}
func (ch *Channel) AddMode(mode string) {
//
}
type ChCommandHook struct {
HookFn func(ch *Channel, msg *Message)
MinArgs int
NeedOper bool
NeedAuth bool
}
var chCommandHooks = map[string]ChCommandHook{
CMD_QUIT: {chHandleCmdQuit, 0, false, false},
CMD_JOIN: {chHandleCmdJoin, 0, false, false},
CMD_PART: {chHandleCmdPart, 0, false, false},
CMD_MODE: {chHandleCmdMode, 0, false, false},
CMD_TOPIC: {chHandleCmdTopic, 0, false, false},
CMD_NAMES: {chHandleCmdNames, 0, false, false},
CMD_LIST: {chHandleCmdList, 0, false, false},
CMD_INVITE: {chHandleCmdInvite, 0, false, false},
CMD_KICK: {chHandleCmdKick, 0, false, false},
CMD_PRIVMSG: {chHandleCmdPrivmsg, 0, false, false},
CMD_NOTICE: {chHandleCmdNotice, 0, false, false},
CMD_USERS: {chHandleCmdUsers, 0, false, false},
}
func chHandleCmdQuit(ch *Channel, msg *Message) {
ch.bcMsg(M(msg.Src, "", msg.Ctx, "QUIT", "", ""), true)
delete(ch.clients, msg.Src)
}
func chHandleCmdJoin(ch *Channel, msg *Message) {
ch.clients[msg.Src] = ""
ch.bcMsg(M(msg.Src, "", msg.Ctx, "JOIN", "", ""), true)
}
func chHandleCmdPart(ch *Channel, msg *Message) {
ch.bcMsg(M(msg.Src, "", msg.Ctx, "PART", "", ""), true)
delete(ch.clients, msg.Src)
}
func chHandleCmdMode(ch *Channel, msg *Message) {
}
func chHandleCmdTopic(ch *Channel, msg *Message) {
}
func chHandleCmdNames(ch *Channel, msg *Message) {
}
func chHandleCmdList(ch *Channel, msg *Message) {
}
func chHandleCmdInvite(ch *Channel, msg *Message) {
}
func chHandleCmdKick(ch *Channel, msg *Message) {
}
func chHandleCmdPrivmsg(ch *Channel, msg *Message) {
ch.bcMsg(msg, false)
}
func chHandleCmdNotice(ch *Channel, msg *Message) {
}
func chHandleCmdUsers(ch *Channel, msg *Message) {
}
// vi:ts=4:sw=4:et

222
client.go
View File

@ -1,26 +1,20 @@
package ircd // vim:ts=4:sts=4:sw=4:noet:tw=72
package main
import ( import (
"bufio" "bufio"
"code.dnix.de/xlog"
"fmt" "fmt"
"io" "io"
"net" "net"
"strings" "strings"
"time" "time"
"code.dnix.de/an/irc"
"code.dnix.de/an/xlog"
) )
type Client interface { type Client struct {
Name() string
Send(*Message)
Receive(*Message)
Register() chan bool
AddMode(string)
DelMode(string)
HasMode(string) bool
}
type RemoteClient struct {
server *Server server *Server
name string name string
@ -32,23 +26,22 @@ type RemoteClient struct {
isAuthed bool isAuthed bool
isClosed bool isClosed bool
receive chan *Message receive chan *irc.Message
register chan bool register chan bool
conn net.Conn conn net.Conn
writeq chan string writeq chan string
channels map[*Channel]bool
} }
func NewRemoteClient(srv *Server, conn net.Conn) *RemoteClient { func NewClient(srv *Server, conn net.Conn) *Client {
cl := new(RemoteClient) cl := new(Client)
cl.server = srv cl.server = srv
cl.name = "" cl.name = ""
cl.password = "" cl.password = ""
cl.modes = "" cl.modes = ""
cl.receive = make(chan *Message) cl.receive = make(chan *irc.Message)
cl.register = make(chan bool) cl.register = make(chan bool)
cl.isRegistered = false cl.isRegistered = false
@ -61,58 +54,45 @@ func NewRemoteClient(srv *Server, conn net.Conn) *RemoteClient {
go cl.connWriter() go cl.connWriter()
go cl.loop() go cl.loop()
xlog.Info("Client connected.") xlog.Info("Client connected")
return cl return cl
} }
func (cl *RemoteClient) Name() string { func (cl *Client) Name() string {
return cl.name return cl.name
} }
func (cl *RemoteClient) Send(msg *Message) { func (cl *Client) Send(msg *irc.Message) {
cl.server.Receive <- msg msg.Pre = cl.name
cl.server.Dispatch <- msg
} }
func (cl *RemoteClient) Receive(msg *Message) { func (cl *Client) Receive(msg *irc.Message) {
cl.receive <- msg cl.receive <- msg
} }
func (cl *RemoteClient) Register() chan bool { func (cl *Client) Register() chan bool {
return cl.register return cl.register
} }
func (cl *RemoteClient) AddMode(mode string) { func (cl *Client) AddMode(mode string) {
cl.modes = cl.modes + mode cl.modes = cl.modes + mode
} }
func (cl *RemoteClient) DelMode(mode string) { func (cl *Client) DelMode(mode string) {
cl.modes = strings.Replace(cl.modes, mode, "", -1) cl.modes = strings.Replace(cl.modes, mode, "", -1)
} }
func (cl *RemoteClient) HasMode(mode string) bool { func (cl *Client) HasMode(mode string) bool {
return strings.IndexRune(cl.modes, rune(mode[0])) != -1 return strings.IndexRune(cl.modes, rune(mode[0])) != -1
} }
func (cl *RemoteClient) writeMsg(msg *Message) { func (cl *Client) writeMsg(msg *irc.Message) {
var src, ctx, cmd, args, text string cl.writeLine(msg.String())
src = fmt.Sprintf("%s!%s@%s", msg.Src, msg.Src, cl.server.Host)
ctx = msg.Ctx
cmd = msg.Cmd
text = msg.Text
args = ""
for _, arg := range msg.Args {
args += " " + arg
}
if text != "" {
cl.writeLine(fmt.Sprintf(":%s %s %s%s :%s", src, cmd, ctx, args, text))
} else {
cl.writeLine(fmt.Sprintf(":%s %s %s%s", src, cmd, ctx, args))
}
} }
func (cl *RemoteClient) loop() { func (cl *Client) loop() {
for { for {
time.Sleep(1 * time.Millisecond) time.Sleep(1 * time.Millisecond)
if cl.isClosed { if cl.isClosed {
@ -127,7 +107,7 @@ func (cl *RemoteClient) loop() {
} }
} }
func (cl *RemoteClient) destroy(s string) { func (cl *Client) destroy(s string) {
if cl.isClosed { if cl.isClosed {
return return
} }
@ -143,20 +123,20 @@ func (cl *RemoteClient) destroy(s string) {
} }
} }
func (cl *RemoteClient) writeLine(format string, a ...interface{}) { func (cl *Client) writeLine(format string, a ...interface{}) {
cl.writeq <- fmt.Sprintf(format, a...) cl.writeq <- fmt.Sprintf(format, a...)
} }
func (cl *RemoteClient) connReader() { func (cl *Client) connReader() {
input := bufio.NewReader(cl.conn) input := bufio.NewReader(cl.conn)
for { for {
s, err := input.ReadString('\n') s, err := input.ReadString('\n')
if err == io.EOF { if err == io.EOF {
cl.destroy("Connection lost.") cl.destroy("Connection lost")
return return
} }
if err != nil { if err != nil {
cl.destroy(fmt.Sprintf("Read error (%s).", err.Error())) cl.destroy(fmt.Sprintf("Read error (%s)", err.Error()))
return return
} }
s = strings.Trim(s, "\r\n") s = strings.Trim(s, "\r\n")
@ -164,17 +144,17 @@ func (cl *RemoteClient) connReader() {
} }
} }
func (cl *RemoteClient) connWriter() { func (cl *Client) connWriter() {
for line := range cl.writeq { for line := range cl.writeq {
written := 0 written := 0
bytes := []byte(line + "\r\n") bytes := []byte(line + "\r\n")
for written < len(line) { for written < len(line) {
n, err := cl.conn.Write(bytes[written:]) n, err := cl.conn.Write(bytes[written:])
if err == io.EOF { if err == io.EOF {
cl.destroy("Connection lost.") cl.destroy("Connection lost")
return return
} else if err != nil { } else if err != nil {
cl.destroy(fmt.Sprintf("Write error (%s).", err.Error())) cl.destroy(fmt.Sprintf("Write error (%s)", err.Error()))
return return
} }
written += n written += n
@ -182,93 +162,63 @@ func (cl *RemoteClient) connWriter() {
} }
} }
var lineFuncs = map[string]func(*RemoteClient, *Message) bool{ var lineFuncs = map[string]func(*Client, *irc.Message) bool{
CMD_PASS: handleLinePass, "PASS": handleLinePass,
CMD_NICK: handleLineNick, "NICK": handleLineNick,
CMD_USER: handleLineUser, "USER": handleLineUser,
// CMD_OPER: handleLineOper, // "OPER: handleLineOper,
// CMD_QUIT: handleLineQuit, // "QUIT: handleLineQuit,
CMD_JOIN: handleLineJoin, "JOIN": handleLineJoin,
CMD_PART: handleLinePart, "PART": handleLinePart,
CMD_MODE: handleLineMode, "MODE": handleLineMode,
// CMD_TOPIC: handleLineTopic, // "TOPIC: handleLineTopic,
// CMD_NAMES: handleLineNames, // "NAMES: handleLineNames,
// CMD_LIST: handleLineList, // "LIST: handleLineList,
// CMD_INVITE: handleLineInvite, // "INVITE: handleLineInvite,
// CMD_KICK: handleLineKick, // "KICK: handleLineKick,
// CMD_VERSION: handleLineVersion, // "VERSION: handleLineVersion,
// CMD_STATS: handleLineStats, // "STATS: handleLineStats,
// CMD_TIME: handleLineTime, // "TIME: handleLineTime,
// CMD_ADMIN: handleLineAdmin, // "ADMIN: handleLineAdmin,
// CMD_INFO: handleLineInfo, // "INFO: handleLineInfo,
CMD_PRIVMSG: handleLinePrivmsg, "PRIVMSG": handleLinePrivmsg,
// CMD_NOTICE: handleLineNotice, // "NOTICE: handleLineNotice,
// CMD_WHO: handleLineWho, // "WHO: handleLineWho,
// CMD_WHOIS: handleLineWhois, // "WHOIS: handleLineWhois,
// CMD_WHOWAS: handleLineWhowas, // "WHOWAS: handleLineWhowas,
// CMD_KILL: handleLineKill, // "KILL: handleLineKill,
CMD_PING: handleLinePing, "PING": handleLinePing,
// CMD_PONG: handleLinePong, // "PONG: handleLinePong,
// CMD_ERROR: handleLineError, // "ERROR: handleLineError,
// CMD_AWAY: handleLineAway, // "AWAY: handleLineAway,
CMD_REHASH: handleLineRehash, "REHASH": handleLineRehash,
// CMD_RESTART: handleLineRestart, // "RESTART: handleLineRestart,
// CMD_SUMMON: handleLineSummon, // "SUMMON: handleLineSummon,
// CMD_USERS: handleLineUsers, // "USERS: handleLineUsers,
// CMD_USERHOST: handleLineUserhost, // "USERHOST: handleLineUserhost,
// CMD_ISON: handleLineIson, // "ISON: handleLineIson,
} }
func (cl *RemoteClient) handleLine(s string) { func (cl *Client) handleLine(s string) {
xlog.Debug("Raw: [%s] '%s'.", cl.name, s) xlog.Debug("Raw: [%s] '%s'.", cl.name, s)
msg := M("", "", "", "", "", "") cl.Send(irc.Parse(s))
args := strings.SplitN(s, " :", 2)
if len(args) > 1 {
msg.Text = args[1]
}
args = strings.Fields(args[0])
msg.Cmd = strings.ToUpper(args[0])
if len(args) > 1 {
msg.Args = args[1:]
}
msg.Src = cl.name
msg.Dst = ""
if _, exists := lineFuncs[msg.Cmd]; !exists {
// xlog.Warning("No such command (%s).", msg.Cmd)
return
}
if route := lineFuncs[msg.Cmd](cl, msg); route {
// xlog.Warning("Routing to server (%s).", msg.Cmd)
cl.Send(msg)
}
} }
func checkAuth(cl *RemoteClient) { func checkAuth(cl *Client) {
if cl.name == "" || cl.password == "" { if cl.name == "" || cl.password == "" {
return return
} }
} }
func handleLinePass(cl *RemoteClient, msg *Message) bool { func handleLinePass(cl *Client, msg *irc.Message) bool {
cl.password = msg.Args[0] cl.password = msg.Args[0]
return false return false
} }
func handleLineNick(cl *RemoteClient, msg *Message) bool { func handleLineNick(cl *Client, msg *irc.Message) bool {
if cl.name != "" { if cl.name != "" {
// TODO multiple registration not possible
return false return false
} }
/*
if _, exists := cl.Server.Clients[msg.Args[0]]; exists {
cl.destroy("User '" + msg.Args[0] + "' already connected.")
} else {
cl.name = msg.Args[0]
cl.isRegistered = true
cl.Server.AddClient <- cl
xlog.Info("User '%s' registered.", msg.Args[0])
}
*/
if len(msg.Args) < 1 { if len(msg.Args) < 1 {
xlog.Warning("Nicksalat!") xlog.Warning("Nicksalat!")
return false return false
@ -284,40 +234,30 @@ func handleLineNick(cl *RemoteClient, msg *Message) bool {
return false return false
} }
func handleLineUser(cl *RemoteClient, msg *Message) bool { func handleLineUser(cl *Client, msg *irc.Message) bool {
return false return false
} }
func handleLineJoin(cl *RemoteClient, msg *Message) bool { func handleLineJoin(cl *Client, msg *irc.Message) bool {
msg.Dst = msg.Args[0]
msg.Args = make([]string, 0)
return true return true
} }
func handleLinePart(cl *RemoteClient, msg *Message) bool { func handleLinePart(cl *Client, msg *irc.Message) bool {
msg.Dst = msg.Args[0]
msg.Args = make([]string, 0)
return true return true
} }
func handleLineMode(cl *RemoteClient, msg *Message) bool { func handleLineMode(cl *Client, msg *irc.Message) bool {
msg.Dst = msg.Args[0]
msg.Args = make([]string, 0)
return true return true
} }
func handleLinePrivmsg(cl *RemoteClient, msg *Message) bool { func handleLinePrivmsg(cl *Client, msg *irc.Message) bool {
msg.Dst = msg.Args[0]
msg.Args = make([]string, 0)
return true return true
} }
func handleLinePing(cl *RemoteClient, msg *Message) bool { func handleLinePing(cl *Client, msg *irc.Message) bool {
return true return true
} }
func handleLineRehash(cl *RemoteClient, msg *Message) bool { func handleLineRehash(cl *Client, msg *irc.Message) bool {
return true return true
} }
// vim:ts=4:sts=4:sw=4:noet:tw=72

View File

@ -1,6 +0,0 @@
package ircd
type Entity interface {
}
// vi:ts=4:sw=4:et

View File

@ -1,24 +0,0 @@
package ircd
import (
"strings"
)
type Message struct {
Src string
Dst string
Ctx string
Cmd string
Args []string
Text string
}
func M(src, dst, ctx, cmd, args, text string) *Message {
argv := []string{}
if args != "" {
argv = strings.Split(args, " ")
}
return &Message{src, dst, ctx, cmd, argv, text}
}
// vi:ts=4:sw=4:et

View File

@ -1,4 +1,4 @@
package ircd package main
const ( const (
// Commands // Commands
@ -203,4 +203,4 @@ const (
ERR_UNKNOWNSTAT = "910" // STATS error for unknown STAT request ERR_UNKNOWNSTAT = "910" // STATS error for unknown STAT request
) )
// vi:ts=4:sw=4:et // vi:ts=4:sw=4:et

297
server.go
View File

@ -1,16 +1,19 @@
package ircd // vim:ts=4:sts=4:sw=4:noet:tw=72
package main
import ( import (
"code.dnix.de/conf"
"fmt" "fmt"
"net" "net"
"os" "os"
"runtime"
"strconv" "strconv"
"strings" "strings"
"time" "time"
// "io"
"code.dnix.de/xlog" "code.dnix.de/an/conf"
"runtime" "code.dnix.de/an/irc"
"code.dnix.de/an/xlog"
) )
const ( const (
@ -30,22 +33,21 @@ type ControlMsg struct {
} }
type Server struct { type Server struct {
Config *conf.ConfigFile Dispatch chan *irc.Message
AddClient chan *Client
Receive chan *Message DelClient chan *Client
AddClient chan Client
DelClient chan Client
Host string Host string
info string info string
software string software string
version string version string
created string created string
motd string motd string
clients map[string]Client clients map[string]*Client
channels map[string]*Channel subscriptions map[string][]string
ports map[int]bool ports map[int]bool
configPath string config *conf.ConfigFile
configPath string
} }
func init() { func init() {
@ -55,19 +57,18 @@ func init() {
func NewServer(configPath, software, version string) *Server { func NewServer(configPath, software, version string) *Server {
srv := &Server{software: software, version: version, created: "yes"} srv := &Server{software: software, version: version, created: "yes"}
srv.Receive = make(chan *Message, 1024) srv.Dispatch = make(chan *irc.Message, 1024)
srv.AddClient = make(chan Client, 1024) srv.AddClient = make(chan *Client, 1024)
srv.DelClient = make(chan Client, 1024) srv.DelClient = make(chan *Client, 1024)
srv.Host = "dnix.de" srv.Host = "dnix.de"
srv.clients = make(map[string]Client) srv.clients = make(map[string]*Client)
srv.channels = make(map[string]*Channel) srv.subscriptions = make(map[string][]string)
srv.info = "" srv.info = ""
srv.motd = `foo bar baz.` srv.motd = `foo bar baz.`
srv.configPath = configPath srv.configPath = configPath
srv.loadConfig() srv.loadConfig()
loglevel, _ := srv.config.GetInt("system", "loglevel")
loglevel, _ := srv.Config.GetInt("system", "loglevel")
xlog.Init(loglevel) xlog.Init(loglevel)
return srv return srv
@ -76,278 +77,260 @@ func NewServer(configPath, software, version string) *Server {
// Open the listening port and start the main server loop. // Open the listening port and start the main server loop.
func (srv *Server) Run() { func (srv *Server) Run() {
xlog.Info("%s/%s", srv.software, srv.version) xlog.Info("%s/%s", srv.software, srv.version)
srv.Host, _ = srv.Config.GetString("server", "host") srv.Host, _ = srv.config.GetString("server", "host")
srv.info, _ = srv.Config.GetString("server", "info") srv.info, _ = srv.config.GetString("server", "info")
port, _ := srv.Config.GetInt("net", "port") port, _ := srv.config.GetInt("net", "port")
go srv.listen(port) go srv.listen(port)
srv.loop() srv.dispatch()
} }
func (srv *Server) loop() { func (srv *Server) dispatch() {
xlog.Debug("Entering server main loop.") xlog.Debug("Entering msg dispatcher")
for { for {
time.Sleep(1 * time.Millisecond) time.Sleep(1 * time.Millisecond)
select { select {
case msg := <-srv.Receive: case msg := <-srv.Dispatch:
srv.recvMsg(msg) srv.recvMsg(msg)
case cl := <-srv.AddClient: case cl := <-srv.AddClient:
if _, exists := srv.clients[cl.Name()]; exists { name := cl.Name()
xlog.Warning("Client registration failed: '%s'.", cl.Name()) if _, exists := srv.clients[name]; exists {
xlog.Warning("Client registration failed: '%s'", name)
go func() { cl.Register() <- false }() go func() { cl.Register() <- false }()
continue continue
} }
go func() { cl.Register() <- true }() go func() { cl.Register() <- true }()
srv.clients[cl.Name()] = cl srv.clients[name] = cl
xlog.Info("Client registered: '%s'.", cl.Name()) xlog.Info("Client registered: '%s'", name)
xlog.Info("Server has %d client(s).", len(srv.clients)) xlog.Info("Server has %d client(s)", len(srv.clients))
xlog.Debug("Goroutines running: %d.", runtime.NumGoroutine()) xlog.Debug("Goroutines running: %d", runtime.NumGoroutine())
srv.clientLogon(cl) srv.clientLogon(cl)
srv.clientMotd(cl) srv.clientMotd(cl)
case cl := <-srv.DelClient: case cl := <-srv.DelClient:
delete(srv.clients, cl.Name()) name := cl.Name()
xlog.Info("Client deleted: '%s'.", cl.Name()) delete(srv.clients, name)
xlog.Info("Server has %d client(s).", len(srv.clients)) xlog.Info("Client deleted: '%s'", name)
xlog.Debug("Goroutines running: %d.", runtime.NumGoroutine()) xlog.Info("Server has %d client(s)", len(srv.clients))
xlog.Debug("Goroutines running: %d", runtime.NumGoroutine())
default: default:
for name, ch := range srv.channels {
if len(ch.clients) == 0 {
ch.destroy <- true
delete(srv.channels, name)
xlog.Info("Channel destroyed: %s.", name)
}
}
} }
} }
} }
func (srv *Server) listen(port int) { func (srv *Server) listen(port int) {
if _, exists := srv.ports[port]; exists { if _, exists := srv.ports[port]; exists {
xlog.Warning("Port %i already opened.", port) xlog.Warning("Port %i already opened", port)
} }
listen, err := net.Listen("tcp", ":"+strconv.Itoa(port)) listen, err := net.Listen("tcp", ":"+strconv.Itoa(port))
if err != nil { if err != nil {
xlog.Fatal("Cannot listen on port %i (%s). Exiting.", xlog.Fatal("Cannot listen on port %i (%s), exiting",
port, err.Error()) port, err.Error())
os.Exit(-1) os.Exit(-1)
} }
xlog.Info("Start listening on port %d.", port) xlog.Info("Start listening on port %d", port)
for { for {
time.Sleep(1e6) time.Sleep(1e6)
conn, err := listen.Accept() conn, err := listen.Accept()
if err != nil { if err != nil {
// return err xlog.Error(err.Error())
} else {
NewClient(srv, conn)
} }
NewRemoteClient(srv, conn)
} }
} }
func (srv *Server) loadConfig() { func (srv *Server) loadConfig() {
conf, err := conf.ReadConfigFile(srv.configPath) cfg, err := conf.ReadConfigFile(srv.configPath)
if err != nil { if err != nil {
xlog.Fatal("Can't read config file (%s).", err.Error()) xlog.Fatal("Can't read config file (%s)", err.Error())
os.Exit(-1) os.Exit(-1)
} }
srv.Config = conf srv.config = cfg
} }
func (srv *Server) recvMsg(msg *Message) { func (srv *Server) recvMsg(msg *irc.Message) {
if AddrHost(msg.Dst) != "" { if msg.Args[0] != "" {
// TODO send remote
return
}
if AddrHost(msg.Src) != "" {
// TODO from remote
return
}
if msg.Dst != "" {
srv.sendMsg(msg) srv.sendMsg(msg)
return return
} }
cmd := msg.Cmd cmd := msg.Cmd
hook, exists := srvCommandHooks[cmd] hook, exists := srvCommandHooks[cmd]
if !exists { if !exists {
srv.sendCommand(msg.Src, ERR_UNKNOWNCOMMAND, cmd, "Unknown command.") srv.sendCommand(msg.Pre, ERR_UNKNOWNCOMMAND, cmd, "Unknown command")
return return
} }
argc := len(msg.Args) argc := len(msg.Args)
if argc < hook.MinArgs { if argc < hook.MinArgs {
srv.sendCommand(msg.Src, ERR_NEEDMOREPARAMS, cmd, srv.sendCommand(msg.Pre, ERR_NEEDMOREPARAMS, cmd,
"Not enough parameters.") "Not enough parameters")
return return
} }
hook.HookFn(srv, msg) hook.HookFn(srv, msg)
} }
func (srv *Server) sendMsg(msg *Message) { func (srv *Server) sendMsg(msg *irc.Message) {
// Splitting this into two functions is necessary to avoid an if strings.HasPrefix(msg.Args[0], "#") {
// initialization loop in channel.go when broadcasting channel messages.
if strings.HasPrefix(msg.Dst, "#") {
srv.sendMsgToChannel(msg) srv.sendMsgToChannel(msg)
} else { } else {
srv.sendMsgToClient(msg) srv.sendMsgToClient(msg)
} }
} }
func (srv *Server) sendMsgToChannel(msg *Message) { func (srv *Server) sendMsgToChannel(msg *irc.Message) {
if _, exists := srv.channels[msg.Dst]; !exists { subj := msg.Args[0]
if msg.Cmd != "JOIN" { if _, exists := srv.subscriptions[subj]; !exists {
srv.sendCommand(msg.Src, ERR_NOSUCHCHANNEL, msg.Dst, "No such channel.")
return
}
srv.channels[msg.Dst] = NewChannel(srv, msg.Dst)
xlog.Info("Channel created: %s.", msg.Dst)
}
ch := srv.channels[msg.Dst]
ch.Receive(msg)
}
func (srv *Server) sendMsgToClient(msg *Message) {
if _, exists := srv.clients[msg.Dst]; !exists {
xlog.Error("Client '%s' does not exist.", msg.Dst)
return return
} }
cl := srv.clients[msg.Dst] subs := srv.subscriptions[subj]
for _, sub := range subs {
if _, exists := srv.clients[sub]; !exists {
continue
}
cl := srv.clients[sub]
cl.Receive(msg)
}
}
func (srv *Server) sendMsgToClient(msg *irc.Message) {
if _, exists := srv.clients[msg.Args[0]]; !exists {
xlog.Error("Client '%s' does not exist", msg.Args[0])
return
}
cl := srv.clients[msg.Args[0]]
cl.Receive(msg) cl.Receive(msg)
} }
func (srv *Server) sendRemote(msg *Message) { func (srv *Server) sendCommand(dst, cmd, args, trail string) {
srv.sendMsg(irc.M(srv.Host, cmd, args, trail))
} }
func (srv *Server) sendCommand(dst, cmd, args, text string) { func (srv *Server) sendClient(cl *Client, cmd, args, trail string) {
srv.sendMsg(M(srv.Host, dst, dst, cmd, args, text)) srv.sendMsg(irc.M(srv.Host, cmd, cl.Name()+" "+args, trail))
} }
func (srv *Server) sendClient(cl Client, cmd, args, text string) { func (srv *Server) clientLogon(cl *Client) {
srv.sendMsg(M(srv.Host, cl.Name(), cl.Name(), cmd, args, text))
}
func (srv *Server) clientLogon(cl Client) {
srv.sendClient(cl, RPL_WELCOME, "", "Willkommen!") srv.sendClient(cl, RPL_WELCOME, "", "Willkommen!")
srv.sendClient(cl, RPL_YOURHOST, "", srv.sendClient(cl, RPL_YOURHOST, "",
fmt.Sprintf("Your host is %s, running on %s/%s.", fmt.Sprintf("Your host is %s, running on %s/%s",
srv.Host, srv.software, srv.version)) srv.Host, srv.software, srv.version))
srv.sendClient(cl, RPL_CREATED, "", srv.sendClient(cl, RPL_CREATED, "", fmt.Sprintf("Created: %s", srv.created))
"This server was created. Yes. Really.")
srv.sendClient(cl, RPL_MYINFO, srv.sendClient(cl, RPL_MYINFO,
fmt.Sprintf(myinfo, srv.Host, srv.software, srv.version), "") fmt.Sprintf(myinfo, srv.Host, srv.software, srv.version), "")
srv.sendClient(cl, RPL_ISUPPORT, isupport, "are supported by this server.") srv.sendClient(cl, RPL_ISUPPORT, isupport, "are supported by this server")
} }
func (srv *Server) clientMotd(cl Client) { func (srv *Server) clientMotd(cl *Client) {
srv.sendClient(cl, RPL_MOTDSTART, "", srv.sendClient(cl, RPL_MOTDSTART, "",
fmt.Sprintf("- %s Message of the day -", srv.Host)) fmt.Sprintf("- %s Message of the day -", srv.Host))
for _, line := range strings.Split(srv.motd, "\n") { for _, line := range strings.Split(srv.motd, "\n") {
srv.sendClient(cl, RPL_MOTD, "", fmt.Sprintf("- %s", line)) srv.sendClient(cl, RPL_MOTD, "", fmt.Sprintf("- %s", line))
} }
srv.sendClient(cl, RPL_ENDOFMOTD, "", "End of MOTD command.") srv.sendClient(cl, RPL_ENDOFMOTD, "", "End of MOTD command")
} }
type SrvCommandHook struct { type SrvCommandHook struct {
HookFn func(srv *Server, msg *Message) HookFn func(srv *Server, msg *irc.Message)
MinArgs int MinArgs int
NeedOper bool NeedOper bool
NeedAuth bool NeedAuth bool
} }
var srvCommandHooks = map[string]SrvCommandHook{ var srvCommandHooks = map[string]SrvCommandHook{
"OPER": {srvHandleCmdOper, 1, false, false}, "OPER": {srvHandleCmdOper, 1, false, false},
"QUIT": {srvHandleCmdQuit, 0, false, false}, "QUIT": {srvHandleCmdQuit, 0, false, false},
"MODE": {srvHandleCmdMode, 1, false, false}, "MODE": {srvHandleCmdMode, 1, false, false},
"LIST": {srvHandleCmdList, 0, false, false}, "LIST": {srvHandleCmdList, 0, false, false},
"VERSION": {srvHandleCmdVersion, 0, false, false}, "VERSION": {srvHandleCmdVersion, 0, false, false},
"STATS": {srvHandleCmdStats, 0, false, false}, "STATS": {srvHandleCmdStats, 0, false, false},
"TIME": {srvHandleCmdTime, 0, false, false}, "TIME": {srvHandleCmdTime, 0, false, false},
"ADMIN": {srvHandleCmdAdmin, 0, false, false}, "ADMIN": {srvHandleCmdAdmin, 0, false, false},
"INFO": {srvHandleCmdInfo, 0, false, false}, "INFO": {srvHandleCmdInfo, 0, false, false},
"WHO": {srvHandleCmdWho, 0, false, false}, "WHO": {srvHandleCmdWho, 0, false, false},
"WHOIS": {srvHandleCmdWhois, 0, false, false}, "WHOIS": {srvHandleCmdWhois, 0, false, false},
"WHOWAS": {srvHandleCmdWhowas, 0, false, false}, "WHOWAS": {srvHandleCmdWhowas, 0, false, false},
"KILL": {srvHandleCmdKill, 0, false, false}, "KILL": {srvHandleCmdKill, 0, false, false},
"PING": {srvHandleCmdPing, 0, false, false}, "PING": {srvHandleCmdPing, 0, false, false},
"PONG": {srvHandleCmdPong, 0, false, false}, "PONG": {srvHandleCmdPong, 0, false, false},
"ERROR": {srvHandleCmdError, 0, false, false}, "ERROR": {srvHandleCmdError, 0, false, false},
"AWAY": {srvHandleCmdAway, 0, false, false}, "AWAY": {srvHandleCmdAway, 0, false, false},
"REHASH": {srvHandleCmdRehash, 0, false, false}, "REHASH": {srvHandleCmdRehash, 0, false, false},
"RESTART": {srvHandleCmdRestart, 0, false, false}, "RESTART": {srvHandleCmdRestart, 0, false, false},
"SUMMON": {srvHandleCmdSummon, 0, false, false}, "SUMMON": {srvHandleCmdSummon, 0, false, false},
"USERS": {srvHandleCmdUsers, 0, false, false}, "USERS": {srvHandleCmdUsers, 0, false, false},
"USERHOST": {srvHandleCmdUserhost, 0, false, false}, "USERHOST": {srvHandleCmdUserhost, 0, false, false},
"ISON": {srvHandleCmdIson, 0, false, false}, "ISON": {srvHandleCmdIson, 0, false, false},
} }
func srvHandleCmdOper(srv *Server, msg *Message) { func srvHandleCmdOper(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdQuit(srv *Server, msg *Message) { func srvHandleCmdQuit(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdMode(srv *Server, msg *Message) { func srvHandleCmdMode(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdList(srv *Server, msg *Message) { func srvHandleCmdList(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdVersion(srv *Server, msg *Message) { func srvHandleCmdVersion(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdStats(srv *Server, msg *Message) { func srvHandleCmdStats(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdTime(srv *Server, msg *Message) { func srvHandleCmdTime(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdAdmin(srv *Server, msg *Message) { func srvHandleCmdAdmin(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdInfo(srv *Server, msg *Message) { func srvHandleCmdInfo(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdWho(srv *Server, msg *Message) { func srvHandleCmdWho(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdWhois(srv *Server, msg *Message) { func srvHandleCmdWhois(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdWhowas(srv *Server, msg *Message) { func srvHandleCmdWhowas(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdKill(srv *Server, msg *Message) { func srvHandleCmdKill(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdPing(srv *Server, msg *Message) { func srvHandleCmdPing(srv *Server, msg *irc.Message) {
srv.sendCommand(msg.Src, "PONG", "", msg.Args[0]) srv.sendCommand(msg.Pre, "PONG", "", msg.Args[0])
} }
func srvHandleCmdPong(srv *Server, msg *Message) { func srvHandleCmdPong(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdError(srv *Server, msg *Message) { func srvHandleCmdError(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdAway(srv *Server, msg *Message) { func srvHandleCmdAway(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdRehash(srv *Server, msg *Message) { func srvHandleCmdRehash(srv *Server, msg *irc.Message) {
srv.loadConfig() srv.loadConfig()
srv.sendCommand(msg.Src, RPL_REHASHING, "", "Rehashing.") srv.sendCommand(msg.Pre, RPL_REHASHING, "", "Rehashing.")
xlog.Info("Rehashing.") xlog.Info("Rehashing.")
} }
func srvHandleCmdRestart(srv *Server, msg *Message) { func srvHandleCmdRestart(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdSummon(srv *Server, msg *Message) { func srvHandleCmdSummon(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdUsers(srv *Server, msg *Message) { func srvHandleCmdUsers(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdUserhost(srv *Server, msg *Message) { func srvHandleCmdUserhost(srv *Server, msg *irc.Message) {
} }
func srvHandleCmdIson(srv *Server, msg *Message) { func srvHandleCmdIson(srv *Server, msg *irc.Message) {
} }
// vim:ts=4:sts=4:sw=4:noet:tw=72

35
user.go
View File

@ -1,35 +0,0 @@
package ircd
import (
// "dnix/conf"
// "dnix/xlog"
// "encoding/json"
// "os"
// "time"
)
type UserRecord struct {
Name string
Pass string
FriendsPending []string
Friends []string
LastLogin int64
}
/*
func LoadUser(cfg *conf.ConfigFile, name string) {
path, _ := cfg.GetString("server", "user_path") + "name"
file, err := os.Open(path)
if err != nil {
xlog.Error("Can't open user file '%s' (%s).", name, err.Error())
return
}
buf := make([]byte, 10000)
_, err := file.Read(buf)
if err != nil {
xlog.Error("Can't read user file '%s' (%s).", name, err.Error())
}
}
*/
// vi:ts=4:sw=4:et