From 8c0c98268440b27a77faf30738dfd72c909bb33f Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Thu, 6 Apr 2023 18:41:06 -0700 Subject: [PATCH] Add hook to regain nickname in ERC * lisp/erc/erc-backend.el (erc-server-reconnect-timeout): Mention `erc-nickname-in-use-functions' in doc string. * lisp/erc/erc.el (erc-nickname-in-use-functions, erc-regain-nick-on-connect): Add abnormal hook and possible value to handle stale connections preventing a desired nick from being reissued by the server. Follows directly from bug#62044. (erc-nickname-in-use): Call `erc-nickname-in-use-functions'. * test/lisp/erc/erc-scenarios-base-renick.el (erc-scenarios-base-renick-auto-regain): New test. * test/lisp/erc/resources/base/renick/regain/normal-again.eld: New file. * test/lisp/erc/resources/base/renick/regain/normal.eld: New file. --- lisp/erc/erc-backend.el | 4 +- lisp/erc/erc.el | 47 ++++++++++++++++ test/lisp/erc/erc-scenarios-base-renick.el | 43 ++++++++++++++ .../base/renick/regain/normal-again.eld | 56 +++++++++++++++++++ .../resources/base/renick/regain/normal.eld | 53 ++++++++++++++++++ 5 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 test/lisp/erc/resources/base/renick/regain/normal-again.eld create mode 100644 test/lisp/erc/resources/base/renick/regain/normal.eld diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index acfbe3ef3a6..84d6b8a7efd 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -418,7 +418,9 @@ This only has an effect if `erc-server-auto-reconnect' is non-nil." If this value is too low, servers may reject your initial nick request upon reconnecting because they haven't yet noticed that your previous connection is dead. If this happens, try setting -this value to 120 or greater." +this value to 120 or greater and/or exploring the option +`erc-nickname-in-use-functions', which may provide a more +proactive means of handling this situation on some servers." :type 'number) (defcustom erc-server-reconnect-function 'erc-server-delayed-reconnect diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 66bc4985027..6d35a62518d 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -392,6 +392,24 @@ Each function should accept two arguments, NEW-NICK and OLD-NICK." :group 'erc-hooks :type 'hook) +(defcustom erc-nickname-in-use-functions nil + "Function to run before trying for a different nickname. +Called with two arguments: the desired but just rejected nickname +and the alternate nickname about to be requested. Use cases +include special handling during connection registration and +wrestling with nickname services. For example, value +`erc-regain-nick-on-connect' is aimed at dealing with reaping +lingering connections that may prevent you from being issued a +requested nick immediately when reconnecting. It's meant to be +used with an `erc-server-reconnect-function' value of +`erc-server-delayed-check-reconnect' alongside SASL +authentication." + :package-version '(ERC . "5.6") + :group 'erc-hooks + :type '(choice (function-item erc-regain-nick-on-connect) + function + (const nil))) + (defcustom erc-connect-pre-hook '(erc-initialize-log-marker) "Hook called just before `erc' calls `erc-connect'. Functions are passed a buffer as the first argument." @@ -4594,6 +4612,34 @@ E.g. \"Read error to Nick [user@some.host]: 110\" would be shortened to (match-string 1 reason)) reason)) +(defun erc-regain-nick-on-connect (want temp) + "Try at most once to grab nickname WANT after settling for TEMP. +Only do so during connection registration, likely prior to +authenticating with SASL. Assume the prior connection was lost +due to connectivity failure and that the server hasn't yet +noticed. Also assume that the server won't process any +authentication-related messages until it has accepted a mulligan +nick or at least sent a 433 and thus triggered +`erc-nickname-in-use-functions'. Expect authentication to have +succeeded by the time a logical IRC connection has been +established and that the contending connection may otherwise +still be alive and require manual intervention involving +NickServ." + (unless erc-server-connected + (letrec ((after-connect + (lambda (_ nick) + (remove-hook 'erc-after-connect after-connect t) + (when (equal temp nick) + (erc-cmd-NICK want)))) + (on-900 + (lambda (_ parsed) + (remove-hook 'erc-server-900-functions on-900 t) + (unless erc-server-connected + (when (equal (car (erc-response.command-args parsed)) temp) + (add-hook 'erc-after-connect after-connect nil t))) + nil))) + (add-hook 'erc-server-900-functions on-900 nil t)))) + (defun erc-nickname-in-use (nick reason) "If NICK is unavailable, tell the user the REASON. @@ -4627,6 +4673,7 @@ See also `erc-display-error-notice'." ;; established a connection yet (- 9 (length erc-nick-uniquifier)))) erc-nick-uniquifier))) + (run-hook-with-args 'erc-nickname-in-use-functions nick newnick) (erc-cmd-NICK newnick) (erc-display-error-notice nil diff --git a/test/lisp/erc/erc-scenarios-base-renick.el b/test/lisp/erc/erc-scenarios-base-renick.el index f1723200533..f8350676fb7 100644 --- a/test/lisp/erc/erc-scenarios-base-renick.el +++ b/test/lisp/erc/erc-scenarios-base-renick.el @@ -303,4 +303,47 @@ (should-not (search-forward "now known as frenemy" nil t)) (erc-d-t-search-for 25 "I have lost")))) +;; The server rejects your nick during registration, so ERC acquires a +;; placeholder and successfully renicks once the connection is up. +;; See also `erc-scenarios-base-renick-self-auto'. + +(ert-deftest erc-scenarios-base-renick-auto-regain () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-server-flood-penalty 0.1) + (erc-scenarios-common-dialog "base/renick/regain") + (dumb-server (erc-d-run "localhost" t 'normal 'normal-again)) + (port (process-contact dumb-server :service)) + (erc-server-auto-reconnect t) + (erc-modules (cons 'sasl erc-modules)) + (erc-nickname-in-use-functions '(erc-regain-nick-on-connect)) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Session succeeds but cut short") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (funcall expect 10 "Last login from") + (erc-cmd-JOIN "#test"))) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#test")) + (funcall expect 10 "was created on")) + + (ert-info ("Service restored") + (with-current-buffer "Libera.Chat" + (erc-d-t-wait-for 10 erc--server-reconnect-timer) + (funcall expect 10 "Connection failed!") + (funcall expect 10 "already in use") + (funcall expect 10 "changed mode for tester`") + (funcall expect 10 "Last login from") + (funcall expect 10 "Your new nickname is tester"))) + + (with-current-buffer (get-buffer "#test") + (funcall expect 10 "tester ") + (funcall expect 10 "was created on")))) + + ;;; erc-scenarios-base-renick.el ends here diff --git a/test/lisp/erc/resources/base/renick/regain/normal-again.eld b/test/lisp/erc/resources/base/renick/regain/normal-again.eld new file mode 100644 index 00000000000..c0529052c70 --- /dev/null +++ b/test/lisp/erc/resources/base/renick/regain/normal-again.eld @@ -0,0 +1,56 @@ +;; -*- mode: lisp-data; -*- +((cap 10 "CAP REQ :sasl")) +((nick 10 "NICK tester")) +((user 10 "USER tester 0 * :tester")) + +((authenticate 10 "AUTHENTICATE PLAIN") + (0.04 ":tantalum.libera.chat NOTICE * :*** Checking Ident") + (0.01 ":tantalum.libera.chat NOTICE * :*** Looking up your hostname...") + (0.01 ":tantalum.libera.chat NOTICE * :*** Couldn't look up your hostname") + (0.06 ":tantalum.libera.chat NOTICE * :*** No Ident response") + (0.02 ":tantalum.libera.chat CAP * ACK :sasl") + (0.03 ":tantalum.libera.chat 433 * tester :Nickname is already in use.")) + +((nick 10 "NICK tester`") + (0.03 "AUTHENTICATE +")) + +((authenticate 10 "AUTHENTICATE AHRlc3RlcgBjaGFuZ2VtZQ==") + (0.06 ":tantalum.libera.chat 900 tester` tester`!tester@127.0.0.1 tester :You are now logged in as tester") + (0.02 ":tantalum.libera.chat 903 tester` :SASL authentication successful")) + +((cap 10 "CAP END") + (0.02 ":tantalum.libera.chat 001 tester` :Welcome to the Libera.Chat Internet Relay Chat Network tester`") + (0.02 ":tantalum.libera.chat 002 tester` :Your host is tantalum.libera.chat[93.158.237.2/6697], running version solanum-1.0-dev") + (0.02 ":tantalum.libera.chat 003 tester` :This server was created Mon Feb 13 2023 at 12:05:04 UTC") + (0.01 ":tantalum.libera.chat 004 tester` tantalum.libera.chat solanum-1.0-dev DGMQRSZaghilopsuwz CFILMPQRSTbcefgijklmnopqrstuvz bkloveqjfI") + (0.01 ":tantalum.libera.chat 005 tester` WHOX MONITOR=100 SAFELIST ELIST=CMNTU ETRACE FNC CALLERID=g KNOCK CHANTYPES=# EXCEPTS INVEX CHANMODES=eIbq,k,flj,CFLMPQRSTcgimnprstuz :are supported by this server") + (0.01 ":tantalum.libera.chat 005 tester` CHANLIMIT=#:250 PREFIX=(ov)@+ MAXLIST=bqeI:100 MODES=4 NETWORK=Libera.Chat STATUSMSG=@+ CASEMAPPING=rfc1459 NICKLEN=16 MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by this server") + (0.03 ":tantalum.libera.chat 005 tester` TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: EXTBAN=$,ajrxz :are supported by this server") + (0.01 ":tantalum.libera.chat 251 tester` :There are 70 users and 42977 invisible on 28 servers") + (0.00 ":tantalum.libera.chat 252 tester` 38 :IRC Operators online") + (0.00 ":tantalum.libera.chat 253 tester` 87 :unknown connection(s)") + (0.00 ":tantalum.libera.chat 254 tester` 22908 :channels formed") + (0.00 ":tantalum.libera.chat 255 tester` :I have 2507 clients and 1 servers") + (0.00 ":tantalum.libera.chat 265 tester` 2507 3232 :Current local users 2507, max 3232") + (0.00 ":tantalum.libera.chat 266 tester` 43047 51777 :Current global users 43047, max 51777") + (0.00 ":tantalum.libera.chat 250 tester` :Highest connection count: 3233 (3232 clients) (284887 connections received)") + (0.03 ":tantalum.libera.chat 375 tester` :- tantalum.libera.chat Message of the Day - ") + (0.00 ":tantalum.libera.chat 372 tester` :- This server provided by Hyperfilter (https://hyperfilter.com)") + (0.00 ":tantalum.libera.chat 372 tester` :- Email: support@libera.chat") + (0.02 ":tantalum.libera.chat 376 tester` :End of /MOTD command.")) + +((mode 10 "MODE tester` +i") + (0.01 ":tester` MODE tester` :+Ziw") + (0.02 ":SaslServ!SaslServ@services.libera.chat NOTICE tester` :Last login from: \2~tester@127.0.0.1\2 on Apr 07 01:36:25 2023 +0000.")) + +((nick 10 "NICK tester") + (0.02 ":tester`!~tester@127.0.0.1 NICK :tester")) + +((join 10 "JOIN #test") + (0.02 ":tester!~tester@127.0.0.1 JOIN #test") + (0.02 ":tantalum.libera.chat 353 tester = #test :tester zbyqbepbqre7 pusevgfpu Thrfg2187 zngbeb qnexNssvavgl wrebzr- rqpentt Ilehf grfg2 AvtugZbaxrl pevfgvvbna xrivap_ fnvybePng shohxv gxan arrqyr avpx16 NeanhqW_kzcc jvyyr wrnaogeq Wnarg cnefavc0 Xbentt RcvpArb flfqrs wfgbxre hafcrag__ Lbevpx_") + (0.02 ":tantalum.libera.chat 366 tester #test :End of /NAMES list.")) + +((mode 10 "MODE #test") + (0.02 ":tantalum.libera.chat 324 tester #test +nt") + (0.02 ":tantalum.libera.chat 329 tester #test 1621432263")) diff --git a/test/lisp/erc/resources/base/renick/regain/normal.eld b/test/lisp/erc/resources/base/renick/regain/normal.eld new file mode 100644 index 00000000000..9f4df70e580 --- /dev/null +++ b/test/lisp/erc/resources/base/renick/regain/normal.eld @@ -0,0 +1,53 @@ +;; -*- mode: lisp-data; -*- +((cap 10 "CAP REQ :sasl")) +((nick 10 "NICK tester")) +((user 10 "USER tester 0 * :tester")) + +((authenticate 10 "AUTHENTICATE PLAIN") + (0.02 ":cadmium.libera.chat NOTICE * :*** Checking Ident") + (0.01 ":cadmium.libera.chat NOTICE * :*** Looking up your hostname...") + (0.01 ":cadmium.libera.chat NOTICE * :*** Couldn't look up your hostname") + (0.06 ":cadmium.libera.chat NOTICE * :*** No Ident response") + (0.09 ":cadmium.libera.chat CAP * ACK :sasl") + (0.01 "AUTHENTICATE +")) + +((authenticate 10 "AUTHENTICATE AHRlc3RlcgBjaGFuZ2VtZQ==") + (0.03 ":cadmium.libera.chat 900 tester tester!tester@127.0.0.1 tester :You are now logged in as tester") + (0.01 ":cadmium.libera.chat 903 tester :SASL authentication successful")) + +((cap 10 "CAP END") + (0.03 ":cadmium.libera.chat 001 tester :Welcome to the Libera.Chat Internet Relay Chat Network tester") + (0.02 ":cadmium.libera.chat 002 tester :Your host is cadmium.libera.chat[103.196.37.95/6697], running version solanum-1.0-dev") + (0.01 ":cadmium.libera.chat 003 tester :This server was created Wed Jan 25 2023 at 10:22:45 UTC") + (0.01 ":cadmium.libera.chat 004 tester cadmium.libera.chat solanum-1.0-dev DGMQRSZaghilopsuwz CFILMPQRSTbcefgijklmnopqrstuvz bkloveqjfI") + (0.00 ":cadmium.libera.chat 005 tester CALLERID=g WHOX ETRACE FNC SAFELIST ELIST=CMNTU KNOCK MONITOR=100 CHANTYPES=# EXCEPTS INVEX CHANMODES=eIbq,k,flj,CFLMPQRSTcgimnprstuz :are supported by this server") + (0.01 ":cadmium.libera.chat 005 tester CHANLIMIT=#:250 PREFIX=(ov)@+ MAXLIST=bqeI:100 MODES=4 NETWORK=Libera.Chat STATUSMSG=@+ CASEMAPPING=rfc1459 NICKLEN=16 MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by this server") + (0.01 ":cadmium.libera.chat 005 tester TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: EXTBAN=$,ajrxz :are supported by this server") + (0.01 ":cadmium.libera.chat 251 tester :There are 70 users and 42996 invisible on 28 servers") + (0.02 ":cadmium.libera.chat 252 tester 38 :IRC Operators online") + (0.01 ":cadmium.libera.chat 253 tester 57 :unknown connection(s)") + (0.01 ":cadmium.libera.chat 254 tester 22912 :channels formed") + (0.01 ":cadmium.libera.chat 255 tester :I have 2499 clients and 1 servers") + (0.01 ":cadmium.libera.chat 265 tester 2499 4187 :Current local users 2499, max 4187") + (0.01 ":cadmium.libera.chat 266 tester 43066 51827 :Current global users 43066, max 51827") + (0.01 ":cadmium.libera.chat 250 tester :Highest connection count: 4188 (4187 clients) (319420 connections received)") + (0.01 ":cadmium.libera.chat 375 tester :- cadmium.libera.chat Message of the Day - ") + (0.01 ":cadmium.libera.chat 372 tester :- This server kindly provided by Mach Dilemma (www.m-d.net)") + (0.01 ":cadmium.libera.chat 372 tester :- Welcome to Libera Chat, the IRC network for") + (0.00 ":cadmium.libera.chat 372 tester :- Email: support@libera.chat") + (0.00 ":cadmium.libera.chat 376 tester :End of /MOTD command.") + (0.00 ":tester MODE tester :+Ziw") + (0.02 ":SaslServ!SaslServ@services.libera.chat NOTICE tester :Last login from: \2~tester@127.0.0.1\2 on Apr 07 01:02:11 2023 +0000.")) + +((mode 10 "MODE tester +i")) + +((join 10 "JOIN #test") + (0.09 ":tester!~tester@127.0.0.1 JOIN #test")) + +((mode 10 "MODE #test") + (0.03 ":cadmium.libera.chat 353 tester = #test :tester zbyqbepbqre7 pusevgfpu Thrfg2187 zngbeb qnexNssvavgl wrebzr- rqpentt Ilehf grfg2 AvtugZbaxrl pevfgvvbna xrivap_ fnvybePng shohxv gxan arrqyr avpx16 NeanhqW_kzcc Lbevpx_ hafcrag__ wfgbxre flfqrs RcvpArb Xbentt jvyyr cnefavc0 Wnarg wrnaogeq") + (0.02 ":cadmium.libera.chat 366 tester #test :End of /NAMES list.") + (0.00 ":cadmium.libera.chat 324 tester #test +nt") + (0.01 ":cadmium.libera.chat 329 tester #test 1621432263")) + +((drop 0 DROP)) -- 2.39.2