require 'xmpp4r/framework/base'
require 'xmpp4r'
require 'xmpp4r/roster'
require 'xmpp4r/caps/c'
require 'xmpp4r/discovery'
require 'xmpp4r/xhtml'
module Jabber
module Framework
##
# Abstract handler methods that *may* be implemented by a deriving class:
# * on_message(text)
# * on_message_xhtml(html_body, text)
class Bot < Base
helper :roster, Roster::Helper
helper(:disco_default) { |cl|
Discovery::Responder.new(cl,
nil,
[Jabber::Discovery::Identity.new('client', 'XMPP4R Bot', 'bot')]
)
}
helper(:disco_caps) { |cl|
Discovery::Responder.new(cl,
"http://home.gna.org/xmpp4r/#{Jabber::XMPP4R_VERSION}",
[Jabber::Discovery::Identity.new('client', 'XMPP4R Bot', 'bot')]
)
}
def initialize(jid, password)
cl = Jabber::Client.new(jid)
cl.connect
cl.auth(password)
super(cl)
roster.add_subscription_request_callback do |item,presence|
if accept_subscription_from?(presence.from.strip)
roster.accept_subscription(presence.from.strip)
else
roster.decline_subscription(presence.from.strip)
end
end
@pep_notifications = []
cl.add_message_callback do |msg|
if msg.type != :error and msg.body
if (html = msg.first_element('html')) and respond_to? :on_message_xhtml
on_message_xhtml(html.body, msg.body)
elsif respond_to? :on_message
on_message(msg.body)
end
elsif msg.type != :error and (event = msg.first_element('event'))
event.each_element('items') do |items|
node = items.attributes['node']
items.each_element('item') do |item|
@pep_notifications.each { |notification_node,callback|
if node == notification_node
callback.call(msg.from, item)
end
}
end
end
else
false
end
end
add_cap('presence')
add_cap(Caps::NS_CAPS)
add_cap('message') if respond_to? :on_message
add_cap(XHTML::NS_XHTML_IM) if respond_to? :on_message_xhtml
@presence_show = nil
@presence_status = nil
end
##
# Add feature namespace to Capabilities Discovery
def add_cap(capability)
disco_default.add_feature(capability)
disco_caps.add_feature(capability)
end
##
# Front-end for Roster::Helper#add_subscription_request_callback
#
# Can be overwritten, must return true or false
def accept_subscription_from?(jid)
true
end
##
# Send a simple text chat message
def send_message(to, text)
msg = Message.new
msg.type = :chat
msg.to = to
msg.body = text
@stream.send(msg)
end
##
# Send an XHTML chat message
# text:: [String] alternate plain text body, generated from xhtml_contents if nil
def send_message_xhtml(to, xhtml_contents, text=nil)
msg = Message.new
msg.type = :chat
msg.to = to
html = msg.add(XHTML::HTML.new(xhtml_contents))
msg.body = text ? text : html.to_text
@stream.send(msg)
end
##
# Set and send a Presence
def set_presence(show=nil, status=nil)
@presence_show = show
@presence_status = status
send_presence
end
private
def send_presence
roster.wait_for_roster
# TODO: vcard photo hash
if @presence_show == :unavailable
presence = Presence.new(nil, @presence_status)
presence.type = :unavailable
else
presence = Presence.new(@presence_show, @presence_status)
end
presence.add(disco_caps.generate_caps)
@stream.send(presence)
end
public
def add_pep_notification(node, &callback)
add_cap("#{node}+notify")
@pep_notifications << [node, callback]
end
end
end
end