Replace `iff' in doc-strings and comments.
[bpt/emacs.git] / lisp / erc / erc.el
index 9ff3ff5..c26bdf2 100644 (file)
@@ -1,8 +1,7 @@
 ;; erc.el --- An Emacs Internet Relay Chat client
 
 ;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-;;   2006 Free Software Foundation, Inc.
-;; Copyright (C) 2004 Brian Palmer
+;;   2006, 2007 Free Software Foundation, Inc.
 
 ;; Author: Alexander L. Belikoff (alexander@belikoff.net)
 ;; Contributors: Sergey Berezin (sergey.berezin@cs.cmu.edu),
 ;;               Andreas Fuchs (afs@void.at)
 ;;               Gergely Nagy (algernon@midgard.debian.net)
 ;;               David Edmondson (dme@dme.org)
-;; Maintainer: Mario Lang (mlang@delysid.org)
+;; Maintainer: Michael Olson (mwolson@gnu.org)
 ;; Keywords: IRC, chat, client, Internet
 
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 
 ;;; Commentary:
 
-;; ERC is an IRC client for Emacs.
+;; ERC is a powerful, modular, and extensible IRC client for Emacs.
 
 ;; For more information, see the following URLs:
-;; * http://sf.net/projects/erc/
-;; * http://www.emacswiki.org/cgi-bin/wiki.pl?EmacsIRCClient
+;; * http://sv.gnu.org/projects/erc/
+;; * http://www.emacswiki.org/cgi-bin/wiki/ERC
 
-;; Jul-26-2001. erc.el is now in CVS on SourceForge.  I invite everyone
-;; who wants to hack it to contact me <mlang@delysid.org> in order to
-;; get write access on the CVS.
+;; 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:
 
 
 ;; To connect to an IRC server, do
 ;;
-;; M-x erc-select RET
+;; M-x erc RET
 ;;
 ;; After you are connected to a server, you can use C-h m or have a look at
-;; the IRC menu.
+;; the ERC menu.
 
 ;;; History:
 ;;
 
 ;;; Code:
 
-(defconst erc-version-string "Version 5.1 (Emacs 22)"
+(defconst erc-version-string "Version 5.2"
   "ERC version.  This is used by function `erc-version'.")
 
 (eval-when-compile (require 'cl))
 (require 'pp)
 (require 'thingatpt)
 (require 'erc-compat)
-(require 'erc-menu)
 
 (defvar erc-official-location
-  "http://erc.sf.net (comments mailto://mlang@delysid.org)"
+  "http://emacswiki.org/cgi-bin/wiki/ERC (mailing list: erc-discuss@gnu.org)"
   "Location of the ERC client on the Internet.")
 
 (defgroup erc nil
   "Emacs Internet Relay Chat client."
-  :link '(url-link "http://www.emacswiki.org/cgi-bin/wiki.pl?EmacsIRCClient")
+  :link '(url-link "http://www.emacswiki.org/cgi-bin/wiki/ERC")
   :prefix "erc-"
   :group 'applications)
 
 ;; tunable connection and authentication parameters
 
 (defcustom erc-server nil
-  "IRC server to use.
+  "IRC server to use if one is not provided.
 See function `erc-compute-server' for more details on connection
 parameters and authentication."
   :group 'erc
-  :type '(choice (const nil) string))
+  :type '(choice (const :tag "None" nil)
+                (string :tag "Server")))
 
 (defcustom erc-port nil
-  "IRC port to use."
+  "IRC port to use if not specified.
+
+This can be either a string or a number."
   :group 'erc
-  :type '(choice (const nil) number string))
+  :type '(choice (const :tag "None" nil)
+                (integer :tag "Port number")
+                (string :tag "Port string")))
 
 (defcustom erc-nick nil
-  "Nickname to use.
+  "Nickname to use if one is not provided.
 
-Can be either a string, or a list of strings.
+This can be either a string, or a list of strings.
 In the latter case, if the first nick in the list is already in use,
 other nicks are tried in the list order.
 
 See function `erc-compute-nick' for more details on connection
 parameters and authentication."
   :group 'erc
-  :type '(choice (const nil)
+  :type '(choice (const :tag "None" nil)
                 (string :tag "Nickname")
-                (repeat string)))
+                (repeat (string :tag "Nickname"))))
 
 (defcustom erc-nick-uniquifier "`"
-  "The character to append to the nick if it is already in use."
+  "The string to append to the nick if it is already in use."
   :group 'erc
   :type 'string)
 
-(defcustom erc-manual-set-nick-on-bad-nick-p nil
-  "If the nickname you chose isn't available, ERC should not automatically
-attempt to set another nickname.  You can manually set another nickname with
-the /NICK command."
+(defcustom erc-try-new-nick-p t
+  "If the nickname you chose isn't available, and this option is non-nil,
+ERC should automatically attempt to connect with another nickname.
+
+You can manually set another nickname with the /NICK command."
   :group 'erc
   :type 'boolean)
 
 (defcustom erc-user-full-name nil
   "User full name.
 
+This can be either a string or a function to call.
+
 See function `erc-compute-full-name' for more details on connection
 parameters and authentication."
   :group 'erc
-  :type '(choice (const nil) string function)
+  :type '(choice (const :tag "No name" nil)
+                (string :tag "Name")
+                (function :tag "Get from function"))
   :set (lambda (sym val)
         (if (functionp val)
             (set sym (funcall val))
           (set sym val))))
 
 (defvar erc-password nil
-  "ERC password to use in authentication (not necessary).")
+  "Password to use when authenticating to an IRC server.
+It is not strictly necessary to provide this, since ERC will
+prompt you for it.")
 
 (defcustom erc-user-mode nil
   "Initial user modes to be set after a connection is established."
@@ -313,7 +324,7 @@ Each function should accept two arguments, NEW-NICK and OLD-NICK."
 
 (defcustom erc-connect-pre-hook '(erc-initialize-log-marker)
   "Hook called just before `erc' calls `erc-connect'.
-Functions are run in the buffer-to-be."
+Functions are passed a buffer as the first argument."
   :group 'erc-hooks
   :type 'hook)
 
@@ -344,6 +355,17 @@ nicknames with erc-server-user struct instances.")
              (cdr (assq (aref s (match-beginning 0)) c)))))
     s))
 
+(defmacro erc-with-server-buffer (&rest body)
+  "Execute BODY in the current ERC server buffer.
+If no server buffer exists, return nil."
+  (let ((buffer (make-symbol "buffer")))
+    `(let ((,buffer (erc-server-buffer)))
+       (when (buffer-live-p ,buffer)
+        (with-current-buffer ,buffer
+          ,@body)))))
+(put 'erc-with-server-buffer 'lisp-indent-function 0)
+(put 'erc-with-server-buffer 'edebug-form-spec '(body))
+
 (defstruct (erc-server-user (:type vector) :named)
   ;; User data
   nickname host login full-name info
@@ -370,14 +392,14 @@ in the current buffer's `erc-channel-users' hash table."
 (defsubst erc-get-server-user (nick)
   "Finds the USER corresponding to NICK in the current server's
 `erc-server-users' hash table."
-  (with-current-buffer (process-buffer erc-server-process)
+  (erc-with-server-buffer
     (gethash (erc-downcase nick) erc-server-users)))
 
 (defsubst erc-add-server-user (nick user)
   "This function is for internal use only.
 
 Adds USER with nickname NICK to the `erc-server-users' hash table."
-  (with-current-buffer (process-buffer erc-server-process)
+  (erc-with-server-buffer
     (puthash (erc-downcase nick) user erc-server-users)))
 
 (defsubst erc-remove-server-user (nick)
@@ -388,7 +410,7 @@ hash table.  This user is not removed from the
 `erc-channel-users' lists of other buffers.
 
 See also: `erc-remove-user'."
-  (with-current-buffer (process-buffer erc-server-process)
+  (erc-with-server-buffer
     (remhash (erc-downcase nick) erc-server-users)))
 
 (defun erc-change-user-nickname (user new-nick)
@@ -399,7 +421,7 @@ Changes the nickname of USER to NEW-NICK in the
 other buffers are also changed."
   (let ((nick (erc-server-user-nickname user)))
     (setf (erc-server-user-nickname user) new-nick)
-    (with-current-buffer (process-buffer erc-server-process)
+    (erc-with-server-buffer
       (remhash (erc-downcase nick) erc-server-users)
       (puthash (erc-downcase new-nick) user erc-server-users))
     (dolist (buf (erc-server-user-buffers user))
@@ -461,7 +483,7 @@ Removes all users in the current channel.  This is called by
     (clrhash erc-channel-users)))
 
 (defsubst erc-channel-user-op-p (nick)
-  "Return `t' if NICK is an operator in the current channel."
+  "Return t if NICK is an operator in the current channel."
   (and nick
        (hash-table-p erc-channel-users)
        (let ((cdata (erc-get-channel-user nick)))
@@ -469,7 +491,7 @@ Removes all users in the current channel.  This is called by
              (erc-channel-user-op (cdr cdata))))))
 
 (defsubst erc-channel-user-voice-p (nick)
-  "Return `t' if NICK has voice in the current channel."
+  "Return t if NICK has voice in the current channel."
   (and nick
        (hash-table-p erc-channel-users)
        (let ((cdata (erc-get-channel-user nick)))
@@ -492,16 +514,15 @@ See also: `erc-sort-channel-users-by-activity'"
 
 (defun erc-get-server-nickname-list ()
   "Returns a list of known nicknames on the current server."
-    (if (erc-server-process-alive)
-       (with-current-buffer (erc-server-buffer)
-         (let (nicks)
-           (when (hash-table-p erc-server-users)
-             (maphash (lambda (n user)
-                        (setq nicks
-                              (cons (erc-server-user-nickname user)
-                                    nicks)))
-                      erc-server-users)
-             nicks)))))
+  (erc-with-server-buffer
+    (let (nicks)
+      (when (hash-table-p erc-server-users)
+       (maphash (lambda (n user)
+                  (setq nicks
+                        (cons (erc-server-user-nickname user)
+                              nicks)))
+                erc-server-users)
+       nicks))))
 
 (defun erc-get-channel-nickname-list ()
   "Returns a list of known nicknames on the current channel."
@@ -516,16 +537,15 @@ See also: `erc-sort-channel-users-by-activity'"
 
 (defun erc-get-server-nickname-alist ()
   "Returns an alist of known nicknames on the current server."
-    (if (erc-server-process-alive)
-       (with-current-buffer (erc-server-buffer)
-         (let (nicks)
-           (when (hash-table-p erc-server-users)
-             (maphash (lambda (n user)
-                        (setq nicks
-                              (cons (cons (erc-server-user-nickname user) nil)
-                                    nicks)))
-                      erc-server-users)
-             nicks)))))
+  (erc-with-server-buffer
+    (let (nicks)
+      (when (hash-table-p erc-server-users)
+       (maphash (lambda (n user)
+                  (setq nicks
+                        (cons (cons (erc-server-user-nickname user) nil)
+                              nicks)))
+                erc-server-users)
+       nicks))))
 
 (defun erc-get-channel-nickname-alist ()
   "Returns an alist of known nicknames on the current channel."
@@ -761,7 +781,7 @@ set if some hacker is trying to flood you away."
   :type 'boolean)
 
 (defcustom erc-prompt-for-channel-key nil
-  "Prompt for channel key when using `erc-join-channel' interactively"
+  "Prompt for channel key when using `erc-join-channel' interactively."
   :group 'erc
   :type 'boolean)
 
@@ -770,6 +790,13 @@ set if some hacker is trying to flood you away."
   :group 'erc
   :type 'string)
 
+(defcustom erc-system-name nil
+  "Use this as the name of your system.
+If nil, ERC will call `system-name' to get this information."
+  :group 'erc
+  :type '(choice (const :tag "Default system name" nil)
+                string))
+
 (defcustom erc-ignore-list nil
   "*List of regexps matching user identifiers to ignore.
 
@@ -794,7 +821,7 @@ whose identifier matches, the message will not be processed.
 CAVEAT: ERC doesn't know about the user and host of anyone who
 was already in the channel when you joined, but never said
 anything, so it won't be able to match the user and host of those
-people. You can update the ERC internal info using /WHO *."
+people.  You can update the ERC internal info using /WHO *."
   :group 'erc-ignore
   :type '(repeat regexp))
 
@@ -809,13 +836,14 @@ See `erc-server-flood-margin' for other flood-related parameters.")
 ;; Script parameters
 
 (defcustom erc-startup-file-list
-  '("~/.ercrc.el" "~/.ercrc" ".ercrc.el" ".ercrc")
+  '("~/.emacs.d/.ercrc.el" "~/.emacs.d/.ercrc"
+    "~/.ercrc.el" "~/.ercrc" ".ercrc.el" ".ercrc")
   "List of files to try for a startup script.
 The first existent and readable one will get executed.
 
-If the filename ends with `.el' it is presumed to be an emacs-lisp
-script and it gets (load)ed.  Otherwise is is treated as a bunch of
-regular IRC commands"
+If the filename ends with `.el' it is presumed to be an Emacs Lisp
+script and it gets (load)ed.  Otherwise it is treated as a bunch of
+regular IRC commands."
   :group 'erc-scripts
   :type '(repeat file))
 
@@ -827,7 +855,7 @@ directory in the list."
   :type '(repeat directory))
 
 (defcustom erc-script-echo t
-  "*If not-NIL, echo the IRC script commands locally."
+  "*If non-nil, echo the IRC script commands locally."
   :group 'erc-scripts
   :type 'boolean)
 
@@ -871,7 +899,7 @@ As an example:
        (\"xmms\" dme:now-playing)
        (\"version\" erc-quit-reason-normal)
        (\"home\" \"Gone home !\")
-       (\"\" \"Default Reason\")))
+       (\"^$\" \"Default Reason\")))
 If the user types \"/quit zippy\", then a Zippy the Pinhead quotation
 will be used as the quit message."
   :group 'erc-quit-and-part
@@ -895,7 +923,7 @@ As an example:
        (\"xmms\" dme:now-playing)
        (\"version\" erc-part-reason-normal)
        (\"home\" \"Gone home !\")
-       (\"\" \"Default Reason\")))
+       (\"^$\" \"Default Reason\")))
 If the user types \"/part zippy\", then a Zippy the Pinhead quotation
 will be used as the part message."
   :group 'erc-quit-and-part
@@ -1028,7 +1056,7 @@ At this point, all modifications from prior hook functions are done.
 NOTE: The functions on this hook are called _before_ sending a command
 to the server.
 
-This function is called with narrowing, ala `erc-send-modify-hook'"
+This function is called with narrowing, ala `erc-send-modify-hook'."
   :group 'erc-hooks
   :type 'hook
   :options '(erc-make-read-only))
@@ -1116,12 +1144,19 @@ which the local user typed."
   "ERC face used for messages you receive in the main erc buffer."
   :group 'erc-faces)
 
+(defface erc-header-line
+  '((t (:foreground "grey20" :background "grey90")))
+  "ERC face used for the header line.
+
+This will only be used if `erc-header-line-face-method' is non-nil."
+  :group 'erc-faces)
+
 (defface erc-input-face '((t (:foreground "brown")))
   "ERC face used for your input."
   :group 'erc-faces)
 
 (defface erc-prompt-face
-  '((t (:bold t :foreground "Black" :background"lightBlue2")))
+  '((t (:bold t :foreground "Black" :background "lightBlue2")))
   "ERC face for the prompt."
   :group 'erc-faces)
 
@@ -1143,6 +1178,12 @@ See the variable `erc-command-indicator'."
   "ERC face for errors."
   :group 'erc-faces)
 
+;; same default color as `erc-input-face'
+(defface erc-my-nick-face '((t (:bold t :foreground "brown")))
+  "ERC face for your current nickname in messages sent by you.
+See also `erc-show-my-nick'."
+  :group 'erc-faces)
+
 (defface erc-nick-default-face '((t (:bold t)))
   "ERC nickname default face."
   :group 'erc-faces)
@@ -1171,7 +1212,7 @@ DOC is the documentation string to use for the minor mode.
 ENABLE-BODY is a list of expressions used to enable the mode.
 DISABLE-BODY is a list of expressions used to disable the mode.
 If LOCAL-P is non-nil, the mode will be created as a buffer-local
-mode.  Rather than a global one.
+mode, rather than a global one.
 
 This will define a minor mode called erc-NAME-mode, possibly
 an alias erc-ALIAS-mode, as well as the helper functions
@@ -1223,7 +1264,11 @@ With arg, turn ERC %S mode on if and only if arg is positive.
                (format "erc-%s-mode"
                        (downcase (symbol-name alias)))))
             (quote
-             ,mode))))))
+             ,mode)))
+       ;; For find-function and find-variable.
+       (put ',mode    'definition-name ',name)
+       (put ',enable  'definition-name ',name)
+       (put ',disable 'definition-name ',name))))
 
 (put 'define-erc-module 'doc-string-elt 3)
 
@@ -1235,7 +1280,7 @@ 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
-or t nil indicates that the other functions on EVENT's hook
+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.
 
@@ -1246,7 +1291,7 @@ capabilities."
   (unless (erc-server-buffer-p)
     (error
      "You should only run `erc-once-with-server-event' in a server buffer"))
-  (let ((fun (erc-gensym))
+  (let ((fun (make-symbol "fun"))
        (hook (erc-get-hook event)))
      (put fun 'erc-original-buffer (current-buffer))
      (fset fun `(lambda (proc parsed)
@@ -1263,13 +1308,13 @@ capabilities."
 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 nil indicates that the other functions on EVENT's hook
+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 (erc-gensym))
+  (let ((fun (make-symbol "fun"))
        (hook (erc-get-hook event)))
      (fset fun `(lambda (proc parsed)
                  (remove-hook ',hook ',fun)
@@ -1291,8 +1336,7 @@ the process buffer."
        (process-buffer erc-server-process)))
 
 (defun erc-server-buffer-live-p ()
-  "Return t if the buffer associated with `erc-server-process'
-has not been killed."
+  "Return t if the server buffer has not been killed."
   (and (processp erc-server-process)
        (buffer-live-p (process-buffer erc-server-process))))
 
@@ -1304,6 +1348,14 @@ If BUFFER is nil, the current buffer is used."
     (and (eq major-mode 'erc-mode)
         (null (erc-default-target)))))
 
+(defun erc-open-server-buffer-p (&optional buffer)
+  "Return non-nil if argument BUFFER is an ERC server buffer that
+has an open IRC process.
+
+If BUFFER is nil, the current buffer is used."
+  (and (erc-server-buffer-p)
+       (erc-server-process-alive)))
+
 (defun erc-query-buffer-p (&optional buffer)
   "Return non-nil if BUFFER is an ERC query buffer.
 If BUFFER is nil, the current buffer is used."
@@ -1316,7 +1368,7 @@ If BUFFER is nil, the current buffer is used."
 (defun erc-ison-p (nick)
   "Return non-nil if NICK is online."
   (interactive "sNick: ")
-  (with-current-buffer (erc-server-buffer)
+  (erc-with-server-buffer
     (let ((erc-online-p 'unknown))
       (erc-once-with-server-event
        303
@@ -1360,13 +1412,16 @@ If BUFFER is nil, the current buffer is used."
 (defvar erc-active-buffer nil
   "The current active buffer, the one where the user typed the last command.
 Defaults to the server buffer, and should only be set in the
-server buffer")
+server buffer.")
 (make-variable-buffer-local 'erc-active-buffer)
 
 (defun erc-active-buffer ()
   "Return the value of `erc-active-buffer' for the current server.
 Defaults to the server buffer."
-  (with-current-buffer (erc-server-buffer) erc-active-buffer))
+  (erc-with-server-buffer
+    (if (buffer-live-p erc-active-buffer)
+       erc-active-buffer
+      (setq erc-active-buffer (current-buffer)))))
 
 (defun erc-set-active-buffer (buffer)
   "Set the value of `erc-active-buffer' to BUFFER."
@@ -1405,7 +1460,7 @@ Turning on `erc-mode' runs the hook `erc-mode-hook'."
 (defconst erc-default-server "irc.freenode.net"
   "IRC server to use if it cannot be detected otherwise.")
 
-(defconst erc-default-port "ircd"
+(defconst erc-default-port "6667"
   "IRC port to use if it cannot be detected otherwise.")
 
 (defcustom erc-join-buffer 'buffer
@@ -1414,7 +1469,7 @@ Turning on `erc-mode' runs the hook `erc-mode-hook'."
 'window-noselect - in another window, but don't select that one,
 'frame - in another frame,
 'bury - bury it in a new buffer,
-any other value - in place of the current buffer"
+any other value - in place of the current buffer."
   :group 'erc-buffers
   :type '(choice (const window)
                 (const window-noselect)
@@ -1424,7 +1479,7 @@ any other value - in place of the current buffer"
 
 (defcustom erc-frame-alist nil
   "*Alist of frame parameters for creating erc frames.
-A value of `nil means to use `default-frame-alist'."
+A value of nil means to use `default-frame-alist'."
   :group 'erc-buffers
   :type '(repeat (cons :format "%v"
                       (symbol :tag "Parameter")
@@ -1506,7 +1561,7 @@ symbol, it may have these values:
             (or target
                 (with-current-buffer (get-buffer buf-name)
                   (and (erc-server-buffer-p)
-                       (not erc-server-connected))))
+                       (not (erc-server-process-alive)))))
             (with-current-buffer (get-buffer buf-name)
               (and (string= erc-session-server server)
                    (erc-port-equal erc-session-port port))))
@@ -1527,7 +1582,8 @@ All strings are compared according to IRC protocol case rules, see
   (catch 'result
     (while list
       (if (string= string (erc-downcase (car list)))
-         (throw 'result list) (setq list (cdr list))))))
+         (throw 'result list)
+       (setq list (cdr list))))))
 
 (defmacro erc-with-buffer (spec &rest body)
   "Execute BODY in the buffer associated with SPEC.
@@ -1539,16 +1595,16 @@ SPEC should have the form
 If TARGET is a buffer, use it.  Otherwise, use the buffer
 matching TARGET in the process specified by PROCESS.
 
-If PROCESS is nil, use the current `erc-server-process'
+If PROCESS is nil, use the current `erc-server-process'.
 See `erc-get-buffer' for details.
 
 See also `with-current-buffer'.
 
 \(fn (TARGET [PROCESS]) BODY...)"
-  (let ((buf (erc-gensym))
-       (proc (erc-gensym))
-       (target (erc-gensym))
-       (process (erc-gensym)))
+  (let ((buf (make-symbol "buf"))
+       (proc (make-symbol "proc"))
+       (target (make-symbol "target"))
+       (process (make-symbol "process")))
     `(let* ((,target ,(car spec))
            (,process ,(cadr spec))
            (,buf (if (bufferp ,target)
@@ -1558,7 +1614,7 @@ See also `with-current-buffer'.
                                          erc-server-process))))
                      (if (and ,target ,proc)
                          (erc-get-buffer ,target ,proc))))))
-       (when ,buf
+       (when (buffer-live-p ,buf)
         (with-current-buffer ,buf
           ,@body)))))
 (put 'erc-with-buffer 'lisp-indent-function 1)
@@ -1588,12 +1644,13 @@ server connection, or nil which means all open connections."
     (delq
      nil
      (mapcar (lambda (buf)
-              (with-current-buffer buf
-                (and (eq major-mode 'erc-mode)
-                     (or (not proc)
-                         (eq proc erc-server-process))
-                     (funcall predicate)
-                     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))))
             (buffer-list)))))
 
 (defun erc-buffer-list (&optional predicate proc)
@@ -1612,8 +1669,8 @@ FORMS will be evaluated in all buffers having the process PROCESS and
 where PRED matches or in all buffers of the server process if PRED is
 nil."
   ;; Make the evaluation have the correct order
-  (let ((pre (erc-gensym))
-       (pro (erc-gensym)))
+  (let ((pre (make-symbol "pre"))
+       (pro (make-symbol "pro")))
     `(let ((,pro ,process)
           (,pre ,pred))
        (mapcar (lambda (buffer)
@@ -1636,21 +1693,24 @@ needs to be active for this function to work."
   (interactive "P")
   (eval-when-compile
     (require 'iswitchb))
-  (let ((iswitchb-make-buflist-hook
-        (lambda ()
-          (setq iswitchb-temp-buflist
-                (mapcar 'buffer-name
-                        (erc-buffer-list
-                         nil
-                         (when (and arg (boundp 'erc-server-process))
-                           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))))
+  (let ((enabled 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)))))
 
 (defun erc-channel-list (proc)
   "Return a list of channel buffers.
@@ -1693,7 +1753,10 @@ all channel buffers on all servers."
 (make-variable-buffer-local 'erc-invitation)
 
 (defvar erc-away nil
-  "Non-nil indicates that we are away.")
+  "Non-nil indicates that we are away.
+
+Use `erc-away-time' to access this if you might be in a channel
+buffer rather than a server buffer.")
 (make-variable-buffer-local 'erc-away)
 
 (defvar erc-channel-list nil
@@ -1716,13 +1779,25 @@ all channel buffers on all servers."
   "Used to keep track of how many times an attempt at changing nick is made.")
 (make-variable-buffer-local 'erc-nick-change-attempt-count)
 
-(defcustom erc-modules '(netsplit fill button match track pcomplete readonly
+(defun erc-migrate-modules (mods)
+  "Migrate old names of ERC modules to new ones."
+  ;; modify `transforms' to specify what needs to be changed
+  ;; each item is in the format '(old . new)
+  (let ((transforms '((pcomplete . completion))))
+    (erc-delete-dups
+     (mapcar (lambda (m) (or (cdr (assoc m transforms)) m))
+            mods))))
+
+(defcustom erc-modules '(netsplit fill button match track completion readonly
                                  ring autojoin noncommands irccontrols
-                                 stamp)
-  "A list of modules which erc should enable.
+                                 stamp menu)
+  "A list of modules which ERC should enable.
 If you set the value of this without using `customize' remember to call
 \(erc-update-modules) after you change it.  When using `customize', modules
 removed from the list will be disabled."
+  :get (lambda (sym)
+        ;; replace outdated names with their newer equivalents
+        (erc-migrate-modules (symbol-value sym)))
   :set (lambda (sym val)
         ;; disable modules which have just been removed
         (when (and (boundp 'erc-modules) erc-modules val)
@@ -1732,44 +1807,51 @@ removed from the list will be disabled."
                 (when (and (fboundp f) (boundp f) (symbol-value f))
                   (message "Disabling `erc-%s'" module)
                   (funcall f 0))))))
-        (set-default sym val)
+        (set sym val)
         ;; this test is for the case where erc hasn't been loaded yet
         (when (fboundp 'erc-update-modules)
           (erc-update-modules)))
-  :type '(set :greedy t
-             (const :tag "Set away status automatically" autoaway)
-             (const :tag "Join channels automatically" autojoin)
-             (const :tag "Integrate with Big Brother Database" bbdb)
-             (const :tag "Buttonize URLs, nicknames, and other text" button)
-             (const :tag "Wrap long lines" fill)
-             (const :tag "Highlight or remove IRC control characters"
-                    irccontrols)
-             (const :tag "Save buffers in logs" log)
-             (const :tag "Highlight pals, fools, and other keywords" match)
-             (const :tag "Detect netsplits" netsplit)
-             (const :tag "Don't display non-IRC commands after evaluation"
-                    noncommands)
-             (const :tag
-                    "Notify when the online status of certain users changes"
-                    notify)
-             (const :tag "Complete nicknames and commands (programmable)"
-                    pcomplete)
-             (const :tag "Complete nicknames and commands (old)" completion)
-             (const :tag "Make displayed lines read-only" readonly)
-             (const :tag "Replace text in messages" replace)
-             (const :tag "Enable an input history" ring)
-             (const :tag "Scroll to the bottom of the buffer" scrolltobottom)
-             (const :tag "Identify to Nickserv (IRC Services) automatically"
-                    services)
-             (const :tag "Convert smileys to pretty icons" smiley)
-             (const :tag "Play sounds when you receive CTCP SOUND requests"
-                    sound)
-             (const :tag "Add timestamps to messages" stamp)
-             (const :tag "Check spelling" spelling)
-             (const :tag "Track channel activity in the mode-line" track)
-             (const :tag "Truncate buffers to a certain size" truncate)
-             (const :tag "Translate morse code in messages" unmorse)
-             (repeat :tag "Others" :inline t symbol))
+  :type
+  '(set
+    :greedy t
+    (const :tag "autoaway: Set away status automatically" autoaway)
+    (const :tag "autojoin: Join channels automatically" autojoin)
+    (const :tag "button: Buttonize URLs, nicknames, and other text" button)
+    (const :tag "capab: Mark unidentified users on servers supporting CAPAB"
+          capab-identify)
+    (const :tag "completion: Complete nicknames and commands (programmable)"
+          completion)
+    (const :tag "hecomplete: Complete nicknames and commands (old)" hecomplete)
+    (const :tag "fill: Wrap long lines" fill)
+    (const :tag "identd: Launch an identd server on port 8113" identd)
+    (const :tag "irccontrols: Highlight or remove IRC control characters"
+          irccontrols)
+    (const :tag "log: Save buffers in logs" log)
+    (const :tag "match: Highlight pals, fools, and other keywords" match)
+    (const :tag "menu: Display a menu in ERC buffers" menu)
+    (const :tag "netsplit: Detect netsplits" netsplit)
+    (const :tag "noncommands: Don't display non-IRC commands after evaluation"
+          noncommands)
+    (const :tag
+          "notify: Notify when the online status of certain users changes"
+          notify)
+    (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)
+    (const :tag "ring: Enable an input history" ring)
+    (const :tag "scrolltobottom: Scroll to the bottom of the buffer"
+          scrolltobottom)
+    (const :tag "services: Identify to Nickserv (IRC Services) automatically"
+          services)
+    (const :tag "smiley: Convert smileys to pretty icons" smiley)
+    (const :tag "sound: Play sounds when you receive CTCP SOUND requests"
+          sound)
+    (const :tag "stamp: Add timestamps to messages" stamp)
+    (const :tag "spelling: Check spelling" spelling)
+    (const :tag "track: Track channel activity in the mode-line" track)
+    (const :tag "truncate: Truncate buffers to a certain size" truncate)
+    (const :tag "unmorse: Translate morse code in messages" unmorse)
+    (repeat :tag "Others" :inline t symbol))
   :group 'erc)
 
 (defun erc-update-modules ()
@@ -1779,18 +1861,21 @@ removed from the list will be disabled."
       (setq req (concat "erc-" (symbol-name mod)))
       (cond
        ;; yuck. perhaps we should bring the filenames into sync?
+       ((string= req "erc-capab-identify")
+       (setq req "erc-capab"))
        ((string= req "erc-completion")
-       (setq req "erc-pcomplete")
-       (setq mod 'pcomplete))
-       ((string= req "erc-services")
-       (setq req "erc-nickserv")
-       (setq mod 'services)))
+       (setq req "erc-pcomplete"))
+       ((string= req "erc-pcomplete")
+       (setq mod 'completion))
+       ((string= req "erc-autojoin")
+       (setq req "erc-join")))
       (condition-case nil
          (require (intern req))
        (error nil))
-      (funcall (or (intern-soft (concat "erc-" (symbol-name mod) "-mode"))
-                  (error "`%s' is not a known ERC module" mod))
-              1))))
+      (let ((sym (intern-soft (concat "erc-" (symbol-name mod) "-mode"))))
+       (if (fboundp sym)
+           (funcall sym 1)
+         (error "`%s' is not a known ERC module" mod))))))
 
 (defun erc-setup-buffer (buffer)
   "Consults `erc-join-buffer' to find out how to display `BUFFER'."
@@ -1816,11 +1901,9 @@ removed from the list will be disabled."
             (display-buffer buffer)
           (switch-to-buffer buffer)))))
 
-(defun erc (&optional server port nick full-name
-                     connect passwd tgt-list channel process)
-  "ERC is a powerful, modular, and extensible IRC client.
-
-Connect to SERVER on PORT as NICK with FULL-NAME.
+(defun erc-open (&optional server port nick full-name
+                          connect passwd tgt-list channel process)
+  "Connect to SERVER on PORT as NICK with FULL-NAME.
 
 If CONNECT is non-nil, connect to the server.  Otherwise assume
 already connected and just create a separate buffer for the new
@@ -1836,9 +1919,12 @@ Returns the buffer for the given server or channel."
        (connected-p (unless connect erc-server-connected))
        (buffer (erc-get-buffer-create server port channel))
        (old-buffer (current-buffer))
+       old-point
        continued-session)
+    (when connect (run-hook-with-args 'erc-before-connect server port nick))
     (erc-update-modules)
     (set-buffer buffer)
+    (setq old-point (point))
     (erc-mode)
     (setq erc-server-announced-name server-announced-name)
     (setq erc-server-connected connected-p)
@@ -1882,10 +1968,6 @@ Returns the buffer for the given server or channel."
     (erc-set-active-buffer buffer)
     ;; last invitation channel
     (setq erc-invitation nil)
-    ;; away flag
-    ;; Should only be used in session-buffers
-    (setq erc-away (let ((serverbuf (erc-server-buffer)))
-                    (and serverbuf (with-current-buffer serverbuf erc-away))))
     ;; Server channel list
     (setq erc-channel-list ())
     ;; login-time 'nick in use' error
@@ -1900,24 +1982,25 @@ Returns the buffer for the given server or channel."
     (setq erc-dbuf
          (when erc-log-p
            (get-buffer-create (concat "*ERC-DEBUG: " server "*"))))
-    (erc-determine-parameters server port nick full-name)
-
-    ;; Saving log file on exit
-    (run-hooks 'erc-connect-pre-hook)
-
-    (when connect
-      (erc-server-connect erc-session-server erc-session-port))
-    (erc-update-mode-line)
-    (set-marker erc-insert-marker (point))
+    ;; set up prompt
     (unless continued-session
       (goto-char (point-max))
       (insert "\n"))
-    (set-marker (process-mark erc-server-process) (point))
-    (unless continued-session
+    (if continued-session
+       (goto-char old-point)
       (set-marker erc-insert-marker (point))
       (erc-display-prompt)
       (goto-char (point-max)))
 
+    (erc-determine-parameters server port nick full-name)
+
+    ;; Saving log file on exit
+    (run-hook-with-args 'erc-connect-pre-hook buffer)
+
+    (when connect
+      (erc-server-connect erc-session-server erc-session-port buffer))
+    (erc-update-mode-line)
+
     ;; Now display the buffer in a window as per user wishes.
     (unless (eq buffer old-buffer)
       (when erc-log-p
@@ -1928,11 +2011,13 @@ Returns the buffer for the given server or channel."
 
     buffer))
 
-(defun erc-initialize-log-marker ()
-  "Initialize the `erc-last-saved-position' marker to a sensible position."
+(defun erc-initialize-log-marker (buffer)
+  "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))))
+                (1- (marker-position erc-insert-marker)))))
 
 ;; interactive startup
 
@@ -1956,12 +2041,12 @@ If no buffer matches, return nil."
 
 (if (not (fboundp 'read-passwd))
     (defun read-passwd (prompt)
-      "Substitute for read-passwd in early emacsen"
+      "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-select' actually invokes `erc-mode'
+This hook gets executed before `erc' actually invokes `erc-mode'
 with your input data.  The functions in here get called with three
 parameters, SERVER, PORT and NICK."
   :group 'erc-hooks
@@ -1969,7 +2054,7 @@ parameters, SERVER, PORT and NICK."
 
 (defcustom erc-after-connect nil
   "Hook called after connecting to a server.
-This hook gets executed when an end of MOTD has been received. All
+This hook gets executed when an end of MOTD has been received.  All
 functions in here get called with the parameters SERVER and NICK."
   :group 'erc-hooks
   :type 'hook)
@@ -2027,13 +2112,17 @@ functions in here get called with the parameters SERVER and NICK."
     (list :server server :port port :nick nick :password passwd)))
 
 ;;;###autoload
-(defun* erc-select (&key (server (erc-compute-server))
-                        (port   (erc-compute-port))
-                        (nick   (erc-compute-nick))
-                        password
-                        (full-name (erc-compute-full-name)))
-  "Select connection parameters and run ERC.
-Non-interactively, it takes keyword arguments
+(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.
+
+It permits you to select connection parameters, and then starts ERC.
+
+Non-interactively, it takes the keyword arguments
    (server (erc-compute-server))
    (port   (erc-compute-port))
    (nick   (erc-compute-nick))
@@ -2041,34 +2130,39 @@ Non-interactively, it takes keyword arguments
    (full-name (erc-compute-full-name)))
 
 That is, if called with
-   (erc-select :server \"irc.freenode.net\" :full-name \"Harry S Truman\")
-server and full-name will be set to those values, whereas
-erc-compute-port, erc-compute-nick and erc-compute-full-name will
-be invoked for those parameters' values"
-  (interactive (erc-select-read-args))
 
-  (run-hook-with-args 'erc-before-connect server port nick)
-  (erc server port nick erc-user-full-name t password))
+   (erc :server \"irc.freenode.net\" :full-name \"Harry S Truman\")
+
+then the server and full-name will be set to those values, whereas
+`erc-compute-port', `erc-compute-nick' and `erc-compute-full-name' will
+be invoked for the values of the other parameters."
+  (interactive (erc-select-read-args))
+  (erc-open server port nick full-name t password))
 
+;;;###autoload
+(defalias 'erc-select 'erc)
 
-(defun erc-select-ssl (&rest r)
+(defun erc-ssl (&rest r)
   "Interactively select SSL connection parameters and run ERC.
-Arguments are as to erc-select."
+Arguments are the same as for `erc'."
   (interactive (erc-select-read-args))
   (let ((erc-server-connect-function 'erc-open-ssl-stream))
-    (apply 'erc-select r)))
+    (apply 'erc r)))
+
+(defalias 'erc-select-ssl 'erc-ssl)
 
 (defun erc-open-ssl-stream (name buffer host port)
   "Open an SSL 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."
-  (when (require 'ssl)
-    (let ((proc (open-ssl-stream name buffer host port)))
+BUFFER.  HOST and PORT specify the connection target."
+  (when (require 'tls)
+    (let ((proc (open-tls-stream name buffer host port)))
       ;; Ugly hack, but it works for now. Problem is it is
       ;; very hard to detect when ssl is established, because s_client
       ;; doesn't give any CONNECTIONESTABLISHED kind of message, and
       ;; most IRC servers send nothing and wait for you to identify.
-      (sit-for 5)
+      ;; Disabled when switching to tls.el -- jas
+      ;(sit-for 5)
       proc)))
 
 ;;; Debugging the protocol
@@ -2078,7 +2172,7 @@ BUFFER.    HOST and PORT specify the connection target."
 
 The buffer is created if it doesn't exist.
 
-NOTE: If this variable is non-nil, and you kill the the only
+NOTE: If this variable is non-nil, and you kill the only
 visible \"*erc-protocol*\" buffer, it will be recreated shortly,
 but you won't see it.
 
@@ -2093,7 +2187,7 @@ This only has any effect if `erc-debug-irc-protocol' is non-nil.
 The buffer is created if it doesn't exist.
 
 If OUTBOUND is non-nil, STRING is being sent to the IRC server
-and appears in erc-input-face in the buffer."
+and appears in face `erc-input-face' in the buffer."
   (when erc-debug-irc-protocol
     (let ((network-name (or (ignore-errors (erc-network-name))
                            "???")))
@@ -2177,7 +2271,7 @@ I.e. any char in it has the `invisible' property set."
 
 (defun erc-display-line-1 (string buffer)
   "Display STRING in `erc-mode' BUFFER.
-Auxiliary function used in `erc-display-line'. The line gets filtered to
+Auxiliary function used in `erc-display-line'.  The line gets filtered to
 interpret the control characters.  Then, `erc-insert-pre-hook' gets called.
 If `erc-insert-this' is still t, STRING gets inserted into the buffer.
 Afterwards, `erc-insert-modify' and `erc-insert-post-hook' get called.
@@ -2261,8 +2355,8 @@ or omitted, the default ERC buffer for the `erc-session-server' is used.
 The BUFFER can be an actual buffer, a list of buffers, 'all or 'active.
 If BUFFER = 'all, the string is displayed in all the ERC buffers for the
 current session.  'active means the current active buffer
-\(`erc-active-buffer').         If the buffer can't be resolved, the current
-buffer is used.         `erc-display-line-1' is used to display STRING.
+\(`erc-active-buffer').  If the buffer can't be resolved, the current
+buffer is used.  `erc-display-line-1' is used to display STRING.
 
 If STRING is nil, the function does nothing."
   (let ((inhibit-point-motion-hooks t)
@@ -2272,9 +2366,8 @@ If STRING is nil, the function does nothing."
                  ((listp buffer) buffer)
                  ((processp buffer) (list (process-buffer buffer)))
                  ((eq 'all buffer)
-                  (and (boundp 'erc-server-process)
-                       ;; Hmm, or all of the same session server?
-                       (erc-buffer-list nil erc-server-process)))
+                  ;; Hmm, or all of the same session server?
+                  (erc-buffer-list nil erc-server-process))
                  ((and (eq 'active buffer) (erc-active-buffer))
                   (list (erc-active-buffer)))
                  ((erc-server-buffer-live-p)
@@ -2289,9 +2382,9 @@ If STRING is nil, the function does nothing."
        (erc-display-line-1 string (current-buffer))))))
 
 (defun erc-display-message-highlight (type string)
-  "Highlight STRING according to TYPE, where erc-TYPE-face is an erc face.
+  "Highlight STRING according to TYPE, where erc-TYPE-face is an ERC face.
 
-See also `erc-make-notice'"
+See also `erc-make-notice'."
   (cond ((eq type 'notice)
         (erc-make-notice string))
        (t
@@ -2314,6 +2407,8 @@ See also `erc-format-message' and `erc-display-line'."
                  msg)))
     (setq string
          (cond
+          ((null type)
+           string)
           ((listp type)
            (mapc (lambda (type)
                    (setq string
@@ -2326,7 +2421,7 @@ See also `erc-format-message' and `erc-display-line'."
     (if (not (erc-response-p parsed))
        (erc-display-line string buffer)
       (unless (member (erc-response.command parsed) erc-hide-list)
-      (erc-put-text-property 0 (length string) 'erc-parsed parsed string)
+       (erc-put-text-property 0 (length string) 'erc-parsed parsed string)
        (erc-put-text-property 0 (length string) 'rear-sticky t string)
        (erc-display-line string buffer)))))
 
@@ -2335,7 +2430,7 @@ See also `erc-format-message' and `erc-display-line'."
 
 This function relies on the erc-parsed text-property being
 present."
-  (let ((prop-val (get-text-property position 'erc-parsed)))
+  (let ((prop-val (erc-get-parsed-vector position)))
     (and prop-val (member (erc-response.command prop-val) list))))
 
 (defvar erc-send-input-line-function 'erc-send-input-line)
@@ -2375,7 +2470,7 @@ Returns non-nil if the command is actually sent to the server, and nil
 otherwise.
 
 If the command in the LINE is not bound as a function `erc-cmd-<COMMAND>',
-it is passed to `erc-cmd-default'.  If LINE is not a command (ie. doesn't
+it is passed to `erc-cmd-default'.  If LINE is not a command (i.e. doesn't
 start with /<COMMAND>) then it is sent as a message.
 
 An optional FORCE argument forces sending the line when flood
@@ -2485,34 +2580,43 @@ therefore has to contain the command itself as well."
   "Ignore USER.  This should be a regexp matching nick!user@host.
 If no USER argument is specified, list the contents of `erc-ignore-list'."
   (if user
-      (progn
+      (let ((quoted (regexp-quote user)))
+       (when (and (not (string= user quoted))
+                  (y-or-n-p (format "Use regexp-quoted form (%s) instead? "
+                                    quoted)))
+         (setq user quoted))
        (erc-display-line
         (erc-make-notice (format "Now ignoring %s" user))
         'active)
-       (with-current-buffer (erc-server-buffer)
-         (add-to-list 'erc-ignore-list user)))
-    (if (null (with-current-buffer (erc-server-buffer) erc-ignore-list))
+       (erc-with-server-buffer (add-to-list 'erc-ignore-list user)))
+    (if (null (erc-with-server-buffer erc-ignore-list))
        (erc-display-line (erc-make-notice "Ignore list is empty") 'active)
       (erc-display-line (erc-make-notice "Ignore list:") 'active)
       (mapc #'(lambda (item)
                (erc-display-line (erc-make-notice item)
                                  'active))
-           (with-current-buffer (erc-server-buffer) erc-ignore-list))))
+           (erc-with-server-buffer erc-ignore-list))))
   t)
 
 (defun erc-cmd-UNIGNORE (user)
   "Remove the user specified in USER from the ignore list."
-  (let ((ignored-nick (car (with-current-buffer (erc-server-buffer)
-                            (erc-member-ignore-case user erc-ignore-list)))))
-    (if (null ignored-nick)
+  (let ((ignored-nick (car (erc-with-server-buffer
+                            (erc-member-ignore-case (regexp-quote user)
+                                                    erc-ignore-list)))))
+    (unless ignored-nick
+      (if (setq ignored-nick (erc-ignored-user-p user))
+         (unless (y-or-n-p (format "Remove this regexp (%s)? "
+                                   ignored-nick))
+           (setq ignored-nick nil))
        (erc-display-line
         (erc-make-notice (format "%s is not currently ignored!" user))
-        'active)
+        'active)))
+    (when ignored-nick
       (erc-display-line
        (erc-make-notice (format "No longer ignoring %s" user))
-       'active))
-    (with-current-buffer (erc-server-buffer)
-      (setq erc-ignore-list (delete ignored-nick erc-ignore-list))))
+       'active)
+      (erc-with-server-buffer
+       (setq erc-ignore-list (delete ignored-nick erc-ignore-list)))))
   t)
 
 (defun erc-cmd-CLEAR ()
@@ -2570,8 +2674,8 @@ If no reason is given, unset away status."
   "Mark the user as being away everywhere, the reason being indicated by LINE."
   ;; on all server buffers.
   (erc-with-all-buffers-of-server nil
-   #'erc-server-buffer-p
-   (erc-cmd-AWAY line)))
+    #'erc-open-server-buffer-p
+    (erc-cmd-AWAY line)))
 (put 'erc-cmd-GAWAY 'do-not-parse-args t)
 
 (defun erc-cmd-CTCP (nick cmd &rest args)
@@ -2591,7 +2695,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 commands.  Otherwise, do `apropos' in the ERC namespace
 \(\"erc-.*LINE\"\).
 
 Examples:
@@ -2717,9 +2821,9 @@ LINE has the format: \"#CHANNEL NICK REASON\" or \"NICK REASON\"."
 
 (defun erc-cmd-LOAD (line)
   "Load the script provided in the LINE.
-If LINE continues beyond the file name,
-the rest of it is put in a (local) variable
-`erc-script-args', which can be used in elisp scripts.
+If LINE continues beyond the file name, the rest of
+it is put in a (local) variable `erc-script-args',
+which can be used in Emacs Lisp scripts.
 
 The optional FORCE argument is ignored here - you can't force loading
 a script after exceeding the flood threshold."
@@ -2763,10 +2867,9 @@ If SERVER is non-nil, use that, rather than the current server."
 
 (defun erc-cmd-IDLE (nick)
   "Show the length of time NICK has been idle."
-  (let ((serverbuf (erc-server-buffer))
-       (origbuf (current-buffer))
+  (let ((origbuf (current-buffer))
        symlist)
-    (with-current-buffer serverbuf
+    (erc-with-server-buffer
       (add-to-list 'symlist
                   (cons (erc-once-with-server-event
                          311 `(string= ,nick
@@ -2924,8 +3027,8 @@ The rest of LINE is the message to send."
 (defun erc-cmd-NICK (nick)
   "Change current nickname to NICK."
   (erc-log (format "cmd: NICK: %s (erc-bad-nick: %S)" nick erc-bad-nick))
-  (let ((nicklen (cdr (assoc "NICKLEN" (with-current-buffer (erc-server-buffer)
-                                   erc-server-parameters)))))
+  (let ((nicklen (cdr (assoc "NICKLEN" (erc-with-server-buffer
+                                        erc-server-parameters)))))
     (and nicklen (> (length nick) (string-to-number nicklen))
         (erc-display-message
          nil 'notice 'active 'nick-too-long
@@ -2980,7 +3083,7 @@ Otherwise leave the channel indicated by LINE."
 All the text given as argument is sent to the sever as unmodified,
 just as you provided it.  Use this command with care!"
   (cond
-   ((string-match "^\\s-\\(.+\\)$" line)
+   ((string-match "^ ?\\(.+\\)$" line)
     (erc-server-send (match-string 1 line)))
    (t nil)))
 (put 'erc-cmd-QUOTE 'do-not-parse-args t)
@@ -3024,8 +3127,8 @@ If S is non-nil, it will be used as the quit reason."
     (cond
      ((functionp res) (funcall res))
      ((stringp res) res)
-     ;; hopefully never reached
-     (s))))
+     (s s)
+     (t (erc-quit-reason-normal)))))
 
 (defun erc-part-reason-normal (&optional s)
   "Normal part message.
@@ -3051,7 +3154,8 @@ If S is non-nil, it will be used as the quit reason."
     (cond
      ((functionp res) (funcall res))
      ((stringp res) res)
-     (s))))
+     (s s)
+     (t (erc-part-reason-normal)))))
 
 (defun erc-cmd-QUIT (reason)
   "Disconnect from the current server.
@@ -3063,7 +3167,8 @@ the message given by REASON."
    ((string-match "^\\s-*\\(.*\\)$" reason)
     (let* ((s (match-string 1 reason))
           (buffer (erc-server-buffer))
-          (reason (funcall erc-quit-reason (if (equal s "") nil s))))
+          (reason (funcall erc-quit-reason (if (equal s "") nil s)))
+          server-proc)
       (with-current-buffer (if (and buffer
                                    (bufferp buffer))
                               buffer
@@ -3071,10 +3176,18 @@ the message given by REASON."
        (erc-log (format "cmd: QUIT: %s" reason))
        (setq erc-server-quitting t)
        (erc-set-active-buffer (erc-server-buffer))
+       (setq server-proc erc-server-process)
        (erc-server-send (format "QUIT :%s" reason)))
-      (run-hook-with-args 'erc-quit-hook erc-server-process)
+      (run-hook-with-args 'erc-quit-hook server-proc)
       (when erc-kill-queries-on-quit
-       (erc-kill-query-buffers erc-server-process)))
+       (erc-kill-query-buffers server-proc))
+      ;; if the process has not been killed within 4 seconds, kill it
+      (run-at-time 4 nil
+                  (lambda (proc)
+                    (when (and (processp proc)
+                               (memq (process-status proc) '(run open)))
+                      (delete-process proc)))
+                  server-proc))
     t)
    (t nil)))
 
@@ -3085,19 +3198,32 @@ the message given by REASON."
 
 (defun erc-cmd-GQUIT (reason)
   "Disconnect from all servers at once with the same quit REASON."
-  (erc-with-all-buffers-of-server nil #'(lambda ()
-                                         (and (erc-server-buffer-p)
-                                              (erc-server-process-alive)))
+  (erc-with-all-buffers-of-server nil #'erc-open-server-buffer-p
                                  (erc-cmd-QUIT reason)))
 
 (defalias 'erc-cmd-GQ 'erc-cmd-GQUIT)
 (put 'erc-cmd-GQUIT 'do-not-parse-args t)
 
+(defun erc-cmd-RECONNECT ()
+  "Try to reconnect to the current IRC server."
+  (let ((buffer (or (erc-server-buffer) (current-buffer)))
+       (process nil))
+    (with-current-buffer (if (bufferp buffer) buffer (current-buffer))
+      (setq erc-server-quitting nil)
+      (setq erc-server-reconnecting t)
+      (setq erc-server-reconnect-count 0)
+      (setq process (get-buffer-process (erc-server-buffer)))
+      (if process
+         (delete-process process)
+       (erc-server-reconnect))
+      (setq erc-server-reconnecting nil)))
+  t)
+
 (defun erc-cmd-SERVER (server)
   "Connect to SERVER, leaving existing connection intact."
   (erc-log (format "cmd: SERVER: %s" server))
   (condition-case nil
-      (erc-select :server server :nick (erc-current-nick))
+      (erc :server server :nick (erc-current-nick))
     (error
      (message "Cannot find host %s." server)
      (beep)))
@@ -3109,7 +3235,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%s)!"
+  (erc-send-message (format "I'm using ERC %s with %s %s (%s%s) of %s."
                            erc-version-string
                            (if (featurep 'xemacs) "XEmacs" "GNU Emacs")
                            emacs-version
@@ -3132,7 +3258,7 @@ the message given by REASON."
                                                      x-toolkit-scroll-bars)))
                               "")
                             (if (featurep 'multi-tty) ", multi-tty" ""))
-                           (concat ", built " erc-emacs-build-time)))
+                           erc-emacs-build-time))
   t)
 
 (defun erc-cmd-SM ()
@@ -3141,12 +3267,6 @@ the message given by REASON."
                            (erc-modes)))
   t)
 
-(defun erc-cmd-SMV ()
-  "Say the current ERC module versions into channel."
-  (erc-send-message (format "I'm using the following module revisions: %s!"
-                           (erc-version-modules)))
-  t)
-
 (defun erc-cmd-DEOP (&rest people)
   "Remove the operator setting from user(s) given in PEOPLE."
   (when (> (length people) 0)
@@ -3269,7 +3389,7 @@ The ban list is fetched from the server if necessary."
        (setq erc-server-367-functions 'erc-banlist-store
              erc-channel-banlist nil)
        ;; fetch the ban list then callback
-       (with-current-buffer (erc-server-buffer)
+       (erc-with-server-buffer
          (erc-once-with-server-event
           368
           `(with-current-buffer ,chnl-name
@@ -3291,7 +3411,7 @@ The ban list is fetched from the server if necessary."
                                  (and (boundp 'fill-column)
                                       fill-column)
                                  (1- (window-width))))
-            (separator (make-string erc-fill-column (string-to-char "=")))
+            (separator (make-string erc-fill-column ?=))
             (fmt (concat
                   "%-" (number-to-string (/ erc-fill-column 2)) "s"
                   "%" (number-to-string (/ erc-fill-column 2)) "s")))
@@ -3339,7 +3459,7 @@ Unban all currently banned users in the current channel."
       (let ((old-367-hook erc-server-367-functions))
        (setq erc-server-367-functions 'erc-banlist-store)
       ;; fetch the ban list then callback
-      (with-current-buffer (erc-server-buffer)
+      (erc-with-server-buffer
        (erc-once-with-server-event
         368
         `(with-current-buffer ,chnl
@@ -3357,7 +3477,7 @@ Unban all currently banned users in the current channel."
        (lambda (x)
         (erc-server-send
          (format "MODE %s -%s %s" (erc-default-target)
-                 (make-string (length x) (string-to-char "b"))
+                 (make-string (length x) ?b)
                        (mapconcat 'identity x " "))))
        (erc-group-list bans 3))))
        t))))
@@ -3473,7 +3593,7 @@ If FACE is non-nil, it will be used to propertize the prompt.  If it is nil,
 If `point' is at the beginning of a channel name, use that as default."
   (interactive
    (list
-    (let ((chnl (if (looking-at "\\([&#+!][^ ]+\\)") (match-string 1) ""))
+    (let ((chnl (if (looking-at "\\([&#+!][^ \n]+\\)") (match-string 1) ""))
          (table (when (erc-server-buffer-live-p)
                   (set-buffer (process-buffer erc-server-process))
                   erc-channel-list)))
@@ -3488,9 +3608,8 @@ If `point' is at the beginning of a channel name, use that as default."
    (list
     (if (and (boundp 'reason) (stringp reason) (not (string= reason "")))
        reason
-      (read-from-minibuffer (concat "Leave " (erc-default-target)
-                                   ", Reason? ")
-                           (cons "No reason" 0)))))
+      (read-from-minibuffer (concat "Reason for leaving " (erc-default-target)
+                                   ": ")))))
   (erc-cmd-PART (concat (erc-default-target)" " reason)))
 
 (defun erc-set-topic (topic)
@@ -3620,21 +3739,21 @@ To change how this query window is displayed, use `let' to bind
               (buffer-live-p server)
               (set-buffer server))
     (error "Couldn't switch to server buffer"))
-  (let ((buf (erc erc-session-server
-                 erc-session-port
-                 (erc-current-nick)
-                 erc-session-user-full-name
-                 nil
-                 nil
-                 (list target)
-                 target
-                 erc-server-process)))
+  (let ((buf (erc-open erc-session-server
+                      erc-session-port
+                      (erc-current-nick)
+                      erc-session-user-full-name
+                      nil
+                      nil
+                      (list target)
+                      target
+                      erc-server-process)))
     (unless buf
       (error "Couldn't open query window"))
     (erc-update-mode-line)
     buf))
 
-(defcustom erc-auto-query nil
+(defcustom erc-auto-query 'bury
   "If non-nil, create a query buffer each time you receive a private message.
 
 If the buffer doesn't already exist it is created.  This can be
@@ -3696,7 +3815,7 @@ E.g. \"Read error to Nick [user@some.host]: 110\" would be shortened to
   "If NICK is unavailable, tell the user the REASON.
 
 See also `erc-display-error-notice'."
-  (if (or erc-manual-set-nick-on-bad-nick-p
+  (if (or (not erc-try-new-nick-p)
          ;; how many default-nicks are left + one more try...
          (eq erc-nick-change-attempt-count
              (if (consp erc-nick)
@@ -3708,7 +3827,7 @@ See also `erc-display-error-notice'."
     (setq erc-nick-change-attempt-count (+ erc-nick-change-attempt-count 1))
     (let ((newnick (nth 1 erc-default-nicks))
          (nicklen (cdr (assoc "NICKLEN"
-                              (with-current-buffer (erc-server-buffer)
+                              (erc-with-server-buffer
                                 erc-server-parameters)))))
       (setq erc-bad-nick t)
       ;; try to use a different nick
@@ -3718,12 +3837,13 @@ See also `erc-display-error-notice'."
          (setq newnick (concat (truncate-string-to-width
                                 nick
                                 (if (and erc-server-connected nicklen)
-                                    (- (string-to-number nicklen) 1)
+                                    (- (string-to-number nicklen)
+                                       (length erc-nick-uniquifier))
                                   ;; rfc2812 max nick length = 9
                                   ;; we must assume this is the
                                   ;; server's setting if we haven't
                                   ;; established a connection yet
-                                  8))
+                                  (- 9 (length erc-nick-uniquifier))))
                                erc-nick-uniquifier)))
       (erc-cmd-NICK newnick)
       (erc-display-error-notice
@@ -3735,7 +3855,7 @@ See also `erc-display-error-notice'."
 
 (defgroup erc-server-hooks nil
   "Server event callbacks.
-Every server event - like numeric replies - has it's own hook.
+Every server event - like numeric replies - has its own hook.
 Those hooks are all called using `run-hook-with-args-until-success'.
 They receive as first argument the process object from where the event
 originated from,
@@ -3799,32 +3919,29 @@ and as second argument the event parsed as a vector."
   :type 'function)
 
 (defun erc-format-nick (&optional user channel-data)
-  "Standard nickname formatting function.  Only returns the value
-of NICK."
-  (if user
-      (erc-server-user-nickname user)))
+  "Return the nickname of USER.
+See also `erc-format-nick-function'."
+  (when user (erc-server-user-nickname user)))
 
 (defun erc-format-@nick (&optional user channel-data)
-  "Format a nickname such that @ or + are prefix for the NICK
-if OP or VOICE are t respectively."
-  (if user
-      (let (op voice)
-       (if channel-data
-           (setq op (erc-channel-user-op channel-data)
-                 voice (erc-channel-user-voice channel-data)))
-    (concat (if voice "+" "")
-           (if op "@" "")
-               (erc-server-user-nickname user)))))
+  "Format the nickname of USER showing if USER is an operator or has voice.
+Operators have \"@\" and users with voice have \"+\" as a prefix.
+Use CHANNEL-DATA to determine op and voice status.
+See also `erc-format-nick-function'."
+  (when user
+    (let ((op (and channel-data (erc-channel-user-op channel-data) "@"))
+         (voice (and channel-data (erc-channel-user-voice channel-data) "+")))
+      (concat voice op (erc-server-user-nickname user)))))
 
 (defun erc-format-my-nick ()
-  "Return the beginning of this user's message, correctly propertized"
+  "Return the beginning of this user's message, correctly propertized."
   (if erc-show-my-nick
       (let ((open "<")
            (close "> ")
            (nick (erc-current-nick)))
        (concat
         (erc-propertize open 'face 'erc-default-face)
-        (erc-propertize nick 'face 'erc-nick-default-face)
+        (erc-propertize nick 'face 'erc-my-nick-face)
         (erc-propertize close 'face 'erc-default-face)))
     (let ((prefix "> "))
       (erc-propertize prefix 'face 'erc-default-face))))
@@ -3841,7 +3958,7 @@ and always returns t."
 (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 iff BUFFER
+or `erc-echo-notice-always-hook', and returns non-nil if BUFFER
 is non-nil."
   (if buffer
       (progn (erc-display-message parsed nil buffer s) t)
@@ -3865,7 +3982,7 @@ designed to be added to either `erc-echo-notice-hook' or
   "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
-`erc-echo-notice-always-hook', and returns non-nil iff the active
+`erc-echo-notice-always-hook', and returns non-nil if the active
 buffer is not the server buffer."
   (if (not (eq (erc-server-buffer) (erc-active-buffer)))
       (progn (erc-display-message parsed nil 'active s) t)
@@ -3882,11 +3999,11 @@ designed to be added to either `erc-echo-notice-hook' or
   "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
-returns non-nil iff there is at least one buffer for which the
+returns non-nil if there is at least one buffer for which the
 sender is a member.
 
 See also: `erc-echo-notice-in-first-user-buffer',
-`erc-buffer-list-with-nick'"
+`erc-buffer-list-with-nick'."
   (let ((buffers (erc-buffer-list-with-nick sender erc-server-process)))
     (if buffers
        (progn (erc-display-message parsed nil buffers s) t)
@@ -3896,12 +4013,12 @@ See also: `erc-echo-notice-in-first-user-buffer',
   "Echos a private notice in BUFFER and 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 returns non-nil iff there is
+`erc-echo-notice-always-hook', and returns non-nil if there is
 at least one buffer for which the sender is a member or the
 default target.
 
 See also: `erc-echo-notice-in-user-buffers',
-`erc-buffer-list-with-nick'"
+`erc-buffer-list-with-nick'."
   (let ((buffers (erc-buffer-list-with-nick sender erc-server-process)))
     (add-to-list 'buffers buffer)
     (if buffers
@@ -3912,11 +4029,11 @@ See also: `erc-echo-notice-in-user-buffers',
   "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
-returns non-nil iff there is at least one buffer for which the
+returns non-nil if there is at least one buffer for which the
 sender is a member.
 
 See also: `erc-echo-notice-in-user-buffers',
-`erc-buffer-list-with-nick'"
+`erc-buffer-list-with-nick'."
   (let ((buffers (erc-buffer-list-with-nick sender erc-server-process)))
     (if buffers
        (progn (erc-display-message parsed nil (car buffers) s) t)
@@ -3999,25 +4116,30 @@ See also: `erc-echo-notice-in-user-buffers',
 (defun erc-connection-established (proc parsed)
   "Run just after connection.
 
-Set user modes and run `erc-after-connect hook'."
-  (unless erc-server-connected ; only once per session
-    (let ((server (or erc-server-announced-name (erc-response.sender parsed)))
-         (nick (car (erc-response.command-args parsed ))))
-      (setq erc-server-connected t)
-      (erc-update-mode-line)
-      (erc-set-initial-user-mode nick)
-      (erc-server-setup-periodical-server-ping)
-      (run-hook-with-args 'erc-after-connect server nick))))
-
-(defun erc-set-initial-user-mode (nick)
-  "If `erc-user-mode' is non-nil for NICK, set the user modes."
-  (when erc-user-mode
-    (let ((mode (if (functionp erc-user-mode)
-                   (funcall erc-user-mode)
-                 erc-user-mode)))
-      (when (stringp mode)
-       (erc-log (format "changing mode for %s to %s" nick mode))
-       (erc-server-send (format "MODE %s %s" nick mode))))))
+Set user modes and run `erc-after-connect' hook."
+  (with-current-buffer (process-buffer proc)
+    (unless erc-server-connected ; only once per session
+      (let ((server (or erc-server-announced-name
+                       (erc-response.sender parsed)))
+           (nick (car (erc-response.command-args parsed)))
+           (buffer (process-buffer proc)))
+       (setq erc-server-connected t)
+       (erc-update-mode-line)
+       (erc-set-initial-user-mode nick buffer)
+       (erc-server-setup-periodical-ping buffer)
+       (run-hook-with-args 'erc-after-connect server nick)))))
+
+(defun erc-set-initial-user-mode (nick buffer)
+  "If `erc-user-mode' is non-nil for NICK, set the user modes.
+The server buffer is given by BUFFER."
+  (with-current-buffer buffer
+    (when erc-user-mode
+      (let ((mode (if (functionp erc-user-mode)
+                     (funcall erc-user-mode)
+                   erc-user-mode)))
+       (when (stringp mode)
+         (erc-log (format "changing mode for %s to %s" nick mode))
+         (erc-server-send (format "MODE %s %s" nick mode)))))))
 
 (defun erc-display-error-notice (parsed string)
   "Display STRING as an error notice.
@@ -4229,8 +4351,10 @@ See also `erc-display-message'."
   nil)
 
 (defun erc-process-away (proc away-p)
-  ;; FIXME: This docstring is AWFUL -- Lawrence 2004-01-08
-  "Process the user being away, or returning from an away break."
+  "Toggle the away status of the user depending on the value of AWAY-P.
+
+If nil, set the user as away.
+If non-nil, return from being away."
   (let ((sessionbuf (process-buffer proc)))
     (when sessionbuf
       (with-current-buffer sessionbuf
@@ -4242,14 +4366,12 @@ See also `erc-display-message'."
                          erc-nick)))
        (cond
         (away-p
-         (erc-with-all-buffers-of-server proc nil
-                                         (setq erc-away (current-time))))
+         (setq erc-away (current-time)))
         (t
          (let ((away-time erc-away))
            ;; away must be set to NIL BEFORE sending anything to prevent
            ;; an infinite recursion
-           (erc-with-all-buffers-of-server proc nil
-                                           (setq erc-away nil))
+           (setq erc-away nil)
            (save-excursion
              (set-buffer (erc-active-buffer))
              (when erc-public-away-p
@@ -4329,7 +4451,7 @@ The buffer where the change happened is current while this hook is called."
   "Updates the stored user information for the user with nickname
 NICK.
 
-See also: `erc-update-user'"
+See also: `erc-update-user'."
   (erc-update-user (erc-get-server-user nick) new-nick
                   host login full-name info))
 
@@ -4340,9 +4462,9 @@ struct.  Any of NEW-NICK, HOST, LOGIN, FULL-NAME, INFO which are
 non-nil and not equal to the existing values for USER are used to
 replace the stored values in USER.
 
-If, any only if a change is made,
+If, and only if, a change is made,
 `erc-channel-members-changed-hook' is run for each channel for
-which USER is a member, and `t' is returned."
+which USER is a member, and t is returned."
   (let (changed)
     (when user
       (when (and new-nick
@@ -4379,10 +4501,10 @@ which USER is a member, and `t' is returned."
        update-message-time)
   "Updates 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 USER in the current channel
-is changed accordingly.  If `update-message-time' is non-nil, the
+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
+changed accordingly.  If UPDATE-MESSAGE-TIME is non-nil, the
 last-message-time of the user in the current channel is set
 to (current-time).
 
@@ -4391,7 +4513,7 @@ information if it is not already present in the user or channel
 lists.
 
 If, and only if, changes are made, or the user is added,
-`erc-channel-members-updated-hook' is run, and `t' is returned.
+`erc-channel-members-updated-hook' is run, and t is returned.
 
 See also: `erc-update-user' and `erc-update-channel-member'."
   (let* (changed user-changed
@@ -4457,7 +4579,7 @@ See also: `erc-update-user' and `erc-update-channel-member'."
   "Updates user and channel information for the user with
 nickname NICK in channel CHANNEL.
 
-See also: `erc-update-current-channel-member'"
+See also: `erc-update-current-channel-member'."
   (erc-with-buffer
    (channel)
    (erc-update-current-channel-member nick new-nick add op voice host
@@ -4465,8 +4587,8 @@ See also: `erc-update-current-channel-member'"
                                      update-message-time)))
 
 (defun erc-remove-current-channel-member (nick)
-  "Remove NICK from current channel membership list.  Runs
-`erc-channel-members-changed-hook'."
+  "Remove NICK from current channel membership list.
+Runs `erc-channel-members-changed-hook'."
   (let ((channel-data (erc-get-channel-user nick)))
     (when channel-data
       (erc-remove-channel-user nick)
@@ -4501,7 +4623,7 @@ TOPIC string to the current topic."
         ;; list of triples: (mode-char 'on/'off argument)
         (arg-modes (nth 2 modes)))
     (cond ((erc-channel-p tgt); channel modes
-          (let ((buf (and (boundp 'erc-server-process) erc-server-process
+          (let ((buf (and erc-server-process
                           (erc-get-buffer tgt erc-server-process))))
             (when buf
               (with-current-buffer buf
@@ -4593,7 +4715,7 @@ person who changed the modes."
         (arg-modes (nth 2 modes)))
     ;; now parse the modes changes and do the updates
     (cond ((erc-channel-p tgt); channel modes
-          (let ((buf (and (boundp 'erc-server-process) erc-server-process
+          (let ((buf (and erc-server-process
                           (erc-get-buffer tgt erc-server-process))))
             (when buf
               ;; FIXME! This used to have an original buffer
@@ -4671,7 +4793,7 @@ So far the following TYPE/L pairs are supported:
 
 (defun erc-highlight-notice (s)
   "Highlight notice message S and return it.
-See also variable `erc-notice-highlight-type'"
+See also variable `erc-notice-highlight-type'."
   (cond
    ((eq erc-notice-highlight-type 'prefix)
     (erc-put-text-property 0 (length erc-notice-prefix)
@@ -4717,12 +4839,12 @@ EmacsSpeak support."
 
 Return a list of the three separate tokens."
   (cond
-   ((string-match "^\\([^!]*\\)!\\([^@]*\\)@\\(.*\\)$" string)
+   ((string-match "^\\([^!\n]*\\)!\\([^@\n]*\\)@\\(.*\\)$" string)
     (list (match-string 1 string)
          (match-string 2 string)
          (match-string 3 string)))
    ;; Some bogus bouncers send Nick!(null), try to live with that.
-   ((string-match "^\\([^!]*\\)!\\(.*\\)$" string)
+   ((string-match "^\\([^!\n]*\\)!\\(.*\\)$" string)
     (list (match-string 1 string)
          ""
          (match-string 2 string)))
@@ -4810,10 +4932,13 @@ Specifically, return the position of `erc-insert-marker'."
    erc-input-marker
    (erc-end-of-input-line)))
 
+(defvar erc-command-regexp "^/\\([A-Za-z]+\\)\\(\\s-+.*\\|\\s-*\\)$"
+  "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
 and the prompt is already deleted.
-This returns non-nil only iff we actually send anything."
+This returns non-nil only if we actually send anything."
   ;; Handle different kinds of inputs
   (cond
    ;; Ignore empty input
@@ -4831,7 +4956,7 @@ This returns non-nil only iff we actually send anything."
       (run-hook-with-args 'erc-send-pre-hook input)
       (when erc-send-this
        (if (or (string-match "\n" str)
-               (not (char-equal (aref str 0) ?/)))
+               (not (string-match erc-command-regexp str)))
            (mapc
             (lambda (line)
               (mapc
@@ -4840,7 +4965,8 @@ This returns non-nil only iff we actually send anything."
                  (erc-display-msg line)
                  (erc-process-input-line (concat line "\n")
                                          (null erc-flood-protect) t))
-               (erc-split-line line)))
+               (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)
@@ -4887,7 +5013,7 @@ current position."
          (run-hooks 'erc-send-post-hook))))))
 
 (defun erc-command-symbol (command)
-  "Return the erc command symbol for COMMAND if it exists and is bound."
+  "Return the ERC command symbol for COMMAND if it exists and is bound."
   (let ((cmd (intern-soft (format "erc-cmd-%s" (upcase command)))))
     (when (fboundp cmd) cmd)))
 
@@ -4895,7 +5021,7 @@ current position."
   "Extract command and args from the input LINE.
 If no command was given, return nil.  If command matches, return a
 list of the form: (command args) where both elements are strings."
-  (when (string-match "^/\\([A-Za-z]+\\)\\(\\s-+.*\\|\\s-*\\)$" line)
+  (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)))
@@ -4930,8 +5056,9 @@ strings over to the next call."
 
 (defun erc-set-current-nick (nick)
   "Set the current nickname to NICK."
-  (with-current-buffer (or (erc-server-buffer)
-                          (current-buffer))
+  (with-current-buffer (if (buffer-live-p (erc-server-buffer))
+                          (erc-server-buffer)
+                        (current-buffer))
     (setq erc-server-current-nick nick)))
 
 (defun erc-current-nick ()
@@ -4986,7 +5113,7 @@ See also `erc-downcase'."
 (defun erc-add-query (nickname)
   "Add QUERY'd NICKNAME to the default channel list.
 
-The previous default target of QUERY type gets removed"
+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))))
@@ -5011,10 +5138,10 @@ The previous default target of QUERY type gets removed"
 Takes a full SPEC of a user in the form \"nick!login@host\", and
 matches against all the regexp's in `erc-ignore-list'.  If any
 match, returns that regexp."
-  (dolist (ignored (with-current-buffer (erc-server-buffer) erc-ignore-list))
-    (if (string-match ignored spec)
-       ;; We have `require'd cl, so we can return from the block named nil
-       (return ignored))))
+  (catch 'found
+    (dolist (ignored (erc-with-server-buffer erc-ignore-list))
+      (if (string-match ignored spec)
+         (throw 'found ignored)))))
 
 (defun erc-ignored-reply-p (msg tgt proc)
   ;; FIXME: this docstring needs fixing -- Lawrence 2004-01-08
@@ -5035,7 +5162,7 @@ user matches any regexp in `erc-ignore-reply-list'."
   "Return the addressed target in MSG.
 
 The addressed target is the string before the first colon in MSG."
-  (if (string-match "^\\([^: ]*\\):" msg)
+  (if (string-match "^\\([^: \n]*\\):" msg)
       (match-string 1 msg)
     nil))
 
@@ -5080,13 +5207,16 @@ If ARG is non-nil and not positive, turns CTCP replies off."
 (defun erc-toggle-flood-control (&optional arg)
   "Toggle use of flood control on sent messages.
 
-If ARG is non-nil, use flood control.
-If ARG is nil, do not use flood control.
+If ARG is positive, use flood control.
+If ARG is non-nil and not positive, do not use flood control.
 
 See `erc-server-flood-margin' for an explanation of the available
 flood control parameters."
   (interactive "P")
-  (setq erc-flood-protect arg)
+  (cond ((and (numberp arg) (> arg 0))
+        (setq erc-flood-protect t))
+       (arg (setq erc-flood-protect nil))
+       (t (setq erc-flood-protect (not erc-flood-protect))))
   (message "ERC flood control is %s"
           (cond (erc-flood-protect "ON")
                 (t "OFF"))))
@@ -5112,10 +5242,10 @@ This command is sent even if excess flood is detected."
 
 (defun erc-get-channel-mode-from-keypress (key)
   "Read a key sequence and call the corresponding channel mode function.
-After doing C-c C-o type in a channel mode letter.
+After doing C-c C-o, type in a channel mode letter.
 
 C-g means quit.
-RET let's you type more than one mode at a time.
+RET lets you type more than one mode at a time.
 If \"l\" is pressed, `erc-set-channel-limit' gets called.
 If \"k\" is pressed, `erc-set-channel-key' gets called.
 Anything else will be sent to `erc-toggle-channel-mode'."
@@ -5193,13 +5323,11 @@ If FILE is found, return the path to it."
 (defun erc-select-startup-file ()
   "Select an ERC startup file.
 See also `erc-startup-file-list'."
-  (let ((l erc-startup-file-list)
-       (f nil))
-    (while (and (not f) l)
-      (if (file-readable-p (car l))
-         (setq f (car l)))
-      (setq l (cdr l)))
-    f))
+  (catch 'found
+    (dolist (f erc-startup-file-list)
+      (setq f (convert-standard-filename f))
+      (when (file-readable-p f)
+       (throw 'found f)))))
 
 (defun erc-find-script-file (file)
   "Search for FILE in `default-directory', and any in `erc-script-path'."
@@ -5210,8 +5338,8 @@ See also `erc-startup-file-list'."
 
 FILE must be the full name, it is not searched in the
 `erc-script-path'.  If the filename ends with `.el', then load it
-as a emacs-lisp program.  Otherwise, treat it as a regular IRC
-script"
+as an Emacs Lisp program.  Otherwise, treat it as a regular IRC
+script."
   (erc-log (concat "erc-load-script: " file))
   (cond
    ((string-match "\\.el$" file)
@@ -5223,13 +5351,13 @@ script"
   "Process an IRC script LINE.
 
 Does script-specific substitutions (script arguments, current nick,
-server, etc.)  in LINE and returns it.
+server, etc.) in LINE and returns it.
 
 Substitutions are: %C and %c = current target (channel or nick),
 %S %s = current server, %N %n = my current nick, and %x is x verbatim,
 where x is any other character;
 $* = the entire argument string, $1 = the first argument, $2 = the second,
-end so on."
+and so on."
   (if (not args) (setq args ""))
   (let* ((arg-esc-regexp "\\(\\$\\(\\*\\|[1-9][0-9]*\\)\\)\\([^0-9]\\|$\\)")
         (percent-regexp "\\(%.\\)")
@@ -5333,7 +5461,7 @@ user input."
   (erc-log (format "login: nick: %s, user: %s %s %s :%s"
                   (erc-current-nick)
                   (user-login-name)
-                  (system-name)
+                  (or erc-system-name (system-name))
                   erc-session-server
                   erc-session-user-full-name))
   (if erc-session-password
@@ -5354,10 +5482,10 @@ user input."
   "Determine the connection and authentication parameters.
 Sets the buffer local variables:
 
-- erc-session-server
-- erc-session-port
-- erc-session-full-name
-- erc-server-current-nick"
+- `erc-session-server'
+- `erc-session-port'
+- `erc-session-full-name'
+- `erc-server-current-nick'"
   (setq erc-session-server (erc-compute-server server)
        erc-session-port (or port erc-default-port)
        erc-session-user-full-name (erc-compute-full-name name))
@@ -5366,28 +5494,28 @@ Sets the buffer local variables:
 (defun erc-compute-server (&optional server)
   "Return an IRC server name.
 
-Tries a number of increasingly more default methods until a non-nil value is
-found:
+This tries a number of increasingly more default methods until a
+non-nil value is found.
 
-- SERVER
-- `erc-server'
+- SERVER (the argument passed to this function)
+- The `erc-server' option
 - The value of the IRCSERVER environment variable
-- `erc-default-server'."
+- The `erc-default-server' variable"
   (or server
       erc-server
       (getenv "IRCSERVER")
       erc-default-server))
 
 (defun erc-compute-nick (&optional nick)
-  "Return user's NICK.
+  "Return user's IRC nick.
 
-Tries a number of increasingly more default methods until a non-nil value is
-found:
+This tries a number of increasingly more default methods until a
+non-nil value is found.
 
-- NICK
-- `erc-nick'
+- NICK (the argument passed to this function)
+- The `erc-nick' option
 - The value of the IRCNICK environment variable
-- via the function `user-login-name'."
+- The result from the `user-login-name' function"
   (or nick
       (if (consp erc-nick) (car erc-nick) erc-nick)
       (getenv "IRCNICK")
@@ -5395,15 +5523,15 @@ found:
 
 
 (defun erc-compute-full-name (&optional full-name)
-  "Return user's FULL-NAME.
+  "Return user's full name.
 
-Tries a number of increasingly more default methods until a non-nil value is
-found:
+This tries a number of increasingly more default methods until a
+non-nil value is found.
 
-- FULL-NAME
-- `erc-user-full-name'
+- FULL-NAME (the argument passed to this function)
+- The `erc-user-full-name' option
 - The value of the IRCNAME environment variable
-- via the function `user-full-name'."
+- The result from the `user-full-name' function"
   (or full-name
       erc-user-full-name
       (getenv "IRCNAME")
@@ -5413,12 +5541,13 @@ found:
 (defun erc-compute-port (&optional port)
   "Return a port for an IRC server.
 
-Tries a number of increasingly more default methods until a non-nil
-value is found:
+This tries a number of increasingly more default methods until a
+non-nil value is found.
 
-- PORT
-- \"ircd\"."
-  (or port erc-port "ircd"))
+- PORT (the argument passed to this function)
+- The `erc-port' option
+- The `erc-default-port' variable"
+  (or port erc-port erc-default-port))
 
 ;; time routines
 
@@ -5498,7 +5627,7 @@ See also `erc-emacs-time-to-erc-time'."
 
 (defun erc-client-info (s)
   "Return CTCP CLIENTINFO on command S.
-If S is NIL or an empty string then return general CLIENTINFO"
+If S is nil or an empty string then return general CLIENTINFO."
   (if (or (not s) (string= s ""))
       (concat
        (apply #'concat
@@ -5564,12 +5693,12 @@ entry of `channel-members'."
                             ""))
        user))))
 
-(defun erc-away-p ()
-  "Return t if the current ERC process is set away."
-  (save-excursion
-    (and (erc-server-buffer-live-p)
-        (set-buffer (process-buffer erc-server-process))
-        erc-away)))
+(defun erc-away-time ()
+  "Return non-nil if the current ERC process is set away.
+
+In particular, the time that we were set away is returned.
+See `current-time' for details on the time format."
+  (erc-with-server-buffer erc-away))
 
 ;; Mode line handling
 
@@ -5581,6 +5710,7 @@ of `mode-line-buffer-identification'.
 
 The following characters are replaced:
 %a: String indicating away status or \"\" if you are not away
+%l: The estimated lag time to the server
 %m: The modes of the channel
 %n: The current nick name
 %o: The topic of the channel
@@ -5592,13 +5722,21 @@ The following characters are replaced:
   :group 'erc-mode-line-and-header
   :type 'string)
 
-(defcustom erc-header-line-format "[IRC] %n on %t %m %o"
+(defcustom erc-header-line-format "%n on %t (%m,%l) %o"
   "A string to be formatted and shown in the header-line in `erc-mode'.
-Only used in Emacs 21.
+Only used starting in Emacs 21.
+
+Set this to nil if you do not want the header line to be
+displayed.
 
 See `erc-mode-line-format' for which characters are can be used."
   :group 'erc-mode-line-and-header
-  :type 'string)
+  :set (lambda (sym val)
+        (set sym val)
+        (when (fboundp 'erc-update-mode-line)
+          (erc-update-mode-line nil)))
+  :type '(choice (const :tag "Disabled" nil)
+                string))
 
 (defcustom erc-header-line-uses-help-echo-p t
   "Show the contents of the header line in the echo area or as a tooltip
@@ -5606,14 +5744,26 @@ when you move point into the header line."
   :group 'erc-mode-line-and-header
   :type 'boolean)
 
+(defcustom erc-header-line-face-method nil
+  "Determine what method to use when colorizing the header line text.
+
+If nil, don't colorize the header text.
+If given a function, call it and use the resulting face name.
+Otherwise, use the `erc-header-line' face."
+  :group 'erc-mode-line-and-header
+  :type '(choice (const :tag "Don't colorize" nil)
+                (const :tag "Use the erc-header-line face" t)
+                (function :tag "Call a function")))
+
 (defcustom erc-show-channel-key-p t
-  "Show the the channel key in the header line."
+  "Show the channel key in the header line."
   :group 'erc-paranoia
   :type 'boolean)
 
 (defcustom erc-common-server-suffixes
   '(("openprojects.net$" . "OPN")
-    ("freenode.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
@@ -5625,7 +5775,7 @@ displayed hostnames."
   "(AWAY since %a %b %d %H:%M) "
   "When you're away on a server, this is shown in the mode line.
 This should be a string with substitution variables recognized by
-format-time-message."
+`format-time-string'."
   :group 'erc-mode-line-and-header
   :type 'string)
 
@@ -5665,41 +5815,41 @@ format-time-message."
 (defun erc-format-away-status ()
   "Return a formatted `erc-mode-line-away-status-format'
 if `erc-away' is non-nil."
-  (let ((a (when (erc-server-buffer-live-p)
-            (with-current-buffer (process-buffer erc-server-process)
-              erc-away))))
+  (let ((a (erc-away-time)))
     (if a
        (format-time-string erc-mode-line-away-status-format a)
       "")))
 
 (defun erc-format-channel-modes ()
-  "Return the current channel's modes and the estimated lag."
-  (let ((lag (when (erc-server-buffer-live-p)
-              (with-current-buffer (process-buffer erc-server-process)
-                erc-server-lag))))
-    (concat (apply 'concat
-                  "(+" erc-channel-modes)
-           (cond ((and erc-channel-user-limit erc-channel-key)
-                  (if erc-show-channel-key-p
-                      (format "lk %.0f %s" erc-channel-user-limit
-                              erc-channel-key)
-                    (format "kl %.0f" erc-channel-user-limit)))
-                 (erc-channel-user-limit
-                  ;; Emacs has no bignums
-                  (format "l %.0f" erc-channel-user-limit))
-                 (erc-channel-key
-                  (if erc-show-channel-key-p
-                      (format "k %s" erc-channel-key)
-                    "k"))
-                 (t ""))
-           (if lag (format ",lag:%.0f" lag) "")
-           ")")))
+  "Return the current channel's modes."
+  (concat (apply 'concat
+                "+" erc-channel-modes)
+         (cond ((and erc-channel-user-limit erc-channel-key)
+                (if erc-show-channel-key-p
+                    (format "lk %.0f %s" erc-channel-user-limit
+                            erc-channel-key)
+                  (format "kl %.0f" erc-channel-user-limit)))
+               (erc-channel-user-limit
+                ;; Emacs has no bignums
+                (format "l %.0f" erc-channel-user-limit))
+               (erc-channel-key
+                (if erc-show-channel-key-p
+                    (format "k %s" erc-channel-key)
+                  "k"))
+               (t nil))))
+
+(defun erc-format-lag-time ()
+  "Return the estimated lag time to server, `erc-server-lag'."
+  (let ((lag (erc-with-server-buffer erc-server-lag)))
+    (cond (lag (format "lag:%.0f" lag))
+         (t ""))))
 
 (defun erc-update-mode-line-buffer (buffer)
   "Update the mode line in a single ERC buffer BUFFER."
   (with-current-buffer buffer
     (let ((spec (format-spec-make
                 ?a (erc-format-away-status)
+                ?l (erc-format-lag-time)
                 ?m (erc-format-channel-modes)
                 ?n (or (erc-current-nick) "")
                 ?o (erc-controls-strip erc-channel-topic)
@@ -5712,7 +5862,13 @@ if `erc-away' is non-nil."
                                ((erc-server-process-alive)
                                 "")
                                (t
-                                ": CLOSED"))))
+                                ": CLOSED")))
+         (face (cond ((eq erc-header-line-face-method nil)
+                      nil)
+                     ((functionp erc-header-line-face-method)
+                      (funcall erc-header-line-face-method))
+                     (t
+                      'erc-header-line))))
       (cond ((featurep 'xemacs)
             (setq modeline-buffer-identification
                   (list (format-spec erc-mode-line-format spec)))
@@ -5736,8 +5892,14 @@ if `erc-away' is non-nil."
                         (erc-replace-regexp-in-string
                          "%"
                          "%%"
-                         (erc-propertize header 'help-echo help-echo)))))
-               (t (setq header-line-format header))))))
+                         (if face
+                             (erc-propertize header 'help-echo help-echo
+                                             'face face)
+                           (erc-propertize header 'help-echo help-echo))))))
+               (t (setq header-line-format
+                        (if face
+                            (erc-propertize header 'face face)
+                          header)))))))
     (if (featurep 'xemacs)
        (redraw-modeline)
       (force-mode-line-update))))
@@ -5763,37 +5925,19 @@ P may be an integer or a service name."
 
 (defun erc-string-to-port (s)
   "Convert string S to either an integer port number or a service name."
-  (let ((n (string-to-number s)))
-    (if (= n 0)
-       s
-      n)))
+  (if (numberp s)
+      s
+    (let ((n (string-to-number s)))
+      (if (= n 0)
+         s
+       n))))
 
 (defun erc-version (&optional here)
   "Show the version number of ERC in the minibuffer.
 If optional argument HERE is non-nil, insert version number at point."
   (interactive "P")
   (let ((version-string
-        (format "ERC %s" erc-version-string)))
-    (if here
-       (insert version-string)
-      (if (interactive-p)
-         (message "%s" version-string)
-       version-string))))
-
-(defun erc-version-modules (&optional here)
-  "Show the version numbers of all loaded ERC modules in the minibuffer.
-If optional argument HERE is non-nil, insert version number at point."
-  (interactive "P")
-  (let ((version-string
-        (mapconcat 'identity
-                   (let (versions (case-fold-search nil))
-                     (dolist (var (apropos-internal "^erc-.*version$"))
-                       (when (and (boundp var)
-                                  (stringp (symbol-value var)))
-                         (setq versions (cons (format "%S: %s"
-                                                      var (symbol-value var))
-                                              versions))))
-                     versions) ", ")))
+        (format "ERC %s (GNU Emacs %s)" erc-version-string emacs-version)))
     (if here
        (insert version-string)
       (if (interactive-p)
@@ -5820,32 +5964,6 @@ If optional argument HERE is non-nil, insert version number at point."
          (message "%s" string)
        string))))
 
-(defun erc-latest-version ()
-  "Retrieve the latest erc.el version from CVS."
-  (interactive)
-  (if (ignore-errors (require 'url))
-      (progn
-       (switch-to-buffer (get-buffer-create "*erc.el latest version*"))
-       (delete-region (point-min) (point-max))
-       (kill-all-local-variables)
-       (url-insert-file-contents (concat
-                                  "http://cvs.sourceforge.net/viewcvs.py/"
-                                  "*checkout*/erc/erc/erc.el?content-type"
-                                  "=text%2Fplain&rev=HEAD"))
-       (emacs-lisp-mode)
-       (current-buffer))
-    (error "URL needs to be installed")))
-
-(defun erc-ediff-latest-version ()
-  "Ediff your installed erc.el with the latest CVS version.
-See also `erc-latest-version'."
-  (interactive)
-  (let ((current (locate-library "erc.el")))
-    (if current
-       (ediff-buffers (find-file current)
-                      (erc-latest-version))
-      (error "You do not appear to have the uncompiled erc.el file"))))
-
 (defun erc-trim-string (s)
   "Trim leading and trailing spaces off S."
   (cond
@@ -5862,8 +5980,8 @@ See also `erc-latest-version'."
 
 All windows are opened in the current frame."
   (interactive)
-  (unless (boundp 'erc-server-process)
-    (error "No erc-process found in current buffer"))
+  (unless erc-server-process
+    (error "No erc-server-process found in current buffer"))
   (let ((bufs (erc-buffer-list nil erc-server-process)))
     (when bufs
       (delete-other-windows)
@@ -5871,12 +5989,13 @@ All windows are opened in the current frame."
       (setq bufs (cdr bufs))
       (while bufs
        (split-window)
-       (switch-to-buffer-other-window (car bufs))
+       (other-window 1)
+       (switch-to-buffer (car bufs))
        (setq bufs (cdr bufs))
        (balance-windows)))))
 
 (defun erc-popup-input-buffer ()
-  "Provide a input buffer."
+  "Provide an input buffer."
    (interactive)
    (let ((buffer-name (generate-new-buffer-name "*ERC input*"))
         (mode (intern
@@ -5923,12 +6042,17 @@ All windows are opened in the current frame."
    (ctcp-request-to . "==> CTCP request from %n (%u@%h) to %t: %r")
    (ctcp-too-many . "Too many CTCP queries in single message. Ignoring")
    (flood-ctcp-off . "FLOOD PROTECTION: Automatic CTCP responses turned off.")
-   (flood-strict-mode . "FLOOD PROTECTION: Switched to Strict Flood Control mode.")
-   (disconnected . "Connection failed!  Re-establishing connection...")
-   (disconnected-noreconnect . "Connection failed!  Not re-establishing connection.")
+   (flood-strict-mode
+    . "FLOOD PROTECTION: Switched to Strict Flood Control mode.")
+   (disconnected . "\n\nConnection failed!  Re-establishing connection...\n")
+   (disconnected-noreconnect
+    . "\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\'...")
    (nick-in-use . "%n is in use. Choose new nickname: ")
-   (nick-too-long . "WARNING: Nick length (%i) exceeds max NICKLEN(%l) defined by server")
+   (nick-too-long
+    . "WARNING: Nick length (%i) exceeds max NICKLEN(%l) defined by server")
    (no-default-channel . "No default channel")
    (no-invitation . "You've got no invitation")
    (no-target . "No target")
@@ -5989,7 +6113,8 @@ All windows are opened in the current frame."
    (s341   . "Inviting %n to channel %c")
    (s352   . "%-11c %-10n %-4a %u@%h (%f)")
    (s353   . "Users on %c: %u")
-   (s367   . "Ban on %b on %c set by %s on %t (Use /banlist!)")
+   (s367   . "Ban for %b on %c")
+   (s367-set-by . "Ban for %b on %c set by %s on %t")
    (s368   . "Banlist of %c ends.")
    (s379   . "%c: Forwarded to %f")
    (s391   . "The time at %s is %t")
@@ -6037,7 +6162,8 @@ functions."
       (format "%s (%s@%s) has left channel %s%s"
              nick user host channel
              (if (not (string= reason ""))
-                 (format ": %s" reason)
+                 (format ": %s"
+                         (erc-replace-regexp-in-string "%" "%%" reason))
                "")))))
 
 
@@ -6126,6 +6252,59 @@ This function should be on `erc-kill-channel-hook'."
                               (funcall erc-part-reason nil))
                       nil tgt))))
 
+;;; Dealing with `erc-parsed'
+
+(defun erc-find-parsed-property ()
+  "Find the next occurrence of the `erc-parsed' text property."
+  (text-property-not-all (point-min) (point-max) 'erc-parsed nil))
+
+(defun erc-restore-text-properties ()
+  "Restore the property 'erc-parsed for the region."
+  (let ((parsed-posn (erc-find-parsed-property)))
+    (put-text-property
+     (point-min) (point-max)
+     'erc-parsed (when parsed-posn (erc-get-parsed-vector parsed-posn)))))
+
+(defun erc-get-parsed-vector (point)
+  "Return the whole parsed vector on POINT."
+  (get-text-property point 'erc-parsed))
+
+(defun erc-get-parsed-vector-nick (vect)
+  "Return nickname in the parsed vector VECT."
+  (let* ((untreated-nick (and vect (erc-response.sender vect)))
+        (maybe-nick (when untreated-nick
+                      (car (split-string untreated-nick "!")))))
+    (when (and (not (null maybe-nick))
+              (erc-is-valid-nick-p maybe-nick))
+      untreated-nick)))
+
+(defun erc-get-parsed-vector-type (vect)
+  "Return message type in the parsed vector VECT."
+  (and vect
+       (erc-response.command vect)))
+
+;; Teach url.el how to open irc:// URLs with ERC.
+;; To activate, customize `url-irc-function' to `url-irc-erc'.
+
+;;;###autoload
+(defun erc-handle-irc-url (host port channel user password)
+  "Use ERC to IRC on HOST:PORT in CHANNEL as USER with PASSWORD.
+If ERC is already connected to HOST:PORT, simply /join CHANNEL.
+Otherwise, connect to HOST:PORT as USER and /join CHANNEL."
+  (let ((server-buffer
+        (car (erc-buffer-filter
+              (lambda ()
+                (and (string-equal erc-session-server host)
+                     (= erc-session-port port)
+                     (erc-open-server-buffer-p)))))))
+    (with-current-buffer (or server-buffer (current-buffer))
+      (if (and server-buffer channel)
+         (erc-cmd-JOIN channel)
+       (erc-open host port (or user (erc-compute-nick)) (erc-compute-full-name)
+                 (not server-buffer) password nil channel
+                 (when server-buffer
+                   (get-buffer-process server-buffer)))))))
+
 (provide 'erc)
 
 ;;; Deprecated. We might eventually stop requiring the goodies automatically.