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.
Files changed (85) hide show
  1. data/bin/marvin +22 -156
  2. data/handlers/keiki_thwopper.rb +21 -0
  3. data/handlers/tweet_tweet.rb +1 -3
  4. data/lib/marvin/abstract_client.rb +75 -189
  5. data/lib/marvin/abstract_parser.rb +9 -11
  6. data/lib/marvin/base.rb +134 -101
  7. data/lib/marvin/client/actions.rb +104 -0
  8. data/lib/marvin/client/default_handlers.rb +97 -0
  9. data/lib/marvin/command_handler.rb +60 -49
  10. data/lib/marvin/console.rb +4 -31
  11. data/lib/marvin/core_commands.rb +30 -12
  12. data/lib/marvin/distributed/client.rb +225 -0
  13. data/lib/marvin/distributed/handler.rb +85 -0
  14. data/lib/marvin/distributed/protocol.rb +88 -0
  15. data/lib/marvin/distributed/server.rb +154 -0
  16. data/lib/marvin/distributed.rb +4 -10
  17. data/lib/marvin/dsl.rb +103 -0
  18. data/lib/marvin/exception_tracker.rb +7 -4
  19. data/lib/marvin/irc/client.rb +127 -99
  20. data/lib/marvin/irc/event.rb +14 -10
  21. data/lib/marvin/irc.rb +0 -1
  22. data/lib/marvin/middle_man.rb +1 -1
  23. data/lib/marvin/parsers/command.rb +10 -8
  24. data/lib/marvin/parsers/prefixes/host_mask.rb +12 -7
  25. data/lib/marvin/parsers/prefixes/server.rb +1 -1
  26. data/lib/marvin/parsers/ragel_parser.rb +59 -52
  27. data/lib/marvin/parsers/ragel_parser.rl +6 -7
  28. data/lib/marvin/parsers/simple_parser.rb +4 -9
  29. data/lib/marvin/parsers.rb +1 -2
  30. data/lib/marvin/settings.rb +29 -79
  31. data/lib/marvin/test_client.rb +20 -26
  32. data/lib/marvin/util.rb +10 -3
  33. data/lib/marvin.rb +42 -39
  34. data/templates/boot.erb +3 -0
  35. data/templates/connections.yml.erb +10 -0
  36. data/templates/debug_handler.erb +5 -0
  37. data/templates/hello_world.erb +10 -0
  38. data/templates/rakefile.erb +15 -0
  39. data/templates/settings.yml.erb +8 -0
  40. data/{config/setup.rb → templates/setup.erb} +8 -10
  41. data/templates/test_helper.erb +17 -0
  42. data/test/abstract_client_test.rb +63 -0
  43. data/test/parser_comparison.rb +2 -2
  44. data/test/parser_test.rb +3 -3
  45. data/test/test_helper.rb +58 -6
  46. metadata +51 -83
  47. data/README.textile +0 -105
  48. data/TUTORIAL.textile +0 -54
  49. data/VERSION.yml +0 -4
  50. data/config/boot.rb +0 -14
  51. data/config/connections.yml.sample +0 -5
  52. data/config/settings.yml.sample +0 -13
  53. data/handlers/logging_handler.rb +0 -89
  54. data/lib/marvin/core_ext.rb +0 -11
  55. data/lib/marvin/daemon.rb +0 -71
  56. data/lib/marvin/data_store.rb +0 -73
  57. data/lib/marvin/dispatchable.rb +0 -99
  58. data/lib/marvin/distributed/dispatch_handler.rb +0 -83
  59. data/lib/marvin/distributed/drb_client.rb +0 -78
  60. data/lib/marvin/distributed/ring_server.rb +0 -41
  61. data/lib/marvin/handler.rb +0 -12
  62. data/lib/marvin/irc/server/abstract_connection.rb +0 -84
  63. data/lib/marvin/irc/server/base_connection.rb +0 -66
  64. data/lib/marvin/irc/server/channel.rb +0 -115
  65. data/lib/marvin/irc/server/named_store.rb +0 -14
  66. data/lib/marvin/irc/server/remote_interface.rb +0 -77
  67. data/lib/marvin/irc/server/user/handle_mixin.rb +0 -140
  68. data/lib/marvin/irc/server/user.rb +0 -5
  69. data/lib/marvin/irc/server/user_connection.rb +0 -134
  70. data/lib/marvin/irc/server/virtual_user_connection.rb +0 -80
  71. data/lib/marvin/irc/server.rb +0 -71
  72. data/lib/marvin/loader.rb +0 -149
  73. data/lib/marvin/logger.rb +0 -86
  74. data/lib/marvin/options.rb +0 -42
  75. data/lib/marvin/parsers/regexp_parser.rb +0 -93
  76. data/lib/marvin/status.rb +0 -72
  77. data/script/client +0 -3
  78. data/script/console +0 -3
  79. data/script/distributed_client +0 -3
  80. data/script/install +0 -1
  81. data/script/ring_server +0 -4
  82. data/script/server +0 -4
  83. data/script/status +0 -3
  84. data/spec/marvin/abstract_client_test.rb +0 -38
  85. 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,5 +0,0 @@
1
- module Marvin::IRC::Server::User
2
-
3
- autoload :HandleMixin, 'marvin/irc/server/user/handle_mixin'
4
-
5
- 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