Class: Jabber::Client
- Inherits:
-
Connection
- Object
- Stream
- Connection
- Jabber::Client
- Defined in:
- 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.
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, #port, #ssl_capath, #ssl_verifycb
Attributes inherited from Stream
Instance Method Summary collapse
-
#auth(password) ⇒ Object
Authenticate with the 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, threaded = true) ⇒ Client
constructor
Create a new Client.
-
#password=(new_password) ⇒ Object
Change the client’s password.
-
#register(password) ⇒ Object
Register a new user account (may be used instead of Client#auth).
-
#remove_registration ⇒ Object
Remove the registration of a user account.
-
#start ⇒ Object
Start the stream-parser and send the client-specific stream opening element.
Methods inherited from Connection
#accept_features, #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, #poll, #process, #receive, #send, #send_with_id, #stop, #wait_and_process
Constructor Details
#initialize(jid, threaded = true) ⇒ Client
Create a new Client. If threaded mode is activated, callbacks are called as soon as messages are received; If it isn’t, you have to call Stream#process from time to time.
Remember to always put a resource in your JID unless the server can do SASL.
31 32 33 34 |
# File 'lib/xmpp4r/client.rb', line 31 def initialize(jid, threaded = true) super(threaded) @jid = (jid.kind_of?(JID) ? jid : JID.new(jid.to_s)) end |
Instance Attribute Details
#jid ⇒ Object (readonly)
The client’s JID
23 24 25 |
# File 'lib/xmpp4r/client.rb', line 23 def jid @jid end |
Instance Method Details
#auth(password) ⇒ Object
Authenticate with the server
Throws AuthenticationFailure
Authentication mechanisms are used in the following preference:
-
SASL DIGEST-MD5
-
SASL PLAIN
-
Non-SASL digest
- password
- String
108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/xmpp4r/client.rb', line 108 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 AuthenticationFailure.new, $!.to_s end end |
#auth_nonsasl(password, digest = true) ⇒ Object
Send auth with given password and wait for result (non-SASL)
Throws ErrorException
- password
- String
-
the password
- digest
- Boolean
-
use Digest authentication
180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/xmpp4r/client.rb', line 180 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) do |r| true end $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
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 166 167 168 169 170 171 |
# File 'lib/xmpp4r/client.rb', line 133 def auth_sasl(sasl, password) sasl.auth(password) # Restart stream after SASL auth stop start # And wait for features - again @features_lock.lock @features_lock.unlock # 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) { |reply| reported_jid = reply.first_element('jid') if reply.type == :result and reported_jid and reported_jid.text @jid = JID.new(reported_jid.text) end true } 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) { true } end end |
#close ⇒ Object
Close the connection, sends </stream:stream>
tag first
80 81 82 83 |
# File 'lib/xmpp4r/client.rb', line 80 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
- return
-
self
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 73 74 75 |
# File 'lib/xmpp4r/client.rb', line 45 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 catched 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 # Try next SRV record end } rescue NameError $stderr.puts "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 (ErrorException from Stream#send_with_id).
- new_password
- String
-
New password
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/xmpp4r/client.rb', line 233 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) { |answer| if answer.type == :result true else false end } end |
#register(password) ⇒ Object
Register a new user account (may be used instead of Client#auth)
This method may raise ErrorException if the registration was not successful.
201 202 203 204 205 206 207 |
# File 'lib/xmpp4r/client.rb', line 201 def register(password) reg = Iq.new_register(jid.node, password) reg.to = jid.domain send_with_id(reg) { |answer| true } end |
#remove_registration ⇒ Object
Remove the registration of a user account
WARNING: this deletes your roster and everything else stored on the server!
214 215 216 217 218 219 220 221 222 |
# File 'lib/xmpp4r/client.rb', line 214 def remove_registration reg = Iq.new_register reg.to = jid.domain reg.query.add(REXML::Element.new('remove')) send_with_id(reg) { |answer| p answer.to_s true } end |
#start ⇒ Object
Start the stream-parser and send the client-specific stream opening element
87 88 89 90 91 92 93 94 95 96 |
# File 'lib/xmpp4r/client.rb', line 87 def start super send(generate_stream_start(@jid.domain)) { |e| if e.name == 'stream' true else false end } end |