jabber-bot 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/LICENSE +25 -0
  2. data/README +52 -0
  3. data/lib/jabber/bot.rb +324 -0
  4. 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: