Update of /project/beirc/cvsroot/beirc
In directory clnet:/tmp/cvs-serv16258
Modified Files:
application.lisp message-display.lisp presentations.lisp
receivers.lisp
Log Message:
Multi-server support; also, make mode change printing more robust.
There's a bug on /quit that I couldn't figure out; users are advised
to use the terminate-thread restart for now (or help me find the bug
(-:)
Details:
* /connect allows opening more than one connection now.
* (current-connection frame) now returns the current connection of
the currently selected receiver.
* this means that every command operates on the current connection
now.
* (except /quit, which terminates all connections and closes the
window)
--- /project/beirc/cvsroot/beirc/application.lisp 2006/02/23 19:43:29 1.40
+++ /project/beirc/cvsroot/beirc/application.lisp 2006/02/25 15:22:22 1.41
@@ -70,12 +70,11 @@
(define-application-frame beirc (redisplay-frame-mixin
standard-application-frame)
- ((connection :initform nil :reader current-connection)
- (connection-process :initform nil :accessor connection-process)
+ ((connection-processes :initform nil :accessor connection-processes)
(nick :initform nil)
(ignored-nicks :initform nil)
(receivers :initform (make-hash-table :test #'equal) :accessor receivers)
- (server-receiver :initform (make-paneless-receiver "*Server*") :reader server-receiver)
+ (server-receivers :initform nil :reader server-receivers)
(tab-panes-to-receivers :initform (make-hash-table :test #'equal) :accessor tab-panes-to-receivers))
(:panes
(io
@@ -105,7 +104,7 @@
(default
(vertically ()
(with-tab-layout ('receiver-pane :name 'query)
- ("*Server*" server 'receiver-pane))
+ ("*Not Connected*" server 'receiver-pane))
;; (68 io) ;; no drop-shadow prompt
(72 io)
(20 pointer-doc)
@@ -121,6 +120,26 @@
receiver
nil)))
+(defmethod current-connection ((frame beirc))
+ (when (current-receiver frame)
+ (connection (current-receiver frame))))
+
+(defmethod server-receiver ((frame beirc)
+ &optional (connection (current-connection *application-frame*)))
+ (cdr (assoc connection (server-receivers frame) :test #'connection=)))
+
+(defmethod (setf server-receiver) (newval (frame beirc)
+ &optional (connection (current-connection *application-frame*)))
+ (pushnew (cons connection newval) (slot-value frame 'server-receivers)
+ :key #'car :test #'connection=))
+
+(defmethod connection-process ((frame beirc) connection)
+ (cdr (assoc connection (connection-processes frame) :test #'connection=)))
+
+(defmethod (setf connection-process) (newval (frame beirc) connection)
+ (pushnew (cons connection newval) (slot-value frame 'connection-processes)
+ :key #'car :test #'connection=))
+
(defvar *gui-process* nil)
(defvar *beirc-frame*)
@@ -242,9 +261,8 @@
(setf *beirc-frame* frame)
(load-user-init-file)
(run-frame-top-level frame)
- (unless (null (current-connection frame))
- (irc:quit (current-connection frame) "Client Quit"))
- (clim-sys:destroy-process ticker-process))))))))
+ (clim-sys:destroy-process ticker-process)
+ (disconnect-all frame "Client Quit"))))))))
(defun message-directed-to-me-p (frame message)
(irc:destructuring-arguments (&last body) message
@@ -314,7 +332,8 @@
(format nil "IDENTIFY ~A" password)))
(define-beirc-command (com-query :name t) ((nick 'nickname :prompt "who"))
- (raise-receiver (intern-receiver nick *application-frame* :query nick)))
+ (raise-receiver (intern-receiver nick (current-connection *application-frame*)
+ *application-frame* :query nick)))
(define-beirc-command (com-raise :name t) ((receiver 'receiver :prompt "receiver"))
(raise-receiver receiver))
@@ -413,7 +432,7 @@
trailing-argument)
(make-instance message-type
:received-time (get-universal-time)
- :connection :local
+ :connection (current-connection *application-frame*)
:arguments `(,@arguments ,trailing-argument)
:command command
:HOST "localhost"
@@ -467,13 +486,12 @@
(irc:away (current-connection *application-frame*) ""))
(define-beirc-command (com-quit :name t) ((reason 'mumble :prompt "reason"))
- (when (current-connection *application-frame*)
- (disconnect *application-frame* reason))
+ (disconnect-all *application-frame* reason)
(frame-exit *application-frame*))
(define-beirc-command (com-disconnect :name t) ((reason 'mumble :prompt "reason"))
(when (current-connection *application-frame*)
- (disconnect *application-frame* reason)))
+ (disconnect (current-connection *application-frame*) *application-frame* reason)))
(define-beirc-command (com-switch-timestamp-orientation :name t) ()
(setf *timestamp-column-orientation* (if (eql *timestamp-column-orientation* :left)
@@ -505,15 +523,14 @@
(com-msg (target) what))
(define-beirc-command (com-me :name t) ((what 'mumble :prompt nil))
- (with-slots (connection) *application-frame*
- (let ((m (make-fake-irc-message 'irc:ctcp-action-message
+ (let ((m (make-fake-irc-message 'irc:ctcp-action-message
:trailing-argument
(format nil "~AACTION ~A~A" (code-char 1) what (code-char 1))
:arguments (list (target))
:command "PRIVMSG"))) ;###
(post-message *application-frame* m)
- (irc:privmsg connection (target)
- (format nil "~AACTION ~A~A" (code-char 1) what (code-char 1))))))
+ (irc:privmsg (current-connection *application-frame*) (target)
+ (format nil "~AACTION ~A~A" (code-char 1) what (code-char 1)))))
(define-beirc-command (com-nick :name t) ((new-nick 'string :prompt "new nick"))
(setf (slot-value *application-frame* 'nick) new-nick) ;This is _not_ the way to do it.
@@ -697,9 +714,16 @@
(format nil "*!*@~A" (irc:hostname (irc:find-user (current-connection *application-frame*) object))))
(define-beirc-command (com-join :name t) ((channel 'channel :prompt "channel"))
- (raise-receiver (intern-receiver channel *application-frame* :channel channel))
+ (raise-receiver (intern-receiver channel (current-connection *application-frame*)
+ *application-frame* :channel channel))
(irc:join (current-connection *application-frame*) channel))
+(defun connection= (connection1 connection2)
+ ;; TODO: should compare by network, not by server name.
+ ;; TODO: also, there is no port that we could compare.
+ (and (equal (irc:nickname (irc:user connection1)) (irc:nickname (irc:user connection2)))
+ (equal (irc:server-name connection1) (irc:server-name connection2))))
+
(define-beirc-command (com-connect :name t)
((server 'string :prompt "Server")
&key
@@ -707,54 +731,47 @@
(pass 'string :prompt "Password" :default nil)
(port 'number :prompt "Port" :default irc::*default-irc-server-port*))
(let ((success nil))
- (cond ((current-connection *application-frame*)
- (format *query-io* "You are already connected.~%"))
- (t
- (setf (slot-value *application-frame* 'connection)
- (apply #'irc:connect
- :nickname nick :server server :connection-type 'beirc-connection :port port
- (if (null pass)
- nil
- `(:password ,pass))))
- (unwind-protect
- (progn
- (setf (irc:client-stream (current-connection *application-frame*))
- (make-broadcast-stream))
- (setf (slot-value *application-frame* 'nick) nick)
- (let ((connection (current-connection *application-frame*)))
- (let ((frame *application-frame*))
- (loop for receiver being the hash-values of (receivers frame)
- if (channelp (channel receiver))
- do (irc:join connection (channel receiver)))
- (join-missing-channels frame)
- (initialize-receiver-with-pane (server-receiver frame) frame
- (find-pane-named frame 'server)
- :add-pane-p nil)
- (setf (gethash "*Server*" (receivers frame)) (server-receiver frame))
- (setf (connection-process *application-frame*)
- (clim-sys:make-process #'(lambda ()
- (restart-case
- (irc-event-loop frame connection)
- (disconnect ()
- :report "Disconnect from IRC"
- (disconnect frame "Client Disconnect"))))
- :name "IRC Message Muffling Loop"))))
- (setf success t))
- (unless success
- (disconnect *application-frame* "Client error.")))))))
+ (let* ((frame *application-frame*)
+ (connection (apply #'irc:connect
+ :nickname nick :server server :connection-type 'beirc-connection :port port
+ (if (null pass)
+ nil
+ `(:password ,pass))))
+ (server-receiver (intern-receiver (format nil "~A on ~A:~A" nick server port) connection frame)))
+ (unwind-protect
+ (progn
+ (setf (irc:client-stream connection) (make-broadcast-stream))
+ (setf (slot-value *application-frame* 'nick) nick)
+ (when (tab-layout:find-in-tab-panes-list (find-pane-named frame 'server)
+ (find-pane-named frame 'query))
+ (tab-layout:remove-pane (find-pane-named frame 'server)
+ (find-pane-named frame 'query)))
+ (setf (server-receiver frame connection) server-receiver)
+ (setf (connection-process *application-frame* connection)
+ (clim-sys:make-process #'(lambda ()
+ (restart-case
+ (irc-event-loop frame connection)
+ (disconnect ()
+ :report "Terminate this connection"
+ (disconnect connection frame "Client Disconnect"))))
+ :name "IRC Message Muffling Loop"))
+ (setf success t))
+ (unless success
+ (disconnect connection frame "Client error."))))))
-(defun disconnect (frame reason)
+(defun disconnect (connection frame reason)
(raise-receiver (server-receiver frame))
- (irc:quit (current-connection frame) reason)
- (when (and (connection-process frame)
+ (irc:quit connection reason)
+ (when (and (connection-process frame connection)
(not (eql (clim-sys:current-process)
- (connection-process frame))))
- (destroy-process (connection-process frame)))
- (setf (slot-value frame 'connection) nil
- (connection-process frame) nil
+ (connection-process frame connection))))
+ (destroy-process (connection-process frame connection)))
+ (setf (connection-process frame connection) nil
(slot-value frame 'nick) nil))
-
+(defun disconnect-all (frame reason)
+ (loop for (conn . receiver) in (server-receivers frame)
+ do (disconnect (connection receiver) frame reason)))
(defmethod clim:read-frame-command ((frame beirc) &key (stream *standard-input*))
(multiple-value-prog1
@@ -768,7 +785,7 @@
(clim:read-gesture :stream stream)
(clim:accept 'clim:command :stream stream :prompt nil))
(t
- (list 'com-say (accept 'mumble :prompt nil :stream stream))))
+ (list 'com-say (accept 'mumble :history 'mumble :prompt nil :stream stream))))
(setf *last-input-line* nil)))
(command
(let ((buffer (stream-input-buffer stream)))
--- /project/beirc/cvsroot/beirc/message-display.lisp 2006/02/22 16:30:50 1.32
+++ /project/beirc/cvsroot/beirc/message-display.lisp 2006/02/25 15:22:22 1.33
@@ -396,8 +396,8 @@
target mode)))
(defmethod print-mode-change (target op mode (user irc:user))
- (format t "~A~A:" op (mode-symbol-to-char target mode))
- (present (irc:nickname user) 'nickname))
+ (format t "~A~A:" op (mode-symbol-to-char target mode))
+ (present (irc:nickname user) 'nickname))
(defmethod print-mode-change (target op (mode (eql :limit)) arg)
(format t "~A~A" op (mode-symbol-to-char target mode))
@@ -405,12 +405,6 @@
(write-char #\:)
(present arg 'number)))
-(defmethod print-mode-change (target op (mode (eql :key)) arg)
- (format t "~A~A" op (mode-symbol-to-char target mode))
- (when (not (null arg))
- (write-char #\:)
- (present arg 'string)))
-
(macrolet ((define-mode-change-with-hostmask-printer (&rest modes)
`(progn
,@(loop for mode in modes
@@ -419,8 +413,8 @@
(present mask 'hostmask))))))
(define-mode-change-with-hostmask-printer :ban :invite :except))
-(defmethod print-mode-change (target op mode (arg (eql nil)))
- (format t "~A~A" op (mode-symbol-to-char target mode)))
+(defmethod print-mode-change (target op mode arg)
+ (format t "~A~A~:[~;:~A~]" op (mode-symbol-to-char target mode) arg arg))
(defmethod print-message ((message irc:irc-mode-message) receiver)
(case (length (irc:arguments message))
--- /project/beirc/cvsroot/beirc/presentations.lisp 2006/01/27 17:18:04 1.8
+++ /project/beirc/cvsroot/beirc/presentations.lisp 2006/02/25 15:22:22 1.9
@@ -88,7 +88,7 @@
(defun nick-equals-my-nick-p (nickname)
(and (not (null *application-frame*))
- (not (null (slot-value *application-frame* 'connection)))
+ (not (null (current-connection *application-frame*)))
(equal (irc:normalize-nickname (current-connection *application-frame*)
(slot-value *application-frame* 'nick))
(irc:normalize-nickname (current-connection *application-frame*)
--- /project/beirc/cvsroot/beirc/receivers.lisp 2006/02/22 16:30:50 1.16
+++ /project/beirc/cvsroot/beirc/receivers.lisp 2006/02/25 15:22:22 1.17
@@ -6,6 +6,7 @@
(all-unseen-messages :accessor all-unseen-messages :initform 0)
(messages-directed-to-me :accessor messages-directed-to-me :initform 0)
(channel :reader channel :initform nil :initarg :channel)
+ (connection :accessor connection :initarg :connection)
(query :reader query :initform nil :initarg :query) ;; <- XXX: remove this.
(focused-nicks :accessor focused-nicks :initform nil)
(title :reader title :initarg :title)
@@ -59,17 +60,18 @@
(change-space-requirements pane)))
(setf (gethash (tab-pane receiver) (tab-panes-to-receivers frame)) receiver))
-(defun find-receiver (name frame)
- (gethash (irc:normalize-channel-name (slot-value frame 'connection) name)
+(defun find-receiver (name connection frame)
+ (gethash (list connection (irc:normalize-channel-name connection name))
(receivers frame)))
-(defun intern-receiver (name frame &rest initargs)
- (let* ((normalized-name (irc:normalize-channel-name (slot-value frame 'connection) name))
- (rec (find-receiver name frame)))
+(defun intern-receiver (name connection frame &rest initargs)
+ (let* ((normalized-name (irc:normalize-channel-name connection name))
+ (rec (find-receiver name connection frame)))
(if rec
rec
(let ((*application-frame* frame))
- (let ((receiver (apply 'make-paneless-receiver normalized-name initargs)))
+ (let ((receiver (apply 'make-paneless-receiver normalized-name :connection connection
+ initargs)))
(initialize-receiver-with-pane receiver frame
(with-look-and-feel-realization
((frame-manager *application-frame*) *application-frame*)
@@ -80,7 +82,7 @@
:display-time nil
:min-width 600 :min-height 800
:incremental-redisplay t)))
- (setf (gethash normalized-name (receivers frame)) receiver)
+ (setf (gethash (list connection normalized-name) (receivers frame)) receiver)
receiver)))))
(defun remove-receiver (receiver frame)
@@ -115,19 +117,19 @@
`(defmethod receiver-for-message ((message ,message-type) frame)
(let* ((mynick (irc:normalize-nickname (current-connection frame)
(slot-value frame 'nick)))
- (nominal-target (irc:normalize-channel-name (slot-value frame 'connection)
+ (nominal-target (irc:normalize-channel-name (irc:connection message)
(first (irc:arguments message))))
(target (if (equal nominal-target mynick)
(irc:source message)
nominal-target)))
- (cond ((find-receiver target frame)
- (intern-receiver target frame :channel target))
+ (cond ((find-receiver target (irc:connection message) frame)
+ (intern-receiver target (irc:connection message) frame :channel target))
((or (global-notice-p message nominal-target frame)
(and (from-network-service-p (irc:source message) frame)
(equal nominal-target mynick)))
- (server-receiver frame))
+ (server-receiver frame (irc:connection message)))
(t
- (intern-receiver target frame :channel target)))))))
+ (intern-receiver target (irc:connection message) frame :channel target)))))))
(define-privmsg-receiver-lookup irc:irc-privmsg-message)
(define-privmsg-receiver-lookup irc:ctcp-action-message)
(define-privmsg-receiver-lookup irc:irc-notice-message))
@@ -136,7 +138,7 @@
`(defmethod receiver-for-message ((message ,message-type) frame)
(remove nil
(mapcar (lambda (channel)
- (find-receiver (irc:name channel) frame))
+ (find-receiver (irc:name channel) (irc:connection message) frame))
(let ((user (irc:find-user (current-connection frame)
(irc:source message))))
(when user
@@ -160,7 +162,7 @@
(let ((target ,(if (numberp nth)
`(nth ,nth (irc:arguments message))
`(first (last (irc:arguments message))))))
- (intern-receiver target frame :channel target))))))))
+ (intern-receiver target (irc:connection message) frame :channel target))))))))
(define-nth-arg-message-receiver-lookup
(0 irc:irc-topic-message irc:irc-kick-message)
(1 irc:irc-rpl_topic-message irc:irc-rpl_topicwhotime-message
@@ -172,17 +174,17 @@
(defmethod receiver-for-message ((message irc:irc-part-message) frame)
(let ((target (first (irc:arguments message))))
(if (and
- (null (find-receiver target frame))
+ (null (find-receiver target (irc:connection message) frame))
(string= (irc:source message) (slot-value frame 'nick)))
- (server-receiver frame) ; don't re-open previously closed channels.
- (intern-receiver target frame :channel target))))
+ (server-receiver frame (irc:connection message)) ; don't re-open previously closed channels.
+ (intern-receiver target (irc:connection message) frame :channel target))))
(defmethod receiver-for-message ((message irc:irc-mode-message) frame)
(case (length (irc:arguments message))
- (1 (server-receiver frame))
+ (1 (server-receiver frame (irc:connection message)))
(t (destructuring-bind (channel modes &rest args) (irc:arguments message)
(declare (ignore modes args))
- (intern-receiver channel frame :channel channel)))))
+ (intern-receiver channel (irc:connection message) frame :channel channel)))))
(macrolet ((define-current-receiver-message-types (&rest mtypes)
`(progn
@@ -226,7 +228,7 @@
(defmethod receiver-for-message ((message irc:irc-message) frame)
#+or ; comment out to debug on uncaught messages.
(break)
- (server-receiver frame))
+ (server-receiver frame (irc:connection message)))
;; TODO: more receiver-for-message methods.