ircguerilla-irc 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/lib/irc/client/client_error.rb +35 -0
  2. data/lib/irc/client/command_handler.rb +113 -0
  3. data/lib/irc/client/connected_state.rb +95 -0
  4. data/lib/irc/client/connection.rb +119 -0
  5. data/lib/irc/client/connection_listener.rb +97 -0
  6. data/lib/irc/client/connection_state.rb +88 -0
  7. data/lib/irc/client/context.rb +250 -0
  8. data/lib/irc/client/disconnected_state.rb +132 -0
  9. data/lib/irc/client/message_handler.rb +87 -0
  10. data/lib/irc/client/registered_state.rb +90 -0
  11. data/lib/irc/client/unregistered_state.rb +113 -0
  12. data/lib/irc/commands/command.rb +57 -0
  13. data/lib/irc/commands/invalid_command.rb +35 -0
  14. data/lib/irc/commands/join_command.rb +122 -0
  15. data/lib/irc/commands/nick_command.rb +86 -0
  16. data/lib/irc/commands/part_command.rb +84 -0
  17. data/lib/irc/commands/password_command.rb +72 -0
  18. data/lib/irc/commands/ping_command.rb +79 -0
  19. data/lib/irc/commands/pong_command.rb +68 -0
  20. data/lib/irc/commands/quit_command.rb +77 -0
  21. data/lib/irc/commands/user_command.rb +105 -0
  22. data/lib/irc/messages/codes.rb +186 -0
  23. data/lib/irc/messages/error_join_message.rb +72 -0
  24. data/lib/irc/messages/error_message.rb +101 -0
  25. data/lib/irc/messages/factory.rb +122 -0
  26. data/lib/irc/messages/invalid_message.rb +35 -0
  27. data/lib/irc/messages/join_message.rb +130 -0
  28. data/lib/irc/messages/message.rb +110 -0
  29. data/lib/irc/messages/nick_message.rb +93 -0
  30. data/lib/irc/messages/notice_message.rb +87 -0
  31. data/lib/irc/messages/part_message.rb +95 -0
  32. data/lib/irc/messages/ping_message.rb +101 -0
  33. data/lib/irc/messages/pong_message.rb +89 -0
  34. data/lib/irc/messages/private_message.rb +121 -0
  35. data/lib/irc/models/bot.rb +159 -0
  36. data/lib/irc/models/channel.rb +158 -0
  37. data/lib/irc/models/network.rb +252 -0
  38. data/lib/irc/models/packet.rb +84 -0
  39. data/lib/irc/models/server.rb +116 -0
  40. data/lib/irc/models/user.rb +112 -0
  41. data/test/functional/irc/client/connection_test.rb +118 -0
  42. data/test/functional/irc/client/context_test.rb +126 -0
  43. data/test/test_helper.rb +32 -0
  44. data/test/unit/irc/client/command_handler_test.rb +137 -0
  45. data/test/unit/irc/commands/join_command_test.rb +72 -0
  46. data/test/unit/irc/commands/nick_command_test.rb +35 -0
  47. data/test/unit/irc/commands/part_command_test.rb +52 -0
  48. data/test/unit/irc/commands/password_command_test.rb +35 -0
  49. data/test/unit/irc/commands/ping_command_test.rb +36 -0
  50. data/test/unit/irc/commands/pong_command_test.rb +36 -0
  51. data/test/unit/irc/commands/quit_command_test.rb +35 -0
  52. data/test/unit/irc/commands/user_command_test.rb +35 -0
  53. data/test/unit/irc/messages/error_join_message_test.rb +45 -0
  54. data/test/unit/irc/messages/factory_test.rb +62 -0
  55. data/test/unit/irc/messages/join_message_test.rb +46 -0
  56. data/test/unit/irc/messages/message_test.rb +56 -0
  57. data/test/unit/irc/messages/nick_message_test.rb +48 -0
  58. data/test/unit/irc/messages/notice_message_test.rb +43 -0
  59. data/test/unit/irc/messages/part_message_test.rb +47 -0
  60. data/test/unit/irc/messages/ping_message_test.rb +57 -0
  61. data/test/unit/irc/messages/pong_message_test.rb +57 -0
  62. data/test/unit/irc/messages/private_message_test.rb +42 -0
  63. data/test/unit/irc/models/bot_test.rb +85 -0
  64. data/test/unit/irc/models/channel_test.rb +90 -0
  65. data/test/unit/irc/models/network_test.rb +210 -0
  66. data/test/unit/irc/models/packet_test.rb +38 -0
  67. data/test/unit/irc/models/server_test.rb +54 -0
  68. data/test/unit/irc/models/user_test.rb +67 -0
  69. metadata +111 -0
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2006 Roman Scherer | IRC Guerilla | Rapid Packet Movement
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ #
24
+ # $Id: connection_state.rb 89 2006-08-13 14:03:35Z roman $
25
+ #
26
+ require 'irc/client/connection_listener'
27
+ require 'singleton'
28
+
29
+ module IRC
30
+
31
+ module Client
32
+
33
+ class ConnectionState
34
+
35
+ include ConnectionListener
36
+ include ::Singleton
37
+
38
+ # Connects to the server.
39
+ def connect(context, server)
40
+ end
41
+
42
+ # Disconnects from the currently connected server.
43
+ def disconnect(context, message = nil)
44
+ end
45
+
46
+ # Joins the given channels.
47
+ def join(context, channels)
48
+ end
49
+
50
+ # Leaves the given channels.
51
+ def part(context, channels)
52
+ end
53
+
54
+ # Sends a private message to the target (a nick or a channel).
55
+ def private_message(context, target, message)
56
+ end
57
+
58
+ # Sends the command to the server bypassing the command queue.
59
+ def send_command(context, command)
60
+ end
61
+
62
+ # Sends the command to the server using the command queue.
63
+ def send_command_via_queue(context, command)
64
+ end
65
+
66
+ # ConnectionListener
67
+
68
+ # This method gets called when a ping message was received from the server.
69
+ def on_ping(connection, servers)
70
+ IRC::Commands::PongCommand.new(servers[0], servers[1]).send(connection)
71
+ end
72
+
73
+ protected
74
+
75
+ # This method changes the state of the connection context to the next state.
76
+ def change_state(context, next_state)
77
+ context.change_state(next_state)
78
+ end
79
+
80
+ def network_name(context)
81
+ return "[#{context.network.to_s.upcase}]"
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2006 Roman Scherer | IRC Guerilla | Rapid Packet Movement
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ #
24
+ # $Id: context.rb 92 2006-08-13 17:54:26Z roman $
25
+ #
26
+ require 'delegate'
27
+ require 'irc/client/command_handler'
28
+ require 'irc/client/context'
29
+ require 'irc/client/connection_listener'
30
+ require 'irc/client/disconnected_state'
31
+ require 'irc/client/message_handler'
32
+ require 'log4r'
33
+
34
+ module IRC
35
+
36
+ module Client
37
+
38
+ class Connection
39
+
40
+ class Context < DelegateClass(IRC::Client::ConnectionListener)
41
+
42
+ # READER
43
+
44
+ # The command handler that is responsible for sending commands to the IRC server.
45
+ attr_reader :command_handler
46
+
47
+ # The connection listeners that get notified when a message was received by the IRC server.
48
+ attr_reader :connection_listeners
49
+
50
+ # The login name that is used when connected to an IRC server.
51
+ attr_reader :login
52
+
53
+ # The nick name that is used when connected to an IRC server.
54
+ attr_reader :nick
55
+
56
+ # The real name that is used when connected to an IRC server.
57
+ attr_reader :realname
58
+
59
+ # The context's current state. The initial state is disconnected.
60
+ attr_reader :state
61
+
62
+ # ACCESSOR
63
+
64
+ # The network to which the context is connected., or nil if no connection has been established.
65
+ attr_accessor :network
66
+
67
+ # The IRC server the context is connected to, or nil if no connection has been established.
68
+ attr_accessor :server
69
+
70
+ # The TCPSocket the context uses to talk to the IRC server.
71
+ attr_accessor :socket
72
+
73
+
74
+ def initialize(nick = nil, login = nil, realname = nil)
75
+
76
+ # Initialize logging framework.
77
+ @log = Log4r::Logger.new('IRC::Client::Connection::Context')
78
+
79
+ # Initialize nick, login & realname. If a value is missing it
80
+ # is taken from the environemnt settings.
81
+ @nick = nick || ENV['USER'] || ENV['USERNAME'] || "i-AM-TOO-LAME"
82
+ @login = login || ENV['USER'] || ENV['USERNAME'] || nick
83
+ @realname = realname || ENV['USER'] || ENV['USERNAME'] || nick
84
+
85
+ # A hash to keep track of currently joined channels.
86
+ @joined_channels = Hash.new
87
+
88
+ # All connection listeners will get notified when a message was received from the IRC server.
89
+ @connection_listeners = Array.new
90
+
91
+ # Add the context as a connection listener. The context doesn't handle messages from the server
92
+ # directly. Instead method calls to the ConnectionListner module get forwarded to the current
93
+ # state object. When the context changes it's state the delegation object is allso changed to
94
+ # the new state.
95
+ add_connection_listener(self)
96
+
97
+ # Change into the disconnected state.
98
+ change_state(DisconnectedState.instance)
99
+
100
+ end
101
+
102
+ # Adds a new connection listener. The connection listener gets notified when a
103
+ # message was received from the IRC server.
104
+ def add_connection_listener(connection_listener)
105
+ connection_listeners << connection_listener unless connection_listeners.include?(connection_listener)
106
+ end
107
+
108
+ # Sends the command to the server using the command queue.
109
+ def <<(command)
110
+ send_command_via_queue(command)
111
+ end
112
+
113
+ # Changes the context's state to the next state,
114
+ def change_state(next_state)
115
+
116
+ # Log the state change.
117
+ if state == nil
118
+ @log.debug("Setting initial state to #{next_state.class.name}.")
119
+ else
120
+ @log.debug("Changing state from #{state.class.name} to #{next_state.class.name}.")
121
+ end
122
+
123
+ # Change the context's state.
124
+ @state = next_state
125
+
126
+ # The context doesn't handle messages from the server directly. Method calls to the
127
+ # ConnectionListener module get forwarded to the current state object.
128
+ __setobj__(@state)
129
+
130
+ end
131
+
132
+ # Connects to the server.
133
+ def connect(server)
134
+ @network = server.network
135
+ state.connect(self, server)
136
+ end
137
+
138
+ # Returns true if a connection to an IRC server has been established.
139
+ def connected?
140
+ state.kind_of?(ConnectedState)
141
+ end
142
+
143
+ # Disconnects from the currently connected server.
144
+ def disconnect(message = nil)
145
+ state.disconnect(self, message)
146
+ end
147
+
148
+ # Joins the given channels.
149
+ def join(channels)
150
+ state.join(self, channels)
151
+ end
152
+
153
+ # Returns true, if the given channel is currently joined.
154
+ def joined?(channel)
155
+ return @joined_channels.include?(channel)
156
+ end
157
+
158
+ # Add the channel to the list of joined channels.
159
+ def join_succeeded(channel)
160
+ @joined_channels[channel] = channel
161
+ end
162
+
163
+ # Remove the channel from the list of joined channels.
164
+ def part_succeeded(channel)
165
+ @joined_channels.delete(channel)
166
+ end
167
+
168
+ # Returns an Array of all currently joined channels.
169
+ def joined_channels
170
+ return @joined_channels.values
171
+ end
172
+
173
+ # Lookup or create a channel object.
174
+ def lookup_channel(channel)
175
+ return network.lookup_or_create_channel(channel)
176
+ end
177
+
178
+ # Lookup or create a server object.
179
+ def lookup_server(server)
180
+ return network.lookup_or_create_server(server)
181
+ end
182
+
183
+ # Lookup or create a user object.
184
+ def lookup_user(user)
185
+ return network.lookup_or_create_user(user)
186
+ end
187
+
188
+ # The network to which the context is connected, or nil if no connection has been established.
189
+ def network
190
+ return @network
191
+ end
192
+
193
+ # Leaves the given channels.
194
+ def part(channels)
195
+ state.part(self, channels)
196
+ end
197
+
198
+ # Returns true if a connection to an IRC server has been established and the connection
199
+ # has been successfully registered.
200
+ def registered?
201
+ state.kind_of?(RegisteredState)
202
+ end
203
+
204
+ # Removes a previously added connection listener. The connection listener will not
205
+ # get notified any longer when a message was received from the IRC server.
206
+ def remove_connection_listener(connection_listener)
207
+ connection_listeners.delete(connection_listener)
208
+ end
209
+
210
+ # Sends the command to the server bypassing the command queue.
211
+ def send_command(command)
212
+ state.send_command(self, command)
213
+ end
214
+
215
+ # Sends the command to the server using the command queue.
216
+ def send_command_via_queue(command)
217
+ state.send_command_via_queue(self, command)
218
+ end
219
+
220
+ # Initializes and starts the command handler.
221
+ def start_command_handler
222
+ @command_handler = CommandHandler.new(self)
223
+ @command_handler.start
224
+ end
225
+
226
+ # Initializes and starts the message handler.
227
+ def start_message_handler
228
+ @message_handler = MessageHandler.new(self)
229
+ @message_handler.start
230
+ end
231
+
232
+ # Stops the command handler.
233
+ def stop_command_handler
234
+ @command_handler.stop
235
+ @command_handler = nil
236
+ end
237
+
238
+ # Stops the message handler.
239
+ def stop_message_handler
240
+ @message_handler.stop
241
+ @message_handler = nil
242
+ end
243
+
244
+ end
245
+
246
+ end
247
+
248
+ end
249
+
250
+ end
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2006 Roman Scherer | IRC Guerilla | Rapid Packet Movement
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ #
24
+ # $Id: disconnected_state.rb 89 2006-08-13 14:03:35Z roman $
25
+ #
26
+ require 'irc/client/client_error'
27
+ require 'irc/client/connection'
28
+ require 'irc/client/connection_state'
29
+ require 'irc/client/unregistered_state'
30
+ require 'irc/commands/nick_command'
31
+ require 'irc/commands/password_command'
32
+ require 'irc/commands/user_command'
33
+ require 'irc/models/server'
34
+ require 'log4r'
35
+ require 'socket'
36
+ require 'timeout'
37
+
38
+
39
+ module IRC
40
+
41
+ module Client
42
+
43
+ class DisconnectedState < ConnectionState
44
+
45
+ def initialize
46
+ @log = Log4r::Logger.new('IRC::Client::DisconnectedState')
47
+ end
48
+
49
+ # Connects to the server.
50
+ def connect(context, server)
51
+
52
+ @log.debug("#{network_name(context)} Trying to connect to server #{server.hostname} on port #{server.port}.")
53
+
54
+ # Establish the connection to the server.
55
+ context.socket = establish_connection(server)
56
+
57
+ # Set the server to which we are connected.
58
+ context.server = server
59
+
60
+ # Initialize and start the command & message handlers.
61
+ context.start_command_handler
62
+ context.start_message_handler
63
+
64
+ # Change to the unregistered state.
65
+ change_state(context, UnregisteredState.instance)
66
+
67
+ # Send the connection registration commands.
68
+ if server.password
69
+ context.send_command_via_queue(IRC::Commands::PasswordCommand.new(server.password))
70
+ end
71
+
72
+ context.send_command_via_queue(IRC::Commands::NickCommand.new(context.nick))
73
+ context.send_command_via_queue(IRC::Commands::UserCommand.new(context.nick, Socket.gethostname, server.hostname, context.realname))
74
+
75
+ # rescue Exception => e
76
+ # raise ClientError.new("Can't connect to server #{server.hostname} on port #{server.port}. #{e.message.capitalize}.")
77
+
78
+ end
79
+
80
+ # Disconnects from the currently connected server.
81
+ def disconnect(context, message = nil)
82
+ raise ClientError.new("Can't disconnect. Not connected to a server.")
83
+ end
84
+
85
+ # Joins the given channels.
86
+ def join(context, channels)
87
+ raise ClientError.new("Can't join any channel. Not connected to a server.")
88
+ end
89
+
90
+ # Leaves the given channels.
91
+ def part(context, channels)
92
+ raise ClientError.new("Can't leave any channel. Not connected to a server.")
93
+ end
94
+
95
+ # Sends a private message to the target (a nick or a channel).
96
+ def private_message(context, target, message)
97
+ raise ClientError.new("Can't send a private message. Not connected to a server.")
98
+ end
99
+
100
+ # Sends the command to the server bypassing the command queue.
101
+ def send_command(context, command)
102
+ raise ClientError.new("Can't send command. Not connected to a server.")
103
+ end
104
+
105
+ # Sends the command to the server using the command queue.
106
+ def send_command_via_queue(context, command)
107
+ raise ClientError.new("Can't send command. Not connected to a server.")
108
+ end
109
+
110
+ # ConnectionListener
111
+
112
+ # This method gets called when successfully connected to a server.
113
+ def on_connect(connection, server)
114
+ log.debug("#{network_name(connection)} Successfully connected to #{server} on port #{server.respond_to?(port) ? server.port.to_s : IRC::Models::Server::DEFAULT_PORT}.")
115
+ end
116
+
117
+ private
118
+
119
+ def establish_connection(server)
120
+
121
+ # Try to connect to the server before the timeout exceeds.
122
+ Timeout::timeout(Connection::MAX_CONNECTION_TIMEOUT_IN_SEC) do
123
+ return TCPSocket.open(server.hostname, server.port)
124
+ end
125
+
126
+ end
127
+
128
+ end
129
+
130
+ end
131
+
132
+ end