]> code.delx.au - gnu-emacs/blobdiff - lisp/net/rcirc.el
* net/dbus.el (dbus-unregister-service): Translate returned
[gnu-emacs] / lisp / net / rcirc.el
index eda3f1aeaeef5df22b77e47798d79331c2720c14..093892a11004bbcd47eba01a433d6647f177526d 100644 (file)
@@ -1,6 +1,7 @@
 ;;; rcirc.el --- default, simple IRC client.
 
-;; Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
+;;   Free Software Foundation, Inc.
 
 ;; Author: Ryan Yeske
 ;; URL: http://www.nongnu.org/rcirc
@@ -8,20 +9,18 @@
 
 ;; This file is part of GNU Emacs.
 
-;; This file is free software; you can redistribute it and/or modify
+;; 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 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
-;; This file is distributed in the hope that it will be useful,
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -30,7 +29,7 @@
 ;; communication in discussion forums called channels, but also allows
 ;; one-to-one communication.
 
-;; Rcirc has simple defaults and clear and consistent behaviour.
+;; Rcirc has simple defaults and clear and consistent behavior.
 ;; Message arrival timestamps, activity notification on the modeline,
 ;; message filling, nick completion, and keepalive pings are all
 ;; enabled by default, but can easily be adjusted or turned off.  Each
@@ -82,6 +81,11 @@ VALUE must be a number or string.  If absent,
 VALUE must be a string.  If absent, `rcirc-default-user-name' is
 used.
 
+`:password'
+
+VALUE must be a string.  If absent, no PASS command will be sent
+to the server.
+
 `:full-name'
 
 VALUE must be a string.  If absent, `rcirc-default-full-name' is
@@ -96,6 +100,7 @@ connected to automatically."
                :value-type (plist :options ((:nick string)
                                             (:port integer)
                                             (:user-name string)
+                                            (:password string)
                                             (:full-name string)
                                             (:channels (repeat string)))))
   :group 'rcirc)
@@ -110,15 +115,15 @@ connected to automatically."
   :type 'string
   :group 'rcirc)
 
