continue work reorganising and redoing EVERYTHING

This commit is contained in:
Daniel Oaks 2016-06-19 10:01:30 +10:00
parent 31c1df55a3
commit 08225c201d
11 changed files with 261 additions and 270 deletions

View File

@ -6,17 +6,8 @@ package irc
import ( import (
"strings" "strings"
)
type CapSubCommand string "github.com/DanielOaks/girc-go/ircmsg"
const (
CAP_LS CapSubCommand = "LS"
CAP_LIST CapSubCommand = "LIST"
CAP_REQ CapSubCommand = "REQ"
CAP_ACK CapSubCommand = "ACK"
CAP_NAK CapSubCommand = "NAK"
CAP_END CapSubCommand = "END"
) )
// Capabilities are optional features a client may request from a server. // Capabilities are optional features a client may request from a server.
@ -81,65 +72,56 @@ func (set CapabilitySet) DisableString() string {
return strings.Join(parts, " ") return strings.Join(parts, " ")
} }
func (msg *CapCommand) HandleRegServer(server *Server) { // CAP <subcmd> [<caps>]
client := msg.Client() func capHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
subCommand := strings.ToUpper(msg.Params[0])
capabilities := make(CapabilitySet)
var capString string
switch msg.subCommand { if len(msg.Params) > 1 {
case CAP_LS: capString = msg.Params[1]
client.capState = CapNegotiating strs := strings.Split(capString, " ")
client.Reply(RplCap(client, CAP_LS, SupportedCapabilities)) for _, str := range strs {
if len(str) > 0 {
case CAP_LIST: capabilities[Capability(str)] = true
client.Reply(RplCap(client, CAP_LIST, client.capabilities))
case CAP_REQ:
for capability := range msg.capabilities {
if !SupportedCapabilities[capability] {
client.Reply(RplCap(client, CAP_NAK, msg.capabilities))
return
} }
} }
for capability := range msg.capabilities {
client.capabilities[capability] = true
}
client.Reply(RplCap(client, CAP_ACK, msg.capabilities))
case CAP_END:
client.capState = CapNegotiated
server.tryRegister(client)
default:
client.ErrInvalidCapCmd(msg.subCommand)
} }
}
func (msg *CapCommand) HandleServer(server *Server) { switch subCommand {
client := msg.Client() case "LS":
if !client.registered {
client.capState = CapNegotiating
}
// client.server needs to be here to workaround a parsing bug in weechat 1.4
// and let it connect to the server (otherwise it doesn't respond to the CAP
// message with anything and just hangs on connection)
client.Send(nil, server.name, "CAP", client.nickString, subCommand, SupportedCapabilities.String())
switch msg.subCommand { case "LIST":
case CAP_LS: client.Send(nil, server.name, "CAP", client.nickString, subCommand, client.capabilities.String())
client.Reply(RplCap(client, CAP_LS, SupportedCapabilities))
case CAP_LIST: case "REQ":
client.Reply(RplCap(client, CAP_LIST, client.capabilities)) // make sure all capabilities actually exist
for capability := range capabilities {
case CAP_REQ:
for capability := range msg.capabilities {
if !SupportedCapabilities[capability] { if !SupportedCapabilities[capability] {
client.Reply(RplCap(client, CAP_NAK, msg.capabilities)) client.Send(nil, server.name, "CAP", client.nickString, subCommand, capString)
return return false
} }
} }
for capability := range msg.capabilities { for capability := range capabilities {
client.capabilities[capability] = true client.capabilities[capability] = true
} }
client.Reply(RplCap(client, CAP_ACK, msg.capabilities)) client.Send(nil, server.name, "CAP", client.nickString, subCommand, capString)
case CAP_END: case "END":
// no-op after registration performed if !client.registered {
return client.capState = CapNegotiated
server.tryRegister(client)
}
default: default:
client.ErrInvalidCapCmd(msg.subCommand) client.Send(nil, server.name, ERR_INVALIDCAPCMD, client.nickString, subCommand, "Invalid CAP subcommand")
} }
return false
} }

View File

@ -32,12 +32,14 @@ type Client struct {
hostname Name hostname Name
idleTimer *time.Timer idleTimer *time.Timer
nick Name nick Name
nickString string // cache for nick string since it's used with every reply
quitTimer *time.Timer quitTimer *time.Timer
realname Text realname Text
registered bool registered bool
server *Server server *Server
socket *Socket socket *Socket
username Name username Name
isDestroyed bool
} }
func NewClient(server *Server, conn net.Conn) *Client { func NewClient(server *Server, conn net.Conn) *Client {
@ -83,20 +85,26 @@ func (client *Client) run() {
break break
} }
msg, err = ParseLine(line) msg, err = ircmsg.ParseLine(line)
if err != nil { if err != nil {
client.Quit("received malformed command") client.Quit("received malformed command")
break break
} }
isExiting = Run(client.server, client, msg) cmd, exists := Commands[msg.Command]
if !exists {
//TODO(dan): Reply with 400 or whatever unknown cmd is
client.Quit("Received unknown command")
}
isExiting = cmd.Run(client.server, client, msg)
if isExiting { if isExiting {
break break
} }
} }
// ensure client connection gets closed // ensure client connection gets closed
client.Destroy() client.destroy()
} }
// //
@ -246,8 +254,9 @@ func (client *Client) Reply(reply string) error {
return client.socket.WriteLine(reply) return client.socket.WriteLine(reply)
} }
func (client *Client) Quit(message Text) { func (client *Client) Quit(message string) {
client.Send("QUIT", message) client.Send(nil, client.nickString, "QUIT", message)
client.Send(nil, client.nickString, "ERROR", message)
} }
func (client *Client) destroy() { func (client *Client) destroy() {
@ -277,11 +286,24 @@ func (client *Client) destroy() {
} }
client.socket.Close() client.socket.Close()
for friend := range client.Friends() {
if len(friends) > 0 { //TODO(dan): store quit message in user, if exists use that instead here
reply := RplQuit(client, message) friend.Send(nil, client.nickString, "QUIT", "Exited")
for friend := range friends {
friend.Reply(reply)
}
} }
} }
// Send sends an IRC line to the client.
func (client *Client) Send(tags *map[string]ircmsg.TagValue, prefix string, command string, params ...string) error {
ircmsg := ircmsg.MakeMessage(tags, prefix, command, params...)
line, err := ircmsg.Line()
if err != nil {
return err
}
client.socket.Write(line)
return nil
}
// Notice sends the client a notice from the server.
func (client *Client) Notice(text string) {
client.Send(nil, client.server.name, "NOTICE", client.nickString, text)
}

View File

