jabber4r-revive 0.9.0 → 0.10.0
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/.gitignore +5 -4
- data/.rspec +3 -3
- data/.travis.yml +7 -7
- data/CHANGELOG +11 -1
- data/Gemfile +3 -3
- data/README.md +29 -29
- data/Rakefile +70 -70
- data/jabber4r-revive.gemspec +25 -25
- data/lib/jabber4r.rb +38 -33
- data/lib/jabber4r/bosh.rb +21 -0
- data/lib/jabber4r/bosh/authentication.rb +13 -0
- data/lib/jabber4r/bosh/authentication/non_sasl.rb +219 -0
- data/lib/jabber4r/bosh/authentication/sasl.rb +239 -0
- data/lib/jabber4r/bosh/session.rb +144 -0
- data/lib/jabber4r/connection.rb +259 -258
- data/lib/jabber4r/debugger.rb +60 -60
- data/lib/jabber4r/jid.rb +20 -19
- data/lib/jabber4r/protocol.rb +249 -257
- data/lib/jabber4r/protocol/authentication.rb +14 -0
- data/lib/jabber4r/protocol/authentication/non_sasl.rb +138 -0
- data/lib/jabber4r/protocol/authentication/sasl.rb +88 -0
- data/lib/jabber4r/protocol/iq.rb +259 -259
- data/lib/jabber4r/protocol/message.rb +245 -245
- data/lib/jabber4r/protocol/parsed_xml_element.rb +207 -207
- data/lib/jabber4r/protocol/presence.rb +160 -160
- data/lib/jabber4r/protocol/xml_element.rb +143 -143
- data/lib/jabber4r/rexml_1.8_patch.rb +15 -15
- data/lib/jabber4r/roster.rb +38 -38
- data/lib/jabber4r/session.rb +615 -615
- data/lib/jabber4r/version.rb +10 -3
- data/spec/lib/jabber4r/bosh/authentication/non_sasl_spec.rb +79 -0
- data/spec/lib/jabber4r/bosh/authentication/sasl_spec.rb +42 -0
- data/spec/lib/jabber4r/bosh/session_spec.rb +406 -0
- data/spec/lib/jabber4r/bosh_spec.rb +0 -0
- data/spec/lib/jabber4r/connection_spec.rb +174 -174
- data/spec/lib/jabber4r/debugger_spec.rb +35 -35
- data/spec/lib/jabber4r/jid_spec.rb +197 -197
- data/spec/lib/jabber4r/protocol/authentication/non_sasl_spec.rb +79 -0
- data/spec/lib/jabber4r/protocol/authentication/sasl_spec.rb +42 -0
- data/spec/spec_helper.rb +11 -11
- data/spec/support/mocks/tcp_socket_mock.rb +8 -8
- metadata +61 -45
- data/Gemfile.lock +0 -45
- data/lib/jabber4r/bosh_session.rb +0 -224
- data/spec/lib/jabber4r/bosh_session_spec.rb +0 -150
@@ -0,0 +1,14 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# License: see LICENSE
|
4
|
+
# Jabber4R - Jabber Instant Messaging Library for Ruby
|
5
|
+
# Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
|
6
|
+
# Copyright (C) 2013 Sergey Fedorov <strech_ftf@mail.ru>
|
7
|
+
|
8
|
+
module Jabber::Protocol
|
9
|
+
# Public: This module provide authentication methods for xmpp protocol
|
10
|
+
module Authentication; end
|
11
|
+
end
|
12
|
+
|
13
|
+
require "jabber4r/protocol/authentication/non_sasl"
|
14
|
+
require "jabber4r/protocol/authentication/sasl"
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# License: see LICENSE
|
4
|
+
# Jabber4R - Jabber Instant Messaging Library for Ruby
|
5
|
+
# Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
|
6
|
+
# Copyright (C) 2013 Sergey Fedorov <strech_ftf@mail.ru>
|
7
|
+
|
8
|
+
require "digest/sha1"
|
9
|
+
|
10
|
+
module Jabber::Protocol::Authentication
|
11
|
+
# Class provided Non-SASL authentication on jabber server
|
12
|
+
# http://xmpp.org/extensions/xep-0078.html
|
13
|
+
class NonSASL
|
14
|
+
MECHANISMS = [:plain, :digest].freeze
|
15
|
+
|
16
|
+
attr_reader :jid, :password
|
17
|
+
attr_reader :stream_id, :mechanism
|
18
|
+
|
19
|
+
# Public: Creates new Non-SASL authentication object
|
20
|
+
#
|
21
|
+
# jid - [Jabber::JID|String] the jid of jabber server user
|
22
|
+
# password - String the user password
|
23
|
+
# options - Hash the authentication options (default: Empty hash)
|
24
|
+
# :stream_id - String the stream identifier (authid)
|
25
|
+
# :mechanism - Symbol the name of mechnism to use
|
26
|
+
#
|
27
|
+
# Examples
|
28
|
+
#
|
29
|
+
# non_sasl = Jabber::Protocol::Authentication::NonSASL.new("strech@localhost/res-1", "my-pass-phrase")
|
30
|
+
# non_sasl.plain? # => true
|
31
|
+
# non_sasl.to_xml # =>
|
32
|
+
#
|
33
|
+
# <iq type="set" id="...">
|
34
|
+
# <query xmlns="jabber:iq:auth">
|
35
|
+
# <username>strech</username>
|
36
|
+
# <password>my-pass-phrase</password>
|
37
|
+
# <resource>res-1</resource>
|
38
|
+
# </query>
|
39
|
+
# </iq>
|
40
|
+
def initialize(jid, password, options = {})
|
41
|
+
raise TypeError,
|
42
|
+
"Class(Jabber::JID) or Class(String) expected," +
|
43
|
+
" but #{jid.class} was given" unless jid.is_a?(Jabber::JID) || jid.is_a?(String)
|
44
|
+
|
45
|
+
@jid = jid.is_a?(Jabber::JID) ? jid : Jabber::JID.new(jid)
|
46
|
+
@password = password
|
47
|
+
|
48
|
+
@mechanism = options.fetch(:mechanism, :plain)
|
49
|
+
@stream_id = options.fetch(:stream_id) if digest?
|
50
|
+
|
51
|
+
raise ArgumentError,
|
52
|
+
"Unknown authentication mechanism '#{mechanism}'," +
|
53
|
+
" available is [#{MECHANISMS * ", "}]" unless MECHANISMS.include?(mechanism)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Public: Is NonSASL object is for plain authentication
|
57
|
+
#
|
58
|
+
# Returns boolean
|
59
|
+
def plain?
|
60
|
+
mechanism == :plain
|
61
|
+
end
|
62
|
+
|
63
|
+
# Public: Is NonSASL object is for digest authentication
|
64
|
+
#
|
65
|
+
# Returns boolean
|
66
|
+
def digest?
|
67
|
+
mechanism == :digest
|
68
|
+
end
|
69
|
+
|
70
|
+
# Public: Create XML string from NonSASL object
|
71
|
+
#
|
72
|
+
# Returns String
|
73
|
+
def dump
|
74
|
+
Ox.dump(send mechanism)
|
75
|
+
end
|
76
|
+
alias :to_xml :dump
|
77
|
+
|
78
|
+
# Public: Create Ox::Element from NonSASL object
|
79
|
+
#
|
80
|
+
# Returns Ox::Element
|
81
|
+
def to_ox
|
82
|
+
send(mechanism)
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
# Internal: Make xml object for plain authentication mechanism
|
87
|
+
#
|
88
|
+
# Returns Ox:Element
|
89
|
+
def plain
|
90
|
+
query = Ox::Element.new("query").tap do |element|
|
91
|
+
element[:xmlns] = "jabber:iq:auth"
|
92
|
+
|
93
|
+
element << (Ox::Element.new("username") << jid.node)
|
94
|
+
element << (Ox::Element.new("password") << password)
|
95
|
+
element << (Ox::Element.new("resource") << jid.resource)
|
96
|
+
end
|
97
|
+
|
98
|
+
build_iq(query)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Internal: Make xml object for digest authentication mechanism
|
102
|
+
#
|
103
|
+
# Returns Ox:Element
|
104
|
+
def digest
|
105
|
+
query = Ox::Element.new("query").tap do |element|
|
106
|
+
element[:xmlns] = "jabber:iq:auth"
|
107
|
+
|
108
|
+
digest_password = self.class.generate_digest(stream_id, password)
|
109
|
+
|
110
|
+
element << (Ox::Element.new("username") << jid.node)
|
111
|
+
element << (Ox::Element.new("digest") << digest_password)
|
112
|
+
element << (Ox::Element.new("resource") << jid.resource)
|
113
|
+
end
|
114
|
+
|
115
|
+
build_iq(query)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Internal: The root iq stanza for authentication
|
119
|
+
#
|
120
|
+
# Returns Ox:Element
|
121
|
+
def build_iq(query)
|
122
|
+
Ox::Element.new("iq").tap do |element|
|
123
|
+
element[:xmlns] = "jabber:client"
|
124
|
+
element[:type] = "set"
|
125
|
+
element[:id] = Jabber.gen_random_id
|
126
|
+
|
127
|
+
element << query
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Internal: Generate hex string consist of concatination stream_id and password
|
132
|
+
#
|
133
|
+
# Returns String
|
134
|
+
def self.generate_digest(stream_id, password)
|
135
|
+
Digest::SHA1.hexdigest([stream_id, password].join)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# License: see LICENSE
|
4
|
+
# Jabber4R - Jabber Instant Messaging Library for Ruby
|
5
|
+
# Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
|
6
|
+
# Copyright (C) 2013 Sergey Fedorov <strech_ftf@mail.ru>
|
7
|
+
|
8
|
+
require 'base64'
|
9
|
+
|
10
|
+
module Jabber::Protocol::Authentication
|
11
|
+
# Class provided SASL authentication on jabber server
|
12
|
+
class SASL
|
13
|
+
# Full list of mechanisms
|
14
|
+
# http://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml
|
15
|
+
MECHANISMS = [:plain].freeze
|
16
|
+
|
17
|
+
attr_reader :jid, :password
|
18
|
+
attr_reader :mechanism
|
19
|
+
|
20
|
+
# Public: Creates new SASL authentication object
|
21
|
+
#
|
22
|
+
# jid - [Jabber::JID|String] the jid of jabber server user
|
23
|
+
# password - String the user password
|
24
|
+
# options - Hash the authentication options (default: Empty hash)
|
25
|
+
# :mechanism - Symbol the name of mechnism to use
|
26
|
+
#
|
27
|
+
# Examples
|
28
|
+
#
|
29
|
+
# non_sasl = Jabber::Protocol::Authentication::SASL.new("strech@localhost/res-1", "my-pass-phrase")
|
30
|
+
# non_sasl.plain? # => true
|
31
|
+
# non_sasl.to_xml # =>
|
32
|
+
#
|
33
|
+
# <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">biwsbj1qdWxpZXQscj1vTXNUQUF3QUFBQU1BQUFBTlAwVEFBQUFBQUJQVTBBQQ==</auth>
|
34
|
+
def initialize(jid, password, options = {})
|
35
|
+
raise TypeError,
|
36
|
+
"Class(Jabber::JID) or Class(String) expected," +
|
37
|
+
" but #{jid.class} was given" unless jid.is_a?(Jabber::JID) || jid.is_a?(String)
|
38
|
+
|
39
|
+
@jid = jid.is_a?(Jabber::JID) ? jid : Jabber::JID.new(jid)
|
40
|
+
@password = password
|
41
|
+
|
42
|
+
@mechanism = options.fetch(:mechanism, :plain)
|
43
|
+
|
44
|
+
raise ArgumentError,
|
45
|
+
"Unknown authentication mechanism '#{mechanism}'," +
|
46
|
+
" available is [#{MECHANISMS * ", "}]" unless MECHANISMS.include?(mechanism)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Public: Is SASL object is for plain authentication
|
50
|
+
#
|
51
|
+
# Returns boolean
|
52
|
+
def plain?
|
53
|
+
mechanism == :plain
|
54
|
+
end
|
55
|
+
|
56
|
+
# Public: Create XML string from SASL object
|
57
|
+
#
|
58
|
+
# Returns String
|
59
|
+
def dump
|
60
|
+
Ox.dump(send mechanism)
|
61
|
+
end
|
62
|
+
alias :to_xml :dump
|
63
|
+
|
64
|
+
# Public: Create Ox::Element from SASL object
|
65
|
+
#
|
66
|
+
# Returns Ox::Element
|
67
|
+
def to_ox
|
68
|
+
send(mechanism)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
# Internal: Make xml object for plain authentication mechanism
|
73
|
+
#
|
74
|
+
# Returns Ox:Element
|
75
|
+
def plain
|
76
|
+
Ox::Element.new("auth").tap do |element|
|
77
|
+
element[:xmlns] = "urn:ietf:params:xml:ns:xmpp-sasl"
|
78
|
+
element[:mechanism] = "PLAIN"
|
79
|
+
|
80
|
+
element << self.class.generate_plain(jid, password)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.generate_plain(jid, password)
|
85
|
+
["#{jid.strip}\x00#{jid.node}\x00#{password}"].pack("m").gsub(/\s/, "")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/jabber4r/protocol/iq.rb
CHANGED
@@ -1,260 +1,260 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
# License: see LICENSE
|
4
|
-
# Jabber4R - Jabber Instant Messaging Library for Ruby
|
5
|
-
# Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
|
6
|
-
|
7
|
-
module Jabber::Protocol
|
8
|
-
##
|
9
|
-
# A class used to build/parse IQ requests/responses
|
10
|
-
#
|
11
|
-
class Iq
|
12
|
-
attr_accessor :session,:to, :from, :id, :type, :xmlns, :data,:error,:errorcode
|
13
|
-
ERROR="error"
|
14
|
-
GET="get"
|
15
|
-
SET="set"
|
16
|
-
RESULT="result"
|
17
|
-
|
18
|
-
##
|
19
|
-
# Factory to build an IQ object from xml element
|
20
|
-
#
|
21
|
-
# session:: [Jabber::Session] The Jabber session instance
|
22
|
-
# element:: [Jabber::Protocol::ParsedXMLElement] The received XML object
|
23
|
-
# return:: [Jabber::Protocol::Iq] The newly created Iq object
|
24
|
-
#
|
25
|
-
def self.from_element(session, element)
|
26
|
-
iq = new(session)
|
27
|
-
|
28
|
-
iq.from = Jabber::JID.new(element.attr_from) if element.attr_from
|
29
|
-
iq.to = Jabber::JID.new(element.attr_to) if element.attr_to
|
30
|
-
|
31
|
-
iq.id = element.attr_id
|
32
|
-
iq.type = element.attr_type
|
33
|
-
iq.xmlns = element.query.attr_xmlns
|
34
|
-
iq.data = element.query
|
35
|
-
iq.session = session
|
36
|
-
|
37
|
-
if element.attr_type = "error"
|
38
|
-
iq.error = element.error
|
39
|
-
iq.errorcode = element.error.attr_code
|
40
|
-
end
|
41
|
-
|
42
|
-
return iq
|
43
|
-
end
|
44
|
-
|
45
|
-
##
|
46
|
-
# Default constructor to build an Iq object
|
47
|
-
# session:: [Jabber::Session] The Jabber session instance
|
48
|
-
# id:: [String=nil] The (optional) id of the Iq object
|
49
|
-
def initialize(session,id=nil)
|
50
|
-
@session=session
|
51
|
-
@id=id
|
52
|
-
end
|
53
|
-
|
54
|
-
##
|
55
|
-
# Return an IQ object that uses the jabber:iq:private namespace
|
56
|
-
#
|
57
|
-
def self.get_private(session,id,ename,ns)
|
58
|
-
iq=Iq.new(session,id)
|
59
|
-
iq.type="get"
|
60
|
-
iq.xmlns="jabber:iq:private"
|
61
|
-
iq.data=XMLElement.new(ename,{'xmlns' => ns});
|
62
|
-
return iq
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
##
|
67
|
-
# Generates an IQ roster request XML element
|
68
|
-
#
|
69
|
-
# id:: [String] The message id
|
70
|
-
# return:: [String] The XML data to send
|
71
|
-
#
|
72
|
-
def self.gen_roster(session, id)
|
73
|
-
iq = Iq.new(session, id)
|
74
|
-
iq.type = "get"
|
75
|
-
iq.xmlns = "jabber:iq:roster"
|
76
|
-
return iq
|
77
|
-
#return XMLElement.new("iq", {"type"=>"get", "id"=>id}).add_child("query", {"xmlns"=>"jabber:iq:roster"}).to_s
|
78
|
-
end
|
79
|
-
|
80
|
-
##
|
81
|
-
# Generates an IQ authortization request XML element
|
82
|
-
#
|
83
|
-
# id:: [String] The message id
|
84
|
-
# username:: [String] The username
|
85
|
-
# password:: [String] The password
|
86
|
-
# email:: [String] The email address of the account
|
87
|
-
# name:: [String] The full name
|
88
|
-
# return:: [String] The XML data to send
|
89
|
-
#
|
90
|
-
def self.gen_registration(session, id, username, password, email, name)
|
91
|
-
iq = Iq.new(session, id)
|
92
|
-
iq.type = "set"
|
93
|
-
iq.xmlns = "jabber:iq:register"
|
94
|
-
iq.data = XMLElement.new("username").add_data(username).to_s
|
95
|
-
iq.data << XMLElement.new("password").add_data(password).to_s
|
96
|
-
iq.data << XMLElement.new("email").add_data(email).to_s
|
97
|
-
iq.data << XMLElement.new("name").add_data(name).to_s
|
98
|
-
return iq
|
99
|
-
end
|
100
|
-
|
101
|
-
##
|
102
|
-
# Generates an IQ Roster Item add request XML element
|
103
|
-
#
|
104
|
-
# session:: [Session] The session
|
105
|
-
# id:: [String] The message id
|
106
|
-
# jid:: [JID] The Jabber ID to add to the roster
|
107
|
-
# name:: [String] The full name
|
108
|
-
# return:: [String] The XML data to send
|
109
|
-
#
|
110
|
-
def self.gen_add_rosteritem(session, id, jid, name)
|
111
|
-
iq = Iq.new(session, id)
|
112
|
-
iq.type = "set"
|
113
|
-
iq.xmlns = "jabber:iq:roster"
|
114
|
-
iq.data = XMLElement.new("item").add_attribute("jid", jid).add_attribute("name", name).to_s
|
115
|
-
return iq
|
116
|
-
end
|
117
|
-
|
118
|
-
##
|
119
|
-
# Generates an IQ authortization request XML element
|
120
|
-
#
|
121
|
-
# id:: [String] The message id
|
122
|
-
# username:: [String] The username
|
123
|
-
# password:: [String] The password
|
124
|
-
# resource:: [String] The resource to bind this session to
|
125
|
-
# return:: [String] The XML data to send
|
126
|
-
#
|
127
|
-
def self.gen_auth(session, id, username, password, resource)
|
128
|
-
iq = Iq.new(session, id)
|
129
|
-
iq.type = "set"
|
130
|
-
iq.xmlns = "jabber:iq:auth"
|
131
|
-
iq.data = XMLElement.new("username").add_data(username).to_s
|
132
|
-
iq.data << XMLElement.new("password").add_data(password).to_s
|
133
|
-
iq.data << XMLElement.new("resource").add_data(resource).to_s
|
134
|
-
return iq
|
135
|
-
#element = XMLElement.new("iq", {"type"=>"set", "id"=>id}).add_child("query", {"xmlns"=>"jabber:iq:auth"}).add_child("username").add_data(username).to_parent.add_child("password").add_data(password).to_parent.add_child("resource").add_data(resource).to_parent.to_s
|
136
|
-
end
|
137
|
-
|
138
|
-
##
|
139
|
-
# Generates an IQ digest authortization request XML element
|
140
|
-
#
|
141
|
-
# id:: [String] The message id
|
142
|
-
# username:: [String] The username
|
143
|
-
# digest:: [String] The SHA-1 hash of the sessionid and the password
|
144
|
-
# resource:: [String] The resource to bind this session to
|
145
|
-
# return:: [String] The XML data to send
|
146
|
-
#
|
147
|
-
def self.gen_auth_digest(session, id, username, digest, resource)
|
148
|
-
iq = Iq.new(session, id)
|
149
|
-
iq.type = "set"
|
150
|
-
iq.xmlns = "jabber:iq:auth"
|
151
|
-
iq.data = XMLElement.new("username").add_data(username).to_s
|
152
|
-
iq.data << XMLElement.new("digest").add_data(digest).to_s
|
153
|
-
iq.data << XMLElement.new("resource").add_data(resource).to_s
|
154
|
-
return iq
|
155
|
-
#return XMLElement.new("iq", {"type"=>"set", "id"=>id}).add_child("query", {"xmlns"=>"jabber:iq:auth"}).add_child("username").add_data(username).to_parent.add_child("digest").add_data(digest).to_parent.add_child("resource").add_data(resource).to_parent.to_s
|
156
|
-
end
|
157
|
-
|
158
|
-
##
|
159
|
-
# Generates an IQ out of bounds XML element
|
160
|
-
#
|
161
|
-
# to:: [JID] The Jabber ID to send to
|
162
|
-
# url:: [String] The data to send
|
163
|
-
# desc:: [String=""] The description of the data
|
164
|
-
# return:: [String] The XML data to send
|
165
|
-
#
|
166
|
-
def self.gen_oob(session, to, url, desc="")
|
167
|
-
iq = Iq.new(session, nil)
|
168
|
-
iq.type = "set"
|
169
|
-
iq.xmlns = "jabber:iq:oob"
|
170
|
-
iq.data = XMLElement.new("url").add_data(url).to_s
|
171
|
-
iq.data << XMLElement.new("desc").add_data(desc).to_s
|
172
|
-
return iq
|
173
|
-
#return XMLElement.new("iq", {"type"=>"set"}).add_child("query", {"xmlns"=>"jabber:iq:oob"}).add_child("url").add_data(url).to_parent.add_child("desc").add_data(data).to_parent.to_s
|
174
|
-
end
|
175
|
-
|
176
|
-
##
|
177
|
-
# Generates an VCard request XML element
|
178
|
-
#
|
179
|
-
# id:: [String] The message ID
|
180
|
-
# to:: [JID] The jabber id of the account to get the VCard for
|
181
|
-
# return:: [String] The XML data to send
|
182
|
-
#
|
183
|
-
def self.gen_vcard(session, id, to)
|
184
|
-
iq = Iq.new(session, id)
|
185
|
-
iq.xmlns = "vcard-temp"
|
186
|
-
iq.type = "get"
|
187
|
-
iq.to = to
|
188
|
-
return iq
|
189
|
-
#return XMLElement.new("iq", {"type"=>"get", "id"=>id, "to"=>to}).add_child("query", {"xmlns"=>"vcard-temp"}).to_s
|
190
|
-
end
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
##
|
196
|
-
# Sends the IQ to the Jabber service for delivery
|
197
|
-
#
|
198
|
-
# wait:: [Boolean = false] Wait for reply before return?
|
199
|
-
# &block:: [Block] A block to process the message replies
|
200
|
-
#
|
201
|
-
def send(wait=false, &block)
|
202
|
-
if wait
|
203
|
-
iq = nil
|
204
|
-
blockedThread = Thread.current
|
205
|
-
@session.connection.send(self.to_s, block) do |je|
|
206
|
-
if je.element_tag == "iq" and je.attr_id == @id
|
207
|
-
je.consume_element
|
208
|
-
iq = self.class.from_element(@session, je)
|
209
|
-
blockedThread.wakeup
|
210
|
-
end
|
211
|
-
end
|
212
|
-
Thread.stop
|
213
|
-
return iq
|
214
|
-
else
|
215
|
-
@session.connection.send(self.to_s, block) if @session
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
##
|
220
|
-
# Builds a reply to an existing Iq
|
221
|
-
#
|
222
|
-
# return:: [Jabber::Protocol::Iq] The result Iq
|
223
|
-
#
|
224
|
-
def reply
|
225
|
-
iq = Iq.new(@session,@id)
|
226
|
-
iq.to = @from
|
227
|
-
iq.id = @id
|
228
|
-
iq.type = 'result'
|
229
|
-
@is_reply = true
|
230
|
-
return iq
|
231
|
-
end
|
232
|
-
|
233
|
-
##
|
234
|
-
# Generates XML that complies with the Jabber protocol for
|
235
|
-
# sending the Iq through the Jabber service.
|
236
|
-
#
|
237
|
-
# return:: [String] The XML string.
|
238
|
-
#
|
239
|
-
def to_xml
|
240
|
-
elem = XMLElement.new("iq", { "type"=>@type})
|
241
|
-
elem.add_attribute("to" ,@to) if @to
|
242
|
-
elem.add_attribute("id", @id) if @id
|
243
|
-
elem.add_child("query").add_attribute("xmlns",@xmlns).add_data(@data.to_s)
|
244
|
-
if @type=="error" then
|
245
|
-
e=elem.add_child("error");
|
246
|
-
e.add_attribute("code",@errorcode) if @errorcode
|
247
|
-
e.add_data(@error) if @error
|
248
|
-
end
|
249
|
-
return elem.to_s
|
250
|
-
end
|
251
|
-
|
252
|
-
##
|
253
|
-
# see to_xml
|
254
|
-
#
|
255
|
-
def to_s
|
256
|
-
to_xml
|
257
|
-
end
|
258
|
-
|
259
|
-
end
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# License: see LICENSE
|
4
|
+
# Jabber4R - Jabber Instant Messaging Library for Ruby
|
5
|
+
# Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
|
6
|
+
|
7
|
+
module Jabber::Protocol
|
8
|
+
##
|
9
|
+
# A class used to build/parse IQ requests/responses
|
10
|
+
#
|
11
|
+
class Iq
|
12
|
+
attr_accessor :session,:to, :from, :id, :type, :xmlns, :data,:error,:errorcode
|
13
|
+
ERROR="error"
|
14
|
+
GET="get"
|
15
|
+
SET="set"
|
16
|
+
RESULT="result"
|
17
|
+
|
18
|
+
##
|
19
|
+
# Factory to build an IQ object from xml element
|
20
|
+
#
|
21
|
+
# session:: [Jabber::Session] The Jabber session instance
|
22
|
+
# element:: [Jabber::Protocol::ParsedXMLElement] The received XML object
|
23
|
+
# return:: [Jabber::Protocol::Iq] The newly created Iq object
|
24
|
+
#
|
25
|
+
def self.from_element(session, element)
|
26
|
+
iq = new(session)
|
27
|
+
|
28
|
+
iq.from = Jabber::JID.new(element.attr_from) if element.attr_from
|
29
|
+
iq.to = Jabber::JID.new(element.attr_to) if element.attr_to
|
30
|
+
|
31
|
+
iq.id = element.attr_id
|
32
|
+
iq.type = element.attr_type
|
33
|
+
iq.xmlns = element.query.attr_xmlns
|
34
|
+
iq.data = element.query
|
35
|
+
iq.session = session
|
36
|
+
|
37
|
+
if element.attr_type = "error"
|
38
|
+
iq.error = element.error
|
39
|
+
iq.errorcode = element.error.attr_code
|
40
|
+
end
|
41
|
+
|
42
|
+
return iq
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Default constructor to build an Iq object
|
47
|
+
# session:: [Jabber::Session] The Jabber session instance
|
48
|
+
# id:: [String=nil] The (optional) id of the Iq object
|
49
|
+
def initialize(session,id=nil)
|
50
|
+
@session=session
|
51
|
+
@id=id
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Return an IQ object that uses the jabber:iq:private namespace
|
56
|
+
#
|
57
|
+
def self.get_private(session,id,ename,ns)
|
58
|
+
iq=Iq.new(session,id)
|
59
|
+
iq.type="get"
|
60
|
+
iq.xmlns="jabber:iq:private"
|
61
|
+
iq.data=XMLElement.new(ename,{'xmlns' => ns});
|
62
|
+
return iq
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
##
|
67
|
+
# Generates an IQ roster request XML element
|
68
|
+
#
|
69
|
+
# id:: [String] The message id
|
70
|
+
# return:: [String] The XML data to send
|
71
|
+
#
|
72
|
+
def self.gen_roster(session, id)
|
73
|
+
iq = Iq.new(session, id)
|
74
|
+
iq.type = "get"
|
75
|
+
iq.xmlns = "jabber:iq:roster"
|
76
|
+
return iq
|
77
|
+
#return XMLElement.new("iq", {"type"=>"get", "id"=>id}).add_child("query", {"xmlns"=>"jabber:iq:roster"}).to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Generates an IQ authortization request XML element
|
82
|
+
#
|
83
|
+
# id:: [String] The message id
|
84
|
+
# username:: [String] The username
|
85
|
+
# password:: [String] The password
|
86
|
+
# email:: [String] The email address of the account
|
87
|
+
# name:: [String] The full name
|
88
|
+
# return:: [String] The XML data to send
|
89
|
+
#
|
90
|
+
def self.gen_registration(session, id, username, password, email, name)
|
91
|
+
iq = Iq.new(session, id)
|
92
|
+
iq.type = "set"
|
93
|
+
iq.xmlns = "jabber:iq:register"
|
94
|
+
iq.data = XMLElement.new("username").add_data(username).to_s
|
95
|
+
iq.data << XMLElement.new("password").add_data(password).to_s
|
96
|
+
iq.data << XMLElement.new("email").add_data(email).to_s
|
97
|
+
iq.data << XMLElement.new("name").add_data(name).to_s
|
98
|
+
return iq
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Generates an IQ Roster Item add request XML element
|
103
|
+
#
|
104
|
+
# session:: [Session] The session
|
105
|
+
# id:: [String] The message id
|
106
|
+
# jid:: [JID] The Jabber ID to add to the roster
|
107
|
+
# name:: [String] The full name
|
108
|
+
# return:: [String] The XML data to send
|
109
|
+
#
|
110
|
+
def self.gen_add_rosteritem(session, id, jid, name)
|
111
|
+
iq = Iq.new(session, id)
|
112
|
+
iq.type = "set"
|
113
|
+
iq.xmlns = "jabber:iq:roster"
|
114
|
+
iq.data = XMLElement.new("item").add_attribute("jid", jid).add_attribute("name", name).to_s
|
115
|
+
return iq
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# Generates an IQ authortization request XML element
|
120
|
+
#
|
121
|
+
# id:: [String] The message id
|
122
|
+
# username:: [String] The username
|
123
|
+
# password:: [String] The password
|
124
|
+
# resource:: [String] The resource to bind this session to
|
125
|
+
# return:: [String] The XML data to send
|
126
|
+
#
|
127
|
+
def self.gen_auth(session, id, username, password, resource)
|
128
|
+
iq = Iq.new(session, id)
|
129
|
+
iq.type = "set"
|
130
|
+
iq.xmlns = "jabber:iq:auth"
|
131
|
+
iq.data = XMLElement.new("username").add_data(username).to_s
|
132
|
+
iq.data << XMLElement.new("password").add_data(password).to_s
|
133
|
+
iq.data << XMLElement.new("resource").add_data(resource).to_s
|
134
|
+
return iq
|
135
|
+
#element = XMLElement.new("iq", {"type"=>"set", "id"=>id}).add_child("query", {"xmlns"=>"jabber:iq:auth"}).add_child("username").add_data(username).to_parent.add_child("password").add_data(password).to_parent.add_child("resource").add_data(resource).to_parent.to_s
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Generates an IQ digest authortization request XML element
|
140
|
+
#
|
141
|
+
# id:: [String] The message id
|
142
|
+
# username:: [String] The username
|
143
|
+
# digest:: [String] The SHA-1 hash of the sessionid and the password
|
144
|
+
# resource:: [String] The resource to bind this session to
|
145
|
+
# return:: [String] The XML data to send
|
146
|
+
#
|
147
|
+
def self.gen_auth_digest(session, id, username, digest, resource)
|
148
|
+
iq = Iq.new(session, id)
|
149
|
+
iq.type = "set"
|
150
|
+
iq.xmlns = "jabber:iq:auth"
|
151
|
+
iq.data = XMLElement.new("username").add_data(username).to_s
|
152
|
+
iq.data << XMLElement.new("digest").add_data(digest).to_s
|
153
|
+
iq.data << XMLElement.new("resource").add_data(resource).to_s
|
154
|
+
return iq
|
155
|
+
#return XMLElement.new("iq", {"type"=>"set", "id"=>id}).add_child("query", {"xmlns"=>"jabber:iq:auth"}).add_child("username").add_data(username).to_parent.add_child("digest").add_data(digest).to_parent.add_child("resource").add_data(resource).to_parent.to_s
|
156
|
+
end
|
157
|
+
|
158
|
+
##
|
159
|
+
# Generates an IQ out of bounds XML element
|
160
|
+
#
|
161
|
+
# to:: [JID] The Jabber ID to send to
|
162
|
+
# url:: [String] The data to send
|
163
|
+
# desc:: [String=""] The description of the data
|
164
|
+
# return:: [String] The XML data to send
|
165
|
+
#
|
166
|
+
def self.gen_oob(session, to, url, desc="")
|
167
|
+
iq = Iq.new(session, nil)
|
168
|
+
iq.type = "set"
|
169
|
+
iq.xmlns = "jabber:iq:oob"
|
170
|
+
iq.data = XMLElement.new("url").add_data(url).to_s
|
171
|
+
iq.data << XMLElement.new("desc").add_data(desc).to_s
|
172
|
+
return iq
|
173
|
+
#return XMLElement.new("iq", {"type"=>"set"}).add_child("query", {"xmlns"=>"jabber:iq:oob"}).add_child("url").add_data(url).to_parent.add_child("desc").add_data(data).to_parent.to_s
|
174
|
+
end
|
175
|
+
|
176
|
+
##
|
177
|
+
# Generates an VCard request XML element
|
178
|
+
#
|
179
|
+
# id:: [String] The message ID
|
180
|
+
# to:: [JID] The jabber id of the account to get the VCard for
|
181
|
+
# return:: [String] The XML data to send
|
182
|
+
#
|
183
|
+
def self.gen_vcard(session, id, to)
|
184
|
+
iq = Iq.new(session, id)
|
185
|
+
iq.xmlns = "vcard-temp"
|
186
|
+
iq.type = "get"
|
187
|
+
iq.to = to
|
188
|
+
return iq
|
189
|
+
#return XMLElement.new("iq", {"type"=>"get", "id"=>id, "to"=>to}).add_child("query", {"xmlns"=>"vcard-temp"}).to_s
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
|
194
|
+
|
195
|
+
##
|
196
|
+
# Sends the IQ to the Jabber service for delivery
|
197
|
+
#
|
198
|
+
# wait:: [Boolean = false] Wait for reply before return?
|
199
|
+
# &block:: [Block] A block to process the message replies
|
200
|
+
#
|
201
|
+
def send(wait=false, &block)
|
202
|
+
if wait
|
203
|
+
iq = nil
|
204
|
+
blockedThread = Thread.current
|
205
|
+
@session.connection.send(self.to_s, block) do |je|
|
206
|
+
if je.element_tag == "iq" and je.attr_id == @id
|
207
|
+
je.consume_element
|
208
|
+
iq = self.class.from_element(@session, je)
|
209
|
+
blockedThread.wakeup
|
210
|
+
end
|
211
|
+
end
|
212
|
+
Thread.stop
|
213
|
+
return iq
|
214
|
+
else
|
215
|
+
@session.connection.send(self.to_s, block) if @session
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
##
|
220
|
+
# Builds a reply to an existing Iq
|
221
|
+
#
|
222
|
+
# return:: [Jabber::Protocol::Iq] The result Iq
|
223
|
+
#
|
224
|
+
def reply
|
225
|
+
iq = Iq.new(@session,@id)
|
226
|
+
iq.to = @from
|
227
|
+
iq.id = @id
|
228
|
+
iq.type = 'result'
|
229
|
+
@is_reply = true
|
230
|
+
return iq
|
231
|
+
end
|
232
|
+
|
233
|
+
##
|
234
|
+
# Generates XML that complies with the Jabber protocol for
|
235
|
+
# sending the Iq through the Jabber service.
|
236
|
+
#
|
237
|
+
# return:: [String] The XML string.
|
238
|
+
#
|
239
|
+
def to_xml
|
240
|
+
elem = XMLElement.new("iq", { "type"=>@type})
|
241
|
+
elem.add_attribute("to" ,@to) if @to
|
242
|
+
elem.add_attribute("id", @id) if @id
|
243
|
+
elem.add_child("query").add_attribute("xmlns",@xmlns).add_data(@data.to_s)
|
244
|
+
if @type=="error" then
|
245
|
+
e=elem.add_child("error");
|
246
|
+
e.add_attribute("code",@errorcode) if @errorcode
|
247
|
+
e.add_data(@error) if @error
|
248
|
+
end
|
249
|
+
return elem.to_s
|
250
|
+
end
|
251
|
+
|
252
|
+
##
|
253
|
+
# see to_xml
|
254
|
+
#
|
255
|
+
def to_s
|
256
|
+
to_xml
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
260
|
end
|