1 ;;; liece-handle.el --- implementation of IRC message handlers
2 ;; Copyright (C) 1998-2000 Daiki Ueno
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
7 ;; Keywords: IRC, liece
9 ;; This file is part of Liece.
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
33 (require 'liece-inlines)
35 (require 'liece-intl))
37 (require 'liece-message)
38 (require 'liece-filter)
40 (require 'liece-handler)
42 (defmacro liece-handle-prepare-comment (rest &optional quote)
43 `(if (zerop (length ,rest))
46 (regexp-quote (format " (%s)" ,rest))
47 (format " (%s)" ,rest))))
49 (defmacro liece-handle-message-check-empty (msg)
52 (defmacro liece-handle-message-check-ignored (prefix rest)
54 (liece-ignore-this-p ,prefix liece-user-at-host)
55 (liece-message-from-ignored ,prefix ,rest)))
57 (defmacro liece-handle-check-changes-ignored ()
58 'liece-ignore-changes)
60 (defconst liece-handle-ctcp-message-regexp "\001\\(.*\\)\001")
62 (defmacro liece-handle-ctcp-message-p (msg)
63 `(string-match liece-handle-ctcp-message-regexp ,msg))
65 (autoload 'liece-ctcp-message "liece-ctcp")
66 (autoload 'liece-ctcp-notice "liece-ctcp")
69 (liece-handler-define-backend "generic")
73 (liece-handler-define-function
74 message '(prefix rest "generic")
75 (intern (format "liece-handle-%s-message" message)))
76 (defvar ,(intern (format "liece-%s-hook" message)) nil)
77 (defvar ,(intern (format "liece-after-%s-hook" message)) nil))
78 '("nick" "notice" "privmsg" "ping" "wall" "wallops" "quit" "topic"
79 "mode" "kick" "invite" "kill" "join" "part" "silence"))
81 (defun* liece-handle-nick-message (prefix rest)
82 (let ((chnls (liece-nick-get-joined-channels prefix)))
83 (liece-nick-change prefix rest)
85 ((liece-nick-equal prefix liece-real-nickname)
86 (setq liece-nickname-last liece-real-nickname
87 liece-real-nickname rest))
88 ((liece-nick-member prefix liece-current-chat-partners)
89 (setq liece-current-chat-partners
90 (string-list-modify-ignore-case (list (cons prefix rest))
91 liece-current-chat-partners))
92 (setcar (string-assoc-ignore-case prefix liece-nick-buffer-alist)
94 (setcar (string-assoc-ignore-case prefix liece-channel-buffer-alist)
96 (if (liece-nick-equal prefix liece-current-chat-partner)
97 (setq liece-current-chat-partner rest))
98 (add-to-list 'chnls rest)
99 (liece-channel-change)))
100 (if (liece-handle-check-changes-ignored)
101 (return-from liece-handle-nick-message))
102 (liece-insert-change (append (liece-pick-buffer chnls)
103 liece-D-buffer liece-O-buffer)
104 (format (_ "%s is now known as %s\n") prefix rest))))
106 (defun* liece-handle-notice-message (prefix rest)
107 (if (liece-handle-message-check-ignored prefix rest)
108 (return-from liece-handle-notice-message))
109 (or liece-ignore-extra-notices
111 (string-match "as being away" rest)
112 (return-from liece-handle-notice-message))
114 ;; No prefix. This is a server notice.
115 (when (and (null prefix) (string-match "^[^ ]* +:?" rest))
116 (liece-insert-notice (append liece-D-buffer liece-O-buffer)
117 (concat (substring rest (match-end 0)) "\n"))
118 (return-from liece-handle-notice-message))
120 (with-liece-decryption (rest prefix)
121 (if (run-hook-with-args-until-success 'liece-notice-cleartext-hook
123 (return-from liece-handle-notice-message))
125 (multiple-value-bind (chnl temp) (liece-split-line rest)
126 ;; This is a ctcp reply but contains additional messages
127 ;; at the left or/and right side.
128 (if (liece-handle-ctcp-message-p temp)
129 (setq temp (liece-ctcp-notice prefix temp)))
130 (if (liece-handle-message-check-empty temp)
131 (return-from liece-handle-notice-message))
133 ;; Normal message via notice.
134 (setq chnl (liece-channel-virtual chnl))
135 (let ((liece-message-target chnl)
136 (liece-message-speaker prefix)
137 (liece-message-type 'notice))
138 (liece-display-message temp)))))
140 (defun* liece-handle-privmsg-message (prefix rest)
141 (if (liece-handle-message-check-ignored prefix rest)
142 (return-from liece-handle-privmsg-message))
143 (with-liece-decryption (rest prefix)
144 (if (run-hook-with-args-until-success 'liece-privmsg-cleartext-hook
146 (return-from liece-handle-privmsg-message))
148 (multiple-value-bind (chnl temp) (liece-split-line rest)
149 (setq temp (or temp ""))
150 ;; This is a ctcp request but contains additional messages
151 ;; at the left or/and right side.
152 (if (liece-handle-ctcp-message-p temp)
153 (setq temp (liece-ctcp-message prefix chnl temp)))
154 (if (liece-handle-message-check-empty temp)
155 (return-from liece-handle-privmsg-message))
157 (setq chnl (liece-channel-virtual chnl))
160 (if liece-beep-on-bells
162 (and (string-match "\007" rest) (beep t))
163 (if (liece-nick-equal chnl liece-real-nickname)
164 (and liece-beep-when-privmsg (beep t))
165 (with-current-buffer (if liece-channel-buffer-mode
166 (liece-pick-buffer-1 chnl)
167 liece-dialogue-buffer)
168 (and liece-beep (beep t))))
170 (word (nth 0 liece-beep-words-list)))
172 (and (string-match word rest) (beep t))
174 (setq word (nth i liece-beep-words-list))))))
176 ;; Append timestamp if we are being away.
177 (and (string-equal "A" liece-away-indicator)
178 (liece-nick-equal chnl liece-real-nickname)
181 (funcall liece-format-time-function (current-time))
185 (let ((liece-message-target chnl)
186 (liece-message-speaker prefix)
187 (liece-message-type 'privmsg))
188 (liece-display-message temp))
190 ;; Append to the unread list.
191 (let ((item (if (eq liece-command-buffer 'chat)
192 liece-current-chat-partner
193 liece-current-channel)))
194 (if (liece-channel-equal chnl item)
196 (and (liece-channel-unread-p chnl)
197 (setq liece-channel-unread-list
198 (delete chnl liece-channel-unread-list)))
199 (setq liece-channel-unread-list
200 (cons chnl liece-channel-unread-list))))
202 (and (liece-nick-equal chnl liece-real-nickname)
203 (not (liece-nick-equal prefix liece-current-chat-partner))
204 (liece-message (_ "A private message has arrived from %s")
207 (defun liece-handle-ping-message (prefix rest)
208 (liece-send "PONG :%s" rest)
209 (liece-command-timestamp-if-interval-expired t)
212 (defun liece-handle-wall-message (prefix rest)
213 (liece-insert-broadcast (append liece-D-buffer liece-O-buffer)
214 (concat (if prefix (concat "from " prefix) "") " "
217 (defun liece-handle-wallops-message (prefix rest)
218 (if liece-show-wallops
219 (liece-insert-wallops (append liece-D-buffer liece-O-buffer)
220 (concat (if prefix prefix "UNKNOWN")
222 (liece-insert-wallops liece-W-buffer
223 (concat (if prefix (concat "from " prefix) "") " "
226 (defun* liece-handle-quit-message (prefix rest)
227 (let ((chnls (liece-nick-get-joined-channels prefix)) text match default)
228 ;; Mark temporary apart, if quitting user is one of our chat partners.
229 (when (liece-nick-member prefix liece-current-chat-partners)
230 (add-to-list 'chnls prefix)
231 (liece-nick-mark-as-apart prefix))
232 (if (liece-handle-check-changes-ignored)
233 (return-from liece-handle-quit-message))
235 (liece-compress-changes
236 (setq text (format (_ " \\(has\\|have\\) left IRC%s")
237 (liece-handle-prepare-comment rest t))
238 match (format "^%s%s.*%s$"
239 (if liece-display-time
240 liece-time-prefix-regexp "")
241 (regexp-quote liece-change-prefix)
243 default (format (_ "%s%s has left IRC%s\n")
244 liece-change-prefix prefix
245 (liece-handle-prepare-comment rest)))
246 (liece-replace (append (liece-pick-buffer chnls)
247 liece-D-buffer liece-O-buffer)
249 (format (_ ", %s have left IRC%s")
250 prefix (liece-handle-prepare-comment rest))))
252 (liece-insert-change (append (liece-pick-buffer chnls)
253 liece-D-buffer liece-O-buffer)
254 (format (_ "%s has left IRC%s\n")
255 (liece-handle-prepare-comment rest)))))
256 (liece-nick-change prefix nil)))
258 (defun* liece-handle-topic-message (prefix rest)
259 (multiple-value-bind (chnl topic) (liece-split-line rest)
260 (setq chnl (liece-channel-virtual chnl)
262 (liece-channel-set-topic topic chnl)
263 (if (liece-handle-check-changes-ignored)
264 (return-from liece-handle-topic-message))
265 (liece-insert-change (liece-pick-buffer chnl)
266 (format (_ "New topic on channel %s set by %s: %s\n")
268 (liece-insert-change (if (liece-nick-equal chnl liece-current-channel)
270 (append liece-D-buffer liece-O-buffer))
271 (format (_ "New topic on channel %s set by %s: %s\n")
273 (liece-set-channel-indicator)))
275 (defun* liece-handle-mode-message (prefix rest)
276 (if (liece-handle-check-changes-ignored)
277 (return-from liece-handle-mode-message))
278 (let ((chnl " ") (str "") mflag mflags marg margs val md chnlp)
279 (or (and (string-match "\\([^ ]*\\) +:?" rest)
280 (setq chnl (match-string 1 rest)
281 str (substring rest (match-end 0))
282 chnlp (liece-channel-p chnl)
283 str (if (= (aref str (1- (length str))) ? )
284 (substring str 0 -1) str)
285 chnl (liece-channel-virtual chnl)))
286 (and (string-match " +:" rest)
287 (setq str (substring rest (match-end 0))))
288 (return-from liece-handle-mode-message))
291 (when (string-match "\\([^ ]*\\) +" str)
292 (setq mflag (match-string 1 str)
293 marg (substring str (match-end 0))
294 mflags (string-to-char-list mflag))
295 (while (string-match "^\\([^ ]*\\) +" marg)
296 (setq margs (cons (match-string 1 marg) margs)
297 marg (substring marg (match-end 0))))
298 (or (string= marg "") (setq margs (cons marg margs)))
299 (while (setq md (pop mflags))
300 (cond ((eq ?- md) (setq val nil))
301 ((eq ?+ md) (setq val t))
302 ((eq ?o md) (liece-channel-set-operator chnl (pop margs) val))
303 ((eq ?v md) (liece-channel-set-voice chnl (pop margs) val))
304 ((eq ?b md) (liece-channel-set-ban chnl (pop margs) val))
305 ((eq ?e md) (liece-channel-set-exception chnl (pop margs) val))
306 ((eq ?I md) (liece-channel-set-invite chnl (pop margs) val))
307 (chnlp (liece-channel-set-mode val md chnl))
308 (t (liece-nick-set-mode val md chnl)))))
310 (liece-set-channel-indicator)
312 (liece-compress-changes
313 (let* ((text (concat (regexp-quote rest) "\n"))
314 (match (format (_ "^%s%sNew mode for %s set by %s: ")
315 (if liece-display-time
316 liece-time-prefix-regexp "")
317 (regexp-quote liece-change-prefix)
318 (regexp-quote chnl) (regexp-quote prefix)))
319 (default (format (_ "%sNew mode for %s set by %s: %s\n")
320 liece-change-prefix chnl prefix str)))
321 (liece-replace (liece-pick-buffer chnl)
322 match default text (concat ", " str "\n"))
323 (liece-replace (if (and liece-current-channel
325 chnl liece-current-channel))
327 (append liece-D-buffer liece-O-buffer))
328 match default text (concat ", " str "\n"))))
330 (liece-insert-change (liece-pick-buffer chnl)
331 (format (_ "New mode for %s set by %s: %s\n")
333 (liece-insert-change (if (and liece-current-channel
335 chnl liece-current-channel))
337 (append liece-D-buffer liece-O-buffer))
338 (format (_ "New mode for %s set by %s: %s\n")
339 chnl prefix str))))))
341 (defun* liece-handle-kick-message (prefix rest)
342 (if (/= 3 (length (setq rest (liece-split-line rest))))
343 (return-from liece-handle-kick-message))
344 (multiple-value-bind (chnl nick message) rest
345 (setq chnl (liece-channel-virtual chnl))
347 (if (liece-nick-equal nick liece-real-nickname)
350 (liece-pick-buffer chnl)
351 (format (_ "You were kicked off channel %s by %s (%s).\n")
352 chnl prefix message))
353 (liece-channel-part chnl))
354 (liece-nick-part nick chnl))
356 (if (liece-handle-check-changes-ignored)
357 (return-from liece-handle-kick-message))
360 (append (liece-pick-buffer chnl)
361 (if (liece-channel-equal chnl liece-current-channel)
363 (append liece-D-buffer liece-O-buffer)))
364 (format "%s has kicked %s out%s%s\n"
366 (if (string= (or liece-current-channel "") chnl)
368 (format " from channel %s" chnl))
371 (format " (%s)" message))))))
373 (defun* liece-handle-invite-message (prefix rest)
374 (or (string-match " +:" rest)
375 (return-from liece-handle-invite-message))
376 (and liece-beep-when-invited liece-beep-on-bells
378 (let ((chnl (liece-channel-virtual (substring rest (match-end 0)))))
379 (liece-insert-info (append liece-D-buffer liece-O-buffer)
380 (format "%s invites you to channel %s\n"
382 (setq liece-default-channel-candidate chnl)))
384 (defun* liece-handle-kill-message (prefix rest)
385 (or (string-match " +:" rest)
386 (return-from liece-handle-kill-message))
387 (let ((path (substring rest (match-end 0))))
388 (liece-insert-info (append liece-D-buffer liece-O-buffer)
389 (format "You were killed by %s. (Path: %s. RIP)\n"
391 (liece-clear-system))
393 (defun* liece-handle-join-message (prefix rest)
394 (let (flag (xnick prefix) (nick prefix) (chnl rest))
396 ((string-match "\007[ov]" chnl)
397 (setq flag (aref (match-string 0 chnl) 1)
398 chnl (substring rest 0 (match-beginning 0))))
399 ((string-match " +$" chnl)
400 (setq chnl (substring chnl 0 (match-beginning 0)))))
401 (setq chnl (liece-channel-virtual chnl))
403 (liece-nick-set-user-at-host nick liece-user-at-host)
405 (if (liece-nick-equal nick liece-real-nickname)
407 (and liece-gather-channel-modes
408 (not (liece-channel-modeless-p (liece-channel-real chnl)))
409 (liece-send "MODE %s " (liece-channel-real chnl)))
410 (liece-channel-join chnl))
411 (liece-nick-join nick chnl))
415 (liece-channel-set-operator chnl xnick t)
416 (setq xnick (concat "@" xnick)))
418 (liece-channel-set-voice chnl xnick t)
419 (setq xnick (concat "+" xnick))))
421 (if (liece-handle-check-changes-ignored)
422 (return-from liece-handle-join-message))
424 (when (and (liece-nick-member nick liece-current-chat-partners)
425 (get (intern nick liece-obarray) 'part))
426 (liece-insert-change (liece-pick-buffer nick)
427 (format (_ "%s has come back as (%s)\n")
428 nick liece-user-at-host))
429 (liece-nick-unmark-as-apart nick))
432 (liece-compress-changes
433 (let* ((text (format (_ " \\(has\\|have\\) joined channel %s")
434 (regexp-quote chnl)))
435 (match (format "^%s%s.*%s$"
436 (if liece-display-time
437 liece-time-prefix-regexp "")
438 (regexp-quote liece-change-prefix)
439 (regexp-quote text)))
440 (default (format (_ "%s%s (%s) has joined channel %s\n")
442 nick liece-user-at-host chnl)))
443 (liece-replace (liece-pick-buffer chnl)
445 (format (_ ", %s (%s) have joined channel %s")
446 nick liece-user-at-host chnl))
447 (liece-replace (if (and liece-current-channel
448 (liece-channel-equal chnl
449 liece-current-channel))
451 (append liece-D-buffer liece-O-buffer))
453 (format (_ ", %s (%s) have joined channel %s")
454 nick liece-user-at-host chnl))))
456 (liece-insert-change (liece-pick-buffer chnl)
457 (format (_ "%s (%s) has joined channel %s\n")
458 nick liece-user-at-host chnl))
459 (liece-insert-change (if (liece-channel-equal chnl
460 liece-current-channel)
462 (append liece-D-buffer liece-O-buffer))
463 (format (_ "%s (%s) has joined channel %s\n")
464 nick liece-user-at-host chnl))))))
466 (defun* liece-handle-part-message (prefix rest)
467 (multiple-value-bind (chnl comment text match default buf) (liece-split-line rest)
468 (setq chnl (liece-channel-virtual chnl)
469 comment (liece-handle-prepare-comment comment))
471 (if (liece-nick-equal prefix liece-real-nickname)
472 (liece-channel-part chnl)
473 (liece-nick-part prefix chnl))
475 (if (liece-handle-check-changes-ignored)
476 (return-from liece-handle-part-message))
478 (setq buf (append liece-D-buffer (liece-pick-buffer chnl)))
479 (unless (and liece-current-channel
480 (liece-channel-equal chnl liece-current-channel))
481 (setq buf (append buf liece-O-buffer)))
483 (liece-compress-changes
484 (setq text (format (_ " \\(has\\|have\\) left channel %s%s")
485 (regexp-quote chnl) (regexp-quote comment))
486 match (format "^%s%s.*%s$"
487 (if liece-display-time
488 liece-time-prefix-regexp "")
489 (regexp-quote liece-change-prefix)
491 default (format (_ "%s%s has left channel %s%s\n")
492 liece-change-prefix prefix chnl comment))
495 (format (_ ", %s have left channel %s%s")
496 prefix chnl comment)))
498 (liece-insert-change buf
499 (format (_ "%s has left channel %s%s\n")
500 prefix chnl comment))))))
502 (defun* liece-handle-silence-message (prefix rest)
503 (let* ((flag (aref rest 0)) (rest (substring rest 1)))
504 (liece-insert-info (append liece-D-buffer liece-O-buffer)
506 (if (eq flag ?-) "unsilenced" "silenced")))))
508 (provide 'liece-handle)
510 ;;; liece-handle.el ends here