@ -120,7 +120,7 @@ func (cs *ClientSocket) processIncomingLine(line string) bool {
command, canBeParsed := Commands[msg.Command] command, canBeParsed := Commands[msg.Command]
if canBeParsed { if canBeParsed {
return command.Run(cs, msg) return command.Run(cs.client.server, &cs.client, msg)
} }
//TODO(dan): This is an error+disconnect purely for reasons of testing. //TODO(dan): This is an error+disconnect purely for reasons of testing.
// Later it may be downgraded to not-that-bad. // Later it may be downgraded to not-that-bad.

View File

@ -5,19 +5,7 @@
package irc package irc
import ( import "fmt"
"fmt"
"github.com/DanielOaks/girc-go/ircmsg"
)
// NICK <nickname>
func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// check NICK validity
// send NICK change to primary server thread for processing
// |-> ensure no other client exists with that nickname
return true
}
type ModeChange struct { type ModeChange struct {
mode UserMode mode UserMode

View File

@ -9,35 +9,26 @@ import "github.com/DanielOaks/girc-go/ircmsg"
// Command represents a command accepted on a listener. // Command represents a command accepted on a listener.
type Command struct { type Command struct {
handler func(client *Client, msg ircmsg.IrcMessage) bool handler func(server *Server, client *Client, msg ircmsg.IrcMessage) bool
usablePreReg bool usablePreReg bool
minParams int minParams int
} }
// Run runs this command with the given listener/message. // Run runs this command with the given listener/message.
func (cmd *Command) Run(server *Server, client *Client, msg ircmsg.IrcMessage) bool { func (cmd *Command) Run(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
if !client.Registered && !cmd.usablePreReg { if !client.registered && !cmd.usablePreReg {
// command silently ignored // command silently ignored
return false return false
} }
if len(msg.Params) < cmd.minParams { if len(msg.Params) < cmd.minParams {
listener.Send(nil, "", "461", client.Nick, msg.Command, "Not enough parameters") client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nickString, msg.Command, "Not enough parameters")
return false return false
} }
exiting := cmd.handler(server, client, msg) exiting := cmd.handler(server, client, msg)
// after each command, see if we can send registration to the client // after each command, see if we can send registration to the client
if !client.Registered { if !client.registered {
isRegistered := true server.tryRegister(client)
for _, fulfilled := range client.regLocks {
if !fulfilled {
isRegistered = false
break
}
}
if isRegistered {
client.DumpRegistration()
}
} }
return exiting return exiting
@ -82,10 +73,11 @@ var Commands = map[string]Command{
handler: listHandler, handler: listHandler,
minParams: 0, minParams: 0,
}, },
/*TODO(dan): ADD THIS BACK.
"MODE": Command{ "MODE": Command{
handler: modeHandler, handler: modeHandler,
minParams: 1, minParams: 1,
}, },*/
"MOTD": Command{ "MOTD": Command{
handler: motdHandler, handler: motdHandler,
minParams: 0, minParams: 0,
@ -103,10 +95,11 @@ var Commands = map[string]Command{
handler: noticeHandler, handler: noticeHandler,
minParams: 2, minParams: 2,
}, },
/*TODO(dan): ADD THIS BACK
"ONICK": Command{ "ONICK": Command{
handler: onickHandler, handler: onickHandler,
minParams: 2, minParams: 2,
}, },*/
"OPER": Command{ "OPER": Command{
handler: operHandler, handler: operHandler,
minParams: 2, minParams: 2,
@ -144,10 +137,11 @@ var Commands = map[string]Command{
usablePreReg: true, usablePreReg: true,
minParams: 0, minParams: 0,
}, },
/*TODO(dan): ADD THIS BACK IN
"THEATRE": Command{ "THEATRE": Command{
handler: theatreHandler, handler: theatreHandler,
minParams: 1, minParams: 1,
}, },*/
"TIME": Command{ "TIME": Command{
handler: timeHandler, handler: timeHandler,
minParams: 0, minParams: 0,

View File

@ -4,6 +4,7 @@
package irc package irc
import ( import (
"fmt"
"os" "os"
"runtime" "runtime"
"runtime/debug" "runtime/debug"
@ -13,9 +14,10 @@ import (
"github.com/DanielOaks/girc-go/ircmsg" "github.com/DanielOaks/girc-go/ircmsg"
) )
// DEBUG GCSTATS/NUMGOROUTINE/etc
func debugHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { func debugHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
if !client.flags[Operator] { if !client.flags[Operator] {
return return false
} }
switch msg.Params[0] { switch msg.Params[0] {
@ -26,47 +28,48 @@ func debugHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
} }
debug.ReadGCStats(&stats) debug.ReadGCStats(&stats)
server.Replyf(client, "last GC: %s", stats.LastGC.Format(time.RFC1123)) client.Notice(fmt.Sprintf("last GC: %s", stats.LastGC.Format(time.RFC1123)))
server.Replyf(client, "num GC: %d", stats.NumGC) client.Notice(fmt.Sprintf("num GC: %d", stats.NumGC))
server.Replyf(client, "pause total: %s", stats.PauseTotal) client.Notice(fmt.Sprintf("pause total: %s", stats.PauseTotal))
server.Replyf(client, "pause quantiles min%%: %s", stats.PauseQuantiles[0]) client.Notice(fmt.Sprintf("pause quantiles min%%: %s", stats.PauseQuantiles[0]))
server.Replyf(client, "pause quantiles 25%%: %s", stats.PauseQuantiles[1]) client.Notice(fmt.Sprintf("pause quantiles 25%%: %s", stats.PauseQuantiles[1]))
server.Replyf(client, "pause quantiles 50%%: %s", stats.PauseQuantiles[2]) client.Notice(fmt.Sprintf("pause quantiles 50%%: %s", stats.PauseQuantiles[2]))
server.Replyf(client, "pause quantiles 75%%: %s", stats.PauseQuantiles[3]) client.Notice(fmt.Sprintf("pause quantiles 75%%: %s", stats.PauseQuantiles[3]))
server.Replyf(client, "pause quantiles max%%: %s", stats.PauseQuantiles[4]) client.Notice(fmt.Sprintf("pause quantiles max%%: %s", stats.PauseQuantiles[4]))
case "NUMGOROUTINE": case "NUMGOROUTINE":
count := runtime.NumGoroutine() count := runtime.NumGoroutine()
server.Replyf(client, "num goroutines: %d", count) client.Notice(fmt.Sprintf("num goroutines: %d", count))
case "PROFILEHEAP": case "PROFILEHEAP":
profFile := "ergonomadic.mprof" profFile := "ergonomadic.mprof"
file, err := os.Create(profFile) file, err := os.Create(profFile)
if err != nil { if err != nil {
server.Replyf(client, "error: %s", err) client.Notice(fmt.Sprintf("error: %s", err))
break break
} }
defer file.Close() defer file.Close()
pprof.Lookup("heap").WriteTo(file, 0) pprof.Lookup("heap").WriteTo(file, 0)
server.Replyf(client, "written to %s", profFile) client.Notice(fmt.Sprintf("written to %s", profFile))
case "STARTCPUPROFILE": case "STARTCPUPROFILE":
profFile := "ergonomadic.prof" profFile := "ergonomadic.prof"
file, err := os.Create(profFile) file, err := os.Create(profFile)
if err != nil { if err != nil {
server.Replyf(client, "error: %s", err) client.Notice(fmt.Sprintf("error: %s", err))
break break
} }
if err := pprof.StartCPUProfile(file); err != nil { if err := pprof.StartCPUProfile(file); err != nil {
defer file.Close() defer file.Close()
server.Replyf(client, "error: %s", err) client.Notice(fmt.Sprintf("error: %s", err))
break break
} }
server.Replyf(client, "CPU profile writing to %s", profFile) client.Notice(fmt.Sprintf("CPU profile writing to %s", profFile))
case "STOPCPUPROFILE": case "STOPCPUPROFILE":
pprof.StopCPUProfile() pprof.StopCPUProfile()
server.Reply(client, "CPU profiling stopped") client.Notice(fmt.Sprintf("CPU profiling stopped"))
} }
return false
} }

View File

@ -4,6 +4,17 @@
package irc package irc
import "github.com/DanielOaks/girc-go/ircmsg"
// NICK <nickname>
func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// check NICK validity
// send NICK change to primary server thread for processing
// |-> ensure no other client exists with that nickname
//TODO(dan): SET client.nickString APPROPRIATELY
return true
}
/* /*
type NickCommand struct { type NickCommand struct {
BaseCommand BaseCommand
@ -17,6 +28,7 @@ func (m *NickCommand) HandleRegServer(s *Server) {
client.Quit("bad password") client.Quit("bad password")
return return
} }
//TODO(dan): SET client.nickString APPROPRIATELY
if m.nickname == "" { if m.nickname == "" {
client.ErrNoNicknameGiven() client.ErrNoNicknameGiven()
@ -39,6 +51,7 @@ func (m *NickCommand) HandleRegServer(s *Server) {
func (msg *NickCommand) HandleServer(server *Server) { func (msg *NickCommand) HandleServer(server *Server) {
client := msg.Client() client := msg.Client()
//TODO(dan): SET client.nickString APPROPRIATELY
if msg.nickname == "" { if msg.nickname == "" {
client.ErrNoNicknameGiven() client.ErrNoNicknameGiven()
@ -71,6 +84,7 @@ type OperNickCommand struct {
func (msg *OperNickCommand) HandleServer(server *Server) { func (msg *OperNickCommand) HandleServer(server *Server) {
client := msg.Client() client := msg.Client()
//TODO(dan): SET client.nickString APPROPRIATELY
if !client.flags[Operator] { if !client.flags[Operator] {
client.ErrNoPrivileges() client.ErrNoPrivileges()

View File

@ -6,142 +6,142 @@
package irc package irc
const ( const (
RPL_WELCOME NumericCode = 1 RPL_WELCOME = "001"
RPL_YOURHOST NumericCode = 2 RPL_YOURHOST = "002"
RPL_CREATED NumericCode = 3 RPL_CREATED = "003"
RPL_MYINFO NumericCode = 4 RPL_MYINFO = "004"
RPL_ISUPPORT NumericCode = 5 RPL_ISUPPORT = "005"
RPL_BOUNCE NumericCode = 10 RPL_BOUNCE = "010"
RPL_TRACELINK NumericCode = 200 RPL_TRACELINK = "200"
RPL_TRACECONNECTING NumericCode = 201 RPL_TRACECONNECTING = "201"
RPL_TRACEHANDSHAKE NumericCode = 202 RPL_TRACEHANDSHAKE = "202"
RPL_TRACEUNKNOWN NumericCode = 203 RPL_TRACEUNKNOWN = "203"
RPL_TRACEOPERATOR NumericCode = 204 RPL_TRACEOPERATOR = "204"
RPL_TRACEUSER NumericCode = 205 RPL_TRACEUSER = "205"
RPL_TRACESERVER NumericCode = 206 RPL_TRACESERVER = "206"
RPL_TRACESERVICE NumericCode = 207 RPL_TRACESERVICE = "207"
RPL_TRACENEWTYPE NumericCode = 208 RPL_TRACENEWTYPE = "208"
RPL_TRACECLASS NumericCode = 209 RPL_TRACECLASS = "209"
RPL_TRACERECONNECT NumericCode = 210 RPL_TRACERECONNECT = "210"
RPL_STATSLINKINFO NumericCode = 211 RPL_STATSLINKINFO = "211"
RPL_STATSCOMMANDS NumericCode = 212 RPL_STATSCOMMANDS = "212"
RPL_ENDOFSTATS NumericCode = 219 RPL_ENDOFSTATS = "219"
RPL_UMODEIS NumericCode = 221 RPL_UMODEIS = "221"
RPL_SERVLIST NumericCode = 234 RPL_SERVLIST = "234"
RPL_SERVLISTEND NumericCode = 235 RPL_SERVLISTEND = "235"
RPL_STATSUPTIME NumericCode = 242 RPL_STATSUPTIME = "242"
RPL_STATSOLINE NumericCode = 243 RPL_STATSOLINE = "243"
RPL_LUSERCLIENT NumericCode = 251 RPL_LUSERCLIENT = "251"
RPL_LUSEROP NumericCode = 252 RPL_LUSEROP = "252"
RPL_LUSERUNKNOWN NumericCode = 253 RPL_LUSERUNKNOWN = "253"
RPL_LUSERCHANNELS NumericCode = 254 RPL_LUSERCHANNELS = "254"
RPL_LUSERME NumericCode = 255 RPL_LUSERME = "255"
RPL_ADMINME NumericCode = 256 RPL_ADMINME = "256"
RPL_ADMINLOC1 NumericCode = 257 RPL_ADMINLOC1 = "257"
RPL_ADMINLOC2 NumericCode = 258 RPL_ADMINLOC2 = "258"
RPL_ADMINEMAIL NumericCode = 259 RPL_ADMINEMAIL = "259"
RPL_TRACELOG NumericCode = 261 RPL_TRACELOG = "261"
RPL_TRACEEND NumericCode = 262 RPL_TRACEEND = "262"
RPL_TRYAGAIN NumericCode = 263 RPL_TRYAGAIN = "263"
RPL_AWAY NumericCode = 301 RPL_AWAY = "301"
RPL_USERHOST NumericCode = 302 RPL_USERHOST = "302"
RPL_ISON NumericCode = 303 RPL_ISON = "303"
RPL_UNAWAY NumericCode = 305 RPL_UNAWAY = "305"
RPL_NOWAWAY NumericCode = 306 RPL_NOWAWAY = "306"
RPL_WHOISUSER NumericCode = 311 RPL_WHOISUSER = "311"
RPL_WHOISSERVER NumericCode = 312 RPL_WHOISSERVER = "312"
RPL_WHOISOPERATOR NumericCode = 313 RPL_WHOISOPERATOR = "313"
RPL_WHOWASUSER NumericCode = 314 RPL_WHOWASUSER = "314"
RPL_ENDOFWHO NumericCode = 315 RPL_ENDOFWHO = "315"
RPL_WHOISIDLE NumericCode = 317 RPL_WHOISIDLE = "317"
RPL_ENDOFWHOIS NumericCode = 318 RPL_ENDOFWHOIS = "318"
RPL_WHOISCHANNELS NumericCode = 319 RPL_WHOISCHANNELS = "319"
RPL_LIST NumericCode = 322 RPL_LIST = "322"
RPL_LISTEND NumericCode = 323 RPL_LISTEND = "323"
RPL_CHANNELMODEIS NumericCode = 324 RPL_CHANNELMODEIS = "324"
RPL_UNIQOPIS NumericCode = 325 RPL_UNIQOPIS = "325"
RPL_NOTOPIC NumericCode = 331 RPL_NOTOPIC = "331"
RPL_TOPIC NumericCode = 332 RPL_TOPIC = "332"
RPL_INVITING NumericCode = 341 RPL_INVITING = "341"
RPL_SUMMONING NumericCode = 342 RPL_SUMMONING = "342"
RPL_INVITELIST NumericCode = 346 RPL_INVITELIST = "346"
RPL_ENDOFINVITELIST NumericCode = 347 RPL_ENDOFINVITELIST = "347"
RPL_EXCEPTLIST NumericCode = 348 RPL_EXCEPTLIST = "348"
RPL_ENDOFEXCEPTLIST NumericCode = 349 RPL_ENDOFEXCEPTLIST = "349"
RPL_VERSION NumericCode = 351 RPL_VERSION = "351"
RPL_WHOREPLY NumericCode = 352 RPL_WHOREPLY = "352"
RPL_NAMREPLY NumericCode = 353 RPL_NAMREPLY = "353"
RPL_LINKS NumericCode = 364 RPL_LINKS = "364"
RPL_ENDOFLINKS NumericCode = 365 RPL_ENDOFLINKS = "365"
RPL_ENDOFNAMES NumericCode = 366 RPL_ENDOFNAMES = "366"
RPL_BANLIST NumericCode = 367 RPL_BANLIST = "367"
RPL_ENDOFBANLIST NumericCode = 368 RPL_ENDOFBANLIST = "368"
RPL_ENDOFWHOWAS NumericCode = 369 RPL_ENDOFWHOWAS = "369"
RPL_INFO NumericCode = 371 RPL_INFO = "371"
RPL_MOTD NumericCode = 372 RPL_MOTD = "372"
RPL_ENDOFINFO NumericCode = 374 RPL_ENDOFINFO = "374"
RPL_MOTDSTART NumericCode = 375 RPL_MOTDSTART = "375"
RPL_ENDOFMOTD NumericCode = 376 RPL_ENDOFMOTD = "376"
RPL_YOUREOPER NumericCode = 381 RPL_YOUREOPER = "381"
RPL_REHASHING NumericCode = 382 RPL_REHASHING = "382"
RPL_YOURESERVICE NumericCode = 383 RPL_YOURESERVICE = "383"
RPL_TIME NumericCode = 391 RPL_TIME = "391"
RPL_USERSSTART NumericCode = 392 RPL_USERSSTART = "392"
RPL_USERS NumericCode = 393 RPL_USERS = "393"
RPL_ENDOFUSERS NumericCode = 394 RPL_ENDOFUSERS = "394"
RPL_NOUSERS NumericCode = 395 RPL_NOUSERS = "395"
ERR_NOSUCHNICK NumericCode = 401 ERR_NOSUCHNICK = "401"
ERR_NOSUCHSERVER NumericCode = 402 ERR_NOSUCHSERVER = "402"
ERR_NOSUCHCHANNEL NumericCode = 403 ERR_NOSUCHCHANNEL = "403"
ERR_CANNOTSENDTOCHAN NumericCode = 404 ERR_CANNOTSENDTOCHAN = "404"
ERR_TOOMANYCHANNELS NumericCode = 405 ERR_TOOMANYCHANNELS = "405"
ERR_WASNOSUCHNICK NumericCode = 406 ERR_WASNOSUCHNICK = "406"
ERR_TOOMANYTARGETS NumericCode = 407 ERR_TOOMANYTARGETS = "407"
ERR_NOSUCHSERVICE NumericCode = 408 ERR_NOSUCHSERVICE = "408"
ERR_NOORIGIN NumericCode = 409 ERR_NOORIGIN = "409"
ERR_INVALIDCAPCMD NumericCode = 410 ERR_INVALIDCAPCMD = "410"
ERR_NORECIPIENT NumericCode = 411 ERR_NORECIPIENT = "411"
ERR_NOTEXTTOSEND NumericCode = 412 ERR_NOTEXTTOSEND = "412"
ERR_NOTOPLEVEL NumericCode = 413 ERR_NOTOPLEVEL = "413"
ERR_WILDTOPLEVEL NumericCode = 414 ERR_WILDTOPLEVEL = "414"
ERR_BADMASK NumericCode = 415 ERR_BADMASK = "415"
ERR_UNKNOWNCOMMAND NumericCode = 421 ERR_UNKNOWNCOMMAND = "421"
ERR_NOMOTD NumericCode = 422 ERR_NOMOTD = "422"
ERR_NOADMININFO NumericCode = 423 ERR_NOADMININFO = "423"
ERR_FILEERROR NumericCode = 424 ERR_FILEERROR = "424"
ERR_NONICKNAMEGIVEN NumericCode = 431 ERR_NONICKNAMEGIVEN = "431"
ERR_ERRONEUSNICKNAME NumericCode = 432 ERR_ERRONEUSNICKNAME = "432"
ERR_NICKNAMEINUSE NumericCode = 433 ERR_NICKNAMEINUSE = "433"
ERR_NICKCOLLISION NumericCode = 436 ERR_NICKCOLLISION = "436"
ERR_UNAVAILRESOURCE NumericCode = 437 ERR_UNAVAILRESOURCE = "437"
ERR_USERNOTINCHANNEL NumericCode = 441 ERR_USERNOTINCHANNEL = "441"
ERR_NOTONCHANNEL NumericCode = 442 ERR_NOTONCHANNEL = "442"
ERR_USERONCHANNEL NumericCode = 443 ERR_USERONCHANNEL = "443"
ERR_NOLOGIN NumericCode = 444 ERR_NOLOGIN = "444"
ERR_SUMMONDISABLED NumericCode = 445 ERR_SUMMONDISABLED = "445"
ERR_USERSDISABLED NumericCode = 446 ERR_USERSDISABLED = "446"
ERR_NOTREGISTERED NumericCode = 451 ERR_NOTREGISTERED = "451"
ERR_NEEDMOREPARAMS NumericCode = 461 ERR_NEEDMOREPARAMS = "461"
ERR_ALREADYREGISTRED NumericCode = 462 ERR_ALREADYREGISTRED = "462"
ERR_NOPERMFORHOST NumericCode = 463 ERR_NOPERMFORHOST = "463"
ERR_PASSWDMISMATCH NumericCode = 464 ERR_PASSWDMISMATCH = "464"
ERR_YOUREBANNEDCREEP NumericCode = 465 ERR_YOUREBANNEDCREEP = "465"
ERR_YOUWILLBEBANNED NumericCode = 466 ERR_YOUWILLBEBANNED = "466"
ERR_KEYSET NumericCode = 467 ERR_KEYSET = "467"
ERR_CHANNELISFULL NumericCode = 471 ERR_CHANNELISFULL = "471"
ERR_UNKNOWNMODE NumericCode = 472 ERR_UNKNOWNMODE = "472"
ERR_INVITEONLYCHAN NumericCode = 473 ERR_INVITEONLYCHAN = "473"
ERR_BANNEDFROMCHAN NumericCode = 474 ERR_BANNEDFROMCHAN = "474"
ERR_BADCHANNELKEY NumericCode = 475 ERR_BADCHANNELKEY = "475"
ERR_BADCHANMASK NumericCode = 476 ERR_BADCHANMASK = "476"
ERR_NOCHANMODES NumericCode = 477 ERR_NOCHANMODES = "477"
ERR_BANLISTFULL NumericCode = 478 ERR_BANLISTFULL = "478"
ERR_NOPRIVILEGES NumericCode = 481 ERR_NOPRIVILEGES = "481"
ERR_CHANOPRIVSNEEDED NumericCode = 482 ERR_CHANOPRIVSNEEDED = "482"
ERR_CANTKILLSERVER NumericCode = 483 ERR_CANTKILLSERVER = "483"
ERR_RESTRICTED NumericCode = 484 ERR_RESTRICTED = "484"
ERR_UNIQOPPRIVSNEEDED NumericCode = 485 ERR_UNIQOPPRIVSNEEDED = "485"
ERR_NOOPERHOST NumericCode = 491 ERR_NOOPERHOST = "491"
ERR_UMODEUNKNOWNFLAG NumericCode = 501 ERR_UMODEUNKNOWNFLAG = "501"
ERR_USERSDONTMATCH NumericCode = 502 ERR_USERSDONTMATCH = "502"
) )

View File

@ -5,11 +5,7 @@
package irc package irc
import ( /*
"fmt"
"strings"
"time"
)
type ReplyCode interface { type ReplyCode interface {
String() string String() string
@ -585,3 +581,4 @@ func (target *Client) ErrInviteOnlyChan(channel *Channel) {
target.NumericReply(ERR_INVITEONLYCHAN, target.NumericReply(ERR_INVITEONLYCHAN,
"%s :Cannot join channel (+i)", channel) "%s :Cannot join channel (+i)", channel)
} }
*/

View File

@ -31,7 +31,7 @@ type Server struct {
db *sql.DB db *sql.DB
idle chan *Client idle chan *Client
motdLines []string motdLines []string
name Name name string
newConns chan net.Conn newConns chan net.Conn
operators map[Name][]byte operators map[Name][]byte
password []byte password []byte
@ -324,6 +324,7 @@ func (s *Server) tryRegister(c *Client) {
(c.capState == CapNegotiating) { (c.capState == CapNegotiating) {
return return
} }
c.registered = true
c.Send("Intro to the network") c.Send("Intro to the network")
c.Register() c.Register()
@ -1015,7 +1016,6 @@ func whowasHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
client.Send("send") client.Send("send")
} }
} }
client.RplEndOfWhoWas(nickname) client.Send(nil, server.Name, RPL_ENDOFWHOWAS, nickname, "End of WHOWAS")
client.Send("send")
} }
} }

View File

@ -14,17 +14,7 @@ func (c TheaterClient) Nick() Name {
return Name(c) return Name(c)
} }
type TheaterSubCommand string /*
type theaterSubCommand interface {
String() string
}
type TheaterIdentifyCommand struct {
PassCommand
channel Name
}
func (m *TheaterIdentifyCommand) LoadPassword(s *Server) { func (m *TheaterIdentifyCommand) LoadPassword(s *Server) {
m.hash = s.theaters[m.channel] m.hash = s.theaters[m.channel]
} }
@ -118,3 +108,4 @@ func (m *TheaterActionCommand) HandleServer(s *Server) {
member.Reply(reply) member.Reply(reply)
} }
} }
*/