From 52e579e364594fd043a7c85fe91ced72362f4a99 Mon Sep 17 00:00:00 2001 From: megaproxy Date: Thu, 4 Jun 2026 17:25:18 +0100 Subject: [PATCH] Defer JOIN until NickServ login confirmed (fixes +r channel 477) --- bot.py | 29 ++++++++++++++++++++++++++--- memory.md | 17 +++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/bot.py b/bot.py index 20c3dd8..c760ef4 100644 --- a/bot.py +++ b/bot.py @@ -173,8 +173,13 @@ class IRCBot: time.sleep(backoff) backoff = min(backoff * 2, 300) + def _join_channel(self): + log.info("Joining %s", CHANNEL) + self._send_raw(f"JOIN {CHANNEL}") + def _event_loop(self): registered = False + joined = False for line in self._read_lines(): log.debug("<< %s", line) prefix, command, params = parse_message(line) @@ -183,15 +188,33 @@ class IRCBot: self._send_raw(f"PONG :{params[-1] if params else ''}") continue - # 376 = end of MOTD, 422 = no MOTD; either means we can join. + # 376 = end of MOTD, 422 = no MOTD; either means we're registered. if command in ("376", "422") and not registered: registered = True if NICKSERV_PASS: + # Identify first, then wait for the login confirmation + # below before joining. +r channels reject us until the + # NickServ login has actually landed, so joining now races. self.send_privmsg("NickServ", f"IDENTIFY {NICKSERV_PASS}") - log.info("Joining %s", CHANNEL) - self._send_raw(f"JOIN {CHANNEL}") + log.info("Identifying with NickServ; join deferred until login") + else: + self._join_channel() + joined = True continue + # 900 RPL_LOGGEDIN, or the NickServ "now identified" notice — + # either confirms login is complete, so it's safe to join +r chans. + if not joined and registered and NICKSERV_PASS: + identified = command == "900" or ( + command == "NOTICE" + and prefix.lower().startswith("nickserv!") + and "now identified" in (params[-1].lower() if params else "") + ) + if identified: + self._join_channel() + joined = True + continue + # Nick already in use — try a variant so we still connect. if command == "433": global NICK diff --git a/memory.md b/memory.md index 630d897..89827f8 100644 --- a/memory.md +++ b/memory.md @@ -17,11 +17,16 @@ Durable memory for this project. Read at session start, update before session en ## Open questions / TODOs -- [ ] Live-test against Libera (join `#r.trees`, exercise commands). Not yet run. +- [ ] Exercise the `!` commands live in-channel (connect + join verified; command + round-trip not yet tested with a second client). - [ ] Decide whether `!delquote` should be restricted to ops/admins (currently anyone can delete). Fine for a trusted channel; revisit if abused. -- [ ] Consider registering the `treesquotes` nick with NickServ if the channel - blocks unregistered users. + +## Resolved + +- `#r.trees` is `+r` (registered-nicks-only). Nick `treesquotes` is registered & + NickServ-verified under megaproxy@gmail.com. Password lives in gitignored + `config.env` (`IRC_NICKSERV_PASS`). Bot identifies and joins successfully. ## Session log @@ -30,7 +35,11 @@ Durable memory for this project. Read at session start, update before session en - Wrote `bot.py`: stdlib IRC client (TLS, PING/PONG, reconnect, nick fallback), `QuoteStore` SQLite wrapper, and `!` command handlers. - Added `README.md`, `config.example.env`; gitignored `quotes.db`/`config.env`. -- Syntax-checked with `py_compile` (Python 3.12.3). Not yet live-tested on IRC. +- Syntax-checked with `py_compile` (Python 3.12.3). +- Live-tested against Libera: discovered `#r.trees` is `+r`. Registered/verified + the `treesquotes` nick. Fixed a join race — bot was sending JOIN before the + NickServ login landed and getting bounced (477); now defers JOIN until the + `900`/"now identified" confirmation. Verified join succeeds (got 353/366). ## External references