xmpp4r 0.5 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +21 -0
- data/README.rdoc +29 -38
- data/Rakefile +11 -18
- data/data/doc/xmpp4r/examples/advanced/recvfile.rb +5 -4
- data/lib/xmpp4r/bytestreams/helper/filetransfer.rb +2 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb +1 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb +1 -1
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +4 -1
- data/lib/xmpp4r/caps/helper/generator.rb +2 -2
- data/lib/xmpp4r/client.rb +18 -4
- data/lib/xmpp4r/connection.rb +8 -5
- data/lib/xmpp4r/delay/x/delay.rb +1 -1
- data/lib/xmpp4r/entity_time.rb +6 -0
- data/lib/xmpp4r/entity_time/iq.rb +45 -0
- data/lib/xmpp4r/entity_time/responder.rb +57 -0
- data/lib/xmpp4r/httpbinding/client.rb +178 -44
- data/lib/xmpp4r/message.rb +46 -0
- data/lib/xmpp4r/muc/helper/mucclient.rb +8 -1
- data/lib/xmpp4r/observable.rb +9 -0
- data/lib/xmpp4r/observable/contact.rb +61 -0
- data/lib/xmpp4r/observable/helper.rb +389 -0
- data/lib/xmpp4r/observable/observable_thing.rb +191 -0
- data/lib/xmpp4r/observable/pubsub.rb +211 -0
- data/lib/xmpp4r/observable/subscription.rb +57 -0
- data/lib/xmpp4r/observable/thread_store.rb +65 -0
- data/lib/xmpp4r/pubsub/children/unsubscribe.rb +16 -1
- data/lib/xmpp4r/pubsub/helper/servicehelper.rb +48 -14
- data/lib/xmpp4r/rexmladdons.rb +46 -6
- data/lib/xmpp4r/roster/helper/roster.rb +19 -9
- data/lib/xmpp4r/sasl.rb +1 -1
- data/lib/xmpp4r/stream.rb +2 -2
- data/lib/xmpp4r/xmpp4r.rb +1 -1
- data/test/bytestreams/tc_socks5bytestreams.rb +2 -2
- data/test/entity_time/tc_responder.rb +65 -0
- data/test/roster/tc_helper.rb +2 -3
- data/test/tc_message.rb +52 -1
- data/test/tc_stream.rb +2 -2
- data/test/tc_streamComponent.rb +11 -1
- data/test/ts_xmpp4r.rb +11 -2
- data/xmpp4r.gemspec +20 -9
- metadata +41 -35
@@ -0,0 +1,191 @@
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
2
|
+
#
|
3
|
+
# This file's copyright (c) 2009 by Pablo Lorenzzoni <pablo@propus.com.br>
|
4
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
5
|
+
# Website::http://home.gna.org/xmpp4r/
|
6
|
+
#
|
7
|
+
# This was based on Observable module from Ruby.
|
8
|
+
module ObservableThing
|
9
|
+
require 'xmpp4r/observable/thread_store'
|
10
|
+
|
11
|
+
# Adds an observer for some "thing".
|
12
|
+
#
|
13
|
+
# thing:: what will be observed.
|
14
|
+
# observer:: the observer.
|
15
|
+
# func:: the observer method that will be called (default: :update).
|
16
|
+
def add_observer(thing, observer, func = :update)
|
17
|
+
@things = {} unless defined? @things
|
18
|
+
@things[thing] = {} unless ! @things[thing].nil?
|
19
|
+
unless observer.respond_to? func
|
20
|
+
raise NoMethodError, "observer does not respond to `#{func.to_s}'"
|
21
|
+
end
|
22
|
+
@things[thing][observer] = func unless @things[thing].include?(observer)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Deletes an observer for some "thing".
|
26
|
+
#
|
27
|
+
# thing:: what has been observed.
|
28
|
+
# observer:: the observer.
|
29
|
+
def delete_observer(thing, observer)
|
30
|
+
@things[thing].delete observer if defined? @things and ! @things[thing].nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Delete observers for some "thing".
|
34
|
+
#
|
35
|
+
# thing:: what has been observed (if nil, deletes all observers).
|
36
|
+
def delete_observers(thing = nil)
|
37
|
+
if thing.nil?
|
38
|
+
@things.clear if defined? @things
|
39
|
+
else
|
40
|
+
@things[thing].clear if defined? @things and ! @things[thing].nil?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Count the number of observers for some "thing".
|
45
|
+
#
|
46
|
+
# thing:: what has been observed (if nil, count all observers).
|
47
|
+
def count_observers(thing = nil)
|
48
|
+
return 0 if ! defined? @things
|
49
|
+
size = 0
|
50
|
+
if thing.nil?
|
51
|
+
@things.each { |thing, hash|
|
52
|
+
size += hash.size
|
53
|
+
}
|
54
|
+
else
|
55
|
+
size = @things[thing].size unless @things[thing].nil?
|
56
|
+
end
|
57
|
+
size
|
58
|
+
end
|
59
|
+
|
60
|
+
# Count the number of notifications for some "thing".
|
61
|
+
#
|
62
|
+
# thing:: what has been observed.
|
63
|
+
def count_notifications(thing)
|
64
|
+
return 0 if (! defined?(@things_counter)) or (! @things_counter.include?(thing))
|
65
|
+
@things_counter[thing]
|
66
|
+
end
|
67
|
+
|
68
|
+
# Change the state of some "thing".
|
69
|
+
#
|
70
|
+
# thing:: what will have the state changed.
|
71
|
+
# state:: the state (default = true).
|
72
|
+
def changed(thing, state = true)
|
73
|
+
@things_state = {} unless defined? @things_state
|
74
|
+
@things_state[thing] = state
|
75
|
+
end
|
76
|
+
|
77
|
+
# Check the state of some "thing".
|
78
|
+
#
|
79
|
+
# thing: what to have its state checked.
|
80
|
+
def changed?(thing)
|
81
|
+
if defined? @things_state and @things_state[thing]
|
82
|
+
true
|
83
|
+
else
|
84
|
+
false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Notify all observers of "thing" about something. This will only be
|
89
|
+
# enforced if the state of that "thing" is true. Also, if the observer
|
90
|
+
# returns the Symbol :delete_me, it will be deleted after being notified.
|
91
|
+
#
|
92
|
+
# thing:: what has been observed.
|
93
|
+
# args:: notification to be sent to the observers of "thing".
|
94
|
+
def notify_observers(thing, *arg)
|
95
|
+
if changed?(thing)
|
96
|
+
if defined? @things and ! @things[thing].nil?
|
97
|
+
@things[thing].each { |observer, func|
|
98
|
+
increase_counter(thing)
|
99
|
+
@thread_store = ThreadStore.new if ! defined? @thread_store
|
100
|
+
@thread_store.add Thread.new {
|
101
|
+
if observer.send(func, thing, *arg) == :delete_me
|
102
|
+
delete_observer(thing, observer)
|
103
|
+
end
|
104
|
+
}
|
105
|
+
}
|
106
|
+
end
|
107
|
+
changed(thing, false)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Is there pending notifications?
|
112
|
+
def pending_notifications?
|
113
|
+
return false if ! defined? @thread_store
|
114
|
+
@thread_store.size > 0
|
115
|
+
end
|
116
|
+
|
117
|
+
# Wait all notifications
|
118
|
+
def wait_notifications
|
119
|
+
sleep 1 while pending_notifications?
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
def increase_counter(thing)
|
124
|
+
@things_counter = {} unless defined? @things_counter
|
125
|
+
@things_counter[thing] = 0 unless @things_counter.include?(thing)
|
126
|
+
@things_counter[thing] += 1
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# QObserver - simple observer-to-queue class
|
131
|
+
class QObserver
|
132
|
+
require 'thread'
|
133
|
+
|
134
|
+
def initialize
|
135
|
+
@queues = Hash.new
|
136
|
+
end
|
137
|
+
|
138
|
+
def inspect
|
139
|
+
h = {}
|
140
|
+
@queues.each do |q, queue|
|
141
|
+
h[q] = queue.size
|
142
|
+
end
|
143
|
+
if h.length > 0
|
144
|
+
sprintf("#<%s:0x%x size=%s>", self.class.name, __id__, h.inspect)
|
145
|
+
else
|
146
|
+
sprintf("#<%s:0x%x>", self.class.name, __id__)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Return the queues we have registered
|
151
|
+
def queues
|
152
|
+
@queues.keys
|
153
|
+
end
|
154
|
+
|
155
|
+
# Received something in this queue?
|
156
|
+
#
|
157
|
+
# q:: queue
|
158
|
+
def received?(q)
|
159
|
+
@queues.include?(q) and ! @queues[q].empty?
|
160
|
+
end
|
161
|
+
|
162
|
+
# Get the contents of the queue in an array (or pass each item to the
|
163
|
+
# given block.
|
164
|
+
#
|
165
|
+
# q:: queue
|
166
|
+
def received(q)
|
167
|
+
return nil if ! @queues.include?(q)
|
168
|
+
if block_given?
|
169
|
+
yield @queues[q].deq while ! @queues[q].empty?
|
170
|
+
else
|
171
|
+
a = []
|
172
|
+
a << @queues[q].deq while ! @queues[q].empty?
|
173
|
+
return a
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Get the size of a given queue
|
178
|
+
#
|
179
|
+
# q:: queue
|
180
|
+
def size(q)
|
181
|
+
@queues[q].size rescue 0
|
182
|
+
end
|
183
|
+
|
184
|
+
# update method for our Observer
|
185
|
+
#
|
186
|
+
# thing:: what to be updated
|
187
|
+
def update(thing, *args)
|
188
|
+
@queues[thing] = Queue.new if ! @queues.include?(thing)
|
189
|
+
@queues[thing].enq args
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
2
|
+
#
|
3
|
+
# This file's copyright (c) 2009 by Pablo Lorenzzoni <pablo@propus.com.br>
|
4
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
5
|
+
# Website::http://home.gna.org/xmpp4r/
|
6
|
+
|
7
|
+
require 'xmpp4r/pubsub'
|
8
|
+
require 'xmpp4r/pubsub/helper/servicehelper'
|
9
|
+
require 'xmpp4r/pubsub/helper/nodebrowser'
|
10
|
+
require 'xmpp4r/pubsub/helper/nodehelper'
|
11
|
+
|
12
|
+
module Jabber
|
13
|
+
class Observable
|
14
|
+
# Jabber::Observable::PubSub - Convenience subclass to deal with PubSub
|
15
|
+
class PubSub
|
16
|
+
class NoService < StandardError; end #:nodoc:
|
17
|
+
|
18
|
+
class AlreadySet < StandardError; end #:nodoc:
|
19
|
+
|
20
|
+
# Creates a new PubSub object
|
21
|
+
#
|
22
|
+
# observable:: points a Jabber::Observable object
|
23
|
+
def initialize(observable)
|
24
|
+
@observable = observable
|
25
|
+
|
26
|
+
@helper = @service_jid = nil
|
27
|
+
@disco = Jabber::Discovery::Helper.new(@observable.client)
|
28
|
+
attach!
|
29
|
+
end
|
30
|
+
|
31
|
+
def attach!
|
32
|
+
begin
|
33
|
+
domain = Jabber::JID.new(@observable.jid).domain
|
34
|
+
@service_jid = "pubsub." + domain
|
35
|
+
set_service(@service_jid)
|
36
|
+
rescue
|
37
|
+
@helper = @service_jid = nil
|
38
|
+
end
|
39
|
+
return has_service?
|
40
|
+
end
|
41
|
+
|
42
|
+
def inspect #:nodoc:
|
43
|
+
if has_service?
|
44
|
+
sprintf("#<%s:0x%x @service_jid=%s>", self.class.name, __id__, @service_jid)
|
45
|
+
else
|
46
|
+
sprintf("#<%s:0x%x @has_service?=false>", self.class.name, __id__)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Checks if the PubSub service is set
|
51
|
+
def has_service?
|
52
|
+
! @helper.nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
# Sets the PubSub service. Just one service is allowed. If nil, reset.
|
56
|
+
def set_service(service)
|
57
|
+
if service.nil?
|
58
|
+
@helper = @service_jid = nil
|
59
|
+
else
|
60
|
+
raise NotConnected, "You are not connected" if ! @observable.connected?
|
61
|
+
raise AlreadySet, "You already have a PubSub service (#{@service_jid})." if has_service?
|
62
|
+
@helper = Jabber::PubSub::ServiceHelper.new(@observable.client, service)
|
63
|
+
@service_jid = service
|
64
|
+
|
65
|
+
@helper.add_event_callback do |event|
|
66
|
+
@observable.changed(:event)
|
67
|
+
@observable.notify_observers(:event, event)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Subscribe to a node.
|
73
|
+
def subscribe_to(node)
|
74
|
+
raise_noservice if ! has_service?
|
75
|
+
@helper.subscribe_to(node) unless is_subscribed_to?(node)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Unsubscribe from a node.
|
79
|
+
def unsubscribe_from(node)
|
80
|
+
raise_noservice if ! has_service?
|
81
|
+
@helper.unsubscribe_from(node)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Return the subscriptions we have in the configured PubSub service.
|
85
|
+
def subscriptions
|
86
|
+
raise_noservice if ! has_service?
|
87
|
+
@helper.get_subscriptions_from_all_nodes()
|
88
|
+
end
|
89
|
+
|
90
|
+
# Create a PubSub node (Lots of options still have to be encoded!)
|
91
|
+
def create_node(node)
|
92
|
+
raise_noservice if ! has_service?
|
93
|
+
begin
|
94
|
+
@helper.create_node(node)
|
95
|
+
rescue => e
|
96
|
+
raise e
|
97
|
+
return nil
|
98
|
+
end
|
99
|
+
@my_nodes << node if defined? @my_nodes
|
100
|
+
node
|
101
|
+
end
|
102
|
+
|
103
|
+
# Return an array of nodes I own
|
104
|
+
def my_nodes
|
105
|
+
if ! defined? @my_nodes
|
106
|
+
ret = []
|
107
|
+
subscriptions.each do |sub|
|
108
|
+
ret << sub.node if sub.attributes['affiliation'] == 'owner'
|
109
|
+
end
|
110
|
+
@my_nodes = ret
|
111
|
+
end
|
112
|
+
return @my_nodes
|
113
|
+
end
|
114
|
+
|
115
|
+
# Return true if a given node exists
|
116
|
+
def node_exists?(node)
|
117
|
+
ret = []
|
118
|
+
if ! defined? @existing_nodes or ! @existing_nodes.include?(node)
|
119
|
+
# We'll renew @existing_nodes if we haven't got it the first time
|
120
|
+
reply = @disco.get_items_for(@service_jid)
|
121
|
+
reply.items.each do |item|
|
122
|
+
ret << item.node
|
123
|
+
end
|
124
|
+
@existing_nodes = ret
|
125
|
+
end
|
126
|
+
return @existing_nodes.include?(node)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns an array of nodes I am subscribed to
|
130
|
+
def subscribed_nodes
|
131
|
+
ret = []
|
132
|
+
subscriptions.each do |sub|
|
133
|
+
next if sub.node.nil?
|
134
|
+
ret << sub.node if sub.attributes['subscription'] == 'subscribed' and ! my_nodes.include?(sub.node)
|
135
|
+
end
|
136
|
+
return ret
|
137
|
+
end
|
138
|
+
|
139
|
+
# Return true if we're subscribed to that node
|
140
|
+
def is_subscribed_to?(node)
|
141
|
+
ret = false
|
142
|
+
subscriptions.each do |sub|
|
143
|
+
ret = true if sub.node == node and sub.attributes['subscription'] == 'subscribed'
|
144
|
+
end
|
145
|
+
return ret
|
146
|
+
end
|
147
|
+
|
148
|
+
# Delete a PubSub node (Lots of options still have to be encoded!)
|
149
|
+
def delete_node(node)
|
150
|
+
raise_noservice if ! has_service?
|
151
|
+
begin
|
152
|
+
@helper.delete_node(node)
|
153
|
+
rescue => e
|
154
|
+
raise e
|
155
|
+
return nil
|
156
|
+
end
|
157
|
+
@my_nodes.delete(node) if defined? @my_nodes
|
158
|
+
node
|
159
|
+
end
|
160
|
+
|
161
|
+
# Publish an Item. This infers an item of Jabber::PubSub::Item kind is passed
|
162
|
+
def publish_item(node, item)
|
163
|
+
raise_noservice if ! has_service?
|
164
|
+
@helper.publish_item_to(node, item)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Publish Simple Item. This is an item with one element and some text to it.
|
168
|
+
def publish_simple_item(node, text)
|
169
|
+
raise_noservice if ! has_service?
|
170
|
+
|
171
|
+
item = Jabber::PubSub::Item.new
|
172
|
+
xml = REXML::Element.new('value')
|
173
|
+
xml.text = text
|
174
|
+
item.add(xml)
|
175
|
+
publish_item(node, item)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Publish atom Item. This is an item with one atom entry with title, body and time.
|
179
|
+
def publish_atom_item(node, title, body, time = Time.now)
|
180
|
+
raise_noservice if ! has_service?
|
181
|
+
|
182
|
+
item = Jabber::PubSub::Item.new
|
183
|
+
entry = REXML::Element.new('entry')
|
184
|
+
entry.add_namespace("http://www.w3.org/2005/Atom")
|
185
|
+
mytitle = REXML::Element.new('title')
|
186
|
+
mytitle.text = title
|
187
|
+
entry.add(mytitle)
|
188
|
+
mybody = REXML::Element.new('body')
|
189
|
+
mybody.text = body
|
190
|
+
entry.add(mybody)
|
191
|
+
published = REXML::Element.new("published")
|
192
|
+
published.text = time.utc.iso8601
|
193
|
+
entry.add(published)
|
194
|
+
item.add(entry)
|
195
|
+
publish_item(node, item)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Get items from a node
|
199
|
+
def get_items_from(node, count = nil)
|
200
|
+
raise_noservice if ! has_service?
|
201
|
+
@helper.get_items_from(node, count)
|
202
|
+
end
|
203
|
+
|
204
|
+
private
|
205
|
+
|
206
|
+
def raise_noservice #:nodoc:
|
207
|
+
raise NoService, "Have you forgot to call #set_service ?"
|
208
|
+
end
|
209
|
+
end # of class PubSub
|
210
|
+
end # of class Observable
|
211
|
+
end # of module Jabber
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
2
|
+
#
|
3
|
+
# This file's copyright (c) 2009 by Pablo Lorenzzoni <pablo@propus.com.br>
|
4
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
5
|
+
# Website::http://home.gna.org/xmpp4r/
|
6
|
+
module Jabber
|
7
|
+
class Observable
|
8
|
+
# Jabber::Observable::Subscriptions - convenience class to deal with
|
9
|
+
# Presence subscriptions
|
10
|
+
#
|
11
|
+
# observable:: points to a Jabber::Observable object
|
12
|
+
class Subscriptions
|
13
|
+
def initialize(observable)
|
14
|
+
@observable = observable
|
15
|
+
@accept = true
|
16
|
+
end
|
17
|
+
|
18
|
+
# Ask the users specified by jids for authorization (i.e., ask them to add
|
19
|
+
# you to their contact list), unless already in the contact list.
|
20
|
+
#
|
21
|
+
# Because the authorization process depends on the other user accepting your
|
22
|
+
# request, results are notified to observers of :new_subscription.
|
23
|
+
def add(*jids)
|
24
|
+
@observable.contacts(*jids).each do |contact|
|
25
|
+
next if subscribed_to?(contact)
|
26
|
+
contact.ask_for_authorization!
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Remove the jabber users specified by jids from the contact list.
|
31
|
+
def remove(*jids)
|
32
|
+
@observable.contacts(*jids).each do |contact|
|
33
|
+
contact.unsubscribe!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns true if this Jabber account is subscribed to status updates for
|
38
|
+
# the jabber user jid, false otherwise.
|
39
|
+
def subscribed_to?(jid)
|
40
|
+
@observable.contacts(jid).each do |contact|
|
41
|
+
return contact.subscribed?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns true if auto-accept subscriptions is enabled (default), false otherwise.
|
46
|
+
def accept?
|
47
|
+
@accept
|
48
|
+
end
|
49
|
+
|
50
|
+
# Change whether or not subscriptions are automatically accepted.
|
51
|
+
def accept=(accept_status)
|
52
|
+
@accept = accept_status
|
53
|
+
end
|
54
|
+
end # of class Subscription
|
55
|
+
end # of class Observable
|
56
|
+
end # of module Jabber
|
57
|
+
|