jabber-bot 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +25 -0
- data/README +52 -0
- data/lib/jabber/bot.rb +324 -0
- metadata +62 -0
data/LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2007 Brett Stimmerman <brettstimmerman@socket7.net>
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name of this project nor the names of its contributors may be
|
13
|
+
used to endorse or promote products derived from this software without
|
14
|
+
specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
17
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
20
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
22
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
23
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
24
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
25
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
= Jabber::Bot
|
2
|
+
|
3
|
+
Easily create powerful Jabber bots to do your bidding.
|
4
|
+
|
5
|
+
Jabber::Bot makes it simple to create and command your own Jabber bot with
|
6
|
+
little fuss. By adding custom commands powered by regular expressions to your
|
7
|
+
bot's repertoire, you and your new bot will be able to accomplish nearly
|
8
|
+
anything.
|
9
|
+
|
10
|
+
Author:: Brett Stimmerman (mailto:brettstimmerman@gmail.com)
|
11
|
+
Version:: 1.0.0
|
12
|
+
Copyright:: Copyright (c) 2007 Brett Stimmerman. All rights reserved.
|
13
|
+
License:: New BSD License (http://opensource.org/licenses/bsd-license.php)
|
14
|
+
Website:: http://socket7.net/software/jabber-bot
|
15
|
+
|
16
|
+
== Dependencies
|
17
|
+
|
18
|
+
- Ruby[http://www.ruby-lang.org] 1.8.4+
|
19
|
+
- xmpp4r-simple[http://xmpp4r-simple.rubyforge.org/] 0.8.7+
|
20
|
+
|
21
|
+
== Basic Usage
|
22
|
+
|
23
|
+
# Create a public Jabber::Bot to do your bidding
|
24
|
+
bot_config = {
|
25
|
+
:jabber_id => 'bot@example.com',
|
26
|
+
:password => 'password',
|
27
|
+
:master => 'master@example.com',
|
28
|
+
:is_public => true
|
29
|
+
}
|
30
|
+
bot = Jabber::Bot.new(bot_config)
|
31
|
+
|
32
|
+
# Give your bot a private command, 'rand'
|
33
|
+
bot.add_command(
|
34
|
+
:syntax => 'rand',
|
35
|
+
:description => 'Produce a random number from 0 to 10',
|
36
|
+
:regex => /^rand$/
|
37
|
+
) { rand(10).to_s }
|
38
|
+
|
39
|
+
# Give your bot a public command, 'puts <string>' with an alias 'p <string>'
|
40
|
+
bot.add_command(
|
41
|
+
:syntax => 'puts <string>',
|
42
|
+
:description => 'Write something to $stdout',
|
43
|
+
:regex => /^puts\s+.+$/,
|
44
|
+
:aliases => [ :alias => 'p <string>', :regex => /^p\s+.+$/ ],
|
45
|
+
:is_public => true
|
46
|
+
) do |message|
|
47
|
+
puts message
|
48
|
+
"'#{message}' written to $stdout"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Bring your new bot to life
|
52
|
+
bot.connect
|
data/lib/jabber/bot.rb
ADDED
@@ -0,0 +1,324 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 Brett Stimmerman <brettstimmerman@gmail.com>
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
# * Neither the name of this project nor the names of its contributors may be
|
14
|
+
# used to endorse or promote products derived from this software without
|
15
|
+
# specific prior written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
21
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
#++
|
28
|
+
|
29
|
+
require 'rubygems'
|
30
|
+
require 'xmpp4r-simple'
|
31
|
+
|
32
|
+
module Jabber
|
33
|
+
|
34
|
+
# = Jabber::Bot
|
35
|
+
#
|
36
|
+
# Jabber::Bot makes it simple to create and command a Jabber bot with little
|
37
|
+
# fuss. By adding custom commands powered by regular expressions to your bot's
|
38
|
+
# repertoire, you and your new bot will be able to accomplish nearly anything.
|
39
|
+
#
|
40
|
+
# Author:: Brett Stimmerman (mailto:brettstimmerman@gmail.com)
|
41
|
+
# Version:: 0.1.0
|
42
|
+
# Copyright:: Copyright (c) 2007 Brett Stimmerman. All rights reserved.
|
43
|
+
# License:: New BSD License (http://opensource.org/licenses/bsd-license.php)
|
44
|
+
# Website:: http://socket7.net/software/jabber-bot
|
45
|
+
#
|
46
|
+
class Bot
|
47
|
+
|
48
|
+
# Creates a new Jabber::Bot object with the specified _name_, _jabber_id_
|
49
|
+
# and _password_. If _name_ is omitted, _jabber_id_ is used. The bot will
|
50
|
+
# respond to commands from one or more masters specified by _master_.
|
51
|
+
# You may choose to restrict a Jabber::Bot to listen only to its master(s),
|
52
|
+
# or make it a public bot that will listen to anyone.
|
53
|
+
#
|
54
|
+
# By default, a Jabber::Bot has only a single command, 'help', which will
|
55
|
+
# display the full list of commands available in the bot's repertoire.
|
56
|
+
#
|
57
|
+
# If you choose to make a public bot only the commands you specify as
|
58
|
+
# public commands, as well as the default 'help' command, will be publicly
|
59
|
+
# executable.
|
60
|
+
#
|
61
|
+
# # A private bot with a single master
|
62
|
+
# bot = Jabber::Bot.new(
|
63
|
+
# :name => 'PrivateBot',
|
64
|
+
# :jabber_id => 'bot@example.com',
|
65
|
+
# :password => 'password',
|
66
|
+
# :master => 'master@example.com'
|
67
|
+
# )
|
68
|
+
#
|
69
|
+
# # A public bot with mutliple masters
|
70
|
+
# masters = ['master1@example.com', 'master2@example.com]
|
71
|
+
# bot = Jabber::Bot.new(
|
72
|
+
# :name => 'PublicBot',
|
73
|
+
# :jabber_id => 'bot@example.com',
|
74
|
+
# :password => 'password',
|
75
|
+
# :master => masters,
|
76
|
+
# :is_public => true
|
77
|
+
# )
|
78
|
+
#
|
79
|
+
def initialize(bot_config)
|
80
|
+
|
81
|
+
if bot_config[:jabber_id].nil?
|
82
|
+
abort 'You must specify a :jabber_id'
|
83
|
+
elsif bot_config[:password].nil?
|
84
|
+
abort 'You must specify a :password'
|
85
|
+
elsif bot_config[:master].nil? or bot_config[:master].length == 0
|
86
|
+
abort 'You must specify at least one :master'
|
87
|
+
end
|
88
|
+
|
89
|
+
@bot_config = bot_config
|
90
|
+
|
91
|
+
@bot_config[:is_public] = false if @bot_config[:is_public].nil?
|
92
|
+
|
93
|
+
if @bot_config[:name].nil? or @bot_config[:name].length == 0
|
94
|
+
@bot_config[:name] = @bot_config[:jabber_id].sub(/@.+$/, '')
|
95
|
+
end
|
96
|
+
|
97
|
+
unless bot_config[:master].is_a?(Array)
|
98
|
+
@bot_config[:master] = [bot_config[:master]]
|
99
|
+
end
|
100
|
+
|
101
|
+
@commands = { :spec => [], :meta => {} }
|
102
|
+
|
103
|
+
add_command(
|
104
|
+
:syntax => 'help',
|
105
|
+
:description => 'Display this help message',
|
106
|
+
:regex => /^help$/,
|
107
|
+
:alias => [ :syntax => '?', :regex => /^\?/ ],
|
108
|
+
:is_public => @bot_config[:is_public]
|
109
|
+
) { |sender, message| help_message(sender) }
|
110
|
+
end
|
111
|
+
|
112
|
+
# Add a command to the bot's repertoire.
|
113
|
+
#
|
114
|
+
# Commands consist of a metadata Hash and a callback block. The metadata
|
115
|
+
# Hash *must* contain the command syntax and a description of the command
|
116
|
+
# for display with the builtin 'help' command, and a regular expression to
|
117
|
+
# detect the presence of the command in an incoming message.
|
118
|
+
#
|
119
|
+
# The metadata Hash may optionally contain an array of command aliases. An
|
120
|
+
# alias consists of an alias syntax and regex. Aliases allow the bot to
|
121
|
+
# understand command shorthands. For example, the default 'help' command has
|
122
|
+
# an alias '?'. Saying either 'help' or '?' will trigger the same command
|
123
|
+
# callback block.
|
124
|
+
#
|
125
|
+
# The metadata Hash may optionally contain an is_public flag, indicating
|
126
|
+
# the bot should respond to *anyone* issuing the command, not just the bot
|
127
|
+
# master(s). Public commands are only truly public if the bot itself has
|
128
|
+
# been made public.
|
129
|
+
#
|
130
|
+
# The specified callback block will be triggered when the bot receives a
|
131
|
+
# message that matches the given command regex (or an alias regex). The
|
132
|
+
# callback block will have access to the sender and the message text (not
|
133
|
+
# including the command), and should either return a String response or
|
134
|
+
# _nil_. If a callback block returns a String response, the response will be
|
135
|
+
# delivered to the bot master that issued the command.
|
136
|
+
#
|
137
|
+
# Examples:
|
138
|
+
#
|
139
|
+
# # Say "puts foo" to the bot and "foo" will be written to $stdout.
|
140
|
+
# # The bot will also respond with "'foo' written to $stdout."
|
141
|
+
# add_command(
|
142
|
+
# :syntax => 'puts <string>',
|
143
|
+
# :description => 'Write something to $stdout',
|
144
|
+
# :regex => /^puts\s+.+$/
|
145
|
+
# ) do |message|
|
146
|
+
# puts message
|
147
|
+
# "'#{message}' written to $stdout."
|
148
|
+
# end
|
149
|
+
#
|
150
|
+
# # "puts!" is a non-responding version of "puts", and has an alias, "p!"
|
151
|
+
# add_command(
|
152
|
+
# :syntax => 'puts! <string>',
|
153
|
+
# :description => 'Write something to $stdout (without response)',
|
154
|
+
# :regex => /^puts!\s+.+$/,
|
155
|
+
# :alias => [ :syntax => 'p! <string>', :regex => /^p!$/ ]
|
156
|
+
# ) do |message|
|
157
|
+
# puts message
|
158
|
+
# nil
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
# # 'rand' is a public command that produces a random number from 0 to 10
|
162
|
+
# add_command(
|
163
|
+
# :syntax => 'rand',
|
164
|
+
# :description => 'Produce a random number from 0 to 10',
|
165
|
+
# :regex => /^rand$/,
|
166
|
+
# :is_public => true
|
167
|
+
# ) { rand(10).to_s }
|
168
|
+
#
|
169
|
+
def add_command(command, &callback)
|
170
|
+
syntax = command[:syntax]
|
171
|
+
is_public = command[:is_public] || false
|
172
|
+
|
173
|
+
# Add the command meta. Using a Hash allows for Hash.sort to list
|
174
|
+
# commands aphabetically in the 'help' command response.
|
175
|
+
@commands[:meta][syntax] = {
|
176
|
+
:syntax => [syntax],
|
177
|
+
:description => command[:description],
|
178
|
+
:is_public => is_public
|
179
|
+
}
|
180
|
+
|
181
|
+
# Add the command spec. The command spec is used by parse_command.
|
182
|
+
@commands[:spec] << {
|
183
|
+
:regex => command[:regex],
|
184
|
+
:callback => callback,
|
185
|
+
:is_public => is_public
|
186
|
+
}
|
187
|
+
|
188
|
+
# Add any command aliases to the command meta and spec
|
189
|
+
unless command[:alias].nil?
|
190
|
+
command[:alias].each do |a|
|
191
|
+
@commands[:meta][syntax][:syntax] << a[:syntax]
|
192
|
+
|
193
|
+
@commands[:spec] << {
|
194
|
+
:regex => a[:regex],
|
195
|
+
:callback => callback,
|
196
|
+
:is_public => is_public
|
197
|
+
}
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Connect the bot, making him available to accept commands.
|
203
|
+
def connect
|
204
|
+
@jabber = Jabber::Simple.new(@bot_config[:jabber_id],
|
205
|
+
@bot_config[:password])
|
206
|
+
|
207
|
+
deliver(@bot_config[:master], "#{@bot_config[:name]} reporting for duty.")
|
208
|
+
|
209
|
+
start_listener_thread
|
210
|
+
end
|
211
|
+
|
212
|
+
# Deliver a message to the specified recipient(s). Accepts a single
|
213
|
+
# recipient or an Array of recipients.
|
214
|
+
def deliver(to, message)
|
215
|
+
if to.is_a?(Array)
|
216
|
+
to.each { |t| @jabber.deliver(t, message) }
|
217
|
+
else
|
218
|
+
@jabber.deliver(to, message)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Returns the default help message describing the bot's command repertoire.
|
223
|
+
# Commands are sorted alphabetically by name.
|
224
|
+
def help_message(sender) #:nodoc:
|
225
|
+
help_message = "I understand the following commands:\n\n"
|
226
|
+
|
227
|
+
is_master = @bot_config[:master].include?(sender)
|
228
|
+
|
229
|
+
@commands[:meta].sort.each do |command|
|
230
|
+
if command[1][:is_public] == true || is_master
|
231
|
+
command[1][:syntax].each { |syntax| help_message += "#{syntax}\n" }
|
232
|
+
help_message += " #{command[1][:description]}\n\n"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
return help_message
|
237
|
+
end
|
238
|
+
|
239
|
+
# Direct access to the underlying
|
240
|
+
# Jabber::Simple[http://xmpp4r-simple.rubyforge.org/] object.
|
241
|
+
def jabber
|
242
|
+
return @jabber
|
243
|
+
end
|
244
|
+
|
245
|
+
# Access the bot master jabber id(s), as an Array
|
246
|
+
def master
|
247
|
+
return @bot_config[:master]
|
248
|
+
end
|
249
|
+
|
250
|
+
# Parses the given command message for the presence of a known command by
|
251
|
+
# testing it against each known command's regex. If a known command is
|
252
|
+
# found, the command parameters are passed on to the callback block, minus
|
253
|
+
# the command trigger. If a String result is present it is delivered to the
|
254
|
+
# sender.
|
255
|
+
#
|
256
|
+
# If the bot has not been made public, commands from anyone other than the
|
257
|
+
# bot master(s) will be silently ignored.
|
258
|
+
def parse_command(sender, message) #:nodoc:
|
259
|
+
puts sender + " " + message
|
260
|
+
is_master = @bot_config[:master].include?(sender)
|
261
|
+
|
262
|
+
if @bot_config[:is_public] or is_master
|
263
|
+
|
264
|
+
@commands[:spec].each do |command|
|
265
|
+
if command[:is_public] or is_master
|
266
|
+
unless (message.strip =~ command[:regex]).nil?
|
267
|
+
response = command[:callback].call(sender,
|
268
|
+
message.sub(/.+\s+/, ''))
|
269
|
+
|
270
|
+
deliver(sender, response) unless response.nil?
|
271
|
+
return
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
response = "I don't understand '#{message.strip}.' Try saying 'help' " +
|
277
|
+
"to see what commands I understand"
|
278
|
+
deliver(sender, response)
|
279
|
+
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
# Disconnect the bot. Once the bot has been disconnected, there is no way
|
284
|
+
# to restart it by issuing a command.
|
285
|
+
def disconnect
|
286
|
+
if @jabber.connected?
|
287
|
+
deliver(@bot_config[:master], "#{@bot_config[:name]} disconnecting...")
|
288
|
+
@jabber.disconnect
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# Creates a new Thread dedicated to listening for incoming chat messages.
|
293
|
+
# When a chat message is received, the bot checks if the sender is its
|
294
|
+
# master. If so, it is tested for the presence commands, and processed
|
295
|
+
# accordingly. If the bot itself or the command issued is not made public,
|
296
|
+
# a message sent by anyone other than the bot's master is silently ignored.
|
297
|
+
#
|
298
|
+
# Only the chat message type is supported. Other message types such as
|
299
|
+
# error and groupchat are not supported.
|
300
|
+
def start_listener_thread #:nodoc:
|
301
|
+
listener_thread = Thread.new do
|
302
|
+
loop do
|
303
|
+
@jabber.received_messages do |message|
|
304
|
+
# Remove the Jabber resourse, if any
|
305
|
+
sender = message.from.to_s.sub(/\/.+$/, '')
|
306
|
+
|
307
|
+
if message.type == :chat
|
308
|
+
parse_thread = Thread.new do
|
309
|
+
parse_command(sender, message.body)
|
310
|
+
end
|
311
|
+
|
312
|
+
parse_thread.join
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
sleep 1
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
listener_thread.join
|
321
|
+
end
|
322
|
+
|
323
|
+
end
|
324
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: jabber-bot
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2007-03-20 00:00:00 -07:00
|
8
|
+
summary: Jabber::Bot makes it simple to create and command your own Jabber bot with little fuss. By adding custom commands powered by regular expressions to your bot's repertoire, you and your new bot will be able to accomplish nearly anything.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: brettstimmerman@gmail.com
|
12
|
+
homepage: http://socket7.net/software/jabber-bot
|
13
|
+
rubyforge_project: jabber-bot
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.8.4
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Brett Stimmerman
|
31
|
+
files:
|
32
|
+
- lib/jabber
|
33
|
+
- lib/jabber/bot.rb
|
34
|
+
- LICENSE
|
35
|
+
- README
|
36
|
+
test_files: []
|
37
|
+
|
38
|
+
rdoc_options:
|
39
|
+
- --title
|
40
|
+
- Jabber::Bot Documentation
|
41
|
+
- --main
|
42
|
+
- README
|
43
|
+
- --line-numbers
|
44
|
+
extra_rdoc_files:
|
45
|
+
- README
|
46
|
+
- LICENSE
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
requirements: []
|
52
|
+
|
53
|
+
dependencies:
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: xmpp4r-simple
|
56
|
+
version_requirement:
|
57
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.7
|
62
|
+
version:
|