Class: Jabber::Session

Inherits:
Object
  • Object
show all
Defined in:
lib/jabber4r/session.rb

Overview

The Jabber Session is the main class for dealing with a Jabber service.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host, port = 5222) ⇒ Session

Creates a new session connected to the supplied host and port. The method attempts to build a Jabber::Protocol::Connection object and send the open_stream XML message. It then blocks to recieve the coorisponding reply open_stream and sets the session_id from that xml element.

host
String

The hostname of the Jabber service

port
Integer=5222

The port of the Jabber service

raise
RuntimeException

If connection fails



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/jabber4r/session.rb', line 200

def initialize(host, port=5222)
  @id = 1
  @host = host
  @port = port
  @roster = Roster.new(self)
  @messageListeners = Hash.new
  @iqHandlers=Hash.new
  @subscriptionHandler = nil
  @connection = Jabber::Protocol::Connection.new(host, port)
  @connection.connect
  unless @connection.is_connected?
    raise "Session Error: Could not connected to #{host}:#{port}"
  else
    @connection.send(Jabber::Protocol.gen_open_stream(host)) do |element| 
      if element.element_tag=="stream:stream"
        element.consume_element 
        @session_id = element.attr_id
      end
    end
    @connection.on_connection_exception do
      if @session_failure_block
        self.release
        @session_failure_block.call
      end
    end
    Thread.stop
  end
end

Instance Attribute Details

#connectionObject (readonly)

The Jabber::Protocol::Connection instance



103
104
105
# File 'lib/jabber4r/session.rb', line 103

def connection
  @connection
end

#hostObject (readonly)

The host this session is connected to



97
98
99
# File 'lib/jabber4r/session.rb', line 97

def host
  @host
end

#iqHandlersObject

The iq handlers for this session



124
125
126
# File 'lib/jabber4r/session.rb', line 124

def iqHandlers
  @iqHandlers
end

#jidObject (readonly)

The Jabber::JID of the current session



112
113
114
# File 'lib/jabber4r/session.rb', line 112

def jid
  @jid
end

#passwordObject

The password to use for authenticating this session



118
119
120
# File 'lib/jabber4r/session.rb', line 118

def password
  @password
end

#portObject (readonly)

The port (defaults to 5222) that this session is connected to



100
101
102
# File 'lib/jabber4r/session.rb', line 100

def port
  @port
end

#resourceObject

The resource id for this session



121
122
123
# File 'lib/jabber4r/session.rb', line 121

def resource
  @resource
end

#rosterObject (readonly)

The Jabber::Roster instance



106
107
108
# File 'lib/jabber4r/session.rb', line 106

def roster
  @roster
end

#session_idObject (readonly)

The session id sent from the Jabber service upon connection



109
110
111
# File 'lib/jabber4r/session.rb', line 109

def session_id
  @session_id
end

#usernameObject

The username to use for authenticating this session



115
116
117
# File 'lib/jabber4r/session.rb', line 115

def username
  @username
end

Class Method Details

.bind(jid, password, port = 5222, digest = false) ⇒ Object

Session creation factory that creates a session, logs in, requests the roster, registers message and presence filters and announces initial presence. Login is done via plaintext password authentication.

jid
String | JID

The account information (“account@host/resouce”)

password
String

The account password

port
Integer = 5222

The host port

digest
Boolean = false

Use digest authentication?

return
Jabber::Session

The new session



138
139
140
141
142
143
144
145
146
147
148
# File 'lib/jabber4r/session.rb', line 138

def Session.bind(jid, password, port=5222, digest=false)
  jid = Jabber::JID.new(jid) if jid.kind_of? String
  session = Session.new(jid.host, port)
  raise "Authentication failed" unless session.authenticate(jid.node, password, jid.resource, digest)
  session.request_roster
  session.register_message_filter
  session.register_presence_filter
  session.register_iq_filter
  session.announce_initial_presence
  session
end

.bind_digest(jid, password, port = 5222) ⇒ Object

Session creation factory that creates a session, logs in, requests the roster, registers message and presence filters and announces initial presence. Login is done via digest (SHA) password authentication.

jid
String | JID

The account information (“account@host/resouce”)

password
String

The account password

port
Integer = 5222

The host port

return
Jabber::Session

The new session



186
187
188
# File 'lib/jabber4r/session.rb', line 186

def Session.bind_digest(jid, password, port=5222)
  Session.bind(jid, password, port, true)
end

