File: bot.rb

package info (click to toggle)
ruby-xmpp4r 0.5.6-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 1,384 kB
  • sloc: ruby: 17,382; xml: 74; sh: 12; makefile: 4
file content (148 lines) | stat: -rw-r--r-- 4,297 bytes parent folder | download | duplicates (2)
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