jabber4r-revive 0.9.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 +4 -0
- data/.rspec +3 -0
- data/.travis.yml +8 -0
- data/CHANGELOG +45 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +45 -0
- data/LICENSE +12 -0
- data/README.md +29 -0
- data/Rakefile +71 -0
- data/jabber4r-revive.gemspec +25 -0
- data/lib/jabber4r/bosh_session.rb +224 -0
- data/lib/jabber4r/connection.rb +258 -0
- data/lib/jabber4r/debugger.rb +61 -0
- data/lib/jabber4r/jid.rb +125 -0
- data/lib/jabber4r/protocol/iq.rb +260 -0
- data/lib/jabber4r/protocol/message.rb +246 -0
- data/lib/jabber4r/protocol/parsed_xml_element.rb +208 -0
- data/lib/jabber4r/protocol/presence.rb +160 -0
- data/lib/jabber4r/protocol/xml_element.rb +144 -0
- data/lib/jabber4r/protocol.rb +257 -0
- data/lib/jabber4r/rexml_1.8_patch.rb +16 -0
- data/lib/jabber4r/roster.rb +322 -0
- data/lib/jabber4r/session.rb +615 -0
- data/lib/jabber4r/vcard.rb +42 -0
- data/lib/jabber4r/version.rb +3 -0
- data/lib/jabber4r.rb +33 -0
- data/spec/lib/jabber4r/bosh_session_spec.rb +150 -0
- data/spec/lib/jabber4r/connection_spec.rb +174 -0
- data/spec/lib/jabber4r/debugger_spec.rb +36 -0
- data/spec/lib/jabber4r/jid_spec.rb +198 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/mocks/tcp_socket_mock.rb +8 -0
- metadata +151 -0
@@ -0,0 +1,258 @@
|
|
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
|
8
|
+
# The connection class encapsulates the connection to the Jabber
|
9
|
+
# service including managing the socket and controlling the parsing
|
10
|
+
# of the Jabber XML stream.
|
11
|
+
class Connection
|
12
|
+
DISCONNECTED = 1
|
13
|
+
CONNECTED = 2
|
14
|
+
|
15
|
+
# Public
|
16
|
+
attr_reader :host, :port, :status, :input, :output
|
17
|
+
|
18
|
+
# Internal
|
19
|
+
attr_reader :poll_thread, :parser_thread
|
20
|
+
|
21
|
+
# Internal
|
22
|
+
attr_reader :filters, :handlers
|
23
|
+
|
24
|
+
# Internal
|
25
|
+
attr_reader :socket, :parser
|
26
|
+
|
27
|
+
def initialize(host, port = 5222)
|
28
|
+
@host, @port = host, port
|
29
|
+
|
30
|
+
@handlers, @filters = {}, {}
|
31
|
+
|
32
|
+
@poll_counter = 10
|
33
|
+
@mutex = Mutex.new
|
34
|
+
|
35
|
+
@status = DISCONNECTED
|
36
|
+
end
|
37
|
+
|
38
|
+
# Public: Connects to the Jabber server through a TCP Socket and
|
39
|
+
# starts the Jabber parser.
|
40
|
+
#
|
41
|
+
# Returns nothing
|
42
|
+
def connect
|
43
|
+
@socket = TCPSocket.new(@host, @port)
|
44
|
+
@parser = Jabber::Protocol.Parser.new(socket, self)
|
45
|
+
|
46
|
+
register_parsing_thread
|
47
|
+
register_polling_thread
|
48
|
+
|
49
|
+
@status = CONNECTED
|
50
|
+
end
|
51
|
+
|
52
|
+
# Internal: Register new parser thread
|
53
|
+
#
|
54
|
+
# Returns nothing
|
55
|
+
def register_parsing_thread
|
56
|
+
@parser_thread = Thread.new { parser.parse }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Internal: Register new polling thread
|
60
|
+
#
|
61
|
+
# Returns nothing
|
62
|
+
def register_polling_thread
|
63
|
+
@poll_thread = Thread.new { poll }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Public: Closes the connection to the Jabber service
|
67
|
+
#
|
68
|
+
# Returns nothing
|
69
|
+
def close
|
70
|
+
parser_thread.kill if parser_thread # why if?
|
71
|
+
poll_thread.kill
|
72
|
+
socket.close if socket
|
73
|
+
|
74
|
+
@status = DISCONNECTED
|
75
|
+
end
|
76
|
+
alias :disconnect :close
|
77
|
+
|
78
|
+
# Public: Returns if this connection is connected to a Jabber service
|
79
|
+
#
|
80
|
+
# Returns boolean
|
81
|
+
def connected?
|
82
|
+
status == CONNECTED
|
83
|
+
end
|
84
|
+
|
85
|
+
# Public: Returns if this connection is NOT connected to a Jabber service
|
86
|
+
#
|
87
|
+
# Returns boolean
|
88
|
+
def disconnected?
|
89
|
+
status == DISCONNECTED
|
90
|
+
end
|
91
|
+
|
92
|
+
# Public: Adds a filter block to process received XML messages
|
93
|
+
#
|
94
|
+
# name - String the name of filter
|
95
|
+
# block - Block of code
|
96
|
+
#
|
97
|
+
# Returns nothing
|
98
|
+
def add_filter(name, &block)
|
99
|
+
raise ArgumentError, "Expected block to be given" if block.nil?
|
100
|
+
|
101
|
+
@filters[name] = block
|
102
|
+
end
|
103
|
+
|
104
|
+
# Public: Removes a filter block
|
105
|
+
#
|
106
|
+
# name - String the name of filter
|
107
|
+
#
|
108
|
+
# Returns Block of code
|
109
|
+
def remove_filter(name)
|
110
|
+
filters.delete(name)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Public: Receiving xml element, and processing it
|
114
|
+
# NOTE: Synchonized by Mutex
|
115
|
+
#
|
116
|
+
# xml - String the string containing xml
|
117
|
+
# proc_object - Proc the proc object to call (default: nil)
|
118
|
+
# block - Block of ruby code
|
119
|
+
#
|
120
|
+
# Returns nothing
|
121
|
+
def send(xml, proc_object = nil, &block)
|
122
|
+
@mutex.synchronize { write_to_socket(xml, proc_object, &block) }
|
123
|
+
end
|
124
|
+
|
125
|
+
# Public: Receiving xml element, and processing it
|
126
|
+
# NOTE: Synchonized by Mutex
|
127
|
+
#
|
128
|
+
# xml_element - ParsedXMLElement the received from socket xml element
|
129
|
+
#
|
130
|
+
# Returns nothing
|
131
|
+
def receive(xml)
|
132
|
+
@mutex.synchronize { process_xml_from_socket(xml) }
|
133
|
+
end
|
134
|
+
|
135
|
+
# Internal: Sends XML data to the socket and (optionally) waits
|
136
|
+
# to process received data.
|
137
|
+
# NOTE: If both habdler and block are given, handler has higher proirity
|
138
|
+
#
|
139
|
+
# xml - String the xml data to send
|
140
|
+
# handler - [Proc|Lambda|#call] the proc object or labda to handle response data (optional)
|
141
|
+
# block - Block the block of ruby code (optional)
|
142
|
+
#
|
143
|
+
# Returns nothing
|
144
|
+
def write_to_socket(xml, handler = nil, &block)
|
145
|
+
Jabber.debug("SENDING:\n#{xml}")
|
146
|
+
|
147
|
+
handler = block if handler.nil?
|
148
|
+
handlers[Thread.current] = handler unless handler.nil?
|
149
|
+
|
150
|
+
socket.write(xml)
|
151
|
+
|
152
|
+
@poll_counter = 10
|
153
|
+
end
|
154
|
+
|
155
|
+
# Internal: Processes a received ParsedXMLElement and executes
|
156
|
+
# registered handlers and filters against it
|
157
|
+
#
|
158
|
+
# xml - ParsedXMLElement The received element
|
159
|
+
#
|
160
|
+
# Returns nothing
|
161
|
+
def process_xml_from_socket(xml)
|
162
|
+
sleep 0.1 while wait_for_consume?
|
163
|
+
|
164
|
+
Jabber.debug("RECEIVED:\n#{xml}")
|
165
|
+
|
166
|
+
consume_xml_by_handlers(xml) || consume_xml_by_filters(xml)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Internal: Processes a received ParsedXMLElement by handlers
|
170
|
+
#
|
171
|
+
# xml - ParsedXMLElement The received element
|
172
|
+
#
|
173
|
+
# Returns boolean
|
174
|
+
def consume_xml_by_handlers(xml)
|
175
|
+
handlers.each do |thread, block|
|
176
|
+
begin
|
177
|
+
block.call(xml)
|
178
|
+
|
179
|
+
if xml.element_consumed?
|
180
|
+
handlers.delete(thread)
|
181
|
+
thread.wakeup if thread.alive?
|
182
|
+
|
183
|
+
return true
|
184
|
+
end
|
185
|
+
rescue Exception => error
|
186
|
+
puts error.to_s
|
187
|
+
puts error.backtrace.join("\n")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
false
|
192
|
+
end
|
193
|
+
|
194
|
+
# Internal: Processes a received ParsedXMLElement by filters
|
195
|
+
#
|
196
|
+
# xml - ParsedXMLElement The received element
|
197
|
+
#
|
198
|
+
# Returns boolean
|
199
|
+
def consume_xml_by_filters(xml)
|
200
|
+
filters.each_value do |block|
|
201
|
+
begin
|
202
|
+
block.call(xml)
|
203
|
+
|
204
|
+
return true if xml.element_consumed?
|
205
|
+
rescue Exception => error
|
206
|
+
puts error.to_s
|
207
|
+
puts error.backtrace.join("\n")
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
false
|
212
|
+
end
|
213
|
+
|
214
|
+
# Internal: Should we wait for next part of socket data
|
215
|
+
#
|
216
|
+
# Returns boolean
|
217
|
+
def wait_for_consume?
|
218
|
+
handlers.size.zero? && filters.size.zero?
|
219
|
+
end
|
220
|
+
|
221
|
+
##
|
222
|
+
# Mounts a block to handle exceptions if they occur during the
|
223
|
+
# poll send. This will likely be the first indication that
|
224
|
+
# the socket dropped in a Jabber Session.
|
225
|
+
#
|
226
|
+
def on_connection_exception(&block)
|
227
|
+
@exception_block = block
|
228
|
+
end
|
229
|
+
|
230
|
+
def parse_failure(exception = nil)
|
231
|
+
Thread.new { @exception_block.call(exception) if @exception_block }
|
232
|
+
end
|
233
|
+
|
234
|
+
############################################################################
|
235
|
+
# All that under needs to be REFACTORED #
|
236
|
+
############################################################################
|
237
|
+
|
238
|
+
##
|
239
|
+
# Starts a polling thread to send "keep alive" data to prevent
|
240
|
+
# the Jabber connection from closing for inactivity.
|
241
|
+
#
|
242
|
+
def poll
|
243
|
+
sleep 10
|
244
|
+
while true
|
245
|
+
sleep 2
|
246
|
+
@poll_counter = @poll_counter - 1
|
247
|
+
if @poll_counter < 0
|
248
|
+
begin
|
249
|
+
send(" \t ")
|
250
|
+
rescue
|
251
|
+
Thread.new {@exception_block.call if @exception_block}
|
252
|
+
break
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
@@ -0,0 +1,61 @@
|
|
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 "singleton"
|
9
|
+
require "logger"
|
10
|
+
|
11
|
+
module Jabber
|
12
|
+
# Produces debug methods
|
13
|
+
#
|
14
|
+
# Example
|
15
|
+
#
|
16
|
+
# def warn(message)
|
17
|
+
# Debug.instance.send(:warn, message)
|
18
|
+
# end
|
19
|
+
# module_function m
|
20
|
+
[:warn, :debug, :info].each do |m|
|
21
|
+
define_method(m) do |message|
|
22
|
+
Debugger.send(m, message)
|
23
|
+
end
|
24
|
+
module_function m
|
25
|
+
end
|
26
|
+
|
27
|
+
class Debugger
|
28
|
+
include Singleton
|
29
|
+
|
30
|
+
attr_accessor :enabled, :logger
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@logger = Logger.new(STDOUT)
|
34
|
+
@enabled = false
|
35
|
+
end
|
36
|
+
|
37
|
+
class << self
|
38
|
+
def logger=(logger)
|
39
|
+
instance.logger = logger
|
40
|
+
end
|
41
|
+
|
42
|
+
def enable!
|
43
|
+
instance.enabled = true
|
44
|
+
end
|
45
|
+
|
46
|
+
def disable!
|
47
|
+
instance.enabled = false
|
48
|
+
end
|
49
|
+
|
50
|
+
def enabled?
|
51
|
+
instance.enabled
|
52
|
+
end
|
53
|
+
|
54
|
+
[:warn, :debug, :info].each do |m|
|
55
|
+
define_method(m) do |message|
|
56
|
+
enabled? && instance.logger.send(m, message)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end # class << self
|
60
|
+
end
|
61
|
+
end
|
data/lib/jabber4r/jid.rb
ADDED
@@ -0,0 +1,125 @@
|
|
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
|
8
|
+
# The Jabber ID class is used to hold a parsed jabber identifier (account+host+resource)
|
9
|
+
class JID
|
10
|
+
PATTERN = /^(?:(?<node>[^@]*)@)??(?<host>[^@\/]*)(?:\/(?<resource>.*?))?$/.freeze
|
11
|
+
|
12
|
+
# The node (account)
|
13
|
+
attr_accessor :node
|
14
|
+
|
15
|
+
# The resource id
|
16
|
+
attr_accessor :resource
|
17
|
+
|
18
|
+
# The host name (or IP address)
|
19
|
+
attr_accessor :host
|
20
|
+
|
21
|
+
# Public: Convert something to Jabber::JID
|
22
|
+
#
|
23
|
+
# jid - [String|Jabber::JID] the jid of future Jabber::JID
|
24
|
+
#
|
25
|
+
# Returns Jabber::JID
|
26
|
+
def self.to_jid(jid)
|
27
|
+
return jid if jid.kind_of? self
|
28
|
+
|
29
|
+
new jid
|
30
|
+
end
|
31
|
+
|
32
|
+
# Constructs a JID from the supplied string of the format:
|
33
|
+
# node@host[/resource] (e.g. "rich_kilmer@jabber.com/laptop")
|
34
|
+
#
|
35
|
+
# jid - String the jabber id string to parse
|
36
|
+
# host - String the host of jabber server (optional)
|
37
|
+
# resource - String the resource of jabber id (optional)
|
38
|
+
#
|
39
|
+
# Examples
|
40
|
+
#
|
41
|
+
# jid = Jabber::JID.new("strech@localhost/attach")
|
42
|
+
# jid.node # => "strech"
|
43
|
+
# jid.host # => "localhost"
|
44
|
+
# jid.resource # => "attach"
|
45
|
+
#
|
46
|
+
# Raises ArgumentError
|
47
|
+
# Returns nothing
|
48
|
+
def initialize(jid, host = nil, resource = nil)
|
49
|
+
raise ArgumentError, "Node can't be empty" if jid.to_s.empty?
|
50
|
+
|
51
|
+
@node, @host, @resource = self.class.parse(jid)
|
52
|
+
@node, @host = @host, nil if @node.nil? && @host
|
53
|
+
|
54
|
+
@host = host unless host.nil?
|
55
|
+
@resource = resource unless resource.nil?
|
56
|
+
|
57
|
+
raise ArgumentError, "Couldn't create JID without host" if @host.to_s.empty?
|
58
|
+
end
|
59
|
+
|
60
|
+
# Public: Evalutes whether the node, resource and host are the same
|
61
|
+
#
|
62
|
+
# jid - Jabber::JID the other jabber id
|
63
|
+
#
|
64
|
+
# Returns boolean
|
65
|
+
def ==(jid)
|
66
|
+
jid.to_s == self.to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
# Public: Compare accounts without resources
|
70
|
+
#
|
71
|
+
# jid - Jabber::JID the other jabber id
|
72
|
+
#
|
73
|
+
# Returns boolean
|
74
|
+
def same?(jid)
|
75
|
+
other_jid = self.class.to_jid(jid)
|
76
|
+
|
77
|
+
other_jid.node == node && other_jid.host == host
|
78
|
+
end
|
79
|
+
|
80
|
+
# Public: Strip resource from jid and return new object
|
81
|
+
#
|
82
|
+
# Returns Jabber::JID
|
83
|
+
def strip
|
84
|
+
self.class.new(node, host)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Public: Strip resource from jid and return the same object
|
88
|
+
#
|
89
|
+
# Returns Jabber::JID
|
90
|
+
def strip!
|
91
|
+
@resource = nil
|
92
|
+
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
# Public: String representation of JID
|
97
|
+
#
|
98
|
+
# Returns String
|
99
|
+
def to_s
|
100
|
+
["#{node}@#{host}", resource].compact.join "/"
|
101
|
+
end
|
102
|
+
|
103
|
+
# Public: Override #hash to hash based on the to_s method
|
104
|
+
#
|
105
|
+
# Returns Fixnum
|
106
|
+
def hash
|
107
|
+
to_s.hash
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
# Internal: Parse jid string for node, host, resource
|
112
|
+
#
|
113
|
+
# jid - String jabber id
|
114
|
+
#
|
115
|
+
# Examples
|
116
|
+
#
|
117
|
+
# result = Jabber::JID.parse("strech@localhost/pewsource")
|
118
|
+
# result # => ["strech", "localhost", "pewsource"]
|
119
|
+
#
|
120
|
+
# Rerturns Array
|
121
|
+
def self.parse(jid)
|
122
|
+
jid.match(PATTERN).captures
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +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
|
260
|
+
end
|