aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/net/rcirc.el993
1 files changed, 588 insertions, 405 deletions
diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index 7684494eb60..7df8e5a5603 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -25,12 +25,17 @@
25 25
26;;; Commentary: 26;;; Commentary:
27 27
28;; rcirc is an Internet Relay Chat (IRC) client for Emacs 28;; Internet Relay Chat (IRC) is a form of instant communication over
29 29;; the Internet. It is mainly designed for group (many-to-many)
30;; IRC is a form of instant communication over the Internet. It is 30;; communication in discussion forums called channels, but also allows
31;; mainly designed for group (many-to-many) communication in 31;; one-to-one communication.
32;; discussion forums called channels, but also allows one-to-one 32
33;; communication. 33;; Rcirc has simple defaults and clear and consistent behaviour.
34;; Message arrival timestamps, activity notification on the modeline,
35;; message filling, nick completion, and keepalive pings are all
36;; enabled by default, but can easily be adjusted or turned off. Each
37;; discussion takes place in its own buffer and there is a single
38;; server buffer per connection.
34 39
35;; Open a new irc connection with: 40;; Open a new irc connection with:
36;; M-x irc RET 41;; M-x irc RET
@@ -41,61 +46,101 @@
41(require 'time-date) 46(require 'time-date)
42(eval-when-compile (require 'cl)) 47(eval-when-compile (require 'cl))
43 48
44(defvar rcirc-server "irc.freenode.net" 49(defgroup rcirc nil
45 "The default server to connect to.") 50 "Simple IRC client."
51 :version "22.1"
52 :prefix "rcirc"
53 :group 'applications)
54
55(defcustom rcirc-server "irc.freenode.net"
56 "The default server to connect to."
57 :type 'string
58 :group 'rcirc)
46 59
47(defvar rcirc-port 6667 60(defcustom rcirc-port 6667
48 "The default port to connect to.") 61 "The default port to connect to."
62 :type 'integer
63 :group 'rcirc)
49 64
50(defvar rcirc-nick (user-login-name) 65(defcustom rcirc-nick (user-login-name)
51 "Your nick.") 66 "Your nick."
67 :type 'string
68 :group 'rcirc)
52 69
53(defvar rcirc-user-name (user-login-name) 70(defcustom rcirc-user-name (user-login-name)
54 "Your user name sent to the server when connecting.") 71 "Your user name sent to the server when connecting."
72 :type 'string
73 :group 'rcirc)
55 74
56(defvar rcirc-user-full-name (if (string= (user-full-name) "") 75(defcustom rcirc-user-full-name (if (string= (user-full-name) "")
57 rcirc-user-name 76 rcirc-user-name
58 (user-full-name)) 77 (user-full-name))
59 "The full name sent to the server when connecting.") 78 "The full name sent to the server when connecting."
79 :type 'string
80 :group 'rcirc)
60 81
61(defvar rcirc-startup-channels-alist nil 82(defcustom rcirc-startup-channels-alist nil
62 "Alist of channels to join at startup. 83 "Alist of channels to join at startup.
63Each element looks like (REGEXP . CHANNEL-LIST).") 84Each element looks like (SERVER-REGEXP . CHANNEL-LIST)."
85 :type '(alist :key-type string :value-type (repeat string))
86 :group 'rcirc)
64 87
65(defvar rcirc-fill-flag t 88(defcustom rcirc-fill-flag t
66 "*Non-nil means fill messages printed in channel buffers.") 89 "*Non-nil means line-wrap messages printed in channel buffers."
90 :type 'boolean
91 :group 'rcirc)
67 92
68(defvar rcirc-fill-column nil 93(defcustom rcirc-fill-column nil
69 "*If non-nil, fill to this column, otherwise use value of `fill-column'.") 94 "*Column beyond which automatic line-wrapping should happen.
95If nil, use value of `fill-column'. If frame-width, use the
96maximum frame width."
97 :type '(choice (const :tag "Value of `fill-column'")
98 (const :tag "Full frame width" frame-width)
99 (integer :tag "Number of columns"))
100 :group 'rcirc)
70 101
71(defvar rcirc-fill-prefix nil 102(defcustom rcirc-fill-prefix nil
72 "*Text to insert before filled lines. 103 "*Text to insert before filled lines.
73If nil, calculate the prefix dynamically to line up text 104If nil, calculate the prefix dynamically to line up text
74underneath each nick.") 105underneath each nick."
106 :type '(choice (const :tag "Dynamic" nil)
107 (string :tag "Prefix text"))
108 :group 'rcirc)
75 109
76(defvar rcirc-ignore-channel-activity nil 110(defvar rcirc-ignore-buffer-activity-flag nil
77 "If non-nil, ignore activity in this channel.") 111 "If non-nil, ignore activity in this buffer.")
78(make-variable-buffer-local 'rcirc-ignore-channel-activity) 112(make-variable-buffer-local 'rcirc-ignore-buffer-activity-flag)
79 113
80(defvar rcirc-ignore-all-activity-flag nil 114(defcustom rcirc-ignore-all-activity-flag nil
81 "*Non-nil means track activity, but do not display it in the modeline.") 115 "*Non-nil means do not indicate any activity in the modeline."
116 :type 'boolean
117 :group 'rcirc)
82 118
83(defvar rcirc-time-format "%H:%M " 119(defcustom rcirc-time-format "%H:%M "
84 "*Describes how timestamps are printed. 120 "*Describes how timestamps are printed.
85Used as the first arg to `format-time-string'.") 121Used as the first arg to `format-time-string'."
122 :type 'string
123 :group 'rcirc)
86 124
87(defvar rcirc-input-ring-size 1024 125(defcustom rcirc-input-ring-size 1024
88 "*Size of input history ring.") 126 "*Size of input history ring."
127 :type 'integer
128 :group 'rcirc)
89 129
90(defvar rcirc-read-only-flag t 130(defcustom rcirc-read-only-flag t
91 "*Non-nil means make text in irc buffers read-only.") 131 "*Non-nil means make text in irc buffers read-only."
132 :type 'boolean
133 :group 'rcirc)
92 134
93(defvar rcirc-buffer-maximum-lines nil 135(defcustom rcirc-buffer-maximum-lines nil
94 "*The maximum size in lines for rcirc buffers. 136 "*The maximum size in lines for rcirc buffers.
95Channel buffers are truncated from the top to be no greater than this 137Channel buffers are truncated from the top to be no greater than this
96number. If zero or nil, no truncating is done.") 138number. If zero or nil, no truncating is done."
139 :type '(choice (const :tag "No truncation" nil)
140 (integer :tag "Number of lines"))
141 :group 'rcirc)
97 142
98(defvar rcirc-authinfo-file-name 143(defcustom rcirc-authinfo-file-name
99 "~/.rcirc-authinfo" 144 "~/.rcirc-authinfo"
100 "File containing rcirc authentication passwords. 145 "File containing rcirc authentication passwords.
101The file consists of a single list, with each element itself a 146The file consists of a single list, with each element itself a
@@ -111,17 +156,17 @@ The required ARGUMENTS for each METHOD symbol are:
111Example: 156Example:
112 ((\"freenode\" \"bob\" nickserv \"p455w0rd\") 157 ((\"freenode\" \"bob\" nickserv \"p455w0rd\")
113 (\"freenode\" \"bob\" chanserv \"#bobland\" \"passwd99\") 158 (\"freenode\" \"bob\" chanserv \"#bobland\" \"passwd99\")
114 (\"bitlbee\" \"robert\" bitlbee \"sekrit\"))") 159 (\"bitlbee\" \"robert\" bitlbee \"sekrit\"))"
160 :type 'string
161 :group 'rcirc)
115 162
116(defvar rcirc-auto-authenticate-flag (file-readable-p rcirc-authinfo-file-name) 163(defcustom rcirc-auto-authenticate-flag (file-readable-p rcirc-authinfo-file-name)
117 "*Non-nil means automatically send authentication string to server. 164 "*Non-nil means automatically send authentication string to server.
118See also `rcirc-authinfo-file-name'.") 165See also `rcirc-authinfo-file-name'."
119 166 :type 'boolean
120(defvar rcirc-print-hooks nil 167 :group 'rcirc)
121 "Hook run after text is printed.
122Called with 5 arguments, PROCESS, SENDER, RESPONSE, TARGET and TEXT.")
123 168
124(defvar rcirc-prompt "%n> " 169(defcustom rcirc-prompt "> "
125 "Prompt string to use in irc buffers. 170 "Prompt string to use in irc buffers.
126 171
127The following replacements are made: 172The following replacements are made:
@@ -129,14 +174,27 @@ The following replacements are made:
129%s is the server. 174%s is the server.
130%t is the buffer target, a channel or a user. 175%t is the buffer target, a channel or a user.
131 176
132Setting this alone will not affect the prompt; 177Setting this alone will not affect the prompt;
133use `rcirc-update-prompt' after changing this variable.") 178use either M-x customize or also call `rcirc-update-prompt'."
179 :type 'string
180 :set 'rcirc-set-changed
181 :initialize 'custom-initialize-default
182 :group 'rcirc)
183
184(defcustom rcirc-print-hooks nil
185 "Hook run after text is printed.
186Called with 5 arguments, PROCESS, SENDER, RESPONSE, TARGET and TEXT."
187 :type 'hook
188 :group 'rcirc)
134 189
135(defvar rcirc-prompt-start-marker nil) 190(defvar rcirc-prompt-start-marker nil)
136(defvar rcirc-prompt-end-marker nil) 191(defvar rcirc-prompt-end-marker nil)
137 192
138(defvar rcirc-nick-table nil) 193(defvar rcirc-nick-table nil)
139 194
195;; each process has an alist of (target . buffer) pairs
196(defvar rcirc-buffer-alist nil)
197
140(defvar rcirc-activity nil 198(defvar rcirc-activity nil
141 "List of channels with unviewed activity.") 199 "List of channels with unviewed activity.")
142 200
@@ -150,30 +208,14 @@ use `rcirc-update-prompt' after changing this variable.")
150(defvar rcirc-target nil 208(defvar rcirc-target nil
151 "The channel or user associated with this buffer.") 209 "The channel or user associated with this buffer.")
152 210
153(defvar rcirc-channels nil
154 "Joined channels.")
155
156(defvar rcirc-private-chats nil
157 "Private chats open.")
158
159(defvar rcirc-urls nil 211(defvar rcirc-urls nil
160 "List of urls seen in the current buffer.") 212 "List of urls seen in the current buffer.")
161 213
162(defvar rcirc-keepalive-seconds 60 214(defvar rcirc-keepalive-seconds 60
163 "Number of seconds between keepalive pings.") 215 "Number of seconds between keepalive pings.")
164 216
217(defconst rcirc-id-string (concat "rcirc on GNU Emacs " emacs-version))
165 218
166(defun rcirc-version (&optional here)
167 "Return rcirc version string.
168If optional argument HERE is non-nil, insert string at point."
169 (interactive "P")
170 (let ((version "rcirc.el 0.9 $Revision: 1.4 $"))
171 (if here
172 (insert version)
173 (if (interactive-p)
174 (message "%s" version)
175 version))))
176
177(defvar rcirc-startup-channels nil) 219(defvar rcirc-startup-channels nil)
178;;;###autoload 220;;;###autoload
179(defun rcirc (&optional server port nick channels) 221(defun rcirc (&optional server port nick channels)
@@ -181,7 +223,7 @@ If optional argument HERE is non-nil, insert string at point."
181 223
182If any of the the optional SERVER, PORT, NICK or CHANNELS are not 224If any of the the optional SERVER, PORT, NICK or CHANNELS are not
183supplied, they are taken from the variables `rcirc-server', 225supplied, they are taken from the variables `rcirc-server',
184`rcirc-port', `rcirc-nick', and `rcirc-startup-channels', 226`rcirc-port', `rcirc-nick', and `rcirc-startup-channels-alist',
185respectively." 227respectively."
186 (interactive (list (read-string "IRC Server: " rcirc-server) 228 (interactive (list (read-string "IRC Server: " rcirc-server)
187 (read-string "IRC Port: " (number-to-string rcirc-port)) 229 (read-string "IRC Port: " (number-to-string rcirc-port))
@@ -192,19 +234,19 @@ respectively."
192 (or channels 234 (or channels
193 (setq channels 235 (setq channels
194 (if (interactive-p) 236 (if (interactive-p)
195 (delete "" 237 (split-string
196 (split-string 238 (read-string "Channels: "
197 (read-string "Channels: " 239 (mapconcat 'identity
198 (mapconcat 'identity 240 (rcirc-startup-channels server)
199 (rcirc-startup-channels server) 241 " "))
200 " ")) 242 "[, ]+" t)
201 "[, ]+"))
202 (rcirc-startup-channels server)))) 243 (rcirc-startup-channels server))))
203 (or global-mode-string (setq global-mode-string '(""))) 244 (or global-mode-string (setq global-mode-string '("")))
204 (and (not (memq 'rcirc-activity-string global-mode-string)) 245 (and (not (memq 'rcirc-activity-string global-mode-string))
205 (setq global-mode-string 246 (setq global-mode-string
206 (append global-mode-string '(rcirc-activity-string)))) 247 (append global-mode-string '(rcirc-activity-string))))
207 (add-hook 'window-configuration-change-hook 'rcirc-update-activity) 248 (add-hook 'window-configuration-change-hook
249 'rcirc-window-configuration-change)
208 (rcirc-connect server port nick rcirc-user-name rcirc-user-full-name 250 (rcirc-connect server port nick rcirc-user-name rcirc-user-full-name
209 channels)) 251 channels))
210 252
@@ -213,7 +255,6 @@ respectively."
213 255
214 256
215(defvar rcirc-process-output nil) 257(defvar rcirc-process-output nil)
216(defvar rcirc-last-buffer nil)
217(defvar rcirc-topic nil) 258(defvar rcirc-topic nil)
218(defvar rcirc-keepalive-timer nil) 259(defvar rcirc-keepalive-timer nil)
219(make-variable-buffer-local 'rcirc-topic) 260(make-variable-buffer-local 'rcirc-topic)
@@ -233,10 +274,12 @@ STARTUP-CHANNELS will automatically be joined on startup."
233 ;; set up process 274 ;; set up process
234 (set-process-coding-system process 'raw-text 'raw-text) 275 (set-process-coding-system process 'raw-text 'raw-text)
235 (set-process-filter process 'rcirc-filter) 276 (set-process-filter process 'rcirc-filter)
236 (switch-to-buffer (concat "*" (process-name process) "*")) 277 (switch-to-buffer (rcirc-generate-new-buffer-name process nil))
237 (set-process-buffer process (current-buffer)) 278 (set-process-buffer process (current-buffer))
238 (set-process-sentinel process 'rcirc-sentinel) 279 (set-process-sentinel process 'rcirc-sentinel)
239 (rcirc-mode process nil) 280 (rcirc-mode process nil)
281 (make-local-variable 'rcirc-buffer-alist)
282 (setq rcirc-buffer-alist nil)
240 (make-local-variable 'rcirc-nick-table) 283 (make-local-variable 'rcirc-nick-table)
241 (setq rcirc-nick-table (make-hash-table :test 'equal)) 284 (setq rcirc-nick-table (make-hash-table :test 'equal))
242 (make-local-variable 'rcirc-server) 285 (make-local-variable 'rcirc-server)
@@ -245,12 +288,6 @@ STARTUP-CHANNELS will automatically be joined on startup."
245 (setq rcirc-nick nick) 288 (setq rcirc-nick nick)
246 (make-local-variable 'rcirc-process-output) 289 (make-local-variable 'rcirc-process-output)
247 (setq rcirc-process-output nil) 290 (setq rcirc-process-output nil)
248 (make-local-variable 'rcirc-last-buffer)
249 (setq rcirc-last-buffer (current-buffer))
250 (make-local-variable 'rcirc-channels)
251 (setq rcirc-channels nil)
252 (make-local-variable 'rcirc-private-chats)
253 (setq rcirc-private-chats nil)
254 (make-local-variable 'rcirc-startup-channels) 291 (make-local-variable 'rcirc-startup-channels)
255 (setq rcirc-startup-channels startup-channels) 292 (setq rcirc-startup-channels startup-channels)
256 293
@@ -270,34 +307,39 @@ STARTUP-CHANNELS will automatically be joined on startup."
270 ;; return process object 307 ;; return process object
271 process))) 308 process)))
272 309
310(defmacro with-rcirc-process-buffer (process &rest body)
311 (declare (indent 1) (debug t))
312 `(with-current-buffer (process-buffer ,process)
313 ,@body))
314
273(defun rcirc-keepalive () 315(defun rcirc-keepalive ()
274 "Send keep alive pings to active rcirc processes." 316 "Send keep alive pings to active rcirc processes."
275 (if (rcirc-process-list) 317 (if (rcirc-process-list)
276 (mapc (lambda (process) 318 (mapc (lambda (process)
277 (with-current-buffer (process-buffer process) 319 (with-rcirc-process-buffer process
278 (rcirc-send-string process (concat "PING " rcirc-server)))) 320 (rcirc-send-string process (concat "PING " rcirc-server))))
279 (rcirc-process-list)) 321 (rcirc-process-list))
280 (cancel-timer rcirc-keepalive-timer) 322 (cancel-timer rcirc-keepalive-timer)
281 (setq rcirc-keepalive-timer nil))) 323 (setq rcirc-keepalive-timer nil)))
282 324
283(defvar rcirc-log-buffer "*rcirc log*") 325(defvar rcirc-debug-buffer " *rcirc debug*")
284(defvar rcirc-log-p nil 326(defvar rcirc-debug-flag nil
285 "If non-nil, write information to `rcirc-log-buffer'.") 327 "If non-nil, write information to `rcirc-debug-buffer'.")
286(defun rcirc-log (process text) 328(defun rcirc-debug (process text)
287 "Add an entry to the debug log including PROCESS and TEXT. 329 "Add an entry to the debug log including PROCESS and TEXT.
288Debug text is written to `rcirc-log-buffer' if `rcirc-log-p' is 330Debug text is written to `rcirc-debug-buffer' if `rcirc-debug-p'
289non-nil." 331is non-nil."
290 (when rcirc-log-p 332 (when rcirc-debug-flag
291 (save-excursion 333 (save-excursion
292 (save-window-excursion 334 (save-window-excursion
293 (set-buffer (get-buffer-create rcirc-log-buffer)) 335 (set-buffer (get-buffer-create rcirc-debug-buffer))
294 (goto-char (point-max)) 336 (goto-char (point-max))
295 (insert (concat 337 (insert (concat
296 "[" 338 "["
297 (format-time-string "%Y-%m-%dT%T ") (process-name process) 339 (format-time-string "%Y-%m-%dT%T ") (process-name process)
298 "] " 340 "] "
299 text)))))) 341 text))))))
300 342
301(defvar rcirc-sentinel-hooks nil 343(defvar rcirc-sentinel-hooks nil
302 "Hook functions called when the process sentinel is called. 344 "Hook functions called when the process sentinel is called.
303Functions are called with PROCESS and SENTINEL arguments.") 345Functions are called with PROCESS and SENTINEL arguments.")
@@ -305,20 +347,16 @@ Functions are called with PROCESS and SENTINEL arguments.")
305(defun rcirc-sentinel (process sentinel) 347(defun rcirc-sentinel (process sentinel)
306 "Called when PROCESS receives SENTINEL." 348 "Called when PROCESS receives SENTINEL."
307 (let ((sentinel (replace-regexp-in-string "\n" "" sentinel))) 349 (let ((sentinel (replace-regexp-in-string "\n" "" sentinel)))
308 (rcirc-log process (format "SENTINEL: %S %S\n" process sentinel)) 350 (rcirc-debug process (format "SENTINEL: %S %S\n" process sentinel))
309 (with-current-buffer (process-buffer process) 351 (with-rcirc-process-buffer process
310 (dolist (target (append rcirc-channels 352 (dolist (buffer (cons nil (mapcar 'cdr rcirc-buffer-alist)))
311 rcirc-private-chats 353 (rcirc-print process "rcirc.el" "ERROR" buffer
312 (list (current-buffer))))
313 (rcirc-print process "rcirc.el" "ERROR" target
314 (format "%s: %s (%S)" 354 (format "%s: %s (%S)"
315 (process-name process) 355 (process-name process)
316 sentinel 356 sentinel
317 (process-status process)) t) 357 (process-status process)) t)
318 ;; remove the prompt from buffers 358 ;; remove the prompt from buffers
319 (with-current-buffer (if (eq target (current-buffer)) 359 (with-current-buffer (or buffer (current-buffer))
320 (current-buffer)
321 (rcirc-get-buffer process target))
322 (let ((inhibit-read-only t)) 360 (let ((inhibit-read-only t))
323 (delete-region rcirc-prompt-start-marker 361 (delete-region rcirc-prompt-start-marker
324 rcirc-prompt-end-marker))))) 362 rcirc-prompt-end-marker)))))
@@ -329,7 +367,7 @@ Functions are called with PROCESS and SENTINEL arguments.")
329 (let (ps) 367 (let (ps)
330 (mapc (lambda (p) 368 (mapc (lambda (p)
331 (when (process-buffer p) 369 (when (process-buffer p)
332 (with-current-buffer (process-buffer p) 370 (with-rcirc-process-buffer p
333 (when (eq major-mode 'rcirc-mode) 371 (when (eq major-mode 'rcirc-mode)
334 (setq ps (cons p ps)))))) 372 (setq ps (cons p ps))))))
335 (process-list)) 373 (process-list))
@@ -340,24 +378,24 @@ Functions are called with PROCESS and SENTINEL arguments.")
340Function is called with PROCESS COMMAND SENDER ARGS and LINE.") 378Function is called with PROCESS COMMAND SENDER ARGS and LINE.")
341(defun rcirc-filter (process output) 379(defun rcirc-filter (process output)
342 "Called when PROCESS receives OUTPUT." 380 "Called when PROCESS receives OUTPUT."
343 (rcirc-log process output) 381 (rcirc-debug process output)
344 (with-current-buffer (process-buffer process) 382 (with-rcirc-process-buffer process
345 (setq rcirc-process-output (concat rcirc-process-output output)) 383 (setq rcirc-process-output (concat rcirc-process-output output))
346 (when (= (aref rcirc-process-output 384 (when (= (aref rcirc-process-output
347 (1- (length rcirc-process-output))) ?\n) 385 (1- (length rcirc-process-output))) ?\n)
348 (mapc (lambda (line) 386 (mapc (lambda (line)
349 (rcirc-process-server-response process line)) 387 (rcirc-process-server-response process line))
350 (delete "" (split-string rcirc-process-output "[\n\r]"))) 388 (split-string rcirc-process-output "[\n\r]" t))
351 (setq rcirc-process-output nil)))) 389 (setq rcirc-process-output nil))))
352 390
353(defvar rcirc-trap-errors nil) 391(defvar rcirc-trap-errors-flag t)
354(defun rcirc-process-server-response (process text) 392(defun rcirc-process-server-response (process text)
355 (if rcirc-trap-errors 393 (if rcirc-trap-errors-flag
356 (condition-case err 394 (condition-case err
357 (rcirc-process-server-response-1 process text) 395 (rcirc-process-server-response-1 process text)
358 (error 396 (error
359 (rcirc-print process "RCIRC" "ERROR" nil 397 (rcirc-print process "RCIRC" "ERROR" nil
360 (format "rcirc: error processing: \"%s\" %s" text err)))) 398 (format "\"%s\" %s" text err) t)))
361 (rcirc-process-server-response-1 process text))) 399 (rcirc-process-server-response-1 process text)))
362 400
363(defun rcirc-process-server-response-1 (process text) 401(defun rcirc-process-server-response-1 (process text)
@@ -369,8 +407,8 @@ Function is called with PROCESS COMMAND SENDER ARGS and LINE.")
369 (string-match "^\\([^:]*\\):?\\(.+\\)?$" args) 407 (string-match "^\\([^:]*\\):?\\(.+\\)?$" args)
370 (let* ((args1 (match-string 1 args)) 408 (let* ((args1 (match-string 1 args))
371 (args2 (match-string 2 args)) 409 (args2 (match-string 2 args))
372 (args (append (delete "" (split-string args1 " ")) 410 (args (delq nil (append (split-string args1 " " t)
373 (list args2)))) 411 (list args2)))))
374 (if (not (fboundp handler)) 412 (if (not (fboundp handler))
375 (rcirc-handler-generic process cmd sender args text) 413 (rcirc-handler-generic process cmd sender args text)
376 (funcall handler process sender args text)) 414 (funcall handler process sender args text))
@@ -381,24 +419,24 @@ Function is called with PROCESS COMMAND SENDER ARGS and LINE.")
381(defun rcirc-handler-generic (process command sender args text) 419(defun rcirc-handler-generic (process command sender args text)
382 "Generic server response handler." 420 "Generic server response handler."
383 (rcirc-print process sender command nil 421 (rcirc-print process sender command nil
384 (mapconcat 'identity (cdr args) " "))) 422 (mapconcat 'identity (cdr args) " ") t))
385 423
386(defun rcirc-send-string (process string) 424(defun rcirc-send-string (process string)
387 "Send PROCESS a STRING plus a newline." 425 "Send PROCESS a STRING plus a newline."
388 (let ((string (concat (encode-coding-string string 426 (let ((string (concat (encode-coding-string string
389 buffer-file-coding-system) 427 buffer-file-coding-system)
390 "\n"))) 428 "\n")))
391 (rcirc-log process string) 429 (rcirc-debug process string)
392 (process-send-string process string))) 430 (process-send-string process string)))
393 431
394(defun rcirc-server (process) 432(defun rcirc-server (process)
395 "Return PROCESS server, given by the 001 response." 433 "Return PROCESS server, given by the 001 response."
396 (with-current-buffer (process-buffer process) 434 (with-rcirc-process-buffer process
397 rcirc-server)) 435 rcirc-server))
398 436
399(defun rcirc-nick (process) 437(defun rcirc-nick (process)
400 "Return PROCESS nick." 438 "Return PROCESS nick."
401 (with-current-buffer (process-buffer process) 439 (with-rcirc-process-buffer process
402 rcirc-nick)) 440 rcirc-nick))
403 441
404(defvar rcirc-max-message-length 450 442(defvar rcirc-max-message-length 450
@@ -418,7 +456,9 @@ If NOTICEP is non-nil, send a notice instead of privmsg."
418 text)) 456 text))
419 (more (if oversize 457 (more (if oversize
420 (substring message rcirc-max-message-length)))) 458 (substring message rcirc-max-message-length))))
421 (rcirc-print process (rcirc-nick process) response target text) 459 (rcirc-print process (rcirc-nick process) response
460 (rcirc-get-buffer-create process target)
461 text)
422 (rcirc-send-string process (concat response " " target " :" text)) 462 (rcirc-send-string process (concat response " " target " :" text))
423 (if more 463 (if more
424 (rcirc-send-message process target more noticep)))) 464 (rcirc-send-message process target more noticep))))
@@ -459,8 +499,8 @@ If NOTICEP is non-nil, send a notice instead of privmsg."
459 rcirc-prompt-end-marker)) 499 rcirc-prompt-end-marker))
460 (setq rcirc-nick-completions 500 (setq rcirc-nick-completions
461 (let ((completion-ignore-case t)) 501 (let ((completion-ignore-case t))
462 (all-completions 502 (all-completions
463 (buffer-substring 503 (buffer-substring
464 (+ rcirc-prompt-end-marker 504 (+ rcirc-prompt-end-marker
465 rcirc-nick-completion-start-offset) 505 rcirc-nick-completion-start-offset)
466 (point)) 506 (point))
@@ -469,11 +509,11 @@ If NOTICEP is non-nil, send a notice instead of privmsg."
469 (rcirc-buffer-target))))))) 509 (rcirc-buffer-target)))))))
470 (let ((completion (car rcirc-nick-completions))) 510 (let ((completion (car rcirc-nick-completions)))
471 (when completion 511 (when completion
472 (delete-region (+ rcirc-prompt-end-marker 512 (delete-region (+ rcirc-prompt-end-marker
473 rcirc-nick-completion-start-offset) 513 rcirc-nick-completion-start-offset)
474 (point)) 514 (point))
475 (insert (concat completion 515 (insert (concat completion
476 (if (= (+ rcirc-prompt-end-marker 516 (if (= (+ rcirc-prompt-end-marker
477 rcirc-nick-completion-start-offset) 517 rcirc-nick-completion-start-offset)
478 rcirc-prompt-end-marker) 518 rcirc-prompt-end-marker)
479 ": ")))))) 519 ": "))))))
@@ -507,7 +547,7 @@ If buffer is nil, return the target of the current buffer."
507(define-key rcirc-mode-map (kbd "C-c C-w") 'rcirc-cmd-whois) 547(define-key rcirc-mode-map (kbd "C-c C-w") 'rcirc-cmd-whois)
508(define-key rcirc-mode-map (kbd "C-c C-x") 'rcirc-cmd-quit) 548(define-key rcirc-mode-map (kbd "C-c C-x") 'rcirc-cmd-quit)
509(define-key rcirc-mode-map (kbd "C-c TAB") ; C-i 549(define-key rcirc-mode-map (kbd "C-c TAB") ; C-i
510 'rcirc-toggle-ignore-channel-activity) 550 'rcirc-toggle-ignore-buffer-activity)
511(define-key rcirc-mode-map (kbd "C-c C-s") 'rcirc-switch-to-server-buffer) 551(define-key rcirc-mode-map (kbd "C-c C-s") 'rcirc-switch-to-server-buffer)
512(define-key rcirc-mode-map (kbd "C-c C-a") 'rcirc-jump-to-first-unread-line) 552(define-key rcirc-mode-map (kbd "C-c C-a") 'rcirc-jump-to-first-unread-line)
513 553
@@ -515,6 +555,15 @@ If buffer is nil, return the target of the current buffer."
515(define-key global-map (kbd "C-c C-@") 'rcirc-next-active-buffer) 555(define-key global-map (kbd "C-c C-@") 'rcirc-next-active-buffer)
516(define-key global-map (kbd "C-c C-SPC") 'rcirc-next-active-buffer) 556(define-key global-map (kbd "C-c C-SPC") 'rcirc-next-active-buffer)
517 557
558(defvar rcirc-browse-url-map (make-sparse-keymap)
559 "Keymap used ror browsing URLs in `rcirc-mode'.")
560
561(define-key rcirc-browse-url-map (kbd "RET") 'rcirc-browse-url-at-point)
562(define-key rcirc-browse-url-map (kbd "<mouse-2>") 'rcirc-browse-url-at-mouse)
563
564(defvar rcirc-short-buffer-name nil
565 "Generated abbreviation to use to indicate buffer activity.")
566
518(defvar rcirc-mode-hook nil 567(defvar rcirc-mode-hook nil
519 "Hook run when setting up rcirc buffer.") 568 "Hook run when setting up rcirc buffer.")
520 569
@@ -533,11 +582,12 @@ If buffer is nil, return the target of the current buffer."
533 (setq rcirc-process process) 582 (setq rcirc-process process)
534 (make-local-variable 'rcirc-target) 583 (make-local-variable 'rcirc-target)
535 (setq rcirc-target target) 584 (setq rcirc-target target)
585
586 (make-local-variable 'rcirc-short-buffer-name)
587 (setq rcirc-short-buffer-name nil)
536 (make-local-variable 'rcirc-urls) 588 (make-local-variable 'rcirc-urls)
537 (setq rcirc-urls nil) 589 (setq rcirc-urls nil)
538 (setq use-hard-newlines t) 590 (setq use-hard-newlines t)
539 (when (rcirc-channel-p rcirc-target)
540 (setq header-line-format 'rcirc-topic))
541 591
542 ;; setup the prompt and markers 592 ;; setup the prompt and markers
543 (make-local-variable 'rcirc-prompt-start-marker) 593 (make-local-variable 'rcirc-prompt-start-marker)
@@ -552,38 +602,59 @@ If buffer is nil, return the target of the current buffer."
552 (setq overlay-arrow-position (make-marker)) 602 (setq overlay-arrow-position (make-marker))
553 (set-marker overlay-arrow-position nil) 603 (set-marker overlay-arrow-position nil)
554 604
605 ;; add to buffer list, and update buffer abbrevs
606 (when target ; skip server buffer
607 (let ((buffer (current-buffer)))
608 (with-rcirc-process-buffer process
609 (setq rcirc-buffer-alist (cons (cons target buffer)
610 rcirc-buffer-alist))))
611 (rcirc-update-short-buffer-names))
612
555 (run-hooks 'rcirc-mode-hook)) 613 (run-hooks 'rcirc-mode-hook))
556 614
557(defmacro with-rcirc-process-buffer (process &rest body) 615(defun rcirc-update-prompt (&optional all)
558 (declare (indent 1) (debug t)) 616 "Reset the prompt string in the current buffer.
559 `(with-current-buffer (process-buffer ,process)
560 ,@body))
561 617
562(defun rcirc-update-prompt () 618If ALL is non-nil, update prompts in all IRC buffers."
563 "Reset the prompt string in the current buffer." 619 (if all
564 (let ((inhibit-read-only t) 620 (mapc (lambda (process)
565 (prompt (or rcirc-prompt ""))) 621 (mapc (lambda (buffer)
566 (mapc (lambda (rep) 622 (with-current-buffer buffer
567 (setq prompt 623 (rcirc-update-prompt)))
568 (replace-regexp-in-string (car rep) (cdr rep) prompt))) 624 (with-rcirc-process-buffer process
569 (list (cons "%n" (with-rcirc-process-buffer rcirc-process 625 (mapcar 'cdr rcirc-buffer-alist))))
570 rcirc-nick)) 626 (rcirc-process-list))
571 (cons "%s" (with-rcirc-process-buffer rcirc-process 627 (let ((inhibit-read-only t)
572 rcirc-server)) 628 (prompt (or rcirc-prompt "")))
573 (cons "%t" (or rcirc-target "")))) 629 (mapc (lambda (rep)
574 (save-excursion 630 (setq prompt
575 (delete-region rcirc-prompt-start-marker rcirc-prompt-end-marker) 631 (replace-regexp-in-string (car rep) (regexp-quote (cdr rep)) prompt)))
576 (goto-char rcirc-prompt-start-marker) 632 (list (cons "%n" (with-rcirc-process-buffer rcirc-process
577 (let ((start (point))) 633 rcirc-nick))
578 (insert-before-markers prompt) 634 (cons "%s" (with-rcirc-process-buffer rcirc-process
579 (set-marker rcirc-prompt-start-marker start) 635 rcirc-server))
580 (when (not (zerop (- rcirc-prompt-end-marker 636 (cons "%t" (or rcirc-target ""))))
581 rcirc-prompt-start-marker))) 637 (save-excursion
582 (add-text-properties rcirc-prompt-start-marker 638 (delete-region rcirc-prompt-start-marker rcirc-prompt-end-marker)
583 rcirc-prompt-end-marker 639 (goto-char rcirc-prompt-start-marker)
584 (list 'face 'rcirc-prompt-face 640 (let ((start (point)))
585 'read-only t 'field t 641 (insert-before-markers prompt)
586 'front-sticky t 'rear-nonsticky t))))))) 642 (set-marker rcirc-prompt-start-marker start)
643 (when (not (zerop (- rcirc-prompt-end-marker
644 rcirc-prompt-start-marker)))
645 (add-text-properties rcirc-prompt-start-marker
646 rcirc-prompt-end-marker
647 (list 'face 'rcirc-prompt
648 'read-only t 'field t
649 'front-sticky t 'rear-nonsticky t))))))))
650
651(defun rcirc-set-changed (option value)
652 "Set OPTION to VALUE and do updates after a customization change."
653 (set-default option value)
654 (cond ((eq option 'rcirc-prompt)
655 (rcirc-update-prompt 'all))
656 (t
657 (error "Bad option %s" option))))
587 658
588(defun rcirc-channel-p (target) 659(defun rcirc-channel-p (target)
589 "Return t if TARGET is a channel name." 660 "Return t if TARGET is a channel name."
@@ -595,65 +666,67 @@ If buffer is nil, return the target of the current buffer."
595(defun rcirc-kill-buffer-hook () 666(defun rcirc-kill-buffer-hook ()
596 "Part the channel when killing an rcirc buffer." 667 "Part the channel when killing an rcirc buffer."
597 (when (eq major-mode 'rcirc-mode) 668 (when (eq major-mode 'rcirc-mode)
598 (rcirc-clear-activity (current-buffer)) 669 (rcirc-kill-buffer-hook-1)))
670(defun rcirc-kill-buffer-hook-1 ()
671 (let ((buffer (current-buffer)))
672 (rcirc-clear-activity buffer)
599 (when (and rcirc-process 673 (when (and rcirc-process
600 (eq (process-status rcirc-process) 'open)) 674 (eq (process-status rcirc-process) 'open))
675 (with-rcirc-process-buffer rcirc-process
676 (setq rcirc-buffer-alist
677 (rassq-delete-all buffer rcirc-buffer-alist)))
678 (rcirc-update-short-buffer-names)
601 (if (rcirc-channel-p rcirc-target) 679 (if (rcirc-channel-p rcirc-target)
602 (rcirc-cmd-part "" rcirc-process rcirc-target) 680 (rcirc-send-string rcirc-process
603 ;; remove target from privchat list 681 (concat "PART " rcirc-target
604 (when rcirc-target 682 " :Killed buffer"))
605 (let ((target (downcase rcirc-target))) 683 (when rcirc-target
606 (with-rcirc-process-buffer rcirc-process 684 (rcirc-remove-nick-channel rcirc-process
607 (setq rcirc-private-chats 685 (rcirc-nick rcirc-process)
608 (delete target rcirc-private-chats))))))))) 686 rcirc-target))))))
687
609(add-hook 'kill-buffer-hook 'rcirc-kill-buffer-hook) 688(add-hook 'kill-buffer-hook 'rcirc-kill-buffer-hook)
610 689
611(defun rcirc-get-buffer-name (process target) 690(defun rcirc-generate-new-buffer-name (process target)
612 "Return buffer name based on PROCESS and TARGET." 691 "Return a buffer name based on PROCESS and TARGET.
613 (concat (and target (downcase target)) "@" (process-name process))) 692This is used for the initial name given to irc buffers."
693 (if target
694 (concat target "@" (process-name process))
695 (concat "*" (process-name process) "*")))
614 696
615(defun rcirc-get-buffer (process target &optional error) 697(defun rcirc-get-buffer (process target &optional server)
616 "Return the buffer associated with the PROCESS and TARGET. 698 "Return the buffer associated with the PROCESS and TARGET.
617If TARGET is nil and ERROR is nil, return the process buffer." 699
618 (let ((buffer (and target 700If TARGET is nil, return the server buffer.
619 (get-buffer (rcirc-get-buffer-name process target))))) 701
620 (if (and buffer (buffer-live-p buffer)) 702If optional argument SERVER is non-nil, return the server buffer
621 buffer 703if there is no existing buffer for TARGET, otherwise return nil."
622 (if error 704 (with-rcirc-process-buffer process
623 (error "Buffer associated with %s does not exist" target) 705 (if (null target)
624 (process-buffer process))))) 706 (current-buffer)
707 (let ((buffer (cdr (assoc-string target rcirc-buffer-alist t))))
708 (or buffer (when server (current-buffer)))))))
625 709
626(defun rcirc-get-buffer-create (process target) 710(defun rcirc-get-buffer-create (process target)
627 "Return the buffer named associated with the PROCESS and TARGET. 711 "Return the buffer associated with the PROCESS and TARGET.
628Create the buffer if it doesn't exist. If TARGET is nil, return 712Create the buffer if it doesn't exist."
629the process buffer." 713 (let ((buffer (rcirc-get-buffer process target)))
630 (with-current-buffer (process-buffer process) 714 (or buffer
631 (if (not target) 715 ;; create the buffer
632 (current-buffer) 716 (with-rcirc-process-buffer process
633 (let ((target (downcase target))) 717 (let ((new-buffer (get-buffer-create
634 ;; add private chats to list. we dont add channels here, they 718 (rcirc-generate-new-buffer-name process target))))
635 ;; are managed by the join/part/quit handlers 719 (with-current-buffer new-buffer
636 (when (and (not (rcirc-channel-p target)) 720 (rcirc-mode process target))
637 (not (member target rcirc-private-chats))) 721 (rcirc-put-nick-channel process (rcirc-nick process) target)
638 (with-rcirc-process-buffer process 722 new-buffer)))))
639 (setq rcirc-private-chats (cons target rcirc-private-chats))))
640 ;; create and setup a buffer, or return the existing one
641 (let ((bufname (rcirc-get-buffer-name process target)))
642 (with-current-buffer (get-buffer-create bufname)
643 (if (or (not rcirc-process)
644 (not (equal (process-status rcirc-process) 'open)))
645 (rcirc-mode process target)
646 (setq rcirc-target target))
647 (current-buffer)))))))
648 723
649(defun rcirc-send-input () 724(defun rcirc-send-input ()
650 "Send input to target associated with the current buffer." 725 "Send input to target associated with the current buffer."
651 (interactive) 726 (interactive)
652 (if (not (eq (process-status rcirc-process) 'open)) 727 (if (not (eq (process-status rcirc-process) 'open))
653 (error "Network connection to %s is not open" 728 (error "Network connection to %s is not open"
654 (process-name rcirc-process)) 729 (process-name rcirc-process))
655 ;; update last buffer
656 (rcirc-set-last-buffer rcirc-process (current-buffer))
657 (if (< (point) rcirc-prompt-end-marker) 730 (if (< (point) rcirc-prompt-end-marker)
658 ;; copy the line down to the input area 731 ;; copy the line down to the input area
659 (progn 732 (progn
@@ -668,9 +741,6 @@ the process buffer."
668 (insert (replace-regexp-in-string 741 (insert (replace-regexp-in-string
669 "\n\\s-+" " " 742 "\n\\s-+" " "
670 (buffer-substring-no-properties start end))))) 743 (buffer-substring-no-properties start end)))))
671 ;; assume text has been read
672 (when (marker-position overlay-arrow-position)
673 (set-marker overlay-arrow-position nil))
674 ;; process input 744 ;; process input
675 (goto-char (point-max)) 745 (goto-char (point-max))
676 (let ((target (rcirc-buffer-target)) 746 (let ((target (rcirc-buffer-target))
@@ -690,10 +760,10 @@ the process buffer."
690 (with-current-buffer (current-buffer) 760 (with-current-buffer (current-buffer)
691 (delete-region rcirc-prompt-end-marker (point)) 761 (delete-region rcirc-prompt-end-marker (point))
692 (if (string= command "me") 762 (if (string= command "me")
693 (rcirc-print rcirc-process (rcirc-nick rcirc-process) 763 (rcirc-print rcirc-process (rcirc-nick rcirc-process)
694 "ACTION" target args) 764 "ACTION" (current-buffer) args)
695 (rcirc-print rcirc-process (rcirc-nick rcirc-process) 765 (rcirc-print rcirc-process (rcirc-nick rcirc-process)
696 "COMMAND" target input)) 766 "COMMAND" (current-buffer) input))
697 (set-marker rcirc-prompt-end-marker (point)) 767 (set-marker rcirc-prompt-end-marker (point))
698 (if (fboundp fun) 768 (if (fboundp fun)
699 (funcall fun args rcirc-process target) 769 (funcall fun args rcirc-process target)
@@ -751,15 +821,16 @@ the process buffer."
751 (interactive) 821 (interactive)
752 (assert (and (eq major-mode 'rcirc-multiline-edit-mode))) 822 (assert (and (eq major-mode 'rcirc-multiline-edit-mode)))
753 (assert rcirc-parent-buffer) 823 (assert rcirc-parent-buffer)
824 (untabify (point-min) (point-max))
754 (let ((text (buffer-substring (point-min) (point-max))) 825 (let ((text (buffer-substring (point-min) (point-max)))
755 (buffer (current-buffer)) 826 (buffer (current-buffer))
756 (pos (point))) 827 (pos (point)))
757 (set-buffer rcirc-parent-buffer) 828 (set-buffer rcirc-parent-buffer)
758 (goto-char (point-max)) 829 (goto-char (point-max))
759 (insert text) 830 (insert text)
760 (goto-char (+ rcirc-prompt-end-marker (1- pos)))
761 (kill-buffer buffer) 831 (kill-buffer buffer)
762 (set-window-configuration rcirc-window-configuration))) 832 (set-window-configuration rcirc-window-configuration)
833 (goto-char (+ rcirc-prompt-end-marker (1- pos)))))
763 834
764(defun rcirc-multiline-edit-cancel () 835(defun rcirc-multiline-edit-cancel ()
765 "Cancel the multiline edit." 836 "Cancel the multiline edit."
@@ -768,19 +839,15 @@ the process buffer."
768 (kill-buffer (current-buffer)) 839 (kill-buffer (current-buffer))
769 (set-window-configuration rcirc-window-configuration)) 840 (set-window-configuration rcirc-window-configuration))
770 841
771(defun rcirc-last-buffer (process) 842(defun rcirc-get-any-buffer (process)
772 "Return the last working buffer for PROCESS. 843 "Return a buffer for PROCESS, either the one selected or the process buffer."
773Used for displaying messages that don't have an explicit destination." 844 (let ((buffer (window-buffer (selected-window))))
774 (with-current-buffer (process-buffer process) 845 (if (and buffer
775 (or (and rcirc-last-buffer 846 (with-current-buffer buffer
776 (buffer-live-p rcirc-last-buffer) 847 (and (eq major-mode 'rcirc-mode)
777 rcirc-last-buffer) 848 (eq rcirc-process process))))
778 (current-buffer)))) 849 buffer
779 850 (process-buffer process))))
780(defun rcirc-set-last-buffer (process buffer)
781 "Set the last working buffer for PROCESS to BUFFER."
782 (with-current-buffer (process-buffer process)
783 (setq rcirc-last-buffer buffer)))
784 851
785(defun rcirc-format-response-string (process sender response target text) 852(defun rcirc-format-response-string (process sender response target text)
786 (concat (when rcirc-time-format 853 (concat (when rcirc-time-format
@@ -792,22 +859,24 @@ Used for displaying messages that don't have an explicit destination."
792 (cond ((string= response "PRIVMSG") 859 (cond ((string= response "PRIVMSG")
793 (setq first "<" middle "> ")) 860 (setq first "<" middle "> "))
794 ((string= response "NOTICE") 861 ((string= response "NOTICE")
795 (setq first "-" middle "- ")) 862 (when sender
863 (setq first "-" middle "- ")))
796 (t 864 (t
797 (setq first "[" middle " " end "]"))) 865 (setq first "[" middle " " end "]")))
798 (concat first 866 (concat first
799 (rcirc-facify (rcirc-user-nick sender) 867 (rcirc-facify (rcirc-user-nick sender)
800 (if (string= sender 868 (if (string= sender
801 (rcirc-nick process)) 869 (rcirc-nick process))
802 'rcirc-my-nick-face 870 'rcirc-my-nick
803 'rcirc-other-nick-face)) 871 'rcirc-other-nick))
804 middle 872 middle
805 (rcirc-mangle-text process text) 873 (rcirc-mangle-text process text)
806 end))) 874 end)))
807 ((string= response "COMMAND") 875 ((string= response "COMMAND")
808 text) 876 text)
809 ((string= response "ERROR") 877 ((string= response "ERROR")
810 (propertize text 'face 'font-lock-warning-face)) 878 (propertize (concat "!!! " text)
879 'face 'font-lock-warning-face))
811 (t 880 (t
812 (rcirc-mangle-text 881 (rcirc-mangle-text
813 process 882 process
@@ -817,10 +886,8 @@ Used for displaying messages that don't have an explicit destination."
817 (concat (rcirc-user-nick sender) " ")) 886 (concat (rcirc-user-nick sender) " "))
818 (when (zerop (string-to-number response)) 887 (when (zerop (string-to-number response))
819 (concat response " ")) 888 (concat response " "))
820 (when (and target (not (string= target rcirc-target)))
821 (concat target " "))
822 text) 889 text)
823 'rcirc-server-face)))))) 890 'rcirc-server))))))
824 891
825(defvar rcirc-activity-type nil) 892(defvar rcirc-activity-type nil)
826(make-variable-buffer-local 'rcirc-activity-type) 893(make-variable-buffer-local 'rcirc-activity-type)
@@ -828,14 +895,15 @@ Used for displaying messages that don't have an explicit destination."
828 "Print TEXT in the buffer associated with TARGET. 895 "Print TEXT in the buffer associated with TARGET.
829Format based on SENDER and RESPONSE. If ACTIVITY is non-nil, 896Format based on SENDER and RESPONSE. If ACTIVITY is non-nil,
830record activity." 897record activity."
831 (let* ((buffer (cond ((bufferp target) 898 (let* ((buffer (cond ((bufferp target)
832 target) 899 target)
833 ((not target) 900 ((not target)
834 (rcirc-last-buffer process)) 901 (rcirc-get-any-buffer process))
835 ((not (rcirc-channel-p target)) 902 ((not (rcirc-channel-p target))
836 (rcirc-get-buffer-create process target)) 903 (rcirc-get-buffer-create process
837 ((rcirc-get-buffer process target)) 904 (rcirc-user-nick sender)))
838 (t (process-buffer process)))) 905 ((or (rcirc-get-buffer process target)
906 (rcirc-get-any-buffer process)))))
839 (inhibit-read-only t)) 907 (inhibit-read-only t))
840 (with-current-buffer buffer 908 (with-current-buffer buffer
841 (let ((moving (= (point) rcirc-prompt-end-marker)) 909 (let ((moving (= (point) rcirc-prompt-end-marker))
@@ -844,11 +912,12 @@ record activity."
844 912
845 (unless (string= sender (rcirc-nick process)) 913 (unless (string= sender (rcirc-nick process))
846 ;; only decode text from other senders, not ours 914 ;; only decode text from other senders, not ours
847 (setq text (decode-coding-string text buffer-file-coding-system)) 915 (setq text (decode-coding-string (or text "")
916 buffer-file-coding-system))
848 ;; mark the line with overlay arrow 917 ;; mark the line with overlay arrow
849 (unless (or (marker-position overlay-arrow-position) 918 (unless (or (marker-position overlay-arrow-position)
850 (get-buffer-window (current-buffer))) 919 (get-buffer-window (current-buffer)))
851 (set-marker overlay-arrow-position 920 (set-marker overlay-arrow-position
852 (marker-position rcirc-prompt-start-marker)))) 921 (marker-position rcirc-prompt-start-marker))))
853 922
854 ;; temporarily set the marker insertion-type because 923 ;; temporarily set the marker insertion-type because
@@ -869,7 +938,7 @@ record activity."
869 (or rcirc-fill-prefix 938 (or rcirc-fill-prefix
870 (make-string 939 (make-string
871 (+ (if rcirc-time-format 940 (+ (if rcirc-time-format
872 (length (format-time-string 941 (length (format-time-string
873 rcirc-time-format)) 942 rcirc-time-format))
874 0) 943 0)
875 (cond ((or (string= response "PRIVMSG") 944 (cond ((or (string= response "PRIVMSG")
@@ -882,30 +951,34 @@ record activity."
882 (t 3)) ; *** 951 (t 3)) ; ***
883 1) 952 1)
884 ? ))) 953 ? )))
885 (fill-column (or rcirc-fill-column fill-column))) 954 (fill-column (cond ((eq rcirc-fill-column 'frame-width)
955 (1- (frame-width)))
956 (rcirc-fill-column
957 rcirc-fill-column)
958 (t fill-column))))
886 (fill-region fill-start rcirc-prompt-start-marker 'left t))) 959 (fill-region fill-start rcirc-prompt-start-marker 'left t)))
887 960
888 ;; truncate buffer if it is very long
889 (save-excursion
890 (when (and rcirc-buffer-maximum-lines
891 (> rcirc-buffer-maximum-lines 0)
892 (= (forward-line (- rcirc-buffer-maximum-lines)) 0))
893 (delete-region (point-min) (point))))
894
895 ;; set inserted text to be read-only 961 ;; set inserted text to be read-only
896 (when rcirc-read-only-flag 962 (when rcirc-read-only-flag
897 (put-text-property rcirc-prompt-start-marker fill-start 'read-only t) 963 (put-text-property rcirc-prompt-start-marker fill-start 'read-only t)
898 (let ((inhibit-read-only t)) 964 (let ((inhibit-read-only t))
899 (put-text-property rcirc-prompt-start-marker fill-start 965 (put-text-property rcirc-prompt-start-marker fill-start
900 'front-sticky t) 966 'front-sticky t)
901 (put-text-property (1- (point)) (point) 'rear-nonsticky t))) 967 (put-text-property (1- (point)) (point) 'rear-nonsticky t)))
902 968
969 ;; truncate buffer if it is very long
970 (save-excursion
971 (when (and rcirc-buffer-maximum-lines
972 (> rcirc-buffer-maximum-lines 0)
973 (= (forward-line (- rcirc-buffer-maximum-lines)) 0))
974 (delete-region (point-min) (point))))
975
903 ;; set the window point for buffers show in windows 976 ;; set the window point for buffers show in windows
904 (walk-windows (lambda (w) 977 (walk-windows (lambda (w)
905 (unless (eq (selected-window) w) 978 (unless (eq (selected-window) w)
906 (when (and (eq (current-buffer) 979 (when (and (eq (current-buffer)
907 (window-buffer w)) 980 (window-buffer w))
908 (>= (window-point w) 981 (>= (window-point w)
909 rcirc-prompt-end-marker)) 982 rcirc-prompt-end-marker))
910 (set-window-point w (point-max))))) 983 (set-window-point w (point-max)))))
911 nil t) 984 nil t)
@@ -924,15 +997,16 @@ record activity."
924 (regexp-quote (rcirc-nick process)) 997 (regexp-quote (rcirc-nick process))
925 "\\b") 998 "\\b")
926 text))) 999 text)))
927 (when (or (not rcirc-ignore-channel-activity) 1000 (when (or (not rcirc-ignore-buffer-activity-flag)
928 ;; always notice when our nick is mentioned, even 1001 ;; always notice when our nick is mentioned, even
929 ;; if ignoring channel activity 1002 ;; if ignoring channel activity
930 nick-match) 1003 nick-match)
931 (rcirc-record-activity 1004 (rcirc-record-activity
932 (current-buffer) 1005 (current-buffer)
933 (when (or nick-match (not (rcirc-channel-p rcirc-target))) 1006 (when (or nick-match (not (rcirc-channel-p rcirc-target)))
934 'nick))))) 1007 'nick)))))
935 1008
1009 (sit-for 0) ; displayed text before hook
936 (run-hook-with-args 'rcirc-print-hooks 1010 (run-hook-with-args 'rcirc-print-hooks
937 process sender response target text)))) 1011 process sender response target text))))
938 1012
@@ -948,11 +1022,7 @@ record activity."
948 "Join CHANNELS." 1022 "Join CHANNELS."
949 (save-window-excursion 1023 (save-window-excursion
950 (mapc (lambda (channel) 1024 (mapc (lambda (channel)
951 (with-current-buffer (process-buffer process) 1025 (with-rcirc-process-buffer process
952 (let (rcirc-last-buffer) ; make sure /join text is
953 ; printed in server buffer
954 (rcirc-print process (rcirc-nick process) "COMMAND"
955 nil (concat "/join " channel)))
956 (rcirc-cmd-join channel process))) 1026 (rcirc-cmd-join channel process)))
957 channels))) 1027 channels)))
958 1028
@@ -972,16 +1042,16 @@ record activity."
972(defun rcirc-nick-channels (process nick) 1042(defun rcirc-nick-channels (process nick)
973 "Return list of channels for NICK." 1043 "Return list of channels for NICK."
974 (let ((nick (rcirc-user-nick nick))) 1044 (let ((nick (rcirc-user-nick nick)))
975 (with-current-buffer (process-buffer process) 1045 (with-rcirc-process-buffer process
976 (mapcar (lambda (x) (car x)) 1046 (mapcar (lambda (x) (car x))
977 (gethash nick rcirc-nick-table))))) 1047 (gethash nick rcirc-nick-table)))))
978 1048
979(defun rcirc-put-nick-channel (process nick channel) 1049(defun rcirc-put-nick-channel (process nick channel)
980 "Add CHANNEL to list associated with NICK." 1050 "Add CHANNEL to list associated with NICK."
981 (with-current-buffer (process-buffer process) 1051 (with-rcirc-process-buffer process
982 (let* ((nick (rcirc-user-nick nick)) 1052 (let* ((nick (rcirc-user-nick nick))
983 (chans (gethash nick rcirc-nick-table)) 1053 (chans (gethash nick rcirc-nick-table))
984 (record (assoc channel chans))) 1054 (record (assoc-string channel chans t)))
985 (if record 1055 (if record
986 (setcdr record (current-time)) 1056 (setcdr record (current-time))
987 (puthash nick (cons (cons channel (current-time)) 1057 (puthash nick (cons (cons channel (current-time))
@@ -990,26 +1060,31 @@ record activity."
990 1060
991(defun rcirc-nick-remove (process nick) 1061(defun rcirc-nick-remove (process nick)
992 "Remove NICK from table." 1062 "Remove NICK from table."
993 (with-current-buffer (process-buffer process) 1063 (with-rcirc-process-buffer process
994 (remhash nick rcirc-nick-table))) 1064 (remhash nick rcirc-nick-table)))
995 1065
996(defun rcirc-remove-nick-channel (process nick channel) 1066(defun rcirc-remove-nick-channel (process nick channel)
997 "Remove the CHANNEL from list associated with NICK." 1067 "Remove the CHANNEL from list associated with NICK."
998 (with-current-buffer (process-buffer process) 1068 (with-rcirc-process-buffer process
999 (let* ((nick (rcirc-user-nick nick)) 1069 (let* ((nick (rcirc-user-nick nick))
1000 (chans (gethash nick rcirc-nick-table)) 1070 (chans (gethash nick rcirc-nick-table))
1001 (newchans (assq-delete-all channel chans))) 1071 (newchans
1072 ;; instead of assoc-string-delete-all:
1073 (let ((record (assoc-string channel chans t)))
1074 (when record
1075 (setcar record 'delete)
1076 (assq-delete-all 'delete chans)))))
1002 (if newchans 1077 (if newchans
1003 (puthash nick newchans rcirc-nick-table) 1078 (puthash nick newchans rcirc-nick-table)
1004 (remhash nick rcirc-nick-table))))) 1079 (remhash nick rcirc-nick-table)))))
1005 1080
1006(defun rcirc-channel-nicks (process channel) 1081(defun rcirc-channel-nicks (process channel)
1007 "Return the list of nicks in CHANNEL sorted by last activity." 1082 "Return the list of nicks in CHANNEL sorted by last activity."
1008 (with-current-buffer (process-buffer process) 1083 (with-rcirc-process-buffer process
1009 (let (nicks) 1084 (let (nicks)
1010 (maphash 1085 (maphash
1011 (lambda (k v) 1086 (lambda (k v)
1012 (let ((record (assoc channel v))) 1087 (let ((record (assoc-string channel v t)))
1013 (if record 1088 (if record
1014 (setq nicks (cons (cons k (cdr record)) nicks))))) 1089 (setq nicks (cons (cons k (cdr record)) nicks)))))
1015 rcirc-nick-table) 1090 rcirc-nick-table)
@@ -1017,12 +1092,12 @@ record activity."
1017 (sort nicks (lambda (x y) (time-less-p (cdr y) (cdr x)))))))) 1092 (sort nicks (lambda (x y) (time-less-p (cdr y) (cdr x))))))))
1018 1093
1019;;; activity tracking 1094;;; activity tracking
1020(or (assq 'rcirc-ignore-channel-activity minor-mode-alist) 1095(or (assq 'rcirc-ignore-buffer-activity-flag minor-mode-alist)
1021 (setq minor-mode-alist 1096 (setq minor-mode-alist
1022 (cons '(rcirc-ignore-channel-activity " Ignore") minor-mode-alist))) 1097 (cons '(rcirc-ignore-buffer-activity-flag " Ignore") minor-mode-alist)))
1023 1098
1024(defun rcirc-toggle-ignore-channel-activity (&optional all) 1099(defun rcirc-toggle-ignore-buffer-activity (&optional all)
1025 "Toggle the value of `rcirc-ignore-channel-activity'. 1100 "Toggle the value of `rcirc-ignore-buffer-activity-flag'.
1026If ALL is non-nil, instead toggle the value of 1101If ALL is non-nil, instead toggle the value of
1027`rcirc-ignore-all-activity-flag'." 1102`rcirc-ignore-all-activity-flag'."
1028 (interactive "P") 1103 (interactive "P")
@@ -1030,13 +1105,15 @@ If ALL is non-nil, instead toggle the value of
1030 (progn 1105 (progn
1031 (setq rcirc-ignore-all-activity-flag 1106 (setq rcirc-ignore-all-activity-flag
1032 (not rcirc-ignore-all-activity-flag)) 1107 (not rcirc-ignore-all-activity-flag))
1033 (message (concat "Global activity " 1108 (message (if rcirc-ignore-all-activity-flag
1034 (if rcirc-ignore-all-activity-flag 1109 "Hide all buffer activity"
1035 "hidden" 1110 "Display buffer activity"))
1036 "displayed")))
1037 (rcirc-update-activity-string)) 1111 (rcirc-update-activity-string))
1038 (setq rcirc-ignore-channel-activity 1112 (setq rcirc-ignore-buffer-activity-flag
1039 (not rcirc-ignore-channel-activity))) 1113 (not rcirc-ignore-buffer-activity-flag))
1114 (message (if rcirc-ignore-buffer-activity-flag
1115 "Ignore activity in this buffer"
1116 "Notice activity in this buffer")))
1040 (force-mode-line-update)) 1117 (force-mode-line-update))
1041 1118
1042(defvar rcirc-switch-to-buffer-function 'switch-to-buffer 1119(defvar rcirc-switch-to-buffer-function 'switch-to-buffer
@@ -1069,29 +1146,30 @@ show the buffer."
1069 (setq rcirc-last-non-irc-buffer (current-buffer))) 1146 (setq rcirc-last-non-irc-buffer (current-buffer)))
1070 (if (and (> arg 0) 1147 (if (and (> arg 0)
1071 (<= arg (length rcirc-activity))) 1148 (<= arg (length rcirc-activity)))
1072 (funcall rcirc-switch-to-buffer-function 1149 (funcall rcirc-switch-to-buffer-function
1073 (nth (1- arg) rcirc-activity)) 1150 (nth (1- arg) rcirc-activity))
1074 (message "Invalid arg: %d" arg))) 1151 (message "Invalid arg: %d" arg)))
1075 (if (eq major-mode 'rcirc-mode) 1152 (if (eq major-mode 'rcirc-mode)
1076 (if (not (and rcirc-last-non-irc-buffer 1153 (if (not (and rcirc-last-non-irc-buffer
1077 (buffer-live-p rcirc-last-non-irc-buffer))) 1154 (buffer-live-p rcirc-last-non-irc-buffer)))
1078 (message "No last buffer.") 1155 (message "No IRC activity. Start something.")
1156 (message "No more IRC activity. Go back to work.")
1079 (funcall rcirc-switch-to-buffer-function rcirc-last-non-irc-buffer) 1157 (funcall rcirc-switch-to-buffer-function rcirc-last-non-irc-buffer)
1080 (setq rcirc-last-non-irc-buffer nil)) 1158 (setq rcirc-last-non-irc-buffer nil))
1081 (message "No channel activity. Go start something.")))) 1159 (message "No IRC activity."))))
1082 1160
1083(defvar rcirc-activity-hooks nil 1161(defvar rcirc-activity-hooks nil
1084 "Hook to be run when there is channel activity. 1162 "Hook to be run when there is channel activity.
1085 1163
1086Functions are called with a single argument, the buffer with the 1164Functions are called with a single argument, the buffer with the
1087activity. Only run if the buffer is not visible and 1165activity. Only run if the buffer is not visible and
1088`rcirc-ignore-channel-activity' is non-nil.") 1166`rcirc-ignore-buffer-activity-flag' is non-nil.")
1089 1167
1090(defun rcirc-record-activity (buffer type) 1168(defun rcirc-record-activity (buffer type)
1091 "Record BUFFER activity with TYPE." 1169 "Record BUFFER activity with TYPE."
1092 (with-current-buffer buffer 1170 (with-current-buffer buffer
1093 (when (not (get-buffer-window (current-buffer) t)) 1171 (when (not (get-buffer-window (current-buffer) t))
1094 (add-to-list 'rcirc-activity (current-buffer) 'append) 1172 (add-to-list 'rcirc-activity (current-buffer))
1095 (if (not rcirc-activity-type) 1173 (if (not rcirc-activity-type)
1096 (setq rcirc-activity-type type)) 1174 (setq rcirc-activity-type type))
1097 (rcirc-update-activity-string))) 1175 (rcirc-update-activity-string)))
@@ -1103,38 +1181,115 @@ activity. Only run if the buffer is not visible and
1103 (with-current-buffer buffer 1181 (with-current-buffer buffer
1104 (setq rcirc-activity-type nil))) 1182 (setq rcirc-activity-type nil)))
1105 1183
1184;; TODO: add mouse properties
1106(defun rcirc-update-activity-string () 1185(defun rcirc-update-activity-string ()
1107 "Update mode-line string." 1186 "Update mode-line string."
1108 (setq rcirc-activity-string 1187 (setq rcirc-activity-string
1109 (if (or rcirc-ignore-all-activity-flag 1188 (cond (rcirc-ignore-all-activity-flag
1110 (not rcirc-activity)) 1189 " DND")
1111 "" 1190 ((not rcirc-activity)
1112 (concat " [" (mapconcat 1191 "")
1192 (t
1193 (concat " ["
1194 (mapconcat
1113 (lambda (b) 1195 (lambda (b)
1114 (let ((s (rcirc-short-buffer-name b))) 1196 (let ((s (rcirc-short-buffer-name b)))
1115 (with-current-buffer b 1197 (with-current-buffer b
1116 (if (not (eq rcirc-activity-type 'nick)) 1198 (if (not (eq rcirc-activity-type 'nick))
1117 s 1199 s
1118 (rcirc-facify s 1200 (rcirc-facify s 'rcirc-mode-line-nick)))))
1119 'rcirc-mode-line-nick-face))))) 1201 rcirc-activity ",")
1120 rcirc-activity ",") "]")))) 1202 "]")))))
1121 1203
1122(defun rcirc-short-buffer-name (buffer) 1204(defun rcirc-short-buffer-name (buffer)
1123 "Return a short name for BUFFER to use in the modeline indicator." 1205 "Return a short name for BUFFER to use in the modeline indicator."
1124 (with-current-buffer buffer 1206 (with-current-buffer buffer
1125 (or rcirc-target (process-name rcirc-process)))) 1207 (or rcirc-short-buffer-name (buffer-name))))
1126 1208
1127(defun rcirc-update-activity () 1209(defvar rcirc-current-buffer nil)
1128 "Go through visible windows and remove buffers from activity list." 1210(defun rcirc-window-configuration-change ()
1129 (walk-windows (lambda (w) (rcirc-clear-activity (window-buffer w)))) 1211 "Go through visible windows and remove buffers from activity list.
1130 (rcirc-update-activity-string)) 1212Also, clear the overlay arrow if the current buffer is now hidden."
1213 (let ((current-now-hidden t))
1214 (walk-windows (lambda (w)
1215 (let ((buf (window-buffer w)))
1216 (rcirc-clear-activity buf)
1217 (when (eq buf rcirc-current-buffer)
1218 (setq current-now-hidden nil)))))
1219 (when (and rcirc-current-buffer current-now-hidden)
1220 (with-current-buffer rcirc-current-buffer
1221 (when (eq major-mode 'rcirc-mode)
1222 (marker-position overlay-arrow-position)
1223 (set-marker overlay-arrow-position nil)))))
1224
1225 ;; remove any killed buffers from list
1226 (setq rcirc-activity
1227 (delq nil (mapcar (lambda (buf) (when (buffer-live-p buf) buf))
1228 rcirc-activity)))
1229 (rcirc-update-activity-string)
1230 (setq rcirc-current-buffer (current-buffer)))
1131 1231
1132 1232
1233;;; buffer name abbreviation
1234(defun rcirc-update-short-buffer-names ()
1235 (let ((bufalist
1236 (apply 'append (mapcar (lambda (process)
1237 (with-rcirc-process-buffer process
1238 rcirc-buffer-alist))
1239 (rcirc-process-list)))))
1240 (dolist (i (rcirc-abbreviate bufalist))
1241 (with-current-buffer (cdr i)
1242 (setq rcirc-short-buffer-name (car i))))))
1243
1244(defun rcirc-abbreviate (pairs)
1245 (apply 'append (mapcar 'rcirc-rebuild-tree (rcirc-make-trees pairs))))
1246
1247(defun rcirc-rebuild-tree (tree &optional acc)
1248 (let ((ch (char-to-string (car tree))))
1249 (dolist (x (cdr tree))
1250 (if (listp x)
1251 (setq acc (append acc
1252 (mapcar (lambda (y)
1253 (cons (concat ch (car y))
1254 (cdr y)))
1255 (rcirc-rebuild-tree x))))
1256 (setq acc (cons (cons ch x) acc))))
1257 acc))
1258
1259(defun rcirc-make-trees (pairs)
1260 (let (alist)
1261 (mapc (lambda (pair)
1262 (if (consp pair)
1263 (let* ((str (car pair))
1264 (data (cdr pair))
1265 (char (unless (zerop (length str))
1266 (aref str 0)))
1267 (rest (unless (zerop (length str))
1268 (substring str 1)))
1269 (part (if char (assq char alist))))
1270 (if part
1271 ;; existing partition
1272 (setcdr part (cons (cons rest data) (cdr part)))
1273 ;; new partition
1274 (setq alist (cons (if char
1275 (list char (cons rest data))
1276 data)
1277 alist))))
1278 (setq alist (cons pair alist))))
1279 pairs)
1280 ;; recurse into cdrs of alist
1281 (mapc (lambda (x)
1282 (when (and (listp x) (listp (cadr x)))
1283 (setcdr x (if (> (length (cdr x)) 1)
1284 (rcirc-make-trees (cdr x))
1285 (setcdr x (list (cdadr x)))))))
1286 alist)))
1287
1133;;; /commands these are called with 3 args: PROCESS, TARGET, which is 1288;;; /commands these are called with 3 args: PROCESS, TARGET, which is
1134;; the current buffer/channel/user, and ARGS, which is a string 1289;; the current buffer/channel/user, and ARGS, which is a string
1135;; containing the text following the /cmd. 1290;; containing the text following the /cmd.
1136 1291
1137(defmacro defun-rcirc-command (command argument docstring interactive-form 1292(defmacro defun-rcirc-command (command argument docstring interactive-form
1138 &rest body) 1293 &rest body)
1139 "Define a command." 1294 "Define a command."
1140 `(defun ,(intern (concat "rcirc-cmd-" (symbol-name command))) 1295 `(defun ,(intern (concat "rcirc-cmd-" (symbol-name command)))
@@ -1153,8 +1308,7 @@ activity. Only run if the buffer is not visible and
1153 (if (null message) 1308 (if (null message)
1154 (progn 1309 (progn
1155 (setq target (completing-read "Message nick: " 1310 (setq target (completing-read "Message nick: "
1156 (with-current-buffer 1311 (with-rcirc-process-buffer rcirc-process
1157 (process-buffer rcirc-process)
1158 rcirc-nick-table))) 1312 rcirc-nick-table)))
1159 (when (> (length target) 0) 1313 (when (> (length target) 0)
1160 (setq message (read-string (format "Message %s: " target))) 1314 (setq message (read-string (format "Message %s: " target)))
@@ -1169,13 +1323,12 @@ activity. Only run if the buffer is not visible and
1169(defun-rcirc-command query (nick) 1323(defun-rcirc-command query (nick)
1170 "Open a private chat buffer to NICK." 1324 "Open a private chat buffer to NICK."
1171 (interactive (list (completing-read "Query nick: " 1325 (interactive (list (completing-read "Query nick: "
1172 (with-current-buffer 1326 (with-rcirc-process-buffer rcirc-process
1173 (process-buffer rcirc-process)
1174 rcirc-nick-table)))) 1327 rcirc-nick-table))))
1175 (let ((new-buffer (eq (rcirc-get-buffer rcirc-process nick) 1328 (let ((existing-buffer (rcirc-get-buffer process nick)))
1176 (process-buffer rcirc-process)))) 1329 (switch-to-buffer (or existing-buffer
1177 (switch-to-buffer (rcirc-get-buffer-create process nick)) 1330 (rcirc-get-buffer-create process nick)))
1178 (when new-buffer 1331 (when (not existing-buffer)
1179 (rcirc-cmd-whois nick)))) 1332 (rcirc-cmd-whois nick))))
1180 1333
1181(defun-rcirc-command join (args) 1334(defun-rcirc-command join (args)
@@ -1185,19 +1338,21 @@ activity. Only run if the buffer is not visible and
1185 (buffer (rcirc-get-buffer-create process channel))) 1338 (buffer (rcirc-get-buffer-create process channel)))
1186 (when (not (eq (selected-window) (minibuffer-window))) 1339 (when (not (eq (selected-window) (minibuffer-window)))
1187 (funcall rcirc-switch-to-buffer-function buffer)) 1340 (funcall rcirc-switch-to-buffer-function buffer))
1188 (rcirc-send-string process (concat "JOIN " args)) 1341 (rcirc-send-string process (concat "JOIN " args))))
1189 (rcirc-set-last-buffer process buffer)))
1190 1342
1191(defun-rcirc-command part (channel) 1343(defun-rcirc-command part (channel)
1192 "Part CHANNEL." 1344 "Part CHANNEL."
1193 (interactive "sPart channel: ") 1345 (interactive "sPart channel: ")
1194 (let ((channel (if (> (length channel) 0) channel target))) 1346 (let ((channel (if (> (length channel) 0) channel target)))
1195 (rcirc-send-string process (concat "PART " channel " :" (rcirc-version))))) 1347 (rcirc-send-string process (concat "PART " channel " :" rcirc-id-string))))
1196 1348
1197(defun-rcirc-command quit (reason) 1349(defun-rcirc-command quit (reason)
1198 "Send a quit message to server with REASON." 1350 "Send a quit message to server with REASON."
1199 (interactive "sQuit reason: ") 1351 (interactive "sQuit reason: ")
1200 (rcirc-send-string process (concat "QUIT :" reason))) 1352 (rcirc-send-string process (concat "QUIT :"
1353 (if (not (zerop (length reason)))
1354 reason
1355 rcirc-id-string))))
1201 1356
1202(defun-rcirc-command nick (nick) 1357(defun-rcirc-command nick (nick)
1203 "Change nick to NICK." 1358 "Change nick to NICK."
@@ -1232,10 +1387,8 @@ With a prefix arg, prompt for new topic."
1232 "Request information from server about NICK." 1387 "Request information from server about NICK."
1233 (interactive (list 1388 (interactive (list
1234 (completing-read "Whois: " 1389 (completing-read "Whois: "
1235 (with-current-buffer 1390 (with-rcirc-process-buffer rcirc-process
1236 (process-buffer rcirc-process)
1237 rcirc-nick-table)))) 1391 rcirc-nick-table))))
1238 (rcirc-set-last-buffer rcirc-process (current-buffer))
1239 (rcirc-send-string process (concat "WHOIS " nick))) 1392 (rcirc-send-string process (concat "WHOIS " nick)))
1240 1393
1241(defun-rcirc-command mode (args) 1394(defun-rcirc-command mode (args)
@@ -1267,7 +1420,7 @@ With a prefix arg, prompt for new topic."
1267 rcirc-target)) 1420 rcirc-target))
1268 (read-from-minibuffer "Kick reason: ")))) 1421 (read-from-minibuffer "Kick reason: "))))
1269 (let* ((arglist (split-string arg)) 1422 (let* ((arglist (split-string arg))
1270 (argstring (concat (car arglist) " :" 1423 (argstring (concat (car arglist) " :"
1271 (mapconcat 'identity (cdr arglist) " ")))) 1424 (mapconcat 'identity (cdr arglist) " "))))
1272 (rcirc-send-string process (concat "KICK " target " " argstring)))) 1425 (rcirc-send-string process (concat "KICK " target " " argstring))))
1273 1426
@@ -1275,9 +1428,10 @@ With a prefix arg, prompt for new topic."
1275 (if (string-match "^\\([^ ]+\\)\\s-+\\(.+\\)$" args) 1428 (if (string-match "^\\([^ ]+\\)\\s-+\\(.+\\)$" args)
1276 (let ((target (match-string 1 args)) 1429 (let ((target (match-string 1 args))
1277 (request (match-string 2 args))) 1430 (request (match-string 2 args)))
1278 (rcirc-send-message process target 1431 (rcirc-send-string process
1279 (concat "\C-a" (upcase request) "\C-a"))) 1432 (format "PRIVMSG %s \C-a%s\C-a"
1280 (rcirc-print process (rcirc-nick process) "ERROR" target 1433 target (upcase request))))
1434 (rcirc-print process (rcirc-nick process) "ERROR" nil
1281 "usage: /ctcp NICK REQUEST"))) 1435 "usage: /ctcp NICK REQUEST")))
1282 1436
1283(defun rcirc-cmd-me (args &optional process target) 1437(defun rcirc-cmd-me (args &optional process target)
@@ -1287,7 +1441,7 @@ With a prefix arg, prompt for new topic."
1287(defun rcirc-message-leader (sender face) 1441(defun rcirc-message-leader (sender face)
1288 "Return a string with SENDER propertized with FACE." 1442 "Return a string with SENDER propertized with FACE."
1289 (rcirc-facify (concat "<" (rcirc-user-nick sender) "> ") face)) 1443 (rcirc-facify (concat "<" (rcirc-user-nick sender) "> ") face))
1290 1444
1291(defun rcirc-facify (string face) 1445(defun rcirc-facify (string face)
1292 "Return a copy of STRING with FACE property added." 1446 "Return a copy of STRING with FACE property added."
1293 (propertize (or string "") 'face face 'rear-nonsticky t)) 1447 (propertize (or string "") 'face face 'rear-nonsticky t))
@@ -1309,6 +1463,20 @@ With a prefix arg, prompt for new topic."
1309 completions nil nil initial-input 'history) 1463 completions nil nil initial-input 'history)
1310 arg))) 1464 arg)))
1311 1465
1466(defun rcirc-browse-url-at-point (point)
1467 "Send URL at point to `browse-url'."
1468 (interactive "d")
1469 (let ((beg (previous-single-property-change point 'mouse-face))
1470 (end (next-single-property-change point 'mouse-face)))
1471 (browse-url (buffer-substring-no-properties beg end))))
1472
1473(defun rcirc-browse-url-at-mouse (event)
1474 "Send URL at mouse click to `browse-url'."
1475 (interactive "e")
1476 (let ((position (event-end event)))
1477 (with-current-buffer (window-buffer (posn-window position))
1478 (rcirc-browse-url-at-point (posn-point position)))))
1479
1312(defun rcirc-map-regexp (function regexp string) 1480(defun rcirc-map-regexp (function regexp string)
1313 "Return a copy of STRING after calling FUNCTION for each REGEXP match. 1481 "Return a copy of STRING after calling FUNCTION for each REGEXP match.
1314FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING." 1482FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
@@ -1346,7 +1514,7 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1346 (rcirc-map-regexp (lambda (start end string) 1514 (rcirc-map-regexp (lambda (start end string)
1347 (add-text-properties 1515 (add-text-properties
1348 start end 1516 start end
1349 (list 'face 'rcirc-nick-in-message-face 1517 (list 'face 'rcirc-nick-in-message
1350 'rear-nonsticky t) 1518 'rear-nonsticky t)
1351 string)) 1519 string))
1352 (concat "\\b" 1520 (concat "\\b"
@@ -1360,7 +1528,9 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1360 (let ((orig-face (get-text-property start 'face string))) 1528 (let ((orig-face (get-text-property start 'face string)))
1361 (add-text-properties start end 1529 (add-text-properties start end
1362 (list 'face (list orig-face 'bold) 1530 (list 'face (list orig-face 'bold)
1363 'rear-nonsticky t) 1531 'rear-nonsticky t
1532 'mouse-face 'highlight
1533 'keymap rcirc-browse-url-map)
1364 string)) 1534 string))
1365 (push (substring string start end) rcirc-urls)) 1535 (push (substring string start end) rcirc-urls))
1366 rcirc-url-regexp 1536 rcirc-url-regexp
@@ -1376,13 +1546,12 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1376(defun rcirc-handler-001 (process sender args text) 1546(defun rcirc-handler-001 (process sender args text)
1377 (rcirc-handler-generic process "001" sender args text) 1547 (rcirc-handler-generic process "001" sender args text)
1378 ;; set the real server name 1548 ;; set the real server name
1379 (with-current-buffer (process-buffer process) 1549 (with-rcirc-process-buffer process
1380 (setq rcirc-server sender) 1550 (setq rcirc-server sender)
1381 (setq rcirc-nick (car args)) 1551 (setq rcirc-nick (car args))
1382 (rcirc-update-prompt) 1552 (rcirc-update-prompt)
1383 (when rcirc-auto-authenticate-flag (rcirc-authenticate)) 1553 (when rcirc-auto-authenticate-flag (rcirc-authenticate))
1384 (let (rcirc-last-buffer) 1554 (rcirc-join-channels process rcirc-startup-channels)))
1385 (rcirc-join-channels process rcirc-startup-channels))))
1386 1555
1387(defun rcirc-handler-PRIVMSG (process sender args text) 1556(defun rcirc-handler-PRIVMSG (process sender args text)
1388 (let ((target (if (rcirc-channel-p (car args)) 1557 (let ((target (if (rcirc-channel-p (car args))
@@ -1399,56 +1568,60 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1399(defun rcirc-handler-NOTICE (process sender args text) 1568(defun rcirc-handler-NOTICE (process sender args text)
1400 (let ((target (car args)) 1569 (let ((target (car args))
1401 (message (cadr args))) 1570 (message (cadr args)))
1402 (rcirc-print process sender "NOTICE" 1571 (if (string-match "^\C-a\\(.*\\)\C-a$" message)
1403 (cond ((rcirc-channel-p target) 1572 (rcirc-handler-CTCP-response process target sender
1404 target) 1573 (match-string 1 message))
1405 ((string-match "^\\[\\(#[^ ]+\\)\\]" message) 1574 (rcirc-print process sender "NOTICE"
1406 (match-string 1 message)) 1575 (cond ((rcirc-channel-p target)
1407 (sender 1576 target)
1408 (if (string= sender (rcirc-server process)) 1577 ;;; -ChanServ- [#gnu] Welcome...
1409 (process-buffer process) 1578 ((string-match "^\\[\\(#[^ ]+\\)\\]" message)
1410 (rcirc-user-nick sender)))) 1579 (match-string 1 message))
1411 message t) 1580 (sender
1412 (and sender (rcirc-put-nick-channel process sender target)))) 1581 (if (string= sender (rcirc-server process))
1582 (process-buffer process)
1583 (rcirc-user-nick sender))))
1584 message t))))
1585 ;; do we need this:
1586 ;;(and sender (rcirc-put-nick-channel process sender target))))
1413 1587
1414(defun rcirc-handler-WALLOPS (process sender args text) 1588(defun rcirc-handler-WALLOPS (process sender args text)
1415 (let ((target (rcirc-user-nick sender))) 1589 (let ((target (rcirc-user-nick sender)))
1416 (rcirc-print process sender "WALLOPS" target (car args) t))) 1590 (rcirc-print process sender "WALLOPS" target (car args) t)))
1417 1591
1418(defun rcirc-handler-JOIN (process sender args text) 1592(defun rcirc-handler-JOIN (process sender args text)
1419 (let ((channel (downcase (car args))) 1593 (let ((channel (car args))
1420 (nick (rcirc-user-nick sender))) 1594 (nick (rcirc-user-nick sender)))
1421 (rcirc-get-buffer-create process channel) 1595 (rcirc-get-buffer-create process channel)
1422 (rcirc-print process sender "JOIN" channel "") 1596 (rcirc-print process sender "JOIN" channel "")
1423 1597
1424 ;; print in private chat buffer if it exists 1598 ;; print in private chat buffer if it exists
1425 (if (not (eq (process-buffer rcirc-process) 1599 (when (rcirc-get-buffer rcirc-process nick)
1426 (rcirc-get-buffer rcirc-process nick))) 1600 (rcirc-print process sender "JOIN" nick channel))
1427 (rcirc-print process sender "JOIN" nick channel))
1428 1601
1429 (rcirc-put-nick-channel process sender channel) 1602 (rcirc-put-nick-channel process sender channel)))
1430 (if (string= nick (rcirc-nick process))
1431 (setq rcirc-channels (cons channel rcirc-channels)))))
1432 1603
1433;; PART and KICK are handled the same way 1604;; PART and KICK are handled the same way
1434(defun rcirc-handler-PART-or-KICK (process response channel sender nick args) 1605(defun rcirc-handler-PART-or-KICK (process response channel sender nick args)
1435 (rcirc-print process sender response channel (concat channel " " args)) 1606 (rcirc-print process sender response channel (concat channel " " args))
1436 1607
1437 ;; print in private chat buffer if it exists 1608 ;; print in private chat buffer if it exists
1438 (when (not (eq (process-buffer rcirc-process) 1609 (when (rcirc-get-buffer rcirc-process nick)
1439 (rcirc-get-buffer rcirc-process nick)))
1440 (rcirc-print process sender response nick (concat channel " " args))) 1610 (rcirc-print process sender response nick (concat channel " " args)))
1441 1611
1442 (if (not (string= nick (rcirc-nick process))) 1612 (if (not (string= nick (rcirc-nick process)))
1443 ;; this is someone else leaving 1613 ;; this is someone else leaving
1444 (rcirc-remove-nick-channel process nick channel) 1614 (rcirc-remove-nick-channel process nick channel)
1445 ;; this is us leaving 1615 ;; this is us leaving
1446 (mapc (lambda (n) 1616 (mapc (lambda (n)
1447 (rcirc-remove-nick-channel process n channel)) 1617 (rcirc-remove-nick-channel process n channel))
1448 (rcirc-channel-nicks process channel)) 1618 (rcirc-channel-nicks process channel))
1449 (setq rcirc-channels (delete channel rcirc-channels)) 1619
1450 (with-current-buffer (rcirc-get-buffer process channel) 1620 ;; if the buffer is still around, make it inactive
1451 (setq rcirc-target nil)))) 1621 (let ((buffer (rcirc-get-buffer process channel)))
1622 (when buffer
1623 (with-current-buffer buffer
1624 (setq rcirc-target nil))))))
1452 1625
1453(defun rcirc-handler-PART (process sender args text) 1626(defun rcirc-handler-PART (process sender args text)
1454 (rcirc-handler-PART-or-KICK process "PART" 1627 (rcirc-handler-PART-or-KICK process "PART"
@@ -1456,7 +1629,7 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1456 (cadr args))) 1629 (cadr args)))
1457 1630
1458(defun rcirc-handler-KICK (process sender args text) 1631(defun rcirc-handler-KICK (process sender args text)
1459 (rcirc-handler-PART-or-KICK process "KICK" (car args) sender (cadr args) 1632 (rcirc-handler-PART-or-KICK process "KICK" (car args) sender (cadr args)
1460 (caddr args))) 1633 (caddr args)))
1461 1634
1462(defun rcirc-handler-QUIT (process sender args text) 1635(defun rcirc-handler-QUIT (process sender args text)
@@ -1466,9 +1639,9 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1466 (rcirc-nick-channels process nick)) 1639 (rcirc-nick-channels process nick))
1467 1640
1468 ;; print in private chat buffer if it exists 1641 ;; print in private chat buffer if it exists
1469 (if (not (eq (process-buffer rcirc-process) 1642 (let ((buffer (rcirc-get-buffer rcirc-process nick)))
1470 (rcirc-get-buffer rcirc-process nick))) 1643 (when buffer
1471 (rcirc-print process sender "QUIT" nick (apply 'concat args))) 1644 (rcirc-print process sender "QUIT" buffer (apply 'concat args))))
1472 1645
1473 (rcirc-nick-remove process nick))) 1646 (rcirc-nick-remove process nick)))
1474 1647
@@ -1480,25 +1653,21 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1480 (dolist (target channels) 1653 (dolist (target channels)
1481 (rcirc-print process sender "NICK" target new-nick)) 1654 (rcirc-print process sender "NICK" target new-nick))
1482 ;; update private chat buffer, if it exists 1655 ;; update private chat buffer, if it exists
1483 (with-current-buffer (rcirc-get-buffer process old-nick) 1656 (let ((chat-buffer (rcirc-get-buffer process old-nick)))
1484 (when (not (equal (process-buffer rcirc-process) 1657 (when chat-buffer
1485 (current-buffer))) 1658 (with-current-buffer chat-buffer
1486 (rcirc-print process sender "NICK" old-nick new-nick) 1659 (rcirc-print process sender "NICK" old-nick new-nick)
1487 (setq rcirc-target new-nick) 1660 (setq rcirc-target new-nick)
1488 (rename-buffer (rcirc-get-buffer-name process new-nick)))) 1661 (rename-buffer (rcirc-generate-new-buffer-name process new-nick)))))
1489 ;; remove old nick and add new one 1662 ;; remove old nick and add new one
1490 (with-current-buffer (process-buffer process) 1663 (with-rcirc-process-buffer process
1491 (let ((v (gethash old-nick rcirc-nick-table))) 1664 (let ((v (gethash old-nick rcirc-nick-table)))
1492 (remhash old-nick rcirc-nick-table) 1665 (remhash old-nick rcirc-nick-table)
1493 (puthash new-nick v rcirc-nick-table)) 1666 (puthash new-nick v rcirc-nick-table))
1494 ;; if this is our nick... 1667 ;; if this is our nick...
1495 (when (string= old-nick rcirc-nick) 1668 (when (string= old-nick rcirc-nick)
1496 (setq rcirc-nick new-nick) 1669 (setq rcirc-nick new-nick)
1497 ;; update prompts 1670 (rcirc-update-prompt t)
1498 (mapc (lambda (target)
1499 (with-current-buffer (rcirc-get-buffer process target)
1500 (rcirc-update-prompt)))
1501 (append rcirc-channels rcirc-private-chats))
1502 ;; reauthenticate 1671 ;; reauthenticate
1503 (when rcirc-auto-authenticate-flag (rcirc-authenticate)))))) 1672 (when rcirc-auto-authenticate-flag (rcirc-authenticate))))))
1504 1673
@@ -1517,18 +1686,22 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1517 1686
1518(defun rcirc-handler-332 (process sender args text) 1687(defun rcirc-handler-332 (process sender args text)
1519 "RPL_TOPIC" 1688 "RPL_TOPIC"
1520 (with-current-buffer (rcirc-get-buffer process (cadr args)) 1689 (let ((buffer (or (rcirc-get-buffer process (cadr args))
1521 (setq rcirc-topic (caddr args)))) 1690 (rcirc-get-temp-buffer-create process (cadr args)))))
1691 (with-current-buffer buffer
1692 (setq rcirc-topic (caddr args)))))
1522 1693
1523(defun rcirc-handler-333 (process sender args text) 1694(defun rcirc-handler-333 (process sender args text)
1524 "Not in rfc1459.txt" 1695 "Not in rfc1459.txt"
1525 (with-current-buffer (rcirc-get-buffer process (cadr args)) 1696 (let ((buffer (or (rcirc-get-buffer process (cadr args))
1526 (let ((setter (caddr args)) 1697 (rcirc-get-temp-buffer-create process (cadr args)))))
1527 (time (current-time-string 1698 (with-current-buffer buffer
1528 (seconds-to-time 1699 (let ((setter (caddr args))
1529 (string-to-number (cadddr args)))))) 1700 (time (current-time-string
1530 (rcirc-print process sender "TOPIC" (cadr args) 1701 (seconds-to-time
1531 (format "%s (%s on %s)" rcirc-topic setter time))))) 1702 (string-to-number (cadddr args))))))
1703 (rcirc-print process sender "TOPIC" (cadr args)
1704 (format "%s (%s on %s)" rcirc-topic setter time))))))
1532 1705
1533(defun rcirc-handler-477 (process sender args text) 1706(defun rcirc-handler-477 (process sender args text)
1534 "ERR_NOCHANMODES" 1707 "ERR_NOCHANMODES"
@@ -1545,10 +1718,10 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1545 1718
1546 ;; print in private chat buffers if they exist 1719 ;; print in private chat buffers if they exist
1547 (mapc (lambda (nick) 1720 (mapc (lambda (nick)
1548 (when (not (eq (process-buffer rcirc-process) 1721 (let ((existing-buffer (rcirc-get-buffer process nick)))
1549 (rcirc-get-buffer rcirc-process nick))) 1722 (when existing-buffer
1550 (rcirc-print process sender "MODE" nick msg))) 1723 (rcirc-print process sender "MODE" existing-buffer msg))))
1551 (cddr args)))) 1724 (cddr args))))
1552 1725
1553(defun rcirc-get-temp-buffer-create (process channel) 1726(defun rcirc-get-temp-buffer-create (process channel)
1554 "Return a buffer based on PROCESS and CHANNEL." 1727 "Return a buffer based on PROCESS and CHANNEL."
@@ -1557,10 +1730,10 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1557 1730
1558(defun rcirc-handler-353 (process sender args text) 1731(defun rcirc-handler-353 (process sender args text)
1559 "RPL_NAMREPLY" 1732 "RPL_NAMREPLY"
1560 (let ((channel (downcase (caddr args)))) 1733 (let ((channel (caddr args)))
1561 (mapc (lambda (nick) 1734 (mapc (lambda (nick)
1562 (rcirc-put-nick-channel process nick channel)) 1735 (rcirc-put-nick-channel process nick channel))
1563 (delete "" (split-string (cadddr args) " "))) 1736 (split-string (cadddr args) " " t))
1564 (with-current-buffer (rcirc-get-temp-buffer-create process channel) 1737 (with-current-buffer (rcirc-get-temp-buffer-create process channel)
1565 (goto-char (point-max)) 1738 (goto-char (point-max))
1566 (insert (car (last args)) " ")))) 1739 (insert (car (last args)) " "))))
@@ -1578,7 +1751,7 @@ FUNCTION takes 3 arguments, MATCH-START, MATCH-END, and STRING."
1578 "ERR_NICKNAMEINUSE" 1751 "ERR_NICKNAMEINUSE"
1579 (rcirc-handler-generic process "433" sender args text) 1752 (rcirc-handler-generic process "433" sender args text)
1580 (let* ((new-nick (concat (cadr args) "`"))) 1753 (let* ((new-nick (concat (cadr args) "`")))
1581 (with-current-buffer (process-buffer process) 1754 (with-rcirc-process-buffer process
1582 (rcirc-cmd-nick new-nick nil process)))) 1755 (rcirc-cmd-nick new-nick nil process))))
1583 1756
1584(defun rcirc-authenticate () 1757(defun rcirc-authenticate ()
@@ -1590,7 +1763,7 @@ Passwords are read from `rcirc-authinfo-file-name' (which see)."
1590 (insert-file-contents-literally rcirc-authinfo-file-name) 1763 (insert-file-contents-literally rcirc-authinfo-file-name)
1591 (goto-char (point-min)) 1764 (goto-char (point-min))
1592 (read (current-buffer))))) 1765 (read (current-buffer)))))
1593 (with-current-buffer (process-buffer rcirc-process) 1766 (with-rcirc-process-buffer rcirc-process
1594 (dolist (i password-alist) 1767 (dolist (i password-alist)
1595 (let ((server (car i)) 1768 (let ((server (car i))
1596 (nick (cadr i)) 1769 (nick (cadr i))
@@ -1602,22 +1775,22 @@ Passwords are read from `rcirc-authinfo-file-name' (which see)."
1602 (rcirc-send-string 1775 (rcirc-send-string
1603 rcirc-process 1776 rcirc-process
1604 (concat 1777 (concat
1605 "PRIVMSG nickserv :identify " 1778 "PRIVMSG nickserv :identify "
1606 (car args)))) 1779 (car args))))
1607 ((equal method 'chanserv) 1780 ((equal method 'chanserv)
1608 (rcirc-send-string 1781 (rcirc-send-string
1609 rcirc-process 1782 rcirc-process
1610 (concat 1783 (concat
1611 "PRIVMSG chanserv :identify " 1784 "PRIVMSG chanserv :identify "
1612 (car args) " " (cadr args)))) 1785 (car args) " " (cadr args))))
1613 ((equal method 'bitlbee) 1786 ((equal method 'bitlbee)
1614 (rcirc-send-string 1787 (rcirc-send-string
1615 rcirc-process 1788 rcirc-process
1616 (concat "PRIVMSG #bitlbee :identify " (car args)))) 1789 (concat "PRIVMSG #bitlbee :identify " (car args))))
1617 (t 1790 (t
1618 (message "No %S authentication method defined" 1791 (message "No %S authentication method defined"
1619 method))))))))) 1792 method)))))))))
1620 1793
1621(defun rcirc-handler-INVITE (process sender args text) 1794(defun rcirc-handler-INVITE (process sender args text)
1622 (rcirc-print process sender "INVITE" nil (mapconcat 'identity args " ") t)) 1795 (rcirc-print process sender "INVITE" nil (mapconcat 'identity args " ") t))
1623 1796
@@ -1631,18 +1804,20 @@ Passwords are read from `rcirc-authinfo-file-name' (which see)."
1631 (nick (rcirc-user-nick sender)) 1804 (nick (rcirc-user-nick sender))
1632 (handler (intern-soft (concat "rcirc-handler-ctcp-" request)))) 1805 (handler (intern-soft (concat "rcirc-handler-ctcp-" request))))
1633 (if (not (fboundp handler)) 1806 (if (not (fboundp handler))
1634 (rcirc-print process sender "ERROR" target 1807 (rcirc-print process sender "ERROR"
1635 (format "unhandled ctcp: %s" text)) 1808 (rcirc-get-buffer process target)
1809 (format "%s sent unsupported ctcp: %s" nick text)
1810 t)
1636 (funcall handler process target sender args) 1811 (funcall handler process target sender args)
1637 (if (not (string= request "ACTION")) 1812 (if (not (string= request "ACTION"))
1638 (rcirc-print process sender "CTCP" target 1813 (rcirc-print process sender "CTCP"
1639 (format "%s" text))))))) 1814 (rcirc-get-buffer process target)
1815 (format "%s" text) t))))))
1640 1816
1641(defun rcirc-handler-ctcp-VERSION (process target sender args) 1817(defun rcirc-handler-ctcp-VERSION (process target sender args)
1642 (rcirc-send-string process 1818 (rcirc-send-string process
1643 (concat "NOTICE " (rcirc-user-nick sender) 1819 (concat "NOTICE " (rcirc-user-nick sender)
1644 " :\C-aVERSION " (rcirc-version) 1820 " :\C-aVERSION " rcirc-id-string
1645 " - http://www.nongnu.org/rcirc"
1646 "\C-a"))) 1821 "\C-a")))
1647 1822
1648(defun rcirc-handler-ctcp-ACTION (process target sender args) 1823(defun rcirc-handler-ctcp-ACTION (process target sender args)
@@ -1652,16 +1827,24 @@ Passwords are read from `rcirc-authinfo-file-name' (which see)."
1652 (rcirc-send-string process 1827 (rcirc-send-string process
1653 (concat "NOTICE " (rcirc-user-nick sender) 1828 (concat "NOTICE " (rcirc-user-nick sender)
1654 " :\C-aTIME " (current-time-string) "\C-a"))) 1829 " :\C-aTIME " (current-time-string) "\C-a")))
1830
1831(defun rcirc-handler-CTCP-response (process target sender message)
1832 (rcirc-print process sender "CTCP" nil message t))
1655 1833
1656(defface rcirc-my-nick-face 1834(defgroup rcirc-faces nil
1835 "Faces for rcirc."
1836 :group 'rcirc
1837 :group 'faces)
1838
1839(defface rcirc-my-nick
1657 '((((type tty) (class color)) (:foreground "blue" :weight bold)) 1840 '((((type tty) (class color)) (:foreground "blue" :weight bold))
1658 (((class color) (background light)) (:foreground "Blue")) 1841 (((class color) (background light)) (:foreground "Blue"))
1659 (((class color) (background dark)) (:foreground "LightSkyBlue")) 1842 (((class color) (background dark)) (:foreground "LightSkyBlue"))
1660 (t (:inverse-video t :bold t))) 1843 (t (:inverse-video t :bold t)))
1661 "The rcirc face used to highlight my messages." 1844 "The face used to highlight my messages."
1662 :group 'rcirc) 1845 :group 'rcirc-faces)
1663 1846
1664(defface rcirc-other-nick-face 1847(defface rcirc-other-nick
1665 '((((type tty) (class color)) (:foreground "yellow" :weight light)) 1848 '((((type tty) (class color)) (:foreground "yellow" :weight light))
1666 (((class grayscale) (background light)) 1849 (((class grayscale) (background light))
1667 (:foreground "Gray90" :bold t :italic t)) 1850 (:foreground "Gray90" :bold t :italic t))
@@ -1670,10 +1853,10 @@ Passwords are read from `rcirc-authinfo-file-name' (which see)."
1670 (((class color) (background light)) (:foreground "DarkGoldenrod")) 1853 (((class color) (background light)) (:foreground "DarkGoldenrod"))
1671 (((class color) (background dark)) (:foreground "LightGoldenrod")) 1854 (((class color) (background dark)) (:foreground "LightGoldenrod"))
1672 (t (:bold t :italic t))) 1855 (t (:bold t :italic t)))
1673 "The rcirc face used to highlight other messages." 1856 "The face used to highlight other messages."
1674 :group 'rcirc) 1857 :group 'rcirc-faces)
1675 1858
1676(defface rcirc-server-face 1859(defface rcirc-server
1677 '((((type tty pc) (class color) (background light)) (:foreground "red")) 1860 '((((type tty pc) (class color) (background light)) (:foreground "red"))
1678 (((type tty pc) (class color) (background dark)) (:foreground "red1")) 1861 (((type tty pc) (class color) (background dark)) (:foreground "red1"))
1679 (((class grayscale) (background light)) 1862 (((class grayscale) (background light))
@@ -1683,31 +1866,31 @@ Passwords are read from `rcirc-authinfo-file-name' (which see)."
1683 (((class color) (background light)) (:foreground "gray40")) 1866 (((class color) (background light)) (:foreground "gray40"))
1684 (((class color) (background dark)) (:foreground "chocolate1")) 1867 (((class color) (background dark)) (:foreground "chocolate1"))
1685 (t (:bold t :italic t))) 1868 (t (:bold t :italic t)))
1686 "The rcirc face used to highlight server messages." 1869 "The face used to highlight server messages."
1687 :group 'rcirc) 1870 :group 'rcirc-faces)
1688 1871
1689(defface rcirc-nick-in-message-face 1872(defface rcirc-nick-in-message
1690 '((((type tty) (class color)) (:foreground "cyan" :weight bold)) 1873 '((((type tty) (class color)) (:foreground "cyan" :weight bold))
1691 (((class grayscale) (background light)) (:foreground "LightGray" :bold t)) 1874 (((class grayscale) (background light)) (:foreground "LightGray" :bold t))
1692 (((class grayscale) (background dark)) (:foreground "DimGray" :bold t)) 1875 (((class grayscale) (background dark)) (:foreground "DimGray" :bold t))
1693 (((class color) (background light)) (:foreground "Purple")) 1876 (((class color) (background light)) (:foreground "Purple"))
1694 (((class color) (background dark)) (:foreground "Cyan")) 1877 (((class color) (background dark)) (:foreground "Cyan"))
1695 (t (:bold t))) 1878 (t (:bold t)))
1696 "The rcirc face used to highlight instances of nick within messages." 1879 "The face used to highlight instances of nick within messages."
1697 :group 'rcirc) 1880 :group 'rcirc-faces)
1698 1881
1699(defface rcirc-prompt-face 1882(defface rcirc-prompt
1700 '((((background dark)) (:foreground "cyan")) 1883 '((((background dark)) (:foreground "cyan"))
1701 (t (:foreground "dark blue"))) 1884 (t (:foreground "dark blue")))
1702 "The rcirc face to use to highlight prompts." 1885 "The face to use to highlight prompts."
1703 :group 'rcirc) 1886 :group 'rcirc-faces)
1704 1887
1705(defface rcirc-mode-line-nick-face 1888(defface rcirc-mode-line-nick
1706 '((t (:bold t))) 1889 '((t (:bold t)))
1707 "The rcirc face used indicate activity directed at you." 1890 "The face used indicate activity directed at you."
1708 :group 'rcirc) 1891 :group 'rcirc-faces)
1709 1892
1710;; When using M-x flyspell-mode, only check words past the input marker 1893;; When using M-x flyspell-mode, only check words after the prompt
1711(put 'rcirc-mode 'flyspell-mode-predicate 'rcirc-looking-at-input) 1894(put 'rcirc-mode 'flyspell-mode-predicate 'rcirc-looking-at-input)
1712(defun rcirc-looking-at-input () 1895(defun rcirc-looking-at-input ()
1713 "Returns true if point is past the input marker." 1896 "Returns true if point is past the input marker."