PerfectlyNormal-Flexo 0.3.9
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/LICENSE +348 -0
- data/README +5 -0
- data/Rakefile +21 -0
- data/bin/flexo +3 -0
- data/bin/mkflexorc +99 -0
- data/flexo.gemspec +53 -0
- data/lib/caselesshash.rb +113 -0
- data/lib/daemonize.rb +59 -0
- data/lib/flexo/client.rb +30 -0
- data/lib/flexo/config.rb +79 -0
- data/lib/flexo/constants.rb +15 -0
- data/lib/flexo/data.rb +104 -0
- data/lib/flexo/dispatcher.rb +134 -0
- data/lib/flexo/errors.rb +29 -0
- data/lib/flexo/event.rb +31 -0
- data/lib/flexo/events/join.rb +13 -0
- data/lib/flexo/events/kick.rb +29 -0
- data/lib/flexo/events/mode.rb +23 -0
- data/lib/flexo/events/nick.rb +14 -0
- data/lib/flexo/events/notice.rb +12 -0
- data/lib/flexo/events/part.rb +14 -0
- data/lib/flexo/events/ping.rb +16 -0
- data/lib/flexo/events/pong.rb +14 -0
- data/lib/flexo/events/privmsg.rb +46 -0
- data/lib/flexo/events/quit.rb +12 -0
- data/lib/flexo/events/reply.rb +45 -0
- data/lib/flexo/events/topic.rb +18 -0
- data/lib/flexo/events/unknown.rb +11 -0
- data/lib/flexo/handler.rb +30 -0
- data/lib/flexo/logger.rb +86 -0
- data/lib/flexo/manager.rb +152 -0
- data/lib/flexo/numerics.rb +207 -0
- data/lib/flexo/plugin.rb +69 -0
- data/lib/flexo/pluginmanager.rb +106 -0
- data/lib/flexo/sender.rb +601 -0
- data/lib/flexo/server.rb +130 -0
- data/lib/flexo/trigger.rb +44 -0
- data/plugins/auth.rb +256 -0
- data/plugins/control.rb +36 -0
- data/plugins/dbus.rb +39 -0
- data/plugins/pstore.rb +34 -0
- data/plugins/svnlookup.rb +63 -0
- metadata +93 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'caselesshash'
|
3
|
+
|
4
|
+
module Flexo
|
5
|
+
# Here's the interesting parts. This class is responsible for...
|
6
|
+
# Managing plugins! Who would've thought that...
|
7
|
+
class PluginManager
|
8
|
+
# As usual. Set up some things. Create some arrays, some hashes,
|
9
|
+
# get a mutex. All that
|
10
|
+
def initialize(mutex)
|
11
|
+
@manager = Flexo::Manager.instance
|
12
|
+
@plugins_available = []
|
13
|
+
@plugins_loaded = CaselessHash.new
|
14
|
+
@plugins_path = @manager.config['plugin.path'].to_a
|
15
|
+
|
16
|
+
find_plugins
|
17
|
+
end
|
18
|
+
|
19
|
+
# Goes through the folders sent to initialize and looks for
|
20
|
+
# anything resembling a plugin. Then shove them into a hash
|
21
|
+
# so that we can find them later
|
22
|
+
def find_plugins
|
23
|
+
@manager.logger.debug " Going to search for plugins (in #{@plugins_path.join(',')}"
|
24
|
+
@plugins_path.each do |dir|
|
25
|
+
Dir["#{dir}/*.rb"].each do |file|
|
26
|
+
begin
|
27
|
+
require file
|
28
|
+
rescue => e
|
29
|
+
@manager.logger.warn(e.message)
|
30
|
+
next
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
ObjectSpace.each_object(Class) do |klass|
|
35
|
+
if klass < Flexo::Plugin
|
36
|
+
@manager.logger.debug("#{klass} looks like a valid Flexo-plugin")
|
37
|
+
unless klass::NAME
|
38
|
+
raise PluginNameError, "The plugin hasn't specified a name!"
|
39
|
+
end
|
40
|
+
|
41
|
+
if @plugins_available.any? { |plugin|
|
42
|
+
plugin::NAME.downcase == klass::NAME.downcase }
|
43
|
+
raise PluginConflictError,
|
44
|
+
"The plugin name #{klass::NAME} is already being used by another plugin."
|
45
|
+
end
|
46
|
+
@plugins_available << klass
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Find a plugin and its class by its name
|
53
|
+
def get_plugin_class(name)
|
54
|
+
@plugins_available.find { |plugin|
|
55
|
+
plugin::NAME.downcase == name.downcase
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
# Load a plugin
|
60
|
+
def load_plugin(name)
|
61
|
+
@manager.logger.debug("Going to load plugin #{name}")
|
62
|
+
klass = get_plugin_class(name)
|
63
|
+
raise Flexo::PluginNotFoundError, "The #{name} plugin could not be found." unless klass
|
64
|
+
|
65
|
+
if !@plugins_loaded.key?(klass::NAME)
|
66
|
+
begin
|
67
|
+
klass::DEPENDS.each do |dependency|
|
68
|
+
if(dependency[0..4] == "ruby-")
|
69
|
+
begin
|
70
|
+
require dependency[5..-1]
|
71
|
+
rescue LoadError
|
72
|
+
raise PluginDependencyError, "Plugin requires #{dependency[5..-1]}, which can't be found"
|
73
|
+
end
|
74
|
+
|
75
|
+
next
|
76
|
+
end
|
77
|
+
|
78
|
+
dep = get_plugin_class(dependency)
|
79
|
+
if !@plugins_loaded.key?(dep::NAME)
|
80
|
+
load_plugin(dep::NAME)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
plugin = klass.new(@plugins_loaded)
|
85
|
+
rescue Flexo::PluginError => e
|
86
|
+
puts "Plugin encountered an error (#{e.class}): #{e.message}"
|
87
|
+
puts e.backtrace
|
88
|
+
rescue Flexo::PluginDependencyError => e
|
89
|
+
@manager.logger.warn e.message
|
90
|
+
return nil
|
91
|
+
rescue Flexo::PluginNotFoundError => e
|
92
|
+
@manager.logger.warn e.message
|
93
|
+
return nil
|
94
|
+
end
|
95
|
+
|
96
|
+
@manager.mutex { @plugins_loaded[klass::NAME] = plugin }
|
97
|
+
@manager.logger.debug " Loaded #{plugin.class}"
|
98
|
+
else
|
99
|
+
@manager.logger.debug " Already loaded #{klass.class}"
|
100
|
+
plugin = @plugins_loaded[klass::NAME]
|
101
|
+
end
|
102
|
+
|
103
|
+
plugin
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/flexo/sender.rb
ADDED
@@ -0,0 +1,601 @@
|
|
1
|
+
module Flexo
|
2
|
+
# One of the important classes. This contains convenience-functions for
|
3
|
+
# sending almost every IRC command imaginable. And if that's not enough,
|
4
|
+
# it'll also have a raw()-function. This is the only class that's supposed
|
5
|
+
# to interact with Server, to make sure that only sanitized content is sent
|
6
|
+
# out from Flexo.
|
7
|
+
#
|
8
|
+
# Most documentation for the functions are grabbed from RFC2812
|
9
|
+
# available at http://tools.ietf.org/html/rfc2812.
|
10
|
+
class Sender
|
11
|
+
# Sets up the link to the manager, and creates a send queue.
|
12
|
+
def initialize
|
13
|
+
@manager = Flexo::Manager.instance
|
14
|
+
@queue = Queue.new
|
15
|
+
|
16
|
+
@manager.thread do
|
17
|
+
while cmd = @queue.pop
|
18
|
+
@manager.server.quote cmd
|
19
|
+
sleep 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Shoves the command into the queue
|
25
|
+
def quote(line)
|
26
|
+
@manager.logger.debug("Adding \"#{line.rstrip}\" to the outgoing queue")
|
27
|
+
@queue << line.rstrip
|
28
|
+
end
|
29
|
+
|
30
|
+
# 3.1.1 Password message
|
31
|
+
# Command: PASS
|
32
|
+
# Paramteres: <password>
|
33
|
+
#
|
34
|
+
# The PASS command is used to set a 'connection password'.
|
35
|
+
# The optional password can and MUST be set before any
|
36
|
+
# attempt to register when the connection is made.
|
37
|
+
# Currently this requires that user send a PASS command
|
38
|
+
# before sending the NICK/USER combination.
|
39
|
+
#
|
40
|
+
# Numeric Replies:
|
41
|
+
# ERR_NEEDMOREPARAMS
|
42
|
+
# ERR_ALREADYREGISTRED
|
43
|
+
#
|
44
|
+
# Example:
|
45
|
+
# PASS secretpasswordhere
|
46
|
+
def pass(password)
|
47
|
+
quote "PASS #{password.to_s}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# 3.1.2 Nick message
|
51
|
+
# Command: NICK
|
52
|
+
# Parameters: <nickname>
|
53
|
+
#
|
54
|
+
# NICK message is used to give the user a nickname if connecting,
|
55
|
+
# or change the previous one if already connected
|
56
|
+
#
|
57
|
+
# Numeric Replies:
|
58
|
+
# ERR_NONICKNAMEGIVEN
|
59
|
+
# ERR_ERRONEUSNICKNAME
|
60
|
+
# ERR_NICKNAMEINUSE
|
61
|
+
# ERR_NICKCOLLISION
|
62
|
+
#
|
63
|
+
# Example:
|
64
|
+
# NICK Wiz # Introducing new nick "Wiz".
|
65
|
+
# :WiZ NICK Kilroy # WiZ changed his nickname to Kilroy.
|
66
|
+
def nick(nickname)
|
67
|
+
quote "NICK #{nickname.to_s}"
|
68
|
+
end
|
69
|
+
|
70
|
+
# 3.1.3 User message
|
71
|
+
# Command: USER
|
72
|
+
# Parameters: <user> <mode> <unused> <realname>
|
73
|
+
#
|
74
|
+
# The USER command is used at the beginning of connection to specify
|
75
|
+
# the username, hostname and realname of a new user.
|
76
|
+
#
|
77
|
+
# The <mode> parameter should be a numeric, and can be used to
|
78
|
+
# automatically set user modes when registering with the server.
|
79
|
+
# This parameter is a bitmask, with only 2 bits having any
|
80
|
+
# signification: if the bit 2 is set, the user mode 'w' will
|
81
|
+
# be set and if the bit 3 is set, the user mode 'i' will be set.
|
82
|
+
# (See Section 3.1.5 "User Modes").
|
83
|
+
# The <realname> may contain space characters.
|
84
|
+
#
|
85
|
+
# Numeric Replies:
|
86
|
+
# ERR_NEEDMOREPARAMS
|
87
|
+
# ERR_ALREADYREGISTRED
|
88
|
+
#
|
89
|
+
# Example:
|
90
|
+
# USER guest 0 * :Ronnie Reagan # User registering themselves with a
|
91
|
+
# # username of "guest" and real name
|
92
|
+
# # "Ronnie Reagan".
|
93
|
+
# USER guest 8 * :Ronnie Reagan # User registering themselves with a
|
94
|
+
# # username of "guest" and real name
|
95
|
+
# # "Ronnie Reagan", and asking to be set
|
96
|
+
# # invisible.
|
97
|
+
def user(user, mode, realname)
|
98
|
+
quote "USER #{user.to_s} #{mode.to_i} * :#{realname.to_s}"
|
99
|
+
end
|
100
|
+
|
101
|
+
# 3.1.4 Oper message
|
102
|
+
# Command: OPER
|
103
|
+
# Parameters: <name> <password>
|
104
|
+
#
|
105
|
+
# A normal user uses the OPER command to obtain operator privileges.
|
106
|
+
# The combination of <name> and <password> are REQUIRED to gain
|
107
|
+
# Operator privileges. Upon success, the user will receive a MODE
|
108
|
+
# message (see section 3.1.5) indicating the new user modes.
|
109
|
+
#
|
110
|
+
# Numeric Replies:
|
111
|
+
# ERR_NEEDMOREPARAMS
|
112
|
+
# RPL_YOUREOPER
|
113
|
+
# ERR_NOOPERHOST
|
114
|
+
# ERR_PASSWDMISMATCH
|
115
|
+
# Example:
|
116
|
+
# OPER foo bar # Attempt to register as an operator
|
117
|
+
# using a username of "foo" and "bar" as the password.
|
118
|
+
def oper(name, password)
|
119
|
+
quote "OPER #{name.to_s} #{password.to_s}"
|
120
|
+
end
|
121
|
+
|
122
|
+
# 3.1.5 User mode message
|
123
|
+
# Command: MODE
|
124
|
+
# Parameters: <nickname> ±<modes>
|
125
|
+
#
|
126
|
+
# The user MODE's are typically changes which affect either how the
|
127
|
+
# client is seen by others or what 'extra' messages the client is sent.
|
128
|
+
# A user MODE command MUST only be accepted if both the sender of the
|
129
|
+
# message and the nickname given as a parameter are both the same. If
|
130
|
+
# no other parameter is given, then the server will return the current
|
131
|
+
# settings for the nick.
|
132
|
+
#
|
133
|
+
# The available modes are as follows:
|
134
|
+
# a - user is flagged as away;
|
135
|
+
# i - marks a users as invisible;
|
136
|
+
# w - user receives wallops;
|
137
|
+
# r - restricted user connection;
|
138
|
+
# o - operator flag;
|
139
|
+
# O - local operator flag;
|
140
|
+
# s - marks a user for receipt of server notices.
|
141
|
+
#
|
142
|
+
# Additional modes may be available later on.
|
143
|
+
#
|
144
|
+
# The flag 'a' SHALL NOT be toggled by the user using the MODE command,
|
145
|
+
# instead use of the AWAY command is REQUIRED.
|
146
|
+
#
|
147
|
+
# If a user attempts to make themselves an operator using the "+o" or
|
148
|
+
# "+O" flag, the attempt SHOULD be ignored as users could bypass the
|
149
|
+
# authentication mechanisms of the OPER command. There is no
|
150
|
+
# restriction, however, on anyone `deopping' themselves (using "-o" or
|
151
|
+
# "-O").
|
152
|
+
#
|
153
|
+
# On the other hand, if a user attempts to make themselves unrestricted
|
154
|
+
# using the "-r" flag, the attempt SHOULD be ignored. There is no
|
155
|
+
# restriction, however, on anyone `deopping' themselves (using "+r").
|
156
|
+
# This flag is typically set by the server upon connection for
|
157
|
+
# administrative reasons. While the restrictions imposed are left up
|
158
|
+
# to the implementation, it is typical that a restricted user not be
|
159
|
+
# allowed to change nicknames, nor make use of the channel operator
|
160
|
+
# status on channels.
|
161
|
+
#
|
162
|
+
# The flag 's' is obsolete but MAY still be used.
|
163
|
+
#
|
164
|
+
# Numeric Replies:
|
165
|
+
# ERR_NEEDMOREPARAMS
|
166
|
+
# ERR_USERSDONTMATCH
|
167
|
+
# ERR_UMODEUNKNOWNFLAG
|
168
|
+
# RPL_UMODEIS
|
169
|
+
# Examples:
|
170
|
+
# MODE WiZ -w # Command by WiZ to turn off
|
171
|
+
# # reception of WALLOPS messages.
|
172
|
+
# MODE Angel +i # Command from Angel to make herself invisible.
|
173
|
+
# MODE WiZ -o # WiZ 'deopping' (removing operator status).
|
174
|
+
def usermode(nickname, mode)
|
175
|
+
quote "MODE #{nickname.to_s} #{mode.to_s}"
|
176
|
+
end
|
177
|
+
|
178
|
+
# 3.1.6 Service message
|
179
|
+
# Command: SERVICE
|
180
|
+
# Parameters: <nickname> <reserved> <distribution> <type>
|
181
|
+
# <reserved> <info>
|
182
|
+
#
|
183
|
+
# The SERVICE command to register a new service. Command parameters
|
184
|
+
# specify the service nickname, distribution, type and info of a new
|
185
|
+
# service.
|
186
|
+
#
|
187
|
+
# The <distribution> parameter is used to specify the visibility of a
|
188
|
+
# service. The service may only be known to servers which have a name
|
189
|
+
# matching the distribution. For a matching server to have knowledge
|
190
|
+
# of the service, the network path between that server and the server
|
191
|
+
# on which the service is connected MUST be composed of servers which
|
192
|
+
# names all match the mask.
|
193
|
+
#
|
194
|
+
# The <type> parameter is currently reserved for future usage.
|
195
|
+
#
|
196
|
+
# Numeric Replies:
|
197
|
+
# ERR_ALREADYREGISTRED
|
198
|
+
# ERR_NEEDMOREPARAMS
|
199
|
+
# ERR_ERRONEUSNICKNAME
|
200
|
+
# RPL_YOURESERVICE
|
201
|
+
# RPL_YOURHOST
|
202
|
+
# RPL_MYINFO
|
203
|
+
# Example:
|
204
|
+
# SERVICE dict * *.fr 0 0 :French Dictionary
|
205
|
+
# # Service registering itself with a name of "dict".
|
206
|
+
# # This service will only be available on servers which
|
207
|
+
# # name matches "*.fr".
|
208
|
+
def service(nickname, distribution, type, info)
|
209
|
+
# Won't be implemented by me
|
210
|
+
end
|
211
|
+
|
212
|
+
# 3.1.7 Quit
|
213
|
+
# Command: QUIT
|
214
|
+
# Parameters: <Quit Message>
|
215
|
+
#
|
216
|
+
# A client session is terminated with a quit message. The server
|
217
|
+
# acknowledges this by sending an ERROR message to the client.
|
218
|
+
#
|
219
|
+
# Numeric Replies:
|
220
|
+
# None.
|
221
|
+
# Example:
|
222
|
+
# QUIT :Gone to have lunch
|
223
|
+
def quit(message="")
|
224
|
+
quote "QUIT :#{message.to_s}"
|
225
|
+
end
|
226
|
+
|
227
|
+
# 3.1.8 Squit
|
228
|
+
# Command: SQUIT
|
229
|
+
# Parameters: <server> <comment>
|
230
|
+
#
|
231
|
+
# The SQUIT command is available only to operators. It is used to
|
232
|
+
# disconnect server links. Also servers can generate SQUIT messages on
|
233
|
+
# error conditions. A SQUIT message may also target a remote server
|
234
|
+
# connection. In this case, the SQUIT message will simply be sent to
|
235
|
+
# the remote server without affecting the servers in between the
|
236
|
+
# operator and the remote server.
|
237
|
+
#
|
238
|
+
# The <comment> SHOULD be supplied by all operators who execute a SQUIT
|
239
|
+
# for a remote server. The server ordered to disconnect its peer
|
240
|
+
# generates a WALLOPS message with <comment> included, so that other
|
241
|
+
# users may be aware of the reason of this action.
|
242
|
+
#
|
243
|
+
# Numeric replies:
|
244
|
+
# ERR_NOPRIVILEGES
|
245
|
+
# ERR_NOSUCHSERVER
|
246
|
+
# ERR_NEEDMOREPARAMS
|
247
|
+
# Examples:
|
248
|
+
# SQUIT tolsun.oulu.fi :Bad Link ? # Command to uplink of the server
|
249
|
+
# # tolson.oulu.fi to terminate its
|
250
|
+
# # connection with comment "Bad Link".
|
251
|
+
# :Trillian SQUIT cm22.eng.umd.edu :Server out of control
|
252
|
+
# # Command from Trillian from to
|
253
|
+
# # disconnect "cm22.eng.umd.edu"
|
254
|
+
# # from the net with comment
|
255
|
+
# # "Server out of control".
|
256
|
+
def squit(server, message="")
|
257
|
+
end
|
258
|
+
|
259
|
+
# 3.2.1 Join message
|
260
|
+
# Command: JOIN
|
261
|
+
# Parameters: <channel>, <key>
|
262
|
+
#
|
263
|
+
# The JOIN command is used by a user to request to start listening to
|
264
|
+
# the specific channel. Servers MUST be able to parse arguments in the
|
265
|
+
# form of a list of target, but SHOULD NOT use lists when sending JOIN
|
266
|
+
# messages to clients.
|
267
|
+
#
|
268
|
+
# Once a user has joined a channel, he receives information about
|
269
|
+
# all commands his server receives affecting the channel. This
|
270
|
+
# includes JOIN, MODE, KICK, PART, QUIT and of course PRIVMSG/NOTICE.
|
271
|
+
# This allows channel members to keep track of the other channel
|
272
|
+
# members, as well as channel modes.
|
273
|
+
#
|
274
|
+
# If a JOIN is successful, the user receives a JOIN message as
|
275
|
+
# confirmation and is then sent the channel's topic (using RPL_TOPIC) and
|
276
|
+
# the list of users who are on the channel (using RPL_NAMREPLY), which
|
277
|
+
# MUST include the user joining.
|
278
|
+
#
|
279
|
+
# Note that this message accepts a special argument ("0"), which is
|
280
|
+
# a special request to leave all channels the user is currently a member
|
281
|
+
# of. The server will process this message as if the user had sent
|
282
|
+
# a PART command (See Section 3.2.2) for each channel he is a member
|
283
|
+
# of.
|
284
|
+
#
|
285
|
+
# Numeric Replies:
|
286
|
+
# ERR_NEEDMOREPARAMS
|
287
|
+
# ERR_BANNEDFROMCHAN
|
288
|
+
# ERR_INVITEONLYCHAN
|
289
|
+
# ERR_BADCHANNELKEY
|
290
|
+
# ERR_CHANNELISFULL
|
291
|
+
# ERR_BADCHANMASK
|
292
|
+
# ERR_NOSUCHCHANNEL
|
293
|
+
# ERR_TOOMANYCHANNELS
|
294
|
+
# ERR_TOOMANYTARGETS
|
295
|
+
# ERR_UNAVAILRESOURCE
|
296
|
+
# RPL_TOPIC
|
297
|
+
# Examples:
|
298
|
+
# JOIN #foobar # Command to join channel #foobar.
|
299
|
+
# JOIN &foo fubar # Command to join channel &foo using
|
300
|
+
# # key "fubar".
|
301
|
+
# JOIN #foo,&bar fubar # Command to join channel #foo using
|
302
|
+
# # key "fubar" and &bar using no key.
|
303
|
+
# JOIN #foo,#bar fubar,foobar # Command to join channel #foo using
|
304
|
+
# # key "fubar", and channel #bar using
|
305
|
+
# # key "foobar".
|
306
|
+
# JOIN #foo,#bar # Command to join channels #foo and
|
307
|
+
# # #bar.
|
308
|
+
# JOIN 0 # Leave all currently joined
|
309
|
+
# # channels.
|
310
|
+
def join(channels, key="")
|
311
|
+
channels.each do |channel|
|
312
|
+
quote "JOIN #{channel.to_s} #{key.to_s}"
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
# 3.2.2 Part message
|
317
|
+
# Command: PART
|
318
|
+
# Parameters: <channel> <part message>
|
319
|
+
#
|
320
|
+
# The PART command causes the user sending the message to be removed
|
321
|
+
# from the list of active members for all given channels listed in the
|
322
|
+
# parameter string. If a "Part Message" is given, this will be sent
|
323
|
+
# instead of the default message, the nickname. This request is always
|
324
|
+
# granted by the server.
|
325
|
+
#
|
326
|
+
# Servers MUST be able to parse arguments in the form of a list of
|
327
|
+
# target, but SHOULD NOT use lists when sending PART messages to
|
328
|
+
# clients.
|
329
|
+
#
|
330
|
+
# Numeric Replies:
|
331
|
+
# ERR_NEEDMOREPARAMS
|
332
|
+
# ERR_NOSUCHCHANNEL
|
333
|
+
# ERR_NOTONCHANNEL
|
334
|
+
# Examples:
|
335
|
+
# PART #twilight_zone # Command to leave channel "#twilight_zone"
|
336
|
+
# PART #oz-ops,&group5 # Command to leave both channels
|
337
|
+
# # "&group5" and "#oz-ops".
|
338
|
+
def part(channels, message="")
|
339
|
+
channels.each do |channel|
|
340
|
+
cmd = "PART #{channel.to_s}"
|
341
|
+
cmd += " :#{message}" if message != ""
|
342
|
+
quote cmd
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
# 3.2.3 Channel mode message
|
347
|
+
# Command: MODE
|
348
|
+
# Parameters: <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
|
349
|
+
#
|
350
|
+
# The MODE command is provided so that users may query and change the
|
351
|
+
# characteristics of a channel. Note that there is a maximum limit of three (3) changes per
|
352
|
+
# command for modes that take a parameter.
|
353
|
+
#
|
354
|
+
# Numeric Replies:
|
355
|
+
# ERR_NEEDMOREPARAMS
|
356
|
+
# ERR_KEYSET
|
357
|
+
# ERR_NOCHANMODES
|
358
|
+
# ERR_CHANOPRIVSNEEDED
|
359
|
+
# ERR_USERNOTINCHANNEL
|
360
|
+
# ERR_UNKNOWNMODE
|
361
|
+
# RPL_CHANNELMODEIS
|
362
|
+
# RPL_BANLIST
|
363
|
+
# RPL_ENDOFBANLIST
|
364
|
+
# RPL_EXCEPTLIST
|
365
|
+
# RPL_ENDOFEXCEPTLIST
|
366
|
+
# RPL_INVITELIST
|
367
|
+
# RPL_ENDOFINVITELIST
|
368
|
+
# RPL_UNIQOPIS
|
369
|
+
#
|
370
|
+
# Information about channel modes and how they work can be found
|
371
|
+
# in RFC2811 (http://tools.ietf.org/html/rfc2811)
|
372
|
+
def chanmode(channel, *modes)
|
373
|
+
quote "MODE #{channel.to_s} #{modes.join(' ')}"
|
374
|
+
end
|
375
|
+
|
376
|
+
# 3.2.4 Topic message
|
377
|
+
# Command: TOPIC
|
378
|
+
# Parameters: <channel> [ <topic> ]
|
379
|
+
#
|
380
|
+
# The TOPIC command is used to change or view the topic of a channel.
|
381
|
+
# The topic for channel <channel> is returned if there is no <topic>
|
382
|
+
# given. If the <topic> parameter is present, the topic for that
|
383
|
+
# channel will be changed, if this action is allowed for the user
|
384
|
+
# requesting it. If the <topic> parameter is an empty string, the
|
385
|
+
# topic for that channel will be removed.
|
386
|
+
#
|
387
|
+
# Numeric Replies:
|
388
|
+
# ERR_NEEDMOREPARAMS
|
389
|
+
# ERR_NOTONCHANNEL
|
390
|
+
# RPL_NOTOPIC
|
391
|
+
# RPL_TOPIC
|
392
|
+
# ERR_CHANOPRIVSNEEDED
|
393
|
+
# ERR_NOCHANMODES
|
394
|
+
# Examples:
|
395
|
+
# :WiZ!jto@tolsun.oulu.fi TOPIC #test :New # User Wiz setting the topic.
|
396
|
+
# TOPIC #test :another topic # Command to set the topic on #test
|
397
|
+
# # to "another topic".
|
398
|
+
# TOPIC #test : # Command to clear the topic on #test.
|
399
|
+
# TOPIC #test # Command to check the topic for #test.
|
400
|
+
def topic(channel, topic="")
|
401
|
+
cmd = "TOPIC #{channel.to_s} "
|
402
|
+
cmd += ":#{topic.to_s}" if topic != ""
|
403
|
+
quote cmd
|
404
|
+
end
|
405
|
+
|
406
|
+
# FIXME: 3.2.5 Names message
|
407
|
+
# FIXME: 3.2.6 List message
|
408
|
+
|
409
|
+
# 3.2.7 Invite message
|
410
|
+
# Command: INVITE
|
411
|
+
# Parameters: <nickname> <channel>
|
412
|
+
#
|
413
|
+
# The INVITE command is used to invite a user to a channel. The
|
414
|
+
# parameter <nickname> is the nickname of the person to be invited to
|
415
|
+
# the target channel <channel>. There is no requirement that the
|
416
|
+
# channel the target user is being invited to must exist or be a valid
|
417
|
+
# channel. However, if the channel exists, only members of the channel
|
418
|
+
# are allowed to invite other users. When the channel has invite-only
|
419
|
+
# flag set, only channel operators may issue INVITE command.
|
420
|
+
#
|
421
|
+
# Only the user inviting and the user being invited will receive
|
422
|
+
# notification of the invitation. Other channel members are not
|
423
|
+
# notified. (This is unlike the MODE changes, and is occasionally the
|
424
|
+
# source of trouble for users.)
|
425
|
+
#
|
426
|
+
# Numeric Replies:
|
427
|
+
# ERR_NEEDMOREPARAMS
|
428
|
+
# ERR_NOSUCHNICK
|
429
|
+
# ERR_NOTONCHANNEL
|
430
|
+
# ERR_USERONCHANNEL
|
431
|
+
# ERR_CHANOPRIVSNEEDED
|
432
|
+
# RPL_INVITING
|
433
|
+
# RPL_AWAY
|
434
|
+
# Examples:
|
435
|
+
# :Angel!wings@irc.org INVITE Wiz #Dust # Message to WiZ when he has
|
436
|
+
# # been invited by user Angel
|
437
|
+
# # to channel #Dust
|
438
|
+
# INVITE Wiz #Twilight_Zone # Command to invite WiZ to
|
439
|
+
# # #Twilight_zone
|
440
|
+
def invite(nick, channel)
|
441
|
+
quote "INVITE #{nick.to_s} #{channel.to_s}"
|
442
|
+
end
|
443
|
+
|
444
|
+
# 3.2.8 Kick command
|
445
|
+
# Command: KICK
|
446
|
+
# Parameters: <channel> <user> [<comment>]
|
447
|
+
#
|
448
|
+
# The KICK command can be used to request the forced removal of a user
|
449
|
+
# from a channel. It causes the <user> to PART from the <channel> by
|
450
|
+
# force. For the message to be syntactically correct, there MUST be
|
451
|
+
# either one channel parameter and multiple user parameter, or as many
|
452
|
+
# channel parameters as there are user parameters. If a "comment" is
|
453
|
+
# given, this will be sent instead of the default message, the nickname
|
454
|
+
# of the user issuing the KICK.
|
455
|
+
#
|
456
|
+
# Numeric Replies:
|
457
|
+
# ERR_NEEDMOREPARAMS
|
458
|
+
# ERR_NOSUCHCHANNEL
|
459
|
+
# ERR_BADCHANMASK
|
460
|
+
# ERR_CHANOPRIVSNEEDED
|
461
|
+
# ERR_USERNOTINCHANNEL
|
462
|
+
# ERR_NOTONCHANNEL
|
463
|
+
def kick(channel, user, message="")
|
464
|
+
quote "KICK #{channel} #{user} :#{message}"
|
465
|
+
end
|
466
|
+
|
467
|
+
# 3.3.1 Private messages
|
468
|
+
# Command: PRIVMSG
|
469
|
+
# Parameters: <target> <text to be sent>
|
470
|
+
#
|
471
|
+
# PRIVMSG is used to send private messages between users, as well as to
|
472
|
+
# send messages to channels. <msgtarget> is usually the nickname of
|
473
|
+
# the recipient of the message, or a channel name.
|
474
|
+
#
|
475
|
+
# The <msgtarget> parameter may also be a host mask (#<mask>) or server
|
476
|
+
# mask ($<mask>). In both cases the server will only send the PRIVMSG
|
477
|
+
# to those who have a server or host matching the mask. The mask MUST
|
478
|
+
# have at least 1 (one) "." in it and no wildcards following the last
|
479
|
+
# ".". This requirement exists to prevent people sending messages to
|
480
|
+
# "#*" or "$*", which would broadcast to all users. Wildcards are the
|
481
|
+
# '*' and '?' characters. This extension to the PRIVMSG command is
|
482
|
+
# only available to operators.
|
483
|
+
#
|
484
|
+
# Numeric Replies:
|
485
|
+
# ERR_NORECIPIENT
|
486
|
+
# ERR_NOTEXTTOSEND
|
487
|
+
# ERR_CANNOTSENDTOCHAN
|
488
|
+
# ERR_NOTOPLEVEL
|
489
|
+
# ERR_WILDTOPLEVEL
|
490
|
+
# ERR_TOOMANYTARGETS
|
491
|
+
# ERR_NOSUCHNICK
|
492
|
+
# RPL_AWAY
|
493
|
+
def privmsg(target, text)
|
494
|
+
quote "PRIVMSG #{target.to_s} :#{text.to_s}"
|
495
|
+
end
|
496
|
+
|
497
|
+
# 3.3.2 Notice
|
498
|
+
# Command: NOTICE
|
499
|
+
# Parameters: <target> <text>
|
500
|
+
#
|
501
|
+
# The NOTICE command is used similarly to PRIVMSG. The difference
|
502
|
+
# between NOTICE and PRIVMSG is that automatic replies MUST NEVER be
|
503
|
+
# sent in response to a NOTICE message. This rule applies to servers
|
504
|
+
# too - they MUST NOT send any error reply back to the client on
|
505
|
+
# receipt of a notice. The object of this rule is to avoid loops
|
506
|
+
# between clients automatically sending something in response to
|
507
|
+
# something it received.
|
508
|
+
#
|
509
|
+
# This command is available to services as well as users.
|
510
|
+
# This is typically used by services, and automatons (clients with
|
511
|
+
# either an AI or other interactive program controlling their actions).
|
512
|
+
#
|
513
|
+
# See PRIVMSG for more details on replies.
|
514
|
+
def notice(target, text)
|
515
|
+
quote "NOTICE #{target.to_s} :#{text.to_s}"
|
516
|
+
end
|
517
|
+
|
518
|
+
# 3.4.1 Motd message
|
519
|
+
# Command: MOTD
|
520
|
+
# Parameters: [ <target> ]
|
521
|
+
#
|
522
|
+
# The MOTD command is used to get the "Message Of The Day" of the given
|
523
|
+
# server, or current server if <target> is omitted.
|
524
|
+
#
|
525
|
+
# Wildcards are allowed in the <target> parameter.
|
526
|
+
#
|
527
|
+
# Numeric Replies:
|
528
|
+
# RPL_MOTDSTART
|
529
|
+
# RPL_MOTD
|
530
|
+
# RPL_ENDOFMOTD
|
531
|
+
# ERR_NOMOTD
|
532
|
+
def motd(target="")
|
533
|
+
quote "MOTD #{target}"
|
534
|
+
end
|
535
|
+
|
536
|
+
# FIXME: 3.4.2 Lusers message
|
537
|
+
# FIXME: 3.4.3 Version message
|
538
|
+
# FIXME: 3.4.4 Stats message
|
539
|
+
# FIXME: 3.4.5 Links message
|
540
|
+
# FIXME: 3.4.6 Time message
|
541
|
+
# FIXME: 3.4.7 Connect message
|
542
|
+
# FIXME: 3.4.8 Trace message
|
543
|
+
# FIXME: 3.4.9 Admin command
|
544
|
+
# FIXME: 3.4.10 Info command
|
545
|
+
# FIXME: 3.5 Service Query and Commands
|
546
|
+
# FIXME: 3.6 User based queries
|
547
|
+
# FIXME: 3.7.1 KILL
|
548
|
+
|
549
|
+
# 3.7.2 Ping message
|
550
|
+
#
|
551
|
+
# Command: PING
|
552
|
+
# Parameters: <server1> [ <server2> ]
|
553
|
+
#
|
554
|
+
# The PING command is used to test the presence of an active client or
|
555
|
+
# server at the other end of the connection. Servers send a PING
|
556
|
+
# message at regular intervals if no other activity detected coming
|
557
|
+
# from a connection. If a connection fails to respond to a PING
|
558
|
+
# message within a set amount of time, that connection is closed. A
|
559
|
+
# PING message MAY be sent even if the connection is active.
|
560
|
+
#
|
561
|
+
# When a PING message is received, the appropriate PONG message MUST be
|
562
|
+
# sent as reply to <server1> (server which sent the PING message out)
|
563
|
+
# as soon as possible. If the <server2> parameter is specified, it
|
564
|
+
# represents the target of the ping, and the message gets forwarded
|
565
|
+
# there.
|
566
|
+
#
|
567
|
+
# Numeric Replies:
|
568
|
+
# ERR_NOORIGIN
|
569
|
+
# ERR_NOSUCHSERVER
|
570
|
+
# Examples:
|
571
|
+
# PING tolsun.oulu.fi # Command to send a PING message to server
|
572
|
+
# PING :irc.funet.fi # Ping message sent by server "irc.funet.fi"
|
573
|
+
def ping(server, server2="")
|
574
|
+
quote "PING #{server.to_s} #{server2.to_s}"
|
575
|
+
end
|
576
|
+
|
577
|
+
# 3.7.3 Pong message
|
578
|
+
#
|
579
|
+
# Command: PONG
|
580
|
+
# Parameters: <server> [ <server2> ]
|
581
|
+
#
|
582
|
+
# PONG message is a reply to ping message. If parameter <server2> is
|
583
|
+
# given, this message MUST be forwarded to given target. The <server>
|
584
|
+
# parameter is the name of the entity who has responded to PING message
|
585
|
+
# and generated this message.
|
586
|
+
#
|
587
|
+
# Numeric Replies:
|
588
|
+
# ERR_NOORIGIN
|
589
|
+
# ERR_NOSUCHSERVER
|
590
|
+
# Example:
|
591
|
+
# PONG csd.bu.edu tolsun.oulu.fi # PONG message from csd.bu.edu to
|
592
|
+
# # tolsun.oulu.fi
|
593
|
+
def pong(server, server2="")
|
594
|
+
quote "PONG #{server.to_s} #{server2.to_s}"
|
595
|
+
end
|
596
|
+
|
597
|
+
# FIXME: 3.7.4 Error
|
598
|
+
|
599
|
+
# FIXME: 4. Optional features
|
600
|
+
end
|
601
|
+
end
|