Sync ERC 5.3 (devel) from upstream
authorMichael Olson <mwolson@gnu.org>
Sat, 8 Sep 2007 03:07:09 +0000 (03:07 +0000)
committerMichael Olson <mwolson@gnu.org>
Sat, 8 Sep 2007 03:07:09 +0000 (03:07 +0000)
14 files changed:
doc/misc/ChangeLog
doc/misc/erc.texi
etc/ChangeLog
etc/ERC-NEWS
lisp/erc/erc-backend.el
lisp/erc/erc-button.el
lisp/erc/erc-compat.el
lisp/erc/erc-goodies.el
lisp/erc/erc-identd.el
lisp/erc/erc-log.el
lisp/erc/erc-sound.el
lisp/erc/erc-stamp.el
lisp/erc/erc-track.el
lisp/erc/erc.el

index 3d11858..3652fb7 100644 (file)
@@ -1,3 +1,8 @@
+2007-09-08  Michael Olson  <mwolson@gnu.org>
+
+       * erc.texi (Copying): New section included from gpl.texi.  This matches
+       the look of the upstream ERC manual.
+
 2007-09-07  Jay Belanger  <jay.p.belanger@gmail.com>
 
        * calc.texi (History and Acknowledgements): Adjust the
index ee10293..3ff8fce 100644 (file)
@@ -68,6 +68,10 @@ and modified without restriction.
 * Advanced Usage::              Cool ways of using ERC.
 * Getting Help and Reporting Bugs::  
 * History::                     The history of ERC.
+* Copying::                     The GNU General Public License gives you
+                                  permission to redistribute ERC on
+                                  certain terms; it also explains that
+                                  there is no warranty.
 * GNU Free Documentation License:: The license for this documentation.
 * Concept Index::               Search for terms.
 
@@ -900,7 +904,7 @@ stuff, to the current ERC buffer."
 @c previous chapter)
 
 This section has not yet been written.  For now, the easiest way to
-check out the available option for ERC is to do
+check out the available options for ERC is to do
 @kbd{M-x customize-group erc RET}.
 
 
@@ -916,7 +920,7 @@ or if you have bugs to report, there are several places you can go.
 @itemize @bullet
 
 @item
