shingara-blather 0.4.8

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.
Files changed (100) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +162 -0
  3. data/examples/echo.rb +18 -0
  4. data/examples/execute.rb +16 -0
  5. data/examples/ping_pong.rb +37 -0
  6. data/examples/print_hierarchy.rb +76 -0
  7. data/examples/rosterprint.rb +14 -0
  8. data/examples/stream_only.rb +27 -0
  9. data/examples/xmpp4r/echo.rb +35 -0
  10. data/lib/blather/client/client.rb +310 -0
  11. data/lib/blather/client/dsl/pubsub.rb +170 -0
  12. data/lib/blather/client/dsl.rb +264 -0
  13. data/lib/blather/client.rb +87 -0
  14. data/lib/blather/core_ext/nokogiri.rb +40 -0
  15. data/lib/blather/errors/sasl_error.rb +43 -0
  16. data/lib/blather/errors/stanza_error.rb +107 -0
  17. data/lib/blather/errors/stream_error.rb +82 -0
  18. data/lib/blather/errors.rb +69 -0
  19. data/lib/blather/jid.rb +142 -0
  20. data/lib/blather/roster.rb +111 -0
  21. data/lib/blather/roster_item.rb +122 -0
  22. data/lib/blather/stanza/disco/disco_info.rb +176 -0
  23. data/lib/blather/stanza/disco/disco_items.rb +132 -0
  24. data/lib/blather/stanza/disco.rb +25 -0
  25. data/lib/blather/stanza/iq/query.rb +53 -0
  26. data/lib/blather/stanza/iq/roster.rb +179 -0
  27. data/lib/blather/stanza/iq.rb +138 -0
  28. data/lib/blather/stanza/message.rb +332 -0
  29. data/lib/blather/stanza/presence/status.rb +212 -0
  30. data/lib/blather/stanza/presence/subscription.rb +101 -0
  31. data/lib/blather/stanza/presence.rb +163 -0
  32. data/lib/blather/stanza/pubsub/affiliations.rb +79 -0
  33. data/lib/blather/stanza/pubsub/create.rb +65 -0
  34. data/lib/blather/stanza/pubsub/errors.rb +18 -0
  35. data/lib/blather/stanza/pubsub/event.rb +123 -0
  36. data/lib/blather/stanza/pubsub/items.rb +103 -0
  37. data/lib/blather/stanza/pubsub/publish.rb +103 -0
  38. data/lib/blather/stanza/pubsub/retract.rb +92 -0
  39. data/lib/blather/stanza/pubsub/subscribe.rb +68 -0
  40. data/lib/blather/stanza/pubsub/subscription.rb +134 -0
  41. data/lib/blather/stanza/pubsub/subscriptions.rb +81 -0
  42. data/lib/blather/stanza/pubsub/unsubscribe.rb +68 -0
  43. data/lib/blather/stanza/pubsub.rb +129 -0
  44. data/lib/blather/stanza/pubsub_owner/delete.rb +52 -0
  45. data/lib/blather/stanza/pubsub_owner/purge.rb +52 -0
  46. data/lib/blather/stanza/pubsub_owner.rb +51 -0
  47. data/lib/blather/stanza.rb +149 -0
  48. data/lib/blather/stream/client.rb +31 -0
  49. data/lib/blather/stream/component.rb +38 -0
  50. data/lib/blather/stream/features/resource.rb +63 -0
  51. data/lib/blather/stream/features/sasl.rb +187 -0
  52. data/lib/blather/stream/features/session.rb +44 -0
  53. data/lib/blather/stream/features/tls.rb +28 -0
  54. data/lib/blather/stream/features.rb +53 -0
  55. data/lib/blather/stream/parser.rb +102 -0
  56. data/lib/blather/stream.rb +231 -0
  57. data/lib/blather/xmpp_node.rb +218 -0
  58. data/lib/blather.rb +78 -0
  59. data/spec/blather/client/client_spec.rb +559 -0
  60. data/spec/blather/client/dsl/pubsub_spec.rb +462 -0
  61. data/spec/blather/client/dsl_spec.rb +143 -0
  62. data/spec/blather/core_ext/nokogiri_spec.rb +83 -0
  63. data/spec/blather/errors/sasl_error_spec.rb +33 -0
  64. data/spec/blather/errors/stanza_error_spec.rb +129 -0
  65. data/spec/blather/errors/stream_error_spec.rb +108 -0
  66. data/spec/blather/errors_spec.rb +33 -0
  67. data/spec/blather/jid_spec.rb +87 -0
  68. data/spec/blather/roster_item_spec.rb +96 -0
  69. data/spec/blather/roster_spec.rb +103 -0
  70. data/spec/blather/stanza/discos/disco_info_spec.rb +226 -0
  71. data/spec/blather/stanza/discos/disco_items_spec.rb +148 -0
  72. data/spec/blather/stanza/iq/query_spec.rb +64 -0
  73. data/spec/blather/stanza/iq/roster_spec.rb +140 -0
  74. data/spec/blather/stanza/iq_spec.rb +45 -0
  75. data/spec/blather/stanza/message_spec.rb +132 -0
  76. data/spec/blather/stanza/presence/status_spec.rb +132 -0
  77. data/spec/blather/stanza/presence/subscription_spec.rb +105 -0
  78. data/spec/blather/stanza/presence_spec.rb +66 -0
  79. data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
  80. data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
  81. data/spec/blather/stanza/pubsub/event_spec.rb +84 -0
  82. data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
  83. data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
  84. data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
  85. data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
  86. data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
  87. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
  88. data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +61 -0
  89. data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
  90. data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
  91. data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
  92. data/spec/blather/stanza/pubsub_spec.rb +67 -0
  93. data/spec/blather/stanza_spec.rb +116 -0
  94. data/spec/blather/stream/client_spec.rb +1011 -0
  95. data/spec/blather/stream/component_spec.rb +95 -0
  96. data/spec/blather/stream/parser_spec.rb +145 -0
  97. data/spec/blather/xmpp_node_spec.rb +231 -0
  98. data/spec/fixtures/pubsub.rb +311 -0
  99. data/spec/spec_helper.rb +43 -0
  100. metadata +249 -0
