1 ! Copyright (C) 2009 Bruno Deferrari
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors assocs arrays concurrency.mailboxes continuations destructors
4 hashtables io irc.client.base irc.client.chats irc.messages kernel namespaces
5 strings words.symbol irc.messages.base irc.client.participants fry threads
6 combinators irc.messages.parser math ;
7 EXCLUDE: sequences => join ;
8 IN: irc.client.internals
10 : do-connect ( server port quot: ( host port -- stream ) attempts -- stream/f )
12 [ drop call( host port -- stream ) ]
13 [ drop 15 sleep 1- do-connect ]
15 ] [ 2drop 2drop f ] if ;
17 : /NICK ( nick -- ) "NICK " prepend irc-print ;
18 : /PONG ( text -- ) "PONG " prepend irc-print ;
22 "USER " prepend " hostname servername :irc.factor" append irc-print ;
24 : /CONNECT ( server port -- stream )
25 irc> [ connect>> ] [ reconnect-attempts>> ] bi do-connect ;
27 : /JOIN ( channel password -- )
28 [ " :" swap 3append ] when* "JOIN " prepend irc-print ;
30 : try-connect ( -- stream/f )
31 irc> profile>> [ server>> ] [ port>> ] bi /CONNECT ;
33 : (terminate-irc) ( -- )
34 irc> dup is-running>> [
36 [ stream>> dispose ] keep
37 [ in-messages>> ] [ out-messages>> ] bi 2array
38 [ irc-end swap mailbox-put ] each
41 : (connect-irc) ( -- )
43 [ irc> ] dip >>stream t >>is-running
44 in-messages>> [ irc-connected ] dip mailbox-put
45 ] [ (terminate-irc) ] if* ;
47 : (do-login) ( -- ) irc> nick>> /LOGIN ;
49 GENERIC: initialize-chat ( chat -- )
50 M: irc-chat initialize-chat drop ;
51 M: irc-channel-chat initialize-chat [ name>> ] [ password>> ] bi /JOIN ;
53 GENERIC: chat-put ( message obj -- )
54 M: irc-chat chat-put in-messages>> mailbox-put ;
55 M: symbol chat-put chat> [ chat-put ] [ drop ] if* ;
56 M: string chat-put chat> +server-chat+ or chat-put ;
57 M: sequence chat-put [ chat-put ] with each ;
59 : delete-chat ( name -- ) irc> chats>> delete-at ;
60 : unregister-chat ( name -- ) [ irc-chat-end chat-put ] [ delete-chat ] bi ;
62 ! Server message handling
64 GENERIC: message-forwards ( irc-message -- seq )
65 M: irc-message message-forwards drop +server-chat+ ;
66 M: to-one-chat message-forwards chat> ;
67 M: to-all-chats message-forwards drop chats> ;
68 M: to-many-chats message-forwards sender>> participant-chats ;
70 GENERIC: process-message ( irc-message -- )
71 M: object process-message drop ;
72 M: ping process-message trailing>> /PONG ;
73 M: join process-message [ sender>> ] [ chat> ] bi join-participant ;
74 M: part process-message [ sender>> ] [ chat> ] bi part-participant ;
75 M: quit process-message sender>> quit-participant ;
76 M: nick process-message [ trailing>> ] [ sender>> ] bi rename-participant* ;
77 M: rpl-nickname-in-use process-message name>> "_" append /NICK ;
79 M: rpl-welcome process-message
81 swap nickname>> >>nick
83 chats>> values [ initialize-chat ] each ;
85 M: kick process-message
86 [ [ user>> ] [ chat> ] bi part-participant ]
87 [ dup user>> me? [ unregister-chat ] [ drop ] if ]
90 M: participant-mode process-message ( participant-mode -- )
91 [ mode>> ] [ name>> ] [ parameter>> ] tri change-participant-mode ;
93 M: rpl-names process-message
94 [ nicks>> ] [ chat> ] bi dup ?clear-participants
95 '[ _ join-participant ] each ;
97 M: rpl-names-end process-message chat> t >>clear-participants drop ;
99 ! Client message handling
101 GENERIC: handle-outgoing-irc ( irc-message -- ? )
102 M: irc-end handle-outgoing-irc drop f ;
103 M: irc-message handle-outgoing-irc irc-message>string irc-print t ;
107 : handle-reader-message ( irc-message -- ) irc> in-messages>> mailbox-put ;
109 : (handle-disconnect) ( -- )
110 irc-disconnected irc> in-messages>> mailbox-put
111 (connect-irc) (do-login) ;
113 : handle-disconnect ( error -- ? )
114 [ irc> exceptions>> push ] when*
115 irc> is-running>> [ (handle-disconnect) t ] [ f ] if ;
117 GENERIC: handle-input ( line/f -- ? )
118 M: string handle-input string>irc-message handle-reader-message t ;
119 M: f handle-input handle-disconnect ;
121 : (reader-loop) ( -- ? )
122 stream> [ |dispose stream-readln handle-input ] with-destructors ;
124 : reader-loop ( -- ? ) [ (reader-loop) ] [ handle-disconnect ] recover ;
125 : writer-loop ( -- ? ) irc> out-messages>> mailbox-get handle-outgoing-irc ;
129 : in-multiplexer-loop ( -- ? )
130 irc> in-messages>> mailbox-get {
137 : strings>privmsg ( name string -- privmsg )
138 " :" prepend append "PRIVMSG " prepend string>irc-message ;
140 GENERIC: annotate-message ( chat object -- object )
141 M: object annotate-message nip ;
142 M: to-channel annotate-message swap name>> >>channel ;
143 M: to-target annotate-message swap name>> >>target ;
144 M: mode annotate-message swap name>> >>name ;
145 M: string annotate-message [ name>> ] dip strings>privmsg ;
148 [ reader-loop ] "irc-reader-loop" spawn-server
149 [ writer-loop ] "irc-writer-loop" spawn-server
150 [ in-multiplexer-loop ] "in-multiplexer-loop" spawn-server
153 GENERIC: (attach-chat) ( irc-chat -- )
155 M: irc-chat (attach-chat)
157 [ [ chats>> ] [ >>client name>> swap ] 2bi set-at ]
158 [ is-ready>> [ initialize-chat ] [ drop ] if ]
161 M: irc-server-chat (attach-chat)
162 irc> [ (>>client) ] [ chats>> +server-chat+ set-at ] 2bi ;
164 GENERIC: remove-chat ( irc-chat -- )
165 M: irc-nick-chat remove-chat name>> unregister-chat ;
166 M: irc-server-chat remove-chat drop +server-chat+ unregister-chat ;
168 M: irc-channel-chat remove-chat
169 [ part new annotate-message irc-send ]
170 [ name>> unregister-chat ] bi ;
172 : (speak) ( message irc-chat -- ) swap annotate-message irc-send ;