Initial Commit
[packages] / xemacs-packages / liece / lisp / liece-handle.el
1 ;;; liece-handle.el --- implementation of IRC message handlers
2 ;; Copyright (C) 1998-2000 Daiki Ueno
3
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
5 ;; Created: 1998-09-28
6 ;; Revised: 1998-11-25
7 ;; Keywords: IRC, liece
8
9 ;; This file is part of Liece.
10
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)
14 ;; any later version.
15
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.
20
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.
25
26
27 ;;; Commentary:
28 ;; 
29
30 ;;; Code:
31
32 (eval-when-compile
33   (require 'liece-inlines)
34   (require 'liece-misc)
35   (require 'liece-intl))
36
37 (require 'liece-message)
38 (require 'liece-filter)
39
40 (require 'liece-handler)
41
42 (defmacro liece-handle-prepare-comment (rest &optional quote)
43   `(if (zerop (length ,rest))
44        ""
45      (if ,quote
46          (regexp-quote (format " (%s)" ,rest))
47        (format " (%s)" ,rest))))
48
49 (defmacro liece-handle-message-check-empty (msg)
50   `(string= ,msg ""))
51
52 (defmacro liece-handle-message-check-ignored (prefix rest)
53   `(and ,prefix
54         (liece-ignore-this-p ,prefix liece-user-at-host)
55         (liece-message-from-ignored ,prefix ,rest)))
56
57 (defmacro liece-handle-check-changes-ignored ()
58   'liece-ignore-changes)
59
60 (defconst liece-handle-ctcp-message-regexp "\001\\(.*\\)\001")
61
62 (defmacro liece-handle-ctcp-message-p (msg)
63   `(string-match liece-handle-ctcp-message-regexp ,msg))
64
65 (autoload 'liece-ctcp-message "liece-ctcp")
66 (autoload 'liece-ctcp-notice "liece-ctcp")
67
68 \f
69 (liece-handler-define-backend "generic")
70
71 (mapcar
72  (lambda (message)
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"))
80
81 (defun* liece-handle-nick-message (prefix rest)
82   (let ((chnls (liece-nick-get-joined-channels prefix)))
83     (liece-nick-change prefix rest)
84     (cond
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)
93               rest)
94       (setcar (string-assoc-ignore-case prefix liece-channel-buffer-alist)
95               rest)
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))))
105
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
110         prefix
111         (string-match "as being away" rest)
112         (return-from liece-handle-notice-message))
113
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))
119   (multiple-value-bind (chnl temp) (liece-split-line rest)
120     ;; This is a ctcp reply but contains additional messages
121     ;; at the left or/and right side.
122     (if (liece-handle-ctcp-message-p temp)
123         (setq temp (liece-ctcp-notice prefix temp)))
124     (if (liece-handle-message-check-empty temp)
125         (return-from liece-handle-notice-message))
126
127     ;; Normal message via notice.
128     (setq chnl (liece-channel-virtual chnl))
129     (let ((liece-message-target chnl)
130           (liece-message-speaker prefix)
131           (liece-message-type 'notice))
132       (liece-display-message temp))))
133
134 (defun* liece-handle-privmsg-message (prefix rest)
135   (if (liece-handle-message-check-ignored prefix rest)
136       (return-from liece-handle-privmsg-message))
137   (multiple-value-bind (chnl temp) (liece-split-line rest)
138     (setq temp (or temp ""))
139     ;; This is a ctcp request but contains additional messages
140     ;; at the left or/and right side.
141     (if (liece-handle-ctcp-message-p temp)
142         (setq temp (liece-ctcp-message prefix chnl temp)))
143     (if (liece-handle-message-check-empty temp)
144         (return-from liece-handle-privmsg-message))
145
146     (setq chnl (liece-channel-virtual chnl))
147       
148     (when liece-beep-on-bells
149       (if (string-match "\007" rest)
150           (liece-beep))
151       (if (liece-nick-equal chnl liece-real-nickname)
152           (and liece-beep-when-privmsg (liece-beep))
153         (with-current-buffer (if liece-channel-buffer-mode
154                                  (liece-pick-buffer-1 chnl)
155                                liece-dialogue-buffer)
156           (if liece-beep
157               (liece-beep))))
158       (dolist (word liece-beep-words-list)
159         (if (string-match word rest)
160             (liece-beep))))
161
162     ;; Append timestamp if we are being away.
163     (if (and (string-equal "A" liece-away-indicator)
164              (liece-nick-equal chnl liece-real-nickname))
165         (setq temp
166               (concat temp " ("
167                       (funcall liece-format-time-function (current-time))
168                       ")")))
169
170     ;; Normal message.
171     (let ((liece-message-target chnl)
172           (liece-message-speaker prefix)
173           (liece-message-type 'privmsg))
174       (liece-display-message temp))
175
176     ;; Append to the unread list.
177     (let ((item (if (eq liece-command-buffer-mode 'chat)
178                     liece-current-chat-partner
179                   liece-current-channel)))
180       (unless (liece-channel-equal chnl item)
181         (if (liece-channel-unread-p chnl)
182             (setq liece-channel-unread-list
183                   (delete chnl liece-channel-unread-list)))
184         (setq liece-channel-unread-list
185               (cons chnl liece-channel-unread-list))
186       (run-hook-with-args 'liece-channel-unread-functions chnl)))
187
188     (if (and (liece-nick-equal chnl liece-real-nickname)
189              (not (liece-nick-equal prefix liece-current-chat-partner)))
190         (liece-message (_ "A private message has arrived from %s")
191                        prefix))))
192
193 (defun liece-handle-ping-message (prefix rest)
194   (liece-send "PONG :%s" rest)
195   (liece-command-timestamp-if-interval-expired t)
196   (liece-maybe-poll))
197
198 (defun liece-handle-wall-message (prefix rest)
199   (liece-insert-broadcast (append liece-D-buffer liece-O-buffer)
200                            (concat (if prefix (concat "from " prefix) "") " "
201                                    rest "\n")))
202
203 (defun liece-handle-wallops-message (prefix rest)
204   (if liece-show-wallops
205       (liece-insert-wallops (append liece-D-buffer liece-O-buffer)
206                              (concat (if prefix prefix "UNKNOWN")
207                                      ": " rest "\n")))
208   (liece-insert-wallops liece-W-buffer
209                          (concat (if prefix (concat "from " prefix) "") " "
210                                  rest "\n")))
211
212 (defun* liece-handle-quit-message (prefix rest)
213   (let ((chnls (liece-nick-get-joined-channels prefix)) text match default)
214     ;; Mark temporary apart, if quitting user is one of our chat partners.
215     (when (liece-nick-member prefix liece-current-chat-partners)
216       (add-to-list 'chnls prefix)
217       (liece-nick-mark-as-part t prefix))
218     (if (liece-handle-check-changes-ignored)
219         (return-from liece-handle-quit-message))
220     (cond
221      (liece-compress-changes
222       (setq text (format (_ " \\(has\\|have\\) left IRC%s")
223                          (liece-handle-prepare-comment rest t))
224             match (format "^%s%s.*%s$"
225                           (if liece-display-time
226                               liece-time-prefix-regexp "")
227                           (regexp-quote liece-change-prefix)
228                           (regexp-quote text))
229             default (format (_ "%s%s has left IRC%s\n")
230                             liece-change-prefix prefix
231                             (liece-handle-prepare-comment rest)))
232       (liece-replace (append (liece-pick-buffer chnls)
233                               liece-D-buffer liece-O-buffer)
234                       match default text
235                       (format (_ ", %s have left IRC%s")
236                               prefix (liece-handle-prepare-comment rest))))
237      (t
238       (liece-insert-change (append (liece-pick-buffer chnls)
239                                     liece-D-buffer liece-O-buffer)
240                             (format (_ "%s has left IRC%s\n")
241                                     (liece-handle-prepare-comment rest)))))
242     (liece-nick-change prefix nil)))
243
244 (defun* liece-handle-topic-message (prefix rest)
245   (multiple-value-bind (chnl topic) (liece-split-line rest)
246     (setq chnl (liece-channel-virtual chnl)
247           topic (or topic ""))
248     (liece-channel-set-topic topic chnl)
249     (if (liece-handle-check-changes-ignored)
250         (return-from liece-handle-topic-message))
251     (liece-insert-change (liece-pick-buffer chnl)
252                           (format (_ "New topic on channel %s set by %s: %s\n")
253                                   chnl prefix topic))
254     (liece-insert-change (if (liece-nick-equal chnl liece-current-channel)
255                               liece-D-buffer
256                             (append liece-D-buffer liece-O-buffer))
257                           (format (_ "New topic on channel %s set by %s: %s\n")
258                                   chnl prefix topic))
259     (liece-set-channel-indicator)))
260
261 (defun* liece-handle-mode-message (prefix rest)
262   (if (liece-handle-check-changes-ignored)
263       (return-from liece-handle-mode-message))
264   (let (mflgs margs val chnl mode chnlp)
265     (if (string-match "\\([^ ]*\\) *:?" rest)
266         (progn
267           (setq chnl (match-string 1 rest)
268                 mode (substring rest (match-end 0)))
269           (if (liece-channel-p chnl)
270               (setq chnl (liece-channel-virtual chnl) chnlp t))
271           (if (string-match " *$" mode)
272               (setq mode (substring mode 0 (match-beginning 0)))))
273       (return-from liece-handle-mode-message))
274     ;; parse modes
275     (when (string-match "\\([^ ]*\\) *" mode)
276       (setq mflgs (liece-string-to-list (match-string 1 mode))
277             margs (delete "" (split-string
278                               (substring mode (match-end 0))
279                               "[ ]+")))
280       (while mflgs
281         (cond ((eq ?- (car mflgs)) (setq val nil))
282               ((eq ?+ (car mflgs)) (setq val t))
283               ((and chnlp (eq ?o (car mflgs)))
284                (liece-channel-set-operator chnl (car margs) val)
285                (setq margs (cdr margs)))
286               ((and chnlp (eq ?v (car mflgs)))
287                (liece-channel-set-voice chnl (car margs) val)
288                (setq margs (cdr margs)))
289               ((and chnlp (eq ?b (car mflgs)))
290                (liece-channel-set-ban chnl (car margs) val)
291                (setq margs (cdr margs)))
292               ((and chnlp (eq ?e (car mflgs)))
293                (liece-channel-set-exception chnl (car margs) val)
294                (setq margs (cdr margs)))
295               ((and chnlp (eq ?I (car mflgs)))
296                (liece-channel-set-invite chnl (car margs) val)
297                (setq margs (cdr margs)))
298               (chnlp (liece-channel-set-mode chnl (car mflgs) val))
299               (t (liece-nick-set-mode chnl (car mflgs) val)))
300         (setq mflgs (cdr mflgs))))
301     (liece-set-channel-indicator)
302     (cond
303      (liece-compress-changes
304       (let* ((text (concat (regexp-quote rest) "\n"))
305              (match (format (_ "^%s%sNew mode for %s set by %s: ")
306                             (if liece-display-time
307                                 liece-time-prefix-regexp "")
308                             (regexp-quote liece-change-prefix)
309                             (regexp-quote chnl) (regexp-quote prefix)))
310              (default (format (_ "%sNew mode for %s set by %s: %s\n")
311                               liece-change-prefix chnl prefix mode)))
312         (liece-replace (liece-pick-buffer chnl)
313                         match default text (concat ", " mode "\n"))
314         (liece-replace (if (and liece-current-channel
315                                  (liece-channel-equal
316                                   chnl liece-current-channel))
317                             liece-D-buffer
318                           (append liece-D-buffer liece-O-buffer))
319                         match default text (concat ", " mode "\n"))))
320      (t
321       (liece-insert-change (liece-pick-buffer chnl)
322                             (format (_ "New mode for %s set by %s: %s\n")
323                                     chnl prefix mode))
324       (liece-insert-change (if (and liece-current-channel
325                                      (liece-channel-equal
326                                       chnl liece-current-channel))
327                                 liece-D-buffer
328                               (append liece-D-buffer liece-O-buffer))
329                             (format (_ "New mode for %s set by %s: %s\n")
330                                     chnl prefix mode))))))
331
332 (defun* liece-handle-kick-message (prefix rest)
333   (if (/= 3 (length (setq rest (liece-split-line rest))))
334       (return-from liece-handle-kick-message))
335   (multiple-value-bind (chnl nick message) rest
336     (setq chnl (liece-channel-virtual chnl))
337     
338     (if (liece-nick-equal nick liece-real-nickname)
339         (progn
340           (liece-insert-change
341            (liece-pick-buffer chnl)
342            (format (_ "You were kicked off channel %s by %s (%s).\n")
343                    chnl prefix message))
344           (liece-channel-part chnl))
345       (liece-nick-part nick chnl))
346     
347     (if (liece-handle-check-changes-ignored)
348         (return-from liece-handle-kick-message))
349
350     (liece-insert-change
351      (append (liece-pick-buffer chnl)
352              (if (liece-channel-equal chnl liece-current-channel)
353                  liece-D-buffer
354                (append liece-D-buffer liece-O-buffer)))
355      (format "%s has kicked %s out%s%s\n"
356              prefix nick
357              (if (string= (or liece-current-channel "") chnl)
358                  ""
359                (format " from channel %s" chnl))
360              (if (not message)
361                  ""
362                (format " (%s)" message))))))
363
364 (defun* liece-handle-invite-message (prefix rest)
365   (or (string-match " +:" rest)
366       (return-from liece-handle-invite-message))
367   (and liece-beep-when-invited liece-beep-on-bells
368        (liece-beep))
369   (let ((chnl (liece-channel-virtual (substring rest (match-end 0)))))
370     (liece-insert-info (append liece-D-buffer liece-O-buffer)
371                         (format "%s invites you to channel %s\n"
372                                 prefix chnl))
373     (setq liece-default-channel-candidate chnl)))
374
375 (defun* liece-handle-kill-message (prefix rest)
376   (or (string-match " +:" rest)
377       (return-from liece-handle-kill-message))
378   (let ((path (substring rest (match-end 0))))
379     (liece-insert-info (append liece-D-buffer liece-O-buffer)
380                         (format "You were killed by %s. (Path: %s. RIP)\n"
381                                 prefix path)))
382   (liece-close-server))
383
384 (defun* liece-handle-join-message (prefix rest)
385   (let (flag (xnick prefix) (nick prefix) (chnl rest))
386     (cond
387      ((string-match "\007[ov]" chnl)
388       (setq flag (aref (match-string 0 chnl) 1)
389             chnl (substring rest 0 (match-beginning 0))))
390      ((string-match " +$" chnl)
391       (setq chnl (substring chnl 0 (match-beginning 0)))))
392     (setq chnl (liece-channel-virtual chnl))
393     (liece-nick-set-user-at-host nick liece-user-at-host)
394     (if (liece-nick-equal nick liece-real-nickname)
395         (progn
396           (and liece-gather-channel-modes
397                (not (liece-channel-modeless-p (liece-channel-real chnl)))
398                (liece-send "MODE %s " (liece-channel-real chnl)))
399           (liece-channel-join chnl))
400       (liece-nick-join nick chnl))
401     (cond
402      ((eq flag ?o)
403       (liece-channel-set-operator chnl xnick t)
404       (setq xnick (concat "@" xnick)))
405      ((eq flag ?v)
406       (liece-channel-set-voice chnl xnick t)
407       (setq xnick (concat "+" xnick))))
408     (if (liece-handle-check-changes-ignored)
409         (return-from liece-handle-join-message))
410     ;; Restore the private conversation to its original state.
411     (when (and (liece-nick-member nick liece-current-chat-partners)
412                (get (intern nick liece-obarray) 'part))
413       (liece-insert-change (liece-pick-buffer nick)
414                             (format (_ "%s has come back as (%s)\n")
415                                     nick liece-user-at-host))
416       (liece-nick-mark-as-part nil nick))
417     (cond
418      (liece-compress-changes
419       (let* ((text (format (_ " \\(has\\|have\\) joined channel %s")
420                            (regexp-quote chnl)))
421              (match (format "^%s%s.*%s$"
422                             (if liece-display-time
423                                 liece-time-prefix-regexp "")
424                             (regexp-quote liece-change-prefix)
425                             (regexp-quote text)))
426              (default (format (_ "%s%s (%s) has joined channel %s\n")
427                               liece-change-prefix
428                               nick liece-user-at-host chnl)))
429         (liece-replace (liece-pick-buffer chnl)
430                         match default text
431                         (format (_ ", %s (%s) have joined channel %s")
432                                 nick liece-user-at-host chnl))
433         (liece-replace (if (and liece-current-channel
434                                  (liece-channel-equal chnl
435                                                        liece-current-channel))
436                             liece-D-buffer
437                           (append liece-D-buffer liece-O-buffer))
438                         match default text
439                         (format (_ ", %s (%s) have joined channel %s")
440                                 nick liece-user-at-host chnl))))
441      (t
442       (liece-insert-change (liece-pick-buffer chnl)
443                             (format (_ "%s (%s) has joined channel %s\n")
444                                     nick liece-user-at-host chnl))
445       (liece-insert-change (if (liece-channel-equal chnl
446                                                       liece-current-channel)
447                                 liece-D-buffer
448                               (append liece-D-buffer liece-O-buffer))
449                             (format (_ "%s (%s) has joined channel %s\n")
450                                     nick liece-user-at-host chnl))))))
451
452 (defun* liece-handle-part-message (prefix rest)
453   (multiple-value-bind (chnl comment text match default buf) (liece-split-line rest)
454     (setq chnl (liece-channel-virtual chnl)
455           comment (liece-handle-prepare-comment comment))
456     
457     (if (liece-nick-equal prefix liece-real-nickname)
458         (liece-channel-part chnl)
459       (liece-nick-part prefix chnl))
460     
461     (if (liece-handle-check-changes-ignored)
462         (return-from liece-handle-part-message))
463     
464     (setq buf (append liece-D-buffer (liece-pick-buffer chnl)))
465     (unless (and liece-current-channel
466                  (liece-channel-equal chnl liece-current-channel))
467       (setq buf (append buf liece-O-buffer)))
468     (cond
469      (liece-compress-changes
470       (setq text (format (_ " \\(has\\|have\\) left channel %s%s")
471                          (regexp-quote chnl) (regexp-quote comment))
472             match (format "^%s%s.*%s$"
473                           (if liece-display-time
474                               liece-time-prefix-regexp "")
475                           (regexp-quote liece-change-prefix)
476                           (regexp-quote text))
477             default (format (_ "%s%s has left channel %s%s\n")
478                             liece-change-prefix prefix chnl comment))
479       (liece-replace buf
480                       match default text
481                       (format (_ ", %s have left channel %s%s")
482                               prefix chnl comment)))
483      (t
484       (liece-insert-change buf
485                             (format (_ "%s has left channel %s%s\n")
486                                     prefix chnl comment))))))
487     
488 (defun* liece-handle-silence-message (prefix rest)
489   (let* ((flag (aref rest 0)) (rest (substring rest 1)))
490     (liece-insert-info (append liece-D-buffer liece-O-buffer)
491                         (concat "User " rest
492                                 (if (eq flag ?-) "unsilenced" "silenced")))))
493
494 (provide 'liece-handle)
495
496 ;;; liece-handle.el ends here