@@ -0,0 +1,68 @@
1
+ module Blather
2
+ class Stanza
3
+ class PubSub
4
+
5
+ # # PubSub Unsubscribe Stanza
6
+ #
7
+ # [XEP-0060 Section 6.2 - Unsubscribe from a Node](http://xmpp.org/extensions/xep-0060.html#subscriber-unsubscribe)
8
+ #
9
+ # @handler :pubsub_unsubscribe
10
+ class Unsubscribe < PubSub
11
+ register :pubsub_unsubscribe, :unsubscribe, self.registered_ns
12
+
13
+ # Create a new unsubscribe node
14
+ #
15
+ # @param [Blather::Stanza::Iq::VALID_TYPES] type the IQ stanza type
16
+ # @param [String] host the host to send the request to
17
+ # @param [String] node the node to unsubscribe from
18
+ # @param [Blather::JID, #to_s] jid the JID of the unsubscription
19
+ def self.new(type = :set, host = nil, node = nil, jid = nil)
20
+ new_node = super(type, host)
21
+ new_node.node = node
22
+ new_node.jid = jid
23
+ new_node
24
+ end
25
+
26
+ # Get the JID of the unsubscription
27
+ #
28
+ # @return [Blather::JID]
29
+ def jid
30
+ JID.new(unsubscribe[:jid])
31
+ end
32
+
33
+ # Set the JID of the unsubscription
34
+ #
35
+ # @param [Blather::JID, #to_s] jid
36
+ def jid=(jid)
37
+ unsubscribe[:jid] = jid
38
+ end
39
+
40
+ # Get the name of the node to unsubscribe from
41
+ #
42
+ # @return [String]
43
+ def node
44
+ unsubscribe[:node]
45
+ end
46
+
47
+ # Set the name of the node to unsubscribe from
48
+ #
49
+ # @param [String] node
50
+ def node=(node)
51
+ unsubscribe[:node] = node
52
+ end
53
+
54
+ # Get or create the actual unsubscribe node
55
+ #
56
+ # @return [Blather::XMPPNode]
57
+ def unsubscribe
58
+ unless unsubscribe = pubsub.find_first('ns:unsubscribe', :ns => self.class.registered_ns)
59
+ self.pubsub << (unsubscribe = XMPPNode.new('unsubscribe', self.document))
60
+ unsubscribe.namespace = self.pubsub.namespace
61
+ end
62
+ unsubscribe
63
+ end
64
+ end # Unsubscribe
65
+
66
+ end # PubSub
67
+ end # Stanza
68
+ end # Blather
@@ -0,0 +1,129 @@
1
+ module Blather
2
+ class Stanza
3
+
4
+ # # Pubsub Stanza
5
+ #
6
+ # [XEP-0060 - Publish-Subscribe](http://xmpp.org/extensions/xep-0060.html)
7
+ #
8
+ # The base class for all PubSub nodes. This provides helper methods common to
9
+ # all PubSub nodes.
10
+ #
11
+ # @handler :pubsub_node
12
+ class PubSub < Iq
13
+ register :pubsub_node, :pubsub, 'http://jabber.org/protocol/pubsub'
14
+
15
+ # @private
16
+ def self.import(node)
17
+ klass = nil
18
+ if pubsub = node.document.find_first('//ns:pubsub', :ns => self.registered_ns)
19
+ pubsub.children.detect do |e|
20
+ ns = e.namespace ? e.namespace.href : nil
21
+ klass = class_from_registration(e.element_name, ns)
22
+ end
23
+ end
24
+ (klass || self).new(node[:type]).inherit(node)
25
+ end
26
+
27
+ # Overwrites the parent constructor to ensure a pubsub node is present.
28
+ # Also allows the addition of a host attribute
29
+ #
30
+ # @param [<Blather::Stanza::Iq::VALID_TYPES>] type the IQ type
31
+ # @param [String, nil] host the host the node should be sent to
32
+ def self.new(type = nil, host = nil)
33
+ new_node = super type
34
+ new_node.to = host
35
+ new_node.pubsub
36
+ new_node
37
+ end
38
+
39
+ # Overrides the parent to ensure the current pubsub node is destroyed before
40
+ # inheritting the new content
41
+ #
42
+ # @private
43
+ def inherit(node)
44
+ remove_children :pubsub
45
+ super
46
+ end
47
+
48
+ # Get or create the pubsub node on the stanza
49
+ #
50
+ # @return [Blather::XMPPNode]
51
+ def pubsub
52
+ p = find_first('ns:pubsub', :ns => self.class.registered_ns) ||
53
+ find_first('pubsub', :ns => self.class.registered_ns)
54
+
55
+ unless p
56
+ self << (p = XMPPNode.new('pubsub', self.document))
57
+ p.namespace = self.class.registered_ns
58
+ end
59
+ p
60
+ end
61
+ end # PubSub
62
+
63
+ # # PubSubItem Fragment
64
+ #
65
+ # This fragment is found in many places throughout the pubsub spec
66
+ # This is a convenience class to attach methods to the node
67
+ class PubSubItem < XMPPNode
68
+ ATOM_NS = 'http://www.w3.org/2005/Atom'.freeze
69
+
70
+ # Create a new PubSubItem
71
+ #
72
+ # @param [String, nil] id the id of the stanza
73
+ # @param [#to_s, nil] payload the payload to attach to this item.
74
+ # @param [XML::Document, nil] document the document the node should be
75
+ # attached to. This should be the document of the parent PubSub node.
76
+ def self.new(id = nil, payload = nil, document = nil)
77
+ new_node = super 'item', document
78
+ new_node.id = id
79
+ new_node.payload = payload if payload
80
+ new_node
81
+ end
82
+
83
+ # Get the item's ID
84
+ #
85
+ # @return [String, nil]
86
+ def id
87
+ read_attr :id
88
+ end
89
+
90
+ # Set the item's ID
91
+ #
92
+ # @param [#to_s] id the new ID
93
+ def id=(id)
94
+ write_attr :id, id
95
+ end
96
+
97
+ # Get the item's payload
98
+ #
99
+ # To get the XML representation use #entry
100
+ #
101
+ # @return [String, nil]
102
+ def payload
103
+ self.entry.content.empty? ? nil : content
104
+ end
105
+
106
+ # Set the item's payload
107
+ #
108
+ # @param [String, nil] payload the payload
109
+ def payload=(payload)
110
+ self.entry.content = payload
111
+ end
112
+
113
+ # Get or create the entry node
114
+ #
115
+ # @return [Blather::XMPPNode]
116
+ def entry
117
+ e = find_first('ns:entry', :ns => ATOM_NS) ||
118
+ find_first('entry', :ns => ATOM_NS)
119
+
120
+ unless e
121
+ self << (e = XMPPNode.new('entry', self.document))
122
+ e.namespace = ATOM_NS
123
+ end
124
+ e
125
+ end
126
+ end # PubSubItem
127
+
128
+ end # Stanza
129
+ end # Blather
@@ -0,0 +1,52 @@
1
+ module Blather
2
+ class Stanza
3
+ class PubSubOwner
4
+
5
+ # # PubSubOwner Delete Stanza
6
+ #
7
+ # [XEP-0060 Section 8.4 Delete a Node](http://xmpp.org/extensions/xep-0060.html#owner-delete)
8
+ #
9
+ # @handler :pubsub_delete
10
+ class Delete < PubSubOwner
11
+ register :pubsub_delete, :delete, self.registered_ns
12
+
13
+ # Create a new delete stanza
14
+ #
15
+ # @param [Blather::Stanza::Iq::VALID_TYPES] type the IQ stanza type
16
+ # @param [String] host the host to send the request to
17
+ # @param [String] node the name of the node to delete
18
+ def self.new(type = :set, host = nil, node = nil)
19
+ new_node = super(type, host)
20
+ new_node.node = node
21
+ new_node
22
+ end
23
+
24
+ # Get the name of the node to delete
25
+ #
26
+ # @return [String]
27
+ def node
28
+ delete_node[:node]
29
+ end
30
+
31
+ # Set the name of the node to delete
32
+ #
33
+ # @param [String] node
34
+ def node=(node)
35
+ delete_node[:node] = node
36
+ end
37
+
38
+ # Get or create the actual delete node on the stanza
39
+ #
40
+ # @return [Blather::XMPPNode]
41
+ def delete_node
42
+ unless delete_node = pubsub.find_first('ns:delete', :ns => self.class.registered_ns)
43
+ self.pubsub << (delete_node = XMPPNode.new('delete', self.document))
44
+ delete_node.namespace = self.pubsub.namespace
45
+ end
46
+ delete_node
47
+ end
48
+ end # Retract
49
+
50
+ end # PubSub
51
+ end # Stanza
52
+ end # Blather
@@ -0,0 +1,52 @@
1
+ module Blather
2
+ class Stanza
3
+ class PubSubOwner
4
+
5
+ # # PubSubOwner Purge Stanza
6
+ #
7
+ # [XEP-0060 Section 8.5 - Purge All Node Items](http://xmpp.org/extensions/xep-0060.html#owner-purge)
8
+ #
9
+ # @handler :pubsub_purge
10
+ class Purge < PubSubOwner
11
+ register :pubsub_purge, :purge, self.registered_ns
12
+
13
+ # Create a new purge stanza
14
+ #
15
+ # @param [Blather::Stanza::Iq::VALID_TYPES] type the IQ stanza type
16
+ # @param [String] host the host to send the request to
17
+ # @param [String] node the name of the node to purge
18
+ def self.new(type = :set, host = nil, node = nil)
19
+ new_node = super(type, host)
20
+ new_node.node = node
21
+ new_node
22
+ end
23
+
24
+ # Get the name of the node to delete
25
+ #
26
+ # @return [String]
27
+ def node
28
+ purge_node[:node]
29
+ end
30
+
31
+ # Set the name of the node to delete
32
+ #
33
+ # @param [String] node
34
+ def node=(node)
35
+ purge_node[:node] = node
36
+ end
37
+
38
+ # Get or create the actual purge node on the stanza
39
+ #
40
+ # @return [Blather::XMPPNode]
41
+ def purge_node
42
+ unless purge_node = pubsub.find_first('ns:purge', :ns => self.class.registered_ns)
43
+ self.pubsub << (purge_node = XMPPNode.new('purge', self.document))
44
+ purge_node.namespace = self.pubsub.namespace
45
+ end
46
+ purge_node
47
+ end
48
+ end # Retract
49
+
50
+ end # PubSub
51
+ end # Stanza
52
+ end # Blather
@@ -0,0 +1,51 @@
1
+ module Blather
2
+ class Stanza
3
+
4
+ # # PubSubOwner Base Class
5
+ #
6
+ # [XEP-0060 - Publish-Subscribe](http://xmpp.org/extensions/xep-0060.html)
7
+ #
8
+ # @handler :pubsub_owner
9
+ class PubSubOwner < Iq
10
+ register :pubsub_owner, :pubsub, 'http://jabber.org/protocol/pubsub#owner'
11
+
12
+ # Creates the proper class from the stana's child
13
+ # @private
14
+ def self.import(node)
15
+ klass = nil
16
+ if pubsub = node.document.find_first('//ns:pubsub', :ns => self.registered_ns)
17
+ pubsub.children.each { |e| break if klass = class_from_registration(e.element_name, (e.namespace.href if e.namespace)) }
18
+ end
19
+ (klass || self).new(node[:type]).inherit(node)
20
+ end
21
+
22
+ # Overrides the parent to ensure a pubsub node is created
23
+ # @private
24
+ def self.new(type = nil, host = nil)
25
+ new_node = super type
26
+ new_node.to = host
27
+ new_node.pubsub
28
+ new_node
29
+ end
30
+
31
+ # Overrides the parent to ensure the pubsub node is destroyed
32
+ # @private
33
+ def inherit(node)
34
+ remove_children :pubsub
35
+ super
36
+ end
37
+
38
+ # Get or create the pubsub node on the stanza
39
+ #
40
+ # @return [Blather::XMPPNode]
41
+ def pubsub
42
+ unless p = find_first('ns:pubsub', :ns => self.class.registered_ns)
43
+ self << (p = XMPPNode.new('pubsub', self.document))
44
+ p.namespace = self.class.registered_ns
45
+ end
46
+ p
47
+ end
48
+ end # PubSubOwner
49
+
50
+ end # Stanza
51
+ end # Blather
@@ -0,0 +1,149 @@
1
+ module Blather
2
+
3
+ # # Base XMPP Stanza
4
+ #
5
+ # All stanzas inherit this class. It provides a set of methods and helpers
6
+ # common to all XMPP Stanzas
7
+ #
8
+ # @handler :stanza
9
+ class Stanza < XMPPNode
10
+ # @private
11
+ @@last_id = 0
12
+ # @private
13
+ @@handler_list = []
14
+
15
+ class_inheritable_array :handler_hierarchy
16
+
17
+ # Registers a callback onto the callback stack
18
+ #
19
+ # @param [Symbol] handler the name of the handler
20
+ # @param [Symbol, String, nil] name the name of the first element in the
21
+ # stanza. If nil the inherited name will be used. If that's nil the
22
+ # handler name will be used.
23
+ # @param [String, nil] ns the namespace of the stanza
24
+ def self.register(handler, name = nil, ns = nil)
25
+ @@handler_list << handler
26
+ self.handler_hierarchy ||= [:stanza]
27
+ self.handler_hierarchy.unshift handler
28
+
29
+ name = name || self.registered_name || handler
30
+ super name, ns
31
+ end
32
+
33
+ # The handler stack for the current stanza class
34
+ #
35
+ # @return [Array<Symbol>]
36
+ def self.handler_list
37
+ @@handler_list
38
+ end
39
+
40
+ # Helper method that creates a unique ID for stanzas
41
+ #
42
+ # @return [String] a new unique ID
43
+ def self.next_id
44
+ @@last_id += 1
45
+ 'blather%04x' % @@last_id
46
+ end
47
+
48
+ # Check if the stanza is an error stanza
49
+ #
50
+ # @return [true, false]
51
+ def error?
52
+ self.type == :error
53
+ end
54
+
55
+ # Creates a copy with to and from swapped
56
+ #
57
+ # @return [Blather::Stanza]
58
+ def reply
59
+ self.dup.reply!
60
+ end
61
+
62
+ # Swaps from and to
63
+ #
64
+ # @return [self]
65
+ def reply!
66
+ self.to, self.from = self.from, self.to
67
+ self
68
+ end
69
+
70
+ # Get the stanza's ID
71
+ #
72
+ # @return [String, nil]
73
+ def id
74
+ read_attr :id
75
+ end
76
+
77
+ # Set the stanza's ID
78
+ #
79
+ # @param [#to_s] id the new stanza ID
80
+ def id=(id)
81
+ write_attr :id, id
82
+ end
83
+
84
+ # Get the stanza's to
85
+ #
86
+ # @return [Blather::JID, nil]
87
+ def to
88
+ JID.new(self[:to]) if self[:to]
89
+ end
90
+
91
+ # Set the stanza's to field
92
+ #
93
+ # @param [#to_s] to the new JID for the to field
94
+ def to=(to)
95
+ write_attr :to, to
96
+ end
97
+
98
+ # Get the stanza's from
99
+ #
100
+ # @return [Blather::JID, nil]
101
+ def from
102
+ JID.new(self[:from]) if self[:from]
103
+ end
104
+
105
+ # Set the stanza's from field
106
+ #
107
+ # @param [#to_s] from the new JID for the from field
108
+ def from=(from)
109
+ write_attr :from, from
110
+ end
111
+
112
+ # Get the stanza's type
113
+ #
114
+ # @return [Symbol, nil]
115
+ def type
116
+ read_attr :type, :to_sym
117
+ end
118
+
119
+ # Set the stanza's type
120
+ #
121
+ # @param [#to_s] type the new stanza type
122
+ def type=(type)
123
+ write_attr :type, type
124
+ end
125
+
126
+ # Create an error stanza from the current stanza
127
+ #
128
+ # @param [String] name the error name
129
+ # @param [<Blather::StanzaError::VALID_TYPES>] type the error type
130
+ # @param [String, nil] text the error text
131
+ # @param [Array<XML::Node>] extras an array of extra nodes to attach to
132
+ # the error
133
+ #
134
+ # @return [Blather::StanzaError]
135
+ def as_error(name, type, text = nil, extras = [])
136
+ StanzaError.new self, name, type, text, extras
137
+ end
138
+
139
+ protected
140
+ # @private
141
+ def reply_if_needed!
142
+ unless @reversed_endpoints
143
+ reply!
144
+ @reversed_endpoints = true
145
+ end
146
+ self
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,31 @@
1
+ module Blather
2
+ class Stream
3
+
4
+ class Client < Stream
5
+ LANG = 'en'
6
+ VERSION = '1.0'
7
+ NAMESPACE = 'jabber:client'
8
+
9
+ def start
10
+ @parser = Parser.new self
11
+ start_stream = <<-STREAM
12
+ <stream:stream
13
+ to='#{@to}'
14
+ xmlns='#{NAMESPACE}'
15
+ xmlns:stream='#{STREAM_NS}'
16
+ version='#{VERSION}'
17
+ xml:lang='#{LANG}'
18
+ >
19
+ STREAM
20
+ send start_stream.gsub(/\s+/, ' ')
21
+ end
22
+
23
+ def send(stanza)
24
+ stanza.from = self.jid if stanza.is_a?(Stanza) && !stanza.from.nil?
25
+ super stanza
26
+ end
27
+
28
+ end #Client
29
+
30
+ end #Stream
31
+ end #Blather
@@ -0,0 +1,38 @@
1
+ module Blather
2
+ class Stream
3
+
4
+ class Component < Stream
5
+ NAMESPACE = 'jabber:component:accept'
6
+
7
+ def receive(node) # :nodoc:
8
+ if node.element_name == 'handshake'
9
+ ready!
10
+ else
11
+ super
12
+ end
13
+
14
+ if node.document.find_first('/stream:stream[not(stream:error)]', :xmlns => NAMESPACE, :stream => STREAM_NS)
15
+ send("<handshake>#{Digest::SHA1.hexdigest(@node['id']+@password)}</handshake>")
16
+ end
17
+ end
18
+
19
+ def send(stanza)
20
+ stanza.from ||= self.jid if stanza.respond_to?(:from) && stanza.respond_to?(:from=)
21
+ super stanza
22
+ end
23
+
24
+ def start
25
+ @parser = Parser.new self
26
+ start_stream = <<-STREAM
27
+ <stream:stream
28
+ to='#{@jid}'
29
+ xmlns='#{NAMESPACE}'
30
+ xmlns:stream='#{STREAM_NS}'
31
+ >
32
+ STREAM
33
+ send start_stream.gsub(/\s+/, ' ')
34
+ end
35
+ end #Client
36
+
37
+ end #Stream
38
+ end #Blather
@@ -0,0 +1,63 @@
1
+ module Blather # :nodoc:
2
+ class Stream # :nodoc:
3
+
4
+ class Resource < Features # :nodoc:
5
+ BIND_NS = 'urn:ietf:params:xml:ns:xmpp-bind'.freeze
6
+ register BIND_NS
7
+
8
+ def initialize(stream, succeed, fail)
9
+ super
10
+ @jid = stream.jid
11
+ end
12
+
13
+ def receive_data(stanza)
14
+ @node = stanza
15
+ case stanza.element_name
16
+ when 'bind' then bind
17
+ when 'iq' then result
18
+ else fail!(UnknownResponse.new(@node))
19
+ end
20
+ end
21
+
22
+ private
23
+ ##
24
+ # Respond to the bind request
25
+ # If @jid has a resource set already request it from the server
26
+ def bind
27
+ response = Stanza::Iq.new :set
28
+ @id = response.id
29
+
30
+ response << (binder = XMPPNode.new('bind', response.document))
31
+ binder.namespace = BIND_NS
32
+
33
+ if @jid.resource
34
+ binder << (resource = XMPPNode.new('resource', binder.document))
35
+ resource.content = @jid.resource
36
+ end
37
+
38
+ @stream.send response
39
+ end
40
+
41
+ ##
42
+ # Process the result from the server
43
+ # Sets the sends the JID (now bound to a resource)
44
+ # back to the stream
45
+ def result
46
+ if @node[:type] == 'error'
47
+ fail! StanzaError.import(@node)
48
+ return
49
+ end
50
+
51
+ Blather.logger.debug "RESOURCE NODE #{@node}"
52
+ # ensure this is a response to our original request
53
+ if @id == @node['id']
54
+ @stream.jid = JID.new @node.find_first('bind_ns:bind/bind_ns:jid', :bind_ns => BIND_NS).content
55
+ succeed!
56
+ else
57
+ fail!("BIND result ID mismatch. Expected: #{@id}. Received: #{@node['id']}")
58
+ end
59
+ end
60
+ end #Resource
61
+
62
+ end #Stream
63
+ end #Blather