diff --git a/lisp/erc/erc-join.el b/lisp/erc/erc-join.el --- a/lisp/erc/erc-join.el +++ b/lisp/erc/erc-join.el @@ -42,9 +42,11 @@ (define-erc-module autojoin nil "Makes ERC autojoin on connects and reconnects." ((add-hook 'erc-after-connect 'erc-autojoin-channels) + (add-hook 'erc-nickserv-identified-hook 'erc-autojoin-after-ident) (add-hook 'erc-server-JOIN-functions 'erc-autojoin-add) (add-hook 'erc-server-PART-functions 'erc-autojoin-remove)) ((remove-hook 'erc-after-connect 'erc-autojoin-channels) + (remove-hook 'erc-nickserv-identified-hook 'erc-autojoin-after-ident) (remove-hook 'erc-server-JOIN-functions 'erc-autojoin-add) (remove-hook 'erc-server-PART-functions 'erc-autojoin-remove))) @@ -66,6 +68,25 @@ time is used again." (repeat :tag "Channels" (string :tag "Name"))))) +(defcustom erc-autojoin-timing :connect + "When erc should try to autojoin channels, assuming this feature has been +enabled. Valid values are:\n + :connect - immediately upon connection to the server + :ident - upon successful identification to services\n +If :ident is chosen, but no identification has occurred after +`erc-autojoin-patience' seconds, erc will attempt to autojoin anyway. +Any unrecognised value will be treated as the default (currently :connect)" + :group 'erc-autojoin + :type '(choice (const :tag "On Connection" :connect) + (const :tag "When Identified" :ident))) + +(defcustom erc-autojoin-patience 30 + "Number of seconds to wait for successful services identification before +attempting to autojoin channels anyway. Values of 0 or less disable this.\n +See also: `erc-autojoin-timing'" + :group 'erc-autojoin + :type 'integer) + (defcustom erc-autojoin-domain-only t "Truncate host name to the domain name when joining a server. If non-nil, and a channel on the server a.b.c is joined, then @@ -75,12 +96,67 @@ servers, presumably in the same domain." :group 'erc-autojoin :type 'boolean) +(defun erc-autojoin-timing-internal () + (if (eq :ident erc-autojoin-timing) :ident :connect)) + +(defvar erc-autojoin-delayed-timer nil) +(make-variable-buffer-local 'erc-autojoin-delayed-timer) + +(defun erc-autojoin-channels-delayed (server nick buffer) + "Kick of a delayed channel autojoin (intended for use when we are waiting +for a successful ident response before autojoining and run out of patience" + (if erc-autojoin-delayed-timer + (setq erc-autojoin-delayed-timer + (erc-cancel-timer erc-autojoin-delayed-timer))) + (with-current-buffer buffer + ;; make sure we don't kick of another delayed autojoin or try to wait for + ;; another ident response: + (let ((erc-autojoin-patience -1) + (erc-autojoin-timing :connect)) + (erc-log "delayed autojoin started (no ident success detected yet)") + (erc-autojoin-channels server nick)) )) + (defun erc-autojoin-channels (server nick) - "Autojoin channels in `erc-autojoin-channels-alist'." - (dolist (l erc-autojoin-channels-alist) - (when (string-match (car l) server) - (dolist (chan (cdr l)) - (erc-server-send (concat "join " chan)))))) + "Autojoin channels in `erc-autojoin-channels-alist'. +See also `erc-autojoin-timing'" + (if (eq (erc-autojoin-timing-internal) :connect) + (dolist (l erc-autojoin-channels-alist) + (when (string-match (car l) server) + (dolist (chan (cdr l)) + (erc-server-send (concat "join " chan))))) + ;; ok, we want post-ident autojoin: prepare the delayed autojoin timer + ;; in case ident doesn't happen within the allotted time limit: + (when (< 0 erc-autojoin-patience) + (setq erc-autojoin-delayed-timer + (run-with-timer erc-autojoin-patience nil + 'erc-autojoin-channels-delayed + server nick (current-buffer))) + ;; make sure we return nil so we don't stomp on any other hook funcs: + nil))) + +(defun erc-autojoin-after-ident (network nick) + "Autojoin channels in `erc-autojoin-channels-alist' after +successful identification to services, or after `erc-autojoin-patience' +seconds otherwise." + (if erc-autojoin-delayed-timer + (setq erc-autojoin-delayed-timer + (erc-cancel-timer erc-autojoin-delayed-timer))) + (when (eq (erc-autojoin-timing-internal) :ident) + (let ((server (or erc-server-announced-name erc-session-server)) + (joined (mapcar (lambda (buf) + (with-current-buffer buf (erc-default-target))) + (erc-channel-list erc-server-process)))) + ;; we may already be in these channels, because the autojoin timer + ;; went off, or random server weirdness (at least one server I know + ;; of automatically pumps all users into a global channel) + (dolist (l erc-autojoin-channels-alist) + (when (string-match (car l) server) + (dolist (chan (cdr l)) + (if (erc-member-ignore-case chan joined) + (erc-log (format "erc-join-after-indent: already in %s" chan)) + (erc-log (format "erc-join-after-indent: joining %s" chan)) + (erc-server-send (concat "join " chan)) )) )) )) + nil) (defun erc-autojoin-add (proc parsed) "Add the channel being joined to `erc-autojoin-channels-alist'."