butler 1.8.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.
- data/CHANGELOG +4 -0
- data/GPL.txt +340 -0
- data/LICENSE.txt +52 -0
- data/README +37 -0
- data/Rakefile +334 -0
- data/bin/botcontrol +230 -0
- data/data/butler/config_template.yaml +4 -0
- data/data/butler/dialogs/backup.rb +19 -0
- data/data/butler/dialogs/botcontrol.rb +4 -0
- data/data/butler/dialogs/config.rb +1 -0
- data/data/butler/dialogs/create.rb +53 -0
- data/data/butler/dialogs/delete.rb +3 -0
- data/data/butler/dialogs/en/backup.yaml +6 -0
- data/data/butler/dialogs/en/botcontrol.yaml +5 -0
- data/data/butler/dialogs/en/create.yaml +11 -0
- data/data/butler/dialogs/en/delete.yaml +2 -0
- data/data/butler/dialogs/en/help.yaml +17 -0
- data/data/butler/dialogs/en/info.yaml +13 -0
- data/data/butler/dialogs/en/list.yaml +4 -0
- data/data/butler/dialogs/en/notyetimplemented.yaml +2 -0
- data/data/butler/dialogs/en/rename.yaml +3 -0
- data/data/butler/dialogs/en/start.yaml +3 -0
- data/data/butler/dialogs/en/sync_plugins.yaml +3 -0
- data/data/butler/dialogs/en/uninstall.yaml +5 -0
- data/data/butler/dialogs/en/unknown_command.yaml +2 -0
- data/data/butler/dialogs/help.rb +11 -0
- data/data/butler/dialogs/info.rb +27 -0
- data/data/butler/dialogs/interactive.rb +1 -0
- data/data/butler/dialogs/list.rb +10 -0
- data/data/butler/dialogs/notyetimplemented.rb +1 -0
- data/data/butler/dialogs/rename.rb +4 -0
- data/data/butler/dialogs/selectbot.rb +2 -0
- data/data/butler/dialogs/start.rb +5 -0
- data/data/butler/dialogs/sync_plugins.rb +30 -0
- data/data/butler/dialogs/uninstall.rb +17 -0
- data/data/butler/dialogs/unknown_command.rb +1 -0
- data/data/butler/plugins/core/logout.rb +41 -0
- data/data/butler/plugins/core/plugins.rb +134 -0
- data/data/butler/plugins/core/privilege.rb +103 -0
- data/data/butler/plugins/core/user.rb +166 -0
- data/data/butler/plugins/dev/eval.rb +64 -0
- data/data/butler/plugins/dev/nometa.rb +14 -0
- data/data/butler/plugins/dev/onhandlers.rb +93 -0
- data/data/butler/plugins/dev/raw.rb +36 -0
- data/data/butler/plugins/dev/rawlog.rb +77 -0
- data/data/butler/plugins/games/eightball.rb +54 -0
- data/data/butler/plugins/games/mastermind.rb +174 -0
- data/data/butler/plugins/irc/action.rb +36 -0
- data/data/butler/plugins/irc/join.rb +38 -0
- data/data/butler/plugins/irc/notice.rb +36 -0
- data/data/butler/plugins/irc/part.rb +38 -0
- data/data/butler/plugins/irc/privmsg.rb +36 -0
- data/data/butler/plugins/irc/quit.rb +36 -0
- data/data/butler/plugins/operator/deop.rb +41 -0
- data/data/butler/plugins/operator/devoice.rb +41 -0
- data/data/butler/plugins/operator/limit.rb +47 -0
- data/data/butler/plugins/operator/op.rb +41 -0
- data/data/butler/plugins/operator/voice.rb +41 -0
- data/data/butler/plugins/public/help.rb +69 -0
- data/data/butler/plugins/public/login.rb +72 -0
- data/data/butler/plugins/public/usage.rb +49 -0
- data/data/butler/plugins/service/clones.rb +56 -0
- data/data/butler/plugins/service/define.rb +47 -0
- data/data/butler/plugins/service/log.rb +183 -0
- data/data/butler/plugins/service/svn.rb +91 -0
- data/data/butler/plugins/util/cycle.rb +98 -0
- data/data/butler/plugins/util/load.rb +41 -0
- data/data/butler/plugins/util/pong.rb +29 -0
- data/data/butler/strings/random/acknowledge.en.yaml +5 -0
- data/data/butler/strings/random/gratitude.en.yaml +3 -0
- data/data/butler/strings/random/hello.en.yaml +4 -0
- data/data/butler/strings/random/ignorance.en.yaml +7 -0
- data/data/butler/strings/random/ignorance_about.en.yaml +3 -0
- data/data/butler/strings/random/insult.en.yaml +3 -0
- data/data/butler/strings/random/rejection.en.yaml +12 -0
- data/data/man/botcontrol.1 +17 -0
- data/lib/access.rb +187 -0
- data/lib/access/admin.rb +16 -0
- data/lib/access/privilege.rb +122 -0
- data/lib/access/role.rb +102 -0
- data/lib/access/savable.rb +18 -0
- data/lib/access/user.rb +180 -0
- data/lib/access/yamlbase.rb +126 -0
- data/lib/butler.rb +188 -0
- data/lib/butler/bot.rb +247 -0
- data/lib/butler/control.rb +93 -0
- data/lib/butler/dialog.rb +64 -0
- data/lib/butler/initialvalues.rb +40 -0
- data/lib/butler/irc/channel.rb +135 -0
- data/lib/butler/irc/channels.rb +96 -0
- data/lib/butler/irc/client.rb +351 -0
- data/lib/butler/irc/hostmask.rb +53 -0
- data/lib/butler/irc/message.rb +184 -0
- data/lib/butler/irc/parser.rb +125 -0
- data/lib/butler/irc/parser/commands.rb +83 -0
- data/lib/butler/irc/parser/generic.rb +343 -0
- data/lib/butler/irc/socket.rb +378 -0
- data/lib/butler/irc/string.rb +186 -0
- data/lib/butler/irc/topic.rb +15 -0
- data/lib/butler/irc/user.rb +265 -0
- data/lib/butler/irc/users.rb +112 -0
- data/lib/butler/plugin.rb +249 -0
- data/lib/butler/plugin/configproxy.rb +35 -0
- data/lib/butler/plugin/mapper.rb +85 -0
- data/lib/butler/plugin/matcher.rb +55 -0
- data/lib/butler/plugin/onhandlers.rb +70 -0
- data/lib/butler/plugin/trigger.rb +58 -0
- data/lib/butler/plugins.rb +147 -0
- data/lib/butler/version.rb +17 -0
- data/lib/cloptions.rb +217 -0
- data/lib/cloptions/adapters.rb +24 -0
- data/lib/cloptions/switch.rb +132 -0
- data/lib/configuration.rb +223 -0
- data/lib/dialogline.rb +296 -0
- data/lib/dialogline/localizations.rb +24 -0
- data/lib/durations.rb +57 -0
- data/lib/event.rb +295 -0
- data/lib/event/at.rb +64 -0
- data/lib/event/every.rb +56 -0
- data/lib/event/timed.rb +112 -0
- data/lib/installer.rb +75 -0
- data/lib/iterator.rb +34 -0
- data/lib/log.rb +68 -0
- data/lib/log/comfort.rb +85 -0
- data/lib/log/converter.rb +23 -0
- data/lib/log/entry.rb +152 -0
- data/lib/log/fakeio.rb +55 -0
- data/lib/log/file.rb +54 -0
- data/lib/log/filereader.rb +81 -0
- data/lib/log/forward.rb +49 -0
- data/lib/log/methods.rb +39 -0
- data/lib/log/nolog.rb +18 -0
- data/lib/log/splitter.rb +26 -0
- data/lib/ostructfixed.rb +26 -0
- data/lib/ruby/array/columnize.rb +38 -0
- data/lib/ruby/dir/mktree.rb +28 -0
- data/lib/ruby/enumerable/join.rb +13 -0
- data/lib/ruby/exception/detailed.rb +24 -0
- data/lib/ruby/file/append.rb +11 -0
- data/lib/ruby/file/write.rb +11 -0
- data/lib/ruby/hash/zip.rb +15 -0
- data/lib/ruby/kernel/bench.rb +15 -0
- data/lib/ruby/kernel/daemonize.rb +42 -0
- data/lib/ruby/kernel/non_verbose.rb +17 -0
- data/lib/ruby/kernel/safe_fork.rb +18 -0
- data/lib/ruby/range/stepped.rb +11 -0
- data/lib/ruby/string/arguments.rb +72 -0
- data/lib/ruby/string/chunks.rb +15 -0
- data/lib/ruby/string/post_arguments.rb +44 -0
- data/lib/ruby/string/unescaped.rb +17 -0
- data/lib/scheduler.rb +164 -0
- data/lib/scriptfile.rb +101 -0
- data/lib/templater.rb +86 -0
- data/test/cloptions.rb +134 -0
- data/test/cv.rb +28 -0
- data/test/irc/client.rb +85 -0
- data/test/irc/client_login.txt +53 -0
- data/test/irc/client_subscribe.txt +8 -0
- data/test/irc/message.rb +30 -0
- data/test/irc/messages.txt +64 -0
- data/test/irc/parser.rb +13 -0
- data/test/irc/profile_parser.rb +12 -0
- data/test/irc/users.rb +28 -0
- metadata +256 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
#require 'ruby/string' # we need the transcode! method
|
|
10
|
+
|
|
11
|
+
class Butler
|
|
12
|
+
module IRC
|
|
13
|
+
|
|
14
|
+
# Butler::IRC::Message represents messages received by the server.
|
|
15
|
+
# It provides convenience methods that allow to access information about
|
|
16
|
+
# those messages easier, e.g. who (as Butler::IRC::User object) sent the
|
|
17
|
+
# message in which channel (IRC::Channel object) with what text.
|
|
18
|
+
# Raw message and raw parsed data are still available though.
|
|
19
|
+
#
|
|
20
|
+
# =FIXME
|
|
21
|
+
class Message
|
|
22
|
+
# the command-symbol, see COMMANDS (e.g. :PRIVMSG, :JOIN, ...)
|
|
23
|
+
attr_reader :symbol
|
|
24
|
+
|
|
25
|
+
# a string containing the raw message as received
|
|
26
|
+
attr_reader :raw
|
|
27
|
+
|
|
28
|
+
# the prefix, normally either the sending user or your irc-server
|
|
29
|
+
attr_reader :prefix
|
|
30
|
+
# the raw command (e.g. "352", "notice", ...)
|
|
31
|
+
attr_reader :command
|
|
32
|
+
# the parameter part
|
|
33
|
+
attr_reader :params
|
|
34
|
+
|
|
35
|
+
def initialize(client, symbol, raw, prefix, command, params)
|
|
36
|
+
@client = client
|
|
37
|
+
|
|
38
|
+
#raw message
|
|
39
|
+
@raw = raw
|
|
40
|
+
|
|
41
|
+
#parsed data
|
|
42
|
+
@prefix = prefix
|
|
43
|
+
@command = command
|
|
44
|
+
@params = params
|
|
45
|
+
@symbol = symbol
|
|
46
|
+
|
|
47
|
+
#specific data
|
|
48
|
+
@fields = Hash.new { |h,k| raise IndexError, "No member '#{k}' available." }.merge({
|
|
49
|
+
:raw => @raw,
|
|
50
|
+
:prefix => @prefix,
|
|
51
|
+
:command => @command,
|
|
52
|
+
:params => @params,
|
|
53
|
+
:symbol => @symbol,
|
|
54
|
+
:from => nil,
|
|
55
|
+
:for => nil,
|
|
56
|
+
:channel => nil,
|
|
57
|
+
:text => nil,
|
|
58
|
+
})
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def initialize_copy(original) #:nodoc:
|
|
62
|
+
super
|
|
63
|
+
@client = original.instance_variable_get(:@client)
|
|
64
|
+
@fields = original.to_hash
|
|
65
|
+
@raw = @fields[:raw]
|
|
66
|
+
@prefix = @fields[:prefix]
|
|
67
|
+
@command = @fields[:command]
|
|
68
|
+
@params = @fields[:params]
|
|
69
|
+
@symbol = @fields[:symbol]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def answer(text)
|
|
73
|
+
reply = channel || from
|
|
74
|
+
case @symbol
|
|
75
|
+
when :PRIVMSG: @client.irc.privmsg(text, reply)
|
|
76
|
+
when :NOTICE: @client.irc.notice(text, reply)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def from
|
|
81
|
+
@fields[:from]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def for
|
|
85
|
+
@fields[:for]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def channel
|
|
89
|
+
@fields[:channel]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def text
|
|
93
|
+
@fields[:text]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# access to raw parsed data
|
|
97
|
+
def [](index)
|
|
98
|
+
@fields[index.to_sym]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def []=(index, value)
|
|
102
|
+
raise NoMethodError, "Can't write to #{index}" unless respond_to?("#{index}=")
|
|
103
|
+
index = index.to_sym
|
|
104
|
+
@fields[index] = value
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def has_key?(key)
|
|
108
|
+
@fields.has_key?(key.to_sym)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def create_method(name, &code)
|
|
112
|
+
singleton = class << self; self; end
|
|
113
|
+
singleton.send(:define_method, name, &code)
|
|
114
|
+
name
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# create a member with it's value, if writable is true, it creates a member= method too
|
|
118
|
+
def create_member(index, value=nil, writable=false)
|
|
119
|
+
index = index.to_sym
|
|
120
|
+
raise IndexError, "Member '#{index}' exists already" if @fields.has_key?(index)
|
|
121
|
+
singleton = class << self; self; end
|
|
122
|
+
singleton.send(:define_method, index) { @fields[index] }
|
|
123
|
+
singleton.send(:define_method, "#{index}=") { |val| @fields[index] = val } if writable
|
|
124
|
+
@fields[index] = value
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# alter a member value with it's value
|
|
128
|
+
# should not be used other than by Butler::IRC::Parser
|
|
129
|
+
def alter_member(index, value=nil, create=false)
|
|
130
|
+
index = index.to_sym
|
|
131
|
+
if @fields.has_key?(index)
|
|
132
|
+
@fields[index] = value
|
|
133
|
+
elsif create then
|
|
134
|
+
create_member(index, value)
|
|
135
|
+
else
|
|
136
|
+
raise IndexError, "No member '#{index}' available."
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# delete a field
|
|
141
|
+
def delete_member(index)
|
|
142
|
+
index = index.to_sym
|
|
143
|
+
raise IndexError, "No member '#{index}' available." unless @fields.has_key?(index)
|
|
144
|
+
remove_method(index)
|
|
145
|
+
remove_method("#{index}=") if respond_to?("#{index}=")
|
|
146
|
+
@fields.delete(index)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# change charset encoding
|
|
150
|
+
def transcode!(from, to)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def ===(other)
|
|
154
|
+
case other
|
|
155
|
+
when Symbol: @symbol == other
|
|
156
|
+
when Regexp: @text && @text =~ other
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# return a hash of the fields
|
|
161
|
+
def to_hash
|
|
162
|
+
@fields.dup
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def hash #:nodoc:
|
|
166
|
+
@raw.hash
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def eql?(other) #:nodoc:
|
|
170
|
+
@raw == other.raw
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def inspect #:nodoc:
|
|
174
|
+
fields = @fields.dup
|
|
175
|
+
#[:raw, :prefix, :command, :params, :command_raw]
|
|
176
|
+
[:raw, :command, :prefix, :params].each { |field| fields.delete(field) }
|
|
177
|
+
fields = fields.map { |k,v| "#{k}=#{v.inspect}" }.join(" ")
|
|
178
|
+
"#<%s:0x%x\n%s\n%s>" % [self.class, object_id, @raw.inspect, fields]
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
alias to_s inspect
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
require 'butler/irc/channels'
|
|
10
|
+
require 'butler/irc/hostmask'
|
|
11
|
+
require 'butler/irc/message'
|
|
12
|
+
require 'butler/irc/parser/commands'
|
|
13
|
+
require 'butler/irc/string'
|
|
14
|
+
require 'butler/irc/users'
|
|
15
|
+
require 'ruby/exception/detailed'
|
|
16
|
+
require 'ruby/hash/zip'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Butler
|
|
21
|
+
module IRC
|
|
22
|
+
# Parses messages, automatically converts
|
|
23
|
+
# provides a parser that automatically connects users and channels
|
|
24
|
+
# regarding who myself is (out_of_sight, back_in_sight for users)
|
|
25
|
+
# allows creation of dialogs from privmsg and notice messages
|
|
26
|
+
class Parser
|
|
27
|
+
# RFC 2812, Parser itself uses a simplified matching
|
|
28
|
+
module Expressions
|
|
29
|
+
Special = /[\[\]\\`_^{|}]/
|
|
30
|
+
Letter = /[A-Za-z]/
|
|
31
|
+
Hex = /[\dA-Fa-f]/
|
|
32
|
+
ChannelID = /[A-Z\d]{5}/
|
|
33
|
+
Chanstring = /[^\x00\x07\x10\x0D\x20,:]/
|
|
34
|
+
Channel = /(?:[#+&]|!#{ChannelID})#{Chanstring}(?::#{Chanstring})?/
|
|
35
|
+
User = /[^\x00\x10\x0D\x20@]/
|
|
36
|
+
Nick = /[A-Za-z\[\]\\`_^{|}][A-Za-z\d\[\]\\`_^{|}-]*/
|
|
37
|
+
Command = /[A-Za-z]+|\d{3}/
|
|
38
|
+
IP4addr = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/
|
|
39
|
+
IP6addr = /[\dA-Fa-f](?::[\dA-Fa-f]){7}|0:0:0:0:0:(?:0|[Ff]{4}):#{IP4addr}/
|
|
40
|
+
Hostaddr = /#{IP4addr}|#{IP6addr}/
|
|
41
|
+
Shortname = /[A-Za-z0-9][A-Za-z0-9-]*/
|
|
42
|
+
Hostname = /#{Shortname}(?:\.#{Shortname})*/
|
|
43
|
+
Host = /#{Hostname}|#{Hostaddr}/
|
|
44
|
+
Prefix = /#{Hostname}|#{Nick}(?:(?:!#{User})?@#{Host})?/
|
|
45
|
+
Params = /.*/ # FIXME
|
|
46
|
+
Message = /(:#{Prefix} )?#{Command}(#{Params})?/
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class InvalidMessageFormat < RuntimeError; end
|
|
50
|
+
class UnknownCommand < RuntimeError; end
|
|
51
|
+
module ParseError
|
|
52
|
+
include Exception::Detailed
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
RMessage = /\A(?::([^ \0]+) )?([A-Za-z\d]+|\d{3})(?: (.*))?\z/
|
|
56
|
+
RHostmask = /(#{Expressions::Nick})(?:(?:!(#{Expressions::User}))?@(#{Expressions::Host}))?/
|
|
57
|
+
|
|
58
|
+
attr_reader :client
|
|
59
|
+
attr_reader :users
|
|
60
|
+
attr_reader :channels
|
|
61
|
+
|
|
62
|
+
def initialize(client, users, channels)
|
|
63
|
+
@client = client
|
|
64
|
+
@users = users
|
|
65
|
+
@channels = channels
|
|
66
|
+
@commands = Commands.new
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# parses an incomming message and returns a Message object from which you
|
|
70
|
+
# can easily access parsed data.
|
|
71
|
+
# Expects the newlines to be already chomped off.
|
|
72
|
+
def server_message(raw)
|
|
73
|
+
prefix, command, params, symbol, from = nil
|
|
74
|
+
|
|
75
|
+
# Basic analysis of the message
|
|
76
|
+
raise InvalidMessageFormat, raw unless matched = raw.match(RMessage)
|
|
77
|
+
prefix, command, params = *matched.captures
|
|
78
|
+
command.downcase!
|
|
79
|
+
|
|
80
|
+
# Parse prefix if possible (<nick>!<user>@<host>)
|
|
81
|
+
from = @users.create(*matched.captures) if prefix and matched = prefix.match(RHostmask)
|
|
82
|
+
|
|
83
|
+
# in depth analyzis of the message
|
|
84
|
+
parser = @commands[command]
|
|
85
|
+
symbol = parser.symbol
|
|
86
|
+
message = Message.new(@client, symbol, raw, prefix, command, params)
|
|
87
|
+
message.alter_member(:from, from)
|
|
88
|
+
|
|
89
|
+
parser.create_fields(message)
|
|
90
|
+
|
|
91
|
+
if message.for then
|
|
92
|
+
if message.for.valid_channelname? then
|
|
93
|
+
channel = @channels.create(message.for)
|
|
94
|
+
message.alter_member(:channel, channel)
|
|
95
|
+
message.alter_member(:for, channel)
|
|
96
|
+
else
|
|
97
|
+
message.alter_member(:for, @users.create(message.for))
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
message.alter_member(:channel, @channels.create(message.channel)) if message.channel
|
|
101
|
+
|
|
102
|
+
parser.process(message, self)
|
|
103
|
+
|
|
104
|
+
return message
|
|
105
|
+
rescue IndexError
|
|
106
|
+
raise UnknownCommand, "Unknown command #{command}: #{raw.inspect}"
|
|
107
|
+
rescue => e
|
|
108
|
+
e.extend ParseError
|
|
109
|
+
e.prepend "Message: #{raw.inspect}"
|
|
110
|
+
raise e
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def leave_channel(message, reason1, reason2)
|
|
114
|
+
if message.from && message.channel then
|
|
115
|
+
message.from.delete_channel(message.channel, reason1)
|
|
116
|
+
message.channel.delete_user(message.from, reason1)
|
|
117
|
+
if message.from == @users.myself then
|
|
118
|
+
@channels.delete(message.channel)
|
|
119
|
+
@users.delete_channel(message.channel, reason2)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
require 'butler/irc/parser'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Butler
|
|
14
|
+
module IRC
|
|
15
|
+
class Parser
|
|
16
|
+
class Commands
|
|
17
|
+
def initialize(specifics=nil)
|
|
18
|
+
@commands = Hash.new { |h,k| raise IndexError, "Unknown command #{k}" }
|
|
19
|
+
file = "#{File.dirname(__FILE__)}/generic.rb"
|
|
20
|
+
instance_eval(File.read(file), file)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def add(raw, *args, &proc)
|
|
24
|
+
raise IndexError, "Command #{raw} is already registered. Did you want 'alter'?" if @commands.has_key?(raw)
|
|
25
|
+
@commands[raw.downcase] = Command.new(raw, *args, &proc)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def alter(raw, *args, &proc)
|
|
29
|
+
raise IndexError, "Command #{raw} is not registered. Did you want 'add'?" unless @commands.has_key?(raw)
|
|
30
|
+
@commands[raw.downcase] = Command.new(raw, *args, &proc)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def [](raw)
|
|
34
|
+
@commands[raw.downcase]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def inspect
|
|
38
|
+
"#<%s:0x%x>" % [self.class, object_id]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Provides parsing information about specific commands.
|
|
43
|
+
class Command
|
|
44
|
+
attr_reader :raw
|
|
45
|
+
attr_reader :symbol
|
|
46
|
+
attr_reader :matcher
|
|
47
|
+
attr_reader :mapping
|
|
48
|
+
attr_reader :processor
|
|
49
|
+
|
|
50
|
+
# See Butler::IRC::COMMANDS for samples on instanciation of
|
|
51
|
+
# Butler::IRC::Command objects.
|
|
52
|
+
def initialize(raw, symbol, matcher=nil, mapping=nil, &processor)
|
|
53
|
+
@raw = raw
|
|
54
|
+
@symbol = symbol
|
|
55
|
+
@matcher = matcher
|
|
56
|
+
@mapping = mapping
|
|
57
|
+
@processor = processor
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def match(message)
|
|
61
|
+
@matcher.match(message)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def fields(message)
|
|
65
|
+
return nil unless @matcher and match = @matcher.match(message.params)
|
|
66
|
+
Hash.zip(@mapping, match.captures)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def create_fields(message)
|
|
70
|
+
if @matcher and match = @matcher.match(message.params) then
|
|
71
|
+
@mapping.zip(match.captures) { |name, value|
|
|
72
|
+
message.alter_member(name, value, true)
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def process(message, parser)
|
|
78
|
+
@processor.call(message, parser) if @processor
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# A list with all known IRC-Commands and it's parsing instructions
|
|
10
|
+
# Commands with __ in it are customs, not verified towards any standard.
|
|
11
|
+
|
|
12
|
+
#Text based codes
|
|
13
|
+
add("error", :ERROR) # ERROR :<error-message>
|
|
14
|
+
|
|
15
|
+
add("invite", :INVITE, /^([^\s]*) :(.*)/, [:invited, :channel])
|
|
16
|
+
|
|
17
|
+
add("join", :JOIN, /^:(.*)/, [:channel]) { |message, parser|
|
|
18
|
+
if message.from && message.channel then
|
|
19
|
+
message.from.add_channel(message.channel, :join)
|
|
20
|
+
message.channel.add_user(message.from, :join)
|
|
21
|
+
end
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
add("kick", :KICK, /^([^\s]*) ([^\s]*) :(.*)/, [:channel, :for, :text]) { |message, parser|
|
|
25
|
+
parser.leave_channel(message, :kick, :kicked)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
add("kill", :KILL, /^([^\s]*) ([^\s]*) (.*)/, [:channel, :for, :text]) { |message, parser|
|
|
29
|
+
if message.for then
|
|
30
|
+
message.for.kill
|
|
31
|
+
parser.channels.delete_user(message.for, :kill)
|
|
32
|
+
end
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# FIXME, really ':?' or just plain ':'?
|
|
36
|
+
add("mode", :MODE, /^([^\s]*) :?(.*)/, [:for, :arguments]) { |message, parser|
|
|
37
|
+
modifiers = message[:arguments].split(" ")
|
|
38
|
+
modes = modifiers.shift.split("")
|
|
39
|
+
flags = {"o" => User::Flags::OP, "v" => User::Flags::VOICE, "u" => User::Flags::UOP}
|
|
40
|
+
message.create_member(:modes, [])
|
|
41
|
+
argumentIndex = 0
|
|
42
|
+
direction = "+"
|
|
43
|
+
|
|
44
|
+
modes.each { |mode|
|
|
45
|
+
# MODEs direction
|
|
46
|
+
if (["+", "-"].include?(mode)) then
|
|
47
|
+
direction = mode
|
|
48
|
+
# MODEs taking an argument
|
|
49
|
+
elsif (["k", "o", "v", "u"].include?(mode) || (mode == "l" && direction == "+")) then
|
|
50
|
+
if ["o", "v", "u"].include?(mode) then
|
|
51
|
+
if (direction == "+") then
|
|
52
|
+
parser.users[modifiers[argumentIndex]].add_flags(message.channel, flags[mode]) #adding flags to user
|
|
53
|
+
else
|
|
54
|
+
parser.users[modifiers[argumentIndex]].delete_flags(message.channel, flags[mode]) #removing flags from user
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
message.modes << [direction, mode, modifiers[argumentIndex]]
|
|
58
|
+
argumentIndex = argumentIndex+1
|
|
59
|
+
# MODEs without argument
|
|
60
|
+
else
|
|
61
|
+
message.modes << [direction, mode, nil]
|
|
62
|
+
end
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
add("nick", :NICK, /^:(.*)/, [:nick]) { |message, parser|
|
|
66
|
+
message.create_member(:old_nick, message.from.nick)
|
|
67
|
+
message.from.nick = message.nick if message.from
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
add("notice", :NOTICE, /([^\s]+) :(.*)/, [:for, :text]) { |message, parser|
|
|
71
|
+
if message.channel then
|
|
72
|
+
message.create_member(:realm, :public)
|
|
73
|
+
message.create_method(:private?) { false }
|
|
74
|
+
message.create_method(:public?) { true }
|
|
75
|
+
else
|
|
76
|
+
message.create_member(:realm, :private)
|
|
77
|
+
message.create_method(:private?) { true }
|
|
78
|
+
message.create_method(:public?) { false }
|
|
79
|
+
end
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
add("part", :PART, /^([^\x00\x07\x10\x0D\x20,:]+)(?: :(.*))?/, [:channel, :reason]) { |message, parser|
|
|
83
|
+
parser.leave_channel(message, :part, :parted)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
add("ping", :PING, /:(.*)/, [:pong])
|
|
87
|
+
|
|
88
|
+
add("pong", :PONG)
|
|
89
|
+
|
|
90
|
+
add("privmsg", :PRIVMSG, /([^\s]+) :(.*)/, [:for, :text]) { |message, parser|
|
|
91
|
+
if message.channel then
|
|
92
|
+
message.create_member(:realm, :public)
|
|
93
|
+
message.create_method(:private?) { false }
|
|
94
|
+
message.create_method(:public?) { true }
|
|
95
|
+
else
|
|
96
|
+
message.create_member(:realm, :private)
|
|
97
|
+
message.create_method(:private?) { true }
|
|
98
|
+
message.create_method(:public?) { false }
|
|
99
|
+
end
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
add("quit", :QUIT, /(.*)/, [:text]) { |message, parser|
|
|
103
|
+
if message.from then
|
|
104
|
+
message.from.quit
|
|
105
|
+
parser.channels.delete_user(message.from, :quit)
|
|
106
|
+
parser.users.delete(message.from, :quit)
|
|
107
|
+
end
|
|
108
|
+
}
|
|
109
|
+
add("topic", :TOPIC, /([^\s]+) :(.*)/, [:channel, :text])
|
|
110
|
+
|
|
111
|
+
#Unknown/Non-RFC codes
|
|
112
|
+
add("007", :UNK_007)
|
|
113
|
+
add("008", :UNK_008)
|
|
114
|
+
add("009", :UNK_009)
|
|
115
|
+
add("307", :RPL_REGISTERED_INFO) #FIXME non2812 "ConferenceRoom" bluewin, sent if a nick is registered
|
|
116
|
+
add("329", :RPL_CHANNEL_INFO) #channel creation time
|
|
117
|
+
add("377", :UNK_377)
|
|
118
|
+
|
|
119
|
+
#0** Codes
|
|
120
|
+
add("001", :RPL_WELCOME)
|
|
121
|
+
add("002", :RPL_YOURHOST)
|
|
122
|
+
add("003", :RPL_CREATED)
|
|
123
|
+
add("004", :RPL_MYINFO)
|
|
124
|
+
add("005", :RPL_ISUPPORT)
|
|
125
|
+
|
|
126
|
+
#2** Codes
|
|
127
|
+
add("200", :RPL_TRACELINK)
|
|
128
|
+
add("201", :RPL_TRACECONNECTING)
|
|
129
|
+
add("202", :RPL_TRACEHANDSHAKE)
|
|
130
|
+
add("203", :RPL_TRACEUNKNOWN)
|
|
131
|
+
add("204", :RPL_TRACEOPERATOR)
|
|
132
|
+
add("205", :RPL_TRACEUSER)
|
|
133
|
+
add("206", :RPL_TRACESERVER)
|
|
134
|
+
add("207", :RPL_TRACESERVICE)
|
|
135
|
+
add("208", :RPL_TRACENEWTYPE)
|
|
136
|
+
add("209", :RPL_TRACECLASS)
|
|
137
|
+
add("210", :RPL_TRACERECONNECT)
|
|
138
|
+
add("211", :RPL_STATSLINKINFO)
|
|
139
|
+
add("212", :RPL_STATSCOMMANDS)
|
|
140
|
+
add("213", :RPL_STATSCLINE)
|
|
141
|
+
add("214", :RPL_STATSNLINE)
|
|
142
|
+
add("215", :RPL_STATSILINE)
|
|
143
|
+
add("216", :RPL_STATSKLINE)
|
|
144
|
+
add("217", :RPL_STATSQLINE)
|
|
145
|
+
add("218", :RPL_STATSYLINE)
|
|
146
|
+
add("219", :RPL_ENDOFSTATS)
|
|
147
|
+
add("221", :RPL_UMODEIS)
|
|
148
|
+
add("231", :RPL_SERVICEINFO)
|
|
149
|
+
add("232", :RPL_ENDOFSERVICES)
|
|
150
|
+
add("233", :RPL_SERVICE)
|
|
151
|
+
add("234", :RPL_SERVLIST)
|
|
152
|
+
add("235", :RPL_SERVLISTEND)
|
|
153
|
+
add("240", :RPL_STATSVLINE)
|
|
154
|
+
add("241", :RPL_STATSLLINE)
|
|
155
|
+
add("242", :RPL_STATSUPTIME)
|
|
156
|
+
add("243", :RPL_STATSOLINE)
|
|
157
|
+
add("244", :RPL_STATSHLINE)
|
|
158
|
+
add("245", :RPL_STATSSLINE) # RFC 2812 seems to be erroneous, it assigns 244 double
|
|
159
|
+
add("246", :RPL_STATSPING)
|
|
160
|
+
add("247", :RPL_STATSBLINE)
|
|
161
|
+
add("250", :RPL_STATSCONN)
|
|
162
|
+
add("251", :RPL_LUSERCLIENT)
|
|
163
|
+
add("252", :RPL_LUSEROP)
|
|
164
|
+
add("253", :RPL_LUSERUNKNOWN)
|
|
165
|
+
add("254", :RPL_LUSERCHANNELS)
|
|
166
|
+
add("255", :RPL_LUSERME)
|
|
167
|
+
add("256", :RPL_ADMINME)
|
|
168
|
+
add("257", :RPL_ADMINLOC1)
|
|
169
|
+
add("258", :RPL_ADMINLOC2)
|
|
170
|
+
add("259", :RPL_ADMINEMAIL)
|
|
171
|
+
add("261", :RPL_TRACELOG)
|
|
172
|
+
add("262", :RPL_TRACEEND)
|
|
173
|
+
add("263", :RPL_TRYAGAIN)
|
|
174
|
+
add("265", :RPL_LOCALUSERS)
|
|
175
|
+
add("266", :RPL_GLOBALUSERS)
|
|
176
|
+
add("290", :RPL_IDENTIFY_MSG) # FIXME non2812 "hyperion-1.0.2b"
|
|
177
|
+
|
|
178
|
+
#3** Codes
|
|
179
|
+
add("300", :RPL_NONE)
|
|
180
|
+
add("301", :RPL_AWAY)
|
|
181
|
+
add("302", :RPL_USERHOST)
|
|
182
|
+
add("303", :RPL_ISON)
|
|
183
|
+
add("305", :RPL_UNAWAY)
|
|
184
|
+
add("306", :RPL_NOWAWAY)
|
|
185
|
+
add("311", :RPL_WHOISUSER, /^([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) \* :(.*)/, [:for, :nick, :user, :host, :real])
|
|
186
|
+
add("312", :RPL_WHOISSERVER)
|
|
187
|
+
add("313", :RPL_WHOISOPERATOR)
|
|
188
|
+
add("314", :RPL_WHOWASUSER)
|
|
189
|
+
add("315", :RPL_ENDOFWHO)
|
|
190
|
+
add("316", :RPL_WHOISCHANOP)
|
|
191
|
+
add("317", :RPL_WHOISIDLE, /^([^\s]+) ([^\s]+) ([^:]+) :(.*)/, [:for, :nick, :values, :descriptions]) { |message, parser|
|
|
192
|
+
values = message[:values].split(" ");
|
|
193
|
+
descriptions = message[:descriptions].split(", ").map { |desc| desc.gsub(" ", "_").to_sym };
|
|
194
|
+
message.delete(:values)
|
|
195
|
+
message.delete(:descriptions)
|
|
196
|
+
0.upto([values.length, descriptions.length].min-1) { |index|
|
|
197
|
+
message[descriptions[index]] = values[index]
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
add("318", :RPL_ENDOFWHOIS)
|
|
201
|
+
add("319", :RPL_WHOISCHANNELS, /^([^\s]+) ([^\s]+) :(.*)/, [:for, :nick, :channels]) { |message, parser|
|
|
202
|
+
# FIXME
|
|
203
|
+
message.alter_member(:channels, message.channels.split(" ").map { |channel| parser.channels.create(channel) })
|
|
204
|
+
}
|
|
205
|
+
add("320", :RPL_IDENTIFIED_TO_SERVICES) # possibly hyperion only
|
|
206
|
+
add("321", :RPL_LISTSTART)
|
|
207
|
+
add("322", :RPL_LIST, /^([^\s]+) ([^\s]+) (\d+) :(.*)/, [:for, :channelname, :usercount, :topic])
|
|
208
|
+
add("323", :RPL_LISTEND)
|
|
209
|
+
add("324", :RPL_CHANNELMODEIS)
|
|
210
|
+
add("325", :RPL_UNIQOPIS)
|
|
211
|
+
add("331", :RPL_NOTOPIC)
|
|
212
|
+
# :irc.server.net 332 YourNickname #channel :Topic
|
|
213
|
+
add("332", :RPL_TOPIC, /^([^\s]+) ([^\s]+) :(.*)/, [:for, :channel, :topic]) { |message, parser|
|
|
214
|
+
message.channel.topic.text = message[:topic]
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
# :irc.server.net 333 YourNickname #channel SetByNick 1139902138
|
|
218
|
+
add("333", :RPL_TOPIC_INFO, /^([^\s]+) ([^\s]+) ([^\s]+) (\d+)/, [:for, :channel, :set_by, :set_at]) { |message, parser|
|
|
219
|
+
topic = message.channel.topic
|
|
220
|
+
topic.set_by = message[:set_by]
|
|
221
|
+
topic.set_at = message[:set_at]
|
|
222
|
+
}
|
|
223
|
+
add("341", :RPL_INVITING)
|
|
224
|
+
add("342", :RPL_SUMMONING)
|
|
225
|
+
add("343", :RPL__MAINTENANCE) #mainenance notice?
|
|
226
|
+
add("346", :RPL_INVITELIST)
|
|
227
|
+
add("347", :RPL_ENDOFINVITELIST)
|
|
228
|
+
add("348", :RPL_EXCEPTLIST)
|
|
229
|
+
add("349", :RPL_ENDOFEXCEPTLIST)
|
|
230
|
+
add("351", :RPL_VERSION)
|
|
231
|
+
# :irc.server.net 352 YourNickname <channel> <user> <host> <server> <nick> ( "H" / "G" > ["*"] [ ( "@" / "+" ) ] :<hopcount> <real name>
|
|
232
|
+
add("352", :RPL_WHOREPLY,
|
|
233
|
+
/([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([HG])[*%]{0,2}([@+-]{0,3}) :(\d+) (.*)/,
|
|
234
|
+
[:for, :channel, :user, :host, :server, :nick, :status, :flags, :hopcount, :real]) { |message, parser|
|
|
235
|
+
#"for", "channel", "user", "host", "server", "nick", "status", "flags", "hopcount", "real"
|
|
236
|
+
user = parser.users.create(message[:nick])
|
|
237
|
+
user.update(message[:user], message[:host], message[:real])
|
|
238
|
+
user.away = message[:status] == "G"
|
|
239
|
+
user.add_channel(message.channel, :joined)
|
|
240
|
+
message.channel.add_user(user, :joined)
|
|
241
|
+
user.add_flags(message.channel, message[:flags].to_flags)
|
|
242
|
+
}
|
|
243
|
+
add("353", :RPL_NAMEREPLY, /([^\s]+) [=@] ([^\s]+) :(.*)/, [:for, :channel, :users]) { |message, parser|
|
|
244
|
+
users = message[:users]
|
|
245
|
+
message.alter_member(:users, [])
|
|
246
|
+
users.split(/ /).each { |nick|
|
|
247
|
+
user = parser.users.create(nick)
|
|
248
|
+
message[:users] << user
|
|
249
|
+
user.add_channel(message.channel, :joined)
|
|
250
|
+
message.channel.add_user(user, :joined)
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
add("361", :RPL_KILLDONE)
|
|
254
|
+
add("362", :RPL_CLOSING)
|
|
255
|
+
add("363", :RPL_CLOSEEND)
|
|
256
|
+
add("364", :RPL_LINKS)
|
|
257
|
+
add("365", :RPL_ENDOFLINKS)
|
|
258
|
+
add("366", :RPL_ENDOFNAMES)
|
|
259
|
+
add("367", :RPL_BANLIST,
|
|
260
|
+
/([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) (\d+)/,
|
|
261
|
+
[:for, :channel, :banmask, :banned_by, :bantime]
|
|
262
|
+
) { |message, parser| #367 nickname #channel nick!user@host nickname 1140125288
|
|
263
|
+
message[:bantime] = Time.at(message[:bantime].to_i)
|
|
264
|
+
message[:banmask] = Hostmask.new(message[:banmask])
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
add("368", :RPL_ENDOFBANLIST)
|
|
268
|
+
add("369", :RPL_ENDOFWHOWAS)
|
|
269
|
+
add("371", :RPL_INFO)
|
|
270
|
+
add("372", :RPL_MOTD)
|
|
271
|
+
add("373", :RPL_INFOSTART)
|
|
272
|
+
add("374", :RPL_ENDOFINFO)
|
|
273
|
+
add("375", :RPL_MOTDSTART)
|
|
274
|
+
add("376", :RPL_ENDOFMOTD)
|
|
275
|
+
add("381", :RPL_YOUREOPER)
|
|
276
|
+
add("382", :RPL_REHASHING)
|
|
277
|
+
add("383", :RPL_YOURESERVICE)
|
|
278
|
+
add("384", :RPL_MYPORTIS)
|
|
279
|
+
add("386", :RPL_PASSWORDACCEPTED) # Custom (chatroom)
|
|
280
|
+
add("391", :RPL_TIME)
|
|
281
|
+
add("392", :RPL_USERSSTART)
|
|
282
|
+
add("393", :RPL_USERS)
|
|
283
|
+
add("394", :RPL_ENDOFUSERS)
|
|
284
|
+
add("395", :RPL_NOUSERS)
|
|
285
|
+
|
|
286
|
+
#4** Codes
|
|
287
|
+
add("401", :ERR_NOSUCHNICK)
|
|
288
|
+
add("402", :ERR_NOSUCHSERVER)
|
|
289
|
+
add("403", :ERR_NOSUCHCHANNEL)
|
|
290
|
+
add("404", :ERR_CANNOTSENDTOCHAN)
|
|
291
|
+
add("405", :ERR_TOOMANYCHANNELS)
|
|
292
|
+
add("406", :ERR_WASNOSUCHNICK)
|
|
293
|
+
add("407", :ERR_TOOMANYTARGETS)
|
|
294
|
+
add("408", :ERR_NOSUCHSERVICE)
|
|
295
|
+
add("409", :ERR_NOORIGIN)
|
|
296
|
+
add("411", :ERR_NORECIPIENT)
|
|
297
|
+
add("412", :ERR_NOTEXTTOSEND)
|
|
298
|
+
add("413", :ERR_NOTOPLEVEL)
|
|
299
|
+
add("414", :ERR_WILDTOPLEVEL)
|
|
300
|
+
add("415", :ERR_BADMASK)
|
|
301
|
+
add("421", :ERR_UNKNOWNCOMMAND)
|
|
302
|
+
add("422", :ERR_NOMOTD)
|
|
303
|
+
add("423", :ERR_NOADMININFO)
|
|
304
|
+
add("424", :ERR_FILEERROR)
|
|
305
|
+
add("431", :ERR_NONICKNAMEGIVEN)
|
|
306
|
+
add("432", :ERR_ERRONEUSNICKNAME)
|
|
307
|
+
add("433", :ERR_NICKNAMEINUSE)
|
|
308
|
+
add("436", :ERR_NICKCOLLISION)
|
|
309
|
+
add("437", :ERR_UNAVAILRESOURCE)
|
|
310
|
+
add("441", :ERR_USERNOTINCHANNEL)
|
|
311
|
+
add("442", :ERR_NOTONCHANNEL)
|
|
312
|
+
add("443", :ERR_USERONCHANNEL)
|
|
313
|
+
add("444", :ERR_NOLOGIN)
|
|
314
|
+
add("445", :ERR_SUMMONDISABLED)
|
|
315
|
+
add("446", :ERR_USERSDISABLED)
|
|
316
|
+
add("451", :ERR_NOTREGISTERED)
|
|
317
|
+
add("461", :ERR_NEEDMOREPARAMS)
|
|
318
|
+
add("462", :ERR_ALREADYREGISTRED)
|
|
319
|
+
add("463", :ERR_NOPERMFORHOST)
|
|
320
|
+
add("464", :ERR_PASSWDMISMATCH)
|
|
321
|
+
add("465", :ERR_YOUREBANNEDCREEP)
|
|
322
|
+
add("466", :ERR_YOUWILLBEBANNED)
|
|
323
|
+
add("467", :ERR_KEYSET)
|
|
324
|
+
add("471", :ERR_CHANNELISFULL)
|
|
325
|
+
add("472", :ERR_UNKNOWNMODE)
|
|
326
|
+
add("473", :ERR_INVITEONLYCHAN)
|
|
327
|
+
add("474", :ERR_BANNEDFROMCHAN)
|
|
328
|
+
add("475", :ERR_BADCHANNELKEY)
|
|
329
|
+
add("476", :ERR_BADCHANMASK)
|
|
330
|
+
add("477", :ERR_NOCHANMODES)
|
|
331
|
+
add("478", :ERR_BANLISTFULL)
|
|
332
|
+
add("481", :ERR_NOPRIVILEGES)
|
|
333
|
+
add("482", :ERR_CHANOPRIVSNEEDED)
|
|
334
|
+
add("483", :ERR_CANTKILLSERVER)
|
|
335
|
+
add("484", :ERR_RESTRICTED)
|
|
336
|
+
add("485", :ERR_UNIQOPPRIVSNEEDED)
|
|
337
|
+
add("491", :ERR_NOOPERHOST)
|
|
338
|
+
add("492", :ERR_NOSERVICEHOST)
|
|
339
|
+
|
|
340
|
+
#5** Codes
|
|
341
|
+
add("501", :ERR_UMODEUNKNOWNFLAG)
|
|
342
|
+
add("502", :ERR_USERSDONTMATCH)
|
|
343
|
+
add("505", :ERR__NOPRIVMSG)
|