]> code.delx.au - gnu-emacs/blobdiff - lisp/erc/erc.el
Reconnect asynchronously.
[gnu-emacs] / lisp / erc / erc.el
index 3bd9ff3ce71a9d3f9f8dab570cfa08c3c0d72f35..d82089f5b05bc322b607b0656c9d4752f44adfdb 100644 (file)
@@ -1,6 +1,6 @@
 ;; erc.el --- An Emacs Internet Relay Chat client  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1997-2014 Free Software Foundation, Inc.
+;; Copyright (C) 1997-2015 Free Software Foundation, Inc.
 
 ;; Author: Alexander L. Belikoff (alexander@belikoff.net)
 ;; Contributors: Sergey Berezin (sergey.berezin@cs.cmu.edu),
@@ -12,6 +12,7 @@
 ;;               Kelvin White (kwhite@gnu.org)
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: IRC, chat, client, Internet
+
 ;; Version: 5.3
 
 ;; This file is part of GNU Emacs.
 ;; * http://sv.gnu.org/projects/erc/
 ;; * http://www.emacswiki.org/cgi-bin/wiki/ERC
 
+
+
 ;; As of 2006-06-13, ERC development is now hosted on Savannah
 ;; (http://sv.gnu.org/projects/erc).  I invite everyone who wants to
 ;; hack on it to contact me <mwolson@gnu.org> in order to get write
 ;; access to the shared Arch archive.
 
-;; Installation:
-
-;; Put erc.el in your load-path, and put (require 'erc) in your .emacs.
-
 ;; Configuration:
 
 ;; Use M-x customize-group RET erc RET to get an overview
 ;;; History:
 ;;
 
-;;; Code:
-
-(defconst erc-version-string "Version 5.3"
+(defconst erc-version-string (format "\C-bERC\C-b (IRC client for Emacs %s)" emacs-version)
   "ERC version.  This is used by function `erc-version'.")
 
+;;; Code:
+
 (eval-when-compile (require 'cl-lib))
 (require 'font-lock)
 (require 'pp)
@@ -196,6 +195,12 @@ parameters and authentication."
   :set (lambda (sym val)
          (set sym (if (functionp val) (funcall val) val))))
 
+(defcustom erc-rename-buffers nil
+  "Non-nil means rename buffers with network name, if available."
+  :version "24.5"
+  :group 'erc
+  :type 'boolean)
+
 (defvar erc-password nil
   "Password to use when authenticating to an IRC server.
 It is not strictly necessary to provide this, since ERC will
@@ -225,7 +230,7 @@ prompt you for it.")
 (defcustom erc-hide-prompt nil
   "If non-nil, do not display the prompt for commands.
 
-\(A command is any input starting with a '/').
+\(A command is any input starting with a `/').
 
 See also the variables `erc-prompt' and `erc-command-indicator'."
   :group 'erc-display
@@ -252,8 +257,22 @@ If nil, only \"> \" will be shown."
           (repeat :inline t :tag "Others" (string :tag "IRC Message Type"))))
 
 (defcustom erc-hide-list nil
-  "List of IRC type messages to hide.
-A typical value would be '(\"JOIN\" \"PART\" \"QUIT\")."
+  "A global list of IRC message types to hide.
+A typical value would be \(\"JOIN\" \"PART\" \"QUIT\")."
+  :group 'erc-ignore
+  :type 'erc-message-type)
+
+(defcustom erc-network-hide-list nil
+  "A list of IRC networks to hide message types from.
+A typical value would be \((\"freenode\" \"MODE\")
+(\"OFTC\" \"JOIN\" \"QUIT\"))."
+  :group 'erc-ignore
+  :type 'erc-message-type)
+
+(defcustom erc-channel-hide-list nil
+  "A list of IRC channels to hide message types from.
+A typical value would be \((\"#emacs\" \"QUIT\" \"JOIN\")
+(\"#erc\" \"NICK\")."
   :group 'erc-ignore
   :type 'erc-message-type)
 
@@ -648,7 +667,7 @@ See also the variable `erc-prompt'."
   "Indicator used by ERC for showing commands.
 
 If non-nil, this will be used in the ERC buffer to indicate
-commands (i.e., input starting with a '/').
+commands (i.e., input starting with a `/').
 
 If nil, the prompt will be constructed from the variable `erc-prompt'."
   :group 'erc-display
@@ -677,8 +696,8 @@ See `erc-notice-prefix'.
 
 The following values are allowed:
 
-    'prefix - highlight notice prefix only
-    'all    - highlight the entire notice
+    `prefix' - highlight notice prefix only
+    `all'    - highlight the entire notice
 
 Any other value disables notice's highlighting altogether."
   :group 'erc-display
@@ -908,7 +927,7 @@ If no elements match, then the empty string is used.
 
 As an example:
   (setq erc-quit-reason-various-alist
-      '((\"xmms\" dme:now-playing)
+      \\='((\"xmms\" dme:now-playing)
         (\"version\" erc-quit-reason-normal)
         (\"home\" \"Gone home !\")
         (\"^$\" \"Default Reason\")))
@@ -931,7 +950,7 @@ If no elements match, then the empty string is used.
 
 As an example:
   (setq erc-part-reason-various-alist
-      '((\"xmms\" dme:now-playing)
+      \\='((\"xmms\" dme:now-playing)
         (\"version\" erc-part-reason-normal)
         (\"home\" \"Gone home !\")
         (\"^$\" \"Default Reason\")))
@@ -1000,7 +1019,7 @@ display of that particular string at all."
   "Hook called first when some text is sent through `erc-send-current-line'.
 It gets called with one argument, STRING.
 
-To change the text that will be sent, set the variable STR which is
+To change the text that will be sent, set the variable `str' which is
 used in `erc-send-current-line'.
 
 To change the text inserted into the buffer without changing the text
@@ -1104,7 +1123,7 @@ which the local user typed."
     (define-key map "\C-a" 'erc-bol)
     (define-key map [home] 'erc-bol)
     (define-key map "\C-c\C-a" 'erc-bol)
-    (define-key map "\C-c\C-b" 'erc-iswitchb)
+    (define-key map "\C-c\C-b" 'erc-switch-to-buffer)
     (define-key map "\C-c\C-c" 'erc-toggle-interpret-controls)
     (define-key map "\C-c\C-d" 'erc-input-action)
     (define-key map "\C-c\C-e" 'erc-toggle-ctcp-autoresponse)
@@ -1143,6 +1162,7 @@ which the local user typed."
   "Faces for ERC."
   :group 'erc)
 
+;; FIXME faces should not end in "-face".
 (defface erc-default-face '((t))
   "ERC default face."
   :group 'erc-faces)
@@ -1238,13 +1258,13 @@ erc-NAME-enable, and erc-NAME-disable.
 
 Example:
 
-  ;;;###autoload (autoload 'erc-replace-mode \"erc-replace\")
+  ;;;###autoload (autoload \\='erc-replace-mode \"erc-replace\")
   (define-erc-module replace nil
     \"This mode replaces incoming text according to `erc-replace-alist'.\"
-    ((add-hook 'erc-insert-modify-hook
-               'erc-replace-insert))
-    ((remove-hook 'erc-insert-modify-hook
-                  'erc-replace-insert)))"
+    ((add-hook \\='erc-insert-modify-hook
+               \\='erc-replace-insert))
+    ((remove-hook \\='erc-insert-modify-hook
+                  \\='erc-replace-insert)))"
   (declare (doc-string 3))
   (let* ((sn (symbol-name name))
          (mode (intern (format "erc-%s-mode" (downcase sn))))
@@ -1456,11 +1476,11 @@ Defaults to the server buffer."
 
 The available choices are:
 
-  'window          - in another window,
-  'window-noselect - in another window, but don't select that one,
-  'frame           - in another frame,
-  'bury            - bury it in a new buffer,
-  'buffer          - in place of the current buffer,
+  `window'          - in another window,
+  `window-noselect' - in another window, but don't select that one,
+  `frame'           - in another frame,
+  `bury'            - bury it in a new buffer,
+  `buffer'          - in place of the current buffer,
   any other value  - in place of the current buffer."
   :group 'erc-buffers
   :type '(choice (const :tag "Split window and select" window)
@@ -1640,6 +1660,14 @@ If PROC is not supplied, all processes are searched."
                 (throw 'buffer (current-buffer)))))
        proc))))
 
+(defun erc--buffer-p (buf predicate proc)
+  (with-current-buffer buf
+    (and (derived-mode-p 'erc-mode)
+        (or (not proc)
+            (eq proc erc-server-process))
+        (funcall predicate)
+        buf)))
+
 (defun erc-buffer-filter (predicate &optional proc)
   "Return a list of `erc-mode' buffers matching certain criteria.
 PREDICATE is a function executed with each buffer, if it returns t, that buffer
@@ -1652,12 +1680,7 @@ server connection, or nil which means all open connections."
      nil
      (mapcar (lambda (buf)
                (when (buffer-live-p buf)
-                 (with-current-buffer buf
-                   (and (eq major-mode 'erc-mode)
-                        (or (not proc)
-                            (eq proc erc-server-process))
-                        (funcall predicate)
-                        buf))))
+                (erc--buffer-p buf predicate proc)))
              (buffer-list)))))
 
 (defun erc-buffer-list (&optional predicate proc)
@@ -1688,42 +1711,33 @@ nil."
                                           ,pro))))
        ;; Silence the byte-compiler by binding the result of mapcar to
        ;; a variable.
+       (ignore res)
        res)))
 
-;; (iswitchb-mode) will autoload iswitchb.el
-(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.
+(define-obsolete-function-alias 'erc-iswitchb 'erc-switch-to-buffer "25.1")
+(defun erc-switch-to-buffer (&optional arg)
+  "Prompt for a ERC buffer to switch to.
 When invoked with prefix argument, use all erc buffers.  Without prefix
 ARG, allow only buffers related to same session server.
 If `erc-track-mode' is in enabled, put the last element of
-`erc-modified-channels-alist' in front of the buffer list.
-
-Due to some yet unresolved reason, global function `iswitchb-mode'
-needs to be active for this function to work."
+`erc-modified-channels-alist' in front of the buffer list."
   (interactive "P")
-  (let ((enabled (bound-and-true-p iswitchb-mode)))
-    (or enabled (iswitchb-mode 1))
-    (unwind-protect
-        (let ((iswitchb-make-buflist-hook
-               (lambda ()
-                 (setq iswitchb-temp-buflist
-                       (mapcar 'buffer-name
-                               (erc-buffer-list
-                                nil
-                                (when arg erc-server-process)))))))
-          (switch-to-buffer
-           (iswitchb-read-buffer
-            "Switch-to: "
-            (if (boundp 'erc-modified-channels-alist)
-                (buffer-name (caar (last erc-modified-channels-alist)))
-              nil)
-            t)))
-      (or enabled (iswitchb-mode -1)))))
+  (switch-to-buffer
+   (read-buffer "Switch to ERC buffer: "
+               (when (boundp 'erc-modified-channels-alist)
+                 (buffer-name (caar (last erc-modified-channels-alist))))
+               t
+               ;; Only allow ERC buffers in the same session.
+               (let ((proc (unless arg erc-server-process)))
+                 (lambda (bufname)
+                   (let ((buf (if (consp bufname)
+                                  (cdr bufname) (get-buffer bufname))))
+                     (when buf
+                       (erc--buffer-p buf (lambda () t) proc)
+                       (with-current-buffer buf
+                         (and (derived-mode-p 'erc-mode)
+                              (or (null proc)
+                                  (eq proc erc-server-process)))))))))))
 
 (defun erc-channel-list (proc)
   "Return a list of channel buffers.
@@ -1949,7 +1963,9 @@ Returns the buffer for the given server or channel."
     (erc-update-modules)
     (set-buffer buffer)
     (setq old-point (point))
-    (erc-mode)
+    (let ((old-recon-count erc-server-reconnect-count))
+      (erc-mode)
+      (setq erc-server-reconnect-count old-recon-count))
     (setq erc-server-announced-name server-announced-name)
     (setq erc-server-connected connected-p)
     ;; connection parameters
@@ -2052,9 +2068,10 @@ Returns the buffer for the given server or channel."
   "Initialize the `erc-last-saved-position' marker to a sensible position.
 BUFFER is the current buffer."
   (with-current-buffer buffer
-    (setq erc-last-saved-position (make-marker))
-    (move-marker erc-last-saved-position
-                 (1- (marker-position erc-insert-marker)))))
+    (unless (markerp erc-last-saved-position)
+      (setq erc-last-saved-position (make-marker))
+      (move-marker erc-last-saved-position
+                  (1- (marker-position erc-insert-marker))))))
 
 ;; interactive startup
 
@@ -2181,13 +2198,14 @@ be invoked for the values of the other parameters."
 Arguments are the same as for `erc'."
   (interactive (erc-select-read-args))
   (let ((erc-server-connect-function 'erc-open-tls-stream))
-    (apply 'erc r)))
+    (apply #'erc r)))
 
 (defun erc-open-tls-stream (name buffer host port)
   "Open an TLS stream to an IRC server.
 The process will be given the name NAME, its target buffer will be
 BUFFER.  HOST and PORT specify the connection target."
   (open-network-stream name buffer host port
+                      :nowait t
                        :type 'tls))
 
 ;;; Displaying error messages
@@ -2395,7 +2413,7 @@ If STRING is nil, the function does nothing."
 
 (defun erc-is-valid-nick-p (nick)
   "Check if NICK is a valid IRC nickname."
-  (string-match (concat "^" erc-valid-nick-regexp "$") nick))
+  (string-match (concat "\\`" erc-valid-nick-regexp "\\'") nick))
 
 (defun erc-display-line (string &optional buffer)
   "Display STRING in the ERC BUFFER.
@@ -2458,7 +2476,7 @@ on the given server.")
 (defcustom erc-lurker-trim-nicks t
   "If t, trim trailing `erc-lurker-ignore-chars' from nicks.
 
-This causes e.g. nick and nick` to be considered as the same
+This causes e.g. nick and nick\\=` to be considered as the same
 individual for activity tracking and lurkiness detection
 purposes."
   :group 'erc-lurker
@@ -2488,7 +2506,7 @@ non-nil."
 (defcustom erc-lurker-hide-list nil
   "List of IRC type messages to hide when sent by lurkers.
 
-A typical value would be '(\"JOIN\" \"PART\" \"QUIT\").
+A typical value would be \(\"JOIN\" \"PART\" \"QUIT\").
 See also `erc-lurker-p' and `erc-hide-list'."
   :group 'erc-lurker
   :type 'erc-message-type)
@@ -2594,9 +2612,9 @@ server within `erc-lurker-threshold-time'.  See also
            erc-lurker-threshold-time))))
 
 (defcustom erc-common-server-suffixes
-  '(("openprojects.net$" . "OPN")
-    ("freenode.net$" . "freenode")
-    ("oftc.net$" . "OFTC"))
+  '(("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
@@ -2614,15 +2632,36 @@ otherwise `erc-server-announced-name'.  SERVER is matched against
                erc-common-server-suffixes))
         erc-server-announced-name)))
 
+(defun erc-add-targets (scope target-list)
+  (let ((targets
+        (mapcar (lambda (targets) (member scope targets)) target-list)))
+    (cdr (apply 'append (delete nil targets)))))
+
 (defun erc-hide-current-message-p (parsed)
   "Predicate indicating whether the parsed ERC response PARSED should be hidden.
 
 Messages are always hidden if the message type of PARSED appears in
-`erc-hide-list'.  In addition, messages whose type is a member of
-`erc-lurker-hide-list' are hidden if `erc-lurker-p' returns true."
+`erc-hide-list'. Message types that appear in `erc-network-hide-list'
+or `erc-channel-hide-list' are are only hidden if the target matches
+the network or channel in the list. In addition, messages whose type
+is a member of `erc-lurker-hide-list' are hidden if `erc-lurker-p'
+returns non-nil."
   (let* ((command (erc-response.command parsed))
-         (sender (car (erc-parse-user (erc-response.sender parsed)))))
+         (sender (car (erc-parse-user (erc-response.sender parsed))))
+         (channel (nth 1 (erc-response.command-args parsed)))
+         (network (or (and (fboundp 'erc-network-name) (erc-network-name))
+                     (erc-shorten-server-name
+                      (or erc-server-announced-name
+                          erc-session-server))))
+        (current-hide-list
+         (when erc-network-hide-list
+           (erc-add-targets network erc-network-hide-list)))
+        (current-hide-list
+         (apply 'append current-hide-list
+                (when erc-channel-hide-list
+                  (erc-add-targets channel erc-channel-hide-list)))))
     (or (member command erc-hide-list)
+        (member command current-hide-list)
         (and (member command erc-lurker-hide-list) (erc-lurker-p sender)))))
 
 (defun erc-display-message (parsed type buffer msg &rest args)
@@ -2632,7 +2671,7 @@ ARGS, PARSED, and TYPE are used to format MSG sensibly.
 
 See also `erc-format-message' and `erc-display-line'."
   (let ((string (if (symbolp msg)
-                    (apply 'erc-format-message msg args)
+                    (apply #'erc-format-message msg args)
                   msg)))
     (setq string
           (cond
@@ -2681,7 +2720,7 @@ See also `erc-server-send'."
 (defun erc-get-arglist (fun)
   "Return the argument list of a function without the parens."
   (let ((arglist (format "%S" (erc-function-arglist fun))))
-    (if (string-match "^(\\(.*\\))$" arglist)
+    (if (string-match "\\`(\\(.*\\))\\'" arglist)
         (match-string 1 arglist)
       arglist)))
 
@@ -2697,7 +2736,7 @@ is not alive, nil otherwise."
   "For CMD being the function name of a ERC command, something like
 erc-cmd-FOO, this returns a string /FOO."
   (let ((command-name (symbol-name cmd)))
-    (if (string-match "^erc-cmd-\\(.*\\)$" command-name)
+    (if (string-match "\\`erc-cmd-\\(.*\\)\\'" command-name)
         (concat "/" (match-string 1 command-name))
       command-name)))
 
@@ -2753,7 +2792,7 @@ this function from interpreting the line as a command."
 (defun erc-cmd-SAY (line)
   "Send LINE to the current query or channel as a message, not a command.
 
-Use this when you want to send a message with a leading '/'.  Note
+Use this when you want to send a message with a leading `/'.  Note
 that since multi-line messages are never a command, you don't
 need this when pasting multiple lines of text."
   (if (string-match "^\\s-*$" line)
@@ -2788,7 +2827,7 @@ VALUE is computed by evaluating the rest of LINE in Lisp."
     (erc-display-line
      (concat "Available user variables:\n"
              (apply
-              'concat
+              #'concat
               (mapcar
                (lambda (var)
                  (let ((val (symbol-value var)))
@@ -2937,7 +2976,7 @@ VERSION and so on.  It is called with ARGS."
 If FUNC contains a valid function or variable, help about that
 will be displayed.  If FUNC is empty, display an apropos about
 ERC commands.  Otherwise, do `apropos' in the ERC namespace
-\(\"erc-.*LINE\"\).
+\(\"erc-.*LINE\").
 
 Examples:
 To find out about erc and bbdb, do
@@ -3083,9 +3122,9 @@ a script after exceeding the flood threshold."
         (erc-display-message nil 'error (current-buffer)
                              'cannot-read-file ?f file))
        (t
-        (message "Loading \'%s\'..." file)
+        (message "Loading `%s'..." file)
         (erc-load-script file)
-        (message "Loading \'%s\'...done" file))))
+        (message "Loading `%s'...done" file))))
     t)
    (t nil)))
 
@@ -3223,7 +3262,7 @@ The lines are shown in a buffer named `*Occur*'.
 It serves as a menu to find any of the occurrences in this buffer.
 \\[describe-mode] in that buffer will explain how.
 
-If LINE contains upper case characters (excluding those preceded by `\'),
+If LINE contains upper case characters (excluding those preceded by `\\'),
 the matching is case-sensitive."
   (occur line)
   t)
@@ -3380,14 +3419,16 @@ If USER is omitted, close the current query buffer if one exists
       (signal 'wrong-number-of-arguments ""))))
 (defalias 'erc-cmd-Q 'erc-cmd-QUERY)
 
+(defun erc-quit/part-reason-default ()
+  "Default quit/part message."
+  (format "\C-bERC\C-b (IRC client for Emacs %s)" emacs-version))
+
+
 (defun erc-quit-reason-normal (&optional s)
   "Normal quit message.
 
 If S is non-nil, it will be used as the quit reason."
-  (or s
-      (format "\C-bERC\C-b %s (IRC client for Emacs)"; - \C-b%s\C-b"
-              erc-version-string) ; erc-official-location)
-      ))
+  (or s (erc-quit/part-reason-default)))
 
 (defun erc-quit-reason-zippy (&optional s)
   "Zippy quit message.
@@ -3396,7 +3437,7 @@ If S is non-nil, it will be used as the quit reason."
   (or s
       (if (fboundp 'yow)
           (erc-replace-regexp-in-string "\n" "" (yow))
-        (erc-quit-reason-normal))))
+        (erc-quit/part-reason-default))))
 
 (make-obsolete 'erc-quit-reason-zippy "it will be removed." "24.4")
 
@@ -3409,16 +3450,13 @@ If S is non-nil, it will be used as the quit reason."
      ((functionp res) (funcall res))
      ((stringp res) res)
      (s s)
-     (t (erc-quit-reason-normal)))))
+     (t (erc-quit/part-reason-default)))))
 
 (defun erc-part-reason-normal (&optional s)
   "Normal part message.
 
-If S is non-nil, it will be used as the quit reason."
-  (or s
-      (format "\C-bERC\C-b %s (IRC client for Emacs)"; - \C-b%s\C-b"
-              erc-version-string) ; erc-official-location)
-      ))
+If S is non-nil, it will be used as the part reason."
+  (or s (erc-quit/part-reason-default)))
 
 (defun erc-part-reason-zippy (&optional s)
   "Zippy part message.
@@ -3427,7 +3465,7 @@ If S is non-nil, it will be used as the quit reason."
   (or s
       (if (fboundp 'yow)
           (erc-replace-regexp-in-string "\n" "" (yow))
-        (erc-part-reason-normal))))
+        (erc-quit/part-reason-default))))
 
 (make-obsolete 'erc-part-reason-zippy "it will be removed." "24.4")
 
@@ -3440,7 +3478,7 @@ If S is non-nil, it will be used as the quit reason."
      ((functionp res) (funcall res))
      ((stringp res) res)
      (s s)
-     (t (erc-part-reason-normal)))))
+     (t (erc-quit/part-reason-default)))))
 
 (defun erc-cmd-QUIT (reason)
   "Disconnect from the current server.
@@ -3534,8 +3572,7 @@ the message given by REASON."
 
 (defun erc-cmd-SV ()
   "Say the current ERC and Emacs version into channel."
-  (erc-send-message (format "I'm using ERC %s with %s %s (%s%s) of %s."
-                            erc-version-string
+  (erc-send-message (format "I'm using ERC with %s %s (%s%s) of %s."
                             (if (featurep 'xemacs) "XEmacs" "GNU Emacs")
                             emacs-version
                             system-configuration
@@ -3769,7 +3806,7 @@ Unban all currently banned users in the current channel."
                t)))
           (erc-server-send (format "MODE %s b" chnl)))))
 
-     (t (let ((bans (mapcar 'cdr erc-channel-banlist)))
+     (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*!*@*
@@ -3924,7 +3961,7 @@ If `point' is at the beginning of a channel name, use that as default."
      (concat "Set topic of " (erc-default-target) ": ")
      (when erc-channel-topic
        (let ((ss (split-string erc-channel-topic "\C-o")))
-         (cons (apply 'concat (if (cdr ss) (butlast ss) ss))
+         (cons (apply #'concat (if (cdr ss) (butlast ss) ss))
                0))))))
   (let ((topic-list (split-string topic "\C-o"))) ; strip off the topic setter
     (erc-cmd-TOPIC (concat (erc-default-target) " " (car topic-list)))))
@@ -4150,7 +4187,7 @@ See also `erc-display-error-notice'."
                                    ;; server's setting if we haven't
                                    ;; established a connection yet
                                    (- 9 (length erc-nick-uniquifier))))
-                                erc-nick-uniquifier)))
+                               erc-nick-uniquifier)))
       (erc-cmd-NICK newnick)
       (erc-display-error-notice
        nil
@@ -4227,11 +4264,7 @@ and as second argument the event parsed as a vector."
 (defun erc-format-nick (&optional user _channel-data)
   "Return the nickname of USER.
 See also `erc-format-nick-function'."
-  (let ((nick (erc-server-user-nickname user)))
-    (concat (erc-propertize
-             (erc-get-user-mode-prefix nick)
-             'face 'erc-nick-prefix-face)
-           nick)))
+  (when user (erc-server-user-nickname user)))
 
 (defun erc-get-user-mode-prefix (user)
   (when user
@@ -4247,7 +4280,7 @@ See also `erc-format-nick-function'."
            (erc-propertize "+" 'help-echo "voice"))
           (t ""))))
 
-(defun erc-format-@nick (&optional user channel-data)
+(defun erc-format-@nick (&optional user _channel-data)
   "Format the nickname of USER showing if USER has a voice, is an
 operator, half-op, admin or owner. Owners have \"~\", admins have
 \"&\", operators have \"@\" and users with voice have \"+\" as a
@@ -4436,7 +4469,7 @@ See also: `erc-echo-notice-in-user-buffers',
   "Handle the logging in process of connection."
   (unless erc-logged-in
     (setq erc-logged-in t)
-    (message "Logging in as \'%s\'... done" (erc-current-nick))
+    (message "Logging in as `%s'... done" (erc-current-nick))
     ;; execute a startup script
     (let ((f (erc-select-startup-file)))
       (when f
@@ -4453,6 +4486,7 @@ Set user modes and run `erc-after-connect' hook."
             (nick (car (erc-response.command-args parsed)))
             (buffer (process-buffer proc)))
         (setq erc-server-connected t)
+       (setq erc-server-reconnect-count 0)
         (erc-update-mode-line)
         (erc-set-initial-user-mode nick buffer)
         (erc-server-setup-periodical-ping buffer)
@@ -4594,8 +4628,8 @@ See also `erc-display-message'."
   (unless erc-disable-ctcp-replies
     (erc-send-ctcp-notice
      nick (format
-           "VERSION \C-bERC\C-b %s - an IRC client for emacs (\C-b%s\C-b)"
-           erc-version-string
+           "VERSION \C-bERC\C-b - an IRC client for Emacs %s (\C-b%s\C-b)"
+           emacs-version
            erc-official-location)))
   nil)
 
@@ -4771,22 +4805,24 @@ channel."
          (hop-ch (cdr (assq ?h prefix)))
          (adm-ch (cdr (assq ?a prefix)))
          (own-ch (cdr (assq ?q prefix)))
-         names name op voice halfop admin owner)
-    (setq names (delete "" (split-string names-string)))
+         (names (delete "" (split-string names-string)))
+        name op voice halfop admin owner)
     (let ((erc-channel-members-changed-hook nil))
       (dolist (item names)
-        (let ((updatep t))
+        (let ((updatep t)
+             (ch (aref item 0)))
           (setq name item op 'off voice 'off halfop 'off admin 'off owner 'off)
-          (if (rassq (elt item 0) prefix)
+          (if (rassq ch prefix)
               (if (= (length item) 1)
                  (setq updatep nil)
                (setq name (substring item 1))
-               (setf (pcase (aref item 0)
+               (setf (pcase ch
                        ((pred (eq voice-ch)) voice)
-                       ((pred (eq hop-ch))   hop)
+                       ((pred (eq hop-ch))   halfop)
                        ((pred (eq op-ch))    op)
-                       ((pred (eq adm-ch))   adm)
-                       ((pred (eq own-ch))   own))
+                       ((pred (eq adm-ch))   admin)
+                       ((pred (eq own-ch))   owner)
+                       (_ (error "Unknown prefix char `%S'" ch) voice))
                      'on)))
           (when updatep
             (puthash (erc-downcase name) t
@@ -5048,7 +5084,7 @@ arg-modes is a list of triples of the form:
 
   (MODE-CHAR ON/OFF ARGUMENT)."
   (if (string-match "^\\s-*\\(\\S-+\\)\\(\\s-.*$\\|$\\)" mode-string)
-      (let ((chars (mapcar 'char-to-string (match-string 1 mode-string)))
+      (let ((chars (mapcar #'char-to-string (match-string 1 mode-string)))
             ;; arguments in channel modes
             (args-str (match-string 2 mode-string))
             (args nil)
@@ -5087,7 +5123,7 @@ arg-modes is a list of triples of the form:
         (list add-modes remove-modes arg-modes))
     nil))
 
-(defun erc-update-modes (tgt mode-string &optional nick host login)
+(defun erc-update-modes (tgt mode-string &optional _nick _host _login)
   "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."
@@ -5171,7 +5207,7 @@ So far the following TYPE/L pairs are supported:
 
        Event                    TYPE                   L
 
-    nickname change            'nick                (NEW-NICK)"
+    nickname change            `nick'                (NEW-NICK)"
   (erc-log (format "user-change: type: %S  nlh: %S  l: %S" type nlh l))
   (cond
    ;; nickname change
@@ -5359,6 +5395,7 @@ This returns non-nil only if we actually send anything."
       (beep))
     nil)
    (t
+    (defvar str) ;; FIXME: Make it obey the "erc-" prefix convention.
     (let ((str input)
           (erc-insert-this t))
       (setq erc-send-this t)
@@ -5377,8 +5414,6 @@ This returns non-nil only if we actually send anything."
                 (or (and erc-flood-protect (erc-split-line line))
                     (list line))))
              (split-string str "\n"))
-          ;; Insert the prompt along with the command.
-          (erc-display-command str)
           (erc-process-input-line (concat str "\n") t nil))
         t)))))
 
@@ -5956,17 +5991,10 @@ Returns a list of the form (HIGH LOW), compatible with Emacs time format."
     (list (truncate (/ n 65536))
           (truncate (mod n 65536)))))
 
-(defun erc-emacs-time-to-erc-time (time)
-  "Convert Emacs TIME to a number of seconds since the epoch."
-  (when time
-    (+ (* (nth 0 time) 65536.0) (nth 1 time))))
-;  (round (+ (* (nth 0 tm) 65536.0) (nth 1 tm))))
-
-(defun erc-current-time ()
-  "Return the `current-time' as a number of seconds since the epoch.
+(defalias 'erc-emacs-time-to-erc-time
+  (if (featurep 'xemacs) 'time-to-seconds 'float-time))
 
-See also `erc-emacs-time-to-erc-time'."
-  (erc-emacs-time-to-erc-time (current-time)))
+(defalias 'erc-current-time 'erc-emacs-time-to-erc-time)
 
 (defun erc-time-diff (t1 t2)
   "Return the time difference in seconds between T1 and T2."
@@ -6002,7 +6030,7 @@ See also `erc-emacs-time-to-erc-time'."
                             (if (> minutes 0)
                                 `("%d minutes, %d seconds" ,minutes ,seconds)
                               `("%d seconds" ,seconds))))
-          output        (apply 'format format-args))
+          output        (apply #'format format-args))
     ;; Change all "1 units" to "1 unit".
     (while (string-match "\\([^0-9]\\|^\\)1 \\S-+\\(s\\)" output)
       (setq output (erc-replace-match-subexpression-in-string
@@ -6086,7 +6114,7 @@ entry of `channel-members'."
                  nick login host
                  (if full-name (format " (%s)" full-name) "")
                  (if (or voice halfop op admin owner)
-                     (format " and is +%s%s on %s"
+                     (format " and is +%s%s%s%s%s on %s"
                              (if voice "v" "")
                              (if halfop "h" "")
                              (if op "o" "")
@@ -6233,7 +6261,11 @@ shortened server name instead."
     (cond ((erc-default-target)
            (concat (erc-string-no-properties (erc-default-target))
                    "@" network-name))
-          (network-name network-name)
+          ((and network-name
+                (not (get-buffer network-name)))
+           (when erc-rename-buffers
+            (rename-buffer network-name))
+           network-name)
           (t (buffer-name (current-buffer))))))
 
 (defun erc-format-away-status ()
@@ -6246,7 +6278,7 @@ if `erc-away' is non-nil."
 
 (defun erc-format-channel-modes ()
   "Return the current channel's modes."
-  (concat (apply 'concat
+  (concat (apply #'concat
                  "+" erc-channel-modes)
           (cond ((and erc-channel-user-limit erc-channel-key)
                  (if erc-show-channel-key-p
@@ -6372,7 +6404,7 @@ P may be an integer or a service name."
 If optional argument HERE is non-nil, insert version number at point."
   (interactive "P")
   (let ((version-string
-         (format "ERC %s (GNU Emacs %s)" erc-version-string emacs-version)))
+         (format "ERC (IRC client for Emacs %s)" emacs-version)))
     (if here
         (insert version-string)
       (if (called-interactively-p 'interactive)
@@ -6438,7 +6470,7 @@ All windows are opened in the current frame."
                 "Mode: "
                 (mapcar (lambda (e)
                           (list (symbol-name e)))
-                        (apropos-internal "-mode$" 'commandp))
+                        (apropos-internal "-mode\\'" 'commandp))
                 nil t))))
     (pop-to-buffer (make-indirect-buffer (current-buffer) buffer-name))
     (funcall mode)
@@ -6484,7 +6516,7 @@ All windows are opened in the current frame."
     . "\n\nConnection failed!  Not re-establishing connection.\n")
    (finished . "\n\n*** ERC finished ***\n")
    (terminated . "\n\n*** ERC terminated: %e\n")
-   (login . "Logging in as \'%n\'...")
+   (login . "Logging in as `%n'...")
    (nick-in-use . "%n is in use. Choose new nickname: ")
    (nick-too-long
     . "WARNING: Nick length (%i) exceeds max NICKLEN(%l) defined by server")
@@ -6634,7 +6666,7 @@ See also `format-spec'."
       (error "No format spec for message %s" msg))
     (when (functionp entry)
       (setq entry (apply entry args)))
-    (format-spec entry (apply 'format-spec-make args))))
+    (format-spec entry (apply #'format-spec-make args))))
 
 ;;; Various hook functions