.register(jid, password, email = "", name = "", port = 5222) ⇒ Object

Account registration method



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/jabber4r/session.rb', line 153

def Session.register(jid, password, email="", name="", port=5222)
  jid = Jabber::JID.new(jid) if jid.kind_of? String
  session = Session.new(jid.host, port)
  msg_id = session.id
  registered = false
  current = Thread.current
  session.connection.send(Jabber::Protocol::Iq.gen_registration(session, msg_id, jid.node, password, email, name)) do |element|
    if element.element_tag=="iq" and element.attr_id==msg_id
      element.consume_element
      if element.attr_type=="result"
        registered = true
      elsif element.attr_type=="error"
        registered = false
      end
      current.wakeup
    end
  end
  Thread.stop
  session.release      
  return registered
end

Instance Method Details

#add_message_listener(&block) ⇒ Object

Add a listener for new messages

Usage

id = session.add_message_listener do |message|

puts message

end

&block [Block] The block to process a message

return
String

The listener ID…used to remove the listener



484
485
486
487
488
# File 'lib/jabber4r/session.rb', line 484

def add_message_listener(&block)
  id = Jabber.gen_random_id("", 10)
  @messageListeners[id]=block if block
  return id
end

#add_roster_listener(&block) ⇒ Object

Registers a listener for roster events

&block
Block

The listener block to process roster changes

return
String

A roster ID to use when removing this listener



590
591
592
# File 'lib/jabber4r/session.rb', line 590

def add_roster_listener(&block)
  roster.add_listener(&block)
end

#announce_away_from_computer(status = nil) ⇒ Object

Sends an away from computer presence message

status
String

The status message



335
336
337
# File 'lib/jabber4r/session.rb', line 335

def announce_away_from_computer(status=nil)
  @connection.send(Jabber::Protocol::Presence.gen_away(id, status))
end

#announce_do_not_disturb(status = nil) ⇒ Object

Sends a do not disturb presence message

status
String

The status message



344
345
346
# File 'lib/jabber4r/session.rb', line 344

def announce_do_not_disturb(status=nil)
  @connection.send(Jabber::Protocol::Presence.gen_dnd(id, status))
end

#announce_extended_away(status = nil) ⇒ Object

Sends an extended away presence message

status
String

The status message



308
309
310
# File 'lib/jabber4r/session.rb', line 308

def announce_extended_away(status=nil)
  @connection.send(Jabber::Protocol::Presence.gen_xa(id, status))
end

#announce_free_for_chat(status = nil) ⇒ Object

Sends a free for chat presence message

status
String

The status message



317
318
319
# File 'lib/jabber4r/session.rb', line 317

def announce_free_for_chat(status=nil)
  @connection.send(Jabber::Protocol::Presence.gen_chat(id, status))
end

#announce_initial_presenceObject

Sends the initial presence message to the Jabber service



299
300
301
# File 'lib/jabber4r/session.rb', line 299

def announce_initial_presence
  @connection.send(Jabber::Protocol::Presence.gen_initial(id))
end

#announce_normal(status = nil) ⇒ Object

Sends a ‘normal’ presence message

status
String

The status message



326
327
328
# File 'lib/jabber4r/session.rb', line 326

def announce_normal(status=nil)
  @connection.send(Jabber::Protocol::Presence.gen_normal(id, status))
end

#authenticate(username, password, resource, digest = false) ⇒ Object

Authenticate (logs into) this session with the supplied credentials. The method blocks waiting for a reply to the login message. Sets the authenticated attribute based on result.

username
String

The username to use for authentication

password
String

The password to use for authentication

resource
String

The resource ID for this session

digest
Boolean=false

True to use digest authentication (not sending password in the clear)

return
Boolean

Whether the authentication succeeded or failed



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/jabber4r/session.rb', line 258

def authenticate(username, password, resource, digest=false)
  @username = username
  @password = password
  @resource = resource
  @jid = JID.new("#{username}@#{@host}/#{resource}")
  @roster.add(@jid, "both", "Me", "My Resources")
  
  msg_id = self.id
  authHandler = Proc.new  do |element| 
    if element.element_tag=="iq" and element.attr_id==msg_id
      element.consume_element
      if element.attr_type=="result"
        @authenticated = true
      elsif element.attr_type=="error"
        @authenticated = false
      end
    end
  end
  if digest
    require 'digest/sha1'
    authRequest = Jabber::Protocol::Iq.gen_auth_digest(self, msg_id, username, Digest::SHA1.new(@session_id + password).hexdigest, resource)
  else
    authRequest = Jabber::Protocol::Iq.gen_auth(self, msg_id, username, password, resource)
  end
  @connection.send(authRequest, &authHandler)
  Thread.stop
  return @authenticated
