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.
- data/LICENSE +21 -0
- data/README.md +105 -0
- data/Rakefile +155 -0
- data/extra/benchmark.rb +41 -0
- data/irc_parser.gemspec +98 -0
- data/lib/irc_parser.rb +25 -0
- data/lib/irc_parser/factory.erb +53 -0
- data/lib/irc_parser/helper.rb +71 -0
- data/lib/irc_parser/messages.rb +96 -0
- data/lib/irc_parser/messages/commands.rb +274 -0
- data/lib/irc_parser/messages/errors.rb +51 -0
- data/lib/irc_parser/messages/replies.rb +212 -0
- data/lib/irc_parser/parser.rb +557 -0
- data/lib/irc_parser/parser.rl +89 -0
- data/spec/fixtures/from_weechat.rb +24 -0
- data/spec/fixtures/inbound.log +3959 -0
- data/spec/irc_parser/helper_spec.rb +32 -0
- data/spec/irc_parser/irc_parser_spec.rb +12 -0
- data/spec/irc_parser/messages_spec.rb +195 -0
- data/spec/irc_parser/parser_spec.rb +9 -0
- data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_1_password_message_spec.rb +28 -0
- data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_2_nick_message_spec.rb +35 -0
- data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_3_user_message_spec.rb +47 -0
- data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_4_server_message_spec.rb +33 -0
- data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_5_oper_spec.rb +17 -0
- data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_6_quit_spec.rb +17 -0
- data/spec/irc_parser/rfc1459/4_1_connection_registration/4_1_7_server_quit_message_spec.rb +32 -0
- data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_1_join_message_spec.rb +65 -0
- data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_2_part_message_spec.rb +23 -0
- data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_3_1_channel_modes_spec.rb +159 -0
- data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_3_2_user_modes_spec.rb +55 -0
- data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_4_topic_message_spec.rb +36 -0
- data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_5_names_message_spec.rb +25 -0
- data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_6_list_message_spec.rb +23 -0
- data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_7_invite_message_spec.rb +31 -0
- data/spec/irc_parser/rfc1459/4_2_channel_operations/4_2_8_kick_command_spec.rb +56 -0
- data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_1_version_message_spec.rb +30 -0
- data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_2_stats_message_spec.rb +32 -0
- data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_3_links_message_spec.rb +31 -0
- data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_4_time_message_spec.rb +34 -0
- data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_5_connect_message_spec.rb +32 -0
- data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_6_trace_message_spec.rb +28 -0
- data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_7_admin_command_spec.rb +28 -0
- data/spec/irc_parser/rfc1459/4_3_server_queries_and_commands/4_3_8_info_command_spec.rb +38 -0
- data/spec/irc_parser/rfc1459/4_4_sending_messages/4_4_1_private_messages_spec.rb +63 -0
- data/spec/irc_parser/rfc1459/4_4_sending_messages/4_4_2_notice_spec.rb +63 -0
- data/spec/irc_parser/rfc1459/4_5_user_based_queries/4_5_1_who_query_spec.rb +27 -0
- data/spec/irc_parser/rfc1459/4_5_user_based_queries/4_5_2_whois_query_spec.rb +27 -0
- data/spec/irc_parser/rfc1459/4_5_user_based_queries/4_5_3_whowas_spec.rb +40 -0
- data/spec/irc_parser/rfc1459/4_6_miscellaneous_messages/4_6_1_kill_message_spec.rb +20 -0
- data/spec/irc_parser/rfc1459/4_6_miscellaneous_messages/4_6_2_ping_message_spec.rb +35 -0
- data/spec/irc_parser/rfc1459/4_6_miscellaneous_messages/4_6_3_pong_message_spec.rb +26 -0
- data/spec/irc_parser/rfc1459/4_6_miscellaneous_messages/4_6_4_error_spec.rb +26 -0
- data/spec/irc_parser/rfc1459/5_0_optionals/5_1_0_away_spec.rb +25 -0
- data/spec/irc_parser/rfc1459/5_0_optionals/5_2_0_rehash_message_spec.rb +14 -0
- data/spec/irc_parser/rfc1459/5_0_optionals/5_3_0_restart_message_spec.rb +14 -0
- data/spec/irc_parser/rfc1459/5_0_optionals/5_4_0_summon_message_spec.rb +28 -0
- data/spec/irc_parser/rfc1459/5_0_optionals/5_5_0_users_spec.rb +27 -0
- data/spec/irc_parser/rfc1459/5_0_optionals/5_6_0_operwall_message_spec.rb +17 -0
- data/spec/irc_parser/rfc1459/5_0_optionals/5_7_0_userhost_message_spec.rb +16 -0
- data/spec/irc_parser/rfc1459/5_0_optionals/5_8_0_ison_message_spec.rb +16 -0
- data/spec/irc_parser/rfc1459/6_0_replies/6_1_error_parsing_spec.rb +488 -0
- data/spec/irc_parser/rfc1459/6_0_replies/6_2_command_responses_generation_spec.rb +934 -0
- data/spec/irc_parser/rfc2812/5_1_command_responses/5_1_command_responses_spec.rb +63 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/messages_helper.rb +24 -0
- data/spec/support/simplecov.rb +12 -0
- 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
|