source: tags/mode_tracking/event.lisp

Last change on this file was 88, checked in by Erik Huelsmann, 19 years ago

Implement MODE tracking.

  • TODO: Remove MODE updating item.
  • doc/user-guide.txt: Add section about modes.
  • package.lisp: Export new symbols.
  • variable.lisp (*default-isupport-CHANMODES*, *default-isupport-PREFIX*): New. (*default-isupport-values*): Add modes described by the RFC and declare them the default (minimal set). (mode-description): New. Structure to describe characteristics of mode arguments sent by the server. (*default-char-to-channel-modes-map*,

*char-to-user-modes-map*): New. Assoc lists to map characters to names.

  • utility.lisp (parse-isupport-prefix-argument): New. Returns the prefix and mode argument parts of the PREFIX RPL_ISUPPORT parameter. (nick-prefixes-from-isupport): New. Returns a plist associating mode prefixes with mode character designations. (chanmode-descs-from-isupport): New. Returns a list of mode-description structures for use with auto-creation of mode objects. (do-property-list): New. Macro to walk a property list like dolist. (parse-mode-arguments): New. Parses mode arguments given a connection object and target and translates those into a list of mode change instructions.
  • protocol.lisp (irc-mode): New. Abstract super class. Derivatives used to store mode values. (set-mode-value, unset-mode-value, reset-mode-value, has-value-p): New. Methods for irc-mode and its derivatives. (single-value-mode, list-value-mode): New. Classes implementing two types of value-holding mode-storage. (connection:channel-mode-descriptions): New. Slot in which the channel mode descriptions for the connection get stored. (connection:nick-prefixes): New. Slot which stores a plist associating RPL_NAMREPLY prefixes with mode characters. (connection:user-mode-descriptions): New. Slot which stores user modes like channel-mode-descriptions does for channels. (add-default-hooks): Add hook for irc-mode-message. (channel:modes): Change initialization to signal the value held will be of LIST type. (mode-name-from-char): New. Translates a mode character into an internal 'name': symbol. (mode-description): New. Retrieves a mode-description record from the given connection of a given mode name. (get-mode, set-mode, unset-mode, remove-mode): New. These provide operations on both channel and user modes. (has-mode-p, has-mode-value-p): New. This must be obvious. (remove-users): Also remove references to all users from any properties which carry the :user value-type. (make-mode): New. Automatically create mode object for the given mode to be added to the given target (user/channel). (user:modes): New. Slot to hold modes just like there is one on the channel class. (remove-user): Same as remove-user, but for the given user only.
  • event.lisp (default-hook [irc-rpl_isupport-message]): Set new channel-mode-descriptions and nick-prefixes slots. (default-hook [irc-rpl_namreply-message]): Set mode fields based on prefixes passed in the reply. (default-hook [irc-mode-message]): Set or unset channel and user modes upon reception of server notification.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.1 KB
