Skip to content

Commit

Permalink
add GetReplyTarget (#105)
Browse files Browse the repository at this point in the history
* add GetReplyTarget

See #97

* clarify error behavior
  • Loading branch information
slingamn authored Feb 11, 2024
1 parent 22ffb35 commit 8895cdf
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
37 changes: 37 additions & 0 deletions ircevent/irc_struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"crypto/tls"
"log"
"net"
"strings"
"sync"
"sync/atomic"
"time"
Expand Down Expand Up @@ -195,6 +196,42 @@ func (irc *Connection) labelNegotiated() bool {
return atomic.LoadUint32(&irc.capFlags)&capFlagLabeledResponse != 0
}

// GetReplyTarget attempts to determine where replies to a PRIVMSG or NOTICE
// should be sent (a channel if the message was sent to a channel, a nick
// if the message was a direct message from a valid nickname). If no valid
// reply target can be determined, it returns the empty string.
func (irc *Connection) GetReplyTarget(msg ircmsg.Message) string {
switch msg.Command {
case "PRIVMSG", "NOTICE", "TAGMSG":
if len(msg.Params) == 0 {
return ""
}
target := msg.Params[0]
chanTypes := irc.ISupport()["CHANTYPES"]
if chanTypes == "" {
chanTypes = "#"
}
for i := 0; i < len(chanTypes); i++ {
if strings.HasPrefix(target, chanTypes[i:i+1]) {
return target
}
}
// this was not a channel message: attempt to reply to the source
if nuh, err := msg.NUH(); err == nil {
if strings.IndexByte(nuh.Name, '.') == -1 {
return nuh.Name
} else {
// this is probably a server name
return ""
}
} else {
return ""
}
default:
return ""
}
}

// Deprecated; use (*ircmsg.Message).Nick() instead
func ExtractNick(source string) string {
nuh, err := ircmsg.ParseNUH(source)
Expand Down
32 changes: 32 additions & 0 deletions ircevent/irc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,35 @@ func TestConnectionCallbacks(t *testing.T) {
<-loopExited
assertEqual(disconnectCalled, true)
}

func mustParse(line string) ircmsg.Message {
msg, err := ircmsg.ParseLine(line)
if err != nil {
panic(err)
}
return msg
}

func TestGetReplyTarget(t *testing.T) {
irc := Connection{}
assertEqual(irc.GetReplyTarget(mustParse(":[email protected] PRIVMSG #ergo :hi")), "#ergo")
assertEqual(irc.GetReplyTarget(mustParse(":[email protected] PRIVMSG titlebot :hi")), "shivaram")
irc.isupport = map[string]string{
"CHANTYPES": "#&",
}
assertEqual(irc.GetReplyTarget(mustParse(":[email protected] PRIVMSG #ergo :hi")), "#ergo")
assertEqual(irc.GetReplyTarget(mustParse(":[email protected] PRIVMSG &ergo :hi")), "&ergo")
assertEqual(irc.GetReplyTarget(mustParse(":[email protected] PRIVMSG titlebot :hi")), "shivaram")
assertEqual(irc.GetReplyTarget(mustParse(":irc.ergo.chat NOTICE titlebot :Server is shutting down")), "")

// no source but it's a channel message
assertEqual(irc.GetReplyTarget(mustParse("PRIVMSG #ergo :hi")), "#ergo")
// no source but it's a DM (no way to reply)
assertEqual(irc.GetReplyTarget(mustParse("PRIVMSG titlebot :hi")), "")
// invalid messages
assertEqual(irc.GetReplyTarget(mustParse(":[email protected] PRIVMSG")), "")
assertEqual(irc.GetReplyTarget(mustParse("PRIVMSG")), "")
assertEqual(irc.GetReplyTarget(mustParse("PRIVMSG :")), "")
// not a PRIVMSG
assertEqual(irc.GetReplyTarget(mustParse(":testnet.ergo.chat 371 shivaram :This is Ergo version 2.13.0.")), "")
}

0 comments on commit 8895cdf

Please sign in to comment.