ircguerilla-irc 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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