PerfectlyNormal-Flexo 0.3.9
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 +348 -0
- data/README +5 -0
- data/Rakefile +21 -0
- data/bin/flexo +3 -0
- data/bin/mkflexorc +99 -0
- data/flexo.gemspec +53 -0
- data/lib/caselesshash.rb +113 -0
- data/lib/daemonize.rb +59 -0
- data/lib/flexo/client.rb +30 -0
- data/lib/flexo/config.rb +79 -0
- data/lib/flexo/constants.rb +15 -0
- data/lib/flexo/data.rb +104 -0
- data/lib/flexo/dispatcher.rb +134 -0
- data/lib/flexo/errors.rb +29 -0
- data/lib/flexo/event.rb +31 -0
- data/lib/flexo/events/join.rb +13 -0
- data/lib/flexo/events/kick.rb +29 -0
- data/lib/flexo/events/mode.rb +23 -0
- data/lib/flexo/events/nick.rb +14 -0
- data/lib/flexo/events/notice.rb +12 -0
- data/lib/flexo/events/part.rb +14 -0
- data/lib/flexo/events/ping.rb +16 -0
- data/lib/flexo/events/pong.rb +14 -0
- data/lib/flexo/events/privmsg.rb +46 -0
- data/lib/flexo/events/quit.rb +12 -0
- data/lib/flexo/events/reply.rb +45 -0
- data/lib/flexo/events/topic.rb +18 -0
- data/lib/flexo/events/unknown.rb +11 -0
- data/lib/flexo/handler.rb +30 -0
- data/lib/flexo/logger.rb +86 -0
- data/lib/flexo/manager.rb +152 -0
- data/lib/flexo/numerics.rb +207 -0
- data/lib/flexo/plugin.rb +69 -0
- data/lib/flexo/pluginmanager.rb +106 -0
- data/lib/flexo/sender.rb +601 -0
- data/lib/flexo/server.rb +130 -0
- data/lib/flexo/trigger.rb +44 -0
- data/plugins/auth.rb +256 -0
- data/plugins/control.rb +36 -0
- data/plugins/dbus.rb +39 -0
- data/plugins/pstore.rb +34 -0
- data/plugins/svnlookup.rb +63 -0
- metadata +93 -0
data/lib/daemonize.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Shamelessly downloaded and included in Flexo
|
2
|
+
# from http://grub.ath.cx/daemonize/
|
3
|
+
# Not my own work at all.
|
4
|
+
module Daemonize
|
5
|
+
VERSION = "0.1.2"
|
6
|
+
|
7
|
+
# Try to fork if at all possible retrying every 5 sec if the
|
8
|
+
# maximum process limit for the system has been reached
|
9
|
+
def safefork
|
10
|
+
tryagain = true
|
11
|
+
|
12
|
+
while tryagain
|
13
|
+
tryagain = false
|
14
|
+
begin
|
15
|
+
if pid = fork
|
16
|
+
return pid
|
17
|
+
end
|
18
|
+
rescue Errno::EWOULDBLOCK
|
19
|
+
sleep 5
|
20
|
+
tryagain = true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# This method causes the current running process to become a daemon
|
26
|
+
# If closefd is true, all existing file descriptors are closed
|
27
|
+
def daemonize(oldmode=0, closefd=false)
|
28
|
+
srand # Split rand streams between spawning and daemonized process
|
29
|
+
safefork and exit # Fork and exit from the parent
|
30
|
+
|
31
|
+
# Detach from the controlling terminal
|
32
|
+
unless sess_id = Process.setsid
|
33
|
+
raise 'Cannot detach from controlled terminal'
|
34
|
+
end
|
35
|
+
|
36
|
+
# Prevent the possibility of acquiring a controlling terminal
|
37
|
+
if oldmode.zero?
|
38
|
+
trap 'SIGHUP', 'IGNORE'
|
39
|
+
exit if pid = safefork
|
40
|
+
end
|
41
|
+
|
42
|
+
Dir.chdir "/" # Release old working directory
|
43
|
+
File.umask 0000 # Insure sensible umask
|
44
|
+
|
45
|
+
if closefd
|
46
|
+
# Make sure all file descriptors are closed
|
47
|
+
ObjectSpace.each_object(IO) do |io|
|
48
|
+
unless [STDIN, STDOUT, STDERR].include?(io)
|
49
|
+
io.close rescue nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
STDIN.reopen "/dev/null" # Free file descriptors and
|
55
|
+
STDOUT.reopen File.expand_path("~/flexo-err.log"), "a+" # point them somewhere sensible
|
56
|
+
STDERR.reopen STDOUT # STDOUT/STDERR should go to a logfile
|
57
|
+
return oldmode ? sess_id : 0 # Return value is mostly irrelevant
|
58
|
+
end
|
59
|
+
end
|
data/lib/flexo/client.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# dirty haxx
|
2
|
+
$:.push 'lib'
|
3
|
+
|
4
|
+
require 'daemonize'
|
5
|
+
require 'flexo/manager'
|
6
|
+
|
7
|
+
module Flexo
|
8
|
+
# This is the 'main' class of Flexo.
|
9
|
+
# The main file just creates an instance of this class, and then
|
10
|
+
# everything goes automatically. Additionally, it contains tons of
|
11
|
+
# convenience functions, so plugins don't neccessarily have to do everything
|
12
|
+
# so complicated.
|
13
|
+
class Client
|
14
|
+
include Daemonize
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@nickname = nil
|
18
|
+
|
19
|
+
begin
|
20
|
+
@manager = Flexo::Manager.instance
|
21
|
+
@manager.setup
|
22
|
+
rescue InvalidConfigurationException => e
|
23
|
+
$stderr.puts "Invalid configuration from Flexo::Client"
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
|
27
|
+
daemonize
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/flexo/config.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Flexo
|
4
|
+
# Configuration-related functions.
|
5
|
+
# Able to read settings from a file, look them up, change them, and save
|
6
|
+
# them back to the file while the bot is running.
|
7
|
+
class Config
|
8
|
+
attr_reader :configpath
|
9
|
+
attr_reader :configfile
|
10
|
+
|
11
|
+
alias path configpath
|
12
|
+
alias file configfile
|
13
|
+
|
14
|
+
# Reads the configuration file into an array
|
15
|
+
def initialize
|
16
|
+
@configpath = File.expand_path("~/.flexo")
|
17
|
+
@configfile = "#{@configpath}/config.yaml"
|
18
|
+
@config = {}
|
19
|
+
reload(:first)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Very basic validity-test. Just checks if we have *anything*
|
23
|
+
# stored in the configuration.
|
24
|
+
def valid?
|
25
|
+
return !@config.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Lookup-function. Lets us use Config as an array,
|
29
|
+
# for convenience. so instead of Config.lookup('key'),
|
30
|
+
# we can use Config['key']
|
31
|
+
def [](key)
|
32
|
+
if @config[key]
|
33
|
+
return @config[key]
|
34
|
+
end
|
35
|
+
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Same as [], lets you use this class as an array for saving
|
40
|
+
# values as well. Plugins also have access to this class, and
|
41
|
+
# can store their own permanent values here.
|
42
|
+
#
|
43
|
+
# Flexo would preferably use a "namespace", and plugins use their own
|
44
|
+
# namespace, using keys like core.nicks instead of just making a mess.
|
45
|
+
# This would also prevent collisions
|
46
|
+
def []=(key, value)
|
47
|
+
@config[key] = value
|
48
|
+
return @config[key]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Reloads configuration from file, resetting changes made since the
|
52
|
+
# last write.
|
53
|
+
def reload(first = false)
|
54
|
+
begin
|
55
|
+
Dir["#{@configpath}/*.yaml"].each do |file|
|
56
|
+
tmp = YAML.load_file(file)
|
57
|
+
next if tmp.class != Hash && tmp.class != Array
|
58
|
+
@config.merge!(tmp)
|
59
|
+
end
|
60
|
+
rescue
|
61
|
+
if first == :first
|
62
|
+
Flexo::Logger.error "No configuration found. "
|
63
|
+
Flexo::Logger.error "Try mkflexorc for an automated tool to help "
|
64
|
+
Flexo::Logger.error "you create a configuration for Flexo.\n"
|
65
|
+
exit
|
66
|
+
else
|
67
|
+
Flexo::Logger.warn "Configuration has disappeared! Aborting reload."
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Saves the current configuration to a file.
|
73
|
+
def write
|
74
|
+
File.open(@configfile, 'w') do |f|
|
75
|
+
f.puts @config.to_yaml
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Flexo
|
2
|
+
# A collection of various constants
|
3
|
+
module Constants
|
4
|
+
LOG_DEBUG2 = 4
|
5
|
+
LOG_DEBUG = 3
|
6
|
+
LOG_INFO = 2
|
7
|
+
LOG_WARN = 1
|
8
|
+
LOG_ERROR = 0
|
9
|
+
|
10
|
+
CHANPREFIX = ['#', '&', '+', '!']
|
11
|
+
|
12
|
+
FLEXO_VERSION = '0.3.9'
|
13
|
+
FLEXO_RELEASE = 'Bendless Love'
|
14
|
+
end
|
15
|
+
end
|
data/lib/flexo/data.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
module Flexo
|
2
|
+
# This is a handy objecty representation
|
3
|
+
# of an IRC message. Each line is broken into
|
4
|
+
# tiny little pieces, made available to the rest
|
5
|
+
# of Flexo through accessors (only readers).
|
6
|
+
class Data
|
7
|
+
attr_reader :raw
|
8
|
+
attr_reader :message
|
9
|
+
attr_reader :origin
|
10
|
+
attr_reader :params
|
11
|
+
attr_reader :string
|
12
|
+
attr_reader :hostmask
|
13
|
+
attr_reader :numeric
|
14
|
+
|
15
|
+
# Calls parse() and fills up all the variables
|
16
|
+
# with sensible data
|
17
|
+
def initialize(raw)
|
18
|
+
@manager = Flexo::Manager.instance
|
19
|
+
data = parse(raw)
|
20
|
+
|
21
|
+
if data == nil
|
22
|
+
@manager.logger.error("Unable to parse\n#{raw}")
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
@raw = raw
|
27
|
+
@message = data[:message]
|
28
|
+
@origin = data[:origin]
|
29
|
+
@params = data[:params]
|
30
|
+
@string = data[:string]
|
31
|
+
@hostmask = parse_hostmask(@origin) if @origin
|
32
|
+
@numeric = @message =~ /^\d+$/ ? true : false
|
33
|
+
end
|
34
|
+
|
35
|
+
def numeric?
|
36
|
+
@numeric
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
@raw
|
41
|
+
end
|
42
|
+
|
43
|
+
def inspect # :nodoc:
|
44
|
+
"#<#{self.class}:#{(@raw.size > 40 ? @raw[0..40] + '...' : @raw).inspect}>"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Does the actual parsing and splitting and trickery
|
48
|
+
# with the received line
|
49
|
+
def parse(line)
|
50
|
+
m = line.lstrip.chomp.match(/^(?::(\S+) )?(\S+)(?: ([^:].*?[^:]))?(?: :(.*?))?$/)
|
51
|
+
{:origin => m[1], :message => m[2], :params => m[3] ? m[3].split(' ') : [], :string => m[4] || ''} if m
|
52
|
+
end
|
53
|
+
|
54
|
+
# This parses the hostmask, creating an instance of
|
55
|
+
# Flexo::Data::Hostmask.
|
56
|
+
def parse_hostmask(mask)
|
57
|
+
m = mask.match(/^([^!\s]+)(?:(?:!([^@\s]+))?@(\S+))?$/)
|
58
|
+
|
59
|
+
if m
|
60
|
+
host = Hostmask.new(m[1], m[2], m[3])
|
61
|
+
return host
|
62
|
+
end
|
63
|
+
|
64
|
+
return nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# For added fun, we have a small, separate class
|
69
|
+
# for hostmasks. And, being very creative, we call it...
|
70
|
+
# Data::Hostmask!
|
71
|
+
class Data::Hostmask
|
72
|
+
attr_reader :nickname
|
73
|
+
attr_reader :hostname
|
74
|
+
attr_reader :username
|
75
|
+
attr_reader :hostmask
|
76
|
+
|
77
|
+
alias :nick :nickname
|
78
|
+
alias :from :nickname
|
79
|
+
alias :by :nickname
|
80
|
+
|
81
|
+
alias :host :hostname
|
82
|
+
alias :ip :hostname
|
83
|
+
|
84
|
+
alias :user :username
|
85
|
+
alias :ident :username
|
86
|
+
|
87
|
+
alias :mask :hostmask
|
88
|
+
|
89
|
+
# The only function in this class.
|
90
|
+
# When instanciated, this populates some instance variables
|
91
|
+
# with sensible values, and then allow us to access those using
|
92
|
+
# attr_readers
|
93
|
+
def initialize(nickname, username, hostname)
|
94
|
+
@nickname = nickname
|
95
|
+
@username = username
|
96
|
+
@hostname = hostname
|
97
|
+
@hostmask = "#{@nickname}!#{@username}@#{@hostname}".sub(/!?@?$/, '')
|
98
|
+
end
|
99
|
+
|
100
|
+
def inspect
|
101
|
+
"#<#{self.class}:#{@hostmask}>"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'flexo/event'
|
2
|
+
require 'flexo/events/privmsg'
|
3
|
+
require 'flexo/events/notice'
|
4
|
+
require 'flexo/events/reply'
|
5
|
+
require 'flexo/events/unknown'
|
6
|
+
require 'flexo/events/mode'
|
7
|
+
require 'flexo/events/ping'
|
8
|
+
require 'flexo/events/pong'
|
9
|
+
require 'flexo/events/join'
|
10
|
+
require 'flexo/events/part'
|
11
|
+
require 'flexo/events/quit'
|
12
|
+
require 'flexo/events/kick'
|
13
|
+
require 'flexo/events/nick'
|
14
|
+
require 'flexo/events/topic'
|
15
|
+
|
16
|
+
module Flexo
|
17
|
+
# Dispatcher receives data from Flexo::Server, analyzes it, and creates
|
18
|
+
# relevant events (see Flexo::Event), which is then broadcast
|
19
|
+
# to all classes and plugins wanting to use it for something.
|
20
|
+
#
|
21
|
+
# This class also manages subscriptions for events, so all plugins
|
22
|
+
# that want to listen for an event, can use subscribe and unsubscribe
|
23
|
+
# to manage things.
|
24
|
+
class Dispatcher
|
25
|
+
# Save a reference to Flexo::Manager, set up the dispatching-queue,
|
26
|
+
# and get ready for working.
|
27
|
+
def initialize
|
28
|
+
@manager = Flexo::Manager.instance
|
29
|
+
@queue = Queue.new
|
30
|
+
@handlers = {}
|
31
|
+
@triggers = []
|
32
|
+
|
33
|
+
@manager.thread do
|
34
|
+
while event = @queue.shift
|
35
|
+
next unless @handlers.key?(event.class)
|
36
|
+
@handlers[event.class].each { |h|
|
37
|
+
@manager.logger.debug2("Running handler #{h} for #{event.class}")
|
38
|
+
h.call(event)
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Does the handling of incoming lines.
|
45
|
+
# First, we use Flexo::Data to get
|
46
|
+
# anything meaningful out of the line received.
|
47
|
+
# Then, we create a subclass of Flexo::Event, which
|
48
|
+
# is pushed onto the dispatching-queue for further processing.
|
49
|
+
def receive(line)
|
50
|
+
@manager.logger.debug2("Received \"#{line.chomp}\"")
|
51
|
+
data = Data.new(line)
|
52
|
+
event = case data.message
|
53
|
+
when /^\d+$/ then Flexo::Events::ReplyEvent.new @manager, data
|
54
|
+
when 'JOIN' then Flexo::Events::JoinEvent.new @manager, data
|
55
|
+
when 'KICK' then Flexo::Events::KickEvent.new @manager, data
|
56
|
+
when 'MODE' then Flexo::Events::ModeEvent.new @manager, data
|
57
|
+
when 'NICK' then Flexo::Events::NickEvent.new @manager, data
|
58
|
+
when 'NOTICE' then Flexo::Events::NoticeEvent.new @manager, data
|
59
|
+
when 'PART' then Flexo::Events::PartEvent.new @manager, data
|
60
|
+
when 'PING' then Flexo::Events::PingEvent.new @manager, data
|
61
|
+
when 'PONG' then Flexo::Events::PongEvent.new @manager, data
|
62
|
+
when 'PRIVMSG' then Flexo::Events::PrivmsgEvent.new @manager, data
|
63
|
+
when 'QUIT' then Flexo::Events::QuitEvent.new @manager, data
|
64
|
+
when 'TOPIC' then Flexo::Events::TopicEvent.new @manager, data
|
65
|
+
else Flexo::Events::UnknownEvent.new @manager, data
|
66
|
+
end
|
67
|
+
|
68
|
+
@queue << event
|
69
|
+
end
|
70
|
+
|
71
|
+
# Registers a callback function for a specific event.
|
72
|
+
def subscribe(event, &block)
|
73
|
+
if event.is_a?(Symbol) || event.kind_of?(String)
|
74
|
+
if (e = event.to_s) =~ /^(?:RPL|ERR)_/i
|
75
|
+
event = Flexo::Events::ReplyEvent[e.upcase]
|
76
|
+
else
|
77
|
+
match = e.match(/^(.+?)(?:_?event)?$/i)
|
78
|
+
event = Flexo::Events.const_get("#{match[1].capitalize}Event")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if event.is_a? Flexo::Events::ReplyEvent::Numeric
|
83
|
+
numeric = event.numeric
|
84
|
+
event = Flexo::Events::ReplyEvent
|
85
|
+
else
|
86
|
+
numeric = false
|
87
|
+
end
|
88
|
+
|
89
|
+
handler = Handler.new(numeric, &block)
|
90
|
+
@manager.mutex do
|
91
|
+
@handlers[event] ||= []
|
92
|
+
@handlers[event] << handler
|
93
|
+
end
|
94
|
+
|
95
|
+
return handler
|
96
|
+
end
|
97
|
+
|
98
|
+
# Removes an event handler.
|
99
|
+
# Known to be broken.
|
100
|
+
# DO NOT USE.
|
101
|
+
# See bug #28
|
102
|
+
def unsubscribe(handler)
|
103
|
+
@manager.logger.debug("Going to remove handler #{handler}")
|
104
|
+
events = []
|
105
|
+
@manager.mutex do
|
106
|
+
@handlers.each { |e,handlers|
|
107
|
+
if handlers.delete(handler)
|
108
|
+
events << e
|
109
|
+
@manager.logger.debug("Adding #{e} to removal queue")
|
110
|
+
end
|
111
|
+
}
|
112
|
+
events.each { |e|
|
113
|
+
@manager.logger.debug("Removing #{e}")
|
114
|
+
@handlers.delete(e)
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Easy way to add a trigger.
|
120
|
+
# See Flexo::Trigger for documentation
|
121
|
+
def add_trigger(pattern, &block)
|
122
|
+
trigger = Flexo::Trigger.new(pattern, &block)
|
123
|
+
@manager.mutex { @triggers << trigger }
|
124
|
+
trigger
|
125
|
+
end
|
126
|
+
|
127
|
+
# Easy way to remove a trigger.
|
128
|
+
# Must be passed a Flexo::Trigger object
|
129
|
+
def remove_trigger(trigger)
|
130
|
+
trigger.unsubscribe
|
131
|
+
@manager.mutex { @triggers.delete(trigger) }
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
data/lib/flexo/errors.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Flexo
|
2
|
+
# Our base-class for errors and exceptions
|
3
|
+
class Error < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
# Raised when the configuration is invalid, and there's no way to recover
|
7
|
+
class InvalidConfigurationException < Error
|
8
|
+
end
|
9
|
+
|
10
|
+
# Raised when a plugin is missing a required dependency
|
11
|
+
class PluginDependencyError < Error
|
12
|
+
end
|
13
|
+
|
14
|
+
# Default error for plugins
|
15
|
+
class PluginError < Error
|
16
|
+
end
|
17
|
+
|
18
|
+
# Exception raised when a plugin is missing a name
|
19
|
+
class PluginNameError < PluginError
|
20
|
+
end
|
21
|
+
|
22
|
+
# Raised when there's a name conflict
|
23
|
+
class PluginConflictError < PluginError
|
24
|
+
end
|
25
|
+
|
26
|
+
# Trying to load, but could not be found (404)
|
27
|
+
class PluginNotFoundError < PluginError
|
28
|
+
end
|
29
|
+
end
|
data/lib/flexo/event.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Flexo
|
2
|
+
# Base class for all events generated by Flexo.
|
3
|
+
# Nothing of interest happening here, actually.
|
4
|
+
# Most of the fun stuff is taken care of by the subclasses
|
5
|
+
class Event
|
6
|
+
attr_reader :data
|
7
|
+
attr_reader :nickname
|
8
|
+
|
9
|
+
alias nick nickname
|
10
|
+
alias from nickname
|
11
|
+
alias by nickname
|
12
|
+
alias who nickname
|
13
|
+
|
14
|
+
# Create the event, setting some variables
|
15
|
+
def initialize(manager, data)
|
16
|
+
@manager = manager
|
17
|
+
@data = data
|
18
|
+
@manager.logger.debug("Creating instance of #{self.class}")
|
19
|
+
end
|
20
|
+
|
21
|
+
# Checks the nickname in the hostmask
|
22
|
+
# to see if you're the one that made this event trigger,
|
23
|
+
# or if it was someone else.
|
24
|
+
def me?
|
25
|
+
end
|
26
|
+
|
27
|
+
alias is_me? me?
|
28
|
+
alias from_me? me?
|
29
|
+
alias by_me? me?
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Flexo
|
2
|
+
module Events
|
3
|
+
class KickEvent < Event
|
4
|
+
attr_reader :channel
|
5
|
+
attr_reader :kicker
|
6
|
+
attr_reader :victim
|
7
|
+
attr_reader :reason
|
8
|
+
|
9
|
+
alias kicked_by kicker
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
super
|
13
|
+
@kicker = @data.hostmask.nick
|
14
|
+
@channel = @data.params[0]
|
15
|
+
@victim = @data.params[1]
|
16
|
+
@reason = @data.string
|
17
|
+
end
|
18
|
+
|
19
|
+
def kicked_me?
|
20
|
+
@victim == @manager.nickname
|
21
|
+
end
|
22
|
+
|
23
|
+
def rejoin
|
24
|
+
sleep rand*5
|
25
|
+
@manager.sender.join(@channel)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Flexo
|
2
|
+
module Events
|
3
|
+
class ModeEvent < Event
|
4
|
+
attr_reader :modes
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
super
|
8
|
+
@channelmode = Flexo::Constants::CHANPREFIX.include?(@data.params[0][0])
|
9
|
+
@modes = @data.params[1..-1].join(' ')
|
10
|
+
end
|
11
|
+
|
12
|
+
def usermode?
|
13
|
+
!@channelmode
|
14
|
+
end
|
15
|
+
|
16
|
+
def channelmode?
|
17
|
+
@channelmode
|
18
|
+
end
|
19
|
+
|
20
|
+
alias chanmode? channelmode?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Flexo
|
2
|
+
module Events
|
3
|
+
# A little special event. This one is identical to Flexo::Events::PrivmsgEvent,
|
4
|
+
# so see that one for documentation.
|
5
|
+
class NoticeEvent < PrivmsgEvent
|
6
|
+
# We default to not replying to a channel for these.
|
7
|
+
def reply(target, to_channel=false)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Flexo
|
2
|
+
module Events
|
3
|
+
# Private messages, which, in fact, isn't neccessarily private.
|
4
|
+
# When the target of a privmsg is a channel, it's displayed to the
|
5
|
+
# entire channel. Which isn't very private at all.
|
6
|
+
class PrivmsgEvent < Event
|
7
|
+
attr_reader :sender
|
8
|
+
attr_reader :target
|
9
|
+
attr_reader :text
|
10
|
+
alias from sender
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
super
|
14
|
+
@sender = @data.hostmask.nick if @data.hostmask
|
15
|
+
@target = @data.params[0]
|
16
|
+
@ctcp = (m = @data.string.match(/^\x01(.+?)\x01$/)) ? true : false
|
17
|
+
@text = @ctcp ? m[1] : @data.string
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns true if this was a CTCP-message, and false if not.
|
21
|
+
def ctcp?
|
22
|
+
return @ctcp
|
23
|
+
end
|
24
|
+
|
25
|
+
# Were you the target of the message?
|
26
|
+
def to_me?
|
27
|
+
return @target == @manager.nickname # FIXME: Should this be stored here?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Sent to a channel, or was it actually a private message?
|
31
|
+
def to_channel?
|
32
|
+
return Flexo::Constants::CHANPREFIX.include?(@target[0..0])
|
33
|
+
end
|
34
|
+
|
35
|
+
# Sends a quick reply to the message.
|
36
|
+
# If to_channel is false, it's sent to the person who sent the
|
37
|
+
# message, whether he sent it to a channel, or private.
|
38
|
+
# If it was sent to you, this will send a direct reply
|
39
|
+
# no matter what to_channel is set to.
|
40
|
+
def reply(text, to_channel=true)
|
41
|
+
target = (to_channel && to_channel?) ? @target : @sender
|
42
|
+
@manager.sender.privmsg(target, text)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|