Sutto-marvin 0.4.0 → 0.8.0.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 (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