fantasy-irc 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|