* net/tramp.el (tramp-read-passwd): Suspend the timers while reading
[bpt/emacs.git] / lisp / erc / erc.el
index 2e97131..d93e9e0 100644 (file)
@@ -1,6 +1,6 @@
-;; erc.el --- An Emacs Internet Relay Chat client
+;; erc.el --- An Emacs Internet Relay Chat client  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1997-2012 Free Software Foundation, Inc.
+;; Copyright (C) 1997-2014 Free Software Foundation, Inc.
 
 ;; Author: Alexander L. Belikoff (alexander@belikoff.net)
 ;; Contributors: Sergey Berezin (sergey.berezin@cs.cmu.edu),
@@ -9,7 +9,7 @@
 ;;               Andreas Fuchs (afs@void.at)
 ;;               Gergely Nagy (algernon@midgard.debian.net)
 ;;               David Edmondson (dme@dme.org)
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: IRC, chat, client, Internet
 ;; Version: 5.3
 
@@ -67,7 +67,7 @@
 (defconst erc-version-string "Version 5.3"
   "ERC version.  This is used by function `erc-version'.")
 
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl-lib))
 (require 'font-lock)
 (require 'pp)
 (require 'thingatpt)
@@ -81,6 +81,7 @@
 (defgroup erc nil
   "Emacs Internet Relay Chat client."
   :link '(url-link "http://www.emacswiki.org/cgi-bin/wiki/ERC")
+  :link '(custom-manual "(erc) Top")
   :prefix "erc-"
   :group 'applications)
 
 
 ;; compatibility with older ERC releases
 
-(if (fboundp 'defvaralias)
-    (progn
-      (defvaralias 'erc-announced-server-name 'erc-server-announced-name)
-      (erc-make-obsolete-variable 'erc-announced-server-name
-                                 'erc-server-announced-name
-                                 "ERC 5.1")
-      (defvaralias 'erc-process 'erc-server-process)
-      (erc-make-obsolete-variable 'erc-process 'erc-server-process "ERC 5.1")
-      (defvaralias 'erc-default-coding-system 'erc-server-coding-system)
-      (erc-make-obsolete-variable 'erc-default-coding-system
-                                 'erc-server-coding-system
-                                 "ERC 5.1"))
-  (message (concat "ERC: The function `defvaralias' is not bound.  See the "
-                  "NEWS file for variable name changes since ERC 5.0.4.")))
+(define-obsolete-variable-alias 'erc-announced-server-name
+  'erc-server-announced-name "ERC 5.1")
+(define-obsolete-variable-alias 'erc-process 'erc-server-process "ERC 5.1")
+(define-obsolete-variable-alias 'erc-default-coding-system
+  'erc-server-coding-system "ERC 5.1")
 
 (define-obsolete-function-alias 'erc-send-command
   'erc-server-send "ERC 5.1")
@@ -201,9 +193,7 @@ parameters and authentication."
                 (string :tag "Name")
                 (function :tag "Get from function"))
   :set (lambda (sym val)
-        (if (functionp val)
-            (set sym (funcall val))
-          (set sym val))))
+        (set sym (if (functionp val) (funcall val) val))))
 
 (defvar erc-password nil
   "Password to use when authenticating to an IRC server.
@@ -369,7 +359,7 @@ If no server buffer exists, return nil."
         (with-current-buffer ,buffer
           ,@body)))))
 
-(defstruct (erc-server-user (:type vector) :named)
+(cl-defstruct (erc-server-user (:type vector) :named)
   ;; User data
   nickname host login full-name info
   ;; Buffers
@@ -379,7 +369,7 @@ If no server buffer exists, return nil."
   (buffers nil)
   )
 
-(defstruct (erc-channel-user (:type vector) :named)
+(cl-defstruct (erc-channel-user (:type vector) :named)
   op voice
   ;; Last message time (in the form of the return value of
   ;; (current-time)
@@ -388,12 +378,12 @@ If no server buffer exists, return nil."
   (last-message-time nil))
 
 (defsubst erc-get-channel-user (nick)
-  "Finds the (USER . CHANNEL-DATA) element corresponding to NICK
+  "Find the (USER . CHANNEL-DATA) element corresponding to NICK
 in the current buffer's `erc-channel-users' hash table."
   (gethash (erc-downcase nick) erc-channel-users))
 
 (defsubst erc-get-server-user (nick)
-  "Finds the USER corresponding to NICK in the current server's
+  "Find the USER corresponding to NICK in the current server's
 `erc-server-users' hash table."
   (erc-with-server-buffer
     (gethash (erc-downcase nick) erc-server-users)))
@@ -480,7 +470,7 @@ Removes all users in the current channel.  This is called by
   (when (and erc-server-connected
             (erc-server-process-alive)
             (hash-table-p erc-channel-users))
-    (maphash (lambda (nick cdata)
+    (maphash (lambda (nick _cdata)
               (erc-remove-channel-user nick))
             erc-channel-users)
     (clrhash erc-channel-users)))
@@ -502,25 +492,25 @@ Removes all users in the current channel.  This is called by
              (erc-channel-user-voice (cdr cdata))))))
 
 (defun erc-get-channel-user-list ()
-  "Returns a list of users in the current channel.  Each element
+  "Return a list of users in the current channel.  Each element
 of the list is of the form (USER . CHANNEL-DATA), where USER is
-an erc-server-user struct, and CHANNEL-DATA is either `nil' or an
+an erc-server-user struct, and CHANNEL-DATA is either nil or an
 erc-channel-user struct.
 
 See also: `erc-sort-channel-users-by-activity'"
   (let (users)
     (if (hash-table-p erc-channel-users)
-      (maphash (lambda (nick cdata)
+      (maphash (lambda (_nick cdata)
                 (setq users (cons cdata users)))
               erc-channel-users))
     users))
 
 (defun erc-get-server-nickname-list ()
-  "Returns a list of known nicknames on the current server."
+  "Return a list of known nicknames on the current server."
   (erc-with-server-buffer
     (let (nicks)
       (when (hash-table-p erc-server-users)
-       (maphash (lambda (n user)
+       (maphash (lambda (_n user)
                   (setq nicks
                         (cons (erc-server-user-nickname user)
                               nicks)))
@@ -528,10 +518,10 @@ See also: `erc-sort-channel-users-by-activity'"
        nicks))))
 
 (defun erc-get-channel-nickname-list ()
-  "Returns a list of known nicknames on the current channel."
+  "Return a list of known nicknames on the current channel."
   (let (nicks)
     (when (hash-table-p erc-channel-users)
-      (maphash (lambda (n cdata)
+      (maphash (lambda (_n cdata)
                 (setq nicks
                       (cons (erc-server-user-nickname (car cdata))
                             nicks)))
@@ -539,11 +529,11 @@ See also: `erc-sort-channel-users-by-activity'"
       nicks)))
 
 (defun erc-get-server-nickname-alist ()
-  "Returns an alist of known nicknames on the current server."
+  "Return an alist of known nicknames on the current server."
   (erc-with-server-buffer
     (let (nicks)
       (when (hash-table-p erc-server-users)
-       (maphash (lambda (n user)
+       (maphash (lambda (_n user)
                   (setq nicks
                         (cons (cons (erc-server-user-nickname user) nil)
                               nicks)))
@@ -551,10 +541,10 @@ See also: `erc-sort-channel-users-by-activity'"
        nicks))))
 
 (defun erc-get-channel-nickname-alist ()
-  "Returns an alist of known nicknames on the current channel."
+  "Return an alist of known nicknames on the current channel."
   (let (nicks)
     (when (hash-table-p erc-channel-users)
-      (maphash (lambda (n cdata)
+      (maphash (lambda (_n cdata)
                 (setq nicks
                       (cons (cons (erc-server-user-nickname (car cdata)) nil)
                             nicks)))
@@ -562,21 +552,18 @@ See also: `erc-sort-channel-users-by-activity'"
       nicks)))
 
 (defun erc-sort-channel-users-by-activity (list)
-  "Sorts LIST such that users which have spoken most recently are
-listed first.  LIST must be of the form (USER . CHANNEL-DATA).
+  "Sort LIST such that users which have spoken most recently are listed first.
+LIST must be of the form (USER . CHANNEL-DATA).
 
 See also: `erc-get-channel-user-list'."
   (sort list
        (lambda (x y)
-         (when (and
-                (cdr x) (cdr y))
+         (when (and (cdr x) (cdr y))
            (let ((tx (erc-channel-user-last-message-time (cdr x)))
                  (ty (erc-channel-user-last-message-time (cdr y))))
-             (if tx
-                 (if ty
-                     (time-less-p ty tx)
-                   t)
-               nil))))))
+             (and tx
+                  (or (not ty)
+                      (time-less-p ty tx))))))))
 
 (defun erc-sort-channel-users-alphabetically (list)
   "Sort LIST so that users' nicknames are in alphabetical order.
@@ -585,15 +572,12 @@ LIST must be of the form (USER . CHANNEL-DATA).
 See also: `erc-get-channel-user-list'."
   (sort list
        (lambda (x y)
-         (when (and
-                (cdr x) (cdr y))
+         (when (and (cdr x) (cdr y))
            (let ((nickx (downcase (erc-server-user-nickname (car x))))
                  (nicky (downcase (erc-server-user-nickname (car y)))))
-             (if nickx
-                 (if nicky
-                     (string-lessp nickx nicky)
-                   t)
-               nil))))))
+             (and nickx
+                  (or (not nicky)
+                      (string-lessp nickx nicky))))))))
 
 (defvar erc-channel-topic nil
   "A topic string for the channel.  Should only be used in channel-buffers.")
@@ -678,8 +662,8 @@ Any other value disables notice's highlighting altogether."
                 (const :tag "don't highlight notices at all" nil)))
 
 (defcustom erc-echo-notice-hook nil
-  "Specifies a list of functions to call to echo a private
-notice.  Each function is called with four arguments, the string
+  "List of functions to call to echo a private notice.
+Each function is called with four arguments, the string
 to display, the parsed server message, the target buffer (or
 nil), and the sender.  The functions are called in order, until a
 function evaluates to non-nil.  These hooks are called after
@@ -709,8 +693,8 @@ See also: `erc-echo-notice-always-hook',
 
 (defcustom erc-echo-notice-always-hook
   '(erc-echo-notice-in-default-buffer)
-  "Specifies a list of functions to call to echo a private
-notice.  Each function is called with four arguments, the string
+  "List of functions to call to echo a private notice.
+Each function is called with four arguments, the string
 to display, the parsed server message, the target buffer (or
 nil), and the sender.  The functions are called in order, and all
 functions are called.  These hooks are called before those
@@ -899,13 +883,12 @@ If no elements match, then the empty string is used.
 
 As an example:
   (setq erc-quit-reason-various-alist
-      '((\"zippy\" erc-quit-reason-zippy)
-       (\"xmms\" dme:now-playing)
+      '((\"xmms\" dme:now-playing)
        (\"version\" erc-quit-reason-normal)
        (\"home\" \"Gone home !\")
        (\"^$\" \"Default Reason\")))
-If the user types \"/quit zippy\", then a Zippy the Pinhead quotation
-will be used as the quit message."
+If the user types \"/quit home\", then \"Gone home !\" will be used
+as the quit message."
   :group 'erc-quit-and-part
   :type '(repeat (list regexp (choice (string) (function)))))
 
@@ -923,13 +906,12 @@ If no elements match, then the empty string is used.
 
 As an example:
   (setq erc-part-reason-various-alist
-      '((\"zippy\" erc-part-reason-zippy)
-       (\"xmms\" dme:now-playing)
+      '((\"xmms\" dme:now-playing)
        (\"version\" erc-part-reason-normal)
        (\"home\" \"Gone home !\")
        (\"^$\" \"Default Reason\")))
-If the user types \"/part zippy\", then a Zippy the Pinhead quotation
-will be used as the part message."
+If the user types \"/part home\", then \"Gone home !\" will be used
+as the part message."
   :group 'erc-quit-and-part
   :type '(repeat (list regexp (choice (string) (function)))))
 
@@ -940,7 +922,6 @@ The function is passed a single argument, the string typed by the
 user after \"/quit\"."
   :group 'erc-quit-and-part
   :type '(choice (const erc-quit-reason-normal)
-                (const erc-quit-reason-zippy)
                 (const erc-quit-reason-various)
                 (symbol)))
 
@@ -951,7 +932,6 @@ The function is passed a single argument, the string typed by the
 user after \"/PART\"."
   :group 'erc-quit-and-part
   :type '(choice (const erc-part-reason-normal)
-                (const erc-part-reason-zippy)
                 (const erc-part-reason-various)
                 (symbol)))
 
@@ -1066,9 +1046,9 @@ This function is called with narrowing, ala `erc-send-modify-hook'."
   :options '(erc-make-read-only))
 
 (defcustom erc-send-completed-hook
-  (when (featurep 'emacspeak)
+  (when (fboundp 'emacspeak-auditory-icon)
     (list (byte-compile
-          (lambda (str)
+          (lambda (_str)
             (emacspeak-auditory-icon 'select-object)))))
   "Hook called after a message has been parsed by ERC.
 
@@ -1119,10 +1099,7 @@ which the local user typed."
 
     ;; Suppress `font-lock-fontify-block' key binding since it
     ;; destroys face properties.
-    (if (fboundp 'command-remapping)
-       (define-key map [remap font-lock-fontify-block] 'undefined)
-      (substitute-key-definition
-       'font-lock-fontify-block 'undefined map global-map))
+    (define-key map [remap font-lock-fontify-block] 'undefined)
 
     map)
   "ERC keymap.")
@@ -1281,14 +1258,14 @@ if ARG is omitted or nil.
        (put ',enable  'definition-name ',name)
        (put ',disable 'definition-name ',name))))
 
-(defun erc-once-with-server-event (event &rest forms)
-  "Execute FORMS the next time EVENT occurs in the `current-buffer'.
+(defun erc-once-with-server-event (event f)
+  "Run function F the next time EVENT occurs in the `current-buffer'.
 
 You should make sure that `current-buffer' is a server buffer.
 
-This function temporarily adds a function to EVENT's hook to
-execute FORMS.  After FORMS are run, the function is removed from
-EVENT's hook.  The last expression of FORMS should be either nil
+This function temporarily adds a function to EVENT's hook to call F with
+two arguments (`proc' and `parsed').  After F is called, the function is
+removed from EVENT's hook.  F should return either nil
 or t, where nil indicates that the other functions on EVENT's hook
 should be run too, and t indicates that other functions should
 not be run.
@@ -1302,35 +1279,14 @@ capabilities."
      "You should only run `erc-once-with-server-event' in a server buffer"))
   (let ((fun (make-symbol "fun"))
        (hook (erc-get-hook event)))
-     (put fun 'erc-original-buffer (current-buffer))
-     (fset fun `(lambda (proc parsed)
-                 (with-current-buffer (get ',fun 'erc-original-buffer)
-                   (remove-hook ',hook ',fun t))
-                 (fmakunbound ',fun)
-                 ,@forms))
-     (add-hook hook fun nil t)
-     fun))
-
-(defun erc-once-with-server-event-global (event &rest forms)
-  "Execute FORMS the next time EVENT occurs in any server buffer.
-
-This function temporarily prepends a function to EVENT's hook to
-execute FORMS.  After FORMS are run, the function is removed from
-EVENT's hook.  The last expression of FORMS should be either nil
-or t, where nil indicates that the other functions on EVENT's hook
-should be run too, and t indicates that other functions should
-not be run.
-
-When FORMS execute, the current buffer is the server buffer associated with the
-connection over which the data was received that triggered EVENT."
-  (let ((fun (make-symbol "fun"))
-       (hook (erc-get-hook event)))
-     (fset fun `(lambda (proc parsed)
-                 (remove-hook ',hook ',fun)
-                 (fmakunbound ',fun)
-                 ,@forms))
-     (add-hook hook fun nil nil)
-     fun))
+    (put fun 'erc-original-buffer (current-buffer))
+    (fset fun (lambda (proc parsed)
+               (with-current-buffer (get fun 'erc-original-buffer)
+                 (remove-hook hook fun t))
+               (fmakunbound fun)
+               (funcall f proc parsed)))
+    (add-hook hook fun nil t)
+    fun))
 
 (defsubst erc-log (string)
   "Logs STRING if logging is on (see `erc-log-p')."
@@ -1362,8 +1318,8 @@ If BUFFER is nil, the current buffer is used."
 has an open IRC process.
 
 If BUFFER is nil, the current buffer is used."
-  (and (erc-server-buffer-p)
-       (erc-server-process-alive)))
+  (and (erc-server-buffer-p buffer)
+       (erc-server-process-alive buffer)))
 
 (defun erc-query-buffer-p (&optional buffer)
   "Return non-nil if BUFFER is an ERC query buffer.
@@ -1381,12 +1337,13 @@ If BUFFER is nil, the current buffer is used."
     (let ((erc-online-p 'unknown))
       (erc-once-with-server-event
        303
-       `(let ((ison (split-string (aref parsed 3))))
-         (setq erc-online-p (car (erc-member-ignore-case ,nick ison)))
-         t))
+       (lambda (_proc parsed)
+        (let ((ison (split-string (aref parsed 3))))
+          (setq erc-online-p (car (erc-member-ignore-case nick ison)))
+          t)))
       (erc-server-send (format "ISON %s" nick))
       (while (eq erc-online-p 'unknown) (accept-process-output))
-      (if (interactive-p)
+      (if (called-interactively-p 'interactive)
          (message "%s is %sonline"
                   (or erc-online-p nick)
                   (if erc-online-p "" "not "))
@@ -1555,7 +1512,7 @@ symbol, it may have these values:
   "Check whether ports A and B are equal."
   (= (erc-normalize-port a) (erc-normalize-port b)))
 
-(defun erc-generate-new-buffer-name (server port target &optional proc)
+(defun erc-generate-new-buffer-name (server port target)
   "Create a new buffer name based on the arguments."
   (when (numberp port) (setq port (number-to-string port)))
   (let ((buf-name (or target
@@ -1586,9 +1543,9 @@ symbol, it may have these values:
     ;; fallback to the old <N> uniquification method:
     (or buffer-name (generate-new-buffer-name buf-name)) ))
 
-(defun erc-get-buffer-create (server port target &optional proc)
+(defun erc-get-buffer-create (server port target)
   "Create a new buffer based on the arguments."
-  (get-buffer-create (erc-generate-new-buffer-name server port target proc)))
+  (get-buffer-create (erc-generate-new-buffer-name server port target)))
 
 
 (defun erc-member-ignore-case (string list)
@@ -1704,6 +1661,7 @@ nil."
 (defvar iswitchb-temp-buflist)
 (declare-function iswitchb-read-buffer "iswitchb"
                 (prompt &optional default require-match start matches-set))
+(defvar iswitchb-make-buflist-hook)
 
 (defun erc-iswitchb (&optional arg)
   "Use `iswitchb-read-buffer' to prompt for a ERC buffer to switch to.
@@ -1843,7 +1801,7 @@ removed from the list will be disabled."
           capab-identify)
     (const :tag "completion: Complete nicknames and commands (programmable)"
           completion)
-    (const :tag "hecomplete: Complete nicknames and commands (old)" hecomplete)
+    (const :tag "hecomplete: Complete nicknames and commands (obsolete, use \"completion\")" hecomplete)
     (const :tag "dcc: Provide Direct Client-to-Client support" dcc)
     (const :tag "fill: Wrap long lines" fill)
     (const :tag "identd: Launch an identd server on port 8113" identd)
@@ -1863,6 +1821,8 @@ removed from the list will be disabled."
     (const :tag
           "notify: Notify when the online status of certain users changes"
           notify)
+    (const :tag "notifications: Send notifications on PRIVMSG or nickname mentions"
+          notifications)
     (const :tag "page: Process CTCP PAGE requests from IRC" page)
     (const :tag "readonly: Make displayed lines read-only" readonly)
     (const :tag "replace: Replace text in messages" replace)
@@ -1908,29 +1868,29 @@ removed from the list will be disabled."
 
 (defun erc-setup-buffer (buffer)
   "Consults `erc-join-buffer' to find out how to display `BUFFER'."
-  (cond ((eq erc-join-buffer 'window)
-        (if (active-minibuffer-window)
-            (display-buffer buffer)
-          (switch-to-buffer-other-window buffer)))
-       ((eq erc-join-buffer 'window-noselect)
-        (display-buffer buffer))
-       ((eq erc-join-buffer 'bury)
-        nil)
-       ((eq erc-join-buffer 'frame)
-        (when (or (not erc-reuse-frames)
-                  (not (get-buffer-window buffer t)))
-          ((lambda (frame)
-                    (raise-frame frame)
-                    (select-frame frame))
-                 (make-frame (or erc-frame-alist
-                                 default-frame-alist)))
-        (switch-to-buffer buffer)
-        (when erc-frame-dedicated-flag
-          (set-window-dedicated-p (selected-window) t))))
-       (t
-        (if (active-minibuffer-window)
-            (display-buffer buffer)
-          (switch-to-buffer buffer)))))
+  (pcase erc-join-buffer
+    (`window
+     (if (active-minibuffer-window)
+        (display-buffer buffer)
+       (switch-to-buffer-other-window buffer)))
+    (`window-noselect
+     (display-buffer buffer))
+    (`bury
+     nil)
+    (`frame
+     (when (or (not erc-reuse-frames)
+              (not (get-buffer-window buffer t)))
+       (let ((frame (make-frame (or erc-frame-alist
+                                   default-frame-alist))))
+        (raise-frame frame)
+        (select-frame frame))
+       (switch-to-buffer buffer)
+       (when erc-frame-dedicated-flag
+        (set-window-dedicated-p (selected-window) t))))
+    (_
+     (if (active-minibuffer-window)
+        (display-buffer buffer)
+       (switch-to-buffer buffer)))))
 
 (defun erc-open (&optional server port nick full-name
                           connect passwd tgt-list channel process)
@@ -2008,19 +1968,20 @@ Returns the buffer for the given server or channel."
     ;; The local copy of `erc-nick' - the list of nicks to choose
     (setq erc-default-nicks (if (consp erc-nick) erc-nick (list erc-nick)))
     ;; password stuff
-    (setq erc-session-password (or passwd
-                                  (let ((secret
-                                         (plist-get
-                                          (nth 0
-                                               (auth-source-search :host server
-                                                                   :max 1
-                                                                   :user nick
-                                                                   :port port
-                                                                   :require '(:secret)))
-                                          :secret)))
-                                    (if (functionp secret)
-                                        (funcall secret)
-                                      secret))))
+    (setq erc-session-password
+         (or passwd
+             (let ((secret
+                    (plist-get
+                     (nth 0
+                          (auth-source-search :host server
+                                              :max 1
+                                              :user nick
+                                              :port port
+                                              :require '(:secret)))
+                     :secret)))
+               (if (functionp secret)
+                   (funcall secret)
+                 secret))))
     ;; debug output buffer
     (setq erc-dbuf
          (when erc-log-p
@@ -2082,11 +2043,6 @@ If no buffer matches, return nil."
          (erc-port-equal erc-session-port port)
          (erc-current-nick-p nick)))))
 
-(if (not (fboundp 'read-passwd))
-    (defun read-passwd (prompt)
-      "Substitute for `read-passwd' in early emacsen."
-      (read-from-minibuffer prompt)))
-
 (defcustom erc-before-connect nil
   "Hook called before connecting to a server.
 This hook gets executed before `erc' actually invokes `erc-mode'
@@ -2155,11 +2111,11 @@ functions in here get called with the parameters SERVER and NICK."
     (list :server server :port port :nick nick :password passwd)))
 
 ;;;###autoload
-(defun* erc (&key (server (erc-compute-server))
-                 (port   (erc-compute-port))
-                 (nick   (erc-compute-nick))
-                 password
-                 (full-name (erc-compute-full-name)))
+(cl-defun erc (&key (server (erc-compute-server))
+                   (port   (erc-compute-port))
+                   (nick   (erc-compute-nick))
+                   password
+                   (full-name (erc-compute-full-name)))
   "ERC is a powerful, modular, and extensible IRC client.
 This function is the main entry point for ERC.
 
@@ -2381,24 +2337,24 @@ If STRING is nil, the function does nothing."
       (while list
        (setq elt (car list))
        (cond ((integerp elt)           ; POSITION
-              (incf (car list) shift))
+              (cl-incf (car list) shift))
              ((or (atom elt)           ; nil, EXTENT
                   ;; (eq t (car elt))  ; (t . TIME)
                   (markerp (car elt))) ; (MARKER . DISTANCE)
               nil)
              ((integerp (car elt))     ; (BEGIN . END)
-              (incf (car elt) shift)
-              (incf (cdr elt) shift))
+              (cl-incf (car elt) shift)
+              (cl-incf (cdr elt) shift))
              ((stringp (car elt))      ; (TEXT . POSITION)
-              (incf (cdr elt) (* (if (natnump (cdr elt)) 1 -1) shift)))
+              (cl-incf (cdr elt) (* (if (natnump (cdr elt)) 1 -1) shift)))
              ((null (car elt))         ; (nil PROPERTY VALUE BEG . END)
               (let ((cons (nthcdr 3 elt)))
-                (incf (car cons) shift)
-                (incf (cdr cons) shift)))
+                (cl-incf (car cons) shift)
+                (cl-incf (cdr cons) shift)))
              ((and (featurep 'xemacs)
                    (extentp (car elt))) ; (EXTENT START END)
-              (incf (nth 1 elt) shift)
-              (incf (nth 2 elt) shift)))
+              (cl-incf (nth 1 elt) shift)
+              (cl-incf (nth 2 elt) shift)))
        (setq list (cdr list))))))
 
 (defvar erc-valid-nick-regexp "[]a-zA-Z^[;\\`_{}|][]^[;\\`_{}|a-zA-Z0-9-]*"
@@ -2435,11 +2391,11 @@ If STRING is nil, the function does nothing."
                  (t (list (current-buffer)))))
       (when (buffer-live-p buf)
        (erc-display-line-1 string buf)
-       (add-to-list 'new-bufs buf)))
+       (push buf new-bufs)))
     (when (null new-bufs)
-      (if (erc-server-buffer-live-p)
-         (erc-display-line-1 string (process-buffer erc-server-process))
-       (erc-display-line-1 string (current-buffer))))))
+      (erc-display-line-1 string (if (erc-server-buffer-live-p)
+                                    (process-buffer erc-server-process)
+                                  (current-buffer))))))
 
 (defun erc-display-message-highlight (type string)
   "Highlight STRING according to TYPE, where erc-TYPE-face is an ERC face.
@@ -2475,6 +2431,13 @@ purposes."
   :group 'erc-lurker
   :type 'boolean)
 
+(defcustom erc-lurker-ignore-chars "`_"
+  "Characters at the end of a nick to strip for activity tracking purposes.
+
+See also `erc-lurker-trim-nicks'."
+  :group 'erc-lurker
+  :type 'string)
+
 (defun erc-lurker-maybe-trim (nick)
   "Maybe trim trailing `erc-lurker-ignore-chars' from NICK.
 
@@ -2489,13 +2452,6 @@ non-nil."
        "" nick)
     nick))
 
-(defcustom erc-lurker-ignore-chars "`_"
-  "Characters at the end of a nick to strip for activity tracking purposes.
-
-See also `erc-lurker-trim-nicks'."
-  :group 'erc-lurker
-  :type 'string)
-
 (defcustom erc-lurker-hide-list nil
   "List of IRC type messages to hide when sent by lurkers.
 
@@ -2532,9 +2488,9 @@ consumption for long-lived IRC or Emacs sessions."
      (maphash
       (lambda (nick last-PRIVMSG-time)
        (when
-           (> (time-to-seconds (time-subtract
-                                (current-time)
-                                last-PRIVMSG-time))
+           (> (float-time (time-subtract
+                           (current-time)
+                           last-PRIVMSG-time))
               erc-lurker-threshold-time)
          (remhash nick hash)))
       hash)
@@ -2546,7 +2502,7 @@ consumption for long-lived IRC or Emacs sessions."
   "Internal counter variable for use with `erc-lurker-cleanup-interval'.")
 
 (defvar erc-lurker-cleanup-interval 100
-  "Specifies frequency of cleaning up stale erc-lurker state.
+  "Frequency of cleaning up stale erc-lurker state.
 
 `erc-lurker-update-status' calls `erc-lurker-cleanup' once for
 every `erc-lurker-cleanup-interval' updates to
@@ -2554,7 +2510,7 @@ every `erc-lurker-cleanup-interval' updates to
 consumption of lurker state during long Emacs sessions and/or ERC
 sessions with large numbers of incoming PRIVMSGs.")
 
-(defun erc-lurker-update-status (message)
+(defun erc-lurker-update-status (_message)
   "Update `erc-lurker-state' if necessary.
 
 This function is called from `erc-insert-pre-hook'.  If the
@@ -2578,7 +2534,8 @@ updates of `erc-lurker-state'."
            (server
             (erc-canonicalize-server-name erc-server-announced-name)))
       (when (equal command "PRIVMSG")
-        (when (>= (incf erc-lurker-cleanup-count) erc-lurker-cleanup-interval)
+        (when (>= (cl-incf erc-lurker-cleanup-count)
+                 erc-lurker-cleanup-interval)
           (setq erc-lurker-cleanup-count 0)
           (erc-lurker-cleanup))
         (unless (gethash server erc-lurker-state)
@@ -2599,12 +2556,23 @@ server within `erc-lurker-threshold-time'.  See also
            (gethash (erc-lurker-maybe-trim nick)
                     (gethash server erc-lurker-state (make-hash-table)))))
       (or (null last-PRIVMSG-time)
-         (> (time-to-seconds
+         (> (float-time
              (time-subtract (current-time) last-PRIVMSG-time))
            erc-lurker-threshold-time))))
 
+(defcustom erc-common-server-suffixes
+  '(("openprojects.net$" . "OPN")
+    ("freenode.net$" . "freenode")
+    ("oftc.net$" . "OFTC"))
+  "Alist of common server name suffixes.
+This variable is used in mode-line display to save screen
+real estate.  Set it to nil if you want to avoid changing
+displayed hostnames."
+  :group 'erc-mode-line-and-header
+  :type 'alist)
+
 (defun erc-canonicalize-server-name (server)
-  "Returns the canonical network name for SERVER if any,
+  "Return the canonical network name for SERVER if any,
 otherwise `erc-server-announced-name'.  SERVER is matched against
 `erc-common-server-suffixes'."
   (when server
@@ -2867,7 +2835,7 @@ If no USER argument is specified, list the contents of `erc-ignore-list'."
   (interactive)
   (let ((ops nil))
     (if erc-channel-users
-       (maphash (lambda (nick user-data)
+       (maphash (lambda (_nick user-data)
                   (let ((cuser (cdr user-data)))
                     (if (and cuser
                              (erc-channel-user-op cuser))
@@ -2997,9 +2965,9 @@ were most recently invited.  See also `invitation'."
            (switch-to-buffer (car (erc-member-ignore-case chnl
                                                           joined-channels)))
          (erc-log (format "cmd: JOIN: %s" chnl))
-         (if (and chnl key)
-             (erc-server-send (format "JOIN %s %s" chnl key))
-           (erc-server-send (format "JOIN %s" chnl)))))))
+         (erc-server-send (if (and chnl key)
+                              (format "JOIN %s %s" chnl key)
+                            (format "JOIN %s" chnl)))))))
   t)
 
 (defalias 'erc-cmd-CHANNEL 'erc-cmd-JOIN)
@@ -3110,68 +3078,76 @@ If SERVER is non-nil, use that, rather than the current server."
   (let ((origbuf (current-buffer))
        symlist)
     (erc-with-server-buffer
-      (add-to-list 'symlist
-                  (cons (erc-once-with-server-event
-                         311 `(string= ,nick
-                                       (second
-                                        (erc-response.command-args parsed))))
-                        'erc-server-311-functions))
-      (add-to-list 'symlist
-                  (cons (erc-once-with-server-event
-                         312 `(string= ,nick
-                                       (second
-                                        (erc-response.command-args parsed))))
-                        'erc-server-312-functions))
-      (add-to-list 'symlist
-                  (cons (erc-once-with-server-event
-                         318 `(string= ,nick
-                                       (second
-                                        (erc-response.command-args parsed))))
-                        'erc-server-318-functions))
-      (add-to-list 'symlist
-                  (cons (erc-once-with-server-event
-                         319 `(string= ,nick
-                                       (second
-                                        (erc-response.command-args parsed))))
-                        'erc-server-319-functions))
-      (add-to-list 'symlist
-                  (cons (erc-once-with-server-event
-                         320 `(string= ,nick
-                                       (second
-                                        (erc-response.command-args parsed))))
-                        'erc-server-320-functions))
-      (add-to-list 'symlist
-                  (cons (erc-once-with-server-event
-                         330 `(string= ,nick
-                                       (second
-                                        (erc-response.command-args parsed))))
-                        'erc-server-330-functions))
-      (add-to-list 'symlist
-                  (cons (erc-once-with-server-event
-                         317
-                         `(let ((idleseconds
-                                 (string-to-number
-                                  (third
-                                   (erc-response.command-args parsed)))))
-                            (erc-display-line
-                             (erc-make-notice
-                              (format "%s has been idle for %s."
-                                      (erc-string-no-properties ,nick)
-                                      (erc-seconds-to-string idleseconds)))
-                             ,origbuf))
-                         t)
-                        'erc-server-317-functions))
-
-      ;; Send the WHOIS command.
-      (erc-cmd-WHOIS nick)
-
-      ;; Remove the uninterned symbols from the server hooks that did not run.
-      (run-at-time 20 nil `(lambda ()
-                            (with-current-buffer ,(current-buffer)
-                              (dolist (sym ',symlist)
-                                (let ((hooksym (cdr sym))
-                                      (funcsym (car sym)))
-                                  (remove-hook hooksym funcsym t))))))))
+     (push (cons (erc-once-with-server-event
+                 311 (lambda (_proc parsed)
+                       (string= nick
+                                (nth 1 (erc-response.command-args
+                                        parsed)))))
+                'erc-server-311-functions)
+          symlist)
+     (push (cons (erc-once-with-server-event
+                 312 (lambda (_proc parsed)
+                       (string= nick
+                                (nth 1 (erc-response.command-args
+                                        parsed)))))
+                'erc-server-312-functions)
+          symlist)
+     (push (cons (erc-once-with-server-event
+                 318 (lambda (_proc parsed)
+                       (string= nick
+                                (nth 1 (erc-response.command-args
+                                        parsed)))))
+                'erc-server-318-functions)
+          symlist)
+     (push (cons (erc-once-with-server-event
+                 319 (lambda (_proc parsed)
+                       (string= nick
+                                (nth 1 (erc-response.command-args
+                                        parsed)))))
+                'erc-server-319-functions)
+          symlist)
+     (push (cons (erc-once-with-server-event
+                 320 (lambda (_proc parsed)
+                       (string= nick
+                                (nth 1 (erc-response.command-args
+                                        parsed)))))
+                'erc-server-320-functions)
+          symlist)
+     (push (cons (erc-once-with-server-event
+                 330 (lambda (_proc parsed)
+                       (string= nick
+                                (nth 1 (erc-response.command-args
+                                        parsed)))))
+                'erc-server-330-functions)
+          symlist)
+     (push (cons (erc-once-with-server-event
+                 317
+                 (lambda (_proc parsed)
+                   (let ((idleseconds
+                          (string-to-number
+                           (cl-third
+                            (erc-response.command-args parsed)))))
+                     (erc-display-line
+                      (erc-make-notice
+                       (format "%s has been idle for %s."
+                               (erc-string-no-properties nick)
+                               (erc-seconds-to-string idleseconds)))
+                      origbuf)
+                     t)))
+                'erc-server-317-functions)
+          symlist)
+
+     ;; Send the WHOIS command.
+     (erc-cmd-WHOIS nick)
+
+     ;; Remove the uninterned symbols from the server hooks that did not run.
+     (run-at-time 20 nil (lambda (buf symlist)
+                          (with-current-buffer buf
+                            (dolist (sym symlist)
+                              (let ((hooksym (cdr sym))
+                                    (funcsym (car sym)))
+                                (remove-hook hooksym funcsym t)))))
+                 (current-buffer) symlist)))
   t)
 
 (defun erc-cmd-DESCRIBE (line)
@@ -3384,7 +3360,11 @@ If S is non-nil, it will be used as the quit reason."
 
 If S is non-nil, it will be used as the quit reason."
   (or s
-      (erc-replace-regexp-in-string "\n" "" (yow))))
+      (if (fboundp 'yow)
+         (erc-replace-regexp-in-string "\n" "" (yow))
+       (erc-quit-reason-normal))))
+
+(make-obsolete 'erc-quit-reason-zippy "it will be removed." "24.4")
 
 (defun erc-quit-reason-various (s)
   "Choose a quit reason based on S (a string)."
@@ -3411,7 +3391,11 @@ If S is non-nil, it will be used as the quit reason."
 
 If S is non-nil, it will be used as the quit reason."
   (or s
-      (erc-replace-regexp-in-string "\n" "" (yow))))
+      (if (fboundp 'yow)
+         (erc-replace-regexp-in-string "\n" "" (yow))
+       (erc-part-reason-normal))))
+
+(make-obsolete 'erc-part-reason-zippy "it will be removed." "24.4")
 
 (defun erc-part-reason-various (s)
   "Choose a part reason based on S (a string)."
@@ -3672,11 +3656,12 @@ The ban list is fetched from the server if necessary."
        (erc-with-server-buffer
          (erc-once-with-server-event
           368
-          `(with-current-buffer ,chnl-name
+          (lambda (_proc _parsed)
+            (with-current-buffer chnl-name
              (put 'erc-channel-banlist 'received-from-server t)
-             (setq erc-server-367-functions ',old-367-hook)
+             (setq erc-server-367-functions old-367-hook)
              (erc-cmd-BANLIST)
-             t))
+             t)))
          (erc-server-send (format "MODE %s b" chnl)))))
 
      ((null erc-channel-banlist)
@@ -3738,28 +3723,29 @@ Unban all currently banned users in the current channel."
      ((not (get 'erc-channel-banlist 'received-from-server))
       (let ((old-367-hook erc-server-367-functions))
        (setq erc-server-367-functions 'erc-banlist-store)
-      ;; fetch the ban list then callback
-      (erc-with-server-buffer
-       (erc-once-with-server-event
-        368
-        `(with-current-buffer ,chnl
-           (put 'erc-channel-banlist 'received-from-server t)
-             (setq erc-server-367-functions ,old-367-hook)
-           (erc-cmd-MASSUNBAN)
-           t))
-         (erc-server-send (format "MODE %s b" chnl)))))
+       ;; fetch the ban list then callback
+       (erc-with-server-buffer
+        (erc-once-with-server-event
+         368
+         (lambda (_proc _parsed)
+           (with-current-buffer chnl
+             (put 'erc-channel-banlist 'received-from-server t)
+             (setq erc-server-367-functions old-367-hook)
+             (erc-cmd-MASSUNBAN)
+             t)))
+        (erc-server-send (format "MODE %s b" chnl)))))
 
      (t (let ((bans (mapcar 'cdr erc-channel-banlist)))
-    (when bans
-      ;; Glob the bans into groups of three, and carry out the unban.
-      ;; eg. /mode #foo -bbb a*!*@* b*!*@* c*!*@*
-      (mapc
-       (lambda (x)
-        (erc-server-send
-         (format "MODE %s -%s %s" (erc-default-target)
-                 (make-string (length x) ?b)
+         (when bans
+           ;; Glob the bans into groups of three, and carry out the unban.
+           ;; eg. /mode #foo -bbb a*!*@* b*!*@* c*!*@*
+           (mapc
+            (lambda (x)
+              (erc-server-send
+               (format "MODE %s -%s %s" (erc-default-target)
+                       (make-string (length x) ?b)
                        (mapconcat 'identity x " "))))
-       (erc-group-list bans 3))))
+            (erc-group-list bans 3))))
        t))))
 
 (defalias 'erc-cmd-MUB 'erc-cmd-MASSUNBAN)
@@ -3915,9 +3901,9 @@ Prompt for one if called interactively."
                      (format "Limit for %s (RET to remove limit): "
                              (erc-default-target)))))
   (let ((tgt (erc-default-target)))
-    (if (and limit (>= (length limit) 1))
-       (erc-server-send (format "MODE %s +l %s" tgt limit))
-      (erc-server-send (format "MODE %s -l" tgt)))))
+    (erc-server-send (if (and limit (>= (length limit) 1))
+                        (format "MODE %s +l %s" tgt limit)
+                      (format "MODE %s -l" tgt)))))
 
 (defun erc-set-channel-key (&optional key)
   "Set a KEY for the current channel.  Remove key if nil.
@@ -3926,9 +3912,9 @@ Prompt for one if called interactively."
                      (format "Key for %s (RET to remove key): "
                              (erc-default-target)))))
   (let ((tgt (erc-default-target)))
-    (if (and key (>= (length key) 1))
-       (erc-server-send (format "MODE %s +k %s" tgt key))
-      (erc-server-send (format "MODE %s -k" tgt)))))
+    (erc-server-send (if (and key (>= (length key) 1))
+                        (format "MODE %s +k %s" tgt key)
+                      (format "MODE %s -k" tgt)))))
 
 (defun erc-quit-server (reason)
   "Disconnect from current server after prompting for REASON.
@@ -4005,7 +3991,7 @@ Displays PROC and PARSED appropriately using `erc-display-message'."
 See `erc-debug-missing-hooks'.")
 ;(make-variable-buffer-local 'erc-server-vectors)
 
-(defun erc-debug-missing-hooks (proc parsed)
+(defun erc-debug-missing-hooks (_proc parsed)
   "Add PARSED server message ERC does not yet handle to `erc-server-vectors'.
 These vectors can be helpful when adding new server message handlers to ERC.
 See `erc-default-server-hook'."
@@ -4145,7 +4131,7 @@ originated from,
 and as second argument the event parsed as a vector."
   :group 'erc-hooks)
 
-(defun erc-display-server-message (proc parsed)
+(defun erc-display-server-message (_proc parsed)
   "Display the message sent by the server as a notice."
   (erc-display-message
    parsed 'notice 'active (erc-response.contents parsed)))
@@ -4201,7 +4187,7 @@ and as second argument the event parsed as a vector."
   :group 'erc-display
   :type 'function)
 
-(defun erc-format-nick (&optional user channel-data)
+(defun erc-format-nick (&optional user _channel-data)
   "Return the nickname of USER.
 See also `erc-format-nick-function'."
   (when user (erc-server-user-nickname user)))
@@ -4229,7 +4215,7 @@ See also `erc-format-nick-function'."
     (let ((prefix "> "))
       (erc-propertize prefix 'face 'erc-default-face))))
 
-(defun erc-echo-notice-in-default-buffer (s parsed buffer sender)
+(defun erc-echo-notice-in-default-buffer (s parsed buffer _sender)
   "Echos a private notice in the default buffer, namely the
 target buffer specified by BUFFER, or there is no target buffer,
 the server buffer.  This function is designed to be added to
@@ -4238,7 +4224,7 @@ and always returns t."
   (erc-display-message parsed nil buffer s)
   t)
 
-(defun erc-echo-notice-in-target-buffer (s parsed buffer sender)
+(defun erc-echo-notice-in-target-buffer (s parsed buffer _sender)
   "Echos a private notice in BUFFER, if BUFFER is non-nil.  This
 function is designed to be added to either `erc-echo-notice-hook'
 or `erc-echo-notice-always-hook', and returns non-nil if BUFFER
@@ -4247,21 +4233,21 @@ is non-nil."
       (progn (erc-display-message parsed nil buffer s) t)
     nil))
 
-(defun erc-echo-notice-in-minibuffer (s parsed buffer sender)
+(defun erc-echo-notice-in-minibuffer (s _parsed _buffer _sender)
   "Echos a private notice in the minibuffer.  This function is
 designed to be added to either `erc-echo-notice-hook' or
 `erc-echo-notice-always-hook', and always returns t."
   (message "%s" (concat "NOTICE: " s))
   t)
 
-(defun erc-echo-notice-in-server-buffer (s parsed buffer sender)
+(defun erc-echo-notice-in-server-buffer (s parsed _buffer _sender)
   "Echos a private notice in the server buffer.  This function is
 designed to be added to either `erc-echo-notice-hook' or
 `erc-echo-notice-always-hook', and always returns t."
   (erc-display-message parsed nil nil s)
   t)
 
-(defun erc-echo-notice-in-active-non-server-buffer (s parsed buffer sender)
+(defun erc-echo-notice-in-active-non-server-buffer (s parsed _buffer _sender)
   "Echos a private notice in the active buffer if the active
 buffer is not the server buffer.  This function is designed to be
 added to either `erc-echo-notice-hook' or
@@ -4271,14 +4257,14 @@ buffer is not the server buffer."
       (progn (erc-display-message parsed nil 'active s) t)
     nil))
 
-(defun erc-echo-notice-in-active-buffer (s parsed buffer sender)
+(defun erc-echo-notice-in-active-buffer (s parsed _buffer _sender)
   "Echos a private notice in the active buffer.  This function is
 designed to be added to either `erc-echo-notice-hook' or
 `erc-echo-notice-always-hook', and always returns t."
   (erc-display-message parsed nil 'active s)
   t)
 
-(defun erc-echo-notice-in-user-buffers (s parsed buffer sender)
+(defun erc-echo-notice-in-user-buffers (s parsed _buffer sender)
   "Echos a private notice in all of the buffers for which SENDER
 is a member.  This function is designed to be added to either
 `erc-echo-notice-hook' or `erc-echo-notice-always-hook', and
@@ -4303,12 +4289,12 @@ default target.
 See also: `erc-echo-notice-in-user-buffers',
 `erc-buffer-list-with-nick'."
   (let ((buffers (erc-buffer-list-with-nick sender erc-server-process)))
-    (add-to-list 'buffers buffer)
-    (if buffers
+    (unless (memq buffer buffers) (push buffer buffers))
+    (if buffers                                ;FIXME: How could it be nil?
        (progn (erc-display-message parsed nil buffers s) t)
       nil)))
 
-(defun erc-echo-notice-in-first-user-buffer (s parsed buffer sender)
+(defun erc-echo-notice-in-first-user-buffer (s parsed _buffer sender)
   "Echos a private notice in one of the buffers for which SENDER
 is a member.  This function is designed to be added to either
 `erc-echo-notice-hook' or `erc-echo-notice-always-hook', and
@@ -4326,8 +4312,8 @@ See also: `erc-echo-notice-in-user-buffers',
 
 (defun erc-banlist-store (proc parsed)
   "Record ban entries for a channel."
-  (multiple-value-bind (channel mask whoset)
-      (values-list (cdr (erc-response.command-args parsed)))
+  (pcase-let ((`(,channel ,mask ,whoset)
+              (cdr (erc-response.command-args parsed))))
     ;; Determine to which buffer the message corresponds
     (let ((buffer (erc-get-buffer channel proc)))
       (with-current-buffer buffer
@@ -4338,7 +4324,7 @@ See also: `erc-echo-notice-in-user-buffers',
 
 (defun erc-banlist-finished (proc parsed)
   "Record that we have received the banlist."
-  (let* ((channel (second (erc-response.command-args parsed)))
+  (let* ((channel (nth 1 (erc-response.command-args parsed)))
         (buffer (erc-get-buffer channel proc)))
     (with-current-buffer buffer
       (put 'erc-channel-banlist 'received-from-server t)))
@@ -4347,7 +4333,7 @@ See also: `erc-echo-notice-in-user-buffers',
 (defun erc-banlist-update (proc parsed)
   "Check MODE commands for bans and update the banlist appropriately."
   ;; FIXME: Possibly incorrect. -- Lawrence 2004-05-11
-  (let* ((tgt (first (erc-response.command-args parsed)))
+  (let* ((tgt (car (erc-response.command-args parsed)))
         (mode (erc-response.contents parsed))
         (whoset (erc-response.sender parsed))
         (buffer (erc-get-buffer tgt proc)))
@@ -4486,7 +4472,7 @@ See also `erc-display-message'."
 
 (defvar erc-ctcp-query-CLIENTINFO-hook '(erc-ctcp-query-CLIENTINFO))
 
-(defun erc-ctcp-query-CLIENTINFO (proc nick login host to msg)
+(defun erc-ctcp-query-CLIENTINFO (_proc nick _login _host _to msg)
   "Respond to a CTCP CLIENTINFO query."
   (when (string-match "^CLIENTINFO\\(\\s-*\\|\\s-+.*\\)$" msg)
     (let ((s (erc-client-info (erc-trim-string (match-string 1 msg)))))
@@ -4495,7 +4481,7 @@ See also `erc-display-message'."
   nil)
 
 (defvar erc-ctcp-query-ECHO-hook '(erc-ctcp-query-ECHO))
-(defun erc-ctcp-query-ECHO (proc nick login host to msg)
+(defun erc-ctcp-query-ECHO (_proc nick _login _host _to msg)
   "Respond to a CTCP ECHO query."
   (when (string-match "^ECHO\\s-+\\(.*\\)\\s-*$" msg)
     (let ((s (match-string 1 msg)))
@@ -4504,7 +4490,7 @@ See also `erc-display-message'."
   nil)
 
 (defvar erc-ctcp-query-FINGER-hook '(erc-ctcp-query-FINGER))
-(defun erc-ctcp-query-FINGER (proc nick login host to msg)
+(defun erc-ctcp-query-FINGER (_proc nick _login _host _to _msg)
   "Respond to a CTCP FINGER query."
   (unless erc-disable-ctcp-replies
     (let ((s (if erc-anonymous-login
@@ -4520,7 +4506,7 @@ See also `erc-display-message'."
   nil)
 
 (defvar erc-ctcp-query-PING-hook '(erc-ctcp-query-PING))
-(defun erc-ctcp-query-PING (proc nick login host to msg)
+(defun erc-ctcp-query-PING (_proc nick _login _host _to msg)
   "Respond to a CTCP PING query."
   (when (string-match "^PING\\s-+\\(.*\\)" msg)
     (unless erc-disable-ctcp-replies
@@ -4529,21 +4515,21 @@ See also `erc-display-message'."
   nil)
 
 (defvar erc-ctcp-query-TIME-hook '(erc-ctcp-query-TIME))
-(defun erc-ctcp-query-TIME (proc nick login host to msg)
+(defun erc-ctcp-query-TIME (_proc nick _login _host _to _msg)
   "Respond to a CTCP TIME query."
   (unless erc-disable-ctcp-replies
     (erc-send-ctcp-notice nick (format "TIME %s" (current-time-string))))
   nil)
 
 (defvar erc-ctcp-query-USERINFO-hook '(erc-ctcp-query-USERINFO))
-(defun erc-ctcp-query-USERINFO (proc nick login host to msg)
+(defun erc-ctcp-query-USERINFO (_proc nick _login _host _to _msg)
   "Respond to a CTCP USERINFO query."
   (unless erc-disable-ctcp-replies
     (erc-send-ctcp-notice nick (format "USERINFO %s" erc-user-information)))
   nil)
 
 (defvar erc-ctcp-query-VERSION-hook '(erc-ctcp-query-VERSION))
-(defun erc-ctcp-query-VERSION (proc nick login host to msg)
+(defun erc-ctcp-query-VERSION (_proc nick _login _host _to _msg)
   "Respond to a CTCP VERSION query."
   (unless erc-disable-ctcp-replies
     (erc-send-ctcp-notice
@@ -4566,7 +4552,7 @@ See also `erc-display-message'."
        'CTCP-UNKNOWN ?n nick ?u login ?h host ?m msg))))
 
 (defvar erc-ctcp-reply-ECHO-hook '(erc-ctcp-reply-ECHO))
-(defun erc-ctcp-reply-ECHO (proc nick login host to msg)
+(defun erc-ctcp-reply-ECHO (_proc nick _login _host _to msg)
   "Handle a CTCP ECHO reply."
   (when (string-match "^ECHO\\s-+\\(.*\\)\\s-*$" msg)
     (let ((message (match-string 1 msg)))
@@ -4576,7 +4562,7 @@ See also `erc-display-message'."
   nil)
 
 (defvar erc-ctcp-reply-CLIENTINFO-hook '(erc-ctcp-reply-CLIENTINFO))
-(defun erc-ctcp-reply-CLIENTINFO (proc nick login host to msg)
+(defun erc-ctcp-reply-CLIENTINFO (_proc nick _login _host _to msg)
   "Handle a CTCP CLIENTINFO reply."
   (when (string-match "^CLIENTINFO\\s-+\\(.*\\)\\s-*$" msg)
     (let ((message (match-string 1 msg)))
@@ -4586,7 +4572,7 @@ See also `erc-display-message'."
   nil)
 
 (defvar erc-ctcp-reply-FINGER-hook '(erc-ctcp-reply-FINGER))
-(defun erc-ctcp-reply-FINGER (proc nick login host to msg)
+(defun erc-ctcp-reply-FINGER (_proc nick _login _host _to msg)
   "Handle a CTCP FINGER reply."
   (when (string-match "^FINGER\\s-+\\(.*\\)\\s-*$" msg)
     (let ((message (match-string 1 msg)))
@@ -4596,7 +4582,7 @@ See also `erc-display-message'."
   nil)
 
 (defvar erc-ctcp-reply-PING-hook '(erc-ctcp-reply-PING))
-(defun erc-ctcp-reply-PING (proc nick login host to msg)
+(defun erc-ctcp-reply-PING (_proc nick _login _host _to msg)
   "Handle a CTCP PING reply."
   (if (not (string-match "^PING\\s-+\\([0-9.]+\\)" msg))
       nil
@@ -4614,7 +4600,7 @@ See also `erc-display-message'."
          'bad-ping-response ?n nick ?t time))))))
 
 (defvar erc-ctcp-reply-TIME-hook '(erc-ctcp-reply-TIME))
-(defun erc-ctcp-reply-TIME (proc nick login host to msg)
+(defun erc-ctcp-reply-TIME (_proc nick _login _host _to msg)
   "Handle a CTCP TIME reply."
   (when (string-match "^TIME\\s-+\\(.*\\)\\s-*$" msg)
     (let ((message (match-string 1 msg)))
@@ -4624,7 +4610,7 @@ See also `erc-display-message'."
   nil)
 
 (defvar erc-ctcp-reply-VERSION-hook '(erc-ctcp-reply-VERSION))
-(defun erc-ctcp-reply-VERSION (proc nick login host to msg)
+(defun erc-ctcp-reply-VERSION (_proc nick _login _host _to msg)
   "Handle a CTCP VERSION reply."
   (when (string-match "^VERSION\\s-+\\(.*\\)\\s-*$" msg)
     (let ((message (match-string 1 msg)))
@@ -4687,7 +4673,7 @@ received.  Should be called with the current buffer set to the
 channel buffer.
 
 See also `erc-channel-begin-receiving-names'."
-  (maphash (lambda (nick user)
+  (maphash (lambda (nick _user)
             (if (null (gethash nick erc-channel-new-member-names))
                 (erc-remove-channel-user nick)))
           erc-channel-users)
@@ -4728,8 +4714,7 @@ channel."
     (setq names (delete "" (split-string names-string)))
     (let ((erc-channel-members-changed-hook nil))
       (dolist (item names)
-       (let ((updatep t)
-             ch)
+       (let ((updatep t))
          (if (rassq (elt item 0) prefix)
              (cond ((= (length item) 1)
                     (setq updatep nil))
@@ -4762,8 +4747,7 @@ The buffer where the change happened is current while this hook is called."
 
 (defun erc-update-user-nick (nick &optional new-nick
                                  host login full-name info)
-  "Updates the stored user information for the user with nickname
-NICK.
+  "Update the stored user information for the user with nickname NICK.
 
 See also: `erc-update-user'."
   (erc-update-user (erc-get-server-user nick) new-nick
@@ -4813,8 +4797,8 @@ which USER is a member, and t is returned."
 (defun erc-update-current-channel-member
   (nick new-nick &optional add op voice host login full-name info
        update-message-time)
-  "Updates the stored user information for the user with nickname
-NICK.  `erc-update-user' is called to handle changes to nickname,
+  "Update the stored user information for the user with nickname NICK.
+`erc-update-user' is called to handle changes to nickname,
 HOST, LOGIN, FULL-NAME, and INFO.  If OP or VOICE are non-nil,
 they must be equal to either `on' or `off', in which case the
 operator or voice status of the user in the current channel is
@@ -4832,7 +4816,7 @@ If, and only if, changes are made, or the user is added,
 See also: `erc-update-user' and `erc-update-channel-member'."
   (let* (changed user-changed
         (channel-data (erc-get-channel-user nick))
-        (cuser (if channel-data (cdr channel-data)))
+        (cuser (cdr channel-data))
         (user (if channel-data (car channel-data)
                 (erc-get-server-user nick))))
     (if cuser
@@ -4890,7 +4874,7 @@ See also: `erc-update-user' and `erc-update-channel-member'."
 (defun erc-update-channel-member (channel nick new-nick
                                  &optional add op voice host login
                                  full-name info update-message-time)
-  "Updates user and channel information for the user with
+  "Update user and channel information for the user with
 nickname NICK in channel CHANNEL.
 
 See also: `erc-update-current-channel-member'."
@@ -4933,7 +4917,6 @@ TOPIC string to the current topic."
   "Set the modes for the TGT provided as MODE-STRING."
   (let* ((modes (erc-parse-modes mode-string))
         (add-modes (nth 0 modes))
-        (remove-modes (nth 1 modes))
         ;; list of triples: (mode-char 'on/'off argument)
         (arg-modes (nth 2 modes)))
     (cond ((erc-channel-p tgt); channel modes
@@ -5022,6 +5005,7 @@ arg-modes is a list of triples of the form:
   "Update the mode information for TGT, provided as MODE-STRING.
 Optional arguments: NICK, HOST and LOGIN - the attributes of the
 person who changed the modes."
+  ;; FIXME: neither of nick, host, and login are used!
   (let* ((modes (erc-parse-modes mode-string))
         (add-modes (nth 0 modes))
         (remove-modes (nth 1 modes))
@@ -5179,8 +5163,7 @@ START and END describe positions in OBJECT.
 If VALUE-LIST is nil, set each property in PROPERTIES to t, else set
 each property to the corresponding value in VALUE-LIST."
   (unless value-list
-    (setq value-list (mapcar (lambda (x)
-                              t)
+    (setq value-list (mapcar (lambda (_x) t)
                             properties)))
   (while (and properties value-list)
     (erc-put-text-property
@@ -5201,42 +5184,65 @@ Specifically, return the position of `erc-insert-marker'."
   "Return the value of `point' at the end of the input line."
   (point-max))
 
+(defvar erc-last-input-time 0
+  "Time of last call to `erc-send-current-line'.
+If that function has never been called, the value is 0.")
+
+(defcustom erc-accidental-paste-threshold-seconds nil
+  "Minimum time, in seconds, before sending new lines via IRC.
+If the value is a number, `erc-send-current-line' signals an error
+if its previous invocation was fewer than this many seconds ago.
+This is useful so that if you accidentally enter large amounts of text
+into the ERC buffer, that text is not sent to the IRC server.
+
+If the value is nil, `erc-send-current-line' always considers any
+submitted line to be intentional."
+  :group 'erc
+  :version "24.4"
+  :type '(choice number (other :tag "disabled" nil)))
+
 (defun erc-send-current-line ()
   "Parse current line and send it to IRC."
   (interactive)
-  (save-restriction
-    (widen)
-    (if (< (point) (erc-beg-of-input-line))
-       (erc-error "Point is not in the input area")
-      (let ((inhibit-read-only t)
-           (str (erc-user-input))
-           (old-buf (current-buffer)))
-       (if (and (not (erc-server-buffer-live-p))
-                (not (erc-command-no-process-p str)))
-           (erc-error "ERC: No process running")
-         (erc-set-active-buffer (current-buffer))
-
-         ;; Kill the input and the prompt
-         (delete-region (erc-beg-of-input-line)
-                        (erc-end-of-input-line))
-
-         (unwind-protect
-             (erc-send-input str)
-           ;; Fix the buffer if the command didn't kill it
-           (when (buffer-live-p old-buf)
-             (with-current-buffer old-buf
-               (save-restriction
-                 (widen)
-                 (goto-char (point-max))
-                 (when (processp erc-server-process)
-                   (set-marker (process-mark erc-server-process) (point)))
-                 (set-marker erc-insert-marker (point))
-                 (let ((buffer-modified (buffer-modified-p)))
-                   (erc-display-prompt)
-                   (set-buffer-modified-p buffer-modified))))))
-
-         ;; Only when last hook has been run...
-         (run-hook-with-args 'erc-send-completed-hook str))))))
+  (let ((now (float-time)))
+    (if (or (not erc-accidental-paste-threshold-seconds)
+           (< erc-accidental-paste-threshold-seconds
+              (- now erc-last-input-time)))
+       (save-restriction
+         (widen)
+         (if (< (point) (erc-beg-of-input-line))
+             (erc-error "Point is not in the input area")
+           (let ((inhibit-read-only t)
+                 (str (erc-user-input))
+                 (old-buf (current-buffer)))
+             (if (and (not (erc-server-buffer-live-p))
+                      (not (erc-command-no-process-p str)))
+                 (erc-error "ERC: No process running")
+               (erc-set-active-buffer (current-buffer))
+               ;; Kill the input and the prompt
+               (delete-region (erc-beg-of-input-line)
+                              (erc-end-of-input-line))
+               (unwind-protect
+                   (erc-send-input str)
+                 ;; Fix the buffer if the command didn't kill it
+                 (when (buffer-live-p old-buf)
+                   (with-current-buffer old-buf
+                     (save-restriction
+                       (widen)
+                       (goto-char (point-max))
+                       (when (processp erc-server-process)
+                         (set-marker (process-mark erc-server-process) (point)))
+                       (set-marker erc-insert-marker (point))
+                       (let ((buffer-modified (buffer-modified-p)))
+                         (erc-display-prompt)
+                         (set-buffer-modified-p buffer-modified))))))
+
+               ;; Only when last hook has been run...
+               (run-hook-with-args 'erc-send-completed-hook str))))
+         (setq erc-last-input-time now))
+      (switch-to-buffer "*ERC Accidental Paste Overflow*")
+      (lwarn 'erc :warning
+            "You seem to have accidentally pasted some text!"))))
 
 (defun erc-user-input ()
   "Return the input of the user in the current buffer."
@@ -5248,7 +5254,7 @@ Specifically, return the position of `erc-insert-marker'."
   "Regular expression used for matching commands in ERC.")
 
 (defun erc-send-input (input)
-  "Treat INPUT as typed in by the user. It is assumed that the input
+  "Treat INPUT as typed in by the user.  It is assumed that the input
 and the prompt is already deleted.
 This returns non-nil only if we actually send anything."
   ;; Handle different kinds of inputs
@@ -5338,8 +5344,8 @@ list of the form: (command args) where both elements are strings."
   (when (string-match erc-command-regexp line)
     (let* ((cmd (erc-command-symbol (match-string 1 line)))
           ;; note: return is nil, we apply this simply for side effects
-          (canon-defun (while (and cmd (symbolp (symbol-function cmd)))
-                         (setq cmd (symbol-function cmd))))
+          (_canon-defun (while (and cmd (symbolp (symbol-function cmd)))
+                          (setq cmd (symbol-function cmd))))
           (cmd-fun (or cmd #'erc-cmd-default))
           (arg (if cmd
                    (if (get cmd-fun 'do-not-parse-args)
@@ -5407,22 +5413,18 @@ See also `erc-downcase'."
 
 (defun erc-add-default-channel (channel)
   "Add CHANNEL to the default channel list."
-
-  (let ((d1 (car erc-default-recipients))
-       (d2 (cdr erc-default-recipients))
-       (chl (downcase channel)))
+  (let ((chl (downcase channel)))
       (setq erc-default-recipients
            (cons chl erc-default-recipients))))
 
 (defun erc-delete-default-channel (channel &optional buffer)
   "Delete CHANNEL from the default channel list."
-  (let ((ob (current-buffer)))
-    (with-current-buffer (if (and buffer
-                                 (bufferp buffer))
-                            buffer
-                          (current-buffer))
-      (setq erc-default-recipients (delete (downcase channel)
-                                          erc-default-recipients)))))
+  (with-current-buffer (if (and buffer
+                               (bufferp buffer))
+                          buffer
+                        (current-buffer))
+    (setq erc-default-recipients (delete (downcase channel)
+                                        erc-default-recipients))))
 
 (defun erc-add-query (nickname)
   "Add QUERY'd NICKNAME to the default channel list.
@@ -5431,10 +5433,10 @@ The previous default target of QUERY type gets removed."
   (let ((d1 (car erc-default-recipients))
        (d2 (cdr erc-default-recipients))
        (qt (cons 'QUERY (downcase nickname))))
-    (if (and (listp d1)
-            (eq (car d1) 'QUERY))
-       (setq erc-default-recipients (cons qt d2))
-      (setq erc-default-recipients (cons qt erc-default-recipients)))))
+    (setq erc-default-recipients (cons qt (if (and (listp d1)
+                                                  (eq (car d1) 'QUERY))
+                                             d2
+                                           erc-default-recipients)))))
 
 (defun erc-delete-query ()
   "Delete the topmost target if it is a QUERY."
@@ -5485,17 +5487,11 @@ The addressed target is the string before the first colon in MSG."
   (let ((nick (erc-server-user-nickname user))
        (host (erc-server-user-host user))
        (login (erc-server-user-login user)))
-  (concat (if nick
-             nick
-           "")
+  (concat (or nick "")
          "!"
-         (if login
-             login
-           "")
+         (or login "")
          "@"
-         (if host
-             host
-           ""))))
+         (or host ""))))
 
 (defun erc-list-match (lst str)
   "Return non-nil if any regexp in LST matches STR."
@@ -5545,8 +5541,7 @@ If ARG is non-nil, turn this mode off (-i).
 This command is sent even if excess flood is detected."
   (interactive "P")
   (erc-set-active-buffer (current-buffer))
-  (let ((tgt (erc-default-target))
-       (erc-force-send t))
+  (let ((tgt (erc-default-target)))
     (cond ((or (not tgt) (not (erc-channel-p tgt)))
           (erc-display-message nil 'error (current-buffer) 'no-target))
          (arg (erc-load-irc-script-lines (list (concat "/mode " tgt " -i"))
@@ -5583,8 +5578,7 @@ If CHANNEL is non-nil, toggle MODE for that channel, otherwise use
 `erc-default-target'."
   (interactive "P")
   (erc-set-active-buffer (current-buffer))
-  (let ((tgt (or channel (erc-default-target)))
-       (erc-force-send t))
+  (let ((tgt (or channel (erc-default-target))))
     (cond ((or (null tgt) (null (erc-channel-p tgt)))
           (erc-display-message nil 'error 'active 'no-target))
          ((member mode erc-channel-modes)
@@ -5628,12 +5622,11 @@ specified in the list PATH.
 If FILE is found, return the path to it."
   (let ((filepath file))
     (if (file-readable-p filepath) filepath
-      (progn
-       (while (and path
-                   (progn (setq filepath (expand-file-name file (car path)))
-                          (not (file-readable-p filepath))))
-         (setq path (cdr path)))
-       (if path filepath nil)))))
+      (while (and path
+                 (progn (setq filepath (expand-file-name file (car path)))
+                        (not (file-readable-p filepath))))
+       (setq path (cdr path)))
+      (if path filepath nil))))
 
 (defun erc-select-startup-file ()
   "Select an ERC startup file.
@@ -5747,7 +5740,6 @@ If optional NOEXPAND is non-nil, do not expand script-specific
 sequences, process the lines verbatim.  Use this for multiline
 user input."
   (let* ((cb (current-buffer))
-        (pnt (point))
         (s "")
         (sp (or (erc-command-indicator) (erc-prompt)))
         (args (and (boundp 'erc-script-args) erc-script-args)))
@@ -5988,17 +5980,16 @@ entry of `channel-members'."
         (user (if channel-data
                   (car channel-data)
                 (erc-get-server-user word)))
-        host login full-name info nick op voice)
+        host login full-name nick op voice)
     (when user
       (setq nick (erc-server-user-nickname user)
            host (erc-server-user-host user)
            login (erc-server-user-login user)
-           full-name (erc-server-user-full-name user)
-           info (erc-server-user-info user))
+           full-name (erc-server-user-full-name user))
       (if cuser
          (setq op (erc-channel-user-op cuser)
                voice (erc-channel-user-voice cuser)))
-      (if (interactive-p)
+      (if (called-interactively-p 'interactive)
          (message "%s is %s@%s%s%s"
                   nick login host
                   (if full-name (format " (%s)" full-name) "")
@@ -6006,7 +5997,7 @@ entry of `channel-members'."
                               (format " and is +%s%s on %s"
                               (if op "o" "")
                               (if voice "v" "")
-                                      (erc-default-target))
+                              (erc-default-target))
                             ""))
        user))))
 
@@ -6086,17 +6077,6 @@ Otherwise, use the `erc-header-line' face."
   :group 'erc-paranoia
   :type 'boolean)
 
-(defcustom erc-common-server-suffixes
-  '(("openprojects.net$" . "OPN")
-    ("freenode.net$" . "freenode")
-    ("oftc.net$" . "OFTC"))
-  "Alist of common server name suffixes.
-This variable is used in mode-line display to save screen
-real estate.  Set it to nil if you want to avoid changing
-displayed hostnames."
-  :group 'erc-mode-line-and-header
-  :type 'alist)
-
 (defcustom erc-mode-line-away-status-format
   "(AWAY since %a %b %d %H:%M) "
   "When you're away on a server, this is shown in the mode line.
@@ -6207,7 +6187,7 @@ if `erc-away' is non-nil."
                 ?m (erc-format-channel-modes)
                 ?n (or (erc-current-nick) "")
                 ?N (erc-format-network)
-                ?o (erc-controls-strip erc-channel-topic)
+                ?o (or (erc-controls-strip erc-channel-topic) "")
                 ?p (erc-port-to-string erc-session-port)
                 ?s (erc-format-target-and/or-server)
                 ?S (erc-format-target-and/or-network)
@@ -6300,7 +6280,7 @@ If optional argument HERE is non-nil, insert version number at point."
         (format "ERC %s (GNU Emacs %s)" erc-version-string emacs-version)))
     (if here
        (insert version-string)
-      (if (interactive-p)
+      (if (called-interactively-p 'interactive)
          (message "%s" version-string)
        version-string))))
 
@@ -6320,7 +6300,7 @@ If optional argument HERE is non-nil, insert version number at point."
                    ", ")))
     (if here
        (insert string)
-      (if (interactive-p)
+      (if (called-interactively-p 'interactive)
          (message "%s" string)
        string))))
 
@@ -6566,7 +6546,7 @@ See also `format-spec'."
 (add-hook 'kill-buffer-hook 'erc-kill-buffer-function)
 
 (defcustom erc-kill-server-hook '(erc-kill-server)
-  "Invoked whenever a server-buffer is killed via `kill-buffer'."
+  "Invoked whenever a server buffer is killed via `kill-buffer'."
   :group 'erc-hooks
   :type 'hook)
 
@@ -6671,9 +6651,9 @@ Otherwise, connect to HOST:PORT as USER and /join CHANNEL."
 
 (provide 'erc)
 
-;;; Deprecated. We might eventually stop requiring the goodies automatically.
-;;; IMPORTANT: This require must appear _after_ the above (provide 'erc) to
-;;; avoid a recursive require error when byte-compiling the entire package.
+;; Deprecated. We might eventually stop requiring the goodies automatically.
+;; IMPORTANT: This require must appear _after_ the above (provide 'erc) to
+;; avoid a recursive require error when byte-compiling the entire package.
 (require 'erc-goodies)
 
 ;;; erc.el ends here