blather 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +3 -0
- data/.travis.yml +1 -8
- data/CHANGELOG.md +230 -0
- data/Guardfile +4 -4
- data/README.md +2 -8
- data/Rakefile +14 -27
- data/blather.gemspec +8 -18
- data/lib/blather.rb +1 -0
- data/lib/blather/client/client.rb +8 -0
- data/lib/blather/roster.rb +7 -0
- data/lib/blather/stanza/iq/roster.rb +1 -1
- data/lib/blather/stanza/message/muc_user.rb +2 -0
- data/lib/blather/stanza/muc/muc_user_base.rb +4 -3
- data/lib/blather/stanza/presence.rb +12 -14
- data/lib/blather/stanza/presence/c.rb +58 -62
- data/lib/blather/stanza/presence/muc.rb +14 -10
- data/lib/blather/stanza/presence/muc_user.rb +47 -36
- data/lib/blather/stanza/presence/status.rb +106 -101
- data/lib/blather/stanza/presence/subscription.rb +59 -60
- data/lib/blather/stream.rb +1 -3
- data/lib/blather/stream/features/resource.rb +0 -1
- data/lib/blather/version.rb +1 -2
- data/lib/blather/xmpp_node.rb +24 -3
- data/spec/blather/client/client_spec.rb +64 -64
- data/spec/blather/client/dsl/pubsub_spec.rb +127 -127
- data/spec/blather/client/dsl_spec.rb +11 -11
- data/spec/blather/errors/sasl_error_spec.rb +3 -3
- data/spec/blather/errors/stanza_error_spec.rb +26 -26
- data/spec/blather/errors/stream_error_spec.rb +22 -22
- data/spec/blather/errors_spec.rb +7 -7
- data/spec/blather/file_transfer_spec.rb +16 -18
- data/spec/blather/jid_spec.rb +29 -29
- data/spec/blather/roster_item_spec.rb +18 -18
- data/spec/blather/roster_spec.rb +18 -18
- data/spec/blather/stanza/discos/disco_info_spec.rb +56 -57
- data/spec/blather/stanza/discos/disco_items_spec.rb +33 -33
- data/spec/blather/stanza/iq/command_spec.rb +57 -57
- data/spec/blather/stanza/iq/ibb_spec.rb +27 -39
- data/spec/blather/stanza/iq/ping_spec.rb +13 -9
- data/spec/blather/stanza/iq/query_spec.rb +16 -16
- data/spec/blather/stanza/iq/roster_spec.rb +29 -30
- data/spec/blather/stanza/iq/s5b_spec.rb +10 -13
- data/spec/blather/stanza/iq/si_spec.rb +20 -23
- data/spec/blather/stanza/iq/vcard_spec.rb +22 -25
- data/spec/blather/stanza/iq_spec.rb +12 -12
- data/spec/blather/stanza/message/muc_user_spec.rb +36 -36
- data/spec/blather/stanza/message_spec.rb +56 -56
- data/spec/blather/stanza/presence/c_spec.rb +17 -7
- data/spec/blather/stanza/presence/muc_spec.rb +8 -8
- data/spec/blather/stanza/presence/muc_user_spec.rb +23 -23
- data/spec/blather/stanza/presence/status_spec.rb +42 -30
- data/spec/blather/stanza/presence/subscription_spec.rb +22 -23
- data/spec/blather/stanza/presence_spec.rb +72 -34
- data/spec/blather/stanza/pubsub/affiliations_spec.rb +12 -12
- data/spec/blather/stanza/pubsub/create_spec.rb +10 -10
- data/spec/blather/stanza/pubsub/event_spec.rb +31 -31
- data/spec/blather/stanza/pubsub/items_spec.rb +21 -21
- data/spec/blather/stanza/pubsub/publish_spec.rb +21 -21
- data/spec/blather/stanza/pubsub/retract_spec.rb +20 -20
- data/spec/blather/stanza/pubsub/subscribe_spec.rb +17 -17
- data/spec/blather/stanza/pubsub/subscription_spec.rb +28 -28
- data/spec/blather/stanza/pubsub/subscriptions_spec.rb +11 -11
- data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +22 -22
- data/spec/blather/stanza/pubsub_owner/delete_spec.rb +9 -9
- data/spec/blather/stanza/pubsub_owner/purge_spec.rb +9 -9
- data/spec/blather/stanza/pubsub_owner_spec.rb +6 -6
- data/spec/blather/stanza/pubsub_spec.rb +16 -16
- data/spec/blather/stanza/x_spec.rb +53 -53
- data/spec/blather/stanza_spec.rb +39 -39
- data/spec/blather/stream/client_spec.rb +133 -133
- data/spec/blather/stream/component_spec.rb +7 -7
- data/spec/blather/stream/parser_spec.rb +24 -24
- data/spec/blather/stream/ssl_spec.rb +7 -7
- data/spec/blather/xmpp_node_spec.rb +17 -7
- data/spec/blather_spec.rb +4 -4
- data/spec/spec_helper.rb +6 -54
- metadata +53 -68
- data/CHANGELOG +0 -220
@@ -85,27 +85,25 @@ class Stanza
|
|
85
85
|
# either a Status or Subscription object is created based
|
86
86
|
# on the type attribute.
|
87
87
|
# If neither is found it instantiates a Presence object
|
88
|
-
def self.import(node) # :nodoc:
|
89
|
-
|
90
|
-
node.children.detect do |e|
|
88
|
+
def self.import(node, *decorators) # :nodoc:
|
89
|
+
node.children.each do |e|
|
91
90
|
ns = e.namespace ? e.namespace.href : nil
|
92
|
-
klass = class_from_registration
|
91
|
+
klass = class_from_registration e.element_name, ns
|
92
|
+
decorators << klass if klass
|
93
93
|
end
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
when /subscribe/ then Subscription
|
101
|
-
else self
|
102
|
-
end
|
103
|
-
klass.new.inherit(node)
|
95
|
+
case node['type']
|
96
|
+
when nil, 'unavailable'
|
97
|
+
decorators << Status
|
98
|
+
when /subscribe/
|
99
|
+
decorators << Subscription
|
104
100
|
end
|
101
|
+
|
102
|
+
super
|
105
103
|
end
|
106
104
|
|
107
105
|
# Ensure element_name is "presence" for all subclasses
|
108
|
-
def self.new
|
106
|
+
def self.new(*args)
|
109
107
|
super :presence
|
110
108
|
end
|
111
109
|
|
@@ -22,82 +22,78 @@ class Presence
|
|
22
22
|
new_node.hash = hash
|
23
23
|
new_node.node = node
|
24
24
|
new_node.ver = ver
|
25
|
-
new_node
|
25
|
+
parse new_node.to_xml
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
self.new.inherit(node)
|
30
|
-
end
|
31
|
-
|
32
|
-
# @private
|
33
|
-
def inherit(node)
|
34
|
-
inherit_attrs node.attributes
|
35
|
-
self
|
36
|
-
end
|
28
|
+
module InstanceMethods
|
37
29
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
30
|
+
# @private
|
31
|
+
def inherit(node)
|
32
|
+
c.remove
|
33
|
+
super
|
34
|
+
self
|
35
|
+
end
|
44
36
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
37
|
+
# Get the name of the node
|
38
|
+
#
|
39
|
+
# @return [String, nil]
|
40
|
+
def node
|
41
|
+
c[:node]
|
42
|
+
end
|
51
43
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
44
|
+
# Set the name of the node
|
45
|
+
#
|
46
|
+
# @param [String, nil] node the new node name
|
47
|
+
def node=(node)
|
48
|
+
c[:node] = node
|
49
|
+
end
|
58
50
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
raise ArgumentError, "Invalid Hash Type (#{hash}), use: #{VALID_HASH_TYPES*' '}"
|
51
|
+
# Get the name of the hash
|
52
|
+
#
|
53
|
+
# @return [Symbol, nil]
|
54
|
+
def hash
|
55
|
+
c[:hash] && c[:hash].to_sym
|
65
56
|
end
|
66
|
-
c[:hash] = hash
|
67
|
-
end
|
68
57
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
58
|
+
# Set the name of the hash
|
59
|
+
#
|
60
|
+
# @param [String, nil] hash the new hash name
|
61
|
+
def hash=(hash)
|
62
|
+
if hash && !VALID_HASH_TYPES.include?(hash.to_s)
|
63
|
+
raise ArgumentError, "Invalid Hash Type (#{hash}), use: #{VALID_HASH_TYPES*' '}"
|
64
|
+
end
|
65
|
+
c[:hash] = hash
|
66
|
+
end
|
75
67
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
68
|
+
# Get the ver
|
69
|
+
#
|
70
|
+
# @return [String, nil]
|
71
|
+
def ver
|
72
|
+
c[:ver]
|
73
|
+
end
|
82
74
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
def c
|
89
|
-
c = if self.class.registered_ns
|
90
|
-
find_first('ns:c', :ns => self.class.registered_ns)
|
91
|
-
else
|
92
|
-
find_first('c')
|
75
|
+
# Set the ver
|
76
|
+
#
|
77
|
+
# @param [String, nil] ver the new ver
|
78
|
+
def ver=(ver)
|
79
|
+
c[:ver] = ver
|
93
80
|
end
|
94
81
|
|
95
|
-
|
96
|
-
|
97
|
-
|
82
|
+
# C node accessor
|
83
|
+
# If a c node exists it will be returned.
|
84
|
+
# Otherwise a new node will be created and returned
|
85
|
+
#
|
86
|
+
# @return [Blather::XMPPNode]
|
87
|
+
def c
|
88
|
+
unless c = find_first('ns:c', :ns => C.registered_ns)
|
89
|
+
self << (c = XMPPNode.new('c', self.document))
|
90
|
+
c.namespace = self.class.registered_ns
|
91
|
+
end
|
92
|
+
c
|
98
93
|
end
|
99
|
-
c
|
100
94
|
end
|
95
|
+
|
96
|
+
include InstanceMethods
|
101
97
|
end # C
|
102
98
|
end #Presence
|
103
99
|
end #Stanza
|
@@ -11,19 +11,23 @@ class Presence
|
|
11
11
|
new_node
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
module InstanceMethods
|
15
|
+
def inherit(node)
|
16
|
+
muc.remove
|
17
|
+
super
|
18
|
+
self
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def muc
|
22
|
+
unless muc = find_first('ns:x', :ns => MUC.registered_ns)
|
23
|
+
self << (muc = XMPPNode.new('x', self.document))
|
24
|
+
muc.namespace = self.class.registered_ns
|
25
|
+
end
|
26
|
+
muc
|
24
27
|
end
|
25
|
-
muc
|
26
28
|
end
|
29
|
+
|
30
|
+
include InstanceMethods
|
27
31
|
end # MUC
|
28
32
|
|
29
33
|
end # Presence
|
@@ -4,59 +4,70 @@ module Blather
|
|
4
4
|
class Stanza
|
5
5
|
class Presence
|
6
6
|
|
7
|
-
class MUCUser <
|
7
|
+
class MUCUser < Presence
|
8
8
|
include Blather::Stanza::MUC::MUCUserBase
|
9
9
|
|
10
|
-
def
|
11
|
-
|
10
|
+
def self.decorator_modules
|
11
|
+
super + [Blather::Stanza::MUC::MUCUserBase]
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
item.affiliation = val
|
16
|
-
end
|
14
|
+
register :muc_user_presence, :x, MUC_USER_NAMESPACE
|
17
15
|
|
18
|
-
|
19
|
-
item.role
|
20
|
-
end
|
16
|
+
module InstanceMethods
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
def affiliation
|
19
|
+
item.affiliation
|
20
|
+
end
|
25
21
|
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
def affiliation=(val)
|
23
|
+
item.affiliation = val
|
24
|
+
end
|
29
25
|
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
def role
|
27
|
+
item.role
|
28
|
+
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
def role=(val)
|
31
|
+
item.role = val
|
32
|
+
end
|
37
33
|
|
38
|
-
|
39
|
-
|
40
|
-
val.each do |code|
|
41
|
-
muc_user << Status.new(code)
|
34
|
+
def jid
|
35
|
+
item.jid
|
42
36
|
end
|
43
|
-
end
|
44
37
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
38
|
+
def jid=(val)
|
39
|
+
item.jid = val
|
40
|
+
end
|
41
|
+
|
42
|
+
def status_codes
|
43
|
+
status.map &:code
|
44
|
+
end
|
45
|
+
|
46
|
+
def status_codes=(val)
|
47
|
+
muc_user.remove_children :status
|
48
|
+
val.each do |code|
|
49
|
+
muc_user << Status.new(code)
|
50
|
+
end
|
51
51
|
end
|
52
|
-
end
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
def item
|
54
|
+
if item = muc_user.find_first('ns:item', :ns => MUCUser.registered_ns)
|
55
|
+
Item.new item
|
56
|
+
else
|
57
|
+
muc_user << (item = Item.new nil, nil, nil, self.document)
|
58
|
+
item
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def status
|
63
|
+
muc_user.find('ns:status', :ns => MUCUser.registered_ns).map do |status|
|
64
|
+
Status.new status
|
65
|
+
end
|
57
66
|
end
|
58
67
|
end
|
59
68
|
|
69
|
+
include InstanceMethods
|
70
|
+
|
60
71
|
class Item < XMPPNode
|
61
72
|
def self.new(affiliation = nil, role = nil, jid = nil, document = nil)
|
62
73
|
new_node = super :item, document
|
@@ -93,127 +93,132 @@ class Presence
|
|
93
93
|
node
|
94
94
|
end
|
95
95
|
|
96
|
-
|
97
|
-
#
|
98
|
-
# @return [true, false]
|
99
|
-
def available?
|
100
|
-
self.state == :available
|
101
|
-
end
|
102
|
-
|
103
|
-
# Check if the state is away
|
104
|
-
#
|
105
|
-
# @return [true, false]
|
106
|
-
def away?
|
107
|
-
self.state == :away
|
108
|
-
end
|
96
|
+
module InstanceMethods
|
109
97
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
98
|
+
# Check if the state is available
|
99
|
+
#
|
100
|
+
# @return [true, false]
|
101
|
+
def available?
|
102
|
+
self.state == :available
|
103
|
+
end
|
116
104
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
105
|
+
# Check if the state is away
|
106
|
+
#
|
107
|
+
# @return [true, false]
|
108
|
+
def away?
|
109
|
+
self.state == :away
|
110
|
+
end
|
123
111
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
112
|
+
# Check if the state is chat
|
113
|
+
#
|
114
|
+
# @return [true, false]
|
115
|
+
def chat?
|
116
|
+
self.state == :chat
|
117
|
+
end
|
130
118
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
if type && type.to_sym != :unavailable
|
137
|
-
raise ArgumentError, "Invalid type (#{type}). Must be nil or unavailable"
|
119
|
+
# Check if the state is dnd
|
120
|
+
#
|
121
|
+
# @return [true, false]
|
122
|
+
def dnd?
|
123
|
+
self.state == :dnd
|
138
124
|
end
|
139
|
-
super
|
140
|
-
end
|
141
125
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
state = state.to_sym if state
|
148
|
-
state = nil if state == :available
|
149
|
-
if state && !VALID_STATES.include?(state)
|
150
|
-
raise ArgumentError, "Invalid Status (#{state}), use: #{VALID_STATES*' '}"
|
126
|
+
# Check if the state is xa
|
127
|
+
#
|
128
|
+
# @return [true, false]
|
129
|
+
def xa?
|
130
|
+
self.state == :xa
|
151
131
|
end
|
152
132
|
|
153
|
-
|
154
|
-
|
133
|
+
# Set the type attribute
|
134
|
+
# Ensures type is nil or :unavailable
|
135
|
+
#
|
136
|
+
# @param [<:unavailable, nil>] type the type
|
137
|
+
def type=(type)
|
138
|
+
if type && type.to_sym != :unavailable
|
139
|
+
raise ArgumentError, "Invalid type (#{type}). Must be nil or unavailable"
|
140
|
+
end
|
141
|
+
super
|
142
|
+
end
|
155
143
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
state
|
161
|
-
|
162
|
-
|
163
|
-
|
144
|
+
# Set the state
|
145
|
+
# Ensure state is one of :available, :away, :chat, :dnd, :xa or nil
|
146
|
+
#
|
147
|
+
# @param [<:available, :away, :chat, :dnd, :xa, nil>] state
|
148
|
+
def state=(state) # :nodoc:
|
149
|
+
state = state.to_sym if state
|
150
|
+
state = nil if state == :available
|
151
|
+
if state && !VALID_STATES.include?(state)
|
152
|
+
raise ArgumentError, "Invalid Status (#{state}), use: #{VALID_STATES*' '}"
|
153
|
+
end
|
154
|
+
|
155
|
+
set_content_for :show, state
|
156
|
+
end
|
164
157
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
158
|
+
# Get the state of the status
|
159
|
+
#
|
160
|
+
# @return [<:available, :away, :chat, :dnd, :xa>]
|
161
|
+
def state
|
162
|
+
state = type || content_from(:show)
|
163
|
+
state = :available if state.blank?
|
164
|
+
state.to_sym
|
172
165
|
end
|
173
|
-
set_content_for :priority, new_priority
|
174
|
-
end
|
175
166
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
167
|
+
# Set the priority of the status
|
168
|
+
# Ensures priority is between -128 and 127
|
169
|
+
#
|
170
|
+
# @param [Fixnum<-128...127>] new_priority
|
171
|
+
def priority=(new_priority) # :nodoc:
|
172
|
+
if new_priority && !(-128..127).include?(new_priority.to_i)
|
173
|
+
raise ArgumentError, 'Priority must be between -128 and +127'
|
174
|
+
end
|
175
|
+
set_content_for :priority, new_priority
|
176
|
+
end
|
182
177
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
178
|
+
# Get the priority of the status
|
179
|
+
#
|
180
|
+
# @return [Fixnum<-128...127>]
|
181
|
+
def priority
|
182
|
+
read_content(:priority).to_i
|
183
|
+
end
|
189
184
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
185
|
+
# Get the status message
|
186
|
+
#
|
187
|
+
# @return [String, nil]
|
188
|
+
def message
|
189
|
+
read_content :status
|
190
|
+
end
|
196
191
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
# @return [true,false]
|
203
|
-
def <=>(o)
|
204
|
-
unless self.from && o.from && self.from.stripped == o.from.stripped
|
205
|
-
raise ArgumentError, "Cannot compare status from different JIDs: #{[self.from, o.from].inspect}"
|
192
|
+
# Set the status message
|
193
|
+
#
|
194
|
+
# @param [String, nil] message
|
195
|
+
def message=(message)
|
196
|
+
set_content_for :status, message
|
206
197
|
end
|
207
198
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
199
|
+
# Compare status based on priority and state:
|
200
|
+
# unavailable status is always less valuable than others
|
201
|
+
# Raises an error if the JIDs aren't the same
|
202
|
+
#
|
203
|
+
# @param [Blather::Stanza::Presence::Status] o
|
204
|
+
# @return [true,false]
|
205
|
+
def <=>(o)
|
206
|
+
unless self.from && o.from && self.from.stripped == o.from.stripped
|
207
|
+
raise ArgumentError, "Cannot compare status from different JIDs: #{[self.from, o.from].inspect}"
|
208
|
+
end
|
209
|
+
|
210
|
+
if (self.type.nil? && o.type.nil?) || (!self.type.nil? && !o.type.nil?)
|
211
|
+
self.priority <=> o.priority
|
212
|
+
elsif self.type.nil? && !o.type.nil?
|
213
|
+
1
|
214
|
+
elsif !self.type.nil? && o.type.nil?
|
215
|
+
-1
|
216
|
+
end
|
214
217
|
end
|
215
218
|
end
|
216
219
|
|
220
|
+
include InstanceMethods
|
221
|
+
|
217
222
|
end #Status
|
218
223
|
|
219
224
|
end #Presence
|