xmpp4r 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +340 -0
- data/ChangeLog +28 -0
- data/LICENSE +59 -0
- data/README +20 -0
- data/Rakefile +103 -0
- data/UPDATING +40 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/README +57 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/adventure.rb +23 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/adventuremuc.rb +136 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/cube.xml +15 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/tower.xml +69 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/world.rb +425 -0
- data/data/doc/xmpp4r/examples/advanced/fileserve.conf +11 -0
- data/data/doc/xmpp4r/examples/advanced/fileserve.rb +344 -0
- data/data/doc/xmpp4r/examples/advanced/getonline.rb +56 -0
- data/data/doc/xmpp4r/examples/advanced/gtkmucclient.rb +315 -0
- data/data/doc/xmpp4r/examples/advanced/migrate.rb +89 -0
- data/data/doc/xmpp4r/examples/advanced/minimuc.rb +266 -0
- data/data/doc/xmpp4r/examples/advanced/recvfile.rb +83 -0
- data/data/doc/xmpp4r/examples/advanced/rosterdiscovery.rb +130 -0
- data/data/doc/xmpp4r/examples/advanced/sendfile.conf +10 -0
- data/data/doc/xmpp4r/examples/advanced/sendfile.rb +72 -0
- data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr.rb +51 -0
- data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_jabber.rb +43 -0
- data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_test.rb +10 -0
- data/data/doc/xmpp4r/examples/advanced/versionpoll.rb +90 -0
- data/data/doc/xmpp4r/examples/advanced/xmpping.rb +134 -0
- data/data/doc/xmpp4r/examples/advanced/xmppingrc.sample +9 -0
- data/data/doc/xmpp4r/examples/basic/change_password.rb +41 -0
- data/data/doc/xmpp4r/examples/basic/client.rb +68 -0
- data/data/doc/xmpp4r/examples/basic/component.rb +11 -0
- data/data/doc/xmpp4r/examples/basic/echo_nonthreaded.rb +32 -0
- data/data/doc/xmpp4r/examples/basic/echo_threaded.rb +32 -0
- data/data/doc/xmpp4r/examples/basic/jabbersend.rb +41 -0
- data/data/doc/xmpp4r/examples/basic/mass_sender.rb +67 -0
- data/data/doc/xmpp4r/examples/basic/mucinfo.rb +39 -0
- data/data/doc/xmpp4r/examples/basic/mucsimplebot.rb +83 -0
- data/data/doc/xmpp4r/examples/basic/register.rb +25 -0
- data/data/doc/xmpp4r/examples/basic/remove_registration.rb +18 -0
- data/data/doc/xmpp4r/examples/basic/roster.rb +42 -0
- data/data/doc/xmpp4r/examples/basic/rosterprint.rb +50 -0
- data/data/doc/xmpp4r/examples/basic/rosterrename.rb +34 -0
- data/data/doc/xmpp4r/examples/basic/rosterwatch.rb +172 -0
- data/data/doc/xmpp4r/examples/basic/send_vcard.rb +68 -0
- data/data/doc/xmpp4r/examples/basic/versionbot.rb +75 -0
- data/data/doc/xmpp4r/examples/buggy/jabber2jabber/jabber2jabber.rb +18 -0
- data/data/doc/xmpp4r/examples/buggy/miniedgarr_cgi.rb +192 -0
- data/data/doc/xmpp4r/examples/buggy/miniedgarr_watch.rb +82 -0
- data/lib/callbacks.rb +122 -0
- data/lib/xmpp4r/authenticationfailure.rb +13 -0
- data/lib/xmpp4r/bytestreams/helper/filetransfer.rb +315 -0
- data/lib/xmpp4r/bytestreams/helper/ibb/base.rb +256 -0
- data/lib/xmpp4r/bytestreams/helper/ibb/initiator.rb +30 -0
- data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +46 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb +151 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb +85 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb +178 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb +56 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +61 -0
- data/lib/xmpp4r/bytestreams/iq/bytestreams.rb +177 -0
- data/lib/xmpp4r/bytestreams/iq/si.rb +221 -0
- data/lib/xmpp4r/bytestreams.rb +11 -0
- data/lib/xmpp4r/client.rb +249 -0
- data/lib/xmpp4r/component.rb +103 -0
- data/lib/xmpp4r/connection.rb +166 -0
- data/lib/xmpp4r/dataforms/x/data.rb +248 -0
- data/lib/xmpp4r/dataforms.rb +1 -0
- data/lib/xmpp4r/debuglog.rb +34 -0
- data/lib/xmpp4r/delay/x/delay.rb +100 -0
- data/lib/xmpp4r/delay.rb +1 -0
- data/lib/xmpp4r/discovery/iq/discoinfo.rb +225 -0
- data/lib/xmpp4r/discovery/iq/discoitems.rb +162 -0
- data/lib/xmpp4r/discovery.rb +2 -0
- data/lib/xmpp4r/error.rb +230 -0
- data/lib/xmpp4r/errorexception.rb +32 -0
- data/lib/xmpp4r/feature_negotiation/iq/feature.rb +42 -0
- data/lib/xmpp4r/feature_negotiation.rb +1 -0
- data/lib/xmpp4r/idgenerator.rb +37 -0
- data/lib/xmpp4r/iq.rb +229 -0
- data/lib/xmpp4r/jid.rb +167 -0
- data/lib/xmpp4r/message.rb +171 -0
- data/lib/xmpp4r/muc/helper/mucbrowser.rb +107 -0
- data/lib/xmpp4r/muc/helper/mucclient.rb +382 -0
- data/lib/xmpp4r/muc/helper/simplemucclient.rb +222 -0
- data/lib/xmpp4r/muc/x/muc.rb +98 -0
- data/lib/xmpp4r/muc/x/mucuserinvite.rb +58 -0
- data/lib/xmpp4r/muc/x/mucuseritem.rb +148 -0
- data/lib/xmpp4r/muc.rb +6 -0
- data/lib/xmpp4r/presence.rb +255 -0
- data/lib/xmpp4r/query.rb +43 -0
- data/lib/xmpp4r/rexmladdons.rb +826 -0
- data/lib/xmpp4r/roster/helper/roster.rb +514 -0
- data/lib/xmpp4r/roster/iq/roster.rb +244 -0
- data/lib/xmpp4r/roster/x/roster.rb +155 -0
- data/lib/xmpp4r/roster.rb +4 -0
- data/lib/xmpp4r/sasl.rb +167 -0
- data/lib/xmpp4r/stream.rb +543 -0
- data/lib/xmpp4r/streamparser.rb +77 -0
- data/lib/xmpp4r/vcard/helper/vcard.rb +86 -0
- data/lib/xmpp4r/vcard/iq/vcard.rb +102 -0
- data/lib/xmpp4r/vcard.rb +3 -0
- data/lib/xmpp4r/version/helper/responder.rb +71 -0
- data/lib/xmpp4r/version/helper/simpleresponder.rb +44 -0
- data/lib/xmpp4r/version/iq/version.rb +118 -0
- data/lib/xmpp4r/version.rb +3 -0
- data/lib/xmpp4r/x.rb +43 -0
- data/lib/xmpp4r/xmlstanza.rb +174 -0
- data/lib/xmpp4r/xmpp4r.rb +16 -0
- data/lib/xmpp4r.rb +122 -0
- data/setup.rb +1360 -0
- data/test/bytestreams/tc_ibb.rb +186 -0
- data/test/bytestreams/tc_socks5bytestreams.rb +57 -0
- data/test/delay/tc_xdelay.rb +51 -0
- data/test/lib/clienttester.rb +110 -0
- data/test/muc/tc_muc_mucclient.rb +569 -0
- data/test/muc/tc_muc_simplemucclient.rb +72 -0
- data/test/roster/.tc_helper.rb.swp +0 -0
- data/test/roster/tc_helper.rb +389 -0
- data/test/roster/tc_iqqueryroster.rb +140 -0
- data/test/roster/tc_xroster.rb +70 -0
- data/test/tc_callbacks.rb +128 -0
- data/test/tc_class_names.rb +129 -0
- data/test/tc_client.rb +30 -0
- data/test/tc_error.rb +103 -0
- data/test/tc_idgenerator.rb +30 -0
- data/test/tc_iq.rb +109 -0
- data/test/tc_iqquery.rb +31 -0
- data/test/tc_jid.rb +202 -0
- data/test/tc_message.rb +114 -0
- data/test/tc_presence.rb +148 -0
- data/test/tc_stream.rb +182 -0
- data/test/tc_streamError.rb +87 -0
- data/test/tc_streamSend.rb +59 -0
- data/test/tc_streamThreaded.rb +168 -0
- data/test/tc_xmlstanza.rb +76 -0
- data/test/ts_xmpp4r.rb +34 -0
- data/test/vcard/tc_iqvcard.rb +52 -0
- data/test/version/tc_helper.rb +46 -0
- data/test/version/tc_iqqueryversion.rb +96 -0
- data/tools/doctoweb.bash +30 -0
- data/tools/gen_requires.bash +10 -0
- metadata +232 -0
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'time' # For Time#xmlschema
|
2
|
+
|
3
|
+
require 'xmpp4r/feature_negotiation/iq/feature'
|
4
|
+
|
5
|
+
module Jabber
|
6
|
+
module Bytestreams
|
7
|
+
##
|
8
|
+
# Iq child 'si' for Stream-Initiation
|
9
|
+
class IqSi < REXML::Element
|
10
|
+
PROFILE_FILETRANSFER = 'http://jabber.org/protocol/si/profile/file-transfer'
|
11
|
+
|
12
|
+
def initialize(id=nil, profile=nil, mime_type=nil)
|
13
|
+
super('si')
|
14
|
+
|
15
|
+
add_namespace 'http://jabber.org/protocol/si'
|
16
|
+
self.id = id
|
17
|
+
self.profile = profile
|
18
|
+
self.mime_type = mime_type
|
19
|
+
end
|
20
|
+
|
21
|
+
def IqSi.import(element)
|
22
|
+
IqSi::new.import(element)
|
23
|
+
end
|
24
|
+
|
25
|
+
def typed_add(element)
|
26
|
+
if element.kind_of?(REXML::Element) and element.name == 'file'
|
27
|
+
super IqSiFile.new.import(element)
|
28
|
+
elsif element.kind_of?(REXML::Element) and element.name == 'feature'
|
29
|
+
super FeatureNegotiation::IqFeature.new.import(element)
|
30
|
+
else
|
31
|
+
super element
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Session ID of this stream
|
37
|
+
def id
|
38
|
+
attributes['id']
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Set Session ID of this stream
|
43
|
+
def id=(s)
|
44
|
+
attributes['id'] = s
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# MIME type of this stream
|
49
|
+
def mime_type
|
50
|
+
attributes['mime-type']
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Set MIME type of this stream
|
55
|
+
def mime_type=(s)
|
56
|
+
attributes['mime-type'] = s
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Stream profile, can indicate file-transfer
|
61
|
+
def profile
|
62
|
+
attributes['profile']
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Set stream profile
|
67
|
+
def profile=(s)
|
68
|
+
attributes['profile'] = s
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# <file/> child
|
73
|
+
# result:: [IqSiFile]
|
74
|
+
def file
|
75
|
+
first_element('file')
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# <feature/> child
|
80
|
+
# result:: [IqFeature]
|
81
|
+
def feature
|
82
|
+
first_element('feature')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
Iq.add_elementclass('si', IqSi)
|
87
|
+
|
88
|
+
##
|
89
|
+
# File-transfer meta-information,
|
90
|
+
# may appear as <file/> in IqSi
|
91
|
+
class IqSiFile < REXML::Element
|
92
|
+
def initialize(fname=nil, size=nil)
|
93
|
+
super 'file'
|
94
|
+
add_namespace IqSi::PROFILE_FILETRANSFER
|
95
|
+
self.fname = fname
|
96
|
+
self.size = size
|
97
|
+
end
|
98
|
+
|
99
|
+
def typed_add(element)
|
100
|
+
if element.kind_of?(REXML::Element) and element.name == 'range'
|
101
|
+
super IqSiFileRange.new.import(element)
|
102
|
+
else
|
103
|
+
super element
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Get filename (attribute 'name')
|
109
|
+
def fname
|
110
|
+
attributes['name']
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Set filename (attribute 'name')
|
115
|
+
def fname=(s)
|
116
|
+
attributes['name'] = s
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# Get MD5 hash
|
121
|
+
def hash
|
122
|
+
attributes['hash']
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Set MD5 hash
|
127
|
+
def hash=(s)
|
128
|
+
attributes['hash'] = s
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# Get file date
|
133
|
+
# result:: [Time] or nil
|
134
|
+
def date
|
135
|
+
begin
|
136
|
+
Time.xmlschema(attributes['date'])
|
137
|
+
rescue ArgumentError
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# Set file date
|
144
|
+
# d:: [Time] or nil
|
145
|
+
def date=(d)
|
146
|
+
attributes['date'] = (d ? d.xmlschema : nil)
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# File size in bytes
|
151
|
+
# result:: [Fixnum]
|
152
|
+
def size
|
153
|
+
(attributes['size'] =~ /^\d+$/) ? attributes['size'].to_i : nil
|
154
|
+
end
|
155
|
+
|
156
|
+
##
|
157
|
+
# Set file size
|
158
|
+
def size=(s)
|
159
|
+
attributes['size'] = s ? s.to_s : nil
|
160
|
+
end
|
161
|
+
|
162
|
+
##
|
163
|
+
# File description
|
164
|
+
def description
|
165
|
+
first_element_text('desc')
|
166
|
+
end
|
167
|
+
|
168
|
+
##
|
169
|
+
# Set file description
|
170
|
+
def description=(s)
|
171
|
+
replace_element_text('desc', s)
|
172
|
+
end
|
173
|
+
|
174
|
+
##
|
175
|
+
# <range/> child
|
176
|
+
#
|
177
|
+
# A file-transfer offer may contain this with
|
178
|
+
# no attributes set, indicating the ability to
|
179
|
+
# do ranged transfers.
|
180
|
+
# result:: [IqSiFileRange]
|
181
|
+
def range
|
182
|
+
first_element('range')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# Information for ranged transfers
|
188
|
+
class IqSiFileRange < REXML::Element
|
189
|
+
def initialize(offset=nil, length=nil)
|
190
|
+
super('range')
|
191
|
+
|
192
|
+
self.offset = offset
|
193
|
+
self.length = length
|
194
|
+
end
|
195
|
+
|
196
|
+
##
|
197
|
+
# File offset (for continuing an interrupted transfer)
|
198
|
+
def offset
|
199
|
+
(attributes['offset'] =~ /^\d+$/) ? attributes['offset'].to_i : nil
|
200
|
+
end
|
201
|
+
|
202
|
+
##
|
203
|
+
# Set file offset
|
204
|
+
def offset=(o)
|
205
|
+
attributes['offset'] = (o ? o.to_s : nil)
|
206
|
+
end
|
207
|
+
|
208
|
+
##
|
209
|
+
# File length (if not to transfer whole file)
|
210
|
+
def length
|
211
|
+
(attributes['length'] =~ /^\d+$/) ? attributes['length'].to_i : nil
|
212
|
+
end
|
213
|
+
|
214
|
+
##
|
215
|
+
# Set file length
|
216
|
+
def length=(o)
|
217
|
+
attributes['length'] = (o ? o.to_s : nil)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'xmpp4r/bytestreams/iq/si.rb'
|
2
|
+
require 'xmpp4r/bytestreams/iq/bytestreams.rb'
|
3
|
+
require 'xmpp4r/bytestreams/helper/ibb/base.rb'
|
4
|
+
require 'xmpp4r/bytestreams/helper/ibb/initiator.rb'
|
5
|
+
require 'xmpp4r/bytestreams/helper/ibb/target.rb'
|
6
|
+
require 'xmpp4r/bytestreams/helper/filetransfer.rb'
|
7
|
+
require 'xmpp4r/bytestreams/helper/socks5bytestreams/base.rb'
|
8
|
+
require 'xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb'
|
9
|
+
require 'xmpp4r/bytestreams/helper/socks5bytestreams/server.rb'
|
10
|
+
require 'xmpp4r/bytestreams/helper/socks5bytestreams/target.rb'
|
11
|
+
require 'xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb'
|
@@ -0,0 +1,249 @@
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
2
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
3
|
+
# Website::http://home.gna.org/xmpp4r/
|
4
|
+
|
5
|
+
require 'resolv'
|
6
|
+
|
7
|
+
require 'xmpp4r/connection'
|
8
|
+
require 'xmpp4r/authenticationfailure'
|
9
|
+
require 'xmpp4r/sasl'
|
10
|
+
|
11
|
+
module Jabber
|
12
|
+
|
13
|
+
# The client class provides everything needed to build a basic XMPP
|
14
|
+
# Client.
|
15
|
+
#
|
16
|
+
# If you want your connection to survive disconnects and timeouts,
|
17
|
+
# catch exception in Stream#on_exception and re-call Client#connect
|
18
|
+
# and Client#auth. Don't forget to re-send initial Presence and
|
19
|
+
# everything else you need to setup your session.
|
20
|
+
class Client < Connection
|
21
|
+
|
22
|
+
# The client's JID
|
23
|
+
attr_reader :jid
|
24
|
+
|
25
|
+
##
|
26
|
+
# Create a new Client. If threaded mode is activated, callbacks are called
|
27
|
+
# as soon as messages are received; If it isn't, you have to call
|
28
|
+
# Stream#process from time to time.
|
29
|
+
#
|
30
|
+
# Remember to *always* put a resource in your JID unless the server can do SASL.
|
31
|
+
def initialize(jid, threaded = true)
|
32
|
+
super(threaded)
|
33
|
+
@jid = (jid.kind_of?(JID) ? jid : JID.new(jid.to_s))
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# connect to the server
|
38
|
+
# (chaining-friendly)
|
39
|
+
#
|
40
|
+
# If you omit the optional host argument SRV records for your jid will
|
41
|
+
# be resolved. If none works, fallback is connecting to the domain part
|
42
|
+
# of the jid.
|
43
|
+
# host:: [String] Optional c2s host, will be extracted from jid if nil
|
44
|
+
# return:: self
|
45
|
+
def connect(host = nil, port = 5222)
|
46
|
+
if host.nil?
|
47
|
+
begin
|
48
|
+
srv = []
|
49
|
+
Resolv::DNS.open { |dns|
|
50
|
+
# If ruby version is too old and SRV is unknown, this will raise a NameError
|
51
|
+
# which is catched below
|
52
|
+
Jabber::debuglog("RESOLVING:\n_xmpp-client._tcp.#{@jid.domain} (SRV)")
|
53
|
+
srv = dns.getresources("_xmpp-client._tcp.#{@jid.domain}", Resolv::DNS::Resource::IN::SRV)
|
54
|
+
}
|
55
|
+
# Sort SRV records: lowest priority first, highest weight first
|
56
|
+
srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
|
57
|
+
|
58
|
+
srv.each { |record|
|
59
|
+
begin
|
60
|
+
connect(record.target.to_s, record.port)
|
61
|
+
# Success
|
62
|
+
return self
|
63
|
+
rescue SocketError
|
64
|
+
# Try next SRV record
|
65
|
+
end
|
66
|
+
}
|
67
|
+
rescue NameError
|
68
|
+
$stderr.puts "Resolv::DNS does not support SRV records. Please upgrade to ruby-1.8.3 or later!"
|
69
|
+
end
|
70
|
+
# Fallback to normal connect method
|
71
|
+
end
|
72
|
+
|
73
|
+
super(host.nil? ? jid.domain : host, port)
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Close the connection,
|
79
|
+
# sends <tt></stream:stream></tt> tag first
|
80
|
+
def close
|
81
|
+
send("</stream:stream>")
|
82
|
+
super
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Start the stream-parser and send the client-specific stream opening element
|
87
|
+
def start
|
88
|
+
super
|
89
|
+
send(generate_stream_start(@jid.domain)) { |e|
|
90
|
+
if e.name == 'stream'
|
91
|
+
true
|
92
|
+
else
|
93
|
+
false
|
94
|
+
end
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Authenticate with the server
|
100
|
+
#
|
101
|
+
# Throws AuthenticationFailure
|
102
|
+
#
|
103
|
+
# Authentication mechanisms are used in the following preference:
|
104
|
+
# * SASL DIGEST-MD5
|
105
|
+
# * SASL PLAIN
|
106
|
+
# * Non-SASL digest
|
107
|
+
# password:: [String]
|
108
|
+
def auth(password)
|
109
|
+
begin
|
110
|
+
if @stream_mechanisms.include? 'DIGEST-MD5'
|
111
|
+
auth_sasl SASL.new(self, 'DIGEST-MD5'), password
|
112
|
+
elsif @stream_mechanisms.include? 'PLAIN'
|
113
|
+
auth_sasl SASL.new(self, 'PLAIN'), password
|
114
|
+
else
|
115
|
+
auth_nonsasl(password)
|
116
|
+
end
|
117
|
+
rescue
|
118
|
+
Jabber::debuglog("#{$!.class}: #{$!}\n#{$!.backtrace.join("\n")}")
|
119
|
+
raise AuthenticationFailure.new, $!.to_s
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# Use a SASL authentication mechanism and bind to a resource
|
125
|
+
#
|
126
|
+
# If there was no resource given in the jid, the jid/resource
|
127
|
+
# generated by the server will be accepted.
|
128
|
+
#
|
129
|
+
# This method should not be used directly. Instead, Client#auth
|
130
|
+
# may look for the best mechanism suitable.
|
131
|
+
# sasl:: Descendant of [Jabber::SASL::Base]
|
132
|
+
# password:: [String]
|
133
|
+
def auth_sasl(sasl, password)
|
134
|
+
sasl.auth(password)
|
135
|
+
|
136
|
+
# Restart stream after SASL auth
|
137
|
+
stop
|
138
|
+
start
|
139
|
+
# And wait for features - again
|
140
|
+
@features_lock.lock
|
141
|
+
@features_lock.unlock
|
142
|
+
|
143
|
+
# Resource binding (RFC3920 - 7)
|
144
|
+
if @stream_features.has_key? 'bind'
|
145
|
+
iq = Iq.new(:set)
|
146
|
+
bind = iq.add REXML::Element.new('bind')
|
147
|
+
bind.add_namespace @stream_features['bind']
|
148
|
+
if jid.resource
|
149
|
+
resource = bind.add REXML::Element.new('resource')
|
150
|
+
resource.text = jid.resource
|
151
|
+
end
|
152
|
+
|
153
|
+
send_with_id(iq) { |reply|
|
154
|
+
reported_jid = reply.first_element('jid')
|
155
|
+
if reply.type == :result and reported_jid and reported_jid.text
|
156
|
+
@jid = JID.new(reported_jid.text)
|
157
|
+
end
|
158
|
+
|
159
|
+
true
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
# Session starting
|
164
|
+
if @stream_features.has_key? 'session'
|
165
|
+
iq = Iq.new(:set)
|
166
|
+
session = iq.add REXML::Element.new('session')
|
167
|
+
session.add_namespace @stream_features['session']
|
168
|
+
|
169
|
+
send_with_id(iq) { true }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# Send auth with given password and wait for result
|
175
|
+
# (non-SASL)
|
176
|
+
#
|
177
|
+
# Throws ErrorException
|
178
|
+
# password:: [String] the password
|
179
|
+
# digest:: [Boolean] use Digest authentication
|
180
|
+
def auth_nonsasl(password, digest=true)
|
181
|
+
authset = nil
|
182
|
+
if digest
|
183
|
+
authset = Iq::new_authset_digest(@jid, @streamid.to_s, password)
|
184
|
+
else
|
185
|
+
authset = Iq::new_authset(@jid, password)
|
186
|
+
end
|
187
|
+
send_with_id(authset) do |r|
|
188
|
+
true
|
189
|
+
end
|
190
|
+
$defout.flush
|
191
|
+
|
192
|
+
true
|
193
|
+
end
|
194
|
+
|
195
|
+
##
|
196
|
+
# Register a new user account
|
197
|
+
# (may be used instead of Client#auth)
|
198
|
+
#
|
199
|
+
# This method may raise ErrorException if the registration was
|
200
|
+
# not successful.
|
201
|
+
def register(password)
|
202
|
+
reg = Iq.new_register(jid.node, password)
|
203
|
+
reg.to = jid.domain
|
204
|
+
send_with_id(reg) { |answer|
|
205
|
+
true
|
206
|
+
}
|
207
|
+
end
|
208
|
+
|
209
|
+
##
|
210
|
+
# Remove the registration of a user account
|
211
|
+
#
|
212
|
+
# *WARNING:* this deletes your roster and everything else
|
213
|
+
# stored on the server!
|
214
|
+
def remove_registration
|
215
|
+
reg = Iq.new_register
|
216
|
+
reg.to = jid.domain
|
217
|
+
reg.query.add(REXML::Element.new('remove'))
|
218
|
+
send_with_id(reg) { |answer|
|
219
|
+
p answer.to_s
|
220
|
+
true
|
221
|
+
}
|
222
|
+
end
|
223
|
+
|
224
|
+
##
|
225
|
+
# Change the client's password
|
226
|
+
#
|
227
|
+
# Threading is suggested, as this code waits
|
228
|
+
# for an answer.
|
229
|
+
#
|
230
|
+
# Raises an exception upon error response (ErrorException from
|
231
|
+
# Stream#send_with_id).
|
232
|
+
# new_password:: [String] New password
|
233
|
+
def password=(new_password)
|
234
|
+
iq = Iq::new_query(:set, @jid.domain)
|
235
|
+
iq.query.add_namespace('jabber:iq:register')
|
236
|
+
iq.query.add(REXML::Element.new('username')).text = @jid.node
|
237
|
+
iq.query.add(REXML::Element.new('password')).text = new_password
|
238
|
+
|
239
|
+
err = nil
|
240
|
+
send_with_id(iq) { |answer|
|
241
|
+
if answer.type == :result
|
242
|
+
true
|
243
|
+
else
|
244
|
+
false
|
245
|
+
end
|
246
|
+
}
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
2
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
3
|
+
# Website::http://home.gna.org/xmpp4r/
|
4
|
+
|
5
|
+
require 'xmpp4r/connection'
|
6
|
+
|
7
|
+
module Jabber
|
8
|
+
##
|
9
|
+
# The component class provides everything needed to build a XMPP Component.
|
10
|
+
#
|
11
|
+
# Components are more flexible as they are only restricted in the use of a
|
12
|
+
# fixed domain. node and resource of JIDs are freely choosable for all stanzas.
|
13
|
+
class Component < Connection
|
14
|
+
|
15
|
+
# The component's JID
|
16
|
+
attr_reader :jid
|
17
|
+
|
18
|
+
# The server's address
|
19
|
+
attr_reader :server_address
|
20
|
+
|
21
|
+
# The server's port
|
22
|
+
attr_reader :server_port
|
23
|
+
|
24
|
+
# Create a new Component
|
25
|
+
# jid:: [JID]
|
26
|
+
def initialize(jid, server_address=nil, server_port=5347, threaded = true)
|
27
|
+
super(threaded)
|
28
|
+
@jid = (jid.kind_of?(JID) ? jid : JID.new(jid.to_s))
|
29
|
+
|
30
|
+
if server_address
|
31
|
+
$stderr.puts "Passing server and port to Jabber::Component::new is " +
|
32
|
+
"obsolete and will vanish in some later XMPP4R release. " +
|
33
|
+
"Please use these arguments when calling " +
|
34
|
+
"Jabber::Client#connect"
|
35
|
+
@server_address = server_address
|
36
|
+
@server_port = server_port
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Connect to the server
|
41
|
+
# (chaining-friendly)
|
42
|
+
# server:: [String] Hostname
|
43
|
+
# port:: [Integer] TCP port (5347)
|
44
|
+
# return:: self
|
45
|
+
def connect(server=nil, port=5347)
|
46
|
+
if server
|
47
|
+
super(server, port)
|
48
|
+
else
|
49
|
+
super(@server_address, @server_port)
|
50
|
+
end
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Close the connection,
|
56
|
+
# sends <tt></stream:stream></tt> tag first
|
57
|
+
def close
|
58
|
+
send("</stream:stream>")
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
62
|
+
def generate_stream_start(to=nil, from=nil, id=nil, xml_lang="en", xmlns="jabber:component:accept", version="1.0")
|
63
|
+
super
|
64
|
+
end
|
65
|
+
private :generate_stream_start
|
66
|
+
|
67
|
+
##
|
68
|
+
# Start the stream-parser and send the component-specific stream opening element
|
69
|
+
def start
|
70
|
+
super
|
71
|
+
send(generate_stream_start(@jid)) { |e|
|
72
|
+
if e.name == 'stream'
|
73
|
+
true
|
74
|
+
else
|
75
|
+
false
|
76
|
+
end
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Send auth with given secret and wait for result
|
82
|
+
#
|
83
|
+
# Throws AuthenticationFailure
|
84
|
+
# secret:: [String] the shared secret
|
85
|
+
def auth(secret)
|
86
|
+
hash = Digest::SHA1::new(@streamid.to_s + secret).to_s
|
87
|
+
authenticated = false
|
88
|
+
send("<handshake>#{hash}</handshake>") { |r|
|
89
|
+
if r.prefix == 'stream' and r.name == 'error'
|
90
|
+
true
|
91
|
+
elsif r.name == 'handshake'
|
92
|
+
authenticated = true
|
93
|
+
true
|
94
|
+
else
|
95
|
+
false
|
96
|
+
end
|
97
|
+
}
|
98
|
+
unless authenticated
|
99
|
+
raise AuthenticationFailure.new, "Component authentication failed"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|