From 56155fb9c2d1ca74c34b56d6982bb95f6203001b Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 18 Aug 2025 18:23:44 +0200 Subject: [PATCH] Allow disconnected /nick changes, and only disconnect on 432 if no fallback. --- ircplom/client.py | 39 +++++++++++++++++++++------------------ ircplom/client_tui.py | 2 +- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/ircplom/client.py b/ircplom/client.py index 248a3ba..e4e5e60 100644 --- a/ircplom/client.py +++ b/ircplom/client.py @@ -45,15 +45,6 @@ class _IrcMsg(IrcMessage): and (n_msg_params == len_params or len_is_min and n_msg_params > len_params)) - def nick_conforms(self, db: '_ClientDb') -> bool: - 'Test .nick_from_source == db.nickname.' - return self.nick_from_source == db.nickname - - def confirm_nick(self, db: '_ClientDb') -> None: - 'Assume .params[0] confirms nickname.' - db.nickname = self.params[0] - db.nickname_confirmed = True - @property def nick_from_source(self) -> str: 'Parse .source into user nickname.' @@ -512,7 +503,7 @@ class Client(ABC, ClientQueueMixin): 'Log msg.raw, then process incoming msg into appropriate client steps.' self._log(msg.raw, scope=LogScope.RAW, out=False) if _NumericsToConfirmNickname.contain(msg.verb): - msg.confirm_nick(self._db) + self.set_nick(msg.params[0], confirm=True) if _NumericsToIgnore.contain(msg.verb): return if msg.match('005', 2, True): # RPL_ISUPPORT @@ -531,12 +522,16 @@ class Client(ABC, ClientQueueMixin): # claims: " can also be in the form " self._db.client_host = msg.params[1].split('@')[-1] elif msg.match('432', 3): # ERR_ERRONEOUSNICKNAME - self._log('nickname refused for bad format, giving up', alert=True) - self.close() + if msg.params[0] == '*': + self._log(alert=True, + msg='nickname refused for bad format, giving up') + self.close() + else: + self._db.nickname = msg.params[0] + self._db.nickname_confirmed = True elif msg.match('433', 3): # ERR_NICKNAMEINUSE - new_nick = self._db.nick_incremented - self._log('nickname already in use, trying {new_nick}', alert=True) - self.send(IrcMessage(verb='NICK', params=(new_nick,))) + self._log('nickname already in use, trying increment', alert=True) + self.set_nick(self._db.nick_incremented) elif msg.match('903', 2) or msg.match('904', 2): # RPL_SUCESS, or … self._db.sasl_auth_state = 'WIN' if msg.verb == '903' else 'FAIL' self._caps.end_negotiation() # … ERR_SASLFAIL @@ -559,8 +554,8 @@ class Client(ABC, ClientQueueMixin): self.close() elif msg.match('MODE', 2) and msg.params[0] == self._db.nickname: self._db.user_modes = msg.params[1] - elif msg.match('NICK') and msg.nick_conforms(self._db): - msg.confirm_nick(self._db) + elif msg.match('NICK'): + self.set_nick(msg.params[0], confirm=True) elif msg.match('NOTICE', 2) or msg.match('PRIVMSG', 2): scope = LogScope.CHAT if '!' in msg.source else LogScope.SERVER self._log(msg.params[-1], scope=scope, channel=msg.params[0], @@ -574,7 +569,7 @@ class Client(ABC, ClientQueueMixin): self._log(log_msg, scope=LogScope.CHAT, channel=channel) if msg.verb == 'JOIN': self._db.chan(channel).users.append(msg.nick_from_source) - elif msg.nick_conforms(self._db): + elif msg.nick_from_source == self._db.nickname: self._db.del_chan(channel) else: self._db.chan(channel).users.remove(msg.nick_from_source) @@ -583,6 +578,14 @@ class Client(ABC, ClientQueueMixin): else: self._log(f'PLEASE IMPLEMENT HANDLER FOR: {msg.raw}') + def set_nick(self, new_nickname: str, confirm=False) -> None: + 'Set ClientDb\'s .nickname, .…_confirmed, and sends NICK if connected.' + if new_nickname != self._db.nickname: + if self.conn: + self.send(IrcMessage(verb='NICK', params=(new_nickname,))) + self._db.nickname = new_nickname + self._db.nickname_confirmed = confirm + @dataclass class NewClientEvent(AffectiveEvent): diff --git a/ircplom/client_tui.py b/ircplom/client_tui.py index f0fbd3f..2f66d7b 100644 --- a/ircplom/client_tui.py +++ b/ircplom/client_tui.py @@ -49,7 +49,7 @@ class _ClientWindow(Window, ClientQueueMixin): def cmd__nick(self, new_nick: str) -> None: 'Attempt nickname change.' - self._send_msg('NICK', (new_nick,)) + self._client_trigger('set_nick', new_nickname=new_nick) def cmd__join(self, channel: str) -> None: 'Attempt joining a channel.' -- 2.30.2