end

#closeObject

Same as _release



525
526
527
# File 'lib/jabber4r/session.rb', line 525

def close
  release
end

#delete_message_listener(lid) ⇒ Object

Deletes a message listener

id
String

A messanger ID returned from add_message_listener



495
496
497
# File 'lib/jabber4r/session.rb', line 495

def delete_message_listener(lid)
  @messageListeners.delete(lid)
end

#delete_roster_listener(id) ⇒ Object

Deletes the roster listener

id
String

A roster ID received from the add_roster_listener method



599
600
601
# File 'lib/jabber4r/session.rb', line 599

def delete_roster_listener(id)
  roster.delete_listener(id)
end

#enable_autosubscriptionObject



356
357
358
# File 'lib/jabber4r/session.rb', line 356

def enable_autosubscription
  set_subscription_handler AutoSubscriptionHandler
end

#idObject

Counter for message IDs

return
String

A unique message id for this session



242
243
244
245
# File 'lib/jabber4r/session.rb', line 242

def id
  @id = @id + 1
  return @id.to_s
end

#is_authenticated?Boolean

Is this an authenticated session?

return
Boolean

True if the session is authenticated

Returns:

  • (Boolean)


292
293
294
# File 'lib/jabber4r/session.rb', line 292

def is_authenticated?
  return @authenticated
end

#new_chat_message(to) ⇒ Object

Creates a new message addressed to the supplied JID of type CHAT

to
JID

Who to send the message to

return
Jabber::Protocol::Message

The new (chat) message



445
446
447
# File 'lib/jabber4r/session.rb', line 445

def new_chat_message(to)
  self.new_message(to, Jabber::Protocol::Message::CHAT)
end

#new_group_chat_message(to) ⇒ Object

Creates a new message addressed to the supplied JID of type GROUPCHAT

to
JID

Who to send the message to

return
Jabber::Protocol::Message

The new (group chat) message



455
456
457
# File 'lib/jabber4r/session.rb', line 455

def new_group_chat_message(to)
  self.new_message(to, Jabber::Protocol::Message::GROUPCHAT)
end

#new_message(to, type = Jabber::Protocol::Message::NORMAL) ⇒ Object

Creates a new message to the supplied JID of type NORMAL

to
Jabber::JID

Who to send the message to

type
String = Jabber::Protocol::Message::NORMAL

The type of message to send (see Jabber::Protocol::Message)

return
Jabber::Protocol::Message

The new message



433
434
435
436
437
# File 'lib/jabber4r/session.rb', line 433

def new_message(to, type=Jabber::Protocol::Message::NORMAL)
  msg = Jabber::Protocol::Message.new(to, type)
  msg.session=self
  return msg
end

#notify_message_listeners(message) ⇒ Object

Notifies message listeners of the received message

message
Jabber::Protocol::Message

The received message



608
609
610
# File 'lib/jabber4r/session.rb', line 608

def notify_message_listeners(message)
  @messageListeners.each_value {|listener| listener.call(message)}
end

#on_session_failure(&block) ⇒ Object

Set a handler for session exceptions that get caught in communicating with the Jabber server.



233
234
235
# File 'lib/jabber4r/session.rb', line 233

def on_session_failure(&block)
  @session_failure_block = block
end

#register_iq_filterObject

Registers the roster filter with the Connection to forward IQ requests to the IQ listeners(they register by namespace)



554
555
556
557
558
559
560
561
562
563
# File 'lib/jabber4r/session.rb', line 554

def register_iq_filter() 
  @connection.add_filter("iqFilter") do |element|
    if element.element_tag=="iq" then
      element.consume_element
      query=element.query
      h=@iqHandlers[query.attr_xmlns]
      h.call(Jabber::Protocol::Iq.from_element(self,element)) if h
    end
  end
end

#register_message_filterObject

Adds a filter to the Connection to manage tracking messages to forward to registered message listeners.



463
464
465
466
467
468
469
470
471
# File 'lib/jabber4r/session.rb', line 463

