? destructuring-irc-message.lisp
? test/package.fasl
? test/test-parse-message.fasl
? test/test-protocol.fasl
RCS file: /project/cl-irc/cvsroot/cl-irc/cl-irc.asd,v
retrieving revision 1.3
diff -u -r1.3 cl-irc.asd
|
|
|
16 | 16 | :version "0.5.2" |
17 | 17 | :licence "MIT" |
18 | 18 | :description "Common Lisp interface to the IRC protocol" |
19 | | :depends-on (:split-sequence :trivial-sockets) |
| 19 | :depends-on (:split-sequence :trivial-sockets :flexi-streams) |
20 | 20 | :properties ((#:author-email . "cl-irc-devel@common-lisp.net") |
21 | 21 | (#:date . "$Date: 2006/01/24 22:10:58 $") |
22 | 22 | ((#:albert #:output-dir) . "doc/api-doc/") |
RCS file: /project/cl-irc/cvsroot/cl-irc/command.lisp,v
retrieving revision 1.16
diff -u -r1.16 command.lisp
|
|
|
250 | 250 | (logging-stream t)) |
251 | 251 | "Connect to server and return a connection object." |
252 | 252 | (let* ((stream (socket-connect server port)) |
| 253 | (input-stream (flexi-streams:make-flexi-stream stream :element-type 'character :external-format '(:latin-1 :eol-style :crlf))) |
253 | 254 | (connection (make-connection :connection-type connection-type |
254 | 255 | :network-stream stream |
| 256 | :input-stream input-stream |
255 | 257 | :client-stream logging-stream |
256 | 258 | :server-name server)) |
257 | 259 | (user (make-user connection |
RCS file: /project/cl-irc/cvsroot/cl-irc/event.lisp,v
retrieving revision 1.24
diff -u -r1.24 event.lisp
RCS file: /project/cl-irc/cvsroot/cl-irc/protocol.lisp,v
retrieving revision 1.39
diff -u -r1.39 protocol.lisp
|
|
|
117 | 117 | (network-stream |
118 | 118 | :initarg :network-stream |
119 | 119 | :accessor network-stream |
120 | | :documentation "Stream used to talk to the IRC server.") |
| 120 | :documentation "Stream used to talk binary to the IRC server.") |
| 121 | (input-stream |
| 122 | :initarg :input-stream |
| 123 | :accessor input-stream |
| 124 | :documentation "Stream used to receive messages from the IRC server.") |
121 | 125 | (server-capabilities |
122 | 126 | :initform *default-isupport-values* |
123 | 127 | :accessor server-capabilities |
… |
… |
|
183 | 187 | (defgeneric re-apply-case-mapping (connection)) |
184 | 188 | |
185 | 189 | (defun make-connection (&key (connection-type 'connection) |
186 | | (user nil) |
187 | | (server-name "") |
188 | | (network-stream nil) |
189 | | (client-stream t) |
190 | | (hooks nil)) |
| 190 | (user nil) |
| 191 | (server-name "") |
| 192 | (network-stream nil) |
| 193 | (output-stream nil) |
| 194 | (input-stream nil) |
| 195 | (client-stream t) |
| 196 | (hooks nil)) |
191 | 197 | (let ((connection (make-instance connection-type |
192 | | :user user |
193 | | :server-name server-name |
194 | | :network-stream network-stream |
195 | | :client-stream client-stream))) |
| 198 | :user user |
| 199 | :server-name server-name |
| 200 | :network-stream network-stream |
| 201 | :input-stream input-stream |
| 202 | :client-stream client-stream))) |
196 | 203 | (dolist (hook hooks) |
197 | 204 | (add-hook connection (car hook) (cadr hook))) |
198 | 205 | connection)) |
… |
… |
|
292 | 299 | (defun read-message-loop (connection) |
293 | 300 | (loop while (read-message connection))) |
294 | 301 | |
| 302 | (defun try-decode-line (line external-formats) |
| 303 | (loop for external-format in external-formats |
| 304 | for decoded = nil |
| 305 | for error = nil |
| 306 | do (multiple-value-setq (decoded error) |
| 307 | (handler-case |
| 308 | (flexi-streams:with-input-from-sequence (in line) |
| 309 | (let ((flexi (flexi-streams:make-flexi-stream in :external-format external-format))) |
| 310 | (read-line flexi))) |
| 311 | (flexi-streams:flexi-stream-encoding-error () |
| 312 | nil))) |
| 313 | if decoded |
| 314 | do (return decoded))) |
| 315 | |
295 | 316 | (defmethod read-irc-message ((connection connection)) |
296 | 317 | "Read and parse an IRC-message from the `connection'." |
297 | 318 | (handler-case |
298 | | (let ((message (create-irc-message |
299 | | (read-line (network-stream connection) t)))) |
300 | | (setf (connection message) connection) |
301 | | message) |
| 319 | (let* ((line (read-line (input-stream connection) t)) |
| 320 | (message (create-irc-message |
| 321 | (concatenate 'string |
| 322 | (try-decode-line (map 'vector #'char-code line) |
| 323 | *default-incoming-external-formats*) |
| 324 | '(#\Return))))) |
| 325 | (setf (connection message) connection) |
| 326 | message) |
302 | 327 | (end-of-file ()))) |
303 | 328 | ;; satisfy read-message-loop assumption of nil when no more messages |
304 | 329 | |
… |
… |
|
306 | 331 | &rest arguments) |
307 | 332 | "Turn the arguments into a valid IRC message and send it to the |
308 | 333 | server, via the `connection'." |
309 | | (let ((raw-message (apply #'make-irc-message command arguments))) |
310 | | (write-sequence raw-message (network-stream connection)) |
311 | | (force-output (network-stream connection)) |
| 334 | (let ((raw-message (apply #'make-irc-message command arguments)) |
| 335 | (output (flexi-streams:make-flexi-stream (network-stream connection) :element-type 'character |
| 336 | :external-format '(:latin-1 :eol-style :crlf)))) |
| 337 | (write-sequence raw-message output) |
| 338 | (force-output output) |
312 | 339 | raw-message)) |
313 | 340 | |
314 | 341 | (defmethod get-hooks ((connection connection) (class symbol)) |
… |
… |
|
370 | 397 | ;; |
371 | 398 | ;; DCC Connection |
372 | 399 | ;; |
373 | | |
| 400 | ;;; big TODO: flexi-streams |
374 | 401 | (defclass dcc-connection () |
375 | 402 | ((user |
376 | 403 | :initarg :user |
RCS file: /project/cl-irc/cvsroot/cl-irc/utility.lisp,v
retrieving revision 1.12
diff -u -r1.12 utility.lisp
|
|
|
54 | 54 | parameters." |
55 | 55 | (let ((*print-circle* nil)) |
56 | 56 | (format nil |
57 | | "~A~{ ~A~}~@[ :~A~]~A~A" |
58 | | command (butlast arguments) (car (last arguments)) |
59 | | #\Return #\Linefeed))) |
| 57 | "~A~{ ~A~}~@[ :~A~]~%" |
| 58 | command (butlast arguments) (car (last arguments))))) |
60 | 59 | |
61 | 60 | (defun make-ctcp-message (string) |
62 | 61 | "Return a valid IRC CTCP message, as a string, composed by |
… |
… |
|
104 | 103 | |
105 | 104 | (defun socket-connect (server port) |
106 | 105 | "Create a socket connected to `server':`port' and return stream for it." |
107 | | (trivial-sockets:open-stream server port)) |
| 106 | (trivial-sockets:open-stream server port :element-type '(unsigned-byte 8))) |
108 | 107 | |
109 | 108 | |
110 | 109 | (defun cut-between (string start-char end-chars &key (start 0) (cut-extra t)) |
111 | | "If `start-char' is not nil, cut string between `start-char' and any |
112 | | of the `end-chars', from `start'. If `start-char' is nil, cut from |
113 | | `start' until any of the `end-chars'. |
| 110 | "If `start-char' is not nil, cut string between `start-char' |
| 111 | and any of the `end-chars', from `start'. If `start-char' is |
| 112 | nil, cut from `start' until any of the `end-chars'. |
114 | 113 | |
115 | 114 | If `cut-extra' is t, we will cut from start + 1 instead of just |
116 | 115 | `start'. |
RCS file: /project/cl-irc/cvsroot/cl-irc/variable.lisp,v
retrieving revision 1.7
diff -u -r1.7 variable.lisp
|
|
|
41 | 41 | ("PREFIX" ,*default-isupport-PREFIX*) |
42 | 42 | ("TARGMAX"))) |
43 | 43 | |
| 44 | (defparameter *default-outgoing-external-format* '(:latin-1 :eol-style :lf) |
| 45 | "The external-format we use to encode outgoing messages. This |
| 46 | should be an external format spec that flexi-streams accepts, |
| 47 | with :eol-style :lf.") |
| 48 | |
| 49 | (defparameter *default-incoming-external-formats* '((:utf-8 :eol-style :lf) |
| 50 | (:latin-1 :eol-style :lf)) |
| 51 | "The external-formats we use to decode incoming messages. This |
| 52 | should be a list of external format spec that flexi-streams accepts, |
| 53 | with :eol-style :lf. |
| 54 | |
| 55 | The external formats are tried in order, until one decodes the |
| 56 | message without encoding errors. Note that the last external |
| 57 | format should be a single-byte one like latin-1.") |
44 | 58 | |
45 | 59 | (defvar *dcc-connections* nil) |
46 | 60 | |