Skip to content

Commit

Permalink
Fallback to alt nick
Browse files Browse the repository at this point in the history
If the nickname we want is taken, fallback to another one by
appending underscores. Use MONITOR to figure out when we can request
our desired nick again.

Closes: https://todo.sr.ht/~emersion/soju/35
  • Loading branch information
emersion committed Dec 4, 2021
1 parent f2a28f6 commit 1c285a1
Showing 1 changed file with 48 additions and 2 deletions.
50 changes: 48 additions & 2 deletions upstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,8 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err
}
}

uc.updateMonitor()

uc.forEachDownstream(func(dc *downstreamConn) {
if dc.network == nil {
return
Expand Down Expand Up @@ -876,6 +878,7 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err
uc.forEachDownstream(func(dc *downstreamConn) {
dc.updateNick()
})
uc.updateMonitor()
}
case "SETNAME":
if msg.Prefix == nil {
Expand Down Expand Up @@ -1522,6 +1525,27 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err
uc.monitored.SetValue(prefix.Name, online)
}

// Check if the nick we want is now free
wantNick := GetNick(&uc.user.User, &uc.network.Network)
wantNickCM := uc.network.casemap(wantNick)
if !online && uc.nickCM != wantNickCM {
found := false
for _, target := range targets {
prefix := irc.ParsePrefix(target)
if uc.network.casemap(prefix.Name) == wantNickCM {
found = true
break
}
}
if found {
uc.logger.Printf("desired nick %q is now available", wantNick)
uc.SendMessage(&irc.Message{
Command: "NICK",
Params: []string{wantNick},
})
}
}

uc.forEachDownstream(func(dc *downstreamConn) {
for _, target := range targets {
prefix := irc.ParsePrefix(target)
Expand Down Expand Up @@ -1687,7 +1711,22 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err
return err
}
return fmt.Errorf("fatal server error: %v", text)
case irc.ERR_PASSWDMISMATCH, irc.ERR_ERRONEUSNICKNAME, irc.ERR_NICKNAMEINUSE, irc.ERR_NICKCOLLISION, irc.ERR_UNAVAILRESOURCE, irc.ERR_NOPERMFORHOST, irc.ERR_YOUREBANNEDCREEP:
case irc.ERR_NICKNAMEINUSE:
// At this point, we haven't received ISUPPORT so we don't know the
// maximum nickname length or whether the server supports MONITOR. Many
// servers have NICKLEN=30 so let's just use that.
if !uc.registered && len(uc.nick)+1 < 30 {
uc.nick = uc.nick + "_"
uc.nickCM = uc.network.casemap(uc.nick)
uc.logger.Printf("desired nick is not available, falling back to %q", uc.nick)
uc.SendMessage(&irc.Message{
Command: "NICK",
Params: []string{uc.nick},
})
return nil
}
fallthrough
case irc.ERR_PASSWDMISMATCH, irc.ERR_ERRONEUSNICKNAME, irc.ERR_NICKCOLLISION, irc.ERR_UNAVAILRESOURCE, irc.ERR_NOPERMFORHOST, irc.ERR_YOUREBANNEDCREEP:
if !uc.registered {
return registrationError{msg}
}
Expand Down Expand Up @@ -2087,14 +2126,21 @@ func (uc *upstreamConn) updateMonitor() {
if !uc.monitored.Has(targetCM) {
if _, ok := add[targetCM]; !ok {
addList = append(addList, targetCM)
add[targetCM] = struct{}{}
}
add[targetCM] = struct{}{}
} else {
seen[targetCM] = struct{}{}
}
}
})

wantNick := GetNick(&uc.user.User, &uc.network.Network)
wantNickCM := uc.network.casemap(wantNick)
if _, ok := add[wantNickCM]; !ok && !uc.monitored.Has(wantNick) && !uc.isOurNick(wantNick) {
addList = append(addList, wantNickCM)
add[wantNickCM] = struct{}{}
}

removeAll := true
var removeList []string
for targetCM, entry := range uc.monitored.innerMap {
Expand Down

0 comments on commit 1c285a1

Please sign in to comment.