irc_parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/LICENSE +21 -0
  2. data/README.md +105 -0
  3. data/Rakefile +155 -0
  4. data/extra/benchmark.rb +41 -0
  5. data/irc_parser.gemspec +98 -0
  6. data/lib/irc_parser.rb +25 -0
  7. data/lib/irc_parser/factory.erb +53 -0
  8. data/lib/irc_parser/helper.rb +71 -0
  9. data/lib/irc_parser/messages.rb +96 -0
  10. data/lib/irc_parser/messages/commands.rb +274 -0
  11. data/lib/irc_parser/messages/errors.rb +51 -0
  12. data/lib/irc_parser/messages/replies.rb +212 -0
  13. data/lib/irc_parser/parser.rb +557 -0
  14. data/lib/irc_parser/parser.rl +89 -0
  15. data/spec/fixtures/from_weechat.rb +24 -0
  16. data/spec/fixtures/inbound.log +3959 -0
  17. data/spec/irc_parser/helper_spec.rb +32 -0
  18. data/spec/irc_parser/irc_parser_spec.rb +12 -0
  19. data/spec/irc_parser/messages_spec.rb +195 -0
  20. data/spec/irc_parser/parser_spec.rb +9 -0
  21. data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_1_password_message_spec.rb +28 -0
  22. data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_2_nick_message_spec.rb +35 -0
  23. data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_3_user_message_spec.rb +47 -0
  24. data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_4_server_message_spec.rb +33 -0
  25. data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_5_oper_spec.rb +17 -0
  26. data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_6_quit_spec.rb +17 -0
  27. data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_7_server_quit_message_spec.rb +32 -0
  28. data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_1_join_message_spec.rb +65 -0
  29. data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_2_part_message_spec.rb +23 -0
  30. data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_3_1_channel_modes_spec.rb +159 -0
  31. data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_3_2_user_modes_spec.rb +55 -0
  32. data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_4_topic_message_spec.rb +36 -0
  33. data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_5_names_message_spec.rb +25 -0
  34. data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_6_list_message_spec.rb +23 -0
  35. data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_7_invite_message_spec.rb +31 -0
  36. data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_8_kick_command_spec.rb +56 -0
  37. data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_1_version_message_spec.rb +30 -0
  38. data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_2_stats_message_spec.rb +32 -0
  39. data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_3_links_message_spec.rb +31 -0
  40. data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_4_time_message_spec.rb +34 -0
  41. data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_5_connect_message_spec.rb +32 -0
  42. data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_6_trace_message_spec.rb +28 -0
  43. data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_7_admin_command_spec.rb +28 -0
  44. data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_8_info_command_spec.rb +38 -0
  45. data/spec/irc_parser/rfc1459/4_4_sending_messages/4_4_1_private_messages_spec.rb +63 -0
  46. data/spec/irc_parser/rfc1459/4_4_sending_messages/4_4_2_notice_spec.rb +63 -0
  47. data/spec/irc_parser/rfc1459/4_5_user_based_queries/4_5_1_who_query_spec.rb +27 -0
  48. data/spec/irc_parser/rfc1459/4_5_user_based_queries/4_5_2_whois_query_spec.rb +27 -0
  49. data/spec/irc_parser/rfc1459/4_5_user_based_queries/4_5_3_whowas_spec.rb +40 -0
  50. data/spec/irc_parser/rfc1459/4_6_miscellaneous_messages/4_6_1_kill_message_spec.rb +20 -0
  51. data/spec/irc_parser/rfc1459/4_6_miscellaneous_messages/4_6_2_ping_message_spec.rb +35 -0
  52. data/spec/irc_parser/rfc1459/4_6_miscellaneous_messages/4_6_3_pong_message_spec.rb +26 -0
  53. data/spec/irc_parser/rfc1459/4_6_miscellaneous_messages/4_6_4_error_spec.rb +26 -0
  54. data/spec/irc_parser/rfc1459/5_0_optionals/5_1_0_away_spec.rb +25 -0
  55. data/spec/irc_parser/rfc1459/5_0_optionals/5_2_0_rehash_message_spec.rb +14 -0
  56. data/spec/irc_parser/rfc1459/5_0_optionals/5_3_0_restart_message_spec.rb +14 -0
  57. data/spec/irc_parser/rfc1459/5_0_optionals/5_4_0_summon_message_spec.rb +28 -0
  58. data/spec/irc_parser/rfc1459/5_0_optionals/5_5_0_users_spec.rb +27 -0
  59. data/spec/irc_parser/rfc1459/5_0_optionals/5_6_0_operwall_message_spec.rb +17 -0
  60. data/spec/irc_parser/rfc1459/5_0_optionals/5_7_0_userhost_message_spec.rb +16 -0
  61. data/spec/irc_parser/rfc1459/5_0_optionals/5_8_0_ison_message_spec.rb +16 -0
  62. data/spec/irc_parser/rfc1459/6_0_replies/6_1_error_parsing_spec.rb +488 -0
  63. data/spec/irc_parser/rfc1459/6_0_replies/6_2_command_responses_generation_spec.rb +934 -0
  64. data/spec/irc_parser/rfc2812/5_1_command_responses/5_1_command_responses_spec.rb +63 -0
  65. data/spec/spec_helper.rb +12 -0
  66. data/spec/support/messages_helper.rb +24 -0
  67. data/spec/support/simplecov.rb +12 -0
  68. metadata +185 -0
