tp-blather 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/.autotest +13 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +8 -0
  6. data/CHANGELOG.md +249 -0
  7. data/Gemfile +4 -0
  8. data/Guardfile +5 -0
  9. data/LICENSE +22 -0
  10. data/README.md +413 -0
  11. data/Rakefile +20 -0
  12. data/TODO.md +2 -0
  13. data/blather.gemspec +51 -0
  14. data/examples/certs/README +20 -0
  15. data/examples/certs/ca-bundle.crt +3987 -0
  16. data/examples/echo.rb +19 -0
  17. data/examples/execute.rb +17 -0
  18. data/examples/ping_pong.rb +38 -0
  19. data/examples/print_hierarchy.rb +77 -0
  20. data/examples/rosterprint.rb +15 -0
  21. data/examples/stream_only.rb +28 -0
  22. data/examples/trusted_echo.rb +21 -0
  23. data/examples/xmpp4r/echo.rb +36 -0
  24. data/lib/blather.rb +112 -0
  25. data/lib/blather/cert_store.rb +53 -0
  26. data/lib/blather/client.rb +95 -0
  27. data/lib/blather/client/client.rb +345 -0
  28. data/lib/blather/client/dsl.rb +320 -0
  29. data/lib/blather/client/dsl/pubsub.rb +174 -0
  30. data/lib/blather/core_ext/eventmachine.rb +125 -0
  31. data/lib/blather/core_ext/ipaddr.rb +20 -0
  32. data/lib/blather/errors.rb +69 -0
  33. data/lib/blather/errors/sasl_error.rb +44 -0
  34. data/lib/blather/errors/stanza_error.rb +110 -0
  35. data/lib/blather/errors/stream_error.rb +84 -0
  36. data/lib/blather/file_transfer.rb +107 -0
  37. data/lib/blather/file_transfer/ibb.rb +68 -0
  38. data/lib/blather/file_transfer/s5b.rb +114 -0
  39. data/lib/blather/jid.rb +141 -0
  40. data/lib/blather/roster.rb +118 -0
  41. data/lib/blather/roster_item.rb +146 -0
  42. data/lib/blather/stanza.rb +167 -0
  43. data/lib/blather/stanza/disco.rb +32 -0
  44. data/lib/blather/stanza/disco/capabilities.rb +161 -0
  45. data/lib/blather/stanza/disco/disco_info.rb +205 -0
  46. data/lib/blather/stanza/disco/disco_items.rb +134 -0
  47. data/lib/blather/stanza/iq.rb +144 -0
  48. data/lib/blather/stanza/iq/command.rb +339 -0
  49. data/lib/blather/stanza/iq/ibb.rb +86 -0
  50. data/lib/blather/stanza/iq/ping.rb +50 -0
  51. data/lib/blather/stanza/iq/query.rb +53 -0
  52. data/lib/blather/stanza/iq/roster.rb +185 -0
  53. data/lib/blather/stanza/iq/s5b.rb +208 -0
  54. data/lib/blather/stanza/iq/si.rb +415 -0
  55. data/lib/blather/stanza/iq/vcard.rb +149 -0
  56. data/lib/blather/stanza/message.rb +428 -0
  57. data/lib/blather/stanza/message/muc_user.rb +119 -0
  58. data/lib/blather/stanza/muc/muc_user_base.rb +54 -0
  59. data/lib/blather/stanza/presence.rb +172 -0
  60. data/lib/blather/stanza/presence/c.rb +100 -0
  61. data/lib/blather/stanza/presence/muc.rb +35 -0
  62. data/lib/blather/stanza/presence/muc_user.rb +147 -0
  63. data/lib/blather/stanza/presence/status.rb +218 -0
  64. data/lib/blather/stanza/presence/subscription.rb +100 -0
  65. data/lib/blather/stanza/pubsub.rb +119 -0
  66. data/lib/blather/stanza/pubsub/affiliations.rb +79 -0
  67. data/lib/blather/stanza/pubsub/create.rb +65 -0
  68. data/lib/blather/stanza/pubsub/errors.rb +18 -0
  69. data/lib/blather/stanza/pubsub/event.rb +139 -0
  70. data/lib/blather/stanza/pubsub/items.rb +103 -0
  71. data/lib/blather/stanza/pubsub/publish.rb +103 -0
  72. data/lib/blather/stanza/pubsub/retract.rb +92 -0
  73. data/lib/blather/stanza/pubsub/subscribe.rb +68 -0
  74. data/lib/blather/stanza/pubsub/subscription.rb +135 -0
  75. data/lib/blather/stanza/pubsub/subscriptions.rb +83 -0
  76. data/lib/blather/stanza/pubsub/unsubscribe.rb +84 -0
  77. data/lib/blather/stanza/pubsub_owner.rb +51 -0
  78. data/lib/blather/stanza/pubsub_owner/delete.rb +52 -0
  79. data/lib/blather/stanza/pubsub_owner/purge.rb +52 -0
  80. data/lib/blather/stanza/x.rb +416 -0
  81. data/lib/blather/stream.rb +266 -0
  82. data/lib/blather/stream/client.rb +32 -0
  83. data/lib/blather/stream/component.rb +39 -0
  84. data/lib/blather/stream/features.rb +70 -0
  85. data/lib/blather/stream/features/register.rb +38 -0
  86. data/lib/blather/stream/features/resource.rb +63 -0
  87. data/lib/blather/stream/features/sasl.rb +190 -0
  88. data/lib/blather/stream/features/session.rb +45 -0
  89. data/lib/blather/stream/features/tls.rb +29 -0
  90. data/lib/blather/stream/parser.rb +102 -0
  91. data/lib/blather/version.rb +3 -0
  92. data/lib/blather/xmpp_node.rb +94 -0
  93. data/spec/blather/client/client_spec.rb +687 -0
  94. data/spec/blather/client/dsl/pubsub_spec.rb +492 -0
  95. data/spec/blather/client/dsl_spec.rb +266 -0
  96. data/spec/blather/errors/sasl_error_spec.rb +33 -0
  97. data/spec/blather/errors/stanza_error_spec.rb +129 -0
  98. data/spec/blather/errors/stream_error_spec.rb +108 -0
  99. data/spec/blather/errors_spec.rb +33 -0
  100. data/spec/blather/file_transfer_spec.rb +135 -0
  101. data/spec/blather/jid_spec.rb +87 -0
  102. data/spec/blather/roster_item_spec.rb +134 -0
  103. data/spec/blather/roster_spec.rb +107 -0
  104. data/spec/blather/stanza/discos/disco_info_spec.rb +247 -0
  105. data/spec/blather/stanza/discos/disco_items_spec.rb +154 -0
  106. data/spec/blather/stanza/iq/command_spec.rb +206 -0
  107. data/spec/blather/stanza/iq/ibb_spec.rb +124 -0
  108. data/spec/blather/stanza/iq/ping_spec.rb +45 -0
  109. data/spec/blather/stanza/iq/query_spec.rb +64 -0
  110. data/spec/blather/stanza/iq/roster_spec.rb +139 -0
  111. data/spec/blather/stanza/iq/s5b_spec.rb +57 -0
  112. data/spec/blather/stanza/iq/si_spec.rb +98 -0
  113. data/spec/blather/stanza/iq/vcard_spec.rb +93 -0
  114. data/spec/blather/stanza/iq_spec.rb +61 -0
  115. data/spec/blather/stanza/message/muc_user_spec.rb +152 -0
  116. data/spec/blather/stanza/message_spec.rb +282 -0
  117. data/spec/blather/stanza/presence/c_spec.rb +56 -0
  118. data/spec/blather/stanza/presence/muc_spec.rb +37 -0
  119. data/spec/blather/stanza/presence/muc_user_spec.rb +83 -0
  120. data/spec/blather/stanza/presence/status_spec.rb +144 -0
  121. data/spec/blather/stanza/presence/subscription_spec.rb +102 -0
  122. data/spec/blather/stanza/presence_spec.rb +125 -0
  123. data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
  124. data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
  125. data/spec/blather/stanza/pubsub/event_spec.rb +98 -0
  126. data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
  127. data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
  128. data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
  129. data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
  130. data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
  131. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
  132. data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +74 -0
  133. data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
  134. data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
  135. data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
  136. data/spec/blather/stanza/pubsub_spec.rb +68 -0
  137. data/spec/blather/stanza/x_spec.rb +231 -0
  138. data/spec/blather/stanza_spec.rb +134 -0
  139. data/spec/blather/stream/client_spec.rb +1090 -0
  140. data/spec/blather/stream/component_spec.rb +108 -0
  141. data/spec/blather/stream/parser_spec.rb +152 -0
  142. data/spec/blather/stream/ssl_spec.rb +32 -0
  143. data/spec/blather/xmpp_node_spec.rb +47 -0
  144. data/spec/blather_spec.rb +34 -0
  145. data/spec/fixtures/pubsub.rb +311 -0
  146. data/spec/spec_helper.rb +17 -0
  147. data/yard/templates/default/class/html/handlers.erb +18 -0
  148. data/yard/templates/default/class/setup.rb +10 -0
  149. data/yard/templates/default/class/text/handlers.erb +1 -0
  150. metadata +459 -0
