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