sprsquish-blather 0.1 → 0.2.3
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/LICENSE +2 -0
- data/README.rdoc +100 -0
- data/Rakefile +110 -0
- data/examples/drb_client.rb +5 -0
- data/examples/echo.rb +18 -0
- data/ext/extconf.rb +65 -0
- data/ext/push_parser.c +231 -0
- data/lib/blather/client.rb +219 -44
- data/lib/blather/{core/sugar.rb → core_ext/active_support.rb} +25 -13
- data/lib/blather/core_ext/libxml.rb +28 -0
- data/lib/blather/errors/sasl_error.rb +87 -0
- data/lib/blather/errors/stanza_error.rb +262 -0
- data/lib/blather/errors/stream_error.rb +253 -0
- data/lib/blather/errors.rb +48 -0
- data/lib/blather/{core/jid.rb → jid.rb} +15 -26
- data/lib/blather/{core/roster.rb → roster.rb} +22 -0
- data/lib/blather/{core/roster_item.rb → roster_item.rb} +39 -8
- data/lib/blather/stanza/iq/disco.rb +11 -0
- data/lib/blather/stanza/iq/discos/disco_info.rb +86 -0
- data/lib/blather/stanza/iq/discos/disco_items.rb +61 -0
- data/lib/blather/stanza/iq/query.rb +51 -0
- data/lib/blather/stanza/iq/roster.rb +90 -0
- data/lib/blather/stanza/iq.rb +38 -0
- data/lib/blather/stanza/message.rb +58 -0
- data/lib/blather/stanza/presence/status.rb +78 -0
- data/lib/blather/stanza/presence/subscription.rb +72 -0
- data/lib/blather/stanza/presence.rb +45 -0
- data/lib/blather/stanza.rb +101 -0
- data/lib/blather/stream/client.rb +26 -0
- data/lib/blather/stream/component.rb +34 -0
- data/lib/blather/stream/parser.rb +70 -0
- data/lib/blather/stream/resource.rb +48 -0
- data/lib/blather/stream/sasl.rb +173 -0
- data/lib/blather/stream/session.rb +36 -0
- data/lib/blather/stream/stream_handler.rb +39 -0
- data/lib/blather/stream/tls.rb +33 -0
- data/lib/blather/stream.rb +249 -0
- data/lib/blather/xmpp_node.rb +199 -0
- data/lib/blather.rb +40 -41
- data/spec/blather/core_ext/libxml_spec.rb +58 -0
- data/spec/blather/errors/sasl_error_spec.rb +56 -0
- data/spec/blather/errors/stanza_error_spec.rb +148 -0
- data/spec/blather/errors/stream_error_spec.rb +114 -0
- data/spec/blather/errors_spec.rb +40 -0
- data/spec/blather/{core/jid_spec.rb → jid_spec.rb} +9 -1
- data/spec/blather/{core/roster_item_spec.rb → roster_item_spec.rb} +6 -1
- data/spec/blather/{core/roster_spec.rb → roster_spec.rb} +16 -6
- data/spec/blather/stanza/iq/discos/disco_info_spec.rb +207 -0
- data/spec/blather/stanza/iq/discos/disco_items_spec.rb +136 -0
- data/spec/blather/stanza/iq/query_spec.rb +34 -0
- data/spec/blather/stanza/iq/roster_spec.rb +123 -0
- data/spec/blather/stanza/iq_spec.rb +40 -0
- data/spec/blather/stanza/message_spec.rb +52 -0
- data/spec/blather/stanza/presence/status_spec.rb +102 -0
- data/spec/blather/stanza/presence/subscription_spec.rb +85 -0
- data/spec/blather/stanza/presence_spec.rb +53 -0
- data/spec/blather/{core/stanza_spec.rb → stanza_spec.rb} +14 -2
- data/spec/blather/stream/client_spec.rb +787 -0
- data/spec/blather/stream/component_spec.rb +86 -0
- data/spec/blather/{core/xmpp_node_spec.rb → xmpp_node_spec.rb} +76 -23
- data/spec/build_safe.rb +20 -0
- data/spec/spec_helper.rb +7 -17
- metadata +79 -59
- data/CHANGELOG +0 -1
- data/blather.gemspec +0 -73
- data/lib/blather/callback.rb +0 -24
- data/lib/blather/core/errors.rb +0 -24
- data/lib/blather/core/stanza.rb +0 -90
- data/lib/blather/core/stream.rb +0 -179
- data/lib/blather/core/xmpp_node.rb +0 -95
- data/lib/blather/extensions/last_activity.rb +0 -57
- data/lib/blather/extensions/version.rb +0 -85
- data/spec/blather/core/stream_spec.rb +0 -263
data/lib/blather/core/stanza.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
module Blather
|
2
|
-
class Stanza < XMPPNode
|
3
|
-
@@registered_callbacks = []
|
4
|
-
|
5
|
-
def self.registered_callbacks
|
6
|
-
@@registered_callbacks
|
7
|
-
end
|
8
|
-
|
9
|
-
class_inheritable_array :callback_heirarchy
|
10
|
-
|
11
|
-
def self.register(callback_type, name = nil, xmlns = nil)
|
12
|
-
@@registered_callbacks << callback_type
|
13
|
-
|
14
|
-
self.callback_heirarchy ||= []
|
15
|
-
self.callback_heirarchy.unshift callback_type
|
16
|
-
|
17
|
-
name = name || self.name || callback_type
|
18
|
-
super name, xmlns
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.next_id
|
22
|
-
@@last_id ||= 0
|
23
|
-
@@last_id += 1
|
24
|
-
'blather%04x' % @@last_id
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.import(node)
|
28
|
-
self.new(node.element_name).inherit(node)
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.new(elem_name = nil)
|
32
|
-
elem = super
|
33
|
-
elem.id = next_id
|
34
|
-
XML::Document.new.root = elem
|
35
|
-
elem
|
36
|
-
end
|
37
|
-
|
38
|
-
def error?
|
39
|
-
self.type == :error
|
40
|
-
end
|
41
|
-
|
42
|
-
def reply
|
43
|
-
elem = self.copy(true)
|
44
|
-
elem.to, elem.from = self.from, self.to
|
45
|
-
elem
|
46
|
-
end
|
47
|
-
|
48
|
-
def reply!
|
49
|
-
self.to, self.from = self.from, self.to
|
50
|
-
self
|
51
|
-
end
|
52
|
-
|
53
|
-
def id=(id)
|
54
|
-
attributes.remove :id
|
55
|
-
self['id'] = id if id
|
56
|
-
end
|
57
|
-
|
58
|
-
def id
|
59
|
-
self['id']
|
60
|
-
end
|
61
|
-
|
62
|
-
def to=(to)
|
63
|
-
attributes.remove :to
|
64
|
-
self['to'] = to.to_s if to
|
65
|
-
end
|
66
|
-
|
67
|
-
def to
|
68
|
-
JID.new(self['to']) if self['to']
|
69
|
-
end
|
70
|
-
|
71
|
-
def from=(from)
|
72
|
-
attributes.remove :from
|
73
|
-
self['from'] = from.to_s if from
|
74
|
-
end
|
75
|
-
|
76
|
-
def from
|
77
|
-
JID.new(self['from']) if self['from']
|
78
|
-
end
|
79
|
-
|
80
|
-
def type=(type)
|
81
|
-
attributes.remove :type
|
82
|
-
self['type'] = type.to_s
|
83
|
-
end
|
84
|
-
|
85
|
-
def type
|
86
|
-
self['type'].to_sym if self['type']
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
end
|
data/lib/blather/core/stream.rb
DELETED
@@ -1,179 +0,0 @@
|
|
1
|
-
module Blather
|
2
|
-
|
3
|
-
module Stream
|
4
|
-
|
5
|
-
# Connect to the server
|
6
|
-
def self.start(client, jid, pass, host = nil, port = 5222)
|
7
|
-
jid = JID.new jid
|
8
|
-
host ||= jid.domain
|
9
|
-
|
10
|
-
EM.connect host, port, self, client, jid, pass
|
11
|
-
end
|
12
|
-
|
13
|
-
def initialize(client, jid, pass)
|
14
|
-
super()
|
15
|
-
|
16
|
-
@client = client
|
17
|
-
|
18
|
-
self.jid = jid
|
19
|
-
@pass = pass
|
20
|
-
|
21
|
-
@to = @jid.domain
|
22
|
-
@id = nil
|
23
|
-
@lang = 'en'
|
24
|
-
@version = '1.0'
|
25
|
-
@namespace = 'jabber:client'
|
26
|
-
|
27
|
-
@parser = Parser.new self
|
28
|
-
end
|
29
|
-
|
30
|
-
def connection_completed
|
31
|
-
# @keepalive = EM::Timer.new(60) { send_data ' ' }
|
32
|
-
@state = :stopped
|
33
|
-
dispatch
|
34
|
-
end
|
35
|
-
|
36
|
-
def receive_data(data)
|
37
|
-
@parser.parse data
|
38
|
-
|
39
|
-
rescue => e
|
40
|
-
@client.respond_to?(:rescue) ? @client.rescue(e) : raise(e)
|
41
|
-
end
|
42
|
-
|
43
|
-
def unbind
|
44
|
-
# @keepalive.cancel
|
45
|
-
@state == :stopped
|
46
|
-
end
|
47
|
-
|
48
|
-
def receive(node)
|
49
|
-
LOG.debug "\n"+('-'*30)+"\n"
|
50
|
-
LOG.debug "RECEIVING (#{node.element_name}) #{node}"
|
51
|
-
@node = node
|
52
|
-
|
53
|
-
case @node.element_name
|
54
|
-
when 'stream:stream'
|
55
|
-
@state = :ready if @state == :stopped
|
56
|
-
|
57
|
-
when 'stream:end'
|
58
|
-
@state = :stopped
|
59
|
-
|
60
|
-
when 'stream:features'
|
61
|
-
@features = @node.children
|
62
|
-
@state = :features
|
63
|
-
dispatch
|
64
|
-
|
65
|
-
when 'stream:error'
|
66
|
-
raise StreamError.new(@node)
|
67
|
-
|
68
|
-
else
|
69
|
-
dispatch
|
70
|
-
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def send(stanza)
|
75
|
-
#TODO Queue if not ready
|
76
|
-
LOG.debug "SENDING: (#{caller[1]}) #{stanza}"
|
77
|
-
send_data stanza.to_s
|
78
|
-
end
|
79
|
-
|
80
|
-
def stopped?
|
81
|
-
@state == :stopped
|
82
|
-
end
|
83
|
-
|
84
|
-
def ready?
|
85
|
-
@state == :ready
|
86
|
-
end
|
87
|
-
|
88
|
-
def jid=(new_jid)
|
89
|
-
LOG.debug "NEW JID: #{new_jid}"
|
90
|
-
new_jid = JID.new new_jid
|
91
|
-
@client.jid = new_jid
|
92
|
-
@jid = new_jid
|
93
|
-
end
|
94
|
-
|
95
|
-
private
|
96
|
-
def dispatch
|
97
|
-
__send__ @state
|
98
|
-
end
|
99
|
-
|
100
|
-
def start
|
101
|
-
send <<-STREAM
|
102
|
-
<stream:stream
|
103
|
-
to='#{@to}'
|
104
|
-
xmlns='#{@namespace}'
|
105
|
-
xmlns:stream='http://etherx.jabber.org/streams'
|
106
|
-
version='#{@version}'
|
107
|
-
xml:lang='#{@lang}'
|
108
|
-
>
|
109
|
-
STREAM
|
110
|
-
end
|
111
|
-
|
112
|
-
def stop
|
113
|
-
send '</stream:stream>'
|
114
|
-
end
|
115
|
-
|
116
|
-
def stopped
|
117
|
-
start
|
118
|
-
end
|
119
|
-
|
120
|
-
def ready
|
121
|
-
@client.call @node.to_stanza
|
122
|
-
end
|
123
|
-
|
124
|
-
def features
|
125
|
-
feature = @features.first
|
126
|
-
LOG.debug "FEATURE: #{feature}"
|
127
|
-
@state = case feature ? feature['xmlns'] : nil
|
128
|
-
when 'urn:ietf:params:xml:ns:xmpp-tls' then :establish_tls
|
129
|
-
when 'urn:ietf:params:xml:ns:xmpp-sasl' then :authenticate_sasl
|
130
|
-
when 'urn:ietf:params:xml:ns:xmpp-bind' then :bind_resource
|
131
|
-
when 'urn:ietf:params:xml:ns:xmpp-session' then :establish_session
|
132
|
-
else :ready
|
133
|
-
end
|
134
|
-
|
135
|
-
dispatch unless ready?
|
136
|
-
end
|
137
|
-
|
138
|
-
def establish_tls
|
139
|
-
unless @tls
|
140
|
-
@tls = TLS.new self
|
141
|
-
@tls.success { LOG.debug "TLS: SUCCESS"; @tls = nil; start }
|
142
|
-
@tls.failure { LOG.debug "TLS: FAILURE"; stop }
|
143
|
-
@node = @features.shift
|
144
|
-
end
|
145
|
-
@tls.receive @node
|
146
|
-
end
|
147
|
-
|
148
|
-
def authenticate_sasl
|
149
|
-
unless @sasl
|
150
|
-
@sasl = SASL.new(self, @jid, @pass)
|
151
|
-
@sasl.success { LOG.debug "SASL SUCCESS"; @sasl = nil; start }
|
152
|
-
@sasl.failure { LOG.debug "SASL FAIL"; stop }
|
153
|
-
@node = @features.shift
|
154
|
-
end
|
155
|
-
@sasl.receive @node
|
156
|
-
end
|
157
|
-
|
158
|
-
def bind_resource
|
159
|
-
unless @resource
|
160
|
-
@resource = Resource.new self, @jid
|
161
|
-
@resource.success { |jid| LOG.debug "RESOURCE: SUCCESS"; @resource = nil; self.jid = jid; @state = :features; dispatch }
|
162
|
-
@resource.failure { LOG.debug "RESOURCE: FAILURE"; stop }
|
163
|
-
@node = @features.shift
|
164
|
-
end
|
165
|
-
@resource.receive @node
|
166
|
-
end
|
167
|
-
|
168
|
-
def establish_session
|
169
|
-
unless @session
|
170
|
-
@session = Session.new self, @to
|
171
|
-
@session.success { LOG.debug "SESSION: SUCCESS"; @session = nil; @client.stream_started(self); @state = :features; dispatch }
|
172
|
-
@session.failure { LOG.debug "SESSION: FAILURE"; stop }
|
173
|
-
@node = @features.shift
|
174
|
-
end
|
175
|
-
@session.receive @node
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
end
|
@@ -1,95 +0,0 @@
|
|
1
|
-
module Blather
|
2
|
-
|
3
|
-
class XMPPNode < XML::Node
|
4
|
-
@@registrations = {}
|
5
|
-
|
6
|
-
alias_method :element_name, :name
|
7
|
-
|
8
|
-
class_inheritable_accessor :xmlns,
|
9
|
-
:name
|
10
|
-
|
11
|
-
def self.new(name = nil, content = nil)
|
12
|
-
name ||= self.name
|
13
|
-
|
14
|
-
args = []
|
15
|
-
args << name.to_s if name
|
16
|
-
args << content if content
|
17
|
-
|
18
|
-
elem = super *args
|
19
|
-
elem.xmlns = xmlns
|
20
|
-
elem
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.register(name, xmlns = nil)
|
24
|
-
self.name = name.to_s
|
25
|
-
self.xmlns = xmlns
|
26
|
-
@@registrations[[name, xmlns]] = self
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.class_from_registration(name, xmlns)
|
30
|
-
name = name.to_s
|
31
|
-
@@registrations[[name, xmlns]] || @@registrations[[name, nil]]
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.import(node)
|
35
|
-
klass = class_from_registration(node.element_name, node.xmlns)
|
36
|
-
if klass && klass != self
|
37
|
-
klass.import(node)
|
38
|
-
else
|
39
|
-
new(node.element_name).inherit(node)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def to_stanza
|
44
|
-
self.class.import self
|
45
|
-
end
|
46
|
-
|
47
|
-
def xmlns=(ns)
|
48
|
-
attributes.remove :xmlns
|
49
|
-
self['xmlns'] = ns if ns
|
50
|
-
end
|
51
|
-
|
52
|
-
def xmlns
|
53
|
-
self['xmlns']
|
54
|
-
end
|
55
|
-
|
56
|
-
def remove_child(name, ns = nil)
|
57
|
-
name = name.to_s
|
58
|
-
self.each { |n| n.remove! if n.element_name == name && (!ns || n.xmlns == ns) }
|
59
|
-
end
|
60
|
-
|
61
|
-
def remove_children(name)
|
62
|
-
name = name.to_s
|
63
|
-
self.find(name).each { |n| n.remove! }
|
64
|
-
end
|
65
|
-
|
66
|
-
def content_from(name)
|
67
|
-
name = name.to_s
|
68
|
-
(child = self.detect { |n| n.element_name == name }) ? child.content : nil
|
69
|
-
end
|
70
|
-
|
71
|
-
def copy(deep = true)
|
72
|
-
self.class.new(self.element_name).inherit(self)
|
73
|
-
end
|
74
|
-
|
75
|
-
def inherit(stanza)
|
76
|
-
inherit_attrs stanza.attributes
|
77
|
-
stanza.children.each { |c| self << c.copy(true) }
|
78
|
-
self
|
79
|
-
end
|
80
|
-
|
81
|
-
def inherit_attrs(attrs)
|
82
|
-
attrs.each { |a| self[a.name] = a.value }
|
83
|
-
self
|
84
|
-
end
|
85
|
-
|
86
|
-
def to_s
|
87
|
-
super.gsub(">\n<", '><')
|
88
|
-
end
|
89
|
-
|
90
|
-
def find(what, nslist = nil)
|
91
|
-
(self.doc ? super(what, nslist) : select { |i| i.element_name == what})
|
92
|
-
end
|
93
|
-
end #XMPPNode
|
94
|
-
|
95
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
module Blather
|
2
|
-
module Extensions
|
3
|
-
|
4
|
-
module LastActivity
|
5
|
-
def self.included(base)
|
6
|
-
base.class_eval do
|
7
|
-
@@last_activity = Time.now
|
8
|
-
|
9
|
-
alias_method :send_data_without_activity, :send_data
|
10
|
-
def send_data(data)
|
11
|
-
@@last_activity = Time.now
|
12
|
-
send_data_without_activity data
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def last_activity
|
18
|
-
(Time.now - @@last_activity).to_i
|
19
|
-
end
|
20
|
-
|
21
|
-
def receive_last_activity(stanza)
|
22
|
-
send_data stanza.reply!(last_activity) if stanza.type == 'get'
|
23
|
-
end
|
24
|
-
end #LastActivity
|
25
|
-
|
26
|
-
class LastActivityStanza < Query
|
27
|
-
register :last_activity, nil, 'jabber:iq:last'
|
28
|
-
|
29
|
-
def self.new(type = :get, seconds = nil)
|
30
|
-
elem = super type
|
31
|
-
elem.seconds = seconds
|
32
|
-
elem
|
33
|
-
end
|
34
|
-
|
35
|
-
def seconds=(seconds)
|
36
|
-
query.attributes.remove :seconds
|
37
|
-
query['seconds'] = seconds.to_i.to_s if seconds
|
38
|
-
end
|
39
|
-
|
40
|
-
def seconds
|
41
|
-
(query['seconds'] || 0).to_i
|
42
|
-
end
|
43
|
-
|
44
|
-
def reply(seconds)
|
45
|
-
elem = super()
|
46
|
-
elem.last_activity = seconds
|
47
|
-
end
|
48
|
-
|
49
|
-
def reply!(seconds)
|
50
|
-
self.last_activity = seconds
|
51
|
-
super()
|
52
|
-
end
|
53
|
-
end #LastActivityStanza
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
Blather::Client.__send__ :include, Blather::Extensions::LastActivity
|
@@ -1,85 +0,0 @@
|
|
1
|
-
module Blather
|
2
|
-
module Extensions
|
3
|
-
|
4
|
-
module Version
|
5
|
-
def self.included(base)
|
6
|
-
base.class_eval do
|
7
|
-
@@version = {}
|
8
|
-
|
9
|
-
def self.version(name, ver, os = nil)
|
10
|
-
@@version = {:name => name, :version => ver, :os => os}
|
11
|
-
end
|
12
|
-
|
13
|
-
add_callback(:iq, 100) do |c, s|
|
14
|
-
if s.detect { |n| n['xmlns'] == 'jabber:iq:version' }
|
15
|
-
ver = VersionStanza.new('result', c.version)
|
16
|
-
ver.id = s.id
|
17
|
-
ver.from = c.jid
|
18
|
-
ver.to = s.from
|
19
|
-
c.send_data ver
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def version
|
26
|
-
@@version
|
27
|
-
end
|
28
|
-
end #Version
|
29
|
-
|
30
|
-
class VersionStanza < Iq
|
31
|
-
def self.new(type = 'result', ver = {})
|
32
|
-
elem = super(type)
|
33
|
-
|
34
|
-
query = XML::Node.new('query')
|
35
|
-
query.xmlns = 'jabber:iq:version'
|
36
|
-
elem << query
|
37
|
-
|
38
|
-
elem.name = ver[:name] if ver[:name]
|
39
|
-
elem.version = ver[:version] if ver[:version]
|
40
|
-
elem.os = ver[:os] if ver[:os]
|
41
|
-
|
42
|
-
elem
|
43
|
-
end
|
44
|
-
|
45
|
-
def query
|
46
|
-
@query ||= self.detect { |n| n.name == 'query' }
|
47
|
-
end
|
48
|
-
|
49
|
-
def name=(name)
|
50
|
-
query.each { |n| n.remove! or break if n.name == 'name' }
|
51
|
-
query << XML::Node.new('name', name)
|
52
|
-
end
|
53
|
-
|
54
|
-
def name
|
55
|
-
if name = query.detect { |n| n.name == 'name' }
|
56
|
-
name.content
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def version=(version)
|
61
|
-
query.each { |n| n.remove! or break if n.name == 'version' }
|
62
|
-
query << XML::Node.new('version', version)
|
63
|
-
end
|
64
|
-
|
65
|
-
def version
|
66
|
-
if version = query.detect { |n| n.version == 'version' }
|
67
|
-
version.content
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def os=(os)
|
72
|
-
query.each { |n| n.remove! or break if n.name == 'os' }
|
73
|
-
query << XML::Node.new('os', os)
|
74
|
-
end
|
75
|
-
|
76
|
-
def os
|
77
|
-
if os = query.detect { |n| n.os == 'os' }
|
78
|
-
os.content
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end #VersionStanza
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
Blather::Client.__send__ :include, Blather::Extensions::Version
|