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.

Methods

Attributes

jid  [R]  The client‘s JID

Public Class methods

Create a new Client.

Remember to always put a resource in your JID unless the server can do SASL.

[Source]

    # File lib/xmpp4r/client.rb, line 29
29:     def initialize(jid, threaded = true)
30:       super(threaded)
31:       @jid = (jid.kind_of?(JID) ? jid : JID.new(jid.to_s))
32:     end

Public Instance methods

Authenticate with the server

Throws AuthenticationFailure

Authentication mechanisms are used in the following preference:

password:[String]

[Source]

     # 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

[Source]

     # 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]

[Source]

     # 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

[Source]

    # 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

[Source]

    # 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

[Source]

     # 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.

[Source]

     # 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!

[Source]

     # 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

Start the stream-parser and send the client-specific stream opening element

[Source]

    # File lib/xmpp4r/client.rb, line 85
85:     def start
86:       super
87:       send(generate_stream_start(@jid.domain)) { |e|
88:         if e.name == 'stream'
89:           true
90:         else
91:           false
92:         end
93:       }
94:     end

[Validate]