Improve cusver-check's handling of the version number
[bpt/emacs.git] / lisp / erc / erc-backend.el
CommitLineData
597993cf
MB
1;;; erc-backend.el --- Backend network communication for ERC
2
acaf905b 3;; Copyright (C) 2004-2012 Free Software Foundation, Inc.
597993cf
MB
4
5;; Filename: erc-backend.el
6;; Author: Lawrence Mitchell <wence@gmx.li>
df5d5f59 7;; Maintainer: FSF
597993cf
MB
8;; Created: 2004-05-7
9;; Keywords: IRC chat client internet
10
11;; This file is part of GNU Emacs.
12
4ee57b2a 13;; GNU Emacs is free software: you can redistribute it and/or modify
597993cf 14;; it under the terms of the GNU General Public License as published by
4ee57b2a
GM
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
597993cf
MB
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
4ee57b2a 24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
597993cf
MB
25
26;;; Commentary:
27
28;; This file defines backend network communication handlers for ERC.
29;;
30;; How things work:
31;;
32;; You define a new handler with `define-erc-response-handler'. This
33;; defines a function, a corresponding hook variable, and populates a
34;; global hash table `erc-server-responses' with a map from response
35;; to hook variable. See the function documentation for more
36;; information.
37;;
38;; Upon receiving a line from the server, `erc-parse-server-response'
39;; is called on it.
40;;
41;; A line generally looks like:
42;;
43;; LINE := ':' SENDER ' ' COMMAND ' ' (COMMAND-ARGS ' ')* ':' CONTENTS
44;; SENDER := Not ':' | ' '
45;; COMMAND := Not ':' | ' '
46;; COMMAND-ARGS := Not ':' | ' '
47;;
48;; This gets parsed and stuffed into an `erc-response' struct. You
49;; can access the fields of the struct with:
50;;
51;; COMMAND --- `erc-response.command'
52;; COMMAND-ARGS --- `erc-response.command-args'
53;; CONTENTS --- `erc-response.contents'
54;; SENDER --- `erc-response.sender'
55;; LINE --- `erc-response.unparsed'
56;;
57;; WARNING, WARNING!!
58;; It's probably not a good idea to destructively modify the list
59;; of command-args in your handlers, since other functions down the
60;; line may well need to access the arguments too.
61;;
62;; That is, unless you're /absolutely/ sure that your handler doesn't
63;; invoke some other function that needs to use COMMAND-ARGS, don't do
64;; something like
65;;
66;; (while (erc-response.command-args parsed)
67;; (let ((a (pop (erc-response.command-args parsed))))
68;; ...))
69;;
70;; The parsed response is handed over to
71;; `erc-handle-parsed-server-response', which checks whether it should
72;; carry out duplicate suppression, and then runs `erc-call-hooks'.
73;; `erc-call-hooks' retrieves the relevant hook variable from
74;; `erc-server-responses' and runs it.
75;;
76;; Most handlers then destructure the parsed response in some way
77;; (depending on what the handler is, the arguments have different
78;; meanings), and generally display something, usually using
79;; `erc-display-message'.
80
81;;; TODO:
82
f6b1b0a8 83;; o Generalize the display-line code so that we can use it to
597993cf
MB
84;; display the stuff we send, as well as the stuff we receive.
85;; Then, move all display-related code into another backend-like
86;; file, erc-display.el, say.
87;;
88;; o Clean up the handlers using new display code (has to be written
89;; first).
90
91;;; History:
92
93;; 2004/05/10 -- Handler bodies taken out of erc.el and ported to new
94;; interface.
95
96;; 2005-08-13 -- Moved sending commands from erc.el.
97
98;;; Code:
99
100(require 'erc-compat)
101(eval-when-compile (require 'cl))
102(autoload 'erc-with-buffer "erc" nil nil 'macro)
103(autoload 'erc-log "erc" nil nil 'macro)
104
105;;;; Variables and options
106
107(defvar erc-server-responses (make-hash-table :test #'equal)
108 "Hashtable mapping server responses to their handler hooks.")
109
110(defstruct (erc-response (:conc-name erc-response.))
111 (unparsed "" :type string)
112 (sender "" :type string)
113 (command "" :type string)
114 (command-args '() :type list)
115 (contents "" :type string))
116
117;;; User data
118
119(defvar erc-server-current-nick nil
120 "Nickname on the current server.
121Use `erc-current-nick' to access this.")
122(make-variable-buffer-local 'erc-server-current-nick)
123
124;;; Server attributes
125
126(defvar erc-server-process nil
127 "The process object of the corresponding server connection.")
128(make-variable-buffer-local 'erc-server-process)
129
130(defvar erc-session-server nil
131 "The server name used to connect to for this session.")
132(make-variable-buffer-local 'erc-session-server)
133
361bbf57
CY
134(defvar erc-session-connector nil
135 "The function used to connect to this session (nil for the default).")
136(make-variable-buffer-local 'erc-session-connector)
137
597993cf
MB
138(defvar erc-session-port nil
139 "The port used to connect to.")
140(make-variable-buffer-local 'erc-session-port)
141
142(defvar erc-server-announced-name nil
143 "The name the server announced to use.")
144(make-variable-buffer-local 'erc-server-announced-name)
145
146(defvar erc-server-version nil
147 "The name and version of the server's ircd.")
148(make-variable-buffer-local 'erc-server-version)
149
150(defvar erc-server-parameters nil
151 "Alist listing the supported server parameters.
152
153This is only set if the server sends 005 messages saying what is
154supported on the server.
155
156Entries are of the form:
157 (PARAMETER . VALUE)
158or
159 (PARAMETER) if no value is provided.
160
161Some examples of possible parameters sent by servers:
162CHANMODES=b,k,l,imnpst - list of supported channel modes
163CHANNELLEN=50 - maximum length of channel names
164CHANTYPES=#&!+ - supported channel prefixes
165CHARMAPPING=rfc1459 - character mapping used for nickname and channels
166KICKLEN=160 - maximum allowed kick message length
167MAXBANS=30 - maximum number of bans per channel
168MAXCHANNELS=10 - maximum number of channels allowed to join
169NETWORK=EFnet - the network identifier
170NICKLEN=9 - maximum allowed length of nicknames
171PREFIX=(ov)@+ - list of channel modes and the user prefixes if user has mode
172RFC2812 - server supports RFC 2812 features
173SILENCE=10 - supports the SILENCE command, maximum allowed number of entries
174TOPICLEN=160 - maximum allowed topic length
175WALLCHOPS - supports sending messages to all operators in a channel")
176(make-variable-buffer-local 'erc-server-parameters)
177
178;;; Server and connection state
179
ff59d266
MB
180(defvar erc-server-ping-timer-alist nil
181 "Mapping of server buffers to their specific ping timer.")
182
597993cf 183(defvar erc-server-connected nil
ff59d266
MB
184 "Non-nil if the current buffer has been used by ERC to establish
185an IRC connection.
186
187If you wish to determine whether an IRC connection is currently
188active, use the `erc-server-process-alive' function instead.")
597993cf
MB
189(make-variable-buffer-local 'erc-server-connected)
190
10dc9f9e
MB
191(defvar erc-server-reconnect-count 0
192 "Number of times we have failed to reconnect to the current server.")
193(make-variable-buffer-local 'erc-server-reconnect-count)
194
597993cf
MB
195(defvar erc-server-quitting nil
196 "Non-nil if the user requests a quit.")
197(make-variable-buffer-local 'erc-server-quitting)
198
ff59d266
MB
199(defvar erc-server-reconnecting nil
200 "Non-nil if the user requests an explicit reconnect, and the
201current IRC process is still alive.")
202(make-variable-buffer-local 'erc-server-reconnecting)
203
204(defvar erc-server-timed-out nil
205 "Non-nil if the IRC server failed to respond to a ping.")
206(make-variable-buffer-local 'erc-server-timed-out)
207
10dc9f9e
MB
208(defvar erc-server-banned nil
209 "Non-nil if the user is denied access because of a server ban.")
210(make-variable-buffer-local 'erc-server-banned)
211
ff59d266
MB
212(defvar erc-server-error-occurred nil
213 "Non-nil if the user triggers some server error.")
214(make-variable-buffer-local 'erc-server-error-occurred)
215
597993cf
MB
216(defvar erc-server-lines-sent nil
217 "Line counter.")
218(make-variable-buffer-local 'erc-server-lines-sent)
219
220(defvar erc-server-last-peers '(nil . nil)
221 "Last peers used, both sender and receiver.
222Those are used for /MSG destination shortcuts.")
223(make-variable-buffer-local 'erc-server-last-peers)
224
225(defvar erc-server-last-sent-time nil
226 "Time the message was sent.
227This is useful for flood protection.")
228(make-variable-buffer-local 'erc-server-last-sent-time)
229
230(defvar erc-server-last-ping-time nil
231 "Time the last ping was sent.
232This is useful for flood protection.")
233(make-variable-buffer-local 'erc-server-last-ping-time)
234
ff59d266
MB
235(defvar erc-server-last-received-time nil
236 "Time the last message was received from the server.
237This is useful for detecting hung connections.")
238(make-variable-buffer-local 'erc-server-last-received-time)
239
597993cf
MB
240(defvar erc-server-lag nil
241 "Calculated server lag time in seconds.
242This variable is only set in a server buffer.")
243(make-variable-buffer-local 'erc-server-lag)
244
245(defvar erc-server-filter-data nil
246 "The data that arrived from the server
247but has not been processed yet.")
248(make-variable-buffer-local 'erc-server-filter-data)
249
250(defvar erc-server-duplicates (make-hash-table :test 'equal)
251 "Internal variable used to track duplicate messages.")
252(make-variable-buffer-local 'erc-server-duplicates)
253
254;; From Circe
255(defvar erc-server-processing-p nil
256 "Non-nil when we're currently processing a message.
257
258When ERC receives a private message, it sets up a new buffer for
259this query. These in turn, though, do start flyspell. This
260involves starting an external process, in which case Emacs will
261wait - and when it waits, it does accept other stuff from, say,
262network exceptions. So, if someone sends you two messages
263quickly after each other, ispell is started for the first, but
264might take long enough for the second message to be processed
265first.")
266(make-variable-buffer-local 'erc-server-processing-p)
267
268(defvar erc-server-flood-last-message 0
269 "When we sent the last message.
270See `erc-server-flood-margin' for an explanation of the flood
271protection algorithm.")
272(make-variable-buffer-local 'erc-server-flood-last-message)
273
274(defvar erc-server-flood-queue nil
275 "The queue of messages waiting to be sent to the server.
276See `erc-server-flood-margin' for an explanation of the flood
277protection algorithm.")
278(make-variable-buffer-local 'erc-server-flood-queue)
279
280(defvar erc-server-flood-timer nil
281 "The timer to resume sending.")
282(make-variable-buffer-local 'erc-server-flood-timer)
283
284;;; IRC protocol and misc options
285
286(defgroup erc-server nil
287 "Parameters for dealing with IRC servers."
288 :group 'erc)
289
290(defcustom erc-server-auto-reconnect t
291 "Non-nil means that ERC will attempt to reestablish broken connections.
292
293Reconnection will happen automatically for any unexpected disconnection."
294 :group 'erc-server
295 :type 'boolean)
296
10dc9f9e
MB
297(defcustom erc-server-reconnect-attempts 2
298 "The number of times that ERC will attempt to reestablish a
299broken connection, or t to always attempt to reconnect.
300
301This only has an effect if `erc-server-auto-reconnect' is non-nil."
302 :group 'erc-server
303 :type '(choice (const :tag "Always reconnect" t)
304 integer))
305
306(defcustom erc-server-reconnect-timeout 1
307 "The amount of time, in seconds, that ERC will wait between
308successive reconnect attempts.
309
310If a key is pressed while ERC is waiting, it will stop waiting."
311 :group 'erc-server
312 :type 'number)
313
597993cf 314(defcustom erc-split-line-length 440
fb7ada5f 315 "The maximum length of a single message.
597993cf
MB
316If a message exceeds this size, it is broken into multiple ones.
317
318IRC allows for lines up to 512 bytes. Two of them are CR LF.
319And a typical message looks like this:
320
321 :nicky!uhuser@host212223.dialin.fnordisp.net PRIVMSG #lazybastards :Hello!
322
323You can limit here the maximum length of the \"Hello!\" part.
324Good luck."
325 :type 'integer
326 :group 'erc-server)
327
5c0c0f77
LMI
328(defcustom erc-coding-system-precedence '(utf-8 undecided)
329 "List of coding systems to be preferred when receiving a string from the server.
330This will only be consulted if the coding system in
331`erc-server-coding-system' is `undecided'."
332 :group 'erc-server
c4077254 333 :version "24.1"
5c0c0f77
LMI
334 :type '(repeat coding-system))
335
597993cf
MB
336(defcustom erc-server-coding-system (if (and (fboundp 'coding-system-p)
337 (coding-system-p 'undecided)
338 (coding-system-p 'utf-8))
339 '(utf-8 . undecided)
340 nil)
341 "The default coding system for incoming and outgoing text.
342This is either a coding system, a cons, a function, or nil.
343
344If a cons, the encoding system for outgoing text is in the car
345and the decoding system for incoming text is in the cdr. The most
5c0c0f77
LMI
346interesting use for this is to put `undecided' in the cdr. This
347means that `erc-coding-system-precedence' will be consulted, and the
348first match there will be used.
5e56b3fb
MO
349
350If a function, it is called with the argument `target' and should
351return a coding system or a cons as described above.
597993cf
MB
352
353If you need to send non-ASCII text to people not using a client that
354does decoding on its own, you must tell ERC what encoding to use.
355Emacs cannot guess it, since it does not know what the people on the
356other end of the line are using."
357 :group 'erc-server
358 :type '(choice (const :tag "None" nil)
359 coding-system
360 (cons (coding-system :tag "encoding" :value utf-8)
361 (coding-system :tag "decoding" :value undecided))
362 function))
363
364(defcustom erc-encoding-coding-alist nil
365 "Alist of target regexp and coding-system pairs to use.
366This overrides `erc-server-coding-system' depending on the
367current target as returned by `erc-default-target'.
368
369Example: If you know that the channel #linux-ru uses the coding-system
370`cyrillic-koi8', then add '(\"#linux-ru\" . cyrillic-koi8) to the
371alist."
372 :group 'erc-server
373 :type '(repeat (cons (string :tag "Target")
374 coding-system)))
375
21bc768b 376(defcustom erc-server-connect-function 'open-network-stream
597993cf
MB
377 "Function used to initiate a connection.
378It should take same arguments as `open-network-stream' does."
379 :group 'erc-server
380 :type 'function)
381
382(defcustom erc-server-prevent-duplicates '("301")
fb7ada5f 383 "Either nil or a list of strings.
597993cf
MB
384Each string is a IRC message type, like PRIVMSG or NOTICE.
385All Message types in that list of subjected to duplicate prevention."
386 :type '(choice (const nil) (list string))
387 :group 'erc-server)
388
389(defcustom erc-server-duplicate-timeout 60
fb7ada5f 390 "The time allowed in seconds between duplicate messages.
597993cf
MB
391
392If two identical messages arrive within this value of one another, the second
393isn't displayed."
394 :type 'integer
395 :group 'erc-server)
396
56551c43 397(defcustom erc-server-timestamp-format "%Y-%m-%d %T"
16245de5 398 "Timestamp format used with server response messages.
56551c43 399This string is processed using `format-time-string'."
2a1e2476 400 :version "24.3"
56551c43
TL
401 :type 'string
402 :group 'erc-server)
403
597993cf
MB
404;;; Flood-related
405
406;; Most of this is courtesy of Jorgen Schaefer and Circe
407;; (http://www.nongnu.org/circe)
408
409(defcustom erc-server-flood-margin 10
fb7ada5f 410 "A margin on how much excess data we send.
597993cf
MB
411The flood protection algorithm of ERC works like the one
412detailed in RFC 2813, section 5.8 \"Flood control of clients\".
413
414 * If `erc-server-flood-last-message' is less than the current
415 time, set it equal.
416 * While `erc-server-flood-last-message' is less than
417 `erc-server-flood-margin' seconds ahead of the current
418 time, send a message, and increase
419 `erc-server-flood-last-message' by
420 `erc-server-flood-penalty' for each message."
421 :type 'integer
422 :group 'erc-server)
423
424(defcustom erc-server-flood-penalty 3
425 "How much we penalize a message.
426See `erc-server-flood-margin' for an explanation of the flood
427protection algorithm."
428 :type 'integer
429 :group 'erc-server)
430
431;; Ping handling
432
ff59d266 433(defcustom erc-server-send-ping-interval 30
fb7ada5f 434 "Interval of sending pings to the server, in seconds.
597993cf
MB
435If this is set to nil, pinging the server is disabled."
436 :group 'erc-server
ff59d266
MB
437 :type '(choice (const :tag "Disabled" nil)
438 (integer :tag "Seconds")))
439
440(defcustom erc-server-send-ping-timeout 120
fb7ada5f 441 "If the time between ping and response is greater than this, reconnect.
ff59d266
MB
442The time is in seconds.
443
444This must be greater than or equal to the value for
445`erc-server-send-ping-interval'.
446
447If this is set to nil, never try to reconnect."
448 :group 'erc-server
449 :type '(choice (const :tag "Disabled" nil)
450 (integer :tag "Seconds")))
597993cf
MB
451
452(defvar erc-server-ping-handler nil
453 "This variable holds the periodic ping timer.")
454(make-variable-buffer-local 'erc-server-ping-handler)
455
456;;;; Helper functions
457
458;; From Circe
459(defun erc-split-line (longline)
460 "Return a list of lines which are not too long for IRC.
461The length is specified in `erc-split-line-length'.
462
463Currently this is called by `erc-send-input'."
464 (if (< (length longline)
465 erc-split-line-length)
466 (list longline)
467 (with-temp-buffer
468 (insert longline)
469 (let ((fill-column erc-split-line-length))
470 (fill-region (point-min) (point-max)
471 nil t))
472 (split-string (buffer-string) "\n"))))
473
474;; Used by CTCP functions
475(defun erc-upcase-first-word (str)
476 "Upcase the first word in STR."
477 (with-temp-buffer
478 (insert str)
479 (goto-char (point-min))
480 (upcase-word 1)
481 (buffer-string)))
482
ff59d266
MB
483(defun erc-server-setup-periodical-ping (buffer)
484 "Set up a timer to periodically ping the current server.
485The current buffer is given by BUFFER."
486 (with-current-buffer buffer
487 (and erc-server-ping-handler (erc-cancel-timer erc-server-ping-handler))
488 (when erc-server-send-ping-interval
489 (setq erc-server-ping-handler (run-with-timer
490 4 erc-server-send-ping-interval
491 #'erc-server-send-ping
492 buffer))
493 (setq erc-server-ping-timer-alist (cons (cons buffer
494 erc-server-ping-handler)
495 erc-server-ping-timer-alist)))))
597993cf
MB
496
497(defun erc-server-process-alive ()
498 "Return non-nil when `erc-server-process' is open or running."
83dc6995 499 (and erc-server-process
597993cf
MB
500 (processp erc-server-process)
501 (memq (process-status erc-server-process) '(run open))))
502
503;;;; Connecting to a server
504
ff59d266
MB
505(defun erc-server-connect (server port buffer)
506 "Perform the connection and login using the specified SERVER and PORT.
507We will store server variables in the buffer given by BUFFER."
597993cf
MB
508 (let ((msg (erc-format-message 'connect ?S server ?p port)))
509 (message "%s" msg)
ff59d266
MB
510 (let ((process (funcall erc-server-connect-function
511 (format "erc-%s-%s" server port)
512 nil server port)))
5e56b3fb
MO
513 (unless (processp process)
514 (error "Connection attempt failed"))
ff59d266
MB
515 (message "%s...done" msg)
516 ;; Misc server variables
517 (with-current-buffer buffer
518 (setq erc-server-process process)
519 (setq erc-server-quitting nil)
520 (setq erc-server-reconnecting nil)
521 (setq erc-server-timed-out nil)
522 (setq erc-server-banned nil)
523 (setq erc-server-error-occurred nil)
524 (let ((time (erc-current-time)))
525 (setq erc-server-last-sent-time time)
526 (setq erc-server-last-ping-time time)
527 (setq erc-server-last-received-time time))
528 (setq erc-server-lines-sent 0)
529 ;; last peers (sender and receiver)
530 (setq erc-server-last-peers '(nil . nil)))
531 ;; we do our own encoding and decoding
532 (when (fboundp 'set-process-coding-system)
533 (set-process-coding-system process 'raw-text))
534 ;; process handlers
535 (set-process-sentinel process 'erc-process-sentinel)
536 (set-process-filter process 'erc-server-filter-function)
537 (set-process-buffer process buffer)))
597993cf 538 (erc-log "\n\n\n********************************************\n")
274f1353 539 (message "%s" (erc-format-message
ff59d266
MB
540 'login ?n
541 (with-current-buffer buffer (erc-current-nick))))
597993cf
MB
542 ;; wait with script loading until we receive a confirmation (first
543 ;; MOTD line)
544 (if (eq erc-server-connect-function 'open-network-stream-nowait)
545 ;; it's a bit unclear otherwise that it's attempting to establish a
546 ;; connection
ff59d266 547 (erc-display-message nil nil buffer "Opening connection..\n")
597993cf
MB
548 (erc-login)))
549
10dc9f9e
MB
550(defun erc-server-reconnect ()
551"Reestablish the current IRC connection.
552Make sure you are in an ERC buffer when running this."
526dc846
MO
553 (let ((buffer (erc-server-buffer)))
554 (unless (buffer-live-p buffer)
555 (if (eq major-mode 'erc-mode)
556 (setq buffer (current-buffer))
557 (error "Reconnect must be run from an ERC buffer")))
558 (with-current-buffer buffer
10dc9f9e
MB
559 (erc-update-mode-line)
560 (erc-set-active-buffer (current-buffer))
561 (setq erc-server-last-sent-time 0)
562 (setq erc-server-lines-sent 0)
361bbf57
CY
563 (let ((erc-server-connect-function (or erc-session-connector
564 'open-network-stream)))
565 (erc-open erc-session-server erc-session-port erc-server-current-nick
566 erc-session-user-full-name t erc-session-password)))))
10dc9f9e 567
597993cf
MB
568(defun erc-server-filter-function (process string)
569 "The process filter for the ERC server."
570 (with-current-buffer (process-buffer process)
ff59d266 571 (setq erc-server-last-received-time (erc-current-time))
597993cf
MB
572 ;; If you think this is written in a weird way - please refer to the
573 ;; docstring of `erc-server-processing-p'
574 (if erc-server-processing-p
575 (setq erc-server-filter-data
576 (if erc-server-filter-data
577 (concat erc-server-filter-data string)
578 string))
579 ;; This will be true even if another process is spawned!
580 (let ((erc-server-processing-p t))
581 (setq erc-server-filter-data (if erc-server-filter-data
582 (concat erc-server-filter-data
583 string)
584 string))
585 (while (and erc-server-filter-data
586 (string-match "[\n\r]+" erc-server-filter-data))
587 (let ((line (substring erc-server-filter-data
588 0 (match-beginning 0))))
589 (setq erc-server-filter-data
590 (if (= (match-end 0)
591 (length erc-server-filter-data))
592 nil
593 (substring erc-server-filter-data
594 (match-end 0))))
5997e340 595 (erc-log-irc-protocol line nil)
597993cf
MB
596 (erc-parse-server-response process line)))))))
597
10dc9f9e
MB
598(defsubst erc-server-reconnect-p (event)
599 "Return non-nil if ERC should attempt to reconnect automatically.
600EVENT is the message received from the closed connection process."
ff59d266
MB
601 (or erc-server-reconnecting
602 (and erc-server-auto-reconnect
603 (not erc-server-banned)
604 (not erc-server-error-occurred)
605 ;; make sure we don't infinitely try to reconnect, unless the
606 ;; user wants that
607 (or (eq erc-server-reconnect-attempts t)
608 (and (integerp erc-server-reconnect-attempts)
609 (< erc-server-reconnect-count
610 erc-server-reconnect-attempts)))
611 (or erc-server-timed-out
612 (not (string-match "^deleted" event)))
613 ;; open-network-stream-nowait error for connection refused
614 (not (string-match "^failed with code 111" event)))))
10dc9f9e 615
526dc846
MO
616(defun erc-process-sentinel-2 (event buffer)
617 "Called when `erc-process-sentinel-1' has detected an unexpected disconnect."
618 (if (not (buffer-live-p buffer))
619 (erc-update-mode-line)
620 (with-current-buffer buffer
621 (let ((reconnect-p (erc-server-reconnect-p event)))
622 (erc-display-message nil 'error (current-buffer)
623 (if reconnect-p 'disconnected
624 'disconnected-noreconnect))
625 (if (not reconnect-p)
626 ;; terminate, do not reconnect
627 (progn
628 (erc-display-message nil 'error (current-buffer)
629 'terminated ?e event)
630 ;; Update mode line indicators
631 (erc-update-mode-line)
632 (set-buffer-modified-p nil))
633 ;; reconnect
634 (condition-case err
635 (progn
636 (setq erc-server-reconnecting nil)
637 (erc-server-reconnect)
638 (setq erc-server-reconnect-count 0))
639 (error (when (buffer-live-p buffer)
640 (set-buffer buffer)
641 (if (integerp erc-server-reconnect-attempts)
642 (setq erc-server-reconnect-count
643 (1+ erc-server-reconnect-count))
644 (message "%s ... %s"
645 "Reconnecting until we succeed"
646 "kill the ERC server buffer to stop"))
647 (if (numberp erc-server-reconnect-timeout)
648 (run-at-time erc-server-reconnect-timeout nil
649 #'erc-process-sentinel-2
650 event buffer)
651 (error (concat "`erc-server-reconnect-timeout`"
652 " must be a number")))))))))))
653
654(defun erc-process-sentinel-1 (event buffer)
10dc9f9e
MB
655 "Called when `erc-process-sentinel' has decided that we're disconnecting.
656Determine whether user has quit or whether erc has been terminated.
657Conditionally try to reconnect and take appropriate action."
526dc846
MO
658 (with-current-buffer buffer
659 (if erc-server-quitting
660 ;; normal quit
661 (progn
662 (erc-display-message nil 'error (current-buffer) 'finished)
663 ;; Update mode line indicators
664 (erc-update-mode-line)
665 ;; Kill server buffer if user wants it
597993cf 666 (set-buffer-modified-p nil)
526dc846
MO
667 (when erc-kill-server-buffer-on-quit
668 (kill-buffer (current-buffer))))
669 ;; unexpected disconnect
670 (erc-process-sentinel-2 event buffer))))
597993cf
MB
671
672(defun erc-process-sentinel (cproc event)
673 "Sentinel function for ERC process."
6bb55f7c
JD
674 (let ((buf (process-buffer cproc)))
675 (when (buffer-live-p buf)
676 (with-current-buffer buf
677 (erc-log (format
678 "SENTINEL: proc: %S status: %S event: %S (quitting: %S)"
679 cproc (process-status cproc) event erc-server-quitting))
680 (if (string-match "^open" event)
681 ;; newly opened connection (no wait)
682 (erc-login)
683 ;; assume event is 'failed
684 (erc-with-all-buffers-of-server cproc nil
685 (setq erc-server-connected nil))
686 (when erc-server-ping-handler
687 (progn (erc-cancel-timer erc-server-ping-handler)
688 (setq erc-server-ping-handler nil)))
689 (run-hook-with-args 'erc-disconnected-hook
690 (erc-current-nick) (system-name) "")
691 ;; Remove the prompt
692 (goto-char (or (marker-position erc-input-marker) (point-max)))
693 (forward-line 0)
694 (erc-remove-text-properties-region (point) (point-max))
695 (delete-region (point) (point-max))
696 ;; Decide what to do with the buffer
697 ;; Restart if disconnected
698 (erc-process-sentinel-1 event buf))))))
597993cf
MB
699
700;;;; Sending messages
701
702(defun erc-coding-system-for-target (target)
703 "Return the coding system or cons cell appropriate for TARGET.
704This is determined via `erc-encoding-coding-alist' or
705`erc-server-coding-system'."
ff59d266 706 (unless target (setq target (erc-default-target)))
2e3ef421
MB
707 (or (when target
708 (let ((case-fold-search t))
709 (catch 'match
710 (dolist (pat erc-encoding-coding-alist)
711 (when (string-match (car pat) target)
712 (throw 'match (cdr pat)))))))
597993cf 713 (and (functionp erc-server-coding-system)
5e56b3fb 714 (funcall erc-server-coding-system target))
597993cf
MB
715 erc-server-coding-system))
716
717(defun erc-decode-string-from-target (str target)
718 "Decode STR as appropriate for TARGET.
719This is indicated by `erc-encoding-coding-alist', defaulting to the value of
720`erc-server-coding-system'."
721 (unless (stringp str)
722 (setq str ""))
723 (let ((coding (erc-coding-system-for-target target)))
724 (when (consp coding)
725 (setq coding (cdr coding)))
5c0c0f77
LMI
726 (when (eq coding 'undecided)
727 (let ((codings (detect-coding-string str))
728 (precedence erc-coding-system-precedence))
729 (while (and precedence
730 (not (memq (car precedence) codings)))
731 (pop precedence))
732 (when precedence
733 (setq coding (car precedence)))))
597993cf
MB
734 (erc-decode-coding-string str coding)))
735
736;; proposed name, not used by anything yet
737(defun erc-send-line (text display-fn)
738 "Send TEXT to the current server. Wrapping and flood control apply.
739Use DISPLAY-FN to show the results."
740 (mapc (lambda (line)
741 (erc-server-send line)
742 (funcall display-fn))
743 (erc-split-line text)))
744
745;; From Circe, with modifications
746(defun erc-server-send (string &optional forcep target)
747 "Send STRING to the current server.
748If FORCEP is non-nil, no flood protection is done - the string is
749sent directly. This might cause the messages to arrive in a wrong
750order.
751
752If TARGET is specified, look up encoding information for that
753channel in `erc-encoding-coding-alist' or
754`erc-server-coding-system'.
755
756See `erc-server-flood-margin' for an explanation of the flood
757protection algorithm."
758 (erc-log (concat "erc-server-send: " string "(" (buffer-name) ")"))
759 (setq erc-server-last-sent-time (erc-current-time))
ff59d266 760 (let ((encoding (erc-coding-system-for-target target)))
597993cf
MB
761 (when (consp encoding)
762 (setq encoding (car encoding)))
ff59d266
MB
763 (if (erc-server-process-alive)
764 (erc-with-server-buffer
597993cf
MB
765 (let ((str (concat string "\r\n")))
766 (if forcep
767 (progn
768 (setq erc-server-flood-last-message
769 (+ erc-server-flood-penalty
770 erc-server-flood-last-message))
771 (erc-log-irc-protocol str 'outbound)
772 (condition-case err
773 (progn
774 ;; Set encoding just before sending the string
775 (when (fboundp 'set-process-coding-system)
776 (set-process-coding-system erc-server-process
777 'raw-text encoding))
778 (process-send-string erc-server-process str))
779 ;; See `erc-server-send-queue' for full
780 ;; explanation of why we need this condition-case
781 (error nil)))
782 (setq erc-server-flood-queue
783 (append erc-server-flood-queue
784 (list (cons str encoding))))
785 (erc-server-send-queue (current-buffer))))
786 t)
787 (message "ERC: No process running")
788 nil)))
789
afa803d5
GM
790(defun erc-server-send-ping (buf)
791 "Send a ping to the IRC server buffer in BUF.
792Additionally, detect whether the IRC process has hung."
793 (if (buffer-live-p buf)
794 (with-current-buffer buf
795 (if (and erc-server-send-ping-timeout
796 (>
797 (erc-time-diff (erc-current-time)
798 erc-server-last-received-time)
799 erc-server-send-ping-timeout))
800 (progn
801 ;; if the process is hung, kill it
802 (setq erc-server-timed-out t)
803 (delete-process erc-server-process))
804 (erc-server-send (format "PING %.0f" (erc-current-time)))))
805 ;; remove timer if the server buffer has been killed
806 (let ((timer (assq buf erc-server-ping-timer-alist)))
807 (when timer
808 (erc-cancel-timer (cdr timer))
809 (setcdr timer nil)))))
810
597993cf
MB
811;; From Circe
812(defun erc-server-send-queue (buffer)
813 "Send messages in `erc-server-flood-queue'.
814See `erc-server-flood-margin' for an explanation of the flood
815protection algorithm."
816 (with-current-buffer buffer
817 (let ((now (erc-current-time)))
818 (when erc-server-flood-timer
819 (erc-cancel-timer erc-server-flood-timer)
820 (setq erc-server-flood-timer nil))
821 (when (< erc-server-flood-last-message
822 now)
823 (setq erc-server-flood-last-message now))
824 (while (and erc-server-flood-queue
825 (< erc-server-flood-last-message
826 (+ now erc-server-flood-margin)))
827 (let ((msg (caar erc-server-flood-queue))
828 (encoding (cdar erc-server-flood-queue)))
829 (setq erc-server-flood-queue (cdr erc-server-flood-queue)
830 erc-server-flood-last-message
831 (+ erc-server-flood-last-message
832 erc-server-flood-penalty))
833 (erc-log-irc-protocol msg 'outbound)
834 (erc-log (concat "erc-server-send-queue: "
835 msg "(" (buffer-name buffer) ")"))
836 (when (erc-server-process-alive)
837 (condition-case err
838 ;; Set encoding just before sending the string
839 (progn
840 (when (fboundp 'set-process-coding-system)
841 (set-process-coding-system erc-server-process
842 'raw-text encoding))
843 (process-send-string erc-server-process msg))
844 ;; Sometimes the send can occur while the process is
845 ;; being killed, which results in a weird SIGPIPE error.
846 ;; Catch this and ignore it.
847 (error nil)))))
848 (when erc-server-flood-queue
849 (setq erc-server-flood-timer
83dc6995
MB
850 (run-at-time (+ 0.2 erc-server-flood-penalty)
851 nil #'erc-server-send-queue buffer))))))
597993cf
MB
852
853(defun erc-message (message-command line &optional force)
854 "Send LINE to the server as a privmsg or a notice.
855MESSAGE-COMMAND should be either \"PRIVMSG\" or \"NOTICE\".
856If the target is \",\", the last person you've got a message from will
857be used. If the target is \".\", the last person you've sent a message
858to will be used."
859 (cond
860 ((string-match "^\\s-*\\(\\S-+\\) ?\\(.*\\)" line)
861 (let ((tgt (match-string 1 line))
862 (s (match-string 2 line)))
863 (erc-log (format "cmd: MSG(%s): [%s] %s" message-command tgt s))
864 (cond
865 ((string= tgt ",")
866 (if (car erc-server-last-peers)
867 (setq tgt (car erc-server-last-peers))
868 (setq tgt nil)))
869 ((string= tgt ".")
870 (if (cdr erc-server-last-peers)
871 (setq tgt (cdr erc-server-last-peers))
872 (setq tgt nil))))
873 (cond
874 (tgt
875 (setcdr erc-server-last-peers tgt)
876 (erc-server-send (format "%s %s :%s" message-command tgt s)
877 force))
878 (t
879 (erc-display-message nil 'error (current-buffer) 'no-target))))
880 t)
881 (t nil)))
882
883;;; CTCP
884
885(defun erc-send-ctcp-message (tgt l &optional force)
886 "Send CTCP message L to TGT.
887
888If TGT is nil the message is not sent.
889The command must contain neither a prefix nor a trailing `\\n'.
890
891See also `erc-server-send'."
892 (let ((l (erc-upcase-first-word l)))
893 (cond
894 (tgt
895 (erc-log (format "erc-send-CTCP-message: [%s] %s" tgt l))
896 (erc-server-send (format "PRIVMSG %s :\C-a%s\C-a" tgt l)
897 force)))))
898
899(defun erc-send-ctcp-notice (tgt l &optional force)
900 "Send CTCP notice L to TGT.
901
902If TGT is nil the message is not sent.
903The command must contain neither a prefix nor a trailing `\\n'.
904
905See also `erc-server-send'."
906 (let ((l (erc-upcase-first-word l)))
907 (cond
908 (tgt
909 (erc-log (format "erc-send-CTCP-notice: [%s] %s" tgt l))
910 (erc-server-send (format "NOTICE %s :\C-a%s\C-a" tgt l)
911 force)))))
912
913;;;; Handling responses
914
915(defun erc-parse-server-response (proc string)
916 "Parse and act upon a complete line from an IRC server.
917PROC is the process (connection) from which STRING was received.
918PROCs `process-buffer' is `current-buffer' when this function is called."
919 (unless (string= string "") ;; Ignore empty strings
920 (save-match-data
921 (let ((posn (if (eq (aref string 0) ?:)
922 (string-match " " string)
923 0))
924 (msg (make-erc-response :unparsed string)))
925
926 (setf (erc-response.sender msg)
927 (if (eq posn 0)
928 erc-session-server
929 (substring string 1 posn)))
930
931 (setf (erc-response.command msg)
21bc768b 932 (let* ((bposn (string-match "[^ \n]" string posn))
597993cf
MB
933 (eposn (string-match " " string bposn)))
934 (setq posn (and eposn
21bc768b 935 (string-match "[^ \n]" string eposn)))
597993cf
MB
936 (substring string bposn eposn)))
937
938 (while (and posn
939 (not (eq (aref string posn) ?:)))
940 (push (let* ((bposn posn)
941 (eposn (string-match " " string bposn)))
942 (setq posn (and eposn
21bc768b 943 (string-match "[^ \n]" string eposn)))
597993cf
MB
944 (substring string bposn eposn))
945 (erc-response.command-args msg)))
946 (when posn
947 (let ((str (substring string (1+ posn))))
948 (push str (erc-response.command-args msg))))
949
950 (setf (erc-response.contents msg)
951 (first (erc-response.command-args msg)))
952
953 (setf (erc-response.command-args msg)
954 (nreverse (erc-response.command-args msg)))
955
956 (erc-decode-parsed-server-response msg)
957
958 (erc-handle-parsed-server-response proc msg)))))
959
960(defun erc-decode-parsed-server-response (parsed-response)
961 "Decode a pre-parsed PARSED-RESPONSE before it can be handled.
962
963If there is a channel name in `erc-response.command-args', decode
964`erc-response' according to this channel name and
965`erc-encoding-coding-alist', or use `erc-server-coding-system'
966for decoding."
967 (let ((args (erc-response.command-args parsed-response))
968 (decode-target nil)
969 (decoded-args ()))
970 (dolist (arg args nil)
971 (when (string-match "^[#&].*" arg)
972 (setq decode-target arg)))
973 (when (stringp decode-target)
974 (setq decode-target (erc-decode-string-from-target decode-target nil)))
975 (setf (erc-response.unparsed parsed-response)
976 (erc-decode-string-from-target
977 (erc-response.unparsed parsed-response)
978 decode-target))
979 (setf (erc-response.sender parsed-response)
980 (erc-decode-string-from-target
981 (erc-response.sender parsed-response)
982 decode-target))
983 (setf (erc-response.command parsed-response)
984 (erc-decode-string-from-target
985 (erc-response.command parsed-response)
986 decode-target))
987 (dolist (arg (nreverse args) nil)
988 (push (erc-decode-string-from-target arg decode-target)
989 decoded-args))
990 (setf (erc-response.command-args parsed-response) decoded-args)
991 (setf (erc-response.contents parsed-response)
992 (erc-decode-string-from-target
993 (erc-response.contents parsed-response)
994 decode-target))))
995
996(defun erc-handle-parsed-server-response (process parsed-response)
997 "Handle a pre-parsed PARSED-RESPONSE from PROCESS.
998
999Hands off to helper functions via `erc-call-hooks'."
1000 (if (member (erc-response.command parsed-response)
1001 erc-server-prevent-duplicates)
1002 (let ((m (erc-response.unparsed parsed-response)))
fac916bf 1003 ;; duplicate suppression
597993cf
MB
1004 (if (< (or (gethash m erc-server-duplicates) 0)
1005 (- (erc-current-time) erc-server-duplicate-timeout))
1006 (erc-call-hooks process parsed-response))
1007 (puthash m (erc-current-time) erc-server-duplicates))
1008 ;; Hand off to the relevant handler.
1009 (erc-call-hooks process parsed-response)))
1010
1011(defun erc-get-hook (command)
1012 "Return the hook variable associated with COMMAND.
1013
1014See also `erc-server-responses'."
1015 (gethash (format (if (numberp command) "%03i" "%s") command)
1016 erc-server-responses))
1017
1018(defun erc-call-hooks (process message)
1019 "Call hooks associated with MESSAGE in PROCESS.
1020
1021Finds hooks by looking in the `erc-server-responses' hashtable."
1022 (let ((hook (or (erc-get-hook (erc-response.command message))
1023 'erc-default-server-functions)))
1024 (run-hook-with-args-until-success hook process message)
ff59d266
MB
1025 (erc-with-server-buffer
1026 (run-hook-with-args 'erc-timer-hook (erc-current-time)))))
597993cf
MB
1027
1028(add-hook 'erc-default-server-functions 'erc-handle-unknown-server-response)
1029
1030(defun erc-handle-unknown-server-response (proc parsed)
1031 "Display unknown server response's message."
1032 (let ((line (concat (erc-response.sender parsed)
1033 " "
1034 (erc-response.command parsed)
1035 " "
1036 (mapconcat 'identity (erc-response.command-args parsed)
1037 " "))))
1038 (erc-display-message parsed 'notice proc line)))
1039
1040
1041(put 'define-erc-response-handler 'edebug-form-spec
1042 '(&define :name erc-response-handler
1043 (name &rest name)
1044 &optional sexp sexp def-body))
1045
1046(defmacro* define-erc-response-handler ((name &rest aliases)
1047 &optional extra-fn-doc extra-var-doc
1048 &rest fn-body)
1049 "Define an ERC handler hook/function pair.
1050NAME is the response name as sent by the server (see the IRC RFC for
1051meanings).
1052
1053This creates:
8e663c3b 1054 - a hook variable `erc-server-NAME-functions' initialized to `erc-server-NAME'.
597993cf
MB
1055 - a function `erc-server-NAME' with body FN-BODY.
1056
1057If ALIASES is non-nil, each alias in ALIASES is `defalias'ed to
1058`erc-server-NAME'.
1059Alias hook variables are created as `erc-server-ALIAS-functions' and
8e663c3b 1060initialized to the same default value as `erc-server-NAME-functions'.
597993cf
MB
1061
1062FN-BODY is the body of `erc-server-NAME' it may refer to the two
1063function arguments PROC and PARSED.
1064
1065If EXTRA-FN-DOC is non-nil, it is inserted at the beginning of the
1066defined function's docstring.
1067
1068If EXTRA-VAR-DOC is non-nil, it is inserted at the beginning of the
1069defined variable's docstring.
1070
1071As an example:
1072
1073 (define-erc-response-handler (311 WHOIS WI)
1074 \"Some non-generic function documentation.\"
1075 \"Some non-generic variable documentation.\"
1076 (do-stuff-with-whois proc parsed))
1077
1078Would expand to:
1079
1080 (prog2
1081 (defvar erc-server-311-functions 'erc-server-311
1082 \"Some non-generic variable documentation.
1083
1084 Hook called upon receiving a 311 server response.
1085 Each function is called with two arguments, the process associated
1086 with the response and the parsed response.
1087 See also `erc-server-311'.\")
1088
1089 (defun erc-server-311 (proc parsed)
1090 \"Some non-generic function documentation.
1091
1092 Handler for a 311 server response.
1093 PROC is the server process which returned the response.
1094 PARSED is the actual response as an `erc-response' struct.
1095 If you want to add responses don't modify this function, but rather
1096 add things to `erc-server-311-functions' instead.\"
1097 (do-stuff-with-whois proc parsed))
1098
1099 (puthash \"311\" 'erc-server-311-functions erc-server-responses)
1100 (puthash \"WHOIS\" 'erc-server-WHOIS-functions erc-server-responses)
1101 (puthash \"WI\" 'erc-server-WI-functions erc-server-responses)
1102
1103 (defalias 'erc-server-WHOIS 'erc-server-311)
1104 (defvar erc-server-WHOIS-functions 'erc-server-311
1105 \"Some non-generic variable documentation.
1106
1107 Hook called upon receiving a WHOIS server response.
526dc846 1108
597993cf 1109 Each function is called with two arguments, the process associated
526dc846
MO
1110 with the response and the parsed response. If the function returns
1111 non-nil, stop processing the hook. Otherwise, continue.
1112
597993cf
MB
1113 See also `erc-server-311'.\")
1114
1115 (defalias 'erc-server-WI 'erc-server-311)
1116 (defvar erc-server-WI-functions 'erc-server-311
1117 \"Some non-generic variable documentation.
1118
1119 Hook called upon receiving a WI server response.
1120 Each function is called with two arguments, the process associated
526dc846
MO
1121 with the response and the parsed response. If the function returns
1122 non-nil, stop processing the hook. Otherwise, continue.
1123
597993cf
MB
1124 See also `erc-server-311'.\"))
1125
1126\(fn (NAME &rest ALIASES) &optional EXTRA-FN-DOC EXTRA-VAR-DOC &rest FN-BODY)"
1127 (if (numberp name) (setq name (intern (format "%03i" name))))
1128 (setq aliases (mapcar (lambda (a)
1129 (if (numberp a)
1130 (format "%03i" a)
1131 a))
1132 aliases))
1133 (let* ((hook-name (intern (format "erc-server-%s-functions" name)))
1134 (fn-name (intern (format "erc-server-%s" name)))
1135 (hook-doc (format "%sHook called upon receiving a %%s server response.
1136Each function is called with two arguments, the process associated
526dc846
MO
1137with the response and the parsed response. If the function returns
1138non-nil, stop processing the hook. Otherwise, continue.
1139
597993cf
MB
1140See also `%s'."
1141 (if extra-var-doc
1142 (concat extra-var-doc "\n\n")
1143 "")
1144 fn-name))
1145 (fn-doc (format "%sHandler for a %s server response.
1146PROC is the server process which returned the response.
1147PARSED is the actual response as an `erc-response' struct.
1148If you want to add responses don't modify this function, but rather
1149add things to `%s' instead."
1150 (if extra-fn-doc
1151 (concat extra-fn-doc "\n\n")
1152 "")
1153 name hook-name))
1154 (fn-alternates
1155 (loop for alias in aliases
1156 collect (intern (format "erc-server-%s" alias))))
1157 (var-alternates
1158 (loop for alias in aliases
1159 collect (intern (format "erc-server-%s-functions" alias)))))
1160 `(prog2
1161 ;; Normal hook variable.
1162 (defvar ,hook-name ',fn-name ,(format hook-doc name))
1163 ;; Handler function
1164 (defun ,fn-name (proc parsed)
1165 ,fn-doc
1166 ,@fn-body)
1167
1168 ;; Make find-function and find-variable find them
1169 (put ',fn-name 'definition-name ',name)
1170 (put ',hook-name 'definition-name ',name)
1171
1172 ;; Hashtable map of responses to hook variables
1173 ,@(loop for response in (cons name aliases)
1174 for var in (cons hook-name var-alternates)
1175 collect `(puthash ,(format "%s" response) ',var
1176 erc-server-responses))
1177 ;; Alternates.
1178 ;; Functions are defaliased, hook variables are defvared so we
1179 ;; can add hooks to one alias, but not another.
1180 ,@(loop for fn in fn-alternates
1181 for var in var-alternates
1182 for a in aliases
1183 nconc (list `(defalias ',fn ',fn-name)
1184 `(defvar ,var ',fn-name ,(format hook-doc a))
1185 `(put ',var 'definition-name ',hook-name))))))
1186
1187(define-erc-response-handler (ERROR)
1188 "Handle an ERROR command from the server." nil
ff59d266 1189 (setq erc-server-error-occurred t)
597993cf
MB
1190 (erc-display-message
1191 parsed 'error nil 'ERROR
1192 ?s (erc-response.sender parsed) ?c (erc-response.contents parsed)))
1193
1194(define-erc-response-handler (INVITE)
1195 "Handle invitation messages."
1196 nil
1197 (let ((target (first (erc-response.command-args parsed)))
1198 (chnl (erc-response.contents parsed)))
1199 (multiple-value-bind (nick login host)
7db26af0 1200 (values-list (erc-parse-user (erc-response.sender parsed)))
597993cf
MB
1201 (setq erc-invitation chnl)
1202 (when (string= target (erc-current-nick))
1203 (erc-display-message
1204 parsed 'notice 'active
1205 'INVITE ?n nick ?u login ?h host ?c chnl)))))
1206
1207
1208(define-erc-response-handler (JOIN)
1209 "Handle join messages."
1210 nil
1211 (let ((chnl (erc-response.contents parsed))
1212 (buffer nil))
1213 (multiple-value-bind (nick login host)
7db26af0 1214 (values-list (erc-parse-user (erc-response.sender parsed)))
597993cf
MB
1215 ;; strip the stupid combined JOIN facility (IRC 2.9)
1216 (if (string-match "^\\(.*\\)?\^g.*$" chnl)
1217 (setq chnl (match-string 1 chnl)))
1218 (save-excursion
1219 (let* ((str (cond
1220 ;; If I have joined a channel
1221 ((erc-current-nick-p nick)
83dc6995
MB
1222 (setq buffer (erc-open erc-session-server erc-session-port
1223 nick erc-session-user-full-name
1224 nil nil
7de0e003 1225 (list chnl) chnl
83dc6995 1226 erc-server-process))
597993cf
MB
1227 (when buffer
1228 (set-buffer buffer)
1229 (erc-add-default-channel chnl)
1230 (erc-server-send (format "MODE %s" chnl)))
1231 (erc-with-buffer (chnl proc)
1232 (erc-channel-begin-receiving-names))
1233 (erc-update-mode-line)
1234 (run-hooks 'erc-join-hook)
1235 (erc-make-notice
1236 (erc-format-message 'JOIN-you ?c chnl)))
1237 (t
1238 (setq buffer (erc-get-buffer chnl proc))
1239 (erc-make-notice
1240 (erc-format-message
1241 'JOIN ?n nick ?u login ?h host ?c chnl))))))
1242 (when buffer (set-buffer buffer))
1243 (erc-update-channel-member chnl nick nick t nil nil host login)
1244 ;; on join, we want to stay in the new channel buffer
1245 ;;(set-buffer ob)
1246 (erc-display-message parsed nil buffer str))))))
1247
1248(define-erc-response-handler (KICK)
1249 "Handle kick messages received from the server." nil
1250 (let* ((ch (first (erc-response.command-args parsed)))
1251 (tgt (second (erc-response.command-args parsed)))
1252 (reason (erc-trim-string (erc-response.contents parsed)))
1253 (buffer (erc-get-buffer ch proc)))
1254 (multiple-value-bind (nick login host)
7db26af0 1255 (values-list (erc-parse-user (erc-response.sender parsed)))
597993cf
MB
1256 (erc-remove-channel-member buffer tgt)
1257 (cond
1258 ((string= tgt (erc-current-nick))
1259 (erc-display-message
1260 parsed 'notice buffer
1261 'KICK-you ?n nick ?u login ?h host ?c ch ?r reason)
1262 (run-hook-with-args 'erc-kick-hook buffer)
1263 (erc-with-buffer
1264 (buffer)
1265 (erc-remove-channel-users))
1266 (erc-delete-default-channel ch buffer)
1267 (erc-update-mode-line buffer))
1268 ((string= nick (erc-current-nick))
1269 (erc-display-message
1270 parsed 'notice buffer
1271 'KICK-by-you ?k tgt ?c ch ?r reason))
1272 (t (erc-display-message
1273 parsed 'notice buffer
1274 'KICK ?k tgt ?n nick ?u login ?h host ?c ch ?r reason))))))
1275
1276(define-erc-response-handler (MODE)
1277 "Handle server mode changes." nil
1278 (let ((tgt (first (erc-response.command-args parsed)))
1279 (mode (mapconcat 'identity (cdr (erc-response.command-args parsed))
1280 " ")))
1281 (multiple-value-bind (nick login host)
7db26af0 1282 (values-list (erc-parse-user (erc-response.sender parsed)))
597993cf
MB
1283 (erc-log (format "MODE: %s -> %s: %s" nick tgt mode))
1284 ;; dirty hack
1285 (let ((buf (cond ((erc-channel-p tgt)
1286 (erc-get-buffer tgt proc))
1287 ((string= tgt (erc-current-nick)) nil)
1288 ((erc-active-buffer) (erc-active-buffer))
1289 (t (erc-get-buffer tgt)))))
1290 (with-current-buffer (or buf
1291 (current-buffer))
1292 (erc-update-modes tgt mode nick host login))
1293 (if (or (string= login "") (string= host ""))
1294 (erc-display-message parsed 'notice buf
1295 'MODE-nick ?n nick
1296 ?t tgt ?m mode)
1297 (erc-display-message parsed 'notice buf
1298 'MODE ?n nick ?u login
1299 ?h host ?t tgt ?m mode)))
1300 (erc-banlist-update proc parsed))))
1301
1302(define-erc-response-handler (NICK)
1303 "Handle nick change messages." nil
1304 (let ((nn (erc-response.contents parsed))
1305 bufs)
1306 (multiple-value-bind (nick login host)
7db26af0 1307 (values-list (erc-parse-user (erc-response.sender parsed)))
597993cf
MB
1308 (setq bufs (erc-buffer-list-with-nick nick proc))
1309 (erc-log (format "NICK: %s -> %s" nick nn))
1310 ;; if we had a query with this user, make sure future messages will be
1311 ;; sent to the correct nick. also add to bufs, since the user will want
1312 ;; to see the nick change in the query, and if it's a newly begun query,
1313 ;; erc-channel-users won't contain it
1314 (erc-buffer-filter
1315 (lambda ()
1316 (when (equal (erc-default-target) nick)
1317 (setq erc-default-recipients
1318 (cons nn (cdr erc-default-recipients)))
1319 (rename-buffer nn)
1320 (erc-update-mode-line)
1321 (add-to-list 'bufs (current-buffer)))))
1322 (erc-update-user-nick nick nn host nil nil login)
1323 (cond
1324 ((string= nick (erc-current-nick))
1325 (add-to-list 'bufs (erc-server-buffer))
1326 (erc-set-current-nick nn)
1327 (erc-update-mode-line)
1328 (setq erc-nick-change-attempt-count 0)
1329 (setq erc-default-nicks (if (consp erc-nick) erc-nick (list erc-nick)))
1330 (erc-display-message
1331 parsed 'notice bufs
1332 'NICK-you ?n nick ?N nn)
1333 (run-hook-with-args 'erc-nick-changed-functions nn nick))
1334 (t
1335 (erc-handle-user-status-change 'nick (list nick login host) (list nn))
1336 (erc-display-message parsed 'notice bufs 'NICK ?n nick
1337 ?u login ?h host ?N nn))))))
1338
1339(define-erc-response-handler (PART)
1340 "Handle part messages." nil
1341 (let* ((chnl (first (erc-response.command-args parsed)))
1342 (reason (erc-trim-string (erc-response.contents parsed)))
1343 (buffer (erc-get-buffer chnl proc)))
1344 (multiple-value-bind (nick login host)
7db26af0 1345 (values-list (erc-parse-user (erc-response.sender parsed)))
597993cf
MB
1346 (erc-remove-channel-member buffer nick)
1347 (erc-display-message parsed 'notice buffer
1348 'PART ?n nick ?u login
1349 ?h host ?c chnl ?r (or reason ""))
1350 (when (string= nick (erc-current-nick))
1351 (run-hook-with-args 'erc-part-hook buffer)
1352 (erc-with-buffer
1353 (buffer)
1354 (erc-remove-channel-users))
1355 (erc-delete-default-channel chnl buffer)
1356 (erc-update-mode-line buffer)
1357 (when erc-kill-buffer-on-part
1358 (kill-buffer buffer))))))
1359
1360(define-erc-response-handler (PING)
1361 "Handle ping messages." nil
1362 (let ((pinger (first (erc-response.command-args parsed))))
1363 (erc-log (format "PING: %s" pinger))
1364 ;; ping response to the server MUST be forced, or you can lose big
1365 (erc-server-send (format "PONG :%s" pinger) t)
1366 (when erc-verbose-server-ping
1367 (erc-display-message
1368 parsed 'error proc
1369 'PING ?s (erc-time-diff erc-server-last-ping-time (erc-current-time))))
1370 (setq erc-server-last-ping-time (erc-current-time))))
1371
1372(define-erc-response-handler (PONG)
1373 "Handle pong messages." nil
1374 (let ((time (string-to-number (erc-response.contents parsed))))
1375 (when (> time 0)
1376 (setq erc-server-lag (erc-time-diff time (erc-current-time)))
1377 (when erc-verbose-server-ping
1378 (erc-display-message
1379 parsed 'notice proc 'PONG
1380 ?h (first (erc-response.command-args parsed)) ?i erc-server-lag
1381 ?s (if (/= erc-server-lag 1) "s" "")))
1382 (erc-update-mode-line))))
1383
1384(define-erc-response-handler (PRIVMSG NOTICE)
712e2b05 1385 "Handle private messages, including messages in channels." nil
597993cf
MB
1386 (let ((sender-spec (erc-response.sender parsed))
1387 (cmd (erc-response.command parsed))
1388 (tgt (car (erc-response.command-args parsed)))
1389 (msg (erc-response.contents parsed)))
1390 (if (or (erc-ignored-user-p sender-spec)
1391 (erc-ignored-reply-p msg tgt proc))
1392 (when erc-minibuffer-ignored
1393 (message "Ignored %s from %s to %s" cmd sender-spec tgt))
1394 (let* ((sndr (erc-parse-user sender-spec))
1395 (nick (nth 0 sndr))
1396 (login (nth 1 sndr))
1397 (host (nth 2 sndr))
1398 (msgp (string= cmd "PRIVMSG"))
1399 (noticep (string= cmd "NOTICE"))
1400 ;; S.B. downcase *both* tgt and current nick
1401 (privp (erc-current-nick-p tgt))
1402 s buffer
1403 fnick)
1404 (setf (erc-response.contents parsed) msg)
1405 (setq buffer (erc-get-buffer (if privp nick tgt) proc))
1406 (when buffer
1407 (with-current-buffer buffer
1408 ;; update the chat partner info. Add to the list if private
cfa61b85 1409 ;; message. We will accumulate private identities indefinitely
597993cf
MB
1410 ;; at this point.
1411 (erc-update-channel-member (if privp nick tgt) nick nick
1412 privp nil nil host login nil nil t)
1413 (let ((cdata (erc-get-channel-user nick)))
1414 (setq fnick (funcall erc-format-nick-function
1415 (car cdata) (cdr cdata))))))
1416 (cond
1417 ((erc-is-message-ctcp-p msg)
1418 (setq s (if msgp
1419 (erc-process-ctcp-query proc parsed nick login host)
1420 (erc-process-ctcp-reply proc parsed nick login host
1421 (match-string 1 msg)))))
1422 (t
1423 (setcar erc-server-last-peers nick)
1424 (setq s (erc-format-privmessage
1425 (or fnick nick) msg
1426 ;; If buffer is a query buffer,
1427 ;; format the nick as for a channel.
1428 (and (not (and buffer
1429 (erc-query-buffer-p buffer)
1430 erc-format-query-as-channel-p))
1431 privp)
1432 msgp))))
1433 (when s
1434 (if (and noticep privp)
1435 (progn
1436 (run-hook-with-args 'erc-echo-notice-always-hook
1437 s parsed buffer nick)
1438 (run-hook-with-args-until-success
1439 'erc-echo-notice-hook s parsed buffer nick))
1440 (erc-display-message parsed nil buffer s)))
1441 (when (string= cmd "PRIVMSG")
1442 (erc-auto-query proc parsed))))))
1443
cd1181db 1444;; FIXME: need clean way of specifying extra hooks in
597993cf
MB
1445;; define-erc-response-handler.
1446(add-hook 'erc-server-PRIVMSG-functions 'erc-auto-query)
1447
1448(define-erc-response-handler (QUIT)
712e2b05 1449 "Another user has quit IRC." nil
597993cf
MB
1450 (let ((reason (erc-response.contents parsed))
1451 bufs)
1452 (multiple-value-bind (nick login host)
7db26af0 1453 (values-list (erc-parse-user (erc-response.sender parsed)))
597993cf
MB
1454 (setq bufs (erc-buffer-list-with-nick nick proc))
1455 (erc-remove-user nick)
1456 (setq reason (erc-wash-quit-reason reason nick login host))
1457 (erc-display-message parsed 'notice bufs
1458 'QUIT ?n nick ?u login
1459 ?h host ?r reason))))
1460
1461(define-erc-response-handler (TOPIC)
712e2b05 1462 "The channel topic has changed." nil
597993cf
MB
1463 (let* ((ch (first (erc-response.command-args parsed)))
1464 (topic (erc-trim-string (erc-response.contents parsed)))
56551c43
TL
1465 (time (format-time-string erc-server-timestamp-format
1466 (current-time))))
597993cf 1467 (multiple-value-bind (nick login host)
7db26af0 1468 (values-list (erc-parse-user (erc-response.sender parsed)))
597993cf
MB
1469 (erc-update-channel-member ch nick nick nil nil nil host login)
1470 (erc-update-channel-topic ch (format "%s\C-o (%s, %s)" topic nick time))
1471 (erc-display-message parsed 'notice (erc-get-buffer ch proc)
1472 'TOPIC ?n nick ?u login ?h host
1473 ?c ch ?T topic))))
1474
1475(define-erc-response-handler (WALLOPS)
712e2b05 1476 "Display a WALLOPS message." nil
597993cf
MB
1477 (let ((message (erc-response.contents parsed)))
1478 (multiple-value-bind (nick login host)
7db26af0 1479 (values-list (erc-parse-user (erc-response.sender parsed)))
597993cf
MB
1480 (erc-display-message
1481 parsed 'notice nil
1482 'WALLOPS ?n nick ?m message))))
1483
1484(define-erc-response-handler (001)
1485 "Set `erc-server-current-nick' to reflect server settings and display the welcome message."
1486 nil
1487 (erc-set-current-nick (first (erc-response.command-args parsed)))
1488 (erc-update-mode-line) ; needed here?
1489 (setq erc-nick-change-attempt-count 0)
1490 (setq erc-default-nicks (if (consp erc-nick) erc-nick (list erc-nick)))
1491 (erc-display-message
1492 parsed 'notice 'active (erc-response.contents parsed)))
1493
1494(define-erc-response-handler (MOTD 002 003 371 372 374 375)
1495 "Display the server's message of the day." nil
1496 (erc-handle-login)
1497 (erc-display-message
1498 parsed 'notice (if erc-server-connected 'active proc)
1499 (erc-response.contents parsed)))
1500
1501(define-erc-response-handler (376 422)
712e2b05 1502 "End of MOTD/MOTD is missing." nil
597993cf
MB
1503 (erc-server-MOTD proc parsed)
1504 (erc-connection-established proc parsed))
1505
1506(define-erc-response-handler (004)
712e2b05 1507 "Display the server's identification." nil
597993cf 1508 (multiple-value-bind (server-name server-version)
7db26af0 1509 (values-list (cdr (erc-response.command-args parsed)))
597993cf
MB
1510 (setq erc-server-version server-version)
1511 (setq erc-server-announced-name server-name)
1512 (erc-update-mode-line-buffer (process-buffer proc))
1513 (erc-display-message
1514 parsed 'notice proc
1515 's004 ?s server-name ?v server-version
1516 ?U (fourth (erc-response.command-args parsed))
1517 ?C (fifth (erc-response.command-args parsed)))))
1518
1519(define-erc-response-handler (005)
1520 "Set the variable `erc-server-parameters' and display the received message.
1521
1522According to RFC 2812, suggests alternate servers on the network.
1523Many servers, however, use this code to show which parameters they have set,
1524for example, the network identifier, maximum allowed topic length, whether
cfa61b85 1525certain commands are accepted and more. See documentation for
597993cf
MB
1526`erc-server-parameters' for more information on the parameters sent.
1527
1528A server may send more than one 005 message."
1529 nil
1530 (let ((line (mapconcat 'identity
1531 (setf (erc-response.command-args parsed)
1532 (cdr (erc-response.command-args parsed)))
1533 " ")))
1534 (while (erc-response.command-args parsed)
1535 (let ((section (pop (erc-response.command-args parsed))))
1536 ;; fill erc-server-parameters
1537 (when (string-match "^\\([A-Z]+\\)\=\\(.*\\)$\\|^\\([A-Z]+\\)$"
1538 section)
1539 (add-to-list 'erc-server-parameters
1540 `(,(or (match-string 1 section)
1541 (match-string 3 section))
1542 .
1543 ,(match-string 2 section))))))
1544 (erc-display-message parsed 'notice proc line)))
1545
1546(define-erc-response-handler (221)
712e2b05 1547 "Display the current user modes." nil
597993cf
MB
1548 (let* ((nick (first (erc-response.command-args parsed)))
1549 (modes (mapconcat 'identity
1550 (cdr (erc-response.command-args parsed)) " ")))
1551 (erc-set-modes nick modes)
1552 (erc-display-message parsed 'notice 'active 's221 ?n nick ?m modes)))
1553
1554(define-erc-response-handler (252)
1555 "Display the number of IRC operators online." nil
1556 (erc-display-message parsed 'notice 'active 's252
1557 ?i (second (erc-response.command-args parsed))))
1558
1559(define-erc-response-handler (253)
1560 "Display the number of unknown connections." nil
1561 (erc-display-message parsed 'notice 'active 's253
1562 ?i (second (erc-response.command-args parsed))))
1563
1564(define-erc-response-handler (254)
1565 "Display the number of channels formed." nil
1566 (erc-display-message parsed 'notice 'active 's254
1567 ?i (second (erc-response.command-args parsed))))
1568
1569(define-erc-response-handler (250 251 255 256 257 258 259 265 266 377 378)
1570 "Generic display of server messages as notices.
1571
1572See `erc-display-server-message'." nil
1573 (erc-display-server-message proc parsed))
1574
1c36df97
MO
1575(define-erc-response-handler (275)
1576 "Display secure connection message." nil
1577 (multiple-value-bind (nick user message)
7db26af0 1578 (values-list (cdr (erc-response.command-args parsed)))
1c36df97
MO
1579 (erc-display-message
1580 parsed 'notice 'active 's275
1581 ?n nick
1582 ?m (mapconcat 'identity (cddr (erc-response.command-args parsed))
1583 " "))))
1584
ff59d266
MB
1585(define-erc-response-handler (290)
1586 "Handle dancer-ircd CAPAB messages." nil nil)
1587
597993cf
MB
1588(define-erc-response-handler (301)
1589 "AWAY notice." nil
1590 (erc-display-message parsed 'notice 'active 's301
1591 ?n (second (erc-response.command-args parsed))
1592 ?r (erc-response.contents parsed)))
1593
1594(define-erc-response-handler (303)
1595 "ISON reply" nil
1596 (erc-display-message parsed 'notice 'active 's303
1597 ?n (second (erc-response.command-args parsed))))
1598
1599(define-erc-response-handler (305)
1600 "Return from AWAYness." nil
1601 (erc-process-away proc nil)
1602 (erc-display-message parsed 'notice 'active
1603 's305 ?m (erc-response.contents parsed)))
1604
1605(define-erc-response-handler (306)
1606 "Set AWAYness." nil
1607 (erc-process-away proc t)
1608 (erc-display-message parsed 'notice 'active
1609 's306 ?m (erc-response.contents parsed)))
1610
2131c501
MO
1611(define-erc-response-handler (307)
1612 "Display nick-identified message." nil
1613 (multiple-value-bind (nick user message)
7db26af0 1614 (values-list (cdr (erc-response.command-args parsed)))
2131c501
MO
1615 (erc-display-message
1616 parsed 'notice 'active 's307
1617 ?n nick
1618 ?m (mapconcat 'identity (cddr (erc-response.command-args parsed))
1619 " "))))
1620
597993cf
MB
1621(define-erc-response-handler (311 314)
1622 "WHOIS/WHOWAS notices." nil
1623 (let ((fname (erc-response.contents parsed))
1624 (catalog-entry (intern (format "s%s" (erc-response.command parsed)))))
1625 (multiple-value-bind (nick user host)
7db26af0 1626 (values-list (cdr (erc-response.command-args parsed)))
597993cf
MB
1627 (erc-update-user-nick nick nick host nil fname user)
1628 (erc-display-message
1629 parsed 'notice 'active catalog-entry
1630 ?n nick ?f fname ?u user ?h host))))
1631
1632(define-erc-response-handler (312)
712e2b05 1633 "Server name response in WHOIS." nil
597993cf 1634 (multiple-value-bind (nick server-host)
7db26af0 1635 (values-list (cdr (erc-response.command-args parsed)))
597993cf
MB
1636 (erc-display-message
1637 parsed 'notice 'active 's312
1638 ?n nick ?s server-host ?c (erc-response.contents parsed))))
1639
1640(define-erc-response-handler (313)
1641 "IRC Operator response in WHOIS." nil
1642 (erc-display-message
1643 parsed 'notice 'active 's313
1644 ?n (second (erc-response.command-args parsed))))
1645
1646(define-erc-response-handler (315 318 323 369)
1647 ;; 315 - End of WHO
1648 ;; 318 - End of WHOIS list
1649 ;; 323 - End of channel LIST
1650 ;; 369 - End of WHOWAS
712e2b05 1651 "End of WHO/WHOIS/LIST/WHOWAS notices." nil
597993cf
MB
1652 (ignore proc parsed))
1653
1654(define-erc-response-handler (317)
1655 "IDLE notice." nil
1656 (multiple-value-bind (nick seconds-idle on-since time)
7db26af0 1657 (values-list (cdr (erc-response.command-args parsed)))
597993cf 1658 (setq time (when on-since
56551c43 1659 (format-time-string erc-server-timestamp-format
597993cf
MB
1660 (erc-string-to-emacs-time on-since))))
1661 (erc-update-user-nick nick nick nil nil nil
1662 (and time (format "on since %s" time)))
1663 (if time
1664 (erc-display-message
1665 parsed 'notice 'active 's317-on-since
1666 ?n nick ?i (erc-sec-to-time (string-to-number seconds-idle)) ?t time)
1667 (erc-display-message
1668 parsed 'notice 'active 's317
1669 ?n nick ?i (erc-sec-to-time (string-to-number seconds-idle))))))
1670
1671(define-erc-response-handler (319)
712e2b05 1672 "Channel names in WHOIS response." nil
597993cf
MB
1673 (erc-display-message
1674 parsed 'notice 'active 's319
1675 ?n (second (erc-response.command-args parsed))
1676 ?c (erc-response.contents parsed)))
1677
1678(define-erc-response-handler (320)
1679 "Identified user in WHOIS." nil
1680 (erc-display-message
1681 parsed 'notice 'active 's320
1682 ?n (second (erc-response.command-args parsed))))
1683
1684(define-erc-response-handler (321)
1685 "LIST header." nil
5e56b3fb
MO
1686 (setq erc-channel-list nil))
1687
1688(defun erc-server-321-message (proc parsed)
1689 "Display a message for the 321 event."
1690 (erc-display-message parsed 'notice proc 's321)
1691 nil)
1692(add-hook 'erc-server-321-functions 'erc-server-321-message t)
597993cf
MB
1693
1694(define-erc-response-handler (322)
1695 "LIST notice." nil
1696 (let ((topic (erc-response.contents parsed)))
1697 (multiple-value-bind (channel num-users)
7db26af0 1698 (values-list (cdr (erc-response.command-args parsed)))
597993cf 1699 (add-to-list 'erc-channel-list (list channel))
5e56b3fb
MO
1700 (erc-update-channel-topic channel topic))))
1701
1702(defun erc-server-322-message (proc parsed)
1703 "Display a message for the 322 event."
1704 (let ((topic (erc-response.contents parsed)))
1705 (multiple-value-bind (channel num-users)
7db26af0 1706 (values-list (cdr (erc-response.command-args parsed)))
597993cf 1707 (erc-display-message
6904f7fe 1708 parsed 'notice proc 's322
597993cf 1709 ?c channel ?u num-users ?t (or topic "")))))
5e56b3fb 1710(add-hook 'erc-server-322-functions 'erc-server-322-message t)
597993cf
MB
1711
1712(define-erc-response-handler (324)
1713 "Channel or nick modes." nil
1714 (let ((channel (second (erc-response.command-args parsed)))
1715 (modes (mapconcat 'identity (cddr (erc-response.command-args parsed))
1716 " ")))
1717 (erc-set-modes channel modes)
1718 (erc-display-message
1719 parsed 'notice (erc-get-buffer channel proc)
1720 's324 ?c channel ?m modes)))
1721
40ef8242
MO
1722(define-erc-response-handler (328)
1723 "Channel URL (on freenode network)." nil
1724 (let ((channel (second (erc-response.command-args parsed)))
1725 (url (erc-response.contents parsed)))
1726 (erc-display-message parsed 'notice (erc-get-buffer channel proc)
1727 's328 ?c channel ?u url)))
1728
597993cf
MB
1729(define-erc-response-handler (329)
1730 "Channel creation date." nil
1731 (let ((channel (second (erc-response.command-args parsed)))
1732 (time (erc-string-to-emacs-time
1733 (third (erc-response.command-args parsed)))))
1734 (erc-display-message
1735 parsed 'notice (erc-get-buffer channel proc)
56551c43
TL
1736 's329 ?c channel ?t (format-time-string erc-server-timestamp-format
1737 time))))
597993cf
MB
1738
1739(define-erc-response-handler (330)
712e2b05 1740 "Nick is authed as (on Quakenet network)." nil
597993cf
MB
1741 ;; FIXME: I don't know what the magic numbers mean. Mummy, make
1742 ;; the magic numbers go away.
1743 ;; No seriously, I have no clue about the format of this command,
1744 ;; and don't sit on Quakenet, so can't test. Originally we had:
1745 ;; nick == (aref parsed 3)
1746 ;; authaccount == (aref parsed 4)
1747 ;; authmsg == (aref parsed 5)
1748 ;; The guesses below are, well, just that. -- Lawrence 2004/05/10
1749 (let ((nick (second (erc-response.command-args parsed)))
1750 (authaccount (third (erc-response.command-args parsed)))
1751 (authmsg (erc-response.contents parsed)))
1752 (erc-display-message parsed 'notice 'active 's330
1753 ?n nick ?a authmsg ?i authaccount)))
1754
1755(define-erc-response-handler (331)
712e2b05 1756 "No topic set for channel." nil
597993cf
MB
1757 (let ((channel (second (erc-response.command-args parsed)))
1758 (topic (erc-response.contents parsed)))
597993cf
MB
1759 (erc-display-message parsed 'notice (erc-get-buffer channel proc)
1760 's331 ?c channel)))
1761
1762(define-erc-response-handler (332)
1763 "TOPIC notice." nil
1764 (let ((channel (second (erc-response.command-args parsed)))
1765 (topic (erc-response.contents parsed)))
1766 (erc-update-channel-topic channel topic)
1767 (erc-display-message parsed 'notice (erc-get-buffer channel proc)
1768 's332 ?c channel ?T topic)))
1769
1770(define-erc-response-handler (333)
712e2b05 1771 "Who set the topic, and when." nil
597993cf 1772 (multiple-value-bind (channel nick time)
7db26af0 1773 (values-list (cdr (erc-response.command-args parsed)))
56551c43 1774 (setq time (format-time-string erc-server-timestamp-format
597993cf
MB
1775 (erc-string-to-emacs-time time)))
1776 (erc-update-channel-topic channel
1777 (format "\C-o (%s, %s)" nick time)
1778 'append)
1779 (erc-display-message parsed 'notice (erc-get-buffer channel proc)
1780 's333 ?c channel ?n nick ?t time)))
1781
1782(define-erc-response-handler (341)
1783 "Let user know when an INVITE attempt has been sent successfully."
1784 nil
1785 (multiple-value-bind (nick channel)
7db26af0 1786 (values-list (cdr (erc-response.command-args parsed)))
597993cf
MB
1787 (erc-display-message parsed 'notice (erc-get-buffer channel proc)
1788 's341 ?n nick ?c channel)))
1789
1790(define-erc-response-handler (352)
1791 "WHO notice." nil
1792 (multiple-value-bind (channel user host server nick away-flag)
7db26af0 1793 (values-list (cdr (erc-response.command-args parsed)))
597993cf
MB
1794 (let ((full-name (erc-response.contents parsed))
1795 hopcount)
1796 (when (string-match "\\(^[0-9]+ \\)\\(.*\\)$" full-name)
1797 (setq hopcount (match-string 1 full-name))
1798 (setq full-name (match-string 2 full-name)))
1799 (erc-update-channel-member channel nick nick nil nil nil host
1800 user full-name)
1801 (erc-display-message parsed 'notice 'active 's352
1802 ?c channel ?n nick ?a away-flag
1803 ?u user ?h host ?f full-name))))
1804
1805(define-erc-response-handler (353)
1806 "NAMES notice." nil
1807 (let ((channel (third (erc-response.command-args parsed)))
1808 (users (erc-response.contents parsed)))
597993cf
MB
1809 (erc-display-message parsed 'notice (or (erc-get-buffer channel proc)
1810 'active)
83dc6995
MB
1811 's353 ?c channel ?u users)
1812 (erc-with-buffer (channel proc)
1813 (erc-channel-receive-names users))))
597993cf
MB
1814
1815(define-erc-response-handler (366)
1816 "End of NAMES." nil
1817 (erc-with-buffer ((second (erc-response.command-args parsed)) proc)
1818 (erc-channel-end-receiving-names)))
1819
1820(define-erc-response-handler (367)
712e2b05 1821 "Channel ban list entries." nil
597993cf 1822 (multiple-value-bind (channel banmask setter time)
7db26af0 1823 (values-list (cdr (erc-response.command-args parsed)))
83dc6995
MB
1824 ;; setter and time are not standard
1825 (if setter
1826 (erc-display-message parsed 'notice 'active 's367-set-by
1827 ?c channel
1828 ?b banmask
1829 ?s setter
1830 ?t (or time ""))
1831 (erc-display-message parsed 'notice 'active 's367
1832 ?c channel
1833 ?b banmask))))
597993cf
MB
1834
1835(define-erc-response-handler (368)
712e2b05 1836 "End of channel ban list." nil
597993cf
MB
1837 (let ((channel (second (erc-response.command-args parsed))))
1838 (erc-display-message parsed 'notice 'active 's368
1839 ?c channel)))
1840
1841(define-erc-response-handler (379)
1842 "Forwarding to another channel." nil
1843 ;; FIXME: Yet more magic numbers in original code, I'm guessing this
1844 ;; command takes two arguments, and doesn't have any "contents". --
1845 ;; Lawrence 2004/05/10
1846 (multiple-value-bind (from to)
7db26af0 1847 (values-list (cdr (erc-response.command-args parsed)))
597993cf
MB
1848 (erc-display-message parsed 'notice 'active
1849 's379 ?c from ?f to)))
1850
1851(define-erc-response-handler (391)
712e2b05 1852 "Server's time string." nil
597993cf
MB
1853 (erc-display-message
1854 parsed 'notice 'active
1855 's391 ?s (second (erc-response.command-args parsed))
1856 ?t (third (erc-response.command-args parsed))))
1857
1858(define-erc-response-handler (401)
1859 "No such nick/channel." nil
1860 (let ((nick/channel (second (erc-response.command-args parsed))))
1861 (when erc-whowas-on-nosuchnick
1862 (erc-log (format "cmd: WHOWAS: %s" nick/channel))
1863 (erc-server-send (format "WHOWAS %s 1" nick/channel)))
1864 (erc-display-message parsed '(notice error) 'active
1865 's401 ?n nick/channel)))
1866
1867(define-erc-response-handler (403)
1868 "No such channel." nil
1869 (erc-display-message parsed '(notice error) 'active
1870 's403 ?c (second (erc-response.command-args parsed))))
1871
1872(define-erc-response-handler (404)
1873 "Cannot send to channel." nil
1874 (erc-display-message parsed '(notice error) 'active
1875 's404 ?c (second (erc-response.command-args parsed))))
1876
1877
1878(define-erc-response-handler (405)
712e2b05 1879 "Can't join that many channels." nil
597993cf
MB
1880 (erc-display-message parsed '(notice error) 'active
1881 's405 ?c (second (erc-response.command-args parsed))))
1882
1883(define-erc-response-handler (406)
712e2b05 1884 "No such nick." nil
597993cf
MB
1885 (erc-display-message parsed '(notice error) 'active
1886 's406 ?n (second (erc-response.command-args parsed))))
1887
1888(define-erc-response-handler (412)
712e2b05 1889 "No text to send." nil
597993cf
MB
1890 (erc-display-message parsed '(notice error) 'active 's412))
1891
1892(define-erc-response-handler (421)
712e2b05 1893 "Unknown command." nil
597993cf
MB
1894 (erc-display-message parsed '(notice error) 'active 's421
1895 ?c (second (erc-response.command-args parsed))))
1896
1897(define-erc-response-handler (432)
712e2b05 1898 "Bad nick." nil
597993cf
MB
1899 (erc-display-message parsed '(notice error) 'active 's432
1900 ?n (second (erc-response.command-args parsed))))
1901
1902(define-erc-response-handler (433)
712e2b05 1903 "Login-time \"nick in use\"." nil
597993cf
MB
1904 (erc-nickname-in-use (second (erc-response.command-args parsed))
1905 "already in use"))
1906
1907(define-erc-response-handler (437)
712e2b05 1908 "Nick temporarily unavailable (on IRCnet)." nil
597993cf
MB
1909 (let ((nick/channel (second (erc-response.command-args parsed))))
1910 (unless (erc-channel-p nick/channel)
1911 (erc-nickname-in-use nick/channel "temporarily unavailable"))))
1912
1913(define-erc-response-handler (442)
712e2b05 1914 "Not on channel." nil
597993cf
MB
1915 (erc-display-message parsed '(notice error) 'active 's442
1916 ?c (second (erc-response.command-args parsed))))
1917
1918(define-erc-response-handler (461)
712e2b05 1919 "Not enough parameters for command." nil
597993cf
MB
1920 (erc-display-message parsed '(notice error) 'active 's461
1921 ?c (second (erc-response.command-args parsed))
1922 ?m (erc-response.contents parsed)))
1923
10dc9f9e
MB
1924(define-erc-response-handler (465)
1925 "You are banned from this server." nil
1926 (setq erc-server-banned t)
1927 ;; show the server's message, as a reason might be provided
1928 (erc-display-error-notice
1929 parsed
1930 (erc-response.contents parsed)))
1931
597993cf 1932(define-erc-response-handler (474)
712e2b05 1933 "Banned from channel errors." nil
597993cf
MB
1934 (erc-display-message parsed '(notice error) nil
1935 (intern (format "s%s"
1936 (erc-response.command parsed)))
1937 ?c (second (erc-response.command-args parsed))))
1938
1939(define-erc-response-handler (475)
1940 "Channel key needed." nil
1941 (erc-display-message parsed '(notice error) nil 's475
1942 ?c (second (erc-response.command-args parsed)))
1943 (when erc-prompt-for-channel-key
1944 (let ((channel (second (erc-response.command-args parsed)))
1945 (key (read-from-minibuffer
1946 (format "Channel %s is mode +k. Enter key (RET to cancel): "
1947 (second (erc-response.command-args parsed))))))
1948 (when (and key (> (length key) 0))
1949 (erc-cmd-JOIN channel key)))))
1950
1951(define-erc-response-handler (477)
712e2b05 1952 "Channel doesn't support modes." nil
597993cf
MB
1953 (let ((channel (second (erc-response.command-args parsed)))
1954 (message (erc-response.contents parsed)))
1955 (erc-display-message parsed 'notice (erc-get-buffer channel proc)
1956 (format "%s: %s" channel message))))
1957
1958(define-erc-response-handler (482)
712e2b05 1959 "You need to be a channel operator to do that." nil
597993cf
MB
1960 (let ((channel (second (erc-response.command-args parsed)))
1961 (message (erc-response.contents parsed)))
1962 (erc-display-message parsed '(error notice) 'active 's482
1963 ?c channel ?m message)))
1964
f927985e
JD
1965(define-erc-response-handler (671)
1966 "Secure connection response in WHOIS." nil
1967 (let ((nick (second (erc-response.command-args parsed)))
1968 (securemsg (erc-response.contents parsed)))
1969 (erc-display-message parsed 'notice 'active 's671
1970 ?n nick ?a securemsg)))
1971
10dc9f9e 1972(define-erc-response-handler (431 445 446 451 462 463 464 481 483 484 485
597993cf
MB
1973 491 501 502)
1974 ;; 431 - No nickname given
1975 ;; 445 - SUMMON has been disabled
1976 ;; 446 - USERS has been disabled
1977 ;; 451 - You have not registered
1978 ;; 462 - Unauthorized command (already registered)
1979 ;; 463 - Your host isn't among the privileged
1980 ;; 464 - Password incorrect
597993cf
MB
1981 ;; 481 - Need IRCop privileges
1982 ;; 483 - You can't kill a server!
1983 ;; 484 - Your connection is restricted!
1984 ;; 485 - You're not the original channel operator
1985 ;; 491 - No O-lines for your host
1986 ;; 501 - Unknown MODE flag
1987 ;; 502 - Cannot change mode for other users
712e2b05
MO
1988 "Generic display of server error messages.
1989
1990See `erc-display-error-notice'." nil
597993cf
MB
1991 (erc-display-error-notice
1992 parsed
1993 (intern (format "s%s" (erc-response.command parsed)))))
1994
1995;; FIXME: These are yet to be implemented, they're just stubs for now
1996;; -- Lawrence 2004/05/12
1997
1998;; response numbers left here for reference
1999
2000;; (define-erc-response-handler (323 364 365 381 382 392 393 394 395
2001;; 200 201 202 203 204 205 206 208 209 211 212 213
2002;; 214 215 216 217 218 219 241 242 243 244 249 261
2003;; 262 302 342 351 402 407 409 411 413 414 415
2004;; 423 424 436 441 443 444 467 471 472 473 KILL)
2005;; nil nil
2006;; (ignore proc parsed))
2007
2008(provide 'erc-backend)
2009
2010;;; erc-backend.el ends here
2011;; Local Variables:
2012;; indent-tabs-mode: nil
2013;; End: