fantasy-irc 0.1.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.
- data/LICENSE.md +23 -0
- data/README.md +30 -0
- data/docs/PLUGINS.md +11 -0
- data/docs/example.rb +37 -0
- data/fantasy-irc.gemspec +15 -0
- data/lib/fantasy-irc.rb +5 -0
- data/lib/fantasy-irc/events.rb +64 -0
- data/lib/fantasy-irc/irc.rb +202 -0
- data/lib/fantasy-irc/plugins.rb +61 -0
- data/lib/fantasy-irc/rooms.rb +79 -0
- data/lib/fantasy-irc/users.rb +80 -0
- data/lib/plugins/corecommands.rb +53 -0
- metadata +73 -0
data/LICENSE.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2013 Jens Becker
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# fantasy-irc
|
2
|
+
|
3
|
+
A modular, event-driven IRC client gem for Ruby with plugin support
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'fantasy-irc'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install fantasy-irc
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
30
|
+
|
data/docs/PLUGINS.md
ADDED
data/docs/example.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'fantasy-irc'
|
3
|
+
|
4
|
+
# new connection
|
5
|
+
bot = Fantasy::IRC.new
|
6
|
+
|
7
|
+
# load some plugins
|
8
|
+
bot.plugins.load 'corecommands'
|
9
|
+
|
10
|
+
# log in once we are connected
|
11
|
+
connected = Proc.new do
|
12
|
+
bot.login :nickname => "example", :username => "example", :realname => "GECOS field"
|
13
|
+
end
|
14
|
+
bot.events.by_name('connected').register &connected
|
15
|
+
|
16
|
+
# join a room and say hi
|
17
|
+
loggedin = Proc.new do
|
18
|
+
%w{#lobby}.each do |r|
|
19
|
+
room = bot.rooms.new(r).join.say "ohai"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
bot.events.by_name('loggedin').register &loggedin
|
23
|
+
|
24
|
+
# we also want to greet users that are joining the room
|
25
|
+
user_joined = Proc.new do |room, user|
|
26
|
+
room.say("Hey, #{user.name}!")
|
27
|
+
end
|
28
|
+
bot.events.by_name('user_joined').register &user_joined
|
29
|
+
|
30
|
+
# and monitor everything they say
|
31
|
+
channel_message = Proc.new do |room, user, text|
|
32
|
+
puts "!! #{user.name} said in room #{room.name}: #{text}"
|
33
|
+
end
|
34
|
+
bot.events.by_name('channel_message').register &channel_message
|
35
|
+
|
36
|
+
bot.connect :server => "irc.example.com", :ssl => true, :port => 6697
|
37
|
+
bot.run
|
data/fantasy-irc.gemspec
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.authors = ["Jens Becker"]
|
3
|
+
s.email = ["v2px@v2px.de"]
|
4
|
+
s.description = "A modular, event-driven IRC client/bot gem for Ruby with plugin support"
|
5
|
+
s.summary = "A modular, event-driven IRC client/bot gem for Ruby with plugin support"
|
6
|
+
s.homepage = "https://github.com/v2px/fantasy-irc"
|
7
|
+
|
8
|
+
s.files = `git ls-files`.split("\n")
|
9
|
+
s.name = "fantasy-irc"
|
10
|
+
s.require_paths = ['lib']
|
11
|
+
s.version = "0.1.0"
|
12
|
+
|
13
|
+
s.rubyforge_project = s.name
|
14
|
+
s.add_runtime_dependency "array-unique", "~> 1.1.1"
|
15
|
+
end
|
data/lib/fantasy-irc.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Fantasy
|
4
|
+
module Event
|
5
|
+
class Factory
|
6
|
+
def initialize
|
7
|
+
puts "Initializing new Event::Factory #{self}"
|
8
|
+
@data, @data[:events] = Hash.new, Hash.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def create name
|
12
|
+
name.downcase!
|
13
|
+
|
14
|
+
if not @data[:events][name].nil? then
|
15
|
+
return @data[:events][name]
|
16
|
+
# TODO: log warning
|
17
|
+
end
|
18
|
+
|
19
|
+
@data[:events][name] = Event.new(name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def by_name name
|
23
|
+
name.downcase!
|
24
|
+
|
25
|
+
if not @data[:events][name] then
|
26
|
+
raise "Tried to access unknown event \"#{name}\" in Event::Factory \"#{self}\""
|
27
|
+
end
|
28
|
+
|
29
|
+
@data[:events][name]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Event
|
34
|
+
attr_reader :name
|
35
|
+
|
36
|
+
def initialize(name)
|
37
|
+
puts "New Event with name #{name}"
|
38
|
+
@name = name
|
39
|
+
@data = Hash.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def register(&callback)
|
43
|
+
uuid = SecureRandom.uuid()
|
44
|
+
|
45
|
+
if @data[:callbacks].nil? then
|
46
|
+
@data[:callbacks] = Hash.new
|
47
|
+
end
|
48
|
+
|
49
|
+
@data[:callbacks][uuid] = callback
|
50
|
+
puts "#{self}: registered callback #{callback} with uuid #{uuid}."
|
51
|
+
end
|
52
|
+
|
53
|
+
def call(args=nil)
|
54
|
+
if @data[:callbacks].nil? or @data[:callbacks].empty? then
|
55
|
+
return
|
56
|
+
end
|
57
|
+
|
58
|
+
@data[:callbacks].each { |uuid, proc|
|
59
|
+
proc.call(args)
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'socket' # TCPSocket
|
2
|
+
require 'openssl'
|
3
|
+
require 'array-unique'
|
4
|
+
|
5
|
+
#require "fantasy-irc/rooms"
|
6
|
+
#require "fantasy-irc/users"
|
7
|
+
#require "fantasy-irc/events"
|
8
|
+
#require "fantasy-irc/plugins"
|
9
|
+
|
10
|
+
module Fantasy
|
11
|
+
class IRC
|
12
|
+
attr_reader :events, :rooms, :users, :plugins
|
13
|
+
attr_reader :started, :session, :loggedin, :connected
|
14
|
+
|
15
|
+
def initialize options={}
|
16
|
+
$bot = self
|
17
|
+
@data = Hash.new
|
18
|
+
@started = Time.now.to_i
|
19
|
+
@running = 0
|
20
|
+
@loggedin = 0
|
21
|
+
@connected = 0
|
22
|
+
@prefix = options[:prefix] || '!'
|
23
|
+
|
24
|
+
@events = Event::Factory.new
|
25
|
+
@rooms = Room::Factory.new self
|
26
|
+
@users = User::Factory.new self
|
27
|
+
@plugins = Plugins.new
|
28
|
+
|
29
|
+
%w{tick loggedin connected user_joined channel_message}.each do |e|
|
30
|
+
@events.create(e)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def login data
|
35
|
+
if not data[:nickname] and data[:username] then
|
36
|
+
data[:nickname] = data[:username]
|
37
|
+
end
|
38
|
+
if not data[:username] and data[:nickname] then
|
39
|
+
data[:username] = data[:nickname]
|
40
|
+
end
|
41
|
+
if not data[:realname] then
|
42
|
+
data[:realname] = "https://bitbucket.org/v2px/fantasy-irc"
|
43
|
+
end
|
44
|
+
|
45
|
+
if not data[:nickname] then
|
46
|
+
raise "you need to specify :nickname and/or :username on login"
|
47
|
+
end
|
48
|
+
|
49
|
+
if data[:password] then
|
50
|
+
self.send("PASS #{data[:password]}")
|
51
|
+
end
|
52
|
+
|
53
|
+
self.send("USER #{data[:username]} fantasy fantasy :#{data[:realname]}")
|
54
|
+
self.send("NICK #{data[:nickname]}")
|
55
|
+
end
|
56
|
+
|
57
|
+
def send(s)
|
58
|
+
# Send a message to the server
|
59
|
+
if not @connected then
|
60
|
+
raise "not connected to a server!"
|
61
|
+
end
|
62
|
+
puts "<-- #{s}"
|
63
|
+
@data[:socket].puts "#{s}\n"
|
64
|
+
end
|
65
|
+
|
66
|
+
def connect data
|
67
|
+
if not data[:server] then
|
68
|
+
raise "you need to specify :server on connect"
|
69
|
+
end
|
70
|
+
if not data[:ssl] then
|
71
|
+
data[:ssl] = false
|
72
|
+
end
|
73
|
+
if not data[:port] then
|
74
|
+
data[:port] = data[:ssl] ? 6697 : 6667
|
75
|
+
end
|
76
|
+
|
77
|
+
# Connect to the chat server
|
78
|
+
@data[:socket] = @data[:realsocket] = TCPSocket.open(data[:server], data[:port])
|
79
|
+
|
80
|
+
if !!data[:ssl] then
|
81
|
+
@data[:socket] = OpenSSL::SSL::SSLSocket.new(@data[:realsocket])
|
82
|
+
@data[:socket].connect
|
83
|
+
end
|
84
|
+
|
85
|
+
@connected = Time.now.to_i
|
86
|
+
self.events.by_name('connected').call
|
87
|
+
end
|
88
|
+
|
89
|
+
def cleanup
|
90
|
+
puts "[!][Cleanup] Closing socket."
|
91
|
+
@data[:socket].close()
|
92
|
+
end
|
93
|
+
|
94
|
+
def parse(s)
|
95
|
+
s.chomp!
|
96
|
+
|
97
|
+
if (s[0,4] == "PING") then
|
98
|
+
tok = s.split(' ', 2)
|
99
|
+
self.send "PONG #{tok[1]}"
|
100
|
+
|
101
|
+
elsif (s[0,1] == ":") then
|
102
|
+
# Server stuff
|
103
|
+
tok = s.split(' ', 4)
|
104
|
+
|
105
|
+
if (tok[1] == "001") then
|
106
|
+
# loggedin
|
107
|
+
@loggedin = Time.now.to_i
|
108
|
+
# ignore ourself
|
109
|
+
self.users.create(tok[2]).ignore!
|
110
|
+
self.events.by_name('loggedin').call
|
111
|
+
|
112
|
+
elsif (tok[1] == "JOIN") then
|
113
|
+
# user joined
|
114
|
+
room = self.rooms.by_name(tok[2][1,tok[2].length])
|
115
|
+
user = self.users.create(tok[0][1,tok[0].length])
|
116
|
+
|
117
|
+
# add user to room and room to user
|
118
|
+
room.users << user
|
119
|
+
user.rooms << room
|
120
|
+
|
121
|
+
return if user.ignored?
|
122
|
+
|
123
|
+
self.events.by_name('user_joined').call([room, user])
|
124
|
+
|
125
|
+
elsif (tok[1] == "PRIVMSG") then
|
126
|
+
# tok = s.split(' ', 4)
|
127
|
+
|
128
|
+
# channel or private message
|
129
|
+
if (tok[2][0,1] == "#") then
|
130
|
+
# channel message
|
131
|
+
room = self.rooms.by_name(tok[2])
|
132
|
+
user = self.users.create(tok[0][1,tok[0].length])
|
133
|
+
|
134
|
+
# add user to room and room to user
|
135
|
+
room.users << user
|
136
|
+
user.rooms << room
|
137
|
+
|
138
|
+
return if user.ignored?
|
139
|
+
|
140
|
+
text = tok[3][1,tok[3].length]
|
141
|
+
self.events.by_name('channel_message').call([room, user, text])
|
142
|
+
|
143
|
+
if text[0] == @prefix then
|
144
|
+
command, args = text.split(' ', 2)
|
145
|
+
self.plugins.command(command[1,command.length], {:room => room, :user => user}, args)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
else
|
150
|
+
# puts "[!] UNKNOWN PROTOCOL PART: #{s}"
|
151
|
+
end
|
152
|
+
else
|
153
|
+
|
154
|
+
puts "[!] UNKNOWN PROTOCOL PART: #{s}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def run
|
159
|
+
if @running.nonzero? then
|
160
|
+
return false
|
161
|
+
end
|
162
|
+
|
163
|
+
@running = Time.now.to_i
|
164
|
+
last_tick = @running
|
165
|
+
last_ping = @running
|
166
|
+
last_session_ping = @running
|
167
|
+
|
168
|
+
loop do
|
169
|
+
time_now = Time.now
|
170
|
+
|
171
|
+
# tick every second
|
172
|
+
if time_now.to_i > last_tick then
|
173
|
+
self.events.by_name('tick').call(time_now)
|
174
|
+
last_tick = time_now.to_i
|
175
|
+
end
|
176
|
+
|
177
|
+
# chatserver ping, every 5 minutes
|
178
|
+
if @connected.nonzero? and time_now.to_i-300 >= last_ping then
|
179
|
+
self.send("PING :"+time_now.to_f.to_s)
|
180
|
+
last_ping = time_now.to_i
|
181
|
+
end
|
182
|
+
|
183
|
+
# connection
|
184
|
+
if @connected.nonzero? then
|
185
|
+
ready = select([@data[:socket]], nil, nil, 0.1)
|
186
|
+
next if !ready
|
187
|
+
for s in ready[0]
|
188
|
+
if s == @data[:socket] then
|
189
|
+
return if @data[:socket].eof # XXX?
|
190
|
+
s = @data[:socket].gets
|
191
|
+
puts "--> #{s}"
|
192
|
+
self.parse(s)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
else # no connection, less cpu usage
|
196
|
+
sleep(0.5)
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Fantasy
|
2
|
+
class Plugins
|
3
|
+
attr_reader :plugins
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@plugins = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def add plugin
|
10
|
+
@plugins[plugin.name] = plugin
|
11
|
+
puts "#{plugin.name} = #{plugin}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def load name
|
15
|
+
Kernel::load "plugins/#{name}.rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
def command command, data, args
|
19
|
+
if not args.nil? then
|
20
|
+
args = args.split(' ')
|
21
|
+
end
|
22
|
+
@plugins.values.each do |plugin|
|
23
|
+
puts "#{plugin}"
|
24
|
+
plugin.handle! command, data, args
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Plugin
|
31
|
+
attr_reader :name
|
32
|
+
|
33
|
+
def initialize name
|
34
|
+
@name = name
|
35
|
+
@handlers = {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def handle pattern, &block
|
39
|
+
@handlers[pattern] = block
|
40
|
+
end
|
41
|
+
|
42
|
+
def handles? command
|
43
|
+
@handlers.keys.each do |pattern|
|
44
|
+
if command.match pattern then
|
45
|
+
return true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
|
52
|
+
def handle! command, data, args=[]
|
53
|
+
puts "trying to handle #{command} with #{data} and #{args}"
|
54
|
+
@handlers.each do |pattern, block|
|
55
|
+
if command.match(pattern) then
|
56
|
+
puts "#{block} handles #{command}"
|
57
|
+
break block.call data, args
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
#require "fantasy-irc/connection"
|
2
|
+
|
3
|
+
module Fantasy
|
4
|
+
module Room
|
5
|
+
class Factory
|
6
|
+
def initialize connection
|
7
|
+
puts "Initializing new Room::Factory #{self} with connection #{connection}"
|
8
|
+
@data, @data[:rooms] = Hash.new, Hash.new
|
9
|
+
@connection = connection
|
10
|
+
end
|
11
|
+
|
12
|
+
def new name
|
13
|
+
name.downcase!
|
14
|
+
|
15
|
+
if not @data[:rooms][name].nil? then
|
16
|
+
raise "We already know the room #{name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
@data[:rooms][name] = Room.new(name, @connection)
|
20
|
+
end
|
21
|
+
|
22
|
+
alias :create :new
|
23
|
+
|
24
|
+
def by_name name
|
25
|
+
name.downcase!
|
26
|
+
|
27
|
+
if not @data[:rooms][name] then
|
28
|
+
raise "Tried to access unknown room \"#{name}\" in Room::Factory \"#{self}\""
|
29
|
+
end
|
30
|
+
|
31
|
+
@data[:rooms][name]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Room
|
36
|
+
attr_reader :name, :users
|
37
|
+
|
38
|
+
def initialize name, connection
|
39
|
+
if not connection.respond_to?(:send) then
|
40
|
+
raise "Connection class needs to be able to respond to :send"
|
41
|
+
end
|
42
|
+
|
43
|
+
puts "New Room #{self.object_id} with name #{name}"
|
44
|
+
@name = name
|
45
|
+
@joined = false
|
46
|
+
@connection = connection
|
47
|
+
@users = Array::Unique.new
|
48
|
+
end
|
49
|
+
|
50
|
+
def join
|
51
|
+
if @joined == true then
|
52
|
+
raise "Already joined room #{@name}."
|
53
|
+
end
|
54
|
+
|
55
|
+
@connection.send("JOIN "+@name)
|
56
|
+
@joined = true # TODO: maybe we should set that if we get the
|
57
|
+
# correct reply. this is for testing only! XXX
|
58
|
+
return self
|
59
|
+
end
|
60
|
+
|
61
|
+
def joined?
|
62
|
+
!!@joined
|
63
|
+
end
|
64
|
+
|
65
|
+
def say message
|
66
|
+
if @joined == false then
|
67
|
+
raise "Tried to talk to a room (#{name}) we're not in."
|
68
|
+
end
|
69
|
+
|
70
|
+
@connection.send('PRIVMSG '+@name+' :'+message)
|
71
|
+
return self
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s
|
75
|
+
"#{@name}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Fantasy
|
2
|
+
module User
|
3
|
+
class Factory
|
4
|
+
def initialize connection
|
5
|
+
puts "Initializing new User::Factory #{self} with connection #{connection}"
|
6
|
+
@data, @data[:users] = Hash.new, Hash.new
|
7
|
+
@connection = connection
|
8
|
+
end
|
9
|
+
|
10
|
+
def new name
|
11
|
+
name = name.split(/!/, 2)[0] # remove mask
|
12
|
+
name_lc = name.downcase
|
13
|
+
|
14
|
+
if not @data[:users][name_lc].nil? then
|
15
|
+
return @data[:users][name_lc]
|
16
|
+
# TODO: log! not raise
|
17
|
+
# raise "We already know the user #{name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
@data[:users][name_lc] = User.new(name, @connection)
|
21
|
+
end
|
22
|
+
|
23
|
+
alias :create :new
|
24
|
+
|
25
|
+
def by_name name
|
26
|
+
name.downcase!
|
27
|
+
|
28
|
+
if not @data[:users][name] then
|
29
|
+
raise "Tried to access unknown user \"#{name}\" in User::Factory \"#{self}\""
|
30
|
+
end
|
31
|
+
|
32
|
+
@data[:users][name]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class User
|
37
|
+
attr_reader :name, :mask
|
38
|
+
attr_accessor :rooms
|
39
|
+
|
40
|
+
def initialize name, connection
|
41
|
+
if not connection.respond_to?(:send) then
|
42
|
+
raise "Connection class needs to be able to respond to :send"
|
43
|
+
end
|
44
|
+
|
45
|
+
@name = name
|
46
|
+
puts "New User #{self.object_id} with name #{@name}"
|
47
|
+
@connection = connection
|
48
|
+
@rooms = Array::Unique.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def say message
|
52
|
+
@connection.send('PRIVMSG '+@name+' :'+message)
|
53
|
+
return self
|
54
|
+
end
|
55
|
+
|
56
|
+
def login
|
57
|
+
self.name
|
58
|
+
end
|
59
|
+
|
60
|
+
# ===================
|
61
|
+
# Ignoring
|
62
|
+
def ignore!
|
63
|
+
@ignored = true
|
64
|
+
end
|
65
|
+
|
66
|
+
def unignore!
|
67
|
+
@ignored = false
|
68
|
+
end
|
69
|
+
|
70
|
+
def ignored?
|
71
|
+
!!@ignored
|
72
|
+
end
|
73
|
+
# ===================
|
74
|
+
|
75
|
+
def to_s
|
76
|
+
"#{@name}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
plugin = Plugin.new "corecommands"
|
2
|
+
|
3
|
+
plugin.handle(/^date$/i) do |data|
|
4
|
+
next data[:room].say Time.now.localtime.strftime "%a, %d %b %Y %T %z"
|
5
|
+
end
|
6
|
+
|
7
|
+
plugin.handle(/^ping$/i) do |data, args|
|
8
|
+
if args.empty? then
|
9
|
+
next data[:room].say "ping needs more arguments"
|
10
|
+
end
|
11
|
+
|
12
|
+
if args[0].match(/[^a-z0-9\.-]/i) then
|
13
|
+
next data[:room].say "invalid characters in argument"
|
14
|
+
end
|
15
|
+
|
16
|
+
Thread.new do
|
17
|
+
ping = `/bin/ping -w 3 -c 1 -- #{args[0]} 2>&1`
|
18
|
+
|
19
|
+
if ping.match /unknown host (.+)/ then
|
20
|
+
data[:room].say "unknown host #{$1}"
|
21
|
+
elsif ping.match /^(64 bytes.+)/ then
|
22
|
+
data[:room].say "#{$1}"
|
23
|
+
elsif ping.match /0 received/m then
|
24
|
+
data[:room].say "no reply :-("
|
25
|
+
else
|
26
|
+
data[:room].say "bogus hostname"
|
27
|
+
end
|
28
|
+
|
29
|
+
next
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
plugin.handle(/^host$/i) do |data, args|
|
34
|
+
if args.empty? then
|
35
|
+
next data[:room].say "host needs more arguments"
|
36
|
+
end
|
37
|
+
|
38
|
+
if args[0].match(/^a-z0-9\.-/i) then
|
39
|
+
next data[:room].say "invalid characters in argument"
|
40
|
+
end
|
41
|
+
|
42
|
+
Thread.new do
|
43
|
+
host = `/usr/bin/host #{args[0]} 2>&1`
|
44
|
+
lines = host.split(/\n/)
|
45
|
+
lines.take(3).each do |line|
|
46
|
+
data[:room].say line
|
47
|
+
end
|
48
|
+
|
49
|
+
next
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
$bot.plugins.add(plugin)
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fantasy-irc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jens Becker
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-26 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: array-unique
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.1.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.1.1
|
30
|
+
description: A modular, event-driven IRC client/bot gem for Ruby with plugin support
|
31
|
+
email:
|
32
|
+
- v2px@v2px.de
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- LICENSE.md
|
38
|
+
- README.md
|
39
|
+
- docs/PLUGINS.md
|
40
|
+
- docs/example.rb
|
41
|
+
- fantasy-irc.gemspec
|
42
|
+
- lib/fantasy-irc.rb
|
43
|
+
- lib/fantasy-irc/events.rb
|
44
|
+
- lib/fantasy-irc/irc.rb
|
45
|
+
- lib/fantasy-irc/plugins.rb
|
46
|
+
- lib/fantasy-irc/rooms.rb
|
47
|
+
- lib/fantasy-irc/users.rb
|
48
|
+
- lib/plugins/corecommands.rb
|
49
|
+
homepage: https://github.com/v2px/fantasy-irc
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project: fantasy-irc
|
69
|
+
rubygems_version: 1.8.25
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: A modular, event-driven IRC client/bot gem for Ruby with plugin support
|
73
|
+
test_files: []
|