blur 1.8.6 → 2.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +10 -24
- data/executables/blur +63 -0
- data/library/blur/callbacks.rb +53 -0
- data/library/blur/channel.rb +78 -0
- data/library/blur/client.rb +165 -107
- data/library/blur/handling.rb +259 -179
- data/library/blur/network/connection.rb +26 -30
- data/library/blur/network/isupport.rb +38 -32
- data/library/blur/network.rb +193 -55
- data/library/blur/script.rb +132 -116
- data/library/blur/script_cache.rb +45 -0
- data/library/blur/user.rb +122 -0
- data/library/blur/version.rb +3 -3
- data/library/blur.rb +46 -19
- metadata +35 -28
- data/library/blur/encryption/base64.rb +0 -71
- data/library/blur/encryption/fish.rb +0 -80
- data/library/blur/encryption.rb +0 -17
- data/library/blur/enhancements.rb +0 -41
- data/library/blur/evaluable.rb +0 -13
- data/library/blur/extension.rb +0 -42
- data/library/blur/network/channel.rb +0 -91
- data/library/blur/network/command.rb +0 -83
- data/library/blur/network/user.rb +0 -106
- data/library/blur/script/cache.rb +0 -77
- data/library/blur/script/commands.rb +0 -77
- data/library/blur/script/dsl.rb +0 -52
@@ -1,71 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
module Encryption
|
5
|
-
# The +Encryption::Base64+ module differs from the original Base64
|
6
|
-
# implementation. I'm not sure how exactly, perhaps the charset?
|
7
|
-
#
|
8
|
-
# I originally found the Ruby implementation of FiSH on a website where
|
9
|
-
# it was graciously submitted by an anonymous user, since then I've
|
10
|
-
# implemented it in a weechat script, and now I've refactored it for use in
|
11
|
-
# Blur.
|
12
|
-
#
|
13
|
-
# @see http://maero.dk/pub/sources/weechat/ruby/autoload/fish.rb
|
14
|
-
module Base64
|
15
|
-
# The difference I suspect between the original Base64 implementation
|
16
|
-
# and the one used in FiSH.
|
17
|
-
Charset = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
18
|
-
|
19
|
-
# Decode a base64-encoded string.
|
20
|
-
#
|
21
|
-
# @return [String] Base64-decoded string.
|
22
|
-
def self.decode string
|
23
|
-
unless string.length % 12 == 0
|
24
|
-
raise BadInputError, "input has to be a multiple of 12 characters."
|
25
|
-
end
|
26
|
-
|
27
|
-
String.new.tap do |buffer|
|
28
|
-
j = -1
|
29
|
-
|
30
|
-
while j < string.length - 1
|
31
|
-
right, left = 0, 0
|
32
|
-
|
33
|
-
6.times{|i| right |= Charset.index(string[j += 1]) << (i * 6) }
|
34
|
-
6.times{|i| left |= Charset.index(string[j += 1]) << (i * 6) }
|
35
|
-
|
36
|
-
4.times do |i|
|
37
|
-
buffer << ((left & (0xFF << ((3 - i) * 8))) >> ((3 - i) * 8)).chr
|
38
|
-
end
|
39
|
-
|
40
|
-
4.times do |i|
|
41
|
-
buffer << ((right & (0xFF << ((3 - i) * 8))) >> ((3 - i) * 8)).chr
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Encode a string-cipher.
|
48
|
-
#
|
49
|
-
# @return [String] Base64-encoded string.
|
50
|
-
def self.encode string
|
51
|
-
unless string.length % 8 == 0
|
52
|
-
raise BadInputError, "input has to be a multiple of 8 characters."
|
53
|
-
end
|
54
|
-
|
55
|
-
left = 0
|
56
|
-
right = 0
|
57
|
-
decimals = [24, 16, 8, 0]
|
58
|
-
|
59
|
-
String.new.tap do |buffer|
|
60
|
-
string.each_block do |block|
|
61
|
-
4.times{|i| left += (block[i].ord << decimals[i]) }
|
62
|
-
4.times{|i| right += (block[i+4].ord << decimals[i]) }
|
63
|
-
|
64
|
-
6.times{|i| buffer << Charset[right & 0x3F].chr; right = right >> 6 }
|
65
|
-
6.times{|i| buffer << Charset[left & 0x3F].chr; left = left >> 6 }
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'crypt/blowfish'
|
4
|
-
|
5
|
-
module Blur
|
6
|
-
module Encryption
|
7
|
-
# The +FiSH+ algorithm is a combination of Base64 encoding
|
8
|
-
# and the blowfish encryption.
|
9
|
-
#
|
10
|
-
# Shared text messages are prepended by "++OK+", an older implementation
|
11
|
-
# prepends it with "+mcps+" - Blur drops support for that implementation.
|
12
|
-
#
|
13
|
-
# There's multiple client-implementations available on the official FiSH
|
14
|
-
# homepage.
|
15
|
-
#
|
16
|
-
# == DH1080 Key exchange
|
17
|
-
# The newer FiSH implementation introduces a 1080bit Diffie-Hellman
|
18
|
-
# key-exchange mechanism.
|
19
|
-
#
|
20
|
-
# Blur does currently not support key exchanges.
|
21
|
-
class FiSH
|
22
|
-
# The standard FiSH block-size.
|
23
|
-
BlockSize = 8
|
24
|
-
|
25
|
-
# @return [String] the blowfish salt-key.
|
26
|
-
attr_accessor :keyphrase
|
27
|
-
|
28
|
-
# Change the keyphrase and instantiate a new blowfish object.
|
29
|
-
def keyphrase= keyphrase
|
30
|
-
@keyphrase = keyphrase
|
31
|
-
@blowfish = Crypt::Blowfish.new @keyphrase
|
32
|
-
end
|
33
|
-
|
34
|
-
# Instantiate a new fish-encryption object.
|
35
|
-
def initialize keyphrase
|
36
|
-
@keyphrase = keyphrase
|
37
|
-
@blowfish = Crypt::Blowfish.new keyphrase
|
38
|
-
end
|
39
|
-
|
40
|
-
# Encrypt an input string using the keyphrase stored in the +@blowfish+
|
41
|
-
# object.
|
42
|
-
#
|
43
|
-
# @return [String] the encrypted string.
|
44
|
-
def encrypt string
|
45
|
-
String.new.tap do |buffer|
|
46
|
-
nullpad(string).each_block do |block|
|
47
|
-
chunk = @blowfish.encrypt_block block
|
48
|
-
buffer.concat Base64.encode chunk
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Decrypt an input string using the keyphrase stored in the +@blowfish+
|
54
|
-
# object.
|
55
|
-
#
|
56
|
-
# @return [String] the decrypted string.
|
57
|
-
def decrypt string
|
58
|
-
unless string.length % 12 == 0
|
59
|
-
raise BadInputError, "input has to be a multiple of 12 characters."
|
60
|
-
end
|
61
|
-
|
62
|
-
String.new.tap do |buffer|
|
63
|
-
string.each_block 12 do |block|
|
64
|
-
chunk = @blowfish.decrypt_block Base64.decode block
|
65
|
-
buffer.concat chunk
|
66
|
-
end
|
67
|
-
end.rstrip
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
# Fill up the last block with null-bytes until it's a multiple of 8.
|
72
|
-
#
|
73
|
-
# @return [String] the nullpadded string.
|
74
|
-
def nullpad string
|
75
|
-
length = string.length + BlockSize - string.length % BlockSize
|
76
|
-
string.ljust length, ?\0
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
data/library/blur/encryption.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
# The +Encryption+ module extends the communication-functionality of
|
5
|
-
# the client. It is intended to enable helpers but also core functionality
|
6
|
-
# that encrypts the incoming and outgoing data of Blur.
|
7
|
-
#
|
8
|
-
# Encryption modules are not loaded into the VM until it's required.
|
9
|
-
module Encryption
|
10
|
-
# Indicates that user-input (a channel user message, e.g.) is in invalid
|
11
|
-
# format to a certain encryption algorithm.
|
12
|
-
class BadInputError < StandardError; end
|
13
|
-
|
14
|
-
autoload :FiSH, "blur/encryption/fish"
|
15
|
-
autoload :Base64, "blur/encryption/base64"
|
16
|
-
end
|
17
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
# Reopens the scope of the standard Exception-class to extend it with helpful
|
4
|
-
# methods.
|
5
|
-
class Exception
|
6
|
-
# The pattern to match against the backtrace log.
|
7
|
-
Pattern = /^.*?:(\d+):/
|
8
|
-
|
9
|
-
# Retrieve the line on which the exception was raised from when raised inside
|
10
|
-
# a script.
|
11
|
-
#
|
12
|
-
# @return Fixnum the line of the script the exception was raised on.
|
13
|
-
def line
|
14
|
-
if result = backtrace[0].match(Pattern)
|
15
|
-
result[1].to_i + 1
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Reopens the scope of the standard String-class to extend it with helpful
|
21
|
-
# methods.
|
22
|
-
class String
|
23
|
-
# Checks if the string contains nothing but a numeric value.
|
24
|
-
#
|
25
|
-
# @return true if it is a numeric value.
|
26
|
-
def numeric?
|
27
|
-
self =~ /^\d+$/
|
28
|
-
end
|
29
|
-
|
30
|
-
# Split a string up in n chunks and then iterate through them, exactly like
|
31
|
-
# Enumerable#each_slice.
|
32
|
-
#
|
33
|
-
# @return [Enumerator] list of slices.
|
34
|
-
# @yieldreturn [Array] list of elements in each slice consecutively.
|
35
|
-
def each_slice size = 8
|
36
|
-
self.chars.each_slice(size).each{|slice| yield slice.join }
|
37
|
-
end
|
38
|
-
|
39
|
-
alias_method :starts_with?, :start_with?
|
40
|
-
alias_method :each_block, :each_slice
|
41
|
-
end
|
data/library/blur/evaluable.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
module Evaluable
|
5
|
-
# Evaluate the contents of the input file in the context of +self+.
|
6
|
-
def evaluate_source_file path
|
7
|
-
instance_eval File.read(path), File.basename(path), 0
|
8
|
-
@__evaluated = true
|
9
|
-
rescue Exception => exception
|
10
|
-
puts "#{exception.message ^ :bold} on line #{exception.line.to_s ^ :bold}"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/library/blur/extension.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
# +Extension+ provides a sort of modules for scripts, for common functionality.
|
5
|
-
#
|
6
|
-
# Think of it as a kind of scripts for scripts.
|
7
|
-
class Extension
|
8
|
-
include Evaluable
|
9
|
-
include Script::DSL
|
10
|
-
include Logging
|
11
|
-
|
12
|
-
# @return the path in which the script remains.
|
13
|
-
attr_accessor :__path
|
14
|
-
# Can be used inside the script to act with the client itself.
|
15
|
-
# @return [Network::Client] the client delegate.
|
16
|
-
attr_accessor :__client
|
17
|
-
|
18
|
-
# Instantiates a new extension context and evaluates the +path+ extension
|
19
|
-
# file.
|
20
|
-
def initialize path
|
21
|
-
@__path = path
|
22
|
-
|
23
|
-
if evaluate_source_file path
|
24
|
-
log.info "Loaded extension #{@__path}"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# Purely for DSL purposes.
|
29
|
-
#
|
30
|
-
# @example
|
31
|
-
# Extension :http do
|
32
|
-
# …
|
33
|
-
# end
|
34
|
-
def Extension name, &block
|
35
|
-
@__name = name
|
36
|
-
|
37
|
-
instance_eval &block
|
38
|
-
|
39
|
-
true
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
class Network
|
5
|
-
# The +Channel+ class is used for encapsulating a channel and its properties.
|
6
|
-
#
|
7
|
-
# Users inside the channel is stored in the {#channels} attribute.
|
8
|
-
#
|
9
|
-
# Modes can be set for a channel, but Blur is not
|
10
|
-
# {http://www.irc.org/tech_docs/005.html ISupport}-compliant yet.
|
11
|
-
#
|
12
|
-
# @todo make so that channels *and* users belongs to the network, and not
|
13
|
-
# like now where the user belongs to the channel, resulting in multiple
|
14
|
-
# user instances.
|
15
|
-
class Channel
|
16
|
-
# @return [String] the channels name.
|
17
|
-
attr_accessor :name
|
18
|
-
# @return [Array] a list of users in the channel.
|
19
|
-
attr_accessor :users
|
20
|
-
# @return [String] the channels topic.
|
21
|
-
attr_accessor :topic
|
22
|
-
# @return [String] all the modes set on the channel.
|
23
|
-
attr_accessor :modes
|
24
|
-
# @return [Network] a reference to the network.
|
25
|
-
attr_accessor :network
|
26
|
-
# @return [Encryption::Fish] the channel encryption, if any.
|
27
|
-
attr_accessor :encryption
|
28
|
-
|
29
|
-
# Check whether or not this is an encrypted channel.
|
30
|
-
def encrypted?; not @encryption.nil? end
|
31
|
-
|
32
|
-
# Instantiate a user with a nickname, a network and a user list.
|
33
|
-
def initialize name, network = nil, users = []
|
34
|
-
@name = name
|
35
|
-
@users = users
|
36
|
-
@modes = ""
|
37
|
-
@network = network
|
38
|
-
|
39
|
-
users.each { |user| user.channel = self }
|
40
|
-
end
|
41
|
-
|
42
|
-
# Merge the channels mode corresponding to the leading character (+ or -).
|
43
|
-
#
|
44
|
-
# @param [String] modes the modes to merge with.
|
45
|
-
def merge_modes modes
|
46
|
-
addition = true
|
47
|
-
|
48
|
-
modes.each_char do |char|
|
49
|
-
case char
|
50
|
-
when ?+
|
51
|
-
addition = true
|
52
|
-
when ?-
|
53
|
-
addition = false
|
54
|
-
else
|
55
|
-
addition ? @modes.concat(char) : @modes.delete!(char)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Send a message to the channel.
|
61
|
-
#
|
62
|
-
# @param [String] message the message to send.
|
63
|
-
def say message
|
64
|
-
@network.say self, message
|
65
|
-
end
|
66
|
-
|
67
|
-
# Find a user with +nick+ as its nickname.
|
68
|
-
#
|
69
|
-
# @param [String] nick the nickname to find the user of.
|
70
|
-
def user_by_nick nick
|
71
|
-
@users.find { |user| user.nick == nick }
|
72
|
-
end
|
73
|
-
|
74
|
-
# Convert it to a debug-friendly format.
|
75
|
-
def inspect
|
76
|
-
%{#<#{self.class.name} @name=#{@name.inspect} @users=#{@users.inspect}}
|
77
|
-
end
|
78
|
-
|
79
|
-
# Called when YAML attempts to save the object, which happens when a
|
80
|
-
# scripts cache contains this user and the script is unloaded.
|
81
|
-
def to_yaml options = {}
|
82
|
-
@name.to_yaml options
|
83
|
-
end
|
84
|
-
|
85
|
-
# Get the channels name.
|
86
|
-
def to_s
|
87
|
-
@name
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
class Network
|
5
|
-
# The +Command+ class is used for encapsulating the command-lines.
|
6
|
-
#
|
7
|
-
# Blur is using regular-expression for parsing, this is to be replaced
|
8
|
-
# with a more native way of parsing, making it much, much easier on the
|
9
|
-
# processor.
|
10
|
-
class Command
|
11
|
-
# @return [Symbol, Fixnum] the command name.
|
12
|
-
# @example
|
13
|
-
# 332 or :quit
|
14
|
-
attr_accessor :name
|
15
|
-
# @return [Array] a list of parameters.
|
16
|
-
attr_accessor :params
|
17
|
-
# @return [String] a hostname or a hostmask.
|
18
|
-
attr_accessor :prefix
|
19
|
-
|
20
|
-
# The arbitrary regex pattern.
|
21
|
-
Pattern = /^(?:[:@]([^\s]+) )?([^\s]+)(?: ((?:[^:\s][^\s]* ?)*))?(?: ?:(.*))?$/
|
22
|
-
|
23
|
-
# Parse a line and encapsulate it as a Command.
|
24
|
-
#
|
25
|
-
# @return [Command] the parsed command.
|
26
|
-
# @example
|
27
|
-
# Command.parse "ChanServ!ChanServ@services.uplink.io MODE #uplink +v mk"
|
28
|
-
# # => #<Blur::Network::Command … >
|
29
|
-
def self.parse data
|
30
|
-
match = data.strip.match Pattern
|
31
|
-
prefix, name, args, extra = match.captures
|
32
|
-
params = extra ? args.split << extra : args.split
|
33
|
-
|
34
|
-
new(name, params).tap do |this|
|
35
|
-
this.prefix = prefix
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# Get a parameter by its +index+.
|
40
|
-
def [] index; @params[index] end
|
41
|
-
|
42
|
-
# Instantiate a command.
|
43
|
-
#
|
44
|
-
# @see Command.parse
|
45
|
-
def initialize name, params = []
|
46
|
-
@name, @params = name, params
|
47
|
-
end
|
48
|
-
|
49
|
-
# Get the sender of the command.
|
50
|
-
#
|
51
|
-
# @note the return value is a string if it's a hostname, and an openstruct
|
52
|
-
# with the attributes #nickname, #username and #hostname if it's a
|
53
|
-
# hostmask.
|
54
|
-
#
|
55
|
-
# @return [String, OpenStruct] the sender.
|
56
|
-
def sender
|
57
|
-
return @sender if @sender
|
58
|
-
|
59
|
-
if prefix =~ /^(\S+)!(\S+)@(\S+)$/
|
60
|
-
@sender = OpenStruct.new nickname: $1, username: $2, hostname: $3
|
61
|
-
else
|
62
|
-
@sender = prefix
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# Convert it to an IRC-compliant line.
|
67
|
-
#
|
68
|
-
# @return [String] the command line.
|
69
|
-
def to_s
|
70
|
-
String.new.tap do |line|
|
71
|
-
line << "#{prefix} " if prefix
|
72
|
-
line << name.to_s
|
73
|
-
|
74
|
-
params.each_with_index do |param, index|
|
75
|
-
line << ' '
|
76
|
-
line << ?: if index == params.length - 1 and param =~ /[ :]/
|
77
|
-
line << param.to_s
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,106 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
class Network
|
5
|
-
# The +User+ class is used for encapsulating a user and its properties.
|
6
|
-
#
|
7
|
-
# The user owns a reference to its parent channel.
|
8
|
-
#
|
9
|
-
# Modes can be set for a user, but Blur is not
|
10
|
-
# {http://www.irc.org/tech_docs/005.html ISupport}-compliant yet.
|
11
|
-
#
|
12
|
-
# @todo make so that channels *and* users belongs to the network, and not
|
13
|
-
# like now where the user belongs to the channel, resulting in multiple
|
14
|
-
# user instances.
|
15
|
-
class User
|
16
|
-
# @return [String] the users nickname.
|
17
|
-
attr_accessor :nick
|
18
|
-
# @return [String] the users username.
|
19
|
-
attr_accessor :name
|
20
|
-
# @return [String] the users hostname.
|
21
|
-
attr_accessor :host
|
22
|
-
# @return [String] all the modes set on the user.
|
23
|
-
attr_accessor :modes
|
24
|
-
# @return [Channel] a reference to the users channel.
|
25
|
-
attr_accessor :channel
|
26
|
-
# @return [Network] a reference to the network.
|
27
|
-
attr_accessor :network
|
28
|
-
|
29
|
-
# Check to see if the user is an admin (+a)
|
30
|
-
def admin?; @modes.include? "a" end
|
31
|
-
# Check to see if the user has voice (+v)
|
32
|
-
def voice?; @modes.include? "v" end
|
33
|
-
# Check to see if the user is the owner (+q)
|
34
|
-
def owner?; @modes.include? "q" end
|
35
|
-
# Check to see if the user is an operator (+o)
|
36
|
-
def operator?; @modes.include? "o" end
|
37
|
-
# Check to see if the user is an half-operator (+h)
|
38
|
-
def half_operator?; @modes.include? "h" end
|
39
|
-
|
40
|
-
# Instantiate a user with a nickname.
|
41
|
-
def initialize nick
|
42
|
-
@nick = nick
|
43
|
-
@modes = ""
|
44
|
-
|
45
|
-
if modes = prefix_to_mode(nick[0])
|
46
|
-
@nick = nick[1..-1]
|
47
|
-
@modes = modes
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Merge the users mode corresponding to the leading character (+ or -).
|
52
|
-
#
|
53
|
-
# @param [String] modes the modes to merge with.
|
54
|
-
def merge_modes modes
|
55
|
-
addition = true
|
56
|
-
|
57
|
-
modes.each_char do |char|
|
58
|
-
case char
|
59
|
-
when ?+
|
60
|
-
addition = true
|
61
|
-
when ?-
|
62
|
-
addition = false
|
63
|
-
else
|
64
|
-
addition ? @modes.concat(char) : @modes.delete!(char)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Send a private message to the user.
|
70
|
-
#
|
71
|
-
# @param [String] message the message to send.
|
72
|
-
def say message
|
73
|
-
@network.say self, message
|
74
|
-
end
|
75
|
-
|
76
|
-
# Convert it to a debug-friendly format.
|
77
|
-
def inspect
|
78
|
-
%{#<#{self.class.name} @nick=#{@nick.inspect} @channel=#{@channel.name.inspect}>}
|
79
|
-
end
|
80
|
-
|
81
|
-
# Called when YAML attempts to save the object, which happens when a
|
82
|
-
# scripts cache contains this user and the script is unloaded.
|
83
|
-
def to_yaml options = {}
|
84
|
-
@nick.to_yaml options
|
85
|
-
end
|
86
|
-
|
87
|
-
# Get the users nickname.
|
88
|
-
def to_s
|
89
|
-
@nick
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
# Translate a nickname-prefix to a mode character.
|
95
|
-
def prefix_to_mode prefix
|
96
|
-
case prefix
|
97
|
-
when '@' then 'o'
|
98
|
-
when '+' then 'v'
|
99
|
-
when '%' then 'h'
|
100
|
-
when '&' then 'a'
|
101
|
-
when '~' then 'q'
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
class Script
|
5
|
-
# The +Cache+ class enables data storing inside Blur and it scripts.
|
6
|
-
#
|
7
|
-
# What it does is simply store a hash, and act like it is that hash.
|
8
|
-
#
|
9
|
-
# When the client closes, it sends a message to all available scripts
|
10
|
-
# and then those scripts tells the cache to save, in order to remember
|
11
|
-
# that data and reload it at the next run.
|
12
|
-
#
|
13
|
-
# Cache can then save the contents of the hash to a yaml file that persists
|
14
|
-
# in the ./cache/ directory.
|
15
|
-
#
|
16
|
-
# That same file is then loaded once needed again.
|
17
|
-
class Cache
|
18
|
-
# Get the path to the cache directory (./cache/)
|
19
|
-
def self.path
|
20
|
-
%{#{File.dirname File.expand_path $0}/cache}
|
21
|
-
end
|
22
|
-
|
23
|
-
# Check if there exists a cache file for the script with name +name+.
|
24
|
-
def self.exists? name
|
25
|
-
File.exists? "#{path}/#{name}.yml"
|
26
|
-
end
|
27
|
-
|
28
|
-
# Get a cache value by key.
|
29
|
-
def [] key; @hash[key] end
|
30
|
-
|
31
|
-
# Set a cache value by key.
|
32
|
-
def []= key, value; @hash[key] = value end
|
33
|
-
|
34
|
-
# Instantiate a cache with a script reference.
|
35
|
-
def initialize script
|
36
|
-
@hash = {}
|
37
|
-
@script = script
|
38
|
-
end
|
39
|
-
|
40
|
-
# Save all internal data to a yaml file in the cache directory.
|
41
|
-
def save
|
42
|
-
directory = File.dirname path
|
43
|
-
|
44
|
-
unless File.directory? directory
|
45
|
-
Dir.mkdir directory
|
46
|
-
end
|
47
|
-
|
48
|
-
File.open path, ?w do |file|
|
49
|
-
YAML.dump @hash, file
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Load a yaml file as internal data from the cache directory.
|
54
|
-
#
|
55
|
-
# @return [Hash] the loaded data.
|
56
|
-
def load
|
57
|
-
if yaml = YAML.load_file(path)
|
58
|
-
@hash = yaml
|
59
|
-
end
|
60
|
-
rescue
|
61
|
-
File.unlink path
|
62
|
-
end
|
63
|
-
|
64
|
-
# Let Hash#to_s do the job.
|
65
|
-
def to_s; @hash end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
# The current caches file path.
|
70
|
-
#
|
71
|
-
# @return [String] the file path.
|
72
|
-
def path
|
73
|
-
%{#{Cache.path}/#{@script.__name}.yml}
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
class Script
|
5
|
-
# The +Commands+ module is a module that gives the ability to turn a
|
6
|
-
# script into a DSL-like framework.
|
7
|
-
module Commands
|
8
|
-
class Command
|
9
|
-
DefaultOptions = { prefix: '.', hostmask: nil }
|
10
|
-
|
11
|
-
def initialize triggers, options = {}, &block
|
12
|
-
@triggers = Array === triggers ? triggers : [triggers]
|
13
|
-
@options = DefaultOptions.merge options
|
14
|
-
@block = block
|
15
|
-
end
|
16
|
-
|
17
|
-
# Called by the Commands module.
|
18
|
-
#
|
19
|
-
# Calls the command block if the trigger matches the criteria.
|
20
|
-
def received_message user, channel, message
|
21
|
-
prefix = @options[:prefix]
|
22
|
-
|
23
|
-
# Return if the prefix don't match.
|
24
|
-
return unless message.start_with? prefix
|
25
|
-
|
26
|
-
# Return if the hostmask don't match.
|
27
|
-
# FIXME: Maybe use globbing instead of regular expressions?
|
28
|
-
unless @options[:hostmask].nil?
|
29
|
-
hostmask = "#{user.nick}!#{user.name}@#{user.host}"
|
30
|
-
|
31
|
-
return unless hostmask =~ @options[:hostmask]
|
32
|
-
end
|
33
|
-
|
34
|
-
command, args = split_message message
|
35
|
-
|
36
|
-
# Strip the prefix and compare the trigger name.
|
37
|
-
if self.matches_trigger? command
|
38
|
-
@block.call user, channel, args
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
protected
|
43
|
-
|
44
|
-
def split_message message
|
45
|
-
prefix = @options[:prefix]
|
46
|
-
command, args = message[prefix.length..-1].split $;, 2
|
47
|
-
|
48
|
-
return command, args
|
49
|
-
end
|
50
|
-
|
51
|
-
def matches_trigger? command
|
52
|
-
return @triggers.find{|trigger| trigger.to_s == command }
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# Extend +base+ with self.
|
57
|
-
def self.extended base
|
58
|
-
base.instance_variable_set :@__commands, []
|
59
|
-
end
|
60
|
-
|
61
|
-
# Add a new command handler and trigger.
|
62
|
-
def command name, *args, &block
|
63
|
-
@__commands << Command.new(name, *args, &block)
|
64
|
-
end
|
65
|
-
|
66
|
-
# Handle all calls to the scripts +message+ method, check to see if
|
67
|
-
# the message containts a valid command, serialize it and pass it to
|
68
|
-
# the script as command_name with the parameters +user+, +channel+
|
69
|
-
# and +message+.
|
70
|
-
def message user, channel, line
|
71
|
-
@__commands.each do |command|
|
72
|
-
command.received_message user, channel, line
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|