Line 
1;;;; $Id: event.lisp 88 2005-03-20 16:55:43Z ehuelsmann $
2;;;; $Source$
3
4;;;; See LICENSE for licensing information.
5
6(in-package :irc)
7
8(defgeneric irc-message-event (message)
9  (:documentation "Upon receipt of an IRC message from the
10connection's stream, irc-message-event will be called with the
11message."))
12
13(defmethod irc-message-event ((message irc-message))
14  (apply-to-hooks message)
15  (client-log (connection message) message "UNHANDLED-EVENT:"))
16
17
18(defgeneric default-hook (message)
19  (:documentation "Minimum action to be executed upon reception
20of the IRC message to keep the connection, channel and user
21objects in sync."))
22
23(defmethod default-hook ((message irc-rpl_isupport-message))
24  (let* ((capabilities (cdr (arguments message)))
25         (connection (connection message))
26         (current-case-mapping (case-map-name connection)))
27    (setf (server-capabilities connection)
28          (let ((new-values (mapcar #'(lambda (x)
29                                        (let ((eq-pos (position #\= x)))
30                                          (if eq-pos
31                                              (list (subseq x 0 eq-pos)
32                                                    (subseq x (1+ eq-pos)))
33                                            (list x)))) capabilities)))
34            (merge 'list new-values (copy-seq *default-isupport-values*)
35                   #'string= :key #'first)))
36    (setf (channel-mode-descriptions connection)
37          (chanmode-descs-from-isupport (server-capabilities connection))
38          (nick-prefixes connection)
39          (nick-prefixes-from-isupport (server-capabilities connection)))
40    (when (not (equal current-case-mapping
41                      (case-map-name connection)))
42      ;; we need to re-normalize nicks and channel names
43      (re-apply-case-mapping connection))))
44
45(defmethod default-hook ((message irc-rpl_whoisuser-message))
46  (let ((user (find-user (connection message)
47                         (second (arguments message))))
48        (realname (trailing-argument message))
49        (username (third (arguments message)))
50        (hostname (fourth (arguments message))))
51    (when user
52      (setf (realname user) realname)
53      (setf (username user) username)
54      (setf (hostname user) hostname))))
55
56(defmethod default-hook ((message irc-rpl_list-message))
57  (let ((connection (connection message))
58        (channel (second (arguments message)))
59        (user-count (parse-integer (or (third (arguments message)) "0")))
60        (topic (trailing-argument message)))
61    (add-channel connection (or (find-channel connection channel)
62                                (make-channel connection
63                                              :name channel
64                                              :topic topic
65                                              :user-count user-count)))))
66
67(defmethod default-hook ((message irc-rpl_topic-message))
68  (setf (topic (find-channel (connection message)
69                             (second (arguments message))))
70        (trailing-argument message)))
71
72(defmethod default-hook ((message irc-rpl_namreply-message))
73  (let* ((connection (connection message))
74         (channel (find-channel connection (car (last (arguments message))))))
75    (dolist (nickname (tokenize-string (trailing-argument message)))
76      (let ((user (find-or-make-user connection
77                                     (canonicalize-nickname connection
78                                                            nickname))))
79        (unless (equal user (user connection))
80          (add-user connection user)
81          (add-user channel user))
82        (let* ((mode-char (getf (nick-prefixes connection)
83                                (elt nickname 0)))
84               (mode-name (when mode-char
85                            (mode-name-from-char connection
86                                                 channel mode-char))))
87          (when mode-name
88            (if (has-mode-p channel mode-name)
89                (set-mode channel mode-name user)
90              (set-mode-value (add-mode channel mode-name
91                                        (make-mode connection
92                                                   channel mode-name))
93                              user))))))))
94
95(defmethod default-hook ((message irc-ping-message))
96  (pong (connection message) (trailing-argument message)))
97
98(defmethod default-hook ((message irc-join-message))
99  (let* ((connection (connection message))
100         (user (find-or-make-user
101                (connection message)
102                (source message)
103                :hostname (host message)
104                :username (user message)))
105         (channel (or (find-channel connection (trailing-argument message))
106                      (make-channel connection
107                                    :name (trailing-argument message)))))
108    (if (self-message-p message)
109        (add-channel connection channel)
110        (progn
111          (add-user connection user)
112          (add-user channel user)))))
113
114(defmethod default-hook ((message irc-topic-message))
115  (setf (topic (find-channel (connection message)
116                             (first (arguments message))))
117        (trailing-argument message)))
118
119(defmethod default-hook ((message irc-part-message))
120  (let* ((connection (connection message))
121         (channel (find-channel connection (first (arguments message))))
122         (user (find-user connection (source message))))
123    (if (self-message-p message)
124        (remove-channel user channel)
125        (remove-user channel user))))
126
127(defmethod default-hook ((message irc-quit-message))
128  (let ((connection (connection message)))
129    (remove-user-everywhere connection (find-user connection (source message)))))
130
131(defmethod default-hook ((message irc-mode-message))
132  (destructuring-bind
133      (target &rest arguments)
134      (arguments message)
135    (let* ((connection (connection message))
136           (target (or (find-channel connection target)
137                       (find-user connection target)))
138           (mode-changes
139            (when target
140              (parse-mode-arguments connection target arguments
141                                     :server-p (user connection)))))
142      (dolist (change mode-changes)
143        (destructuring-bind
144            (op mode-name value)
145            change
146          (unless (has-mode-p target mode-name)
147            (add-mode target mode-name
148                      (make-mode connection target mode-name)))
149          (funcall (if (char= #\+ op) #'set-mode #'unset-mode)
150                   target mode-name value))))))
151
152(defmethod default-hook ((message irc-nick-message))
153  (let ((con (connection message)))
154    (change-nickname con (find-user con (source message))
155                     (trailing-argument message))))
156
157(defmethod default-hook ((message irc-kick-message))
158  (let* ((connection (connection message))
159         (channel (find-channel connection (first (arguments message))))
160         (user (find-user connection (second (arguments message)))))
161    (if (self-message-p message)
162        (remove-channel user channel)
163        (remove-user channel user))))
164
165(defmethod default-hook ((message ctcp-time-message))
166  (multiple-value-bind (second minute hour date month year day) (get-decoded-time)
167    (send-irc-message
168     (connection message)
169     :notice (make-ctcp-message
170              (format nil "TIME ~A"
171                      (make-time-message second minute hour date month year day)))
172     (source message))))
173
174(defmethod default-hook ((message ctcp-source-message))
175  (send-irc-message
176   (connection message)
177   :notice (make-ctcp-message
178            (format nil "SOURCE ~A:~A:~A"
179                    *download-host*
180                    *download-directory*
181                    *download-file*))
182   (source message)))
183
184(defmethod default-hook ((message ctcp-finger-message))
185  (let* ((user (user (connection message)))
186         (finger-info (if (not (zerop (length (realname user))))
187                          (realname user)
188                          (nickname user))))
189    (send-irc-message
190     (connection message)
191     :notice (make-ctcp-message
192              (format nil "FINGER ~A" finger-info))
193     (source message))))
194
195(defmethod default-hook ((message ctcp-version-message))
196  (send-irc-message
197   (connection message)
198   :notice (make-ctcp-message
199            (format nil "VERSION ~A" *ctcp-version*))
200   (source message)))
201
202(defmethod default-hook ((message ctcp-ping-message))
203  (send-irc-message
204   (connection message)
205   :notice (make-ctcp-message
206            (format nil "PING ~A" (trailing-argument message)))
207   (source message)))
208
209(defmethod irc-message-event ((message ctcp-dcc-chat-request-message))
210  (apply-to-hooks message)
211  (client-log (connection message) message))
212;  (when (automatically-accept-dcc-connections (configuration (connection message)))
213;    (let* ((user (find-user (connection message) (source message)))
214;           (args (tokenize-string (trailing-argument message)))
215;           (remote-address (hbo-to-vector-quad (parse-integer (fourth args))))
216;           (remote-port (parse-integer (fifth args) :junk-allowed t)))
217;      (push (make-dcc-connection :user user
218;                                 :remote-address remote-address
219;                                 :remote-port remote-port)
220;            *dcc-connections*))))
221 
222(defmethod irc-message-event ((message ctcp-dcc-send-request-message))
223  (apply-to-hooks message)
224  (client-log (connection message) message))
225;  (when (automatically-accept-dcc-downloads (configuration (connection message)))
226;    (let* ((user (find-user (connection message) (source message)))
227;           (args (tokenize-string (trailing-argument message)))
228;           (filename (third args))
229;           (remote-address (hbo-to-vector-quad (parse-integer (fourth args))))
230;           (remote-port (parse-integer (fifth args)))
231;           (filesize (parse-integer (sixth args) :junk-allowed t)))
232;      (let ((dcc-connection (make-dcc-connection :user user
233;                                                 :remote-address remote-address
234;                                                 :remote-port remote-port)))
235;      (with-open-file (stream filename :direction :output
236;                              :if-exists :supersede)
237;        (write-sequence (read-message-loop dcc-connection) stream))))))
238 
Note: See TracBrowser for help on using the repository browser.