summaryrefslogtreecommitdiff
path: root/lisp/net/rcirc.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/net/rcirc.el')
-rw-r--r--lisp/net/rcirc.el201
1 files changed, 136 insertions, 65 deletions
diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index b4f97466baa..964f9c44ccc 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -1,9 +1,11 @@
;;; rcirc.el --- default, simple IRC client.
-;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+;; Free Software Foundation, Inc.
-;; Author: Ryan Yeske
-;; URL: http://www.nongnu.org/rcirc
+;; Author: Ryan Yeske <rcyeske@gmail.com>
+;; Maintainers: Ryan Yeske <rcyeske@gmail.com>,
+;; Deniz Dogan <deniz.a.m.dogan@gmail.com>
;; Keywords: comm
;; This file is part of GNU Emacs.
@@ -114,15 +116,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)
@@ -375,6 +377,9 @@ and the cdr part is used for encoding."
(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'.
@@ -399,8 +404,12 @@ If ARG is non-nil, instead prompt for connection parameters."
(or (plist-get server-plist :nick)
rcirc-default-nick)
'rcirc-nick-name-history))
- (password (read-passwd "IRC Password: "
- (plist-get server-plist 'password)))
+ (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
@@ -408,11 +417,7 @@ If ARG is non-nil, instead prompt for connection parameters."
:channels)
" "))
"[, ]+" t)))
-
- (when (= 0 (length password))
- (setq password nil))
-
- (rcirc-connect server port nick rcirc-default-user-name
+ (rcirc-connect server port nick user-name
rcirc-default-full-name
channels password))
;; connect to servers in `rcirc-server-alist'
@@ -466,8 +471,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 password)
+(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)
@@ -520,8 +525,7 @@ If ARG is non-nil, instead prompt for connection parameters."
(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
@@ -771,42 +775,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."
@@ -824,7 +850,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)
@@ -870,6 +896,7 @@ Each element looks like (FILENAME . TEXT).")
This number is independent of the number of lines in the buffer.")
(defun rcirc-mode (process target)
+ ;; FIXME: Use define-derived-mode.
"Major mode for IRC channel buffers.
\\{rcirc-mode-map}"
@@ -945,7 +972,10 @@ This number is independent of the number of lines in the buffer.")
rcirc-buffer-alist))))
(rcirc-update-short-buffer-names))
- (run-hooks 'rcirc-mode-hook))
+ (add-hook 'completion-at-point-functions
+ 'rcirc-completion-at-point nil 'local)
+
+ (run-mode-hooks 'rcirc-mode-hook))
(defun rcirc-update-prompt (&optional all)
"Reset the prompt string in the current buffer.
@@ -1339,6 +1369,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."
@@ -1504,14 +1540,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
@@ -1648,6 +1691,31 @@ if NICK is also on `rcirc-ignore-list-automatic'."
rcirc-ignore-list
(delete nick rcirc-ignore-list))))
+(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)))
+
;;; activity tracking
(defvar rcirc-track-minor-mode-map (make-sparse-keymap)
"Keymap for rcirc track minor mode.")
@@ -1963,16 +2031,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."
@@ -2561,7 +2631,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)