Class Jabber::Roster::Helper
In: lib/xmpp4r/roster/helper/roster.rb
Parent: Object

The Roster helper intercepts <iq/> stanzas with Jabber::IqQueryRoster and <presence/> stanzas, but provides cbs which allow the programmer to keep track of updates.

A thread for any received stanza is spawned, so the user can invoke accept_subscription et al in the callback blocks, without stopping the current (= parser) thread when waiting for a reply.

Methods

Classes and Modules

Class Jabber::Roster::Helper::RosterItem

Attributes

items  [R]  All items in your roster
items:[Hash] ([JID] => [Roster::Helper::RosterItem])

Public Class methods

Initialize a new Roster helper

Registers its cbs (prio = 120, ref = self)

Request a roster (Remember to send initial presence afterwards!)

The initialization will not wait for the roster being received, use wait_for_roster.

Attention: If you send presence and receive presences before the roster has arrived, the Roster helper will let them pass through and does not keep them!

[Source]

    # File lib/xmpp4r/roster/helper/roster.rb, line 39
39:       def initialize(stream, startnow = true)
40:         @stream = stream
41:         @items = {}
42:         @items_lock = Mutex.new
43:         @roster_wait = Semaphore.new
44:         @query_cbs = CallbackList.new
45:         @update_cbs = CallbackList.new
46:         @presence_cbs = CallbackList.new
47:         @subscription_cbs = CallbackList.new
48:         @subscription_request_cbs = CallbackList.new
49: 
50:         # Register cbs
51:         stream.add_iq_callback(120, self) { |iq|
52:           if iq.query.kind_of?(IqQueryRoster)
53:             Thread.new do
54:               Thread.current.abort_on_exception = true
55:               handle_iq_query_roster(iq)
56:             end
57: 
58:             true
59:           else
60:             false
61:           end
62:         }
63:         stream.add_presence_callback(120, self) { |pres|
64:           Thread.new do
65:             Thread.current.abort_on_exception = true
66:             handle_presence(pres)
67:           end
68:         }
69:         get_roster if startnow
70:       end

Public Instance methods

Get an item by jid

If not available tries to look for it with the resource stripped

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 247
247:       def [](jid)
248:         jid = JID.new(jid) unless jid.kind_of? JID
249: 
250:         @items_lock.synchronize {
251:           if @items.has_key?(jid)
252:             @items[jid]
253:           elsif @items.has_key?(jid.strip)
254:             @items[jid.strip]
255:           else
256:             nil
257:           end
258:         }
259:       end

Accept a subscription request

  • Sends a <presence type=‘subscribed’/> stanza
  • Adds the contact to your roster
jid:[JID] of contact
iname:[String] Optional roster item name

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 350
350:       def accept_subscription(jid, iname=nil)
351:         pres = Presence.new.set_type(:subscribed).set_to(jid.strip)
352:         @stream.send(pres)
353: 
354:         unless self[jid.strip]
355:           request = Iq.new_rosterset
356:           request.query.add(Jabber::Roster::RosterItem.new(jid.strip, iname))
357:           @stream.send_with_id(request)
358:         end
359:       end

Add a user to your roster

Threading is encouraged as the function waits for a result. ServerError is thrown upon error.

See Jabber::Roster::Helper::RosterItem#subscribe for details about subscribing. (This method isn‘t used here but the same functionality applies.)

If the item is already in the local roster it will simply send itself

jid:[JID] to add
iname:[String] Optional item name
subscribe:[Boolean] Whether to subscribe to this jid

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 326
326:       def add(jid, iname=nil, subscribe=false)
327:         if self[jid]
328:           self[jid].send
329:         else
330:           request = Iq.new_rosterset
331:           request.query.add(Jabber::Roster::RosterItem.new(jid, iname))
332:           @stream.send_with_id(request)
333:           # Adding to list is handled by handle_iq_query_roster
334:         end
335: 
336:         if subscribe
337:           # Actually the item *should* already be known now,
338:           # but we do it manually to exclude conditions.
339:           pres = Presence.new.set_type(:subscribe).set_to(jid.strip)
340:           @stream.send(pres)
341:         end
342:       end

