| Class | Jabber::Client |
| In: |
lib/xmpp4r/client.rb
|
| Parent: | Connection |
The client class provides everything needed to build a basic XMPP Client.
If you want your connection to survive disconnects and timeouts, catch exception in Stream#on_exception and re-call Client#connect and Client#auth. Don‘t forget to re-send initial Presence and everything else you need to setup your session.
| jid | [R] | The client‘s JID |
Authenticate with the server
Throws AuthenticationFailure
Authentication mechanisms are used in the following preference:
| password: | [String] |
# File lib/xmpp4r/client.rb, line 106
106: def auth(password)
107: begin
108: if @stream_mechanisms.include? 'DIGEST-MD5'
109: auth_sasl SASL.new(self, 'DIGEST-MD5'), password
110: elsif @stream_mechanisms.include? 'PLAIN'
111: auth_sasl SASL.new(self, 'PLAIN'), password
112: else
113: auth_nonsasl(password)
114: end
115: rescue
116: Jabber::debuglog("#{$!.class}: #{$!}\n#{$!.backtrace.join("\n")}")
117: raise AuthenticationFailure.new, $!.to_s
118: end
119: end
Send auth with given password and wait for result (non-SASL)
Throws ErrorException
| password: | [String] the password |
| digest: | [Boolean] use Digest authentication |
# File lib/xmpp4r/client.rb, line 177
177: def auth_nonsasl(password, digest=true)
178: authset = nil
179: if digest
180: authset = Iq::new_authset_digest(@jid, @streamid.to_s, password)
181: else
182: authset = Iq::new_authset(@jid, password)
183: end
184: send_with_id(authset) do |r|
185: true
186: end
187: $defout.flush
188:
189: true
190: end
Use a SASL authentication mechanism and bind to a resource
If there was no resource given in the jid, the jid/resource generated by the server will be accepted.
This method should not be used directly. Instead, Client#auth may look for the best mechanism suitable.
| sasl: | Descendant of [Jabber::SASL::Base] |
| password: | [String] |
# File lib/xmpp4r/client.rb, line 131
131: def auth_sasl(sasl, password)
132: sasl.auth(password)
133:
134: # Restart stream after SASL auth
135: stop
136: start
137: # And wait for features - again
138: @features_sem.wait
139:
140: # Resource binding (RFC3920 - 7)
141: if @stream_features.has_key? 'bind'
142: iq = Iq.new(:set)
143: bind = iq.add REXML::Element.new('bind')
144: bind.add_namespace @stream_features['bind']
145: if jid.resource
146: resource = bind.add REXML::Element.new('resource')
147: resource.text = jid.resource
148: end
149:
150: send_with_id(iq) { |reply|
151: reported_jid = reply.first_element('jid')
152: if reply.type == :result and reported_jid and reported_jid.text
153: @jid = JID.new(reported_jid.text)
154: end
155:
156: true
157: }
158: end
159:
160: # Session starting
161: if @stream_features.has_key? 'session'
162: iq = Iq.new(:set)
163: session = iq.add REXML::Element.new('session')
164: session.add_namespace @stream_features['session']
165:
166: send_with_id(iq) { true }
167: end
168: end
Close the connection, sends </stream:stream> tag first
# File lib/xmpp4r/client.rb, line 78
78: def close
79: send("</stream:stream>")
80: super
81: end
connect to the server (chaining-friendly)
If you omit the optional host argument SRV records for your jid will be resolved. If none works, fallback is connecting to the domain part of the jid.
| host: | [String] Optional c2s host, will be extracted from jid if nil |
| return: | self |
# File lib/xmpp4r/client.rb, line 43
43: def connect(host = nil, port = 5222)
44: if host.nil?
45: begin
46: srv = []
47: Resolv::DNS.open { |dns|
48: # If ruby version is too old and SRV is unknown, this will raise a NameError
49: # which is catched below
50: Jabber::debuglog("RESOLVING:\n_xmpp-client._tcp.#{@jid.domain} (SRV)")
51: srv = dns.getresources("_xmpp-client._tcp.#{@jid.domain}", Resolv::DNS::Resource::IN::SRV)
52: }
53: # Sort SRV records: lowest priority first, highest weight first
54: srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
55:
56: srv.each { |record|
57: begin
58: connect(record.target.to_s, record.port)
59: # Success
60: return self
61: rescue SocketError
62: # Try next SRV record
63: end
64: }
65: rescue NameError
66: $stderr.puts "Resolv::DNS does not support SRV records. Please upgrade to ruby-1.8.3 or later!"
67: end
68: # Fallback to normal connect method
69: end
70:
71: super(host.nil? ? jid.domain : host, port)
72: self
73: end
Change the client‘s password
Threading is suggested, as this code waits for an answer.
Raises an exception upon error response (ErrorException from Stream#send_with_id).
| new_password: | [String] New password |
# File lib/xmpp4r/client.rb, line 230
230: def password=(new_password)
231: iq = Iq::new_query(:set, @jid.domain)
232: iq.query.add_namespace('jabber:iq:register')
233: iq.query.add(REXML::Element.new('username')).text = @jid.node
234: iq.query.add(REXML::Element.new('password')).text = new_password
235:
236: err = nil
237: send_with_id(iq) { |answer|
238: if answer.type == :result
239: true
240: else
241: false
242: end
243: }
244: end
Register a new user account (may be used instead of Client#auth)
This method may raise ErrorException if the registration was not successful.
# File lib/xmpp4r/client.rb, line 198
198: def register(password)
199: reg = Iq.new_register(jid.node, password)
200: reg.to = jid.domain
201: send_with_id(reg) { |answer|
202: true
203: }
204: end
Remove the registration of a user account
*WARNING:* this deletes your roster and everything else stored on the server!
# File lib/xmpp4r/client.rb, line 211
211: def remove_registration
212: reg = Iq.new_register
213: reg.to = jid.domain
214: reg.query.add(REXML::Element.new('remove'))
215: send_with_id(reg) { |answer|
216: p answer.to_s
217: true
218: }
219: end