summaryrefslogtreecommitdiff
path: root/irc/session.go
diff options
context:
space:
mode:
authorHubert Hirtz <hubert@hirtz.pm>2021-09-29 21:47:11 +0200
committerHubert Hirtz <hubert@hirtz.pm>2021-09-29 21:47:11 +0200
commit928c0a068601884260b0fb22a551d35854e6af91 (patch)
tree82d9cced626bd9da23401585bb7cb5ac458c209f /irc/session.go
parentEager registration (diff)
Revert "Eager registration"
Diffstat (limited to '')
-rw-r--r--irc/session.go87
1 files changed, 62 insertions, 25 deletions
diff --git a/irc/session.go b/irc/session.go
index ec90631..716d3fb 100644
--- a/irc/session.go
+++ b/irc/session.go
@@ -115,7 +115,8 @@ type Session struct {
host string
auth SASLClient
- enabledCaps map[string]struct{}
+ availableCaps map[string]string
+ enabledCaps map[string]struct{}
// ISUPPORT features
casemap func(string) string
@@ -143,6 +144,7 @@ func NewSession(out chan<- Message, params SessionParams) *Session {
user: params.Username,
real: params.RealName,
auth: params.Auth,
+ availableCaps: map[string]string{},
enabledCaps: map[string]struct{}{},
casemap: CasemapRFC1459,
chantypes: "#&",
@@ -157,21 +159,9 @@ func NewSession(out chan<- Message, params SessionParams) *Session {
pendingChannels: map[string]time.Time{},
}
- s.out <- NewMessage("CAP", "LS", "302") // needed to advertise 302 support
- for capability := range SupportedCapabilities {
- s.out <- NewMessage("CAP", "REQ", capability)
- }
+ s.out <- NewMessage("CAP", "LS", "302")
s.out <- NewMessage("NICK", s.nick)
s.out <- NewMessage("USER", s.user, "0", "*", s.real)
- if s.auth != nil {
- s.out <- NewMessage("AUTHENTICATE", s.auth.Handshake())
- resp, err := s.auth.Respond("+")
- if err != nil {
- panic(err)
- }
- s.out <- NewMessage("AUTHENTICATE", resp)
- }
- s.out <- NewMessage("CAP", "END")
return s
}
@@ -476,18 +466,53 @@ func (s *Session) handleUnregistered(msg Message) Event {
switch msg.Command {
case "AUTHENTICATE":
if s.auth != nil {
- if msg.Params[0] == "+" {
- // Server has processed the "AUTHENTICATE <mechanism>" message
- } else {
- // Unexpected AUTHENTICATE message from server, abort authentication.
+ res, err := s.auth.Respond(msg.Params[0])
+ if err != nil {
s.out <- NewMessage("AUTHENTICATE", "*")
+ } else {
+ s.out <- NewMessage("AUTHENTICATE", res)
}
}
case rplLoggedin:
+ s.out <- NewMessage("CAP", "END")
s.acct = msg.Params[2]
s.host = ParsePrefix(msg.Params[1]).Host
case errNicklocked, errSaslfail, errSasltoolong, errSaslaborted, errSaslalready, rplSaslmechs:
- // Auth failed, let registration end anyway.
+ s.out <- NewMessage("CAP", "END")
+ case "CAP":
+ switch msg.Params[1] {
+ case "LS":
+ var willContinue bool
+ var ls string
+
+ if msg.Params[2] == "*" {
+ willContinue = true
+ ls = msg.Params[3]
+ } else {
+ willContinue = false
+ ls = msg.Params[2]
+ }
+
+ for _, c := range ParseCaps(ls) {
+ s.availableCaps[c.Name] = c.Value
+ }
+
+ if !willContinue {
+ for c := range s.availableCaps {
+ if _, ok := SupportedCapabilities[c]; !ok {
+ continue
+ }
+ s.out <- NewMessage("CAP", "REQ", c)
+ }
+
+ _, ok := s.availableCaps["sasl"]
+ if s.auth == nil || !ok {
+ s.out <- NewMessage("CAP", "END")
+ }
+ }
+ default:
+ return s.handleRegistered(msg)
+ }
case errNicknameinuse:
s.out <- NewMessage("NICK", msg.Params[1]+"_")
case rplSaslsuccess:
@@ -538,26 +563,38 @@ func (s *Session) handleRegistered(msg Message) Event {
delete(s.enabledCaps, c.Name)
}
- if c.Name == "multi-prefix" {
+ if s.auth != nil && c.Name == "sasl" {
+ h := s.auth.Handshake()
+ s.out <- NewMessage("AUTHENTICATE", h)
+ } else if len(s.channels) != 0 && c.Name == "multi-prefix" {
// TODO merge NAMES commands
for channel := range s.channels {
s.out <- NewMessage("NAMES", channel)
}
}
}
+ case "NAK":
+ // do nothing
case "NEW":
for _, c := range ParseCaps(msg.Params[2]) {
- if _, ok := SupportedCapabilities[c.Name]; ok {
- s.out <- NewMessage("CAP", "REQ", c.Name)
+ s.availableCaps[c.Name] = c.Value
+ _, ok := SupportedCapabilities[c.Name]
+ if !ok {
+ continue
}
- // TODO authenticate if necessary
+ s.out <- NewMessage("CAP", "REQ", c.Name)
+ }
+
+ _, ok := s.availableCaps["sasl"]
+ if s.acct == "" && ok {
+ // TODO authenticate
}
case "DEL":
for _, c := range ParseCaps(msg.Params[2]) {
+ delete(s.availableCaps, c.Name)
delete(s.enabledCaps, c.Name)
}
}
- // do nothing on LS and NAK
case "JOIN":
nickCf := s.Casemap(msg.Prefix.Name)
channelCf := s.Casemap(msg.Params[0])
@@ -710,7 +747,7 @@ func (s *Session) handleRegistered(msg Message) Event {
if c, ok := s.channels[channelCf]; ok {
return ModeChangeEvent{
Channel: c.Name,
- Mode: strings.Join(msg.Params[1:], " "),
+ Mode: strings.Join(msg.Params[1:], " "),
}
}
case "PRIVMSG", "NOTICE":