@@ -0,0 +1,161 @@
1
+ module Blather
2
+ class Stanza
3
+
4
+ # # Capabilities Stanza
5
+ #
6
+ # [XEP-0115 Entity Capabilities](http://xmpp.org/extensions/xep-0115.html)
7
+ #
8
+ # XMPP protocol extension for broadcasting and dynamically discovering client, device, or generic entity capabilities.
9
+ #
10
+ class Capabilities < Blather::Stanza::DiscoInfo
11
+ def self.new
12
+ super :result
13
+ end
14
+
15
+ # A string that is used to verify the identity and supported features of the entity.
16
+ #
17
+ # @return [String]
18
+ def ver
19
+ generate_ver identities, features
20
+ end
21
+
22
+ # A URI that uniquely identifies a software application, typically a URL at the
23
+ # website of the project or company that produces the software.
24
+ #
25
+ # @param [String] node the node URI
26
+ def node=(node)
27
+ @bare_node = node
28
+ super "#{node}##{ver}"
29
+ end
30
+
31
+ # Add an array of identities
32
+ # @param identities the array of identities, passed directly to Identity.new
33
+ def identities=(identities)
34
+ super identities
35
+ regenerate_full_node
36
+ end
37
+
38
+ # Add an array of features
39
+ # @param features the array of features, passed directly to Feature.new
40
+ def features=(features)
41
+ super features
42
+ regenerate_full_node
43
+ end
44
+
45
+ # The generated Presence::C node
46
+ #
47
+ # @return [Blather::Stanza::Presence::C]
48
+ def c
49
+ Blather::Stanza::Presence::C.new @bare_node, ver
50
+ end
51
+
52
+ private
53
+
54
+ def regenerate_full_node
55
+ self.node = @bare_node
56
+ end
57
+
58
+ def generate_ver_str(identities, features, forms = [])
59
+ # 1. Initialize an empty string S.
60
+ s = ''
61
+
62
+ # 2. Sort the service discovery identities by category and
63
+ # then by type (if it exists) and then by xml:lang (if it
64
+ # exists), formatted as CATEGORY '/' [TYPE] '/' [LANG] '/'
65
+ # [NAME]. Note that each slash is included even if the TYPE,
66
+ # LANG, or NAME is not included.
67
+ identities.sort! do |identity1, identity2|
68
+ cmp_result = nil
69
+ [:category, :type, :xml_lang, :name].each do |field|
70
+ value1 = identity1.send(field)
71
+ value2 = identity2.send(field)
72
+
73
+ if value1 != value2
74
+ cmp_result = value1 <=> value2
75
+ break
76
+ end
77
+ end
78
+ cmp_result
79
+ end
80
+
81
+ # 3. For each identity, append the 'category/type/lang/name' to
82
+ # S, followed by the '<' character.
83
+ s += identities.collect do |identity|
84
+ [:category, :type, :xml_lang, :name].collect do |field|
85
+ identity.send(field).to_s
86
+ end.join('/') + '<'
87
+ end.join
88
+
89
+ # 4. Sort the supported service discovery features.
90
+ features.sort! { |feature1, feature2| feature1.var <=> feature2.var }
91
+
92
+ # 5. For each feature, append the feature to S, followed by the
93
+ # '<' character.
94
+ s += features.collect { |feature| feature.var.to_s + '<' }.join
95
+
96
+ # 6. If the service discovery information response includes
97
+ # XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e., by
98
+ # the XML character data of the <value/> element).
99
+ forms.sort! do |form1, form2|
100
+ fform_type1 = form1.field 'FORM_TYPE'
101
+ fform_type2 = form2.field 'FORM_TYPE'
102
+ form_type1 = fform_type1 ? fform_type1.values.to_s : nil
103
+ form_type2 = fform_type2 ? fform_type2.values.to_s : nil
104
+ form_type1 <=> form_type2
105
+ end
106
+
107
+ # 7. For each extended service discovery information form:
108
+ forms.each do |form|
109
+ # 7.1. Append the XML character data of the FORM_TYPE field's
110
+ # <value/> element, followed by the '<' character.
111
+ fform_type = form.field 'FORM_TYPE'
112
+ form_type = fform_type ? fform_type.values.to_s : nil
113
+ s += "#{form_type}<"
114
+
115
+ # 7.2. Sort the fields by the value of the "var" attribute
116
+ fields = form.fields.sort { |field1, field2| field1.var <=> field2.var }
117
+
118
+ # 7.3. For each field:
119
+ fields.each do |field|
120
+ # 7.3.1. Append the value of the "var" attribute, followed by
121
+ # the '<' character.
122
+ s += "#{field.var}<"
123
+
124
+ # 7.3.2. Sort values by the XML character data of the <value/> element
125
+ # values = field.values.sort { |value1, value2| value1 <=> value2 }
126
+
127
+ # 7.3.3. For each <value/> element, append the XML character
128
+ # data, followed by the '<' character.
129
+ # s += values.collect { |value| "#{value}<" }.join
130
+ s += "#{field.value}<"
131
+ end
132
+ end
133
+ s
134
+ end
135
+
136
+ def generate_ver(identities, features, forms = [], hash = 'sha-1')
137
+ s = generate_ver_str identities, features, forms
138
+
139
+ # 9. Compute the verification string by hashing S using the
140
+ # algorithm specified in the 'hash' attribute (e.g., SHA-1 as
141
+ # defined in RFC 3174). The hashed data MUST be generated
142
+ # with binary output and encoded using Base64 as specified in
143
+ # Section 4 of RFC 4648 (note: the Base64 output MUST NOT
144
+ # include whitespace and MUST set padding bits to zero).
145
+
146
+ # See http://www.iana.org/assignments/hash-function-text-names
147
+ hash_klass = case hash
148
+ when 'md2' then nil
149
+ when 'md5' then Digest::MD5
150
+ when 'sha-1' then Digest::SHA1
151
+ when 'sha-224' then nil
152
+ when 'sha-256' then Digest::SHA256
153
+ when 'sha-384' then Digest::SHA384
154
+ when 'sha-512' then Digest::SHA512
155
+ end
156
+ hash_klass ? [hash_klass::digest(s)].pack('m').strip : nil
157
+ end
158
+ end # Caps
159
+
160
+ end # Stanza
161
+ end # Blather
@@ -0,0 +1,205 @@
1
+ module Blather
2
+ class Stanza
3
+
4
+ # # DiscoInfo Stanza
5
+ #
6
+ # [XEP-0030 Disco Info](http://xmpp.org/extensions/xep-0030.html#info)
7
+ #
8
+ # Disco Info node that provides or retreives information about a jabber entity
9
+ #
10
+ # @handler :disco_info
11
+ class DiscoInfo < Disco
12
+ register :disco_info, nil, 'http://jabber.org/protocol/disco#info'
13
+
14
+ # Create a new DiscoInfo stanza
15
+ # @param [:get, :set, :result, :error, nil] type the Iq stanza type
16
+ # @param [String, nil] node the name of the node the info belongs to
17
+ # @param [Array<Array, DiscoInfo::Identity>, nil] identities a list of
18
+ # identities. these are passed directly to DiscoInfo::Identity.new
19
+ # @param [Array<Array, DiscoInfo::Identity>, nil] features a list of
20
+ # features. these are passed directly to DiscoInfo::Feature.new
21
+ # @return [DiscoInfo] a new DiscoInfo stanza
22
+ def self.new(type = nil, node = nil, identities = [], features = [])
23
+ new_node = super type
24
+ new_node.node = node
25
+ new_node.identities = [identities]
26
+ new_node.features = [features]
27
+ new_node
28
+ end
29
+
30
+ # List of identity objects
31
+ def identities
32
+ query.find('//ns:identity', :ns => self.class.registered_ns).map do |i|
33
+ Identity.new i
34
+ end
35
+ end
36
+
37
+ # Add an array of identities
38
+ # @param identities the array of identities, passed directly to Identity.new
39
+ def identities=(identities)
40
+ query.find('//ns:identity', :ns => self.class.registered_ns).each &:remove
41
+ if identities
42
+ [identities].flatten.each { |i| self.query << Identity.new(i) }
43
+ end
44
+ end
45
+
46
+ # List of feature objects
47
+ def features
48
+ query.find('//ns:feature', :ns => self.class.registered_ns).map do |f|
49
+ Feature.new f
50
+ end
51
+ end
52
+
53
+ # Add an array of features
54
+ # @param features the array of features, passed directly to Feature.new
55
+ def features=(features)
56
+ query.find('//ns:feature', :ns => self.class.registered_ns).each &:remove
57
+ if features
58
+ [features].flatten.each { |f| self.query << Feature.new(f) }
59
+ end
60
+ end
61
+
62
+ # Compare two DiscoInfo objects by name, type and category
63
+ # @param [DiscoInfo] o the Identity object to compare against
64
+ # @return [true, false]
65
+ def eql?(o, *fields)
66
+ super o, *(fields + [:identities, :features])
67
+ end
68
+
69
+ # DiscoInfo::Identity
70
+ class Identity < XMPPNode
71
+ # Create a new DiscoInfo::Identity
72
+ # @overload new(node)
73
+ # Imports the XML::Node to create a Identity object
74
+ # @param [XML::Node] node the node object to import
75
+ # @overload new(opts = {})
76
+ # Creates a new Identity using a hash of options
77
+ # @param [Hash] opts a hash of options
78
+ # @option opts [String] :name the name of the identity
79
+ # @option opts [String] :type the type of the identity
80
+ # @option opts [String] :category the category of the identity
81
+ # @overload new(name, type = nil, category = nil)
82
+ # Create a new Identity by name
83
+ # @param [String] name the name of the Identity
84
+ # @param [String, nil] type the type of the Identity
85
+ # @param [String, nil] category the category of the Identity
86
+ def self.new(name, type = nil, category = nil, xml_lang = nil)
87
+ new_node = super :identity
88
+
89
+ case name
90
+ when Nokogiri::XML::Node
91
+ new_node.inherit name
92
+ when Hash
93
+ new_node.name = name[:name]
94
+ new_node.type = name[:type]
95
+ new_node.category = name[:category]
96
+ new_node.xml_lang = name[:xml_lang]
97
+ else
98
+ new_node.name = name
99
+ new_node.type = type
100
+ new_node.category = category
101
+ new_node.xml_lang = xml_lang
102
+ end
103
+ new_node
104
+ end
105
+
106
+ # The Identity's category
107
+ # @return [Symbol, nil]
108
+ def category
109
+ read_attr :category, :to_sym
110
+ end
111
+
112
+ # Set the Identity's category
113
+ # @param [String, Symbol] category the new category
114
+ def category=(category)
115
+ write_attr :category, category
116
+ end
117
+
118
+ # The Identity's type
119
+ # @return [Symbol, nil]
120
+ def type
121
+ read_attr :type, :to_sym
122
+ end
123
+
124
+ # Set the Identity's type
125
+ # @param [String, Symbol] type the new category
126
+ def type=(type)
127
+ write_attr :type, type
128
+ end
129
+
130
+ # The Identity's name
131
+ # @return [String]
132
+ def name
133
+ read_attr :name
134
+ end
135
+
136
+ # Set the Identity's name
137
+ # @param [String] name the new name for the identity
138
+ def name=(name)
139
+ write_attr :name, name
140
+ end
141
+
142
+ # The Identity's xml_lang
143
+ # @return [String]
144
+ def xml_lang
145
+ read_attr "lang"
146
+ end
147
+
148
+ # Set the Identity's name
149
+ # @param [String] name the new name for the identity
150
+ def xml_lang=(xml_lang)
151
+ write_attr "xml:lang", xml_lang
152
+ end
153
+
154
+ # Compare two Identity objects by name, type and category
155
+ # @param [DiscoInfo::Identity] o the Identity object to compare against
156
+ # @return [true, false]
157
+ def eql?(o, *fields)
158
+ super o, *(fields + [:name, :type, :category, :xml_lang])
159
+ end
160
+ end # Identity
161
+
162
+ # DiscoInfo::Feature
163
+ class Feature < XMPPNode
164
+ # Create a new DiscoInfo::Feature object
165
+ # @overload new(node)
166
+ # Create a new Feature by importing an XML::Node
167
+ # @param [XML::Node] node an XML::Node to import
168
+ # @overload new(var)
169
+ # Create a new feature by var
170
+ # @param [String] var a the Feautre's var
171
+ # @return [DiscoInfo::Feature]
172
+ def self.new(var)
173
+ new_node = super :feature
174
+ case var
175
+ when Nokogiri::XML::Node
176
+ new_node.inherit var
177
+ else
178
+ new_node.var = var
179
+ end
180
+ new_node
181
+ end
182
+
183
+ # The Feature's var
184
+ # @return [String]
185
+ def var
186
+ read_attr :var
187
+ end
188
+
189
+ # Set the Feature's var
190
+ # @param [String] var the new var
191
+ def var=(var)
192
+ write_attr :var, var
193
+ end
194
+
195
+ # Compare two DiscoInfo::Feature objects by name, type and category
196
+ # @param [DiscoInfo::Feature] o the Identity object to compare against
197
+ # @return [true, false]
198
+ def eql?(o, *fields)
199
+ super o, *(fields + [:var])
200
+ end
201
+ end
202
+ end # Feature
203
+
204
+ end # Stanza
205
+ end # Blather
@@ -0,0 +1,134 @@
1
+ module Blather
2
+ class Stanza
3
+
4
+ # # DiscoItems Stanza
5
+ #
6
+ # [XEP-0030 Disco Info](http://xmpp.org/extensions/xep-0030.html#items)
7
+ #
8
+ # Disco Items node that provides or retreives items associated with a
9
+ # jabbery entity
10
+ #
11
+ # @handler :disco_items
12
+ class DiscoItems < Disco
13
+ register :disco_items, nil, 'http://jabber.org/protocol/disco#items'
14
+
15
+ # Create a new DiscoItems node
16
+ #
17
+ # @param [#to_s] type the IQ type
18
+ # @param [#to_s] node the node the items are associated with
19
+ # @param [Array<Blather::XMPPNode>] items an array of Disco::Items
20
+ # @return [Blather::Stanza::DiscoItems]
21
+ def self.new(type = nil, node = nil, items = [])
22
+ new_node = super type
23
+ new_node.node = node
24
+ new_node.items = [items]
25
+ new_node
26
+ end
27
+
28
+ # Set of items associated with the node
29
+ #
30
+ # @return [Array<Blather::Stanza::DiscoItems::Item>]
31
+ def items
32
+ query.find('//ns:item', :ns => self.class.registered_ns).map do |i|
33
+ Item.new i
34
+ end
35
+ end
36
+
37
+ # Add an array of items
38
+ # @param items the array of items, passed directly to Item.new
39
+ def items=(items)
40
+ query.find('//ns:item', :ns => self.class.registered_ns).each &:remove
41
+ if items
42
+ [items].flatten.each { |i| self.query << Item.new(i) }
43
+ end
44
+ end
45
+
46
+ # An individual Disco Item
47
+ class Item < XMPPNode
48
+ # Create a new Blather::Stanza::DiscoItems::Item
49
+ #
50
+ # @overload new(node)
51
+ # Create a new Item by inheriting an existing node
52
+ # @param [XML::Node] node an XML::Node to inherit from
53
+ # @overload new(opts)
54
+ # Create a new Item through a hash of options
55
+ # @param [Hash] opts a hash options
56
+ # @option opts [Blather::JID, String] :jid the JID to attach to the item
57
+ # @option opts [#to_s] :node the node the item is attached to
58
+ # @option opts [#to_S] :name the name of the Item
59
+ # @overload new(jid, node = nil, name = nil)
60
+ # Create a new Item
61
+ # @param [Blather::JID, String] jid the JID to attach to the item
62
+ # @param [#to_s] node the node the item is attached to
63
+ # @param [#to_s] name the name of the Item
64
+ def self.new(jid, node = nil, name = nil)
65
+ new_node = super :item
66
+
67
+ case jid
68
+ when Nokogiri::XML::Node
69
+ new_node.inherit jid
70
+ when Hash
71
+ new_node.jid = jid[:jid]
72
+ new_node.node = jid[:node]
73
+ new_node.name = jid[:name]
74
+ else
75
+ new_node.jid = jid
76
+ new_node.node = node
77
+ new_node.name = name
78
+ end
79
+ new_node
80
+ end
81
+
82
+ # Get the JID attached to the node
83
+ #
84
+ # @return [Blather::JID, nil]
85
+ def jid
86
+ (j = self[:jid]) ? JID.new(j) : nil
87
+ end
88
+
89
+ # Set the JID of the node
90
+ #
91
+ # @param [Blather::JID, String, nil] jid the new JID
92
+ def jid=(jid)
93
+ write_attr :jid, jid
94
+ end
95
+
96
+ # Get the name of the node
97
+ #
98
+ # @return [String, nil]
99
+ def node
100
+ read_attr :node
101
+ end
102
+
103
+ # Set the name of the node
104
+ #
105
+ # @param [String, nil] node the new node name
106
+ def node=(node)
107
+ write_attr :node, node
108
+ end
109
+
110
+ # Get the Item name
111
+ #
112
+ # @return [String, nil]
113
+ def name
114
+ read_attr :name
115
+ end
116
+
117
+ # Set the Item name
118
+ #
119
+ # @param [#to_s] name the Item name
120
+ def name=(name)
121
+ write_attr :name, name
122
+ end
123
+
124
+ # Compare two DiscoItems::Item objects by name, type and category
125
+ # @param [DiscoItems::Item] o the Identity object to compare against
126
+ # @return [true, false]
127
+ def eql?(o, *fields)
128
+ super o, *(fields + [:jid, :node, :name])
129
+ end
130
+ end
131
+ end
132
+
133
+ end #Stanza
134
+ end #Blather