irc_parser 0.1.0

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