Sutto-marvin 0.4.0 → 0.8.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/marvin +22 -156
- data/handlers/keiki_thwopper.rb +21 -0
- data/handlers/tweet_tweet.rb +1 -3
- data/lib/marvin/abstract_client.rb +75 -189
- data/lib/marvin/abstract_parser.rb +9 -11
- data/lib/marvin/base.rb +134 -101
- data/lib/marvin/client/actions.rb +104 -0
- data/lib/marvin/client/default_handlers.rb +97 -0
- data/lib/marvin/command_handler.rb +60 -49
- data/lib/marvin/console.rb +4 -31
- data/lib/marvin/core_commands.rb +30 -12
- data/lib/marvin/distributed/client.rb +225 -0
- data/lib/marvin/distributed/handler.rb +85 -0
- data/lib/marvin/distributed/protocol.rb +88 -0
- data/lib/marvin/distributed/server.rb +154 -0
- data/lib/marvin/distributed.rb +4 -10
- data/lib/marvin/dsl.rb +103 -0
- data/lib/marvin/exception_tracker.rb +7 -4
- data/lib/marvin/irc/client.rb +127 -99
- data/lib/marvin/irc/event.rb +14 -10
- data/lib/marvin/irc.rb +0 -1
- data/lib/marvin/middle_man.rb +1 -1
- data/lib/marvin/parsers/command.rb +10 -8
- data/lib/marvin/parsers/prefixes/host_mask.rb +12 -7
- data/lib/marvin/parsers/prefixes/server.rb +1 -1
- data/lib/marvin/parsers/ragel_parser.rb +59 -52
- data/lib/marvin/parsers/ragel_parser.rl +6 -7
- data/lib/marvin/parsers/simple_parser.rb +4 -9
- data/lib/marvin/parsers.rb +1 -2
- data/lib/marvin/settings.rb +29 -79
- data/lib/marvin/test_client.rb +20 -26
- data/lib/marvin/util.rb +10 -3
- data/lib/marvin.rb +42 -39
- data/templates/boot.erb +3 -0
- data/templates/connections.yml.erb +10 -0
- data/templates/debug_handler.erb +5 -0
- data/templates/hello_world.erb +10 -0
- data/templates/rakefile.erb +15 -0
- data/templates/settings.yml.erb +8 -0
- data/{config/setup.rb → templates/setup.erb} +8 -10
- data/templates/test_helper.erb +17 -0
- data/test/abstract_client_test.rb +63 -0
- data/test/parser_comparison.rb +2 -2
- data/test/parser_test.rb +3 -3
- data/test/test_helper.rb +58 -6
- metadata +51 -83
- data/README.textile +0 -105
- data/TUTORIAL.textile +0 -54
- data/VERSION.yml +0 -4
- data/config/boot.rb +0 -14
- data/config/connections.yml.sample +0 -5
- data/config/settings.yml.sample +0 -13
- data/handlers/logging_handler.rb +0 -89
- data/lib/marvin/core_ext.rb +0 -11
- data/lib/marvin/daemon.rb +0 -71
- data/lib/marvin/data_store.rb +0 -73
- data/lib/marvin/dispatchable.rb +0 -99
- data/lib/marvin/distributed/dispatch_handler.rb +0 -83
- data/lib/marvin/distributed/drb_client.rb +0 -78
- data/lib/marvin/distributed/ring_server.rb +0 -41
- data/lib/marvin/handler.rb +0 -12
- data/lib/marvin/irc/server/abstract_connection.rb +0 -84
- data/lib/marvin/irc/server/base_connection.rb +0 -66
- data/lib/marvin/irc/server/channel.rb +0 -115
- data/lib/marvin/irc/server/named_store.rb +0 -14
- data/lib/marvin/irc/server/remote_interface.rb +0 -77
- data/lib/marvin/irc/server/user/handle_mixin.rb +0 -140
- data/lib/marvin/irc/server/user.rb +0 -5
- data/lib/marvin/irc/server/user_connection.rb +0 -134
- data/lib/marvin/irc/server/virtual_user_connection.rb +0 -80
- data/lib/marvin/irc/server.rb +0 -71
- data/lib/marvin/loader.rb +0 -149
- data/lib/marvin/logger.rb +0 -86
- data/lib/marvin/options.rb +0 -42
- data/lib/marvin/parsers/regexp_parser.rb +0 -93
- data/lib/marvin/status.rb +0 -72
- data/script/client +0 -3
- data/script/console +0 -3
- data/script/distributed_client +0 -3
- data/script/install +0 -1
- data/script/ring_server +0 -4
- data/script/server +0 -4
- data/script/status +0 -3
- data/spec/marvin/abstract_client_test.rb +0 -38
- data/spec/spec_helper.rb +0 -14
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'eventmachine'
|
2
|
-
|
3
|
-
module Marvin
|
4
|
-
module IRC
|
5
|
-
module Server
|
6
|
-
class BaseConnection < EventMachine::Protocols::LineAndTextProtocol
|
7
|
-
|
8
|
-
attr_accessor :port, :host, :started_at
|
9
|
-
|
10
|
-
# Our initialize method
|
11
|
-
def initialize(opts = {})
|
12
|
-
super
|
13
|
-
@buffer = []
|
14
|
-
@port = opts[:port]
|
15
|
-
@host = opts[:host]
|
16
|
-
@started_at = opts[:started_at] || Time.now
|
17
|
-
end
|
18
|
-
|
19
|
-
attr_accessor :connection_implementation, :buffer
|
20
|
-
|
21
|
-
# Receive the line, processing as it needs to be.
|
22
|
-
# Not that we have a conditional check to setup
|
23
|
-
# the correct connection
|
24
|
-
def receive_line(line)
|
25
|
-
Marvin::Logger.debug "<< #{line}"
|
26
|
-
if !@connection_implementation.nil?
|
27
|
-
@connection_implementation.receive_line(line)
|
28
|
-
elsif line[0..3] == "USER"
|
29
|
-
@buffer << line
|
30
|
-
self.connection_implementation = UserConnection.new(self, @buffer)
|
31
|
-
@buffer = nil
|
32
|
-
elsif line[0..5] == "SERVER"
|
33
|
-
@buffer << line
|
34
|
-
self.connection_implementation = ServerConnection.new(self, @buffer)
|
35
|
-
@buffer = nil
|
36
|
-
else
|
37
|
-
@buffer << line
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def send_line(line)
|
42
|
-
Marvin::Logger.debug ">> #{line.strip}"
|
43
|
-
line += "\r\n" unless line[-2..-1] == "\r\n"
|
44
|
-
send_data line
|
45
|
-
end
|
46
|
-
|
47
|
-
def kill_connection!
|
48
|
-
close_connection_after_writing
|
49
|
-
end
|
50
|
-
|
51
|
-
# Do things on the unbind
|
52
|
-
def unbind
|
53
|
-
super # Call the old version
|
54
|
-
@connection_implementation.process_disconnect
|
55
|
-
end
|
56
|
-
|
57
|
-
# Do things on the connection implementation
|
58
|
-
def post_init
|
59
|
-
super
|
60
|
-
send_line "NOTICE AUTH :Marvin Server v#{Marvin.version} initialized, welcome."
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,115 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server
|
2
|
-
class Channel
|
3
|
-
include Marvin::Dispatchable
|
4
|
-
|
5
|
-
cattr_accessor :logger
|
6
|
-
self.logger = Marvin::Logger
|
7
|
-
|
8
|
-
attr_accessor :name, :members, :name, :topic, :operators, :mode
|
9
|
-
|
10
|
-
def inspect
|
11
|
-
"#<Marvin::IRC::Server::Channel name='#{name}' topic='#{@topic}' members=[#{self.members.map { |m| m.nick.inspect}.join(", ")}]>"
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(name)
|
15
|
-
@name = name
|
16
|
-
@members = []
|
17
|
-
@operators = []
|
18
|
-
@topic = ""
|
19
|
-
@mode = ""
|
20
|
-
logger.info "Created the channel #{name}"
|
21
|
-
dispatch :channel_created, :channel => self
|
22
|
-
end
|
23
|
-
|
24
|
-
def member?(user)
|
25
|
-
@members.include?(user)
|
26
|
-
end
|
27
|
-
|
28
|
-
def each_member(&blk)
|
29
|
-
members.each(&blk)
|
30
|
-
end
|
31
|
-
|
32
|
-
def add(user)
|
33
|
-
logger.info "Adding user #{user.nick} to #{@name}"
|
34
|
-
@operators << user if needs_op?
|
35
|
-
@members << user
|
36
|
-
end
|
37
|
-
|
38
|
-
def remove(user)
|
39
|
-
@members.delete(user)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Ind. operations on the room
|
43
|
-
|
44
|
-
def join(user)
|
45
|
-
return false if member?(user)
|
46
|
-
# Otherwise, we add a user
|
47
|
-
add user
|
48
|
-
@members.each { |m| m.notify :join, @name, :prefix => user.prefix }
|
49
|
-
dispatch :outgoing_join, :target => @name, :nick => user.nick
|
50
|
-
return true
|
51
|
-
end
|
52
|
-
|
53
|
-
def part(user, message = nil)
|
54
|
-
logger.debug "Getting part from #{user.inspect} w/ #{message}"
|
55
|
-
return false if !member?(user)
|
56
|
-
@members.each { |m| m.notify :part, @name, user.nick, message, :prefix => user.prefix }
|
57
|
-
remove user
|
58
|
-
# TODO: Remove channel from ChannelStore if it's empty.
|
59
|
-
dispatch :outgoing_part, :target => @name, :user => user, :message => message
|
60
|
-
check_emptyness!
|
61
|
-
return true
|
62
|
-
end
|
63
|
-
|
64
|
-
def quit(user, message = nil)
|
65
|
-
remove user
|
66
|
-
@members.each { |m| m.notify :quit, @name, message, :prefix => user.prefix }
|
67
|
-
# TODO: Remove channel from the store if it's empty
|
68
|
-
dispatch :outgoing_quit, :target => @name, :user => user, :message => message
|
69
|
-
check_emptyness!
|
70
|
-
end
|
71
|
-
|
72
|
-
def message(user, message, virtual = false)
|
73
|
-
@members.each do |m|
|
74
|
-
if virtual || user != m
|
75
|
-
m.notify(:privmsg, @name, ":#{message}", :prefix => user.prefix, :virtual => virtual)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
dispatch :outgoing_message, :target => self, :user => user, :message => message, :virtual => virtual
|
79
|
-
end
|
80
|
-
|
81
|
-
def notice(user, message)
|
82
|
-
@members.each { |m| m.notify :notice, @name, ":#{message}", :prefix => user.prefix unless user == m }
|
83
|
-
dispatch :outgoing_notice, :target => self, :user => user, :message => message
|
84
|
-
end
|
85
|
-
|
86
|
-
def topic(user = nil, t = nil)
|
87
|
-
return @topic if t.blank?
|
88
|
-
logger.info "Getting topic for '#{@name}' - #{t.inspect}"
|
89
|
-
@topic = t
|
90
|
-
@members.each { |m| m.notify :topic, @name, ":#{t}", :prefix => user.prefix }
|
91
|
-
dispatch :outgoing_topic, :target => @name, :user => user, :topic => t
|
92
|
-
return @topic
|
93
|
-
end
|
94
|
-
|
95
|
-
def mode(user)
|
96
|
-
@operators.include?(user) ? "@" : ""
|
97
|
-
end
|
98
|
-
|
99
|
-
private
|
100
|
-
|
101
|
-
def needs_op?
|
102
|
-
@operators.empty? && @members.empty?
|
103
|
-
end
|
104
|
-
|
105
|
-
def check_emptyness!
|
106
|
-
destroy if @members.empty?
|
107
|
-
end
|
108
|
-
|
109
|
-
def destroy
|
110
|
-
Marvin::IRC::Server::ChannelStore.delete(@name)
|
111
|
-
dispatch :channel_destroyed, :channel => self
|
112
|
-
end
|
113
|
-
|
114
|
-
end
|
115
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server
|
2
|
-
class NamedStore
|
3
|
-
|
4
|
-
def self.new(key_plural, ref_value, &blk)
|
5
|
-
klass = Class.new(Hash) do
|
6
|
-
alias_method :"each_#{ref_value}", :each_value
|
7
|
-
alias_method key_plural.to_sym, :keys
|
8
|
-
end
|
9
|
-
klass.class_eval(&blk) unless blk.blank?
|
10
|
-
return klass.new
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'drb'
|
2
|
-
require 'rinda/ring'
|
3
|
-
module Marvin
|
4
|
-
module IRC
|
5
|
-
module Server
|
6
|
-
|
7
|
-
# Make sure that a proxy object is used vs. the real thing.
|
8
|
-
[Channel, AbstractConnection, User, NamedStore].each do |c|
|
9
|
-
c.class_eval { include DRbUndumped }
|
10
|
-
end
|
11
|
-
|
12
|
-
# A DRb interface to post / receive messages from the
|
13
|
-
# a running server instance. Used for things such as
|
14
|
-
# posting status updated directly on the server.
|
15
|
-
class RemoteInterface
|
16
|
-
include DRbUndumped
|
17
|
-
|
18
|
-
# Attempts to find a running IRC server,
|
19
|
-
# returning an instance of it if it exists.
|
20
|
-
def self.primary
|
21
|
-
DRb.start_service
|
22
|
-
begin
|
23
|
-
rs = Rinda::RingFinger.primary
|
24
|
-
server = rs.read_all([:marvin_server, Marvin::Settings.distributed_namespace, nil])
|
25
|
-
if server.empty?
|
26
|
-
return nil
|
27
|
-
else
|
28
|
-
# Return the first element in the list of servers, getting it's servers instance.
|
29
|
-
return server.first.last
|
30
|
-
end
|
31
|
-
rescue
|
32
|
-
return nil
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.start
|
37
|
-
DRb.start_service
|
38
|
-
instance = self.new # Create the new instance
|
39
|
-
begin
|
40
|
-
rs = Rinda::RingFinger.primary
|
41
|
-
renewer = Rinda::SimpleRenewer.new
|
42
|
-
tuple = [:marvin_server, Marvin::Settings.distributed_namespace, instance]
|
43
|
-
Marvin::Logger.info "Publishing information about service to the tuplespace"
|
44
|
-
Marvin::Logger.debug "Pushing #{tuple.inspect} to #{rs.__drburi}"
|
45
|
-
rs.write(tuple, renewer)
|
46
|
-
rescue
|
47
|
-
Marvin::Logger.warn "No ring server found - remote interface not running"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Returns an array of all channels
|
52
|
-
def channels
|
53
|
-
Marvin::IRC::Server::ChannelStore.values
|
54
|
-
end
|
55
|
-
|
56
|
-
# Returns the names of all channels
|
57
|
-
def channel_names
|
58
|
-
Marvin::IRC::Server::ChannelStore.keys
|
59
|
-
end
|
60
|
-
|
61
|
-
# Returns the channel with the given name.
|
62
|
-
def channel(name)
|
63
|
-
Marvin::IRC::Server::ChannelStore[name]
|
64
|
-
end
|
65
|
-
|
66
|
-
# Send an action from a user to a specific
|
67
|
-
# channel, using from nick as a facade.
|
68
|
-
def message(from_nick, target, contents)
|
69
|
-
u = (Marvin::IRC::Server::UserStore[from_nick.to_s.downcase] ||= VirtualUserConnection.new(from_nick))
|
70
|
-
Marvin::Logger.info "#{from_nick} (#{u.inspect}) messaging #{target}: #{contents}"
|
71
|
-
u.send_message(target, contents) unless u.blank?
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,140 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server::User::HandleMixin
|
2
|
-
|
3
|
-
def handle_incoming_pass(opts = {})
|
4
|
-
@password = opts[:password]
|
5
|
-
end
|
6
|
-
|
7
|
-
def handle_incoming_user(opts = {})
|
8
|
-
@user = opts[:user]
|
9
|
-
@mode = opts[:mode]
|
10
|
-
@real_name = opts[:real_name]
|
11
|
-
welcome_if_complete!
|
12
|
-
end
|
13
|
-
|
14
|
-
def handle_incoming_nick(opts = {})
|
15
|
-
nick = opts[:new_nick]
|
16
|
-
if !nick.blank? && !Marvin::IRC::Server::UserStore.nick_taken?(nick.downcase)
|
17
|
-
if !(new_nick = @nick.nil?)
|
18
|
-
logger.info "Reclaiming nick (if taken)"
|
19
|
-
Marvin::IRC::Server::UserStore.reclaim(nick)
|
20
|
-
logger.debug "Notifying all users of nick change: #{@nick} => #{nick}"
|
21
|
-
# Get all users and let them now we've changed nick from @nick to nick
|
22
|
-
users = [self]
|
23
|
-
@channels.each do |c|
|
24
|
-
users += c.members
|
25
|
-
end
|
26
|
-
users.uniq.each { |u| u.notify :NICK, nick, :prefix => prefix }
|
27
|
-
dispatch :outgoing_nick, :nick => @nick, :new_nick => nick
|
28
|
-
end
|
29
|
-
# Update the store values
|
30
|
-
Marvin::IRC::Server::UserStore.delete(@nick.downcase) unless @nick.blank?
|
31
|
-
Marvin::IRC::Server::UserStore[nick.downcase] = self
|
32
|
-
# Change the nick and reset the number of attempts
|
33
|
-
@nick = nick
|
34
|
-
@nick_attempts = 0
|
35
|
-
# Finally, update the prefix.
|
36
|
-
update_prefix!
|
37
|
-
welcome_if_complete! if new_nick
|
38
|
-
elsif Marvin::IRC::Server::UserStore[nick.downcase] != self
|
39
|
-
# The nick is taken
|
40
|
-
# TODO: Remove hard coded nick attempts limit
|
41
|
-
if @nick_attempts > 5
|
42
|
-
# Handle abort here.
|
43
|
-
logger.debug "User has gone over nick attempt limits - Killing connection."
|
44
|
-
kill_connection!
|
45
|
-
dispatch :outgoing_nick_killed, :client => self
|
46
|
-
else
|
47
|
-
logger.debug "Noting users nick is taken, warning"
|
48
|
-
err :NICKNAMEINUSE, "*", nick, ":Nickname is already in use."
|
49
|
-
@nick_attempts += 1
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def handle_incoming_join(opts = {})
|
55
|
-
return if @prefix.blank?
|
56
|
-
opts[:target].split(",").each do |channel|
|
57
|
-
# If the channel name is invalud, let the user known and dispatch
|
58
|
-
# the correct event.
|
59
|
-
if channel !~ Marvin::IRC::Server::UserConnection::CHANNEL
|
60
|
-
logger.debug "Attempted to join invalid channel name '#{channel}'"
|
61
|
-
err :NOSUCHCHANNEL, channel, ":That channel doesn't exist"
|
62
|
-
dispatch :invalid_channel_name, :channel => channel, :client => self
|
63
|
-
return
|
64
|
-
end
|
65
|
-
chan = (Marvin::IRC::Server::ChannelStore[channel.downcase] ||= Marvin::IRC::Server::Channel.new(channel))
|
66
|
-
if chan.join(self)
|
67
|
-
rpl :TOPIC, channel, ":#{chan.topic.blank? ? "There is no topic" : chan.topic}"
|
68
|
-
rpl :NAMREPLY, "=", channel, ":#{chan.members.map { |m| m.nick }.join(" ")}"
|
69
|
-
rpl :ENDOFNAMES, channel, ":End of /NAMES list."
|
70
|
-
@channels << chan
|
71
|
-
else
|
72
|
-
logger.debug "Couldn't join channel '#{channel}'"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def handle_incoming_ping(opts = {})
|
78
|
-
command :PONG, ":#{opts[:data]}"
|
79
|
-
end
|
80
|
-
|
81
|
-
def handle_incoming_pong(opts = {})
|
82
|
-
# Decrease the ping count.
|
83
|
-
@ping_count -= 1
|
84
|
-
@ping_count = 0 if @ping_count < 0
|
85
|
-
logger.debug "Got pong: #{opts[:data]}"
|
86
|
-
end
|
87
|
-
|
88
|
-
def handle_incoming_message(opts = {})
|
89
|
-
return if @prefix.blank?
|
90
|
-
unless (t = target_from(opts[:target])).blank?
|
91
|
-
t.message self, opts[:message]
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def handle_incoming_notice(opts = {})
|
96
|
-
return if @prefix.blank?
|
97
|
-
unless (t = target_from(opts[:target])).blank?
|
98
|
-
t.notice self, opts[:message]
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def handle_incoming_part(opts = {})
|
103
|
-
t = opts[:target].downcase
|
104
|
-
if !(chan = Marvin::IRC::Server::ChannelStore[t]).blank?
|
105
|
-
if chan.part(self, opts[:message])
|
106
|
-
@channels.delete(chan)
|
107
|
-
else
|
108
|
-
err :NOTONCHANNEL, opts[:target], ":Not a member of that channel"
|
109
|
-
end
|
110
|
-
else
|
111
|
-
err :NOSUCHNICK, opts[:target], ":No such nick/channel"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def handle_incoming_quit(opts = {})
|
116
|
-
return unless @alive
|
117
|
-
@alive = false
|
118
|
-
@channels.each { |c| c.quit(self, opts[:message]) }
|
119
|
-
kill_connection!
|
120
|
-
end
|
121
|
-
|
122
|
-
def handle_incoming_topic(opts = {})
|
123
|
-
return if @prefix.blank? || opts[:target].blank?
|
124
|
-
c = Marvin::IRC::Server::ChannelStore[opts[:target].downcase]
|
125
|
-
return if c.blank?
|
126
|
-
if !@channels.include?(c)
|
127
|
-
err :NOTONCHANNEL, opts[:target], ":Not a member of that channel"
|
128
|
-
elsif opts[:topic].blank?
|
129
|
-
t = c.topic
|
130
|
-
if t.blank?
|
131
|
-
rpl :NOTOPIC, c.name, ":No topic is set"
|
132
|
-
else
|
133
|
-
rpl :TOPIC, c.name, ":#{t}"
|
134
|
-
end
|
135
|
-
else
|
136
|
-
c.topic self, opts[:topic].strip
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
end
|
@@ -1,134 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server
|
2
|
-
class UserConnection < AbstractConnection
|
3
|
-
USER_MODES = "aAbBcCdDeEfFGhHiIjkKlLmMnNopPQrRsStUvVwWxXyYzZ0123459*@"
|
4
|
-
CHANNEL_MODES = "bcdefFhiIklmnoPqstv"
|
5
|
-
CHANNEL = /^[\&\#]+/
|
6
|
-
|
7
|
-
include User::HandleMixin
|
8
|
-
|
9
|
-
attr_accessor :nick, :host, :user, :prefix, :password, :mode,
|
10
|
-
:real_name, :nick_attempts, :channels, :ping_count
|
11
|
-
|
12
|
-
def inspect
|
13
|
-
"#<Marvin::IRC::Server::UserConnection nick='#{@nick}' host='#{@host}' real_name='#{@real_name}' channels=[#{self.channels.map { |c| c.name.inspect}.join(", ")}]>"
|
14
|
-
end
|
15
|
-
|
16
|
-
def initialize(base, buffer = [])
|
17
|
-
super
|
18
|
-
@nick_attempts = 0
|
19
|
-
@channels = []
|
20
|
-
@ping_count = 0
|
21
|
-
end
|
22
|
-
|
23
|
-
# Notify is essentially command BUT it
|
24
|
-
# requires that the prefix is set.
|
25
|
-
def notify(command, *args)
|
26
|
-
opts = args.extract_options!
|
27
|
-
return if opts[:prefix].blank?
|
28
|
-
command command, *(args << opts)
|
29
|
-
end
|
30
|
-
|
31
|
-
# Notification messages
|
32
|
-
|
33
|
-
def send_message(target, message)
|
34
|
-
t = target_from(target)
|
35
|
-
logger.debug "Sending #{t.inspect} #{message.inspect} from #{self.inspect}"
|
36
|
-
t.message(self, message) unless t.blank?
|
37
|
-
end
|
38
|
-
|
39
|
-
def message(user, message, virtual = false)
|
40
|
-
notify :PRIVMSG, @nick, ":#{message}", :prefix => user.prefix, :virtual => virtual
|
41
|
-
dispatch :outgoing_message, :user => user, :message => message, :target => self, :virtual => virtual
|
42
|
-
end
|
43
|
-
|
44
|
-
def notice(user, message)
|
45
|
-
notify :NOTICE, @nick, ":#{message}", :prefix => user.prefix
|
46
|
-
dispatch :outgoing_notice, :user => user, :message => message, :target => self
|
47
|
-
end
|
48
|
-
|
49
|
-
# Get the user / channel targeted by a particular request.
|
50
|
-
|
51
|
-
def target_from(target)
|
52
|
-
case target
|
53
|
-
when CHANNEL
|
54
|
-
chan = Marvin::IRC::Server::ChannelStore[target.downcase]
|
55
|
-
if chan.nil?
|
56
|
-
rpl :NOSUCHNICK, target, ":No such nick/channel"
|
57
|
-
elsif !chan.member?(self)
|
58
|
-
err :CANNOTSENDTOCHAN, target, ":Cannot send to channel"
|
59
|
-
else
|
60
|
-
return chan
|
61
|
-
end
|
62
|
-
else
|
63
|
-
user = Marvin::IRC::Server::UserStore[target.downcase]
|
64
|
-
if user.nil?
|
65
|
-
err :NOSUCHNICK, target, ":No suck nick/channel"
|
66
|
-
else
|
67
|
-
return user
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# Implementations for connect / disconnect
|
73
|
-
|
74
|
-
def process_connect
|
75
|
-
super
|
76
|
-
end
|
77
|
-
|
78
|
-
def process_disconnect
|
79
|
-
super
|
80
|
-
end
|
81
|
-
|
82
|
-
def kill_connection!
|
83
|
-
@connection.kill_connection!
|
84
|
-
end
|
85
|
-
|
86
|
-
protected
|
87
|
-
|
88
|
-
def welcome_if_complete!
|
89
|
-
update_prefix!
|
90
|
-
# Next, send the MOTD and other misc. stuff
|
91
|
-
return if @welcomed || @prefix.blank?
|
92
|
-
rpl :WELCOME, @nick, ":Welcome to Marvin Server - #{@prefix}"
|
93
|
-
rpl :YOURHOST, @nick, ":Your host is #{server_host}, running version #{Marvin.version}"
|
94
|
-
rpl :CREATED, @nick, ":This server was created #{@connection.started_at}"
|
95
|
-
rpl :MYINFO, @nick, ":#{server_host} #{Marvin.version} #{USER_MODES} #{CHANNEL_MODES}"
|
96
|
-
rpl :MOTDSTART, @nick, ":- MOTD"
|
97
|
-
rpl :MOTD, @nick, ":- Welcome to Marvin Server, a Ruby + EventMachine ircd."
|
98
|
-
rpl :ENDOFMOTD, @nick, ":- End of /MOTD command."
|
99
|
-
@welcomed = true
|
100
|
-
end
|
101
|
-
|
102
|
-
def update_prefix!
|
103
|
-
@prefix = "#{@nick}!n=#{@user}@#{peer_name}" if details_complete?
|
104
|
-
end
|
105
|
-
|
106
|
-
def details_complete?
|
107
|
-
!@nick.nil? && !@user.nil?
|
108
|
-
end
|
109
|
-
|
110
|
-
def server_host
|
111
|
-
@connection.host
|
112
|
-
end
|
113
|
-
|
114
|
-
def server_port
|
115
|
-
@connection.port
|
116
|
-
end
|
117
|
-
|
118
|
-
def rpl(number, *args)
|
119
|
-
numeric Marvin::IRC::Replies["RPL_#{number.to_s.upcase}"], *args
|
120
|
-
end
|
121
|
-
|
122
|
-
def err(number, *args)
|
123
|
-
numeric Marvin::IRC::Replies["ERR_#{number.to_s.upcase}"], *args
|
124
|
-
end
|
125
|
-
|
126
|
-
def numeric(number, *args)
|
127
|
-
args << {} unless args[-1].is_a?(Hash)
|
128
|
-
args[-1][:prefix] ||= server_host
|
129
|
-
args.unshift(@nick) unless args.first == @nick
|
130
|
-
command(number.to_s, *args)
|
131
|
-
end
|
132
|
-
|
133
|
-
end
|
134
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server
|
2
|
-
class VirtualUserConnection
|
3
|
-
include Marvin::Dispatchable
|
4
|
-
|
5
|
-
CHANNEL = /^[\&\#]+/
|
6
|
-
|
7
|
-
attr_accessor :nick, :channels
|
8
|
-
|
9
|
-
def initialize(nick)
|
10
|
-
self.nick = nick
|
11
|
-
self.channels = []
|
12
|
-
end
|
13
|
-
|
14
|
-
def prefix
|
15
|
-
"#{@nick}!n=rruser@relayrelay.com"
|
16
|
-
end
|
17
|
-
|
18
|
-
def notify(*args)
|
19
|
-
Marvin::Logger.debug "Virtual User #{self.nick} got notify w/ #{args.inspect}"
|
20
|
-
end
|
21
|
-
|
22
|
-
# Notify the remote handler we've received a message
|
23
|
-
def message(user, message, virtual = false)
|
24
|
-
dispatch :received_message, :user => user, :message => message, :target => self unless virtual
|
25
|
-
end
|
26
|
-
|
27
|
-
def send_message(target, message)
|
28
|
-
t = target_from(target)
|
29
|
-
Marvin::Logger.debug "DRb Message from #{self.nick} to #{t.inspect}: #{message.inspect}"
|
30
|
-
if t.blank?
|
31
|
-
Marvin::Logger.debug "Target not found"
|
32
|
-
return nil
|
33
|
-
else
|
34
|
-
Marvin::Logger.debug "Sending message to #{t.inspect}"
|
35
|
-
return t.message(self, message, true)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def reclaim!
|
40
|
-
self.channels.each { |c| c.part(self, "Reclaiming nick for virtual user...") }
|
41
|
-
Marvin::IRC::Server::UserStore.delete(self.nick.downcase)
|
42
|
-
end
|
43
|
-
|
44
|
-
def join(channel)
|
45
|
-
return nil if channel !~ CHANNEL
|
46
|
-
chan = (Marvin::IRC::Server::ChannelStore[channel.downcase] ||= Marvin::IRC::Server::Channel.new(channel))
|
47
|
-
if chan.join(self)
|
48
|
-
@channels << channel
|
49
|
-
return chan
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
class << self
|
54
|
-
|
55
|
-
def claimed?(nick)
|
56
|
-
Marvin::IRC::Server::UserStore.virtual?(nick)
|
57
|
-
end
|
58
|
-
|
59
|
-
def claim(nick)
|
60
|
-
unless Marvin::IRC::Server::UserStore[nick.downcase].blank?
|
61
|
-
return(Marvin::IRC::Server::UserStore[nick.downcase] ||= Marvin::IRC::Server::VirtualUserConnection.new(nick))
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def target_from(target)
|
70
|
-
if target =~ CHANNEL
|
71
|
-
c = Marvin::IRC::Server::ChannelStore[target.downcase]
|
72
|
-
c = join(target) if c.nil? || !c.member?(self)
|
73
|
-
return c
|
74
|
-
else
|
75
|
-
return Marvin::IRC::Server::UserStore[target.downcase] ||= Marvin::IRC::Server::VirtualUserConnection.new(target)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
end
|