failirc 0.0.1
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.
- data/bin/failbot +162 -0
- data/bin/failircd +61 -0
- data/lib/failirc.rb +25 -0
- data/lib/failirc/client.rb +227 -0
- data/lib/failirc/client/channel.rb +98 -0
- data/lib/failirc/client/channels.rb +85 -0
- data/lib/failirc/client/client.rb +59 -0
- data/lib/failirc/client/clients.rb +43 -0
- data/lib/failirc/client/dispatcher.rb +209 -0
- data/lib/failirc/client/dispatcher/connectiondispatcher.rb +410 -0
- data/lib/failirc/client/dispatcher/event.rb +113 -0
- data/lib/failirc/client/dispatcher/eventdispatcher.rb +203 -0
- data/lib/failirc/client/module.rb +103 -0
- data/lib/failirc/client/modules/Base.rb +361 -0
- data/lib/failirc/client/modules/Logger.rb +89 -0
- data/lib/failirc/client/server.rb +89 -0
- data/lib/failirc/client/user.rb +66 -0
- data/lib/failirc/client/users.rb +100 -0
- data/lib/failirc/errors.rb +339 -0
- data/lib/failirc/extensions.rb +124 -0
- data/lib/failirc/mask.rb +117 -0
- data/lib/failirc/modes.rb +54 -0
- data/lib/failirc/responses.rb +360 -0
- data/lib/failirc/server.rb +266 -0
- data/lib/failirc/server/channel.rb +122 -0
- data/lib/failirc/server/channels.rb +84 -0
- data/lib/failirc/server/client.rb +100 -0
- data/lib/failirc/server/clients.rb +54 -0
- data/lib/failirc/server/dispatcher.rb +219 -0
- data/lib/failirc/server/dispatcher/connectiondispatcher.rb +477 -0
- data/lib/failirc/server/dispatcher/event.rb +113 -0
- data/lib/failirc/server/dispatcher/eventdispatcher.rb +196 -0
- data/lib/failirc/server/link.rb +50 -0
- data/lib/failirc/server/links.rb +49 -0
- data/lib/failirc/server/module.rb +103 -0
- data/lib/failirc/server/modules/Base.rb +2545 -0
- data/lib/failirc/server/modules/Cloaking.rb +170 -0
- data/lib/failirc/server/modules/Firewall.rb +104 -0
- data/lib/failirc/server/modules/Netlog.rb +67 -0
- data/lib/failirc/server/modules/Roulette.rb +78 -0
- data/lib/failirc/server/modules/TinyURL.rb +98 -0
- data/lib/failirc/server/modules/Translate.rb +62 -0
- data/lib/failirc/server/modules/WordFilter.rb +144 -0
- data/lib/failirc/server/user.rb +72 -0
- data/lib/failirc/server/users.rb +103 -0
- data/lib/failirc/sslutils.rb +74 -0
- data/lib/failirc/utils.rb +53 -0
- metadata +107 -0
@@ -0,0 +1,266 @@
|
|
1
|
+
# failirc, a fail IRC library.
|
2
|
+
#
|
3
|
+
# Copyleft meh. [http://meh.doesntexist.org | meh.ffff@gmail.com]
|
4
|
+
#
|
5
|
+
# This file is part of failirc.
|
6
|
+
#
|
7
|
+
# failirc is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Affero General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# failirc is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with failirc. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require 'resolv'
|
21
|
+
|
22
|
+
require 'rexml/document'
|
23
|
+
include REXML
|
24
|
+
|
25
|
+
require 'failirc'
|
26
|
+
require 'failirc/utils'
|
27
|
+
|
28
|
+
require 'failirc/server/clients'
|
29
|
+
require 'failirc/server/links'
|
30
|
+
require 'failirc/server/channels'
|
31
|
+
require 'failirc/server/dispatcher'
|
32
|
+
|
33
|
+
module IRC
|
34
|
+
|
35
|
+
class Server
|
36
|
+
attr_reader :version, :createdOn, :verbose, :dispatcher, :modules, :channels, :connections, :config, :data
|
37
|
+
|
38
|
+
def initialize (conf, verbose)
|
39
|
+
@version = IRC::VERSION
|
40
|
+
@createdOn = Time.now
|
41
|
+
@verbose = verbose ? true : false
|
42
|
+
|
43
|
+
@dispatcher = Dispatcher.new(self)
|
44
|
+
|
45
|
+
@modules = {}
|
46
|
+
|
47
|
+
@data = ThreadSafeHash.new
|
48
|
+
|
49
|
+
@channels = Channels.new(self)
|
50
|
+
|
51
|
+
self.config = conf
|
52
|
+
end
|
53
|
+
|
54
|
+
def clients
|
55
|
+
dispatcher.connection.clients
|
56
|
+
end
|
57
|
+
|
58
|
+
def links
|
59
|
+
dispatcher.connection.links
|
60
|
+
end
|
61
|
+
|
62
|
+
def comments
|
63
|
+
result = ''
|
64
|
+
|
65
|
+
modules.each_value {|mod|
|
66
|
+
begin
|
67
|
+
result << " #{mod.description}"
|
68
|
+
rescue
|
69
|
+
end
|
70
|
+
}
|
71
|
+
|
72
|
+
return result[1, result.length]
|
73
|
+
end
|
74
|
+
|
75
|
+
def host
|
76
|
+
@config.elements['config/server/host'].text
|
77
|
+
end
|
78
|
+
|
79
|
+
def ip
|
80
|
+
begin
|
81
|
+
return Resolv.getaddress(@config.elements['config/server/host'].text)
|
82
|
+
rescue
|
83
|
+
return Resolv.getaddress('localhost')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def name
|
88
|
+
@config.elements['config/server/name'].text
|
89
|
+
end
|
90
|
+
|
91
|
+
def loadModule (name, path=nil, reload=false)
|
92
|
+
if @modules[name] && !reload
|
93
|
+
return
|
94
|
+
end
|
95
|
+
|
96
|
+
begin
|
97
|
+
if path[0] == '/'
|
98
|
+
$LOAD_PATH.push path
|
99
|
+
require name
|
100
|
+
$LOAD_PATH.pop
|
101
|
+
else
|
102
|
+
require "#{path}/#{name}"
|
103
|
+
end
|
104
|
+
|
105
|
+
klass = eval("Modules::#{name}") rescue nil
|
106
|
+
|
107
|
+
if klass
|
108
|
+
@modules[name] = klass.new(self)
|
109
|
+
self.debug "Loaded `#{name}`."
|
110
|
+
else
|
111
|
+
raise Exception
|
112
|
+
end
|
113
|
+
rescue Exception => e
|
114
|
+
self.debug "Failed to load `#{name}`."
|
115
|
+
self.debug e
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def start
|
120
|
+
if @started
|
121
|
+
return
|
122
|
+
end
|
123
|
+
|
124
|
+
if !@config
|
125
|
+
raise 'config is missing.'
|
126
|
+
end
|
127
|
+
|
128
|
+
@started = true
|
129
|
+
|
130
|
+
@config.elements.each('config/server/listen') {|listen|
|
131
|
+
self.listen({
|
132
|
+
:bind => listen.attributes['bind'],
|
133
|
+
:port => listen.attributes['port'],
|
134
|
+
|
135
|
+
:ssl => listen.attributes['ssl'],
|
136
|
+
:ssl_cert => listen.attributes['sslCert'],
|
137
|
+
:ssl_key => listen.attributes['sslKey']
|
138
|
+
}, listen)
|
139
|
+
}
|
140
|
+
|
141
|
+
@dispatcher.start
|
142
|
+
end
|
143
|
+
|
144
|
+
def stop
|
145
|
+
@stopping = true
|
146
|
+
|
147
|
+
begin
|
148
|
+
dispatcher.stop
|
149
|
+
|
150
|
+
@modules.each {|mod|
|
151
|
+
mod.finalize
|
152
|
+
}
|
153
|
+
rescue
|
154
|
+
end
|
155
|
+
|
156
|
+
@stopping = false
|
157
|
+
@started = false
|
158
|
+
end
|
159
|
+
|
160
|
+
def stopping?
|
161
|
+
@stopping
|
162
|
+
end
|
163
|
+
|
164
|
+
def listen (*args)
|
165
|
+
@dispatcher.connection.listen(*args)
|
166
|
+
end
|
167
|
+
|
168
|
+
# kill connection with harpoons on fire
|
169
|
+
def kill (thing, message=nil, force=false)
|
170
|
+
if !thing || (thing.modes[:killing] && (!force || thing.modes[:kill_forcing])) || !@dispatcher.connections.exists?(thing.socket)
|
171
|
+
return
|
172
|
+
end
|
173
|
+
|
174
|
+
if thing.is_a?(User)
|
175
|
+
thing = thing.client
|
176
|
+
end
|
177
|
+
|
178
|
+
thing.modes[:killing] = true
|
179
|
+
|
180
|
+
if force
|
181
|
+
thing.modes[:kill_forcing] = true
|
182
|
+
|
183
|
+
tmp = @dispatcher.output[thing].drop_while {|item|
|
184
|
+
item != :EOC
|
185
|
+
}
|
186
|
+
|
187
|
+
@dispatcher.output[thing].clear
|
188
|
+
@dispatcher.output[thing].insert(-1, *tmp)
|
189
|
+
end
|
190
|
+
|
191
|
+
@dispatcher.output.push(thing, :EOC)
|
192
|
+
@dispatcher.output.push(thing, message)
|
193
|
+
end
|
194
|
+
|
195
|
+
# reload the config and modules' configurations
|
196
|
+
def rehash
|
197
|
+
self.config = @configReference
|
198
|
+
end
|
199
|
+
|
200
|
+
def config= (reference)
|
201
|
+
@config = Document.new reference
|
202
|
+
@configReference = reference
|
203
|
+
|
204
|
+
if !@config.elements['config/server']
|
205
|
+
@config.elements['config'].add(Element.new('server'))
|
206
|
+
end
|
207
|
+
|
208
|
+
if !@config.elements['config/server/name']
|
209
|
+
@config.elements['config/server'].add(Element.new('name')).text = 'Fail IRC'
|
210
|
+
end
|
211
|
+
|
212
|
+
if !@config.elements['config/server/host']
|
213
|
+
@config.elements['config/server'].add(Element.new('host')).text = Socket.gethostname
|
214
|
+
end
|
215
|
+
|
216
|
+
if !@config.elements['config/server/pingTimeout']
|
217
|
+
@config.elements['config/server'].add(Element.new('pingTimeout')).text = '60'
|
218
|
+
end
|
219
|
+
|
220
|
+
if !@config.elements['config/server/listen']
|
221
|
+
@config.elements['config/server'].add(Element.new('listen'))
|
222
|
+
end
|
223
|
+
|
224
|
+
@config.elements.each('config/server/listen') {|element|
|
225
|
+
if !element.attributes['port']
|
226
|
+
element.attributes['port'] = '6667'
|
227
|
+
end
|
228
|
+
|
229
|
+
if !element.attributes['bind']
|
230
|
+
element.attributes['bind'] = '0.0.0.0'
|
231
|
+
end
|
232
|
+
|
233
|
+
if !element.attributes['ssl'] || (element.attributes['ssl'] != 'enabled' && element.attributes['ssl'] != 'disabled' && element.attributes['ssl'] != 'promiscuous')
|
234
|
+
element.attributes['ssl'] = 'disabled'
|
235
|
+
end
|
236
|
+
|
237
|
+
if element.attributes['password'] && element.attributes['password'].match(/:/)
|
238
|
+
raise 'Password CANNOT contain :'
|
239
|
+
end
|
240
|
+
}
|
241
|
+
|
242
|
+
if !@config.elements['config/modules']
|
243
|
+
@config.elements['config'].add(Element.new('modules'))
|
244
|
+
end
|
245
|
+
|
246
|
+
@modules.each_value {|mod|
|
247
|
+
mod.rehash
|
248
|
+
}
|
249
|
+
|
250
|
+
self.debug 'Loading modules.'
|
251
|
+
|
252
|
+
@config.elements.each('config/modules/module') {|element|
|
253
|
+
if !element.attributes['path']
|
254
|
+
element.attributes['path'] = 'failirc/server/modules'
|
255
|
+
end
|
256
|
+
|
257
|
+
self.loadModule element.attributes['name'], element.attributes['path']
|
258
|
+
}
|
259
|
+
|
260
|
+
self.debug 'Finished loading modules.', "\n"
|
261
|
+
end
|
262
|
+
|
263
|
+
alias to_s host
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# failirc, a fail IRC library.
|
2
|
+
#
|
3
|
+
# Copyleft meh. [http://meh.doesntexist.org | meh.ffff@gmail.com]
|
4
|
+
#
|
5
|
+
# This file is part of failirc.
|
6
|
+
#
|
7
|
+
# failirc is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Affero General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# failirc is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with failirc. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require 'failirc/utils'
|
21
|
+
require 'failirc/modes'
|
22
|
+
|
23
|
+
require 'failirc/server/users'
|
24
|
+
|
25
|
+
module IRC
|
26
|
+
|
27
|
+
class Server
|
28
|
+
|
29
|
+
class Channel
|
30
|
+
class Topic
|
31
|
+
attr_reader :server, :channel, :text, :setBy
|
32
|
+
attr_accessor :setOn
|
33
|
+
|
34
|
+
def initialize (channel)
|
35
|
+
@server = channel.server
|
36
|
+
@channel = channel
|
37
|
+
|
38
|
+
@semaphore = Mutex.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def text= (value)
|
42
|
+
@semaphore.synchronize {
|
43
|
+
@text = value
|
44
|
+
@setOn = Time.now
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def setBy= (value)
|
49
|
+
@setBy = value.mask.clone
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
text
|
54
|
+
end
|
55
|
+
|
56
|
+
def nil?
|
57
|
+
text.nil?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
attr_reader :server, :name, :type, :createdOn, :users, :modes, :topic
|
62
|
+
|
63
|
+
def initialize (server, name)
|
64
|
+
@server = server
|
65
|
+
@name = name
|
66
|
+
@type = name[0, 1]
|
67
|
+
|
68
|
+
@createdOn = Time.now
|
69
|
+
@users = Users.new(self)
|
70
|
+
@modes = Modes.new
|
71
|
+
@topic = Topic.new(self)
|
72
|
+
|
73
|
+
@semaphore = Mutex.new
|
74
|
+
end
|
75
|
+
|
76
|
+
def type
|
77
|
+
@name[0, 1]
|
78
|
+
end
|
79
|
+
|
80
|
+
def topic= (data)
|
81
|
+
@semaphore.synchronize {
|
82
|
+
if data.is_a?(Topic)
|
83
|
+
@topic = data
|
84
|
+
elsif data.is_a?(Array)
|
85
|
+
@topic.setBy = data[0]
|
86
|
+
@topic.text = data[1]
|
87
|
+
end
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def [] (user)
|
92
|
+
users[user]
|
93
|
+
end
|
94
|
+
|
95
|
+
def add (user)
|
96
|
+
users.add(user)
|
97
|
+
end
|
98
|
+
|
99
|
+
def delete (user)
|
100
|
+
users.delete(user)
|
101
|
+
end
|
102
|
+
|
103
|
+
def user (client)
|
104
|
+
return @users[client.nick]
|
105
|
+
end
|
106
|
+
|
107
|
+
def empty?
|
108
|
+
return @users.empty?
|
109
|
+
end
|
110
|
+
|
111
|
+
def send (*args)
|
112
|
+
users.send(*args)
|
113
|
+
end
|
114
|
+
|
115
|
+
def to_s
|
116
|
+
@name
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# failirc, a fail IRC library.
|
2
|
+
#
|
3
|
+
# Copyleft meh. [http://meh.doesntexist.org | meh.ffff@gmail.com]
|
4
|
+
#
|
5
|
+
# This file is part of failirc.
|
6
|
+
#
|
7
|
+
# failirc is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Affero General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# failirc is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with failirc. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require 'failirc/extensions'
|
21
|
+
require 'failirc/server/clients'
|
22
|
+
require 'failirc/server/channel'
|
23
|
+
|
24
|
+
module IRC
|
25
|
+
|
26
|
+
class Server
|
27
|
+
|
28
|
+
class Channels < ThreadSafeHash
|
29
|
+
attr_reader :server
|
30
|
+
|
31
|
+
def initialize (server, *args)
|
32
|
+
@server = server
|
33
|
+
|
34
|
+
super(*args)
|
35
|
+
end
|
36
|
+
|
37
|
+
alias __delete delete
|
38
|
+
|
39
|
+
def delete (channel)
|
40
|
+
if channel.is_a?(Channel)
|
41
|
+
__delete(channel.name)
|
42
|
+
else
|
43
|
+
__delete(channel)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def add (channel)
|
48
|
+
self[channel.name] = channel
|
49
|
+
end
|
50
|
+
|
51
|
+
# get single users in the channels
|
52
|
+
def unique_users
|
53
|
+
result = Clients.new(server)
|
54
|
+
|
55
|
+
each_value {|channel|
|
56
|
+
channel.users.each {|nick, user|
|
57
|
+
result[nick] = user.client
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
return result
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s (thing=nil)
|
65
|
+
result = ''
|
66
|
+
|
67
|
+
|
68
|
+
if thing.is_a?(Client) || thing.is_a?(User)
|
69
|
+
each_value {|channel|
|
70
|
+
result << " #{channel.user(thing).modes[:level]}#{channel.name}"
|
71
|
+
}
|
72
|
+
else
|
73
|
+
each_value {|channel|
|
74
|
+
result << " #{channel.name}"
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
return result[1, result.length]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|