@@ -0,0 +1,53 @@
1
+ #class Struct::<%= name %>
2
+
3
+ def initialize(prefix = nil, arguments = nil)
4
+ arguments ? super(prefix, *arguments) : super(prefix)
5
+
6
+ <% if @postfix_format %>
7
+ self.postfix ||= <%= @postfix_format.inspect %>
8
+ <% end %>
9
+
10
+ <% csv_arguments.each do |argument| %>
11
+ self[<%=argument[:name].inspect%>] = Array(self[<%=argument[:name].inspect%>]).join(<%=argument[:csv].inspect%>)
12
+ <% end %>
13
+
14
+ yield self if block_given?
15
+ end
16
+
17
+ def format_postfix(hash)
18
+ self.postfix = <%= @postfix_format.inspect %> % hash
19
+ end
20
+
21
+ EMPTY_STRING = "".freeze
22
+
23
+ # Generates the IRC message. It will have the form:
24
+ # ':prefix IDENTIFIER param1 param2 :postfix thay may have spaces\r\n'
25
+ def to_s
26
+ result = "#{prefix && prefix != EMPTY_STRING ? ":#{prefix} " : nil}<%= @identifier %>"
27
+
28
+ <% arguments.each_with_index do |argument, index| %>
29
+ part = self[<%= argument[:name].inspect %>]
30
+ <% if argument.member?(:default) %>
31
+ result << " " << ((part && part != EMPTY_STRING) ? part.to_s : <%= argument[:default].inspect %>)
32
+ <% else %>
33
+ result << " " << part.to_s if (part && part != EMPTY_STRING)
34
+ <% end %>
35
+ <% end %>
36
+
37
+ result << " :#{postfix}" if postfix && postfix != EMPTY_STRING
38
+ result << "\r\n"
39
+ end
40
+ alias_method :to_str, :to_s
41
+
42
+ <% csv_arguments.each do |argument| %>
43
+ def <%=argument[:name]%>
44
+ self[<%=argument[:name].inspect%>].split(<%=argument[:csv].inspect%>)
45
+ end
46
+
47
+ def <%=argument[:name]%>=(val)
48
+ self[<%=argument[:name].inspect%>] = Array(val).join(<%=argument[:csv].inspect%>)
49
+ end
50
+ <% end %>
51
+
52
+ #end
53
+ # vim: set ft=ruby ts=8 sw=2 tw=0 :
@@ -0,0 +1,71 @@
1
+ module IRCParser
2
+ module Helper
3
+ extend self
4
+
5
+ def underscore(string)
6
+ string.to_s.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
7
+ end
8
+
9
+ def parse_regexp(text)
10
+ /#{ text.to_s.split(".").join("\\.").gsub(/\*|\?/, ".*") }/
11
+ end
12
+
13
+ # http://tools.ietf.org/html/rfc1459#section-4.3.2
14
+ # c - returns a list of servers which the server may connect to or allow connections from;
15
+ # h - returns a list of servers which are either forced to be treated as leaves or allowed to act as hubs;
16
+ # i - returns a list of hosts which the server allows a client to connect from;
17
+ # k - returns a list of banned username/hostname combinations for that server;
18
+ # l - returns a list of the server's connections, showing how long each connection has been established and the traffic
19
+ # over that connection in bytes and messages for each direction;
20
+ # m - returns a list of commands supported by the server and the usage count for each if the usage count is non zero;
21
+ # o - returns a list of hosts from which normal clients may become operators;
22
+ # y - show Y (Class) lines from server's configuration file;
23
+ # u - returns a string showing how long the server has been up.
24
+ STATS_MODES = %w|c h i k l m o y u|
25
+
26
+ NICK_REGEXP = /^[a-zA-Z]+[a-zA-Z0-9]*/
27
+
28
+ def valid_nick?(nick)
29
+ nick =~ NICK_REGEXP
30
+ end
31
+
32
+ def invalid_nick?(nick)
33
+ not valid_nick?(nick)
34
+ end
35
+
36
+ module NicknameHelpers
37
+ %w|valid_nick? invalid_nick?|.each do |meth|
38
+ define_method(meth) { IRCParser::Helper.send(meth, self) }
39
+ end
40
+ end
41
+
42
+ CHANNEL_PREFIXES = {
43
+ :normal => "#",
44
+ :local => "&",
45
+ :modeless => "+",
46
+ :safe => "!"
47
+ }
48
+
49
+ CHANNEL_REGEXP = /^[#{CHANNEL_PREFIXES.values.join("|")}][a-zA-Z0-9]+/
50
+
51
+ def valid_channel_name?(name)
52
+ name.to_s =~ CHANNEL_REGEXP
53
+ end
54
+
55
+ def invalid_channel_name?(name)
56
+ not valid_channel_name?(name)
57
+ end
58
+
59
+ CHANNEL_PREFIXES.each do |channel_mode, prefix|
60
+ define_method("#{channel_mode}_channel?") do |name|
61
+ name.to_s[0, 1] == prefix
62
+ end
63
+ end
64
+
65
+ module Channel
66
+ (CHANNEL_PREFIXES.keys.map {|mode| "#{mode}_channel?" } + %w|valid_channel_name? invalid_channel_name?|).each do |meth|
67
+ define_method(meth) { IRCParser::Helper.send(meth, self) }
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,96 @@
1
+ require 'erb'
2
+
3
+ module IRCParser
4
+ module Messages
5
+ # Store all known message classes under convenient keys so they are easy to find.
6
+ ALL = Hash.new
7
+
8
+ # Create a Message class and save it on the IRCParser::Messages::ALL hash
9
+ # for easy retrieval with different names.
10
+ def self.define_message(name, *arguments, &block)
11
+ klass = message_class(name, *arguments, &block)
12
+ [klass.name.to_s, klass.name.to_s.upcase, klass.to_sym.to_s, klass.to_sym.to_s.upcase, klass.identifier.to_s].uniq.each do |key|
13
+ IRCParser::Messages::ALL[key] = klass
14
+ IRCParser::Messages::ALL[key.to_sym] = klass
15
+ end
16
+ IRCParser::Messages::ALL[klass.identifier.to_s.to_i] = klass if klass.identifier.to_s =~ /^\d+$/
17
+ const_set(name, klass)
18
+ end
19
+
20
+ IMPLEMENTATION_PATH = File.expand_path(File.join(File.dirname(__FILE__), "factory.erb"))
21
+ IMPLEMENTATION = File.read(IMPLEMENTATION_PATH)
22
+
23
+ # Creates a message class, which inherits from a ruby Struct to save the different message params.
24
+ def self.message_class(name, *arguments, &block)
25
+ # # #
26
+ # Prepare information needed to generate the classes
27
+ # # #
28
+
29
+ # klass.to_sym is convenient name for storing the class in the ALL hash. E.g.: AWAY -> :away
30
+ to_sym = IRCParser::Helper.underscore(name).to_sym
31
+ identifier = (arguments.first.is_a?(String) ? arguments.shift : name).to_s.upcase.to_sym
32
+ postfix_format = arguments.pop if arguments.last.is_a?(String)
33
+ postfix_alias = arguments.pop.keys.first if arguments.last.is_a?(Hash) && arguments.last.values.first == :postfix
34
+
35
+ placeholders = 0 # used to give name to placeholder arguments.
36
+
37
+ # normalize the parameter information so it is easy to work with.
38
+ arguments.map! do |arg|
39
+ if arg.is_a?(Hash) then {:name => arg.keys.first}.merge(arg.values.first)
40
+ elsif arg.is_a?(String) then {:name => "placeholder_#{placeholders += 1}", :default => arg}
41
+ else {:name => arg}
42
+ end
43
+ end
44
+
45
+ # we will generate accessors to move from and to char separated values (char can be a comma, a space, etc..)
46
+ csv_arguments = arguments.select { |arg| arg.has_key?(:csv) }
47
+
48
+ # # #
49
+ # Generate the class, inhereting from Struct, and generate its methods.
50
+ # # #
51
+
52
+ klass = Struct.new("IRC#{name}", *([:prefix] + (arguments.map { |arg| arg[:name] } + [:postfix]))) do
53
+ @name, @to_sym, @identifier, @postfix_format = name, to_sym, identifier, postfix_format
54
+
55
+ extend ClassMethods
56
+
57
+ # It would be trivial to rewrite the code on factory.erb using define_methods,
58
+ # but the code generated using eval runs about 10% faster, with the only caveat
59
+ # *sometimes* is a little harder to follow backtraces when errors occur.
60
+ class_eval(ERB.new(IMPLEMENTATION).result(binding), IMPLEMENTATION_PATH)
61
+
62
+ [postfix_alias, :body, :message].compact.uniq.each do |attr|
63
+ alias_method attr, :postfix
64
+ alias_method "#{attr}=", :postfix=
65
+ end
66
+ end
67
+
68
+ # # #
69
+ # Evaluate any additional configuration block passed to this method, and return the resulting class.
70
+ # # #
71
+
72
+ klass.class_eval(&block) if block
73
+ klass
74
+ end
75
+
76
+ module ClassMethods
77
+ attr_reader :name, :to_sym, :identifier, :postfix_format
78
+
79
+ def is_error?
80
+ !(@name !~ /^Err[A-Z]/)
81
+ end
82
+
83
+ def is_reply?
84
+ !(@name !~ /^Rpl[A-Z]/)
85
+ end
86
+
87
+ def is_command?
88
+ !(@name =~ /^(Rpl|Err)[A-Z]/)
89
+ end
90
+ end
91
+
92
+ require 'irc_parser/messages/commands'
93
+ require 'irc_parser/messages/errors'
94
+ require 'irc_parser/messages/replies'
95
+ end
96
+ end
@@ -0,0 +1,274 @@
1
+ module IRCParser::Messages
2
+ define_message :Admin , :target
3
+ define_message :Away , :away_message => :postfix
4
+ define_message :Connect , :target_server, :port, :remote_server
5
+ define_message :Info , :target
6
+ define_message :Invite , :to_nick, :channel
7
+ define_message :Join , {:channels => {:csv => ","}}, {:keys => {:csv => ","}}
8
+ define_message :Kick , {:channels => {:csv => ","}}, {:users => {:csv => ","}}, :kick_message => :postfix
9
+ define_message :Kill , :nick, :kill_message => :postfix
10
+ define_message :Links , :remote_server, :server_mask
11
+ define_message :List , :channels => {:csv => ","}
12
+ define_message :Names , :channels => {:csv => ","}
13
+ define_message :Oper , :user, :password
14
+ define_message :Part , {:channels => {:csv => ","}}, :part_message
15
+ define_message :Pass , :password
16
+ define_message :Ping , :target, :final_target
17
+ define_message :Pong , :server, :target
18
+ define_message :Quit , :quit_message => :postfix
19
+ define_message :Rehash
20
+ define_message :Restart
21
+ define_message :SQuit , :server, :reason => :postfix
22
+ define_message :Stats , :mode, :server
23
+ define_message :Time , :for_server
24
+ define_message :Topic , :channel, :topic => :postfix
25
+ define_message :Trace , :target
26
+ define_message :User , :user, {:mode => { :default => "*" }}, {:servername => { :default => "*" }}, :realname => :postfix
27
+ define_message :Users , :target
28
+ define_message :Version , :server
29
+ define_message :WallOps , :wall_message => :postfix
30
+
31
+ define_message :Mode, :target, :flags, :limit, :user, :ban_mask do
32
+
33
+ # Channel Parameters: <channel> {[+|-]|o|p|s|i|t|n|b|v} [<limit>] [<user>] [<ban mask>]
34
+ # User Parameters: <nickname> {[+|-]|i|w|s|o}
35
+ def initialize(prefix, params = [], &block)
36
+ super(prefix, *params)
37
+
38
+ return if params == nil || params.length <= 1
39
+
40
+ if params.length != 5 && params.length != 2
41
+ self.target = params[0]
42
+ self.flags = params[1]
43
+
44
+ if remaining = params[2..-1]
45
+ if remaining.first =~ /\d+/ || self.flags =~ /\+k/
46
+ self.limit = remaining.shift
47
+ elsif self.flags =~ /\+b/
48
+ self.ban_mask = remaining.first
49
+ else
50
+ self.user, self.ban_mask = *remaining
51
+ end
52
+ end
53
+ end
54
+
55
+ self.flags = self.flags.downcase if self.flags
56
+ end
57
+
58
+ def for_channel?
59
+ IRCParser::Helper.valid_channel_name?(target)
60
+ end
61
+
62
+ def for_user?
63
+ IRCParser::Helper.valid_nick?(target)
64
+ end
65
+
66
+ CHANNEL_MODES = {
67
+ :invitation => "I", # set/remove an invitation mask to automatically override the invite-only flag;
68
+ :exception => "e", # set/remove an exception mask to override a ban mask;
69
+ :quiet => "q", # toggle the quiet channel flag;
70
+ :reop => "r", # toggle the server reop channel flag;
71
+ :anonymous => "a", # toggle the anonymous channel flag;
72
+ :ban_mask => "b", # set a ban mask to keep users out;
73
+ :creator => "O", # give "channel creator" status;
74
+ :invite_only => "i", # invite-only channel flag;
75
+ :moderated => "m", # moderated channel;
76
+ :no_foreign_messages => "n", # no messages to channel from clients on the outside;
77
+ :operator => "o", # give/take channel operator privileges;
78
+ :password => "k", # set a channel key (password).
79
+ :private => "p", # private channel flag;
80
+ :secret => "s", # secret channel flag;
81
+ :speaker => "v", # give/take the ability to speak on a moderated channel;
82
+ :topic_by_op_only => "t", # topic settable by channel operator only flag;
83
+ :users_limit => "l" # set the user limit to channel;
84
+ }
85
+
86
+ def negative_flags?
87
+ flags && ( flags[0,1] == "-" )
88
+ end
89
+
90
+ def positive_flags?
91
+ not negative_flags?
92
+ end
93
+
94
+ def negative_flags!
95
+ self.flags ||= ""
96
+
97
+ case flags[0,1]
98
+ when "-" then # Do nothing
99
+ when "+" then self.flags[0] = "-"
100
+ else
101
+ self.flags.insert(0, "-") # Should not happen. Anyway.
102
+ end
103
+ end
104
+
105
+ def positive_flags!
106
+ self.flags ||= ""
107
+
108
+ case flags[0,1]
109
+ when "+" then # Do nothing
110
+ when "-" then self.flags[0] = "+"
111
+ else
112
+ self.flags.insert(0, "+") # Should not happen. Anyway.
113
+ end
114
+ end
115
+
116
+ CHANNEL_MODES.each do |name, flag|
117
+ define_method("chan_flags_include_#{name}?") do
118
+ flags && for_channel? && flags.include?(flag)
119
+ end
120
+
121
+ define_method("chan_#{name}?") do
122
+ flags && for_channel? && flags.include?(flag) && positive_flags?
123
+ end
124
+
125
+ define_method("chan_#{name}!") do
126
+ self.flags ||= ""
127
+ self.flags = flags + flag unless flags.include?(flag)
128
+ end
129
+ end
130
+
131
+ USER_MODES = {
132
+ :invisible => "i", # marks a users as invisible;
133
+ :server_receptor => "s", # marks a user for receipt of server notices;
134
+ :wallops_receptor => "w", # user receives wallops;
135
+ :operator => "o", # operator flag.
136
+ :away => "a", # user is flagged as away;
137
+ :restricted => "r", # restricted user connection;
138
+ :local_operator => "O" # local operator flag;
139
+ }
140
+
141
+ USER_MODES.each do |name, flag|
142
+ define_method("user_flags_include_#{name}?") do
143
+ flags && for_user? && flags.include?(flag)
144
+ end
145
+
146
+ define_method("user_#{name}?") do
147
+ flags && for_user? && flags.include?(flag) && positive_flags?
148
+ end
149
+
150
+ define_method("user_#{name}!") do
151
+ self.flags ||= ""
152
+ self.flags = flags + flag unless self.flags.include?(flag)
153
+ end
154
+ end
155
+ end
156
+
157
+ # hopcount: removed in RFC 2812
158
+ define_message :Nick, :nick, :hopcount do
159
+ def invalid_nick?
160
+ IRCParser::Helper.invalid_nick?(nick)
161
+ end
162
+
163
+ def changing?
164
+ prefix.to_s =~ /\S/
165
+ end
166
+ end
167
+
168
+ define_message :Server, :server, :hopcount, :info => :postfix do
169
+ def hopcount
170
+ self[:hopcount].to_i
171
+ end
172
+
173
+ # not sure about this one, from RFC 2813
174
+ # http://tools.ietf.org/html/rfc2813#section-4.1.2
175
+ def token
176
+ info
177
+ end
178
+ end
179
+
180
+ module MesageMan
181
+ def for_channel?
182
+ IRCParser::Helper.valid_channel_name?(target.to_s)
183
+ end
184
+
185
+ def for_user?
186
+ IRCParser::Helper.valid_nick?(target.to_s)
187
+ end
188
+
189
+ def for_server_pattern?
190
+ target.to_s =~ /^\$/
191
+ end
192
+
193
+ def for_host_pattern?
194
+ target.to_s =~ /^\#/
195
+ end
196
+
197
+ def server_pattern
198
+ for_server_pattern? && IRCParser::Helper::parse_regexp(target[1..-1])
199
+ end
200
+
201
+ def host_pattern
202
+ for_host_pattern? && IRCParser::Helper::parse_regexp(target[1..-1])
203
+ end
204
+ end
205
+
206
+ define_message :PrivMsg, :target, :body => :postfix do
207
+ include MesageMan
208
+ end
209
+
210
+ define_message :Notice, :target, :body => :postfix do
211
+ include MesageMan
212
+ end
213
+
214
+ define_message :Who, :pattern, :operator do
215
+ alias_method :operator?, :operator
216
+
217
+ def for_channel?
218
+ IRCParser::Helper.valid_channel_name?(pattern)
219
+ end
220
+
221
+ def operator!(true_or_false = true)
222
+ self.operator = true_or_false ? "o" : ""
223
+ end
224
+
225
+ def regexp
226
+ IRCParser::Helper.parse_regexp(pattern)
227
+ end
228
+ end
229
+
230
+ define_message :WhoIs, :target, :pattern do
231
+ def initialize(prefix, params = [], &block)
232
+ super(prefix, *params)
233
+ self.target, self.pattern = nil, self.target if params && params.length == 1
234
+ end
235
+
236
+ def regexp
237
+ IRCParser::Helper.parse_regexp(pattern)
238
+ end
239
+ end
240
+
241
+ define_message :WhoWas, :nick, :count, :server do
242
+ def count
243
+ self[:count].to_i
244
+ end
245
+ end
246
+
247
+ define_message :Error, :nick, :error_message => :postfix do
248
+ def initialize(prefix, params = [], &block)
249
+ super(prefix, *params)
250
+
251
+ if params
252
+ if params.length == 2
253
+ self.nick, self.error_message = *params
254
+ else
255
+ self.error_message = params.first
256
+ end
257
+ end
258
+ end
259
+ end
260
+
261
+ define_message :Summon, :nick, :server
262
+
263
+ define_message :UserHost, :nicks => { :csv => " " } do
264
+ def initialize(prefix = nil, *nicks)
265
+ super(prefix, nicks.join(" "))
266
+ end
267
+ end
268
+
269
+ define_message :IsOn, :nicks => { :csv => " " } do
270
+ def initialize(prefix = nil, *nicks)
271
+ super(prefix, nicks.join(" "))
272
+ end
273
+ end
274
+ end