Add a callback for Jabber::Presence updates

This will be called for <presence/> stanzas for known RosterItems. Unknown JIDs may still pass and can be caught via Jabber::Stream#add_presence_callback.

The block receives three objects:

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 119
119:       def add_presence_callback(prio = 0, ref = nil, &block)
120:         @presence_cbs.add(prio, ref, block)
121:       end

Add a callback to be called when a query has been processed

Because update callbacks are called for each roster item, this may be appropriate to notify that anything has updated.

Arguments for callback block: The received <iq/> stanza

[Source]

    # File lib/xmpp4r/roster/helper/roster.rb, line 92
92:       def add_query_callback(prio = 0, ref = nil, &block)
93:         @query_cbs.add(prio, ref, block)
94:       end

Add a callback for subscription updates, which will be called upon receiving a <presence/> stanza with type:

  • :subscribed
  • :unsubscribe
  • :unsubscribed

The block receives two objects:

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 134
134:       def add_subscription_callback(prio = 0, ref = nil, &block)
135:         @subscription_cbs.add(prio, ref, block)
136:       end

Add a callback for subscription requests, which will be called upon receiving a <presence type=‘subscribe’/> stanza

The block receives two objects:

Response to this event can be taken with accept_subscription and decline_subscription.

Example usage:

 my_roster.add_subscription_request_callback do |item,presence|
   if accept_subscription_requests
     my_roster.accept_subscription(presence.from)
   else
     my_roster.decline_subscription(presence.from)
   end
 end

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 157
157:       def add_subscription_request_callback(prio = 0, ref = nil, &block)
158:         @subscription_request_cbs.add(prio, ref, block)
159:       end

Add a callback for Jabber::Roster::Helper::RosterItem updates

Note that this will be called much after initialization for the answer of the initial roster request

The block receives two objects:

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 105
105:       def add_update_callback(prio = 0, ref = nil, &block)
106:         @update_cbs.add(prio, ref, block)
107:       end

Decline a subscription request

  • Sends a <presence type=‘unsubscribed’/> stanza

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 364
364:       def decline_subscription(jid)
365:         pres = Presence.new.set_type(:unsubscribed).set_to(jid.strip)
366:         @stream.send(pres)
367:       end

Returns the list of RosterItems which, stripped, are equal to the one you are looking for.

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 264
264:       def find(jid)
265:         jid = JID.new(jid) unless jid.kind_of? JID
266: 
267:         j = jid.strip
268:         l = {}
269:         @items_lock.synchronize {
270:           @items.each_pair do |k, v|
271:             l[k] = v if k.strip == j
272:           end
273:         }
274:         l
275:       end

Get items in a group

When group is nil, return ungrouped items

group:[String] Group name
result:Array of [RosterItem]

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 300
300:       def find_by_group(group)
301:         res = []
302:         @items_lock.synchronize {
303:           @items.each_pair do |jid,item|
304:             res.push(item) if item.groups.include?(group)
305:             res.push(item) if item.groups == [] and group.nil?
306:           end
307:         }
308:         res
309:       end

[Source]

    # File lib/xmpp4r/roster/helper/roster.rb, line 72
72:       def get_roster
73:         # Request the roster
74:         rosterget = Iq.new_rosterget
75:         @stream.send(rosterget)
76:       end

Groups in this Roster, sorted by name

Contains nil if there are ungrouped items

result:[Array] containing group names (String)

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 283
283:       def groups
284:         res = []
285:         @items_lock.synchronize {
286:           @items.each_pair do |jid,item|
287:             res += item.groups
288:             res += [nil] if item.groups == []
289:           end
290:         }
291:         res.uniq.sort { |a,b| a.to_s <=> b.to_s }
292:       end

Wait for first roster query result to arrive

[Source]

    # File lib/xmpp4r/roster/helper/roster.rb, line 80
80:       def wait_for_roster
81:         @roster_wait.wait
82:         @roster_wait.run
83:       end

[Validate]