blather 0.4.7 → 0.4.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +162 -0
- data/examples/{print_heirarchy.rb → print_hierarchy.rb} +5 -5
- data/examples/stream_only.rb +27 -0
- data/lib/blather.rb +4 -0
- data/lib/blather/client/client.rb +91 -73
- data/lib/blather/client/dsl.rb +156 -32
- data/lib/blather/client/dsl/pubsub.rb +86 -54
- data/lib/blather/core_ext/active_support.rb +9 -9
- data/lib/blather/core_ext/active_support/inheritable_attributes.rb +2 -2
- data/lib/blather/core_ext/nokogiri.rb +12 -7
- data/lib/blather/errors.rb +25 -14
- data/lib/blather/errors/sasl_error.rb +21 -3
- data/lib/blather/errors/stanza_error.rb +37 -21
- data/lib/blather/errors/stream_error.rb +27 -17
- data/lib/blather/jid.rb +79 -24
- data/lib/blather/roster.rb +39 -21
- data/lib/blather/roster_item.rb +43 -21
- data/lib/blather/stanza.rb +88 -40
- data/lib/blather/stanza/disco.rb +12 -2
- data/lib/blather/stanza/disco/disco_info.rb +112 -20
- data/lib/blather/stanza/disco/disco_items.rb +81 -12
- data/lib/blather/stanza/iq.rb +94 -38
- data/lib/blather/stanza/iq/query.rb +16 -22
- data/lib/blather/stanza/iq/roster.rb +98 -20
- data/lib/blather/stanza/message.rb +266 -111
- data/lib/blather/stanza/presence.rb +118 -42
- data/lib/blather/stanza/presence/status.rb +140 -60
- data/lib/blather/stanza/presence/subscription.rb +44 -10
- data/lib/blather/stanza/pubsub.rb +70 -15
- data/lib/blather/stanza/pubsub/affiliations.rb +36 -7
- data/lib/blather/stanza/pubsub/create.rb +26 -4
- data/lib/blather/stanza/pubsub/errors.rb +13 -4
- data/lib/blather/stanza/pubsub/event.rb +56 -10
- data/lib/blather/stanza/pubsub/items.rb +46 -6
- data/lib/blather/stanza/pubsub/publish.rb +52 -7
- data/lib/blather/stanza/pubsub/retract.rb +45 -6
- data/lib/blather/stanza/pubsub/subscribe.rb +30 -4
- data/lib/blather/stanza/pubsub/subscription.rb +74 -6
- data/lib/blather/stanza/pubsub/subscriptions.rb +35 -9
- data/lib/blather/stanza/pubsub/unsubscribe.rb +30 -4
- data/lib/blather/stanza/pubsub_owner.rb +17 -7
- data/lib/blather/stanza/pubsub_owner/delete.rb +23 -5
- data/lib/blather/stanza/pubsub_owner/purge.rb +23 -5
- data/lib/blather/stream.rb +96 -29
- data/lib/blather/stream/parser.rb +6 -9
- data/lib/blather/xmpp_node.rb +101 -153
- data/spec/blather/client/client_spec.rb +1 -1
- data/spec/blather/errors_spec.rb +5 -5
- data/spec/blather/stanza/message_spec.rb +56 -0
- data/spec/blather/stanza/presence/status_spec.rb +1 -1
- data/spec/blather/stanza_spec.rb +3 -3
- data/spec/blather/xmpp_node_spec.rb +19 -74
- metadata +6 -10
- data/README.rdoc +0 -185
- data/examples/drb_client.rb +0 -5
- data/examples/ping.rb +0 -11
- data/examples/pong.rb +0 -6
- data/examples/pubsub/cli.rb +0 -64
- data/examples/pubsub/ping_pong.rb +0 -18
@@ -1,58 +1,85 @@
|
|
1
1
|
module Blather
|
2
2
|
class Stanza
|
3
3
|
|
4
|
-
#
|
4
|
+
# # Presence Stanza
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# [RFC 3921 Section 2.2 - Presence Syntax](http://xmpp.org/rfcs/rfc3921.html#stanzas-presence)
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# that availability. Presence stanzas are also used to negotiate and manage subscriptions to the presence of other entities.
|
8
|
+
# Within Blather most of the interaction with Presence stanzas will be
|
9
|
+
# through one of its child classes: Status or Subscription.
|
11
10
|
#
|
12
|
-
#
|
11
|
+
# Presence stanzas are used to express an entity's current network
|
12
|
+
# availability (offline or online, along with various sub-states of the
|
13
|
+
# latter and optional user-defined descriptive text), and to notify other
|
14
|
+
# entities of that availability. Presence stanzas are also used to negotiate
|
15
|
+
# and manage subscriptions to the presence of other entities.
|
13
16
|
#
|
14
|
-
#
|
15
|
-
# is used to signal to the server that the sender is online and available for communication. If included, the +type+
|
16
|
-
# attribute specifies a lack of availability, a request to manage a subscription to another entity's presence, a
|
17
|
-
# request for another entity's current presence, or an error related to a previously-sent presence stanza. If included,
|
18
|
-
# the +type+ attribute must have one of the following values:
|
17
|
+
# ## "Type" Attribute
|
19
18
|
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
19
|
+
# The `type` attribute of a presence stanza is optional. A presence stanza
|
20
|
+
# that does not possess a `type` attribute is used to signal to the server
|
21
|
+
# that the sender is online and available for communication. If included,
|
22
|
+
# the `type` attribute specifies a lack of availability, a request to manage
|
23
|
+
# a subscription to another entity's presence, a request for another
|
24
|
+
# entity's current presence, or an error related to a previously-sent
|
25
|
+
# presence stanza. If included, the `type` attribute must have one of the
|
26
|
+
# following values:
|
27
|
+
#
|
28
|
+
# * `:unavailable` -- Signals that the entity is no longer available for
|
29
|
+
# communication
|
30
|
+
#
|
31
|
+
# * `:subscribe` -- The sender wishes to subscribe to the recipient's
|
32
|
+
# presence.
|
33
|
+
#
|
34
|
+
# * `:subscribed` -- The sender has allowed the recipient to receive their
|
35
|
+
# presence.
|
36
|
+
#
|
37
|
+
# * `:unsubscribe` -- The sender is unsubscribing from another entity's
|
38
|
+
# presence.
|
39
|
+
#
|
40
|
+
# * `:unsubscribed` -- The subscription request has been denied or a
|
41
|
+
# previously-granted subscription has been cancelled.
|
42
|
+
#
|
43
|
+
# * `:probe` -- A request for an entity's current presence; should be
|
44
|
+
# generated only by a server on behalf of a user.
|
45
|
+
#
|
46
|
+
# * `:error` -- An error has occurred regarding processing or delivery of a
|
47
|
+
# previously-sent presence stanza.
|
27
48
|
#
|
28
49
|
# Blather provides a helper for each possible type:
|
29
50
|
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
51
|
+
# Presence#unavailabe?
|
52
|
+
# Presence#unavailable?
|
53
|
+
# Presence#subscribe?
|
54
|
+
# Presence#subscribed?
|
55
|
+
# Presence#unsubscribe?
|
56
|
+
# Presence#unsubscribed?
|
57
|
+
# Presence#probe?
|
58
|
+
# Presence#error?
|
38
59
|
#
|
39
|
-
# Blather treats the
|
40
|
-
# The default
|
60
|
+
# Blather treats the `type` attribute like a normal ruby object attribute
|
61
|
+
# providing a getter and setter. The default `type` is nil.
|
41
62
|
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
63
|
+
# presence = Presence.new
|
64
|
+
# presence.type # => nil
|
65
|
+
# presence.type = :unavailable
|
66
|
+
# presence.unavailable? # => true
|
67
|
+
# presence.error? # => false
|
47
68
|
#
|
48
|
-
#
|
69
|
+
# presence.type = :invalid # => RuntimeError
|
49
70
|
#
|
71
|
+
# @handler :presence
|
50
72
|
class Presence < Stanza
|
51
|
-
VALID_TYPES = [:unavailable,
|
73
|
+
VALID_TYPES = [ :unavailable,
|
74
|
+
:subscribe,
|
75
|
+
:subscribed,
|
76
|
+
:unsubscribe,
|
77
|
+
:unsubscribed,
|
78
|
+
:probe,
|
79
|
+
:error].freeze
|
52
80
|
|
53
81
|
register :presence
|
54
82
|
|
55
|
-
##
|
56
83
|
# Creates a class based on the presence type
|
57
84
|
# either a Status or Subscription object is created based
|
58
85
|
# on the type attribute.
|
@@ -66,18 +93,67 @@ class Stanza
|
|
66
93
|
klass.new.inherit(node)
|
67
94
|
end
|
68
95
|
|
69
|
-
##
|
70
96
|
# Ensure element_name is "presence" for all subclasses
|
71
97
|
def self.new
|
72
98
|
super :presence
|
73
99
|
end
|
74
100
|
|
75
|
-
|
101
|
+
# Check if the IQ is of type :unavailable
|
102
|
+
#
|
103
|
+
# @return [true, false]
|
104
|
+
def unavailable?
|
105
|
+
self.type == :unavailable
|
106
|
+
end
|
76
107
|
|
77
|
-
|
78
|
-
#
|
79
|
-
|
80
|
-
|
108
|
+
# Check if the IQ is of type :subscribe
|
109
|
+
#
|
110
|
+
# @return [true, false]
|
111
|
+
def subscribe?
|
112
|
+
self.type == :subscribe
|
113
|
+
end
|
114
|
+
|
115
|
+
# Check if the IQ is of type :subscribed
|
116
|
+
#
|
117
|
+
# @return [true, false]
|
118
|
+
def subscribed?
|
119
|
+
self.type == :subscribed
|
120
|
+
end
|
121
|
+
|
122
|
+
# Check if the IQ is of type :unsubscribe
|
123
|
+
#
|
124
|
+
# @return [true, false]
|
125
|
+
def unsubscribe?
|
126
|
+
self.type == :unsubscribe
|
127
|
+
end
|
128
|
+
|
129
|
+
# Check if the IQ is of type :unsubscribed
|
130
|
+
#
|
131
|
+
# @return [true, false]
|
132
|
+
def unsubscribed?
|
133
|
+
self.type == :unsubscribed
|
134
|
+
end
|
135
|
+
|
136
|
+
# Check if the IQ is of type :probe
|
137
|
+
#
|
138
|
+
# @return [true, false]
|
139
|
+
def probe?
|
140
|
+
self.type == :probe
|
141
|
+
end
|
142
|
+
|
143
|
+
# Check if the IQ is of type :error
|
144
|
+
#
|
145
|
+
# @return [true, false]
|
146
|
+
def error?
|
147
|
+
self.type == :error
|
148
|
+
end
|
149
|
+
|
150
|
+
# Ensures type is one of Blather::Stanza::Presence::VALID_TYPES
|
151
|
+
#
|
152
|
+
# @param [#to_sym] type the Presence type. Must be one of VALID_TYPES
|
153
|
+
def type=(type)
|
154
|
+
if type && !VALID_TYPES.include?(type.to_sym)
|
155
|
+
raise ArgumentError, "Invalid Type (#{type}), use: #{VALID_TYPES*' '}"
|
156
|
+
end
|
81
157
|
super
|
82
158
|
end
|
83
159
|
|
@@ -2,73 +2,89 @@ module Blather
|
|
2
2
|
class Stanza
|
3
3
|
class Presence
|
4
4
|
|
5
|
-
#
|
5
|
+
# # Status Stanza
|
6
6
|
#
|
7
|
-
#
|
8
|
-
# various sub-states of the latter and optional user-defined descriptive text), and to notify other entities of
|
9
|
-
# that availability.
|
7
|
+
# [RFC 3921 Section 2.2.2 - Presence Child Elements](http://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2)
|
10
8
|
#
|
11
|
-
#
|
9
|
+
# Presence stanzas are used to express an entity's current network
|
10
|
+
# availability (offline or online, along with various sub-states of the
|
11
|
+
# latter and optional user-defined descriptive text), and to notify other
|
12
|
+
# entities of that availability.
|
12
13
|
#
|
13
|
-
#
|
14
|
+
# ## "State" Attribute
|
14
15
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# *
|
19
|
-
#
|
16
|
+
# The `state` attribute determains the availability of the entity and can be
|
17
|
+
# one of the following:
|
18
|
+
#
|
19
|
+
# * `:available` -- The entity or resource is available
|
20
|
+
#
|
21
|
+
# * `:away` -- The entity or resource is temporarily away.
|
22
|
+
#
|
23
|
+
# * `:chat` -- The entity or resource is actively interested in chatting.
|
24
|
+
#
|
25
|
+
# * `:dnd` -- The entity or resource is busy (dnd = "Do Not Disturb").
|
26
|
+
#
|
27
|
+
# * `:xa` -- The entity or resource is away for an extended period (xa =
|
28
|
+
# "eXtended Away").
|
20
29
|
#
|
21
30
|
# Blather provides a helper for each possible state:
|
22
31
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
32
|
+
# Status#available?
|
33
|
+
# Status#away?
|
34
|
+
# Status#chat?
|
35
|
+
# Status#dnd?
|
36
|
+
# Status#xa?
|
37
|
+
#
|
38
|
+
# Blather treats the `type` attribute like a normal ruby object attribute
|
39
|
+
# providing a getter and setter. The default `type` is `available`.
|
28
40
|
#
|
29
|
-
#
|
30
|
-
#
|
41
|
+
# status = Status.new
|
42
|
+
# status.state # => :available
|
43
|
+
# status.available? # => true
|
44
|
+
# status.state = :away
|
45
|
+
# status.away? # => true
|
46
|
+
# status.available? # => false
|
47
|
+
# status
|
48
|
+
# status.state = :invalid # => RuntimeError
|
31
49
|
#
|
32
|
-
#
|
33
|
-
# status.state # => :available
|
34
|
-
# status.available? # => true
|
35
|
-
# status.state = :away
|
36
|
-
# status.away? # => true
|
37
|
-
# status.available? # => false
|
38
|
-
# status
|
39
|
-
# status.state = :invalid # => RuntimeError
|
50
|
+
# ## "Type" Attribute
|
40
51
|
#
|
41
|
-
#
|
52
|
+
# The `type` attribute is inherited from Presence, but limits the value to
|
53
|
+
# either `nil` or `:unavailable` as these are the only types that relate to
|
54
|
+
# Status.
|
42
55
|
#
|
43
|
-
#
|
44
|
-
# as these are the only types that relate to Status.
|
56
|
+
# ## "Priority" Attribute
|
45
57
|
#
|
46
|
-
#
|
58
|
+
# The `priority` attribute sets the priority of the status for the entity
|
59
|
+
# and must be an integer between -128 and 127.
|
47
60
|
#
|
48
|
-
#
|
49
|
-
# -128 and 127.
|
61
|
+
# ## "Message" Attribute
|
50
62
|
#
|
51
|
-
#
|
63
|
+
# The optional `message` element contains XML character data specifying a
|
64
|
+
# natural-language description of availability status. It is normally used
|
65
|
+
# in conjunction with the show element to provide a detailed description of
|
66
|
+
# an availability state (e.g., "In a meeting").
|
52
67
|
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# description of an availability state (e.g., "In a meeting").
|
56
|
-
#
|
57
|
-
# Blather treats the +message+ attribute like a normal ruby object attribute providing a getter and setter.
|
58
|
-
# The default +message+ is nil.
|
68
|
+
# Blather treats the `message` attribute like a normal ruby object attribute
|
69
|
+
# providing a getter and setter. The default `message` is nil.
|
59
70
|
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
71
|
+
# status = Status.new
|
72
|
+
# status.message # => nil
|
73
|
+
# status.message = "gone!"
|
74
|
+
# status.message # => "gone!"
|
64
75
|
#
|
76
|
+
# @handler :status
|
65
77
|
class Status < Presence
|
66
|
-
VALID_STATES = [:away, :chat, :dnd, :xa]
|
78
|
+
VALID_STATES = [:away, :chat, :dnd, :xa].freeze
|
67
79
|
|
68
80
|
include Comparable
|
69
81
|
|
70
82
|
register :status, :status
|
71
83
|
|
84
|
+
# Create a new Status stanza
|
85
|
+
#
|
86
|
+
# @param [<:away, :chat, :dnd, :xa>] state the state of the status
|
87
|
+
# @param [#to_s] message a message to send with the status
|
72
88
|
def self.new(state = nil, message = nil)
|
73
89
|
node = super()
|
74
90
|
node.state = state
|
@@ -76,48 +92,112 @@ class Presence
|
|
76
92
|
node
|
77
93
|
end
|
78
94
|
|
79
|
-
|
95
|
+
# Check if the state is available
|
96
|
+
#
|
97
|
+
# @return [true, false]
|
98
|
+
def available?
|
99
|
+
self.state == :available
|
100
|
+
end
|
101
|
+
|
102
|
+
# Check if the state is away
|
103
|
+
#
|
104
|
+
# @return [true, false]
|
105
|
+
def away?
|
106
|
+
self.state == :away
|
107
|
+
end
|
108
|
+
|
109
|
+
# Check if the state is chat
|
110
|
+
#
|
111
|
+
# @return [true, false]
|
112
|
+
def chat?
|
113
|
+
self.state == :chat
|
114
|
+
end
|
115
|
+
|
116
|
+
# Check if the state is dnd
|
117
|
+
#
|
118
|
+
# @return [true, false]
|
119
|
+
def dnd?
|
120
|
+
self.state == :dnd
|
121
|
+
end
|
122
|
+
|
123
|
+
# Check if the state is xa
|
124
|
+
#
|
125
|
+
# @return [true, false]
|
126
|
+
def xa?
|
127
|
+
self.state == :xa
|
128
|
+
end
|
80
129
|
|
81
|
-
|
130
|
+
# Set the type attribute
|
82
131
|
# Ensures type is nil or :unavailable
|
83
|
-
|
84
|
-
|
132
|
+
#
|
133
|
+
# @param [<:unavailable, nil>] type the type
|
134
|
+
def type=(type)
|
135
|
+
if type && type.to_sym != :unavailable
|
136
|
+
raise ArgumentError, "Invalid type (#{type}). Must be nil or unavailable"
|
137
|
+
end
|
85
138
|
super
|
86
139
|
end
|
87
140
|
|
88
|
-
|
141
|
+
# Set the state
|
89
142
|
# Ensure state is one of :available, :away, :chat, :dnd, :xa or nil
|
143
|
+
#
|
144
|
+
# @param [<:available, :away, :chat, :dnd, :xa, nil>] state
|
90
145
|
def state=(state) # :nodoc:
|
91
146
|
state = state.to_sym if state
|
92
147
|
state = nil if state == :available
|
93
|
-
|
148
|
+
if state && !VALID_STATES.include?(state)
|
149
|
+
raise ArgumentError, "Invalid Status (#{state}), use: #{VALID_STATES*' '}"
|
150
|
+
end
|
94
151
|
|
95
152
|
set_content_for :show, state
|
96
153
|
end
|
97
154
|
|
98
|
-
|
99
|
-
#
|
100
|
-
|
155
|
+
# Get the state of the status
|
156
|
+
#
|
157
|
+
# @return [<:available, :away, :chat, :dnd, :xa>]
|
158
|
+
def state
|
101
159
|
state = type || content_from(:show)
|
102
160
|
state = :available if state.blank?
|
103
161
|
state.to_sym
|
104
162
|
end
|
105
163
|
|
106
|
-
|
107
|
-
#
|
164
|
+
# Set the priority of the status
|
165
|
+
# Ensures priority is between -128 and 127
|
166
|
+
#
|
167
|
+
# @param [Fixnum<-128...127>] new_priority
|
108
168
|
def priority=(new_priority) # :nodoc:
|
109
|
-
|
169
|
+
if new_priority && !(-128..127).include?(new_priority.to_i)
|
170
|
+
raise ArgumentError, 'Priority must be between -128 and +127'
|
171
|
+
end
|
110
172
|
set_content_for :priority, new_priority
|
111
|
-
|
112
173
|
end
|
113
174
|
|
114
|
-
|
175
|
+
# Get the priority of the status
|
176
|
+
#
|
177
|
+
# @return [Fixnum<-128...127>]
|
178
|
+
def priority
|
179
|
+
read_content(:priority).to_i
|
180
|
+
end
|
115
181
|
|
116
|
-
|
182
|
+
# Get the status message
|
183
|
+
#
|
184
|
+
# @return [String, nil]
|
185
|
+
def message
|
186
|
+
read_content :status
|
187
|
+
end
|
188
|
+
|
189
|
+
# Set the status message
|
190
|
+
#
|
191
|
+
# @param [String, nil] message
|
192
|
+
def message=(message)
|
193
|
+
set_content_for :status, message
|
194
|
+
end
|
117
195
|
|
118
|
-
##
|
119
196
|
# Compare status based on priority
|
120
197
|
# raises an error if the JIDs aren't the same
|
198
|
+
#
|
199
|
+
# @param [Blather::Stanza::Presence::Status] o
|
200
|
+
# @return [true,false]
|
121
201
|
def <=>(o)
|
122
202
|
unless self.from && o.from && self.from.stripped == o.from.stripped
|
123
203
|
raise ArgumentError, "Cannot compare status from different JIDs: #{[self.from, o.from].inspect}"
|