diff --git a/src/irc/channel.go b/src/irc/channel.go index 10d80c0f..c3684b40 100644 --- a/src/irc/channel.go +++ b/src/irc/channel.go @@ -4,6 +4,10 @@ import ( "log" ) +const ( + DEBUG_CHANNEL = true +) + type Channel struct { server *Server commands chan<- ChannelCommand @@ -51,6 +55,9 @@ func NewChannel(s *Server, name string) *Channel { // Forward `Reply`s to all `User`s of the `Channel`. func (ch *Channel) receiveReplies(replies <-chan Reply) { for reply := range replies { + if DEBUG_CHANNEL { + log.Printf("%s → %s", ch, reply) + } for user := range ch.members { if user != reply.Source() { user.replies <- reply @@ -61,7 +68,9 @@ func (ch *Channel) receiveReplies(replies <-chan Reply) { func (ch *Channel) receiveCommands(commands <-chan ChannelCommand) { for command := range commands { - log.Printf("%s %T %+v", ch.Id(), command, command) + if DEBUG_CHANNEL { + log.Printf("%s ← %s %s", ch, command.Source(), command) + } command.HandleChannel(ch) } } @@ -89,18 +98,26 @@ func (channel *Channel) GetTopic(replier Replier) { replier.Replies() <- RplTopic(channel) } -func (channel Channel) Id() string { +func (channel *Channel) Id() string { return channel.name } -func (channel Channel) PublicId() string { +func (channel *Channel) PublicId() string { return channel.name } -func (channel Channel) Commands() chan<- ChannelCommand { +func (channel *Channel) Commands() chan<- ChannelCommand { return channel.commands } +func (channel *Channel) Replies() chan<- Reply { + return channel.replies +} + +func (channel *Channel) String() string { + return channel.Id() +} + // // commands // @@ -170,5 +187,5 @@ func (m *TopicCommand) HandleChannel(channel *Channel) { } func (m *PrivMsgCommand) HandleChannel(channel *Channel) { - channel.replies <- RplPrivMsgChannel(channel, m.Client().user, m.message) + channel.Replies() <- RplPrivMsgChannel(channel, m.Client().user, m.message) } diff --git a/src/irc/client.go b/src/irc/client.go index 7158ce63..7a0b0894 100644 --- a/src/irc/client.go +++ b/src/irc/client.go @@ -35,7 +35,7 @@ func NewClient(server *Server, conn net.Conn) *Client { client := &Client{ conn: conn, - hostname: LookupHostname(conn.RemoteAddr()), + hostname: conn.RemoteAddr().String(), server: server, replies: replies, } @@ -73,57 +73,57 @@ func (c *Client) writeConn(write chan<- string, replies <-chan Reply) { } } -func (c Client) Replies() chan<- Reply { +func (c *Client) Replies() chan<- Reply { return c.replies } -func (c Client) Server() *Server { +func (c *Client) Server() *Server { return c.server } -func (c Client) Nick() string { +func (c *Client) Nick() string { if c.user != nil { - return c.user.nick + return c.user.Nick() } if c.nick != "" { return c.nick } - return "*" + return "guest" } -func (c Client) UModeString() string { +func (c *Client) UModeString() string { return "" } -func (c Client) HasNick() bool { - return c.nick != "" +func (c *Client) HasNick() bool { + return c.Nick() != "" } -func (c Client) HasUser() bool { +func (c *Client) HasUsername() bool { return c.username != "" } -func (c Client) Username() string { - if c.HasUser() { +func (c *Client) Username() string { + if c.HasUsername() { return c.username } - return "*" + return "guest" } -func (c Client) UserHost() string { +func (c *Client) UserHost() string { return fmt.Sprintf("%s!%s@%s", c.Nick(), c.Username(), c.hostname) } -func (c Client) Id() string { +func (c *Client) Id() string { return c.UserHost() } -func (c Client) String() string { - return c.Id() +func (c *Client) String() string { + return c.hostname } -func (c Client) PublicId() string { +func (c *Client) PublicId() string { return fmt.Sprintf("%s!%s@%s", c.Nick(), c.Nick(), c.server.Id()) } diff --git a/src/irc/commands.go b/src/irc/commands.go index 71b3da12..b22de07f 100644 --- a/src/irc/commands.go +++ b/src/irc/commands.go @@ -9,6 +9,7 @@ import ( type Command interface { Client() *Client + Source() Identifier HandleServer(*Server) } @@ -39,7 +40,7 @@ type BaseCommand struct { client *Client } -func (command BaseCommand) Client() *Client { +func (command *BaseCommand) Client() *Client { return command.client } @@ -50,6 +51,17 @@ func (command *BaseCommand) SetClient(c *Client) { command.client = c } +func (command *BaseCommand) Source() Identifier { + client := command.Client() + if client == nil { + return nil + } + if client.user != nil { + return client.user + } + return client +} + func ParseCommand(line string) (EditableCommand, error) { command, args := parseLine(line) constructor := parseCommandFuncs[command] @@ -93,6 +105,10 @@ type UnknownCommand struct { args []string } +func (cmd *UnknownCommand) String() string { + return fmt.Sprintf("UNKNOWN(command=%s, args=%s)", cmd.command, cmd.args) +} + func NewUnknownCommand(command string, args []string) *UnknownCommand { return &UnknownCommand{ BaseCommand: BaseCommand{}, @@ -109,7 +125,7 @@ type PingCommand struct { server2 string } -func (cmd PingCommand) String() string { +func (cmd *PingCommand) String() string { return fmt.Sprintf("PING(server=%s, server2=%s)", cmd.server, cmd.server2) } @@ -135,7 +151,7 @@ type PongCommand struct { server2 string } -func (cmd PongCommand) String() string { +func (cmd *PongCommand) String() string { return fmt.Sprintf("PONG(server1=%s, server2=%s)", cmd.server1, cmd.server2) } @@ -160,6 +176,10 @@ type PassCommand struct { password string } +func (cmd *PassCommand) String() string { + return fmt.Sprintf("PASS(password=%s)", cmd.password) +} + func NewPassCommand(args []string) (EditableCommand, error) { if len(args) < 1 { return nil, NotEnoughArgsError @@ -177,7 +197,7 @@ type NickCommand struct { nickname string } -func (m NickCommand) String() string { +func (m *NickCommand) String() string { return fmt.Sprintf("NICK(nickname=%s)", m.nickname) } @@ -201,7 +221,7 @@ type UserMsgCommand struct { realname string } -func (cmd UserMsgCommand) String() string { +func (cmd *UserMsgCommand) String() string { return fmt.Sprintf("USER(user=%s, mode=%o, unused=%s, realname=%s)", cmd.user, cmd.mode, cmd.unused, cmd.realname) } @@ -230,7 +250,7 @@ type QuitCommand struct { message string } -func (cmd QuitCommand) String() string { +func (cmd *QuitCommand) String() string { return fmt.Sprintf("QUIT(message=%s)", cmd.message) } @@ -252,6 +272,10 @@ type JoinCommand struct { zero bool } +func (cmd *JoinCommand) String() string { + return fmt.Sprintf("JOIN(channels=%s, zero=%t)", cmd.channels, cmd.zero) +} + func NewJoinCommand(args []string) (EditableCommand, error) { msg := &JoinCommand{ BaseCommand: BaseCommand{}, @@ -289,6 +313,10 @@ type PartCommand struct { message string } +func (cmd *PartCommand) String() string { + return fmt.Sprintf("PART(channels=%s, message=%s)", cmd.channels, cmd.message) +} + func NewPartCommand(args []string) (EditableCommand, error) { if len(args) < 1 { return nil, NotEnoughArgsError @@ -311,7 +339,7 @@ type PrivMsgCommand struct { message string } -func (cmd PrivMsgCommand) String() string { +func (cmd *PrivMsgCommand) String() string { return fmt.Sprintf("PRIVMSG(target=%s, message=%s)", cmd.target, cmd.message) } @@ -342,6 +370,10 @@ type TopicCommand struct { topic string } +func (cmd *TopicCommand) String() string { + return fmt.Sprintf("TOPIC(channel=%s, topic=%s)", cmd.channel, cmd.topic) +} + func NewTopicCommand(args []string) (EditableCommand, error) { if len(args) < 1 { return nil, NotEnoughArgsError @@ -362,7 +394,7 @@ type ModeCommand struct { modes string } -func (cmd ModeCommand) String() string { +func (cmd *ModeCommand) String() string { return fmt.Sprintf("MODE(nickname=%s, modes=%s)", cmd.nickname, cmd.modes) } diff --git a/src/irc/constants.go b/src/irc/constants.go index 5d3ce2ee..6633d379 100644 --- a/src/irc/constants.go +++ b/src/irc/constants.go @@ -6,142 +6,142 @@ const ( const ( // numeric codes - RPL_WELCOME = "001" - RPL_YOURHOST = "002" - RPL_CREATED = "003" - RPL_MYINFO = "004" - RPL_BOUNCE = "005" - RPL_TRACELINK = "200" - RPL_TRACECONNECTING = "201" - RPL_TRACEHANDSHAKE = "202" - RPL_TRACEUNKNOWN = "203" - RPL_TRACEOPERATOR = "204" - RPL_TRACEUSER = "205" - RPL_TRACESERVER = "206" - RPL_TRACESERVICE = "207" - RPL_TRACENEWTYPE = "208" - RPL_TRACECLASS = "209" - RPL_TRACERECONNECT = "210" - RPL_STATSLINKINFO = "211" - RPL_STATSCOMMANDS = "212" - RPL_ENDOFSTATS = "219" - RPL_UMODEIS = "221" - RPL_SERVLIST = "234" - RPL_SERVLISTEND = "235" - RPL_STATSUPTIME = "242" - RPL_STATSOLINE = "243" - RPL_LUSERCLIENT = "251" - RPL_LUSEROP = "252" - RPL_LUSERUNKNOWN = "253" - RPL_LUSERCHANNELS = "254" - RPL_LUSERME = "255" - RPL_ADMINME = "256" - RPL_ADMINLOC1 = "257" - RPL_ADMINLOC2 = "258" - RPL_ADMINEMAIL = "259" - RPL_TRACELOG = "261" - RPL_TRACEEND = "262" - RPL_TRYAGAIN = "263" - RPL_AWAY = "301" - RPL_USERHOST = "302" - RPL_ISON = "303" - RPL_UNAWAY = "305" - RPL_NOWAWAY = "306" - RPL_WHOISUSER = "311" - RPL_WHOISSERVER = "312" - RPL_WHOISOPERATOR = "313" - RPL_WHOWASUSER = "314" - RPL_ENDOFWHO = "315" - RPL_WHOISIDLE = "317" - RPL_ENDOFWHOIS = "318" - RPL_WHOISCHANNELS = "319" - RPL_LIST = "322" - RPL_LISTEND = "323" - RPL_CHANNELMODEIS = "324" - RPL_UNIQOPIS = "325" - RPL_NOTOPIC = "331" - RPL_TOPIC = "332" - RPL_INVITING = "341" - RPL_SUMMONING = "342" - RPL_INVITELIST = "346" - RPL_ENDOFINVITELIST = "347" - RPL_EXCEPTLIST = "348" - RPL_ENDOFEXCEPTLIST = "349" - RPL_VERSION = "351" - RPL_WHOREPLY = "352" - RPL_NAMREPLY = "353" - RPL_LINKS = "364" - RPL_ENDOFLINKS = "365" - RPL_ENDOFNAMES = "366" - RPL_BANLIST = "367" - RPL_ENDOFBANLIST = "368" - RPL_ENDOFWHOWAS = "369" - RPL_INFO = "371" - RPL_MOTD = "372" - RPL_ENDOFINFO = "374" - RPL_MOTDSTART = "375" - RPL_ENDOFMOTD = "376" - RPL_YOUREOPER = "381" - RPL_REHASHING = "382" - RPL_YOURESERVICE = "383" - RPL_TIME = "391" - RPL_USERSSTART = "392" - RPL_USERS = "393" - RPL_ENDOFUSERS = "394" - RPL_NOUSERS = "395" - ERR_NOSUCHNICK = "401" - ERR_NOSUCHSERVER = "402" - ERR_NOSUCHCHANNEL = "403" - ERR_CANNOTSENDTOCHAN = "404" - ERR_TOOMANYCHANNELS = "405" - ERR_WASNOSUCHNICK = "406" - ERR_TOOMANYTARGETS = "407" - ERR_NOSUCHSERVICE = "408" - ERR_NOORIGIN = "409" - ERR_NORECIPIENT = "411" - ERR_NOTEXTTOSEND = "412" - ERR_NOTOPLEVEL = "413" - ERR_WILDTOPLEVEL = "414" - ERR_BADMASK = "415" - ERR_UNKNOWNCOMMAND = "421" - ERR_NOMOTD = "422" - ERR_NOADMININFO = "423" - ERR_FILEERROR = "424" - ERR_NONICKNAMEGIVEN = "431" - ERR_ERRONEUSNICKNAME = "432" - ERR_NICKNAMEINUSE = "433" - ERR_NICKCOLLISION = "436" - ERR_UNAVAILRESOURCE = "437" - ERR_USERNOTINCHANNEL = "441" - ERR_NOTONCHANNEL = "442" - ERR_USERONCHANNEL = "443" - ERR_NOLOGIN = "444" - ERR_SUMMONDISABLED = "445" - ERR_USERSDISABLED = "446" - ERR_NOTREGISTERED = "451" - ERR_NEEDMOREPARAMS = "461" - ERR_ALREADYREGISTRED = "462" - ERR_NOPERMFORHOST = "463" - ERR_PASSWDMISMATCH = "464" - ERR_YOUREBANNEDCREEP = "465" - ERR_YOUWILLBEBANNED = "466" - ERR_KEYSET = "467" - ERR_CHANNELISFULL = "471" - ERR_UNKNOWNMODE = "472" - ERR_INVITEONLYCHAN = "473" - ERR_BANNEDFROMCHAN = "474" - ERR_BADCHANNELKEY = "475" - ERR_BADCHANMASK = "476" - ERR_NOCHANMODES = "477" - ERR_BANLISTFULL = "478" - ERR_NOPRIVILEGES = "481" - ERR_CHANOPRIVSNEEDED = "482" - ERR_CANTKILLSERVER = "483" - ERR_RESTRICTED = "484" - ERR_UNIQOPPRIVSNEEDED = "485" - ERR_NOOPERHOST = "491" - ERR_UMODEUNKNOWNFLAG = "501" - ERR_USERSDONTMATCH = "502" + RPL_WELCOME = 1 + RPL_YOURHOST = 2 + RPL_CREATED = 3 + RPL_MYINFO = 4 + RPL_BOUNCE = 5 + RPL_TRACELINK = 200 + RPL_TRACECONNECTING = 201 + RPL_TRACEHANDSHAKE = 202 + RPL_TRACEUNKNOWN = 203 + RPL_TRACEOPERATOR = 204 + RPL_TRACEUSER = 205 + RPL_TRACESERVER = 206 + RPL_TRACESERVICE = 207 + RPL_TRACENEWTYPE = 208 + RPL_TRACECLASS = 209 + RPL_TRACERECONNECT = 210 + RPL_STATSLINKINFO = 211 + RPL_STATSCOMMANDS = 212 + RPL_ENDOFSTATS = 219 + RPL_UMODEIS = 221 + RPL_SERVLIST = 234 + RPL_SERVLISTEND = 235 + RPL_STATSUPTIME = 242 + RPL_STATSOLINE = 243 + RPL_LUSERCLIENT = 251 + RPL_LUSEROP = 252 + RPL_LUSERUNKNOWN = 253 + RPL_LUSERCHANNELS = 254 + RPL_LUSERME = 255 + RPL_ADMINME = 256 + RPL_ADMINLOC1 = 257 + RPL_ADMINLOC2 = 258 + RPL_ADMINEMAIL = 259 + RPL_TRACELOG = 261 + RPL_TRACEEND = 262 + RPL_TRYAGAIN = 263 + RPL_AWAY = 301 + RPL_USERHOST = 302 + RPL_ISON = 303 + RPL_UNAWAY = 305 + RPL_NOWAWAY = 306 + RPL_WHOISUSER = 311 + RPL_WHOISSERVER = 312 + RPL_WHOISOPERATOR = 313 + RPL_WHOWASUSER = 314 + RPL_ENDOFWHO = 315 + RPL_WHOISIDLE = 317 + RPL_ENDOFWHOIS = 318 + RPL_WHOISCHANNELS = 319 + RPL_LIST = 322 + RPL_LISTEND = 323 + RPL_CHANNELMODEIS = 324 + RPL_UNIQOPIS = 325 + RPL_NOTOPIC = 331 + RPL_TOPIC = 332 + RPL_INVITING = 341 + RPL_SUMMONING = 342 + RPL_INVITELIST = 346 + RPL_ENDOFINVITELIST = 347 + RPL_EXCEPTLIST = 348 + RPL_ENDOFEXCEPTLIST = 349 + RPL_VERSION = 351 + RPL_WHOREPLY = 352 + RPL_NAMREPLY = 353 + RPL_LINKS = 364 + RPL_ENDOFLINKS = 365 + RPL_ENDOFNAMES = 366 + RPL_BANLIST = 367 + RPL_ENDOFBANLIST = 368 + RPL_ENDOFWHOWAS = 369 + RPL_INFO = 371 + RPL_MOTD = 372 + RPL_ENDOFINFO = 374 + RPL_MOTDSTART = 375 + RPL_ENDOFMOTD = 376 + RPL_YOUREOPER = 381 + RPL_REHASHING = 382 + RPL_YOURESERVICE = 383 + RPL_TIME = 391 + RPL_USERSSTART = 392 + RPL_USERS = 393 + RPL_ENDOFUSERS = 394 + RPL_NOUSERS = 395 + ERR_NOSUCHNICK = 401 + ERR_NOSUCHSERVER = 402 + ERR_NOSUCHCHANNEL = 403 + ERR_CANNOTSENDTOCHAN = 404 + ERR_TOOMANYCHANNELS = 405 + ERR_WASNOSUCHNICK = 406 + ERR_TOOMANYTARGETS = 407 + ERR_NOSUCHSERVICE = 408 + ERR_NOORIGIN = 409 + ERR_NORECIPIENT = 411 + ERR_NOTEXTTOSEND = 412 + ERR_NOTOPLEVEL = 413 + ERR_WILDTOPLEVEL = 414 + ERR_BADMASK = 415 + ERR_UNKNOWNCOMMAND = 421 + ERR_NOMOTD = 422 + ERR_NOADMININFO = 423 + ERR_FILEERROR = 424 + ERR_NONICKNAMEGIVEN = 431 + ERR_ERRONEUSNICKNAME = 432 + ERR_NICKNAMEINUSE = 433 + ERR_NICKCOLLISION = 436 + ERR_UNAVAILRESOURCE = 437 + ERR_USERNOTINCHANNEL = 441 + ERR_NOTONCHANNEL = 442 + ERR_USERONCHANNEL = 443 + ERR_NOLOGIN = 444 + ERR_SUMMONDISABLED = 445 + ERR_USERSDISABLED = 446 + ERR_NOTREGISTERED = 451 + ERR_NEEDMOREPARAMS = 461 + ERR_ALREADYREGISTRED = 462 + ERR_NOPERMFORHOST = 463 + ERR_PASSWDMISMATCH = 464 + ERR_YOUREBANNEDCREEP = 465 + ERR_YOUWILLBEBANNED = 466 + ERR_KEYSET = 467 + ERR_CHANNELISFULL = 471 + ERR_UNKNOWNMODE = 472 + ERR_INVITEONLYCHAN = 473 + ERR_BANNEDFROMCHAN = 474 + ERR_BADCHANNELKEY = 475 + ERR_BADCHANMASK = 476 + ERR_NOCHANMODES = 477 + ERR_BANLISTFULL = 478 + ERR_NOPRIVILEGES = 481 + ERR_CHANOPRIVSNEEDED = 482 + ERR_CANTKILLSERVER = 483 + ERR_RESTRICTED = 484 + ERR_UNIQOPPRIVSNEEDED = 485 + ERR_NOOPERHOST = 491 + ERR_UMODEUNKNOWNFLAG = 501 + ERR_USERSDONTMATCH = 502 // message codes RPL_INVITE = "INVITE" RPL_JOIN = "JOIN" diff --git a/src/irc/nickserv.go b/src/irc/nickserv.go index 7f0b4d19..49d3dd35 100644 --- a/src/irc/nickserv.go +++ b/src/irc/nickserv.go @@ -74,7 +74,7 @@ type RegisterCommand struct { email string } -func (m RegisterCommand) String() string { +func (m *RegisterCommand) String() string { return fmt.Sprintf("REGISTER(email=%s, password=%s)", m.email, m.password) } @@ -107,11 +107,11 @@ func (m *RegisterCommand) HandleNickServ(ns *NickServ) { } user := NewUser(client.nick, m.password, ns.server) - ns.server.users[client.nick] = user ns.Reply(client, "You have registered.") if !user.Login(client, client.nick, m.password) { ns.Reply(client, "Login failed.") + return } ns.Reply(client, "Logged in.") } @@ -121,7 +121,7 @@ type IdentifyCommand struct { password string } -func (m IdentifyCommand) String() string { +func (m *IdentifyCommand) String() string { return fmt.Sprintf("IDENTIFY(password=%s)", m.password) } diff --git a/src/irc/reply.go b/src/irc/reply.go index d670dbd3..e3d6f229 100644 --- a/src/irc/reply.go +++ b/src/irc/reply.go @@ -22,78 +22,88 @@ type Reply interface { Source() Identifier } -type BasicReply struct { +type BaseReply struct { source Identifier - code string message string } -func NewBasicReply(source Identifier, code string, - format string, args ...interface{}) *BasicReply { - message := fmt.Sprintf(format, args...) - fullMessage := fmt.Sprintf(":%s %s %s", source.Id(), code, message) - return &BasicReply{source, code, fullMessage} +func (reply *BaseReply) Source() Identifier { + return reply.source } -func (reply BasicReply) String() string { +type StringReply struct { + BaseReply + code string +} + +func NewStringReply(source Identifier, code string, + format string, args ...interface{}) *StringReply { + message := fmt.Sprintf(format, args...) + fullMessage := fmt.Sprintf(":%s %s %s", source.Id(), code, message) + return &StringReply{BaseReply{source, fullMessage}, code} +} + +func (reply *StringReply) Format(client *Client) string { + return reply.message +} + +func (reply *StringReply) String() string { return fmt.Sprintf("Reply(source=%s, code=%s, message=%s)", reply.source, reply.code, reply.message) } -func (reply BasicReply) Format(client *Client) string { - return reply.message -} - -func (reply BasicReply) Source() Identifier { - return reply.source -} - type NumericReply struct { - BasicReply + BaseReply + code int } -func NewNumericReply(source Identifier, code string, +func NewNumericReply(source Identifier, code int, format string, args ...interface{}) *NumericReply { - return &NumericReply{BasicReply{source, code, fmt.Sprintf(format, args...)}} + return &NumericReply{BaseReply{source, fmt.Sprintf(format, args...)}, code} } -func (reply NumericReply) Format(client *Client) string { - return fmt.Sprintf(":%s %s %s %s\r\n", reply.source.Id(), reply.code, client.Nick(), - reply.message) +func (reply *NumericReply) Format(client *Client) string { + return fmt.Sprintf(":%s %03d %s %s", reply.Source().Id(), reply.code, + client.Nick(), reply.message) +} + +func (reply *NumericReply) String() string { + return fmt.Sprintf("Reply(source=%s, code=%d, message=%s)", + reply.source, reply.code, reply.message) } // messaging replies func RplPrivMsg(source Identifier, target Identifier, message string) Reply { - return NewBasicReply(source, RPL_PRIVMSG, "%s :%s", target.Nick(), message) + return NewStringReply(source, RPL_PRIVMSG, "%s :%s", target.Nick(), message) } func RplNick(client *Client, newNick string) Reply { - return NewBasicReply(client, RPL_NICK, newNick) + return NewStringReply(client, RPL_NICK, newNick) } func RplPrivMsgChannel(channel *Channel, source Identifier, message string) Reply { - return NewBasicReply(source, RPL_PRIVMSG, "%s :%s", channel.name, message) + return NewStringReply(source, RPL_PRIVMSG, "%s :%s", channel.name, message) } func RplJoin(channel *Channel, user *User) Reply { - return NewBasicReply(user, RPL_JOIN, channel.name) + return NewStringReply(user, RPL_JOIN, channel.name) } func RplPart(channel *Channel, user *User, message string) Reply { - return NewBasicReply(user, RPL_PART, "%s :%s", channel.name, message) + return NewStringReply(user, RPL_PART, "%s :%s", channel.name, message) } func RplPong(server *Server) Reply { - return NewBasicReply(server, RPL_PONG, server.Id()) + return NewStringReply(server, RPL_PONG, server.Id()) } func RplQuit(client *Client, message string) Reply { - return NewBasicReply(client, RPL_QUIT, ":%", message) + return NewStringReply(client, RPL_QUIT, ":%s", message) } func RplInviteMsg(channel *Channel, inviter *Client) Reply { - return NewBasicReply(inviter, RPL_INVITE, channel.name) + return NewStringReply(inviter, RPL_INVITE, channel.name) } // numeric replies diff --git a/src/irc/server.go b/src/irc/server.go index de8df906..5c6c113e 100644 --- a/src/irc/server.go +++ b/src/irc/server.go @@ -99,7 +99,7 @@ func (s Server) InterestedUsers(fromUser *User) UserSet { // server functionality func (s *Server) tryRegister(c *Client) { - if !c.registered && c.HasNick() && c.HasUser() && (s.password == nil || c.serverPass) { + if !c.registered && c.HasNick() && c.HasUsername() && (s.password == nil || c.serverPass) { c.registered = true replies := []Reply{RplWelcome(s, c), RplYourHost(s, c), RplCreated(s), RplMyInfo(s)} for _, reply := range replies { @@ -112,15 +112,15 @@ func (s Server) Id() string { return s.name } -func (s Server) String() string { +func (s *Server) String() string { return s.Id() } -func (s Server) PublicId() string { +func (s *Server) PublicId() string { return s.Id() } -func (s Server) Nick() string { +func (s *Server) Nick() string { return s.name } @@ -132,7 +132,7 @@ func (s *Server) DeleteChannel(channel *Channel) { // commands // -func (m UnknownCommand) HandleServer(s *Server) { +func (m *UnknownCommand) HandleServer(s *Server) { m.Client().Replies() <- ErrUnknownCommand(s, m.command) } diff --git a/src/irc/service.go b/src/irc/service.go index d12b6e18..162287b2 100644 --- a/src/irc/service.go +++ b/src/irc/service.go @@ -50,19 +50,19 @@ func receiveCommands(service Service, commands <-chan ServiceCommand) { } } -func (service BaseService) Id() string { +func (service *BaseService) Id() string { return fmt.Sprintf("%s!%s@%s", service.name, service.name, service.server.name) } -func (service BaseService) String() string { +func (service *BaseService) String() string { return service.Id() } -func (service BaseService) PublicId() string { +func (service *BaseService) PublicId() string { return service.Id() } -func (service BaseService) Nick() string { +func (service *BaseService) Nick() string { return service.name } @@ -70,10 +70,14 @@ func (service *BaseService) Reply(client *Client, message string) { client.Replies() <- RplPrivMsg(service, client, message) } -func (service BaseService) Commands() chan<- ServiceCommand { +func (service *BaseService) Commands() chan<- ServiceCommand { return service.commands } +// +// commands +// + func (m *PrivMsgCommand) HandleService(service Service) { service.HandlePrivMsg(m) } diff --git a/src/irc/user.go b/src/irc/user.go index 447e4745..507ca202 100644 --- a/src/irc/user.go +++ b/src/irc/user.go @@ -6,6 +6,10 @@ import ( "log" ) +const ( + DEBUG_USER = true +) + type UserCommand interface { Command HandleUser(*User) @@ -44,6 +48,7 @@ func NewUser(nick string, password string, server *Server) *User { user.SetPassword(password) go user.receiveCommands(commands) go user.receiveReplies(replies) + server.users[nick] = user return user } @@ -57,7 +62,9 @@ func (user *User) SetPassword(password string) { func (user *User) receiveCommands(commands <-chan UserCommand) { for command := range commands { - log.Printf("%s %T %+v", user.Id(), command, command) + if DEBUG_USER { + log.Printf("%s ← %s %s", user, command.Client(), command) + } command.HandleUser(user) } } @@ -65,7 +72,7 @@ func (user *User) receiveCommands(commands <-chan UserCommand) { // Distribute replies to clients. func (user *User) receiveReplies(replies <-chan Reply) { for reply := range replies { - log.Printf("%s %T %+v", user.Id(), reply, reply) + log.Printf("%s ← %s", user, reply) for client := range user.clients { client.Replies() <- reply } @@ -74,19 +81,23 @@ func (user *User) receiveReplies(replies <-chan Reply) { // Identifier -func (user User) Id() string { +func (user *User) Id() string { return fmt.Sprintf("%s!%s@%s", user.nick, user.nick, user.server.Id()) } -func (user User) PublicId() string { +func (user *User) PublicId() string { return user.Id() } -func (user User) Nick() string { +func (user *User) Nick() string { return user.nick } -func (user User) Commands() chan<- UserCommand { +func (user *User) String() string { + return user.Id() +} + +func (user *User) Commands() chan<- UserCommand { return user.commands } @@ -123,11 +134,11 @@ func (user *User) LogoutClient(c *Client) bool { return false } -func (user User) HasClients() bool { +func (user *User) HasClients() bool { return len(user.clients) > 0 } -func (user User) Replies() chan<- Reply { +func (user *User) Replies() chan<- Reply { return user.replies }