def register_message_filter
  @connection.add_filter("messageFilter") do |element|
    if element.element_tag=="message" and @messageListeners.size > 0
      element.consume_element
      message = Jabber::Protocol::Message.from_element(self, element)
      notify_message_listeners(message)
    end #if message 
  end #do
end

#register_presence_filterObject

Adds a filter to the Connection to manage tracking resources that come online/offline



385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/jabber4r/session.rb', line 385

def register_presence_filter
  @connection.add_filter("presenceAvailableFilter") do |element|
    if element.element_tag=="presence"
      type = element.attr_type
      type = nil if type.nil?
      case type
      when nil, "available"
        element.consume_element
        from = JID.new(element.attr_from)
        rItem = @roster[from]
        show = element.show.element_data
        show = "chat" unless show
        status = element.status.element_data
        status = "" unless status
        if rItem
          resource = rItem[from.resource]
          if resource
            resource.update(show, status)
          else
            rItem.add(from.resource, show, status)
          end
        end
      when "unavailable"
        element.consume_element
        from = JID.new(element.attr_from)
        rItem = @roster[from]
        resource = rItem.delete(from.resource) if rItem
      when "subscribe", "unsubscribe", "subscribed", "unsubscribed"
        element.consume_element
        from = JID.new(element.attr_from)
        break unless @subscriptionHandler
        if @subscriptionHandler.kind_of? Proc
          @subscriptionHandler.call(Subscription.new(self, type.intern, from, id))
        else
          @subscriptionHandler.send(Subscription.new(self, type.intern, from, id))
        end
      end
    end #if presence 
  end #do
end

#register_roster_filterObject

Registers the roster filter with the Connection to forward roster changes to the roster listeners.



570
571
572
573
574
575
576
577
578
579
580
581
582
# File 'lib/jabber4r/session.rb', line 570

def register_roster_filter
  @connection.add_filter("rosterFilter") do |element|
    if element.element_tag=="iq" and element.query.attr_xmlns=="jabber:iq:roster" and element.attr_type=="set"
      element.consume_element
      item = element.query.item
      if item.attr_subscription=="remove" then
        @roster.remove(item.attr_jid)
      else
        @roster.add(item.attr_jid, item.attr_subscription, item.attr_name, item.group.element_data)
      end
    end
  end
end

#releaseObject

Releases the connection and resets the session. The Session instance is no longer usable after this method is called



505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
# File 'lib/jabber4r/session.rb', line 505

def release
  begin
    @connection.on_connection_exception do
      #Do nothing...we are shutting down
    end
    @connection.send(Jabber::Protocol::Presence.gen_unavailable(id))
    @connection.send(Jabber::Protocol.gen_close_stream)
  rescue
    #ignore error
  end
  begin
    @connection.close
  rescue
    #ignore error
  end
end

#request_rosterObject

Requests the Roster for the (authenticated) account. This method blocks until a reply to the roster request is received.



533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
# File 'lib/jabber4r/session.rb', line 533

def request_roster
  if @authenticated
    msg_id = id
    @connection.send(Jabber::Protocol::Iq.gen_roster(self, msg_id)) do |element|
      if element.attr_id == msg_id
        element.consume_element
        element.query.item.count.times do |i|
          item = element.query.item[i]
          @roster.add(item.attr_jid, item.attr_subscription, item.attr_name, item.group.element_data)
        end
      end
    end
    Thread.stop
    register_roster_filter
  end
end

#set_subscription_handler(handler = nil, &block) ⇒ Object

Sets the handler for subscription requests, notifications, etc.



351
352
353
354
# File 'lib/jabber4r/session.rb', line 351

def set_subscription_handler(handler=nil, &block)
  @subscriptionHandler = handler.new(self) if handler
  @subscriptionHandler = block if block_given? and !handler
end

#subscribe(to, name = "") ⇒ Object



360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/jabber4r/session.rb', line 360

def subscribe(to, name="") 
  to = JID.to_jid(to)
  roster_item = @roster[to]
  
  if roster_item #if you already have a roster item just send the subscribe request
    if roster_item.subscription=="to" or roster_item.subscription=="both"
      return
    end
    @connection.send(Jabber::Protocol::Presence.gen_new_subscription(to))
    return
  end
  myid = self.id
  @connection.send(Jabber::Protocol::Iq.gen_add_rosteritem(self, myid, to, name)) do |element|
    if element.attr_id==myid
      element.consume_element
      if element.attr_type=="result"
        @connection.send(Jabber::Protocol::Presence.gen_new_subscription(to))
      end
    end
  end
end