caps: Add message-tags draft capability

This commit is contained in:
Daniel Oaks 2016-10-16 12:54:15 +10:00
parent 90bc444468
commit 2e3ffd2f23
5 changed files with 53 additions and 14 deletions

View File

@ -13,7 +13,7 @@ Improved compatibility, more features, etc.
### Added ### Added
* Added integrated help. * Added integrated help.
* Support for IRCv3 capability [`account-notify`](http://ircv3.net/specs/extensions/account-notify-3.1.html) * Support for IRCv3 capability [`account-notify`](http://ircv3.net/specs/extensions/account-notify-3.1.html), and draft capability [`message-tags`](http://ircv3.net/specs/core/message-tags-3.3.html) as `draft/message-tags`.
### Changed ### Changed
* Casemapping changed from custom unicode mapping to preliminary [rfc7700](https://github.com/ircv3/ircv3-specifications/pull/272) mapping. * Casemapping changed from custom unicode mapping to preliminary [rfc7700](https://github.com/ircv3/ircv3-specifications/pull/272) mapping.

View File

@ -18,6 +18,7 @@ const (
AccountNotify Capability = "account-notify" AccountNotify Capability = "account-notify"
AwayNotify Capability = "away-notify" AwayNotify Capability = "away-notify"
ExtendedJoin Capability = "extended-join" ExtendedJoin Capability = "extended-join"
MessageTags Capability = "draft/message-tags"
MultiPrefix Capability = "multi-prefix" MultiPrefix Capability = "multi-prefix"
SASL Capability = "sasl" SASL Capability = "sasl"
ServerTime Capability = "server-time" ServerTime Capability = "server-time"
@ -30,6 +31,7 @@ var (
AccountNotify: true, AccountNotify: true,
AwayNotify: true, AwayNotify: true,
ExtendedJoin: true, ExtendedJoin: true,
MessageTags: true,
MultiPrefix: true, MultiPrefix: true,
SASL: true, SASL: true,
ServerTime: true, ServerTime: true,

View File

@ -10,6 +10,8 @@ import (
"log" "log"
"strconv" "strconv"
"time" "time"
"github.com/DanielOaks/girc-go/ircmsg"
) )
type Channel struct { type Channel struct {
@ -300,7 +302,7 @@ func (channel *Channel) CanSpeak(client *Client) bool {
return true return true
} }
func (channel *Channel) PrivMsg(client *Client, message string) { func (channel *Channel) PrivMsg(clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message string) {
if !channel.CanSpeak(client) { if !channel.CanSpeak(client) {
client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel") client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
return return
@ -309,7 +311,11 @@ func (channel *Channel) PrivMsg(client *Client, message string) {
if member == client { if member == client {
continue continue
} }
member.SendFromClient(client, nil, client.nickMaskString, "PRIVMSG", channel.name, message) if member.capabilities[MessageTags] {
member.SendFromClient(client, clientOnlyTags, client.nickMaskString, "PRIVMSG", channel.name, message)
} else {
member.SendFromClient(client, nil, client.nickMaskString, "PRIVMSG", channel.name, message)
}
} }
} }

23
irc/message_tags.go Normal file
View File

@ -0,0 +1,23 @@
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license
package irc
import "github.com/DanielOaks/girc-go/ircmsg"
// GetClientOnlyTags tags a tag map, and returns a map containing just the client-only tags from it.
func GetClientOnlyTags(tags map[string]ircmsg.TagValue) *map[string]ircmsg.TagValue {
if len(tags) < 1 {
return nil
}
clientOnlyTags := make(map[string]ircmsg.TagValue)
for name, value := range tags {
if len(name) > 1 && name[0] == '+' {
clientOnlyTags[name] = value
}
}
return &clientOnlyTags
}

View File

@ -91,13 +91,13 @@ func NewServer(config *Config) *Server {
NickLen: config.Limits.NickLen, NickLen: config.Limits.NickLen,
TopicLen: config.Limits.TopicLen, TopicLen: config.Limits.TopicLen,
}, },
name: config.Server.Name, name: config.Server.Name,
nameCasefolded: casefoldedName, nameCasefolded: casefoldedName,
newConns: make(chan clientConn), newConns: make(chan clientConn),
operators: config.Operators(), operators: config.Operators(),
signals: make(chan os.Signal, len(SERVER_SIGNALS)), signals: make(chan os.Signal, len(SERVER_SIGNALS)),
whoWas: NewWhoWasList(config.Limits.WhowasEntries), whoWas: NewWhoWasList(config.Limits.WhowasEntries),
checkIdent: config.Server.CheckIdent, checkIdent: config.Server.CheckIdent,
} }
// open data store // open data store
@ -567,6 +567,7 @@ func topicHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// PRIVMSG <target>{,<target>} <message> // PRIVMSG <target>{,<target>} <message>
func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
clientOnlyTags := GetClientOnlyTags(msg.Tags)
targets := strings.Split(msg.Params[0], ",") targets := strings.Split(msg.Params[0], ",")
message := msg.Params[1] message := msg.Params[1]
@ -578,7 +579,7 @@ func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool
client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, "No such channel") client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, "No such channel")
continue continue
} }
channel.PrivMsg(client, message) channel.PrivMsg(clientOnlyTags, client, message)
} else { } else {
target, err = CasefoldName(targetString) target, err = CasefoldName(targetString)
user := server.clients.Get(target) user := server.clients.Get(target)
@ -586,7 +587,10 @@ func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool
client.Send(nil, server.name, ERR_NOSUCHNICK, target, "No such nick") client.Send(nil, server.name, ERR_NOSUCHNICK, target, "No such nick")
continue continue
} }
user.Send(nil, client.nickMaskString, "PRIVMSG", user.nick, message) if !user.capabilities[MessageTags] {
clientOnlyTags = nil
}
user.Send(clientOnlyTags, client.nickMaskString, "PRIVMSG", user.nick, message)
if user.flags[Away] { if user.flags[Away] {
//TODO(dan): possibly implement cooldown of away notifications to users //TODO(dan): possibly implement cooldown of away notifications to users
client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage) client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
@ -852,6 +856,7 @@ func motdHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// NOTICE <target>{,<target>} <message> // NOTICE <target>{,<target>} <message>
func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
clientOnlyTags := GetClientOnlyTags(msg.Tags)
targets := strings.Split(msg.Params[0], ",") targets := strings.Split(msg.Params[0], ",")
message := msg.Params[1] message := msg.Params[1]
@ -863,7 +868,7 @@ func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// errors silently ignored with NOTICE as per RFC // errors silently ignored with NOTICE as per RFC
continue continue
} }
channel.PrivMsg(client, message) channel.PrivMsg(clientOnlyTags, client, message)
} else { } else {
target, err := CasefoldName(targetString) target, err := CasefoldName(targetString)
if err != nil { if err != nil {
@ -875,7 +880,10 @@ func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// errors silently ignored with NOTICE as per RFC // errors silently ignored with NOTICE as per RFC
continue continue
} }
user.Send(nil, client.nickMaskString, "NOTICE", user.nick, message) if !user.capabilities[MessageTags] {
clientOnlyTags = nil
}
user.Send(clientOnlyTags, client.nickMaskString, "NOTICE", user.nick, message)
} }
} }
return false return false