Class: Jabber::Roster::Helper

Inherits:
Object
  • Object
show all
Defined in:
lib/xmpp4r/roster/helper/roster.rb

Overview

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.

Defined Under Namespace

Classes: RosterItem

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(stream) ⇒ Helper

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 add_query_callback to get notifyed when Roster::Helper#items has been filled.


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/xmpp4r/roster/helper/roster.rb', line 36

def initialize(stream)
  @stream = stream
  @items = {}
  @items_lock = Mutex.new
  @query_cbs = CallbackList.new
  @update_cbs = CallbackList.new
  @presence_cbs = CallbackList.new
  @subscription_cbs = CallbackList.new
  @subscription_request_cbs = CallbackList.new

  # Register cbs
  stream.add_iq_callback(120, self) { |iq|
    Thread.new do
      handle_iq(iq)
    end
  }
  stream.add_presence_callback(120, self) { |pres|
    Thread.new do
      handle_presence(pres)
    end
  }

  # Request the roster
  rosterget = Iq.new_rosterget
  stream.send(rosterget)
end

Instance Attribute Details

#itemsObject (readonly)

All items in your roster

items
Hash

([JID] => [Roster::Helper::RosterItem])


23
24
25
# File 'lib/xmpp4r/roster/helper/roster.rb', line 23

def items
  @items
end

Instance Method Details

#[](jid) ⇒ Object

Get an item by jid

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


239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/xmpp4r/roster/helper/roster.rb', line 239

def [](jid)
  jid = JID.new(jid) unless jid.kind_of? JID

  @items_lock.synchronize {
    if @items.has_key?(jid)
      @items[jid]
    elsif @items.has_key?(jid.strip)
      @items[jid.strip]
    else
      nil
    end
  }
end

#accept_subscription(jid, iname = nil) ⇒ Object

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


342
343
344
345
346
347
348
349
350
351
# File 'lib/xmpp4r/roster/helper/roster.rb', line 342

def accept_subscription(jid, iname=nil)
  pres = Presence.new.set_type(:subscribed).set_to(jid.strip)
  @stream.send(pres)

  unless self[jid.strip]
    request = Iq.new_rosterset
    request.query.add(Jabber::Roster::RosterItem.new(jid.strip, iname))
    @stream.send_with_id(request) { true }
  end
end

#add(jid, iname = nil, subscribe = false) ⇒ Object

Add a user to your roster

Threading is encouraged as the function waits for a result. ErrorException 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


318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/xmpp4r/roster/helper/roster.rb', line 318

def add(jid, iname=nil, subscribe=false)
  if self[jid]
    self[jid].send
  else
    request = Iq.new_rosterset
    request.query.add(Jabber::Roster::RosterItem.new(jid, iname))
    @stream.send_with_id(request) { true }
    # Adding to list is handled by handle_iq
  end

  if subscribe
    # Actually the item *should* already be known now,
    # but we do it manually to exclude conditions.
    pres = Presence.new.set_type(:subscribe).set_to(jid.strip)
    @stream.send(pres)
  end
end

#add_presence_callback(prio = 0, ref = nil, &block) ⇒ Object

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:

  • the Jabber::Roster::Helper::RosterItem

  • the old Jabber::Presence (or nil)

  • the new Jabber::Presence (or nil)


97
98
99
# File 'lib/xmpp4r/roster/helper/roster.rb', line 97

def add_presence_callback(prio = 0, ref = nil, &block)
  @presence_cbs.add(prio, ref, block)
end

#add_query_callback(prio = 0, ref = nil, &block) ⇒ Object

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


70
71
72
# File 'lib/xmpp4r/roster/helper/roster.rb', line 70

def add_query_callback(prio = 0, ref = nil, &block)
  @query_cbs.add(prio, ref, block)
end

#add_subscription_callback(prio = 0, ref = nil, &block) ⇒ Object

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:

  • the Jabber::Roster::Helper::RosterItem (or nil)

  • the <presence/> stanza


112
113
114
# File 'lib/xmpp4r/roster/helper/roster.rb', line 112

def add_subscription_callback(prio = 0, ref = nil, &block)
  @subscription_cbs.add(prio, ref, block)
end

#add_subscription_request_callback(prio = 0, ref = nil, &block) ⇒ Object

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

The block receives two objects:

  • the Jabber::Roster::Helper::RosterItem (or nil)

  • the <presence/> stanza

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

135
136
137
# File 'lib/xmpp4r/roster/helper/roster.rb', line 135

def add_subscription_request_callback(prio = 0, ref = nil, &block)
  @subscription_request_cbs.add(prio, ref, block)
end

#add_update_callback(prio = 0, ref = nil, &block) ⇒ Object

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:

  • the old Jabber::Roster::Helper::RosterItem

  • the new Jabber::Roster::Helper::RosterItem


83
84
85
# File 'lib/xmpp4r/roster/helper/roster.rb', line 83

def add_update_callback(prio = 0, ref = nil, &block)
  @update_cbs.add(prio, ref, block)
end

#decline_subscription(jid) ⇒ Object

Decline a subscription request

  • Sends a <presence type='unsubscribed'/> stanza


356
357
358
359
# File 'lib/xmpp4r/roster/helper/roster.rb', line 356

def decline_subscription(jid)
  pres = Presence.new.set_type(:unsubscribed).set_to(jid.strip)
  @stream.send(pres)
end

#find(jid) ⇒ Object

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


256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/xmpp4r/roster/helper/roster.rb', line 256

def find(jid)
  jid = JID.new(jid) unless jid.kind_of? JID

  j = jid.strip
  l = {}
  @items_lock.synchronize {
    @items.each_pair do |k, v|
      l[k] = v if k.strip == j
    end
  }
  l
end

#find_by_group(group) ⇒ Object

Get items in a group

When group is nil, return ungrouped items

group
String

Group name

result

Array of [RosterItem]


292
293
294
295
296
297
298
299
300
301
# File 'lib/xmpp4r/roster/helper/roster.rb', line 292

def find_by_group(group)
  res = []
  @items_lock.synchronize {
    @items.each_pair do |jid,item|
      res.push(item) if item.groups.include?(group)
      res.push(item) if item.groups == [] and group.nil?
    end
  }
  res
end

#groupsObject

Groups in this Roster, sorted by name

Contains nil if there are ungrouped items

result
Array

containing group names (String)


275
276
277
278
279
280
281
282
283
284
# File 'lib/xmpp4r/roster/helper/roster.rb', line 275

def groups
  res = []
  @items_lock.synchronize {
    @items.each_pair do |jid,item|
      res += item.groups
      res += [nil] if item.groups == []
    end
  }
  res.uniq.sort { |a,b| a.to_s <=> b.to_s }
end