1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
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
|