-(defcustom rcirc-default-user-name (user-login-name)
+(defcustom rcirc-default-user-name "user"
   "Your user name sent to the server when connecting."
+  :version "24.1"                       ; changed default
   :type 'string
   :group 'rcirc)
 
-(defcustom rcirc-default-full-name (if (string= (user-full-name) "")
-                                      rcirc-default-user-name
-                                    (user-full-name))
+(defcustom rcirc-default-full-name "unknown"
   "The full name sent to the server when connecting."
+  :version "24.1"                       ; changed default
   :type 'string
   :group 'rcirc)
 
@@ -195,15 +200,16 @@ and a method symbol followed by method specific arguments.
 The valid METHOD symbols are `nickserv', `chanserv' and
 `bitlbee'.
 
-The required ARGUMENTS for each METHOD symbol are:
-  `nickserv': NICK PASSWORD
+The ARGUMENTS for each METHOD symbol are:
+  `nickserv': NICK PASSWORD [NICKSERV-NICK]
   `chanserv': NICK CHANNEL PASSWORD
   `bitlbee': NICK PASSWORD
 
-Example:
+Examples:
  ((\"freenode\" nickserv \"bob\" \"p455w0rd\")
   (\"freenode\" chanserv \"bob\" \"#bobland\" \"passwd99\")
-  (\"bitlbee\" bitlbee \"robert\" \"sekrit\"))"
+  (\"bitlbee\" bitlbee \"robert\" \"sekrit\")
+  (\"dal.net\" nickserv \"bob\" \"sekrit\" \"NickServ@services.dal.net\"))"
   :type '(alist :key-type (string :tag "Server")
                :value-type (choice (list :tag "NickServ"
                                          (const nickserv)
@@ -361,6 +367,18 @@ and the cdr part is used for encoding."
 \f
 (defvar rcirc-startup-channels nil)
 
+(defvar rcirc-server-name-history nil
+  "History variable for \\[rcirc] call.")
+
+(defvar rcirc-server-port-history nil
+  "History variable for \\[rcirc] call.")
+
+(defvar rcirc-nick-name-history nil
+  "History variable for \\[rcirc] call.")
+
+(defvar rcirc-user-name-history nil
+  "History variable for \\[rcirc] call.")
+
 ;;;###autoload
 (defun rcirc (arg)
   "Connect to all servers in `rcirc-server-alist'.
@@ -373,25 +391,34 @@ If ARG is non-nil, instead prompt for connection parameters."
       (let* ((server (completing-read "IRC Server: "
                                      rcirc-server-alist
                                      nil nil
-                                     (caar rcirc-server-alist)))
+                                     (caar rcirc-server-alist)
+                                     'rcirc-server-name-history))
             (server-plist (cdr (assoc-string server rcirc-server-alist)))
             (port (read-string "IRC Port: "
                                (number-to-string
-                                (or (plist-get server-plist 'port)
-                                    rcirc-default-port))))
+                                (or (plist-get server-plist :port)
+                                    rcirc-default-port))
+                               'rcirc-server-port-history))
             (nick (read-string "IRC Nick: "
-                               (or (plist-get server-plist 'nick)
-                                   rcirc-default-nick)))
+                               (or (plist-get server-plist :nick)
+                                   rcirc-default-nick)
+                               'rcirc-nick-name-history))
+            (user-name (read-string "IRC Username: "
+                                     (or (plist-get server-plist :user-name)
+                                         rcirc-default-user-name)
+                                     'rcirc-user-name-history))
+            (password (read-passwd "IRC Password: " nil
+                                    (plist-get server-plist :password)))
             (channels (split-string
                        (read-string "IRC Channels: "
                                     (mapconcat 'identity
                                                (plist-get server-plist
-                                                          'channels)
+                                                          :channels)
                                                " "))
                        "[, ]+" t)))
-       (rcirc-connect server port nick rcirc-default-user-name
+       (rcirc-connect server port nick user-name
                       rcirc-default-full-name
-                      channels))
+                      channels password))
     ;; connect to servers in `rcirc-server-alist'
     (let (connected-servers)
       (dolist (c rcirc-server-alist)
@@ -402,7 +429,8 @@ If ARG is non-nil, instead prompt for connection parameters."
                             rcirc-default-user-name))
              (full-name (or (plist-get (cdr c) :full-name)
                             rcirc-default-full-name))
-             (channels (plist-get (cdr c) :channels)))
+             (channels (plist-get (cdr c) :channels))
+              (password (plist-get (cdr c) :password)))
          (when server
            (let (connected)
              (dolist (p (rcirc-process-list))
@@ -411,7 +439,7 @@ If ARG is non-nil, instead prompt for connection parameters."
              (if (not connected)
                  (condition-case e
                      (rcirc-connect server port nick user-name
-                                    full-name channels)
+                                    full-name channels password)
                    (quit (message "Quit connecting to %s" server)))
                (with-current-buffer (process-buffer connected)
                  (setq connected-servers
@@ -442,8 +470,8 @@ If ARG is non-nil, instead prompt for connection parameters."
 (defvar rcirc-process nil)
 
 ;;;###autoload
-(defun rcirc-connect (server &optional port nick user-name full-name
-                            startup-channels)
+(defun rcirc-connect (server &optional port nick user-name
+                             full-name startup-channels password)
   (save-excursion
     (message "Connecting to %s..." server)
     (let* ((inhibit-eol-conversion)
@@ -492,10 +520,11 @@ If ARG is non-nil, instead prompt for connection parameters."
       (add-hook 'auto-save-hook 'rcirc-log-write)
 
       ;; identify
+      (when password
+        (rcirc-send-string process (concat "PASS " password)))
       (rcirc-send-string process (concat "NICK " nick))
       (rcirc-send-string process (concat "USER " user-name
-                                      " hostname servername :"
-                                      full-name))
+                                         " 0 * :" full-name))
 
       ;; setup ping timer if necessary
       (unless rcirc-keepalive-timer
@@ -528,8 +557,10 @@ last ping."
                  (rcirc-send-string process
                                     (format "PRIVMSG %s :\C-aKEEPALIVE %f\C-a"
                                             rcirc-nick
-                                            (time-to-seconds
-                                             (current-time)))))))
+                                             (if (featurep 'xemacs)
+                                                 (time-to-seconds
+                                                  (current-time))
+                                               (float-time)))))))
             (rcirc-process-list))
     ;; no processes, clean up timer
     (cancel-timer rcirc-keepalive-timer)
@@ -537,7 +568,10 @@ last ping."
 
 (defun rcirc-handler-ctcp-KEEPALIVE (process target sender message)
   (with-rcirc-process-buffer process
-    (setq header-line-format (format "%f" (- (time-to-seconds (current-time))
+    (setq header-line-format (format "%f" (- (if (featurep 'xemacs)
+                                                 (time-to-seconds
+                                                  (current-time))
+                                               (float-time))
                                             (string-to-number message))))))
 
 (defvar rcirc-debug-buffer " *rcirc debug*")
@@ -548,8 +582,7 @@ last ping."
 Debug text is written to `rcirc-debug-buffer' if `rcirc-debug-flag'
 is non-nil."
   (when rcirc-debug-flag
-    (save-excursion
-      (set-buffer (get-buffer-create rcirc-debug-buffer))
+    (with-current-buffer (get-buffer-create rcirc-debug-buffer)
       (goto-char (point-max))
       (insert (concat
               "["
@@ -741,42 +774,64 @@ If SILENT is non-nil, do not print the message in any irc buffer."
     (setq rcirc-input-ring-index (1- rcirc-input-ring-index))
     (insert (rcirc-prev-input-string -1))))
 
-(defvar rcirc-nick-completions nil)
-(defvar rcirc-nick-completion-start-offset nil)
-
-(defun rcirc-complete-nick ()
-  "Cycle through nick completions from list of nicks in channel."
+(defvar rcirc-server-commands
+  '("/admin"   "/away"   "/connect" "/die"      "/error"   "/info"
+    "/invite"  "/ison"   "/join"    "/kick"     "/kill"    "/links"
+    "/list"    "/lusers" "/mode"    "/motd"     "/names"   "/nick"
+    "/notice"  "/oper"   "/part"    "/pass"     "/ping"    "/pong"
+    "/privmsg" "/quit"   "/rehash"  "/restart"  "/service" "/servlist"
+    "/server"  "/squery" "/squit"   "/stats"    "/summon"  "/time"
+    "/topic"   "/trace"  "/user"    "/userhost" "/users"   "/version"
+    "/wallops" "/who"    "/whois"   "/whowas")
+  "A list of user commands by IRC server.
+The value defaults to RFCs 1459 and 2812.")
+
+;; /me and /ctcp are not defined by `defun-rcirc-command'.
+(defvar rcirc-client-commands '("/me" "/ctcp")
+  "A list of user commands defined by IRC client rcirc.
+The list is updated automatically by `defun-rcirc-command'.")
+
+(defun rcirc-completion-at-point ()
+  "Function used for `completion-at-point-functions' in `rcirc-mode'."
+  (let* ((beg (save-excursion
+               (if (re-search-backward " " rcirc-prompt-end-marker t)
+                   (1+ (point))
+                 rcirc-prompt-end-marker)))
+        (table (if (and (= beg rcirc-prompt-end-marker)
+                        (eq (char-after beg) ?/))
+                   (delete-dups
+                    (nconc
+                     (sort (copy-sequence rcirc-client-commands) 'string-lessp)
+                     (sort (copy-sequence rcirc-server-commands) 'string-lessp)))
+                 (rcirc-channel-nicks (rcirc-buffer-process) rcirc-target))))
+    (list beg (point) table)))
+
+(defvar rcirc-completions nil)
+(defvar rcirc-completion-start nil)
+
+(defun rcirc-complete ()
+  "Cycle through completions from list of nicks in channel or IRC commands.
+IRC command completion is performed only if '/' is the first input char."
   (interactive)
   (if (eq last-command this-command)
-      (setq rcirc-nick-completions
-            (append (cdr rcirc-nick-completions)
-                    (list (car rcirc-nick-completions))))
-    (setq rcirc-nick-completion-start-offset
-          (- (save-excursion
-               (if (re-search-backward " " rcirc-prompt-end-marker t)
-                   (1+ (point))
-                 rcirc-prompt-end-marker))
-             rcirc-prompt-end-marker))
-    (setq rcirc-nick-completions
-          (let ((completion-ignore-case t))
-            (all-completions
-            (buffer-substring
-             (+ rcirc-prompt-end-marker
-                rcirc-nick-completion-start-offset)
-             (point))
-            (mapcar (lambda (x) (cons x nil))
-                    (rcirc-channel-nicks (rcirc-buffer-process)
-                                         rcirc-target))))))
-  (let ((completion (car rcirc-nick-completions)))
+      (setq rcirc-completions
+           (append (cdr rcirc-completions) (list (car rcirc-completions))))
+    (let ((completion-ignore-case t)
+         (table (rcirc-completion-at-point)))
+      (setq rcirc-completion-start (car table))
+      (setq rcirc-completions
+           (all-completions (buffer-substring rcirc-completion-start
+                                              (cadr table))
+                            (nth 2 table)))))
+  (let ((completion (car rcirc-completions)))
     (when completion
-      (delete-region (+ rcirc-prompt-end-marker
-                       rcirc-nick-completion-start-offset)
-                    (point))
-      (insert (concat completion
-                      (if (= (+ rcirc-prompt-end-marker
-                                rcirc-nick-completion-start-offset)
-                             rcirc-prompt-end-marker)
-                          ": "))))))
+      (delete-region rcirc-completion-start (point))
+      (insert
+       (concat completion
+              (cond
+               ((= (aref completion 0) ?/) " ")
+               ((= rcirc-completion-start rcirc-prompt-end-marker) ": ")
+               (t "")))))))
 
 (defun set-rcirc-decode-coding-system (coding-system)
   "Set the decode coding system used in this channel."
@@ -794,7 +849,7 @@ If SILENT is non-nil, do not print the message in any irc buffer."
 (define-key rcirc-mode-map (kbd "RET") 'rcirc-send-input)
 (define-key rcirc-mode-map (kbd "M-p") 'rcirc-insert-prev-input)
 (define-key rcirc-mode-map (kbd "M-n") 'rcirc-insert-next-input)
-(define-key rcirc-mode-map (kbd "TAB") 'rcirc-complete-nick)
+(define-key rcirc-mode-map (kbd "TAB") 'rcirc-complete)
 (define-key rcirc-mode-map (kbd "C-c C-b") 'rcirc-browse-url)
 (define-key rcirc-mode-map (kbd "C-c C-c") 'rcirc-edit-multiline)
 (define-key rcirc-mode-map (kbd "C-c C-j") 'rcirc-cmd-join)
@@ -821,6 +876,7 @@ If SILENT is non-nil, do not print the message in any irc buffer."
 
 (define-key rcirc-browse-url-map (kbd "RET") 'rcirc-browse-url-at-point)
 (define-key rcirc-browse-url-map (kbd "<mouse-2>") 'rcirc-browse-url-at-mouse)
+(define-key rcirc-browse-url-map [follow-link] 'mouse-face)
 
 (defvar rcirc-short-buffer-name nil
   "Generated abbreviation to use to indicate buffer activity.")
@@ -914,6 +970,9 @@ This number is independent of the number of lines in the buffer.")
                                       rcirc-buffer-alist))))
     (rcirc-update-short-buffer-names))
 
+  (add-hook 'completion-at-point-functions
+            'rcirc-completion-at-point nil 'local)
+
   (run-hooks 'rcirc-mode-hook))
 
 (defun rcirc-update-prompt (&optional all)
@@ -1052,7 +1111,7 @@ Create the buffer if it doesn't exist."
     (when (not (equal 0 (- (point) rcirc-prompt-end-marker)))
       ;; delete a trailing newline
       (when (eq (point) (point-at-bol))
-       (delete-backward-char 1))
+       (delete-char -1))
       (let ((input (buffer-substring-no-properties
                    rcirc-prompt-end-marker (point))))
        (dolist (line (split-string input "\n"))
@@ -1308,6 +1367,12 @@ Logfiles are kept in `rcirc-log-directory'."
   :type 'integer
   :group 'rcirc)
 
+(defcustom rcirc-log-process-buffers nil
+  "Non-nil if rcirc process buffers should be logged to disk."
+  :group 'rcirc
+  :type 'boolean
+  :version "24.1")
+
 (defun rcirc-last-quit-line (process nick target)
   "Return the line number where NICK left TARGET.
 Returns nil if the information is not recorded."
@@ -1473,14 +1538,21 @@ record activity."
                                     (when (not (rcirc-channel-p rcirc-target))
                                       'nick)))
 
-       (when rcirc-log-flag
+       (when (and rcirc-log-flag
+                  (or target
+                      rcirc-log-process-buffers))
          (rcirc-log process sender response target text))
 
        (sit-for 0)                     ; displayed text before hook
        (run-hook-with-args 'rcirc-print-hooks
                            process sender response target text)))))
 
-(defcustom rcirc-log-filename-function 'rcirc-generate-new-buffer-name
+(defun rcirc-generate-log-filename (process target)
+  (if target
+      (rcirc-generate-new-buffer-name process target)
+    (process-name process)))
+
+(defcustom rcirc-log-filename-function 'rcirc-generate-log-filename
   "A function to generate the filename used by rcirc's logging facility.
 
 It is called with two arguments, PROCESS and TARGET (see
@@ -1523,6 +1595,14 @@ log-files with absolute names (see `rcirc-log-filename-function')."
        (write-region (point-min) (point-max) filename t 'quiet))))
   (setq rcirc-log-alist nil))
 
+(defun rcirc-view-log-file ()
+  "View logfile corresponding to the current buffer."
+  (interactive)
+  (find-file-other-window 
+   (expand-file-name (funcall rcirc-log-filename-function 
+                             (rcirc-buffer-process) rcirc-target)
+                    rcirc-log-directory)))
+
 (defun rcirc-join-channels (process channels)
   "Join CHANNELS."
   (save-window-excursion
@@ -1609,11 +1689,35 @@ if NICK is also on `rcirc-ignore-list-automatic'."
            rcirc-ignore-list
            (delete nick rcirc-ignore-list))))
 \f
+(defun rcirc-nickname< (s1 s2)
+  "Return t if IRC nickname S1 is less than S2, and nil otherwise.
+Operator nicknames (@) are considered less than voiced
+nicknames (+).  Any other nicknames are greater than voiced
+nicknames.  The comparison is case-insensitive."
+  (setq s1 (downcase s1)
+        s2 (downcase s2))
+  (let* ((s1-op (eq ?@ (string-to-char s1)))
+         (s2-op (eq ?@ (string-to-char s2))))
+    (if s1-op
+        (if s2-op
+            (string< (substring s1 1) (substring s2 1))
+          t)
+      (if s2-op
+          nil
+        (string< s1 s2)))))
+
+(defun rcirc-sort-nicknames-join (input sep)
+  "Return a string of sorted nicknames.
+INPUT is a string containing nicknames separated by SEP.
+This function does not alter the INPUT string."
+  (let* ((parts (split-string input sep t))
+         (sorted (sort parts 'rcirc-nickname<)))
+    (mapconcat 'identity sorted sep)))
+\f
 ;;; activity tracking
 (defvar rcirc-track-minor-mode-map (make-sparse-keymap)
   "Keymap for rcirc track minor mode.")
 
-(define-key rcirc-track-minor-mode-map (kbd "C-c `") 'rcirc-next-active-buffer)
 (define-key rcirc-track-minor-mode-map (kbd "C-c C-@") 'rcirc-next-active-buffer)
 (define-key rcirc-track-minor-mode-map (kbd "C-c C-SPC") 'rcirc-next-active-buffer)
 
@@ -1925,16 +2029,18 @@ activity.  Only run if the buffer is not visible and
 ;; containing the text following the /cmd.
 
 (defmacro defun-rcirc-command (command argument docstring interactive-form
-                                       &rest body)
+                                      &rest body)
   "Define a command."
-  `(defun ,(intern (concat "rcirc-cmd-" (symbol-name command)))
-     (,@argument &optional process target)
-     ,(concat docstring "\n\nNote: If PROCESS or TARGET are nil, the values given"
-              "\nby `rcirc-buffer-process' and `rcirc-target' will be used.")
-     ,interactive-form
-     (let ((process (or process (rcirc-buffer-process)))
-           (target (or target rcirc-target)))
-       ,@body)))
+  `(progn
+     (add-to-list 'rcirc-client-commands ,(concat "/" (symbol-name command)))
+     (defun ,(intern (concat "rcirc-cmd-" (symbol-name command)))
+       (,@argument &optional process target)
+       ,(concat docstring "\n\nNote: If PROCESS or TARGET are nil, the values given"
+               "\nby `rcirc-buffer-process' and `rcirc-target' will be used.")
+       ,interactive-form
+       (let ((process (or process (rcirc-buffer-process)))
+            (target (or target rcirc-target)))
+        ,@body))))
 
 (defun-rcirc-command msg (message)
   "Send private MESSAGE to TARGET."
@@ -1999,7 +2105,7 @@ activity.  Only run if the buffer is not visible and
   "Display list of names in CHANNEL or in current channel if CHANNEL is nil.
 If called interactively, prompt for a channel when prefix arg is supplied."
   (interactive "P")
-  (if (interactive-p)
+  (if (called-interactively-p 'interactive)
       (if channel
           (setq channel (read-string "List names in channel: " target))))
   (let ((channel (if (> (length channel) 0)
@@ -2011,7 +2117,7 @@ If called interactively, prompt for a channel when prefix arg is supplied."
   "List TOPIC for the TARGET channel.
 With a prefix arg, prompt for new topic."
   (interactive "P")
-  (if (and (interactive-p) topic)
+  (if (and (called-interactively-p 'interactive) topic)
       (setq topic (read-string "New Topic: " rcirc-topic)))
   (rcirc-send-string process (concat "TOPIC " target
                                      (when (> (length topic) 0)
@@ -2072,12 +2178,13 @@ With a prefix arg, prompt for new topic."
   (rcirc-send-string process (format "PRIVMSG %s :\C-aACTION %s\C-a"
                                      target args)))
 
-(defun rcirc-add-or-remove (set &optional elt)
-  (if (and elt (not (string= "" elt)))
-      (if (member-ignore-case elt set)
-         (delete elt set)
-       (cons elt set))
-    set))
+(defun rcirc-add-or-remove (set &rest elements)
+  (dolist (elt elements)
+    (if (and elt (not (string= "" elt)))
+       (setq set (if (member-ignore-case elt set)
+                     (delete elt set)
+                   (cons elt set)))))
+  set)
 
 (defun-rcirc-command ignore (nick)
   "Manage the ignore list.
@@ -2085,7 +2192,9 @@ Ignore NICK, unignore NICK if already ignored, or list ignored
 nicks when no NICK is given.  When listing ignored nicks, the
 ones added to the list automatically are marked with an asterisk."
   (interactive "sToggle ignoring of nick: ")
-  (setq rcirc-ignore-list (rcirc-add-or-remove rcirc-ignore-list nick))
+  (setq rcirc-ignore-list
+       (apply #'rcirc-add-or-remove rcirc-ignore-list
+              (split-string nick nil t)))
   (rcirc-print process nil "IGNORE" target
               (mapconcat
                (lambda (nick)
@@ -2097,14 +2206,18 @@ ones added to the list automatically are marked with an asterisk."
 (defun-rcirc-command bright (nick)
   "Manage the bright nick list."
   (interactive "sToggle emphasis of nick: ")
-  (setq rcirc-bright-nicks (rcirc-add-or-remove rcirc-bright-nicks nick))
+  (setq rcirc-bright-nicks
+       (apply #'rcirc-add-or-remove rcirc-bright-nicks
+              (split-string nick nil t)))
   (rcirc-print process nil "BRIGHT" target
               (mapconcat 'identity rcirc-bright-nicks " ")))
 
 (defun-rcirc-command dim (nick)
   "Manage the dim nick list."
   (interactive "sToggle deemphasis of nick: ")
-  (setq rcirc-dim-nicks (rcirc-add-or-remove rcirc-dim-nicks nick))
+  (setq rcirc-dim-nicks
+       (apply #'rcirc-add-or-remove rcirc-dim-nicks
+              (split-string nick nil t)))
   (rcirc-print process nil "DIM" target
               (mapconcat 'identity rcirc-dim-nicks " ")))
 
@@ -2113,7 +2226,9 @@ ones added to the list automatically are marked with an asterisk."
 Mark KEYWORD, unmark KEYWORD if already marked, or list marked
 keywords when no KEYWORD is given."
   (interactive "sToggle highlighting of keyword: ")
-  (setq rcirc-keywords (rcirc-add-or-remove rcirc-keywords keyword))
+  (setq rcirc-keywords
+       (apply #'rcirc-add-or-remove rcirc-keywords
+              (split-string keyword nil t)))
   (rcirc-print process nil "KEYWORD" target
               (mapconcat 'identity rcirc-keywords " ")))
 
@@ -2198,7 +2313,7 @@ keywords when no KEYWORD is given."
     (when (not (eq ?\C-o (char-before (match-end 2))))
       (delete-region (match-beginning 2) (match-end 2)))
     (delete-region (match-beginning 1) (match-end 1))
-    (goto-char (1+ (match-beginning 1))))
+    (goto-char (match-beginning 1)))
   ;; remove the ^O characters now
   (while (re-search-forward "\C-o+" nil t)
     (delete-region (match-beginning 0) (match-end 0))))
@@ -2514,7 +2629,8 @@ keywords when no KEYWORD is given."
          (buffer (rcirc-get-temp-buffer-create process channel)))
     (with-current-buffer buffer
       (rcirc-print process sender "NAMES" channel
-                   (buffer-substring (point-min) (point-max))))
+                   (let ((content (buffer-substring (point-min) (point-max))))
+                    (rcirc-sort-nicknames-join content " "))))
     (kill-buffer buffer)))
 
 (defun rcirc-handler-433 (process sender args text)
@@ -2540,9 +2656,8 @@ Passwords are stored in `rcirc-authinfo' (which see)."
          (cond ((equal method 'nickserv)
                 (rcirc-send-string
                  process
-                 (concat
-                  "PRIVMSG nickserv :identify "
-                  (car args))))
+                 (concat "PRIVMSG " (or (cadr args) "nickserv")
+                          " :identify " (car args))))
                ((equal method 'chanserv)
                 (rcirc-send-string
                  process