Class: Jabber::Client
- Inherits:
-
Connection
- Object
- Stream
- Connection
- Jabber::Client
- Defined in:
- lib/vendor/xmpp4r/lib/xmpp4r/client.rb
Overview
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.
Direct Known Subclasses
Constant Summary
Constants inherited from Stream
Stream::CONNECTED, Stream::DISCONNECTED
Instance Attribute Summary collapse
-
#jid ⇒ Object
readonly
The client’s JID.
Attributes inherited from Connection
#allow_tls, #features_timeout, #host, #keepalive_interval, #port, #ssl_capath, #ssl_verifycb, #use_ssl
Attributes inherited from Stream
Instance Method Summary collapse
-
#auth(password) ⇒ Object
Authenticate with the server.
-
#auth_anonymous ⇒ Object
See Client#auth_anonymous_sasl.
-
#auth_anonymous_sasl ⇒ Object
Shortcut for anonymous connection to server.
-
#auth_nonsasl(password, digest = true) ⇒ Object
Send auth with given password and wait for result (non-SASL).
-
#auth_sasl(sasl, password) ⇒ Object
Use a SASL authentication mechanism and bind to a resource.
-
#close ⇒ Object
Close the connection, sends
</stream:stream>
tag first. -
#connect(host = nil, port = 5222) ⇒ Object
connect to the server (chaining-friendly).
-
#initialize(jid) ⇒ Client
constructor
Create a new Client.
-
#password=(new_password) ⇒ Object
Change the client’s password.
-
#register(password, fields = {}) ⇒ Object
Register a new user account (may be used instead of Client#auth).
-
#register_info ⇒ Object
- Get instructions and available fields for registration return
- instructions, fields
-
Where instructions is a String and fields is an Array of Strings.
-
#remove_registration ⇒ Object
Remove the registration of a user account.
-
#start ⇒ Object
Start the stream-parser and send the client-specific stream opening element.
-
#supports_anonymous? ⇒ Boolean
Reports whether or not anonymous authentication is reported by the client.
Methods inherited from Connection
#accept_features, #close!, #is_tls?, #starttls
Methods inherited from Stream
#add_iq_callback, #add_message_callback, #add_presence_callback, #add_stanza_callback, #add_xml_callback, #close!, #delete_iq_callback, #delete_message_callback, #delete_presence_callback, #delete_stanza_callback, #delete_xml_callback, #is_connected?, #is_disconnected?, #on_exception, #parse_failure, #parser_end, #receive, #send, #send_data, #send_with_id, #stop
Constructor Details
Instance Attribute Details
#jid ⇒ Object (readonly)
The client’s JID
21 22 23 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 21 def jid @jid end |
Instance Method Details
#auth(password) ⇒ Object
Authenticate with the server
Throws ClientAuthenticationFailure
Authentication mechanisms are used in the following preference:
-
SASL DIGEST-MD5
-
SASL PLAIN
-
Non-SASL digest
- password
- String
105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 105 def auth(password) begin if @stream_mechanisms.include? 'DIGEST-MD5' auth_sasl SASL.new(self, 'DIGEST-MD5'), password elsif @stream_mechanisms.include? 'PLAIN' auth_sasl SASL.new(self, 'PLAIN'), password else auth_nonsasl(password) end rescue Jabber::debuglog("#{$!.class}: #{$!}\n#{$!.backtrace.join("\n")}") raise ClientAuthenticationFailure.new, $!.to_s end end |
#auth_anonymous ⇒ Object
See Client#auth_anonymous_sasl
169 170 171 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 169 def auth_anonymous auth_anonymous_sasl end |
#auth_anonymous_sasl ⇒ Object
Shortcut for anonymous connection to server
Throws ClientAuthenticationFailure
178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 178 def auth_anonymous_sasl if self.supports_anonymous? begin auth_sasl SASL.new(self, 'ANONYMOUS'), "" rescue Jabber::debuglog("#{$!.class}: #{$!}\n#{$!.backtrace.join("\n")}") raise ClientAuthenticationFailure, $!.to_s end else raise ClientAuthenticationFailure, 'Anonymous authentication unsupported' end end |
#auth_nonsasl(password, digest = true) ⇒ Object
Send auth with given password and wait for result (non-SASL)
Throws ServerError
- password
- String
-
the password
- digest
- Boolean
-
use Digest authentication
207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 207 def auth_nonsasl(password, digest=true) authset = nil if digest authset = Iq.new_authset_digest(@jid, @streamid.to_s, password) else authset = Iq.new_authset(@jid, password) end send_with_id(authset) $defout.flush true end |
#auth_sasl(sasl, password) ⇒ Object
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
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 130 def auth_sasl(sasl, password) sasl.auth(password) # Restart stream after SASL auth stop start # And wait for features - again @features_sem.wait # Resource binding (RFC3920 - 7) if @stream_features.has_key? 'bind' iq = Iq.new(:set) bind = iq.add REXML::Element.new('bind') bind.add_namespace @stream_features['bind'] if jid.resource resource = bind.add REXML::Element.new('resource') resource.text = jid.resource end send_with_id(iq) do |reply| reported_jid = reply.first_element('jid') if reported_jid and reported_jid.text @jid = JID.new(reported_jid.text) end end end # Session starting if @stream_features.has_key? 'session' iq = Iq.new(:set) session = iq.add REXML::Element.new('session') session.add_namespace @stream_features['session'] send_with_id(iq) end end |
#close ⇒ Object
Close the connection, sends </stream:stream>
tag first
77 78 79 80 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 77 def close send("</stream:stream>") super end |
#connect(host = nil, port = 5222) ⇒ Object
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
- use_ssl
- Boolean
-
Optional. Use (old, deprecated) SSL when connecting.
- return
-
self
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 42 def connect(host = nil, port = 5222) if host.nil? begin srv = [] Resolv::DNS.open { |dns| # If ruby version is too old and SRV is unknown, this will raise a NameError # which is caught below Jabber::debuglog("RESOLVING:\n_xmpp-client._tcp.#{@jid.domain} (SRV)") srv = dns.getresources("_xmpp-client._tcp.#{@jid.domain}", Resolv::DNS::Resource::IN::SRV) } # Sort SRV records: lowest priority first, highest weight first srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) } srv.each { |record| begin connect(record.target.to_s, record.port) # Success return self rescue SocketError, Errno::ECONNREFUSED # Try next SRV record end } rescue NameError Jabber::debuglog "Resolv::DNS does not support SRV records. Please upgrade to ruby-1.8.3 or later!" end # Fallback to normal connect method end super(host.nil? ? jid.domain : host, port) self end |
#password=(new_password) ⇒ Object
Change the client’s password
Threading is suggested, as this code waits for an answer.
Raises an exception upon error response (ServerError from Stream#send_with_id).
- new_password
- String
-
New password
307 308 309 310 311 312 313 314 315 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 307 def password=(new_password) iq = Iq.new_query(:set, @jid.domain) iq.query.add_namespace('jabber:iq:register') iq.query.add(REXML::Element.new('username')).text = @jid.node iq.query.add(REXML::Element.new('password')).text = new_password err = nil send_with_id(iq) end |
#register(password, fields = {}) ⇒ Object
Register a new user account (may be used instead of Client#auth)
This method may raise ServerError if the registration was not successful.
- password
-
String
- fields
-
String=>String additional registration information
XEP-0077 Defines the following fields for registration information: www.xmpp.org/extensions/xep-0077.html
‘username’ => ‘Account name associated with the user’ ‘nick’ => ‘Familiar name of the user’ ‘password’ => ‘Password or secret for the user’ ‘name’ => ‘Full name of the user’ ‘first’ => ‘First name or given name of the user’ ‘last’ => ‘Last name, surname, or family name of the user’ ‘email’ => ‘Email address of the user’ ‘address’ => ‘Street portion of a physical or mailing address’ ‘city’ => ‘Locality portion of a physical or mailing address’ ‘state’ => ‘Region portion of a physical or mailing address’ ‘zip’ => ‘Postal code portion of a physical or mailing address’ ‘phone’ => ‘Telephone number of the user’ ‘url’ => ‘URL to web page describing the user’ ‘date’ => ‘Some date (e.g., birth date, hire date, sign-up date)’
276 277 278 279 280 281 282 283 284 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 276 def register(password, fields={}) reg = Iq.new_register(jid.node, password) reg.to = jid.domain fields.each { |name,value| reg.query.add(REXML::Element.new(name)).text = value } send_with_id(reg) end |
#register_info ⇒ Object
Get instructions and available fields for registration
- return
- instructions, fields
-
Where instructions is a String and fields is an Array of Strings
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 223 def register_info instructions = nil fields = [] reg = Iq.new_registerget reg.to = jid.domain send_with_id(reg) do |answer| if answer.query answer.query.each_element { |e| if e.namespace == 'jabber:iq:register' if e.name == 'instructions' instructions = e.text.strip else fields << e.name end end } end true end [instructions, fields] end |
#remove_registration ⇒ Object
Remove the registration of a user account
WARNING: this deletes your roster and everything else stored on the server!
291 292 293 294 295 296 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 291 def remove_registration reg = Iq.new_register reg.to = jid.domain reg.query.add(REXML::Element.new('remove')) send_with_id(reg) end |
#start ⇒ Object
Start the stream-parser and send the client-specific stream opening element
84 85 86 87 88 89 90 91 92 93 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 84 def start super send(generate_stream_start(@jid.domain)) { |e| if e.name == 'stream' true else false end } end |
#supports_anonymous? ⇒ Boolean
Reports whether or not anonymous authentication is reported by the client.
Returns true or false
196 197 198 |
# File 'lib/vendor/xmpp4r/lib/xmpp4r/client.rb', line 196 def supports_anonymous? @stream_mechanisms.include? 'ANONYMOUS' end |