diff --git a/irc/channel.go b/irc/channel.go index 54e4379c..a95ebeba 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -402,3 +402,22 @@ func (channel *Channel) Kick(client *Client, target *Client, comment string) { } channel.Quit(target) } + +func (channel *Channel) Invite(invitee *Client, inviter *Client) { + if channel.flags[InviteOnly] && !channel.ClientIsOperator(inviter) { + inviter.ErrChanOPrivIsNeeded(channel) + return + } + + if !channel.members.Has(inviter) { + inviter.ErrNotOnChannel(channel) + return + } + + // TODO Modify channel masks + inviter.RplInviting(invitee, channel.name) + invitee.Reply(RplInviteMsg(inviter, channel.name)) + if invitee.flags[Away] { + inviter.RplAway(invitee) + } +} diff --git a/irc/commands.go b/irc/commands.go index 6fad2f32..d935ec04 100644 --- a/irc/commands.go +++ b/irc/commands.go @@ -29,6 +29,7 @@ var ( AWAY: NewAwayCommand, CAP: NewCapCommand, DEBUG: NewDebugCommand, + INVITE: NewInviteCommand, ISON: NewIsOnCommand, JOIN: NewJoinCommand, KICK: NewKickCommand, @@ -914,3 +915,20 @@ func NewVersionCommand(args []string) (editableCommand, error) { } return cmd, nil } + +type InviteCommand struct { + BaseCommand + nickname string + channel string +} + +func NewInviteCommand(args []string) (editableCommand, error) { + if len(args) < 2 { + return nil, NotEnoughArgsError + } + + return &InviteCommand{ + nickname: args[0], + channel: args[1], + }, nil +} diff --git a/irc/reply.go b/irc/reply.go index bd53ec25..18b30549 100644 --- a/irc/reply.go +++ b/irc/reply.go @@ -128,8 +128,8 @@ func RplError(message string) string { return NewStringReply(nil, ERROR, ":%s", message) } -func RplInviteMsg(channel *Channel, inviter *Client) string { - return NewStringReply(inviter, INVITE, channel.name) +func RplInviteMsg(inviter *Client, channel string) string { + return NewStringReply(inviter, INVITE, channel) } func RplKick(channel *Channel, client *Client, target *Client, comment string) string { @@ -175,9 +175,9 @@ func (target *Client) RplTopic(channel *Channel) { // // NB: correction in errata -func (target *Client) RplInvitingMsg(channel *Channel, invitee *Client) { +func (target *Client) RplInvitingMsg(invitee *Client, channel string) { target.NumericReply(RPL_INVITING, - "%s %s", invitee.Nick(), channel.name) + "%s %s", invitee.Nick(), channel) } func (target *Client) RplEndOfNames(channel *Channel) { @@ -369,6 +369,11 @@ func (target *Client) RplVersion() { "ergonomadic-%s %s", SERVER_VERSION, target.server.name) } +func (target *Client) RplInviting(invitee *Client, channel string) { + target.NumericReply(RPL_INVITING, + "%s %s", invitee.Nick(), channel) +} + // // errors (also numeric) // diff --git a/irc/server.go b/irc/server.go index f15780fb..8d3b72d8 100644 --- a/irc/server.go +++ b/irc/server.go @@ -448,7 +448,7 @@ func (msg *PrivMsgCommand) HandleServer(server *Server) { } target.Reply(RplPrivMsg(client, target, msg.message)) if target.flags[Away] { - target.RplAway(client) + client.RplAway(target) } } @@ -772,3 +772,22 @@ func (msg *VersionCommand) HandleServer(server *Server) { client.RplVersion() } + +func (msg *InviteCommand) HandleServer(server *Server) { + client := msg.Client() + + target := server.clients.Get(msg.nickname) + if target == nil { + client.ErrNoSuchNick(msg.nickname) + return + } + + channel := server.channels[msg.channel] + if channel == nil { + client.RplInviting(target, msg.channel) + target.Reply(RplInviteMsg(client, msg.channel)) + return + } + + channel.Invite(target, client) +}