-@uref{http://www.emacswiki.org/cgi-bin/wiki/EmacsIRCClient} is the
+@uref{http://www.emacswiki.org/cgi-bin/wiki/ERC} is the
 emacswiki.org page for ERC.  Anyone may add tips, hints, or bug
 descriptions to it.
 
@@ -929,14 +933,11 @@ The mailing lists are also available on Gmane.
 accessing the mailing lists, adding content to them, and searching them.
 
 @enumerate
-@item gmane.emacs.erc.announce
-Announcements
+@item gmane.emacs.erc.announce: Announcements
 
-@item gmane.emacs.erc.discuss
-General discussion
+@item gmane.emacs.erc.discuss: General discussion
 
-@item gmane.emacs.erc.cvs
-Log messages for changes to the ERC source code
+@item gmane.emacs.erc.cvs: Log messages for changes to the ERC source code
 
 @end enumerate
 
@@ -948,7 +949,7 @@ questions.
 @end itemize
 
 
-@node History, GNU Free Documentation License, Getting Help and Reporting Bugs, Top
+@node History, Copying, Getting Help and Reporting Bugs, Top
 @comment  node-name,  next,  previous,  up
 @chapter History
 @cindex history, of ERC
@@ -1010,8 +1011,12 @@ our revision control system.  Our mailing list address changed as well.
 
 @end itemize
 
-@node GNU Free Documentation License, Concept Index, History, Top
-@appendix GNU Free Documentation License
+@node Copying, GNU Free Documentation License, History, Top
+@comment  node-name,  next,  previous,  up
+@include gpl.texi
+
+@node GNU Free Documentation License, Concept Index, Copying, Top
+@comment  node-name,  next,  previous,  up
 @include doclicense.texi
 
 @node Concept Index,  , GNU Free Documentation License, Top
index 8760888..0ec046d 100644 (file)
@@ -1,3 +1,8 @@
+2007-09-08  Michael Olson  <mwolson@gnu.org>
+
+       * ERC-NEWS: Update for changes to the development version of ERC
+       5.3.
+
 2007-09-06  Glenn Morris  <rgm@gnu.org>
 
        * ctags.1, emacs.1, emacsclient.1, etags.1: Move from etc/ to
index f5bf1e8..409dcf0 100644 (file)
@@ -3,6 +3,22 @@ ERC NEWS                                                       -*- outline -*-
 Copyright (C) 2006, 2007  Free Software Foundation, Inc.
 See the end of the file for license conditions.
 
+* Changes in ERC 5.3
+
+** New function `erc-tls' is to be used for connecting to a server via TLS.
+The function `erc-ssl' should never be used for that purpose any
+longer, which was the case with the version of ERC that is included
+with Emacs.
+
+** Changes and additions to modules
+
+*** Channel tracking (erc-track.el)
+
+If erc-track-position-in-mode-line is set to nil, the tracking
+information won't be shown in the mode line, which is a change
+from the previous behavior of showing it "After all other
+information".
+
 * Changes in ERC 5.2
 
 ** M-x erc RET now starts ERC.
index 349f913..4e25049 100644 (file)
@@ -550,11 +550,12 @@ We will store server variables in the buffer given by BUFFER."
 (defun erc-server-reconnect ()
 "Reestablish the current IRC connection.
 Make sure you are in an ERC buffer when running this."
-  (let ((server (erc-server-buffer)))
-    (unless (and server
-                 (buffer-live-p server))
-      (error "Couldn't switch to server buffer"))
-    (with-current-buffer server
+  (let ((buffer (erc-server-buffer)))
+    (unless (buffer-live-p buffer)
+      (if (eq major-mode 'erc-mode)
+          (setq buffer (current-buffer))
+        (error "Reconnect must be run from an ERC buffer")))
+    (with-current-buffer buffer
       (erc-update-mode-line)
       (erc-set-active-buffer (current-buffer))
       (setq erc-server-last-sent-time 0)
@@ -609,39 +610,61 @@ EVENT is the message received from the closed connection process."
            ;; open-network-stream-nowait error for connection refused
            (not (string-match "^failed with code 111" event)))))
 
-(defun erc-process-sentinel-1 (event)
+(defun erc-process-sentinel-2 (event buffer)
+  "Called when `erc-process-sentinel-1' has detected an unexpected disconnect."
+  (if (not (buffer-live-p buffer))
+      (erc-update-mode-line)
+    (with-current-buffer buffer
+      (let ((reconnect-p (erc-server-reconnect-p event)))
+        (erc-display-message nil 'error (current-buffer)
+                             (if reconnect-p 'disconnected
+                               'disconnected-noreconnect))
+        (if (not reconnect-p)
+            ;; terminate, do not reconnect
+            (progn
+              (erc-display-message nil 'error (current-buffer)
+                                   'terminated ?e event)
+              ;; Update mode line indicators
+              (erc-update-mode-line)
+              (set-buffer-modified-p nil))
+          ;; reconnect
+          (condition-case err
+              (progn
+                (setq erc-server-reconnecting nil)
+                (erc-server-reconnect)
+                (setq erc-server-reconnect-count 0))
+            (error (when (buffer-live-p buffer)
+                     (set-buffer buffer)
+                     (if (integerp erc-server-reconnect-attempts)
+                         (setq erc-server-reconnect-count
+                               (1+ erc-server-reconnect-count))
+                       (message "%s ... %s"
+                                "Reconnecting until we succeed"
+                                "kill the ERC server buffer to stop"))
+                     (if (numberp erc-server-reconnect-timeout)
+                         (run-at-time erc-server-reconnect-timeout nil
+                                      #'erc-process-sentinel-2
+                                      event buffer)
+                       (error (concat "`erc-server-reconnect-timeout`"
+                                      " must be a number")))))))))))
+
+(defun erc-process-sentinel-1 (event buffer)
   "Called when `erc-process-sentinel' has decided that we're disconnecting.
 Determine whether user has quit or whether erc has been terminated.
 Conditionally try to reconnect and take appropriate action."
-  (if erc-server-quitting
-      ;; normal quit
-      (progn
-        (erc-display-message nil 'error (current-buffer) 'finished)
-        (when erc-kill-server-buffer-on-quit
+  (with-current-buffer buffer
+    (if erc-server-quitting
+        ;; normal quit
+        (progn
+          (erc-display-message nil 'error (current-buffer) 'finished)
+          ;; Update mode line indicators
+          (erc-update-mode-line)
+          ;; Kill server buffer if user wants it
           (set-buffer-modified-p nil)
-          (kill-buffer (current-buffer))))
-    ;; unexpected disconnect
-    (let ((again t))
-      (while again
-        (setq again nil)
-        (erc-display-message nil 'error (current-buffer)
-                             (if (erc-server-reconnect-p event)
-                                 'disconnected
-                               'disconnected-noreconnect))
-        (if (erc-server-reconnect-p event)
-            (condition-case err
-                (progn
-                  (setq erc-server-reconnecting nil)
-                  (erc-server-reconnect)
-                  (setq erc-server-reconnect-count 0))
-              (error (when (integerp erc-server-reconnect-attempts)
-                       (setq erc-server-reconnect-count
-                             (1+ erc-server-reconnect-count))
-                       (sit-for erc-server-reconnect-timeout)
-                       (setq again t))))
-          ;; terminate, do not reconnect
-          (erc-display-message nil 'error (current-buffer)
-                               'terminated ?e event))))))
+          (when erc-kill-server-buffer-on-quit
+            (kill-buffer (current-buffer))))
+      ;; unexpected disconnect
+      (erc-process-sentinel-2 event buffer))))
 
 (defun erc-process-sentinel (cproc event)
   "Sentinel function for ERC process."
@@ -668,12 +691,7 @@ Conditionally try to reconnect and take appropriate action."
         (delete-region (point) (point-max))
         ;; Decide what to do with the buffer
         ;; Restart if disconnected
-        (erc-process-sentinel-1 event)
-        ;; Make sure we don't write to the buffer if it has been
-        ;; killed
-        (when (buffer-live-p buf)
-          (erc-update-mode-line)
-          (set-buffer-modified-p nil))))))
+        (erc-process-sentinel-1 event buf)))))
 
 ;;;; Sending messages
 
@@ -1054,8 +1072,11 @@ Would expand to:
       \"Some non-generic variable documentation.
 
   Hook called upon receiving a WHOIS server response.
+
   Each function is called with two arguments, the process associated
-  with the response and the parsed response.
+  with the response and the parsed response.  If the function returns
+  non-nil, stop processing the hook.  Otherwise, continue.
+
   See also `erc-server-311'.\")
 
     (defalias 'erc-server-WI 'erc-server-311)
@@ -1064,7 +1085,9 @@ Would expand to:
 
   Hook called upon receiving a WI server response.
   Each function is called with two arguments, the process associated
-  with the response and the parsed response.
+  with the response and the parsed response.  If the function returns
+  non-nil, stop processing the hook.  Otherwise, continue.
+
   See also `erc-server-311'.\"))
 
 \(fn (NAME &rest ALIASES) &optional EXTRA-FN-DOC EXTRA-VAR-DOC &rest FN-BODY)"
@@ -1078,7 +1101,9 @@ Would expand to:
          (fn-name (intern (format "erc-server-%s" name)))
          (hook-doc (format "%sHook called upon receiving a %%s server response.
 Each function is called with two arguments, the process associated
-with the response and the parsed response.
+with the response and the parsed response.  If the function returns
+non-nil, stop processing the hook.  Otherwise, continue.
+
 See also `%s'."
                            (if extra-var-doc
                                (concat extra-var-doc "\n\n")
index 35a20d5..81c604d 100644 (file)
@@ -99,7 +99,7 @@ above them."
   (concat "\\(www\\.\\|\\(s?https?\\|"
           "ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\):\\)"
           "\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?"
-          "[-a-zA-Z0-9_=!?#$@~`%&*+\\/:;.,]+[-a-zA-Z0-9_=#$@~`%&*+\\/]")
+          "[-a-zA-Z0-9_=!?#$@~`%&*+\\/:;.,()]+[-a-zA-Z0-9_=#$@~`%&*+\\/()]")
   "Regular expression that matches URLs."
   :group 'erc-button
   :type 'regexp)
index 8be3bed..47bdd94 100644 (file)
@@ -56,6 +56,18 @@ See `erc-encoding-coding-alist'."
     (format-time-string "%Y-%m-%d" emacs-build-time))
   "Time at which Emacs was dumped out.")
 
+;; Emacs 21 and XEmacs do not have user-emacs-directory, but XEmacs
+;; has user-init-directory.
+(defvar erc-user-emacs-directory
+  (cond ((boundp 'user-emacs-directory)
+        user-emacs-directory)
+       ((boundp 'user-init-directory)
+        user-init-directory)
+       (t "~/.emacs.d/"))
+  "Directory beneath which additional per-user Emacs-specific files
+are placed.
+Note that this should end with a directory separator.")
+
 ;; XEmacs' `replace-match' does not replace matching subexpressions in strings.
 (defun erc-replace-match-subexpression-in-string
   (newtext string match subexp start &optional fixedcase literal)
@@ -68,6 +80,7 @@ See `replace-match' for explanations of FIXEDCASE and LITERAL."
         (replace-match newtext fixedcase literal string))
        (t (replace-match newtext fixedcase literal string subexp))))
 
+(defalias 'erc-with-selected-window 'with-selected-window)
 (defalias 'erc-cancel-timer 'cancel-timer)
 (defalias 'erc-make-obsolete 'make-obsolete)
 (defalias 'erc-make-obsolete-variable 'make-obsolete-variable)
index 49a0451..9131ce6 100644 (file)
@@ -84,8 +84,7 @@ DISPLAY-START is ignored."
       ;; works, but it solves the problem, and has no negative side effects.
       ;; (Fran Litterio, 2003/01/07)
       (let ((resize-mini-windows nil))
-        (save-selected-window
-          (select-window window)
+        (erc-with-selected-window window
           (save-restriction
             (widen)
             (when (and erc-insert-marker
@@ -282,10 +281,8 @@ The value `erc-interpret-controls-p' must also be t for this to work."
   "Fetches the right face for background color N (0-15)."
   (if (stringp n) (setq n (string-to-number n)))
   (if (not (numberp n))
-      (progn
-        (message "erc-get-bg-color-face: n is NaN: %S" n)
-        (beep)
-        'default)
+      (prog1 'default
+        (erc-error "erc-get-bg-color-face: n is NaN: %S" n))
     (when (> n 16)
       (erc-log (format "   Wrong color: %s" n))
       (setq n (mod n 16)))
@@ -298,10 +295,8 @@ The value `erc-interpret-controls-p' must also be t for this to work."
   "Fetches the right face for foreground color N (0-15)."
   (if (stringp n) (setq n (string-to-number n)))
   (if (not (numberp n))
-      (progn
-        (message "erc-get-fg-color-face: n is NaN: %S" n)
-        (beep)
-        'default)
+      (prog1 'default
+        (erc-error "erc-get-fg-color-face: n is NaN: %S" n))
     (when (> n 16)
       (erc-log (format "   Wrong color: %s" n))
       (setq n (mod n 16)))
index 4b72ee1..db93309 100644 (file)
@@ -74,7 +74,8 @@ This can be either a string or a number."
                     (format "%s, %s : USERID : %s : %s\n"
                             port-on-server port-on-client
                             system-type (user-login-name)))
-       (process-send-eof erc-identd-process)))))
+       (stop-process erc-identd-process)
+       (delete-process proc)))))
 
 ;;;###autoload
 (defun erc-identd-start (&optional port)
index 88132af..856f1dc 100644 (file)
 
 ;; Quick start:
 ;;
-;; (setq erc-enable-logging t)
+;; (require 'erc-log)
 ;; (setq erc-log-channels-directory "/path/to/logfiles") ; must be writable
+;; (erc-log-enable)
 ;;
-;; There are two ways to setup logging. The first will write to the log files
-;; on each incoming or outgoing line - this may not be optimal on a laptop
-;; HDD. To do this, M-x customize-variable erc-modules, and add "log".
+;; Or:
 ;;
-;; The second method will save buffers on /part, /quit, or killing the
-;; channel buffer. To do this, add the following to your .emacs:
+;; M-x customize-variable erc-modules, and add "log".
 ;;
-;; (require 'erc-log)
+;; There are two ways to setup logging.  The first (default) method
+;; will save buffers on /part, /quit, or killing the channel
+;; buffer.
+;;
+;; The second will write to the log files on each incoming or outgoing
+;; line - this may not be optimal on a laptop HDD.  To use this
+;; method, add the following to the above instructions.
+;;
+;; (setq erc-save-buffer-on-part nil
+;;       erc-save-queries-on-quit nil
+;;       erc-log-write-after-send t
+;;       erc-log-write-after-insert t)
 ;;
 ;; If you only want to save logs for some buffers, customise the
 ;; variable `erc-enable-logging'.
@@ -99,15 +108,19 @@ The function must take five arguments: BUFFER, TARGET, NICK, SERVER and PORT.
 BUFFER is the buffer to be saved,
 TARGET is the name of the channel, or the target of the query,
 NICK is the current nick,
-SERVER and PORT are the parameters used to connect BUFFERs
-`erc-server-process'."
+SERVER and PORT are the parameters that were used to connect to BUFFERs
+`erc-server-process'.
+
+If you want to write logs into different directories, make a
+custom function which returns the directory part and set
+`erc-log-channels-directory' to its name."
   :group 'erc-log
   :type '(choice (const :tag "Long style" erc-generate-log-file-name-long)
                 (const :tag "Long, but with network name rather than server"
                        erc-generate-log-file-name-network)
                 (const :tag "Short" erc-generate-log-file-name-short)
                 (const :tag "With date" erc-generate-log-file-name-with-date)
-                (symbol :tag "Other function")))
+                (function :tag "Other function")))
 
 (defcustom erc-truncate-buffer-on-save nil
   "Truncate any ERC (channel, query, server) buffer when it is saved."
@@ -134,10 +147,16 @@ Log files are stored in `erc-log-channels-directory'."
   "The directory to place log files for channels.
 Leave blank to disable logging.  If not nil, all the channel
 buffers are logged in separate files in that directory.  The
-directory should not end with a trailing slash."
+directory should not end with a trailing slash.
+
+If this is the name of a function, the function will be called
+with the buffer, target, nick, server, and port arguments.  See
+`erc-generate-log-file-name-function' for a description of these
+arguments."
   :group 'erc-log
   :type '(choice directory
-                (const nil)))
+                (function "Function")
+                (const :tag "Disable logging" nil)))
 
 (defcustom erc-log-insert-log-on-open nil
   "*Insert log file contents into the buffer if a log file exists."
@@ -297,7 +316,8 @@ Logging is enabled if `erc-log-channels-directory' is non-nil, the directory
 is writeable (it will be created as necessary) and
 `erc-enable-logging' returns a non-nil value."
   (and erc-log-channels-directory
-       (erc-directory-writable-p erc-log-channels-directory)
+       (or (functionp erc-log-channels-directory)
+          (erc-directory-writable-p erc-log-channels-directory))
        (if (functionp erc-enable-logging)
           (funcall erc-enable-logging (or buffer (current-buffer)))
         erc-enable-logging)))
@@ -316,14 +336,19 @@ filename is downcased."
 If BUFFER is nil, the value of `current-buffer' is used.
 This is determined by `erc-generate-log-file-name-function'.
 The result is converted to lowercase, as IRC is case-insensitive"
-  (expand-file-name
-   (erc-log-standardize-name
-    (funcall erc-generate-log-file-name-function
-            (or buffer (current-buffer))
-            (or (buffer-name buffer) (erc-default-target))
-            (erc-current-nick)
-            erc-session-server erc-session-port))
-   erc-log-channels-directory))
+  (unless buffer (setq buffer (current-buffer)))
+  (let ((target (or (buffer-name buffer) (erc-default-target)))
+       (nick (erc-current-nick))
+       (server erc-session-server)
+       (port erc-session-port))
+    (expand-file-name
+     (erc-log-standardize-name
+      (funcall erc-generate-log-file-name-function
+              buffer target nick server port))
+     (if (functionp erc-log-channels-directory)
+        (funcall erc-log-channels-directory
+                 buffer target nick server port)
+       erc-log-channels-directory))))
 
 (defun erc-generate-log-file-name-with-date (buffer &rest ignore)
   "This function computes a short log file name.
index 4d3d792..d02887a 100644 (file)
@@ -125,7 +125,7 @@ See also `play-sound-file'."
     (if (and (not filepath) erc-default-sound)
        (setq filepath erc-default-sound))
     (cond ((and filepath (file-exists-p filepath))
-           (play-sound-file filepath))
+          (play-sound-file filepath))
          (t (beep)))
     (erc-log (format "Playing sound file %S" filepath))))
 
@@ -142,5 +142,11 @@ See also `play-sound-file'."
 
 (provide 'erc-sound)
 
-;; arch-tag: 53657d1d-007f-4a20-91c1-588e71cf0cee
 ;;; erc-sound.el ends here
+;;
+;; Local Variables:
+;; indent-tabs-mode: t
+;; tab-width: 8
+;; End:
+
+;; arch-tag: 53657d1d-007f-4a20-91c1-588e71cf0cee
index d67dffe..3b7f5ba 100644 (file)
@@ -58,16 +58,48 @@ If nil, timestamping is turned off."
   :type '(choice (const nil)
                 (string)))
 
-(defcustom erc-insert-timestamp-function 'erc-insert-timestamp-right
+(defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n"
+  "*If set to a string, messages will be timestamped.
+This string is processed using `format-time-string'.
+Good examples are \"%T\" and \"%H:%M\".
+
+This timestamp is used for timestamps on the left side of the
+screen when `erc-insert-timestamp-function' is set to
+`erc-insert-timestamp-left-and-right'.
+
+If nil, timestamping is turned off."
+  :group 'erc-stamp
+  :type '(choice (const nil)
+                (string)))
+
+(defcustom erc-timestamp-format-right " [%H:%M]"
+  "*If set to a string, messages will be timestamped.
+This string is processed using `format-time-string'.
+Good examples are \"%T\" and \"%H:%M\".
+
+This timestamp is used for timestamps on the right side of the
+screen when `erc-insert-timestamp-function' is set to
+`erc-insert-timestamp-left-and-right'.
+
+If nil, timestamping is turned off."
+  :group 'erc-stamp
+  :type '(choice (const nil)
+                (string)))
+
+(defcustom erc-insert-timestamp-function 'erc-insert-timestamp-left-and-right
   "*Function to use to insert timestamps.
 
 It takes a single argument STRING which is the final string
 which all text-properties already appended.  This function only cares about
 inserting this string at the right position.  Narrowing is in effect
 while it is called, so (point-min) and (point-max) determine the region to
-operate on."
+operate on.
+
+You will probably want to set
+`erc-insert-away-timestamp-function' to the same value."
   :group 'erc-stamp
-  :type '(choice (const :tag "Right" erc-insert-timestamp-right)
+  :type '(choice (const :tag "Both sides" erc-insert-timestamp-left-and-right)
+                (const :tag "Right" erc-insert-timestamp-right)
                 (const :tag "Left" erc-insert-timestamp-left)
                 function))
 
@@ -82,12 +114,14 @@ If `erc-timestamp-format' is set, this will not be used."
   :type '(choice (const nil)
                 (string)))
 
-(defcustom erc-insert-away-timestamp-function 'erc-insert-timestamp-right
+(defcustom erc-insert-away-timestamp-function
+  'erc-insert-timestamp-left-and-right
   "*Function to use to insert the away timestamp.
 
 See `erc-insert-timestamp-function' for details."
   :group 'erc-stamp
-  :type '(choice (const :tag "Right" erc-insert-timestamp-right)
+  :type '(choice (const :tag "Both sides" erc-insert-timestamp-left-and-right)
+                (const :tag "Right" erc-insert-timestamp-right)
                 (const :tag "Left" erc-insert-timestamp-left)
                 function))
 
@@ -160,6 +194,18 @@ or `erc-send-modify-hook'."
   "Last timestamp inserted into the buffer.")
 (make-variable-buffer-local 'erc-timestamp-last-inserted)
 
+(defvar erc-timestamp-last-inserted-left nil
+  "Last timestamp inserted into the left side of the buffer.
+This is used when `erc-insert-timestamp-function' is set to
+`erc-timestamp-left-and-right'")
+(make-variable-buffer-local 'erc-timestamp-last-inserted-left)
+
+(defvar erc-timestamp-last-inserted-right nil
+  "Last timestamp inserted into the right side of the buffer.
+This is used when `erc-insert-timestamp-function' is set to
+`erc-timestamp-left-and-right'")
+(make-variable-buffer-local 'erc-timestamp-last-inserted-right)
+
 (defcustom erc-timestamp-only-if-changed-flag t
   "*Insert timestamp only if its value changed since last insertion.
 If `erc-insert-timestamp-function' is `erc-insert-timestamp-left', a
@@ -272,6 +318,26 @@ be printed just before the window-width."
       (when erc-timestamp-intangible
        (erc-put-text-property from (1+ (point)) 'intangible t)))))
 
+(defun erc-insert-timestamp-left-and-right (string)
+  "This is another function that can be assigned to
+`erc-insert-timestamp-function'.  If the date is changed, it will
+print a blank line, the date, and another blank line.  If the time is
+changed, it will then print it off to the right."
+  (let* ((ct (current-time))
+        (ts-left (erc-format-timestamp ct erc-timestamp-format-left))
+        (ts-right (erc-format-timestamp ct erc-timestamp-format-right)))
+    ;; insert left timestamp
+    (unless (string-equal ts-left erc-timestamp-last-inserted-left)
+      (goto-char (point-min))
+      (erc-put-text-property 0 (length ts-left) 'field 'erc-timestamp ts-left)
+      (insert ts-left)
+      (setq erc-timestamp-last-inserted-left ts-left))
+    ;; insert right timestamp
+    (let ((erc-timestamp-only-if-changed-flag t)
+         (erc-timestamp-last-inserted erc-timestamp-last-inserted-right))
+      (erc-insert-timestamp-right ts-right)
+      (setq erc-timestamp-last-inserted-right ts-right))))
+
 ;; for testing: (setq erc-timestamp-only-if-changed-flag nil)
 
 (defun erc-format-timestamp (time format)
index f72a5be..5865257 100644 (file)
@@ -95,6 +95,12 @@ Activity means that there was no user input in the last 10 seconds."
   :group 'erc-track
   :type '(repeat string))
 
+(defcustom erc-track-remove-disconnected-buffers nil
+  "*If true, remove buffers associated with a server that is
+disconnected from `erc-modified-channels-alist'."
+  :group 'erc-track
+  :type 'boolean)
+
 (defcustom erc-track-exclude-types '("NICK")
   "*List of message types to be ignored.
 This list could look like '(\"JOIN\" \"PART\")."
@@ -151,6 +157,16 @@ If nil instead of a function, shortening is disabled."
   :type '(choice (const :tag "Disabled")
                 function))
 
+(defcustom erc-track-list-changed-hook nil
+  "Hook that is run whenever the contents of
+`erc-modified-channels-alist' changes.
+
+This is useful for people that don't use the default mode-line
+notification but instead use a separate mechanism to provide
+notification of channel activity."
+  :group 'erc-track
+  :type 'hook)
+
 (defcustom erc-track-use-faces t
   "*Use faces in the mode-line.
 The faces used are the same as used for text in the buffers.
@@ -192,12 +208,14 @@ Setting this variable only has effects in GNU Emacs versions above 21.3.
 Choices are:
 'before-modes - add to the beginning of `mode-line-modes'
 'after-modes  - add to the end of `mode-line-modes'
-
-Any other value means add to the end of `global-mode-string'."
+t             - add to the end of `global-mode-string'.
+nil           - don't add to mode line
+"
   :group 'erc-track
   :type '(choice (const :tag "Just before mode information" before-modes)
                 (const :tag "Just after mode information" after-modes)
-                (const :tag "After all other information" nil))
+                (const :tag "After all other information" t)
+                (const :tag "Don't display in mode line" nil))
   :set (lambda (sym val)
         (set sym val)
         (when (and (boundp 'erc-track-mode)
@@ -263,12 +281,14 @@ when there are no more active channels."
 (defcustom erc-track-switch-direction 'oldest
   "Direction `erc-track-switch-buffer' should switch.
 
+  importance  -  find buffer with the most important message
   oldest      -  find oldest active buffer
   newest      -  find newest active buffer
   leastactive -  find buffer with least unseen messages
   mostactive  -  find buffer with most unseen messages."
   :group 'erc-track
-  :type '(choice (const oldest)
+  :type '(choice (const importance)
+                (const oldest)
                 (const newest)
                 (const leastactive)
                 (const mostactive)))
@@ -296,7 +316,7 @@ See `erc-track-position-in-mode-line' for possible values."
              (boundp 'mode-line-modes))
         (add-to-list 'mode-line-modes
                      '(t erc-modified-channels-object) t))
-       (t
+       ((eq position t)
         (when (not global-mode-string)
           (setq global-mode-string '(""))) ; Padding for mode-line wart
         (add-to-list 'global-mode-string
@@ -644,14 +664,21 @@ only consider active buffers visible.")
   (setq erc-buffer-activity (erc-current-time))
   (erc-track-modified-channels))
 
+(defun erc-track-get-buffer-window (buffer frame-param)
+  (if (eq frame-param 'selected-visible)
+      (if (eq (frame-visible-p (selected-frame)) t)
+         (get-buffer-window buffer nil)
+       nil)
+    (get-buffer-window buffer frame-param)))
+
 (defun erc-buffer-visible (buffer)
   "Return non-nil when the buffer is visible."
   (if erc-track-when-inactive
       (when erc-buffer-activity; could be nil
-       (and (get-buffer-window buffer erc-track-visibility)
+       (and (erc-track-get-buffer-window buffer erc-track-visibility)
             (<= (erc-time-diff erc-buffer-activity (erc-current-time))
                 erc-buffer-activity-timeout)))
-    (get-buffer-window buffer erc-track-visibility)))
+    (erc-track-get-buffer-window buffer erc-track-visibility)))
 
 ;;; Tracking the channel modifications
 
@@ -668,18 +695,22 @@ called via `window-configuration-change-hook'.
 ARGS are ignored."
   (interactive)
   (unless erc-modified-channels-update-inside
-    (let ((erc-modified-channels-update-inside t))
+    (let ((erc-modified-channels-update-inside t)
+         (removed-channel nil))
       (mapcar (lambda (elt)
                (let ((buffer (car elt)))
                  (when (or (not (bufferp buffer))
                            (not (buffer-live-p buffer))
                            (erc-buffer-visible buffer)
+                           (and erc-track-remove-disconnected-buffers
                            (not (with-current-buffer buffer
-                                  erc-server-connected)))
+                                       erc-server-connected))))
+                   (setq removed-channel t)
                    (erc-modified-channels-remove-buffer buffer))))
              erc-modified-channels-alist)
+      (when removed-channel
       (erc-modified-channels-display)
-      (force-mode-line-update t))))
+       (force-mode-line-update t)))))
 
 (defvar erc-track-mouse-face (if (featurep 'xemacs)
                                 'modeline-mousable
@@ -729,10 +760,13 @@ If FACES are provided, color STRING with them."
   "Set `erc-modified-channels-object'
 according to `erc-modified-channels-alist'.
 Use `erc-make-mode-line-buffer-name' to create buttons."
-  (if (or
-       (eq 'mostactive erc-track-switch-direction)
-       (eq 'leastactive erc-track-switch-direction))
-      (erc-track-sort-by-activest))
+  (cond ((or (eq 'mostactive erc-track-switch-direction)
+            (eq 'leastactive erc-track-switch-direction))
+        (erc-track-sort-by-activest))
+       ((eq 'importance erc-track-switch-direction)
+        (erc-track-sort-by-importance)))
+  (run-hooks 'erc-track-list-changed-hook)
+  (unless (eq erc-track-position-in-mode-line nil)
   (if (null erc-modified-channels-alist)
       (setq erc-modified-channels-object (erc-modified-channels-object nil))
     ;; erc-modified-channels-alist contains all the data we need.  To
@@ -768,7 +802,7 @@ Use `erc-make-mode-line-buffer-name' to create buttons."
       (when (featurep 'xemacs)
        (erc-modified-channels-object nil))
       (setq erc-modified-channels-object
-           (erc-modified-channels-object strings)))))
+             (erc-modified-channels-object strings))))))
 
 (defun erc-modified-channels-remove-buffer (buffer)
   "Remove BUFFER from `erc-modified-channels-alist'."
@@ -802,8 +836,7 @@ is in `erc-mode'."
     (if (and (not (erc-buffer-visible (current-buffer)))
             (not (member this-channel erc-track-exclude))
             (not (and erc-track-exclude-server-buffer
-                      (string= this-channel
-                               (buffer-name (erc-server-buffer)))))
+                      (erc-server-buffer-p)))
             (not (erc-message-type-member
                   (or (erc-find-parsed-property)
                       (point-min))
@@ -847,10 +880,10 @@ is in `erc-mode'."
            (erc-modified-channels-display)))
       ;; Else if the active buffer is the current buffer, remove it
       ;; from our list.
-      (when (or (erc-buffer-visible (current-buffer))
+      (when (and (or (erc-buffer-visible (current-buffer))
                (and this-channel
-                    (assq (current-buffer) erc-modified-channels-alist)
                     (member this-channel erc-track-exclude)))
+                (assq (current-buffer) erc-modified-channels-alist))
        ;; Remove it from mode-line if buffer is visible or
        ;; channel was added to erc-track-exclude recently.
        (erc-modified-channels-remove-buffer (current-buffer))
@@ -887,6 +920,29 @@ That means the number of unseen messages in a channel."
        (sort erc-modified-channels-alist
              (lambda (a b) (> (nth 1 a) (nth 1 b))))))
 
+(defun erc-track-face-priority (face)
+  "Return a number indicating the priority of FACE in
+`erc-track-faces-priority-list'.  Lower number means higher
+priority.
+
+If face is not in `erc-track-faces-priority-list', it will have a
+higher number than any other face in that list."
+  (let ((count 0))
+    (catch 'done
+      (dolist (item erc-track-faces-priority-list)
+       (if (eq item face)
+           (throw 'done t)
+         (setq count (1+ count)))))
+    count))
+
+(defun erc-track-sort-by-importance ()
+  "Sort erc-modified-channels-alist by importance.
+That means the position of the face in `erc-track-faces-priority-list'."
+  (setq erc-modified-channels-alist
+       (sort erc-modified-channels-alist
+             (lambda (a b) (< (erc-track-face-priority (cddr a))
+                              (erc-track-face-priority (cddr b)))))))
+
 (defun erc-track-get-active-buffer (arg)
   "Return the buffer name of ARG in `erc-modified-channels-alist'.
 Negative arguments index in the opposite direction.  This direction is
@@ -898,7 +954,8 @@ relative to `erc-track-switch-direction'"
                  (oldest      'newest)
                  (newest      'oldest)
                  (mostactive  'leastactive)
-                 (leastactive 'mostactive)))
+                 (leastactive 'mostactive)
+                 (importance  'oldest)))
       (setq arg (- arg)))
     (setq offset (case dir
                   ((oldest leastactive)
index 2ebadd1..2c5786a 100644 (file)
@@ -66,7 +66,7 @@
 
 ;;; Code:
 
-(defconst erc-version-string "Version 5.2"
+(defconst erc-version-string "Version 5.3 (devel)"
   "ERC version.  This is used by function `erc-version'.")
 
 (eval-when-compile (require 'cl))
@@ -836,8 +836,9 @@ See `erc-server-flood-margin' for other flood-related parameters.")
 ;; Script parameters
 
 (defcustom erc-startup-file-list
-  '("~/.emacs.d/.ercrc.el" "~/.emacs.d/.ercrc"
-    "~/.ercrc.el" "~/.ercrc" ".ercrc.el" ".ercrc")
+  (list (concat erc-user-emacs-directory ".ercrc.el")
+       (concat erc-user-emacs-directory ".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.
 
@@ -1460,7 +1461,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 "6667"
+(defconst erc-default-port 6667
   "IRC port to use if it cannot be detected otherwise.")
 
 (defcustom erc-join-buffer 'buffer
@@ -1491,6 +1492,14 @@ This only has effect when `erc-join-buffer' is set to `frame'."
   :group 'erc-buffers
   :type 'boolean)
 
+(defcustom erc-reuse-frames t
+  "*Determines whether new frames are always created.
+Non-nil means that a new frame is not created to display an ERC
+buffer if there is already a window displaying it.  This only has
+effect when `erc-join-buffer' is set to `frame'."
+  :group 'erc-buffers
+  :type 'boolean)
+
 (defun erc-channel-p (channel)
   "Return non-nil if CHANNEL seems to be an IRC channel name."
   (cond ((stringp channel)
@@ -1888,14 +1897,16 @@ removed from the list will be disabled."
        ((eq erc-join-buffer 'bury)
         nil)
        ((eq erc-join-buffer 'frame)
-        (funcall '(lambda (frame)
+        (when (or (not erc-reuse-frames)
+                  (not (get-buffer-window buffer t)))
+          ((lambda (frame)
                     (raise-frame frame)
                     (select-frame frame))
                  (make-frame (or erc-frame-alist
                                  default-frame-alist)))
         (switch-to-buffer buffer)
         (when erc-frame-dedicated-flag
-          (set-window-dedicated-p (selected-window) t)))
+          (set-window-dedicated-p (selected-window) t))))
        (t
         (if (active-minibuffer-window)
             (display-buffer buffer)
@@ -2155,16 +2166,48 @@ Arguments are the same as for `erc'."
   "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 'tls)
-    (let ((proc (open-tls-stream name buffer host port)))
+  (when (condition-case nil
+           (require 'ssl)
+         (error (message "You don't have ssl.el.  %s"
+                         "Try using `erc-tls' instead.")
+                nil))
+    (let ((proc (open-ssl-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.
-      ;; Disabled when switching to tls.el -- jas
-      ;(sit-for 5)
+      (sit-for 5)
       proc)))
 
+(defun erc-tls (&rest r)
+  "Interactively select TLS connection parameters and run ERC.
+Arguments are the same as for `erc'."
+  (interactive (erc-select-read-args))
+  (let ((erc-server-connect-function 'erc-open-tls-stream))
+    (apply 'erc r)))
+
+(defun erc-open-tls-stream (name buffer host port)
+  "Open an TLS stream to an IRC server.
+The process will be given the name NAME, its target buffer will be
+BUFFER.  HOST and PORT specify the connection target."
+  (when (condition-case nil
+           (require 'tls)
+         (error (message "You don't have tls.el.  %s"
+                         "Try using `erc-ssl' instead.")
+                nil))
+    (open-tls-stream name buffer host port)))
+
+;;; Displaying error messages
+
+(defun erc-error (&rest args)
+  "Pass ARGS to `format', and display the result as an error message.
+If `debug-on-error' is set to non-nil, then throw a real error with this
+message instead, to make debugging easier."
+  (if debug-on-error
+      (apply #'error args)
+    (apply #'message args)
+    (beep)))
+
 ;;; Debugging the protocol
 
 (defvar erc-debug-irc-protocol nil
@@ -2456,6 +2499,14 @@ See also `erc-server-send'."
        (match-string 1 arglist)
       arglist)))
 
+(defun erc-command-no-process-p (str)
+  "Return non-nil if STR is an ERC command that can be run when the process
+is not alive, nil otherwise."
+  (let ((fun (erc-extract-command-from-line str)))
+    (and fun
+        (symbolp (car fun))
+        (get (car fun) 'process-not-needed))))
+
 (defun erc-command-name (cmd)
   "For CMD being the function name of a ERC command, something like
 erc-cmd-FOO, this returns a string /FOO."
@@ -2565,6 +2616,7 @@ VALUE is computed by evaluating the rest of LINE in Lisp."
 (defalias 'erc-cmd-VAR 'erc-cmd-SET)
 (defalias 'erc-cmd-VARIABLE 'erc-cmd-SET)
 (put 'erc-cmd-SET 'do-not-parse-args t)
+(put 'erc-cmd-SET 'process-not-needed t)
 
 (defun erc-cmd-default (line)
   "Fallback command.
@@ -2623,6 +2675,7 @@ If no USER argument is specified, list the contents of `erc-ignore-list'."
   "Clear the window content."
   (recenter 0)
   t)
+(put 'erc-cmd-CLEAR 'process-not-needed t)
 
 (defun erc-cmd-OPS ()
   "Show the ops in the current channel."
@@ -2656,6 +2709,7 @@ If no USER argument is specified, list the contents of `erc-ignore-list'."
       (erc-display-message
        nil 'notice 'active 'country-unknown ?d tld))
   t))
+(put 'erc-cmd-COUNTRY 'process-not-needed t)
 
 (defun erc-cmd-AWAY (line)
   "Mark the user as being away, the reason being indicated by LINE.
@@ -2736,6 +2790,7 @@ For a list of user commands (/join /part, ...):
     t))
 
 (defalias 'erc-cmd-H 'erc-cmd-HELP)
+(put 'erc-cmd-HELP 'process-not-needed t)
 
 (defun erc-cmd-JOIN (channel &optional key)
   "Join the channel given in CHANNEL, optionally with KEY.
@@ -2973,6 +3028,7 @@ the matching is case-sensitive."
   (occur line)
   t)
 (put 'erc-cmd-LASTLOG 'do-not-parse-args t)
+(put 'erc-cmd-LASTLOG 'process-not-needed t)
 
 (defun erc-send-message (line &optional force)
   "Send LINE to the current channel or user and display it.
@@ -3195,20 +3251,34 @@ the message given by REASON."
 (defalias 'erc-cmd-EXIT 'erc-cmd-QUIT)
 (defalias 'erc-cmd-SIGNOFF 'erc-cmd-QUIT)
 (put 'erc-cmd-QUIT 'do-not-parse-args t)
+(put 'erc-cmd-QUIT 'process-not-needed t)
 
 (defun erc-cmd-GQUIT (reason)
   "Disconnect from all servers at once with the same quit REASON."
   (erc-with-all-buffers-of-server nil #'erc-open-server-buffer-p
-                                 (erc-cmd-QUIT reason)))
+                                 (erc-cmd-QUIT reason))
+  (when erc-kill-queries-on-quit
+    ;; if the query buffers have not been killed within 4 seconds,
+    ;; kill them
+    (run-at-time
+     4 nil
+     (lambda ()
+       (dolist (buffer (erc-buffer-list (lambda (buf)
+                                         (not (erc-server-buffer-p buf)))))
+        (kill-buffer buffer)))))
+  t)
 
 (defalias 'erc-cmd-GQ 'erc-cmd-GQUIT)
 (put 'erc-cmd-GQUIT 'do-not-parse-args t)
+(put 'erc-cmd-GQUIT 'process-not-needed t)
 
 (defun erc-cmd-RECONNECT ()
   "Try to reconnect to the current IRC server."
-  (let ((buffer (or (erc-server-buffer) (current-buffer)))
+  (let ((buffer (erc-server-buffer))
        (process nil))
-    (with-current-buffer (if (bufferp buffer) buffer (current-buffer))
+    (unless (buffer-live-p buffer)
+      (setq buffer (current-buffer)))
+    (with-current-buffer buffer
       (setq erc-server-quitting nil)
       (setq erc-server-reconnecting t)
       (setq erc-server-reconnect-count 0)
@@ -3218,6 +3288,7 @@ the message given by REASON."
        (erc-server-reconnect))
       (setq erc-server-reconnecting nil)))
   t)
+(put 'erc-cmd-RECONNECT 'process-not-needed t)
 
 (defun erc-cmd-SERVER (server)
   "Connect to SERVER, leaving existing connection intact."
@@ -3225,9 +3296,9 @@ the message given by REASON."
   (condition-case nil
       (erc :server server :nick (erc-current-nick))
     (error
-     (message "Cannot find host %s." server)
-     (beep)))
+     (erc-error "Cannot find host %s." server)))
   t)
+(put 'erc-cmd-SERVER 'process-not-needed t)
 
 (eval-when-compile
   (defvar motif-version-string)
@@ -4411,33 +4482,65 @@ See also `erc-channel-begin-receiving-names'."
           erc-channel-users)
   (setq erc-channel-new-member-names nil))
 
+(defun erc-parse-prefix ()
+  "Return an alist of valid prefix character types and their representations.
+Example: (operator) o => @, (voiced) v => +."
+  (let ((str (or (cdr (assoc "PREFIX" (erc-with-server-buffer
+                                       erc-server-parameters)))
+                ;; provide a sane default
+                "(ov)@+"))
+       types chars)
+    (when (string-match "^(\\([^)]+\\))\\(.+\\)$" str)
+      (setq types (match-string 1 str)
+           chars (match-string 2 str))
+      (let ((len (min (length types) (length chars)))
+           (i 0)
+           (alist nil))
+       (while (< i len)
+         (setq alist (cons (cons (elt types i) (elt chars i))
+                           alist))
+         (setq i (1+ i)))
+       alist))))
+
 (defun erc-channel-receive-names (names-string)
   "This function is for internal use only.
 
 Update `erc-channel-users' according to NAMES-STRING.
 NAMES-STRING is a string listing some of the names on the
 channel."
-  (let (names name op voice)
-      ;; We need to delete "" because in XEmacs, (split-string "a ")
-      ;; returns ("a" "").
-      (setq names (delete "" (split-string names-string)))
-      (let ((erc-channel-members-changed-hook nil))
-       (dolist (item names)
-         (cond ((string-match "^@\\(.*\\)$" item)
-                (setq name (match-string 1 item)
-                      op 'on
-                      voice 'off))
-               ((string-match "^+\\(.*\\)$" item)
-                (setq name (match-string 1 item)
-                      op 'off
-                      voice 'on))
-               (t (setq name item
-                        op 'off
-                        voice 'off)))
-       (puthash (erc-downcase name) t
-                erc-channel-new-member-names)
-       (erc-update-current-channel-member
-        name name t op voice)))
+  (let (prefix op-ch voice-ch names name op voice)
+    (setq prefix (erc-parse-prefix))
+    (setq op-ch (cdr (assq ?o prefix))
+         voice-ch (cdr (assq ?v prefix)))
+    ;; We need to delete "" because in XEmacs, (split-string "a ")
+    ;; returns ("a" "").
+    (setq names (delete "" (split-string names-string)))
+    (let ((erc-channel-members-changed-hook nil))
+      (dolist (item names)
+       (let ((updatep t)
+             ch)
+         (if (rassq (elt item 0) prefix)
+             (cond ((= (length item) 1)
+                    (setq updatep nil))
+                   ((eq (elt item 0) op-ch)
+                    (setq name (substring item 1)
+                          op 'on
+                          voice 'off))
+                   ((eq (elt item 0) voice-ch)
+                    (setq name (substring item 1)
+                          op 'off
+                          voice 'on))
+                   (t (setq name (substring item 1)
+                            op 'off
+                            voice 'off)))
+           (setq name item
+                 op 'off
+                 voice 'off))
+         (when updatep
+           (puthash (erc-downcase name) t
+                    erc-channel-new-member-names)
+           (erc-update-current-channel-member
+            name name t op voice)))))
     (run-hooks 'erc-channel-members-changed-hook)))
 
 (defcustom erc-channel-members-changed-hook nil
@@ -4529,15 +4632,15 @@ See also: `erc-update-user' and `erc-update-channel-member'."
              (setq changed t)
            (setf (erc-channel-user-op cuser)
                  (cond ((eq op 'on) t)
-                                  ((eq op 'off) nil)
-                                  (t op))))
+                       ((eq op 'off) nil)
+                       (t op))))
          (when (and voice
                     (not (eq (erc-channel-user-voice cuser) voice)))
              (setq changed t)
            (setf (erc-channel-user-voice cuser)
                  (cond ((eq voice 'on) t)
-                                     ((eq voice 'off) nil)
-                                     (t voice))))
+                       ((eq voice 'off) nil)
+                       (t voice))))
          (when update-message-time
            (setf (erc-channel-user-last-message-time cuser) (current-time)))
          (setq user-changed
@@ -4559,11 +4662,11 @@ See also: `erc-update-user' and `erc-update-channel-member'."
                      (erc-server-user-buffers user))))
        (setq cuser (make-erc-channel-user
                     :op (cond ((eq op 'on) t)
-                                      ((eq op 'off) nil)
-                                      (t op))
+                              ((eq op 'off) nil)
+                              (t op))
                     :voice (cond ((eq voice 'on) t)
-                                      ((eq voice 'off) nil)
-                                      (t voice))
+                                 ((eq voice 'off) nil)
+                                 (t voice))
                     :last-message-time
                     (if update-message-time (current-time))))
        (puthash (erc-downcase nick) (cons user cuser)
@@ -4892,39 +4995,37 @@ Specifically, return the position of `erc-insert-marker'."
   (interactive)
   (save-restriction
     (widen)
-    (cond
-     ((< (point) (erc-beg-of-input-line))
-      (message "Point is not in the input area")
-      (beep))
-     ((not (erc-server-buffer-live-p))
-      (message "ERC: No process running")
-      (beep))
-     (t
-      (erc-set-active-buffer (current-buffer))
+    (if (< (point) (erc-beg-of-input-line))
+       (erc-error "Point is not in the input area")
       (let ((inhibit-read-only t)
            (str (erc-user-input))
            (old-buf (current-buffer)))
-
-       ;; Kill the input and the prompt
-       (delete-region (erc-beg-of-input-line)
-                      (erc-end-of-input-line))
-
-       (unwind-protect
-           (erc-send-input str)
-         ;; Fix the buffer if the command didn't kill it
-         (when (buffer-live-p old-buf)
-           (with-current-buffer old-buf
-             (save-restriction
-               (widen)
-               (goto-char (point-max))
-               (set-marker (process-mark erc-server-process) (point))
-               (set-marker erc-insert-marker (point))
-               (let ((buffer-modified (buffer-modified-p)))
-                 (erc-display-prompt)
-                 (set-buffer-modified-p buffer-modified))))))
-
-       ;; Only when last hook has been run...
-       (run-hook-with-args 'erc-send-completed-hook str))))))
+       (if (and (not (erc-server-buffer-live-p))
+                (not (erc-command-no-process-p str)))
+           (erc-error "ERC: No process running")
+         (erc-set-active-buffer (current-buffer))
+
+         ;; Kill the input and the prompt
+         (delete-region (erc-beg-of-input-line)
+                        (erc-end-of-input-line))
+
+         (unwind-protect
+             (erc-send-input str)
+           ;; Fix the buffer if the command didn't kill it
+           (when (buffer-live-p old-buf)
+             (with-current-buffer old-buf
+               (save-restriction
+                 (widen)
+                 (goto-char (point-max))
+                 (when (processp erc-server-process)
+                   (set-marker (process-mark erc-server-process) (point)))
+                 (set-marker erc-insert-marker (point))
+                 (let ((buffer-modified (buffer-modified-p)))
+                   (erc-display-prompt)
+                   (set-buffer-modified-p buffer-modified))))))
+
+         ;; Only when last hook has been run...
+         (run-hook-with-args 'erc-send-completed-hook str))))))
 
 (defun erc-user-input ()
   "Return the input of the user in the current buffer."
@@ -4985,7 +5086,8 @@ This returns non-nil only if we actually send anything."
        (erc-put-text-property beg (point)
                               'face 'erc-command-indicator-face)
        (insert "\n"))
-      (set-marker (process-mark erc-server-process) (point))
+      (when (processp erc-server-process)
+       (set-marker (process-mark erc-server-process) (point)))
       (set-marker erc-insert-marker (point))
       (save-excursion
        (save-restriction
@@ -5004,7 +5106,8 @@ current position."
        (erc-put-text-property beg (point)
                               'face 'erc-input-face))
       (insert "\n")
-      (set-marker (process-mark erc-server-process) (point))
+      (when (processp erc-server-process)
+       (set-marker (process-mark erc-server-process) (point)))
       (set-marker erc-insert-marker (point))
       (save-excursion
        (save-restriction