Class Jabber::Roster::Helper
In: lib/xmpp4r/roster/helper/roster.rb
Parent: Object
XMLStanza Message Presence Iq REXML::Element X IqQuery Error StreamHost IqSiFileRange IqSiFile StreamHostUsed IqSi IqFeature XRosterItem RosterItem XMUCUserItem XMUCUserInvite XDataField XDataReported XDataTitle XDataInstructions Feature Identity Item IqVcard Singleton IdGenerator Connection Client Component Comparable JID RuntimeError AuthenticationFailure ErrorException SOCKS5Error Stream SOCKS5Bytestreams SOCKS5BytestreamsTarget SOCKS5BytestreamsInitiator SOCKS5BytestreamsServerStreamHost TCPSocket SOCKS5Socket IqQuery IqQueryBytestreams IqQueryVersion IqQueryRoster IqQueryDiscoItems IqQueryDiscoInfo IBB IBBTarget IBBInitiator Responder SimpleResponder X XRoster XMUCUser XMUC XDelay XData MUCClient SimpleMUCClient Base DigestMD5 Plain FileSource StreamParser SOCKS5BytestreamsPeer SOCKS5BytestreamsServer IBBQueueItem Helper MUCBrowser Helper Helper lib/xmpp4r/authenticationfailure.rb lib/xmpp4r/idgenerator.rb lib/xmpp4r/connection.rb lib/xmpp4r/iq.rb lib/xmpp4r/jid.rb lib/xmpp4r/xmlstanza.rb lib/xmpp4r/errorexception.rb lib/xmpp4r/stream.rb lib/xmpp4r/client.rb lib/xmpp4r/x.rb lib/xmpp4r/streamparser.rb lib/xmpp4r/error.rb lib/xmpp4r/component.rb lib/xmpp4r/query.rb lib/xmpp4r/message.rb lib/xmpp4r/presence.rb lib/xmpp4r/bytestreams/helper/ibb/initiator.rb lib/xmpp4r/bytestreams/iq/si.rb lib/xmpp4r/bytestreams/iq/bytestreams.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb lib/xmpp4r/bytestreams/helper/ibb/base.rb lib/xmpp4r/bytestreams/helper/ibb/target.rb Bytestreams lib/xmpp4r/version/iq/version.rb lib/xmpp4r/version/helper/responder.rb lib/xmpp4r/version/helper/simpleresponder.rb Version lib/xmpp4r/feature_negotiation/iq/feature.rb FeatureNegotiation lib/xmpp4r/roster/helper/roster.rb lib/xmpp4r/roster/iq/roster.rb lib/xmpp4r/roster/x/roster.rb Roster lib/xmpp4r/muc/x/muc.rb lib/xmpp4r/muc/helper/mucclient.rb lib/xmpp4r/muc/x/mucuseritem.rb lib/xmpp4r/muc/helper/mucbrowser.rb lib/xmpp4r/muc/x/mucuserinvite.rb lib/xmpp4r/muc/helper/simplemucclient.rb MUC lib/xmpp4r/sasl.rb SASL lib/xmpp4r/bytestreams/helper/filetransfer.rb TransferSource FileTransfer lib/xmpp4r/delay/x/delay.rb Delay lib/xmpp4r/dataforms/x/data.rb Dataforms lib/xmpp4r/discovery/iq/discoinfo.rb lib/xmpp4r/discovery/iq/discoitems.rb Discovery lib/xmpp4r/vcard/helper/vcard.rb lib/xmpp4r/vcard/iq/vcard.rb Vcard Jabber Module: Jabber

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

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!)

[Source]

    # File lib/xmpp4r/roster/helper/roster.rb, line 28
28:       def initialize(stream)
29:         @stream = stream
30:         @items = {}
31:         @items_lock = Mutex.new
32:         @query_cbs = CallbackList.new
33:         @update_cbs = CallbackList.new
34:         @presence_cbs = CallbackList.new
35:         @subscription_cbs = CallbackList.new
36:         @subscription_request_cbs = CallbackList.new
37: 
38:         # Register cbs
39:         stream.add_iq_callback(120, self) { |iq|
40:           handle_iq(iq)
41:         }
42:         stream.add_presence_callback(120, self) { |pres|
43:           handle_presence(pres)
44:         }
45:         
46:         # Request the roster
47:         rosterget = Iq.new_rosterget
48:         stream.send(rosterget)
49:       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 224
224:       def [](jid)
225:         jid = JID.new(jid) unless jid.kind_of? JID
226: 
227:         @items_lock.synchronize {
228:           if @items.has_key?(jid)
229:             @items[jid]
230:           elsif @items.has_key?(jid.strip)
231:             @items[jid.strip]
232:           else
233:             nil
234:           end
235:         }
236:       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 327
327:       def accept_subscription(jid, iname=nil)
328:         pres = Presence.new.set_type(:subscribed).set_to(jid.strip)
329:         @stream.send(pres)
330: 
331:         unless self[jid.strip]
332:           request = Iq.new_rosterset
333:           request.query.add(Jabber::Roster::RosterItem.new(jid.strip, iname))
334:           @stream.send_with_id(request) { true }
335:         end
336:       end

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

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 303
303:       def add(jid, iname=nil, subscribe=false)
304:         if self[jid]
305:           self[jid].send
306:         else
307:           request = Iq.new_rosterset
308:           request.query.add(Jabber::Roster::RosterItem.new(jid, iname))
309:           @stream.send_with_id(request) { true }
310:           # Adding to list is handled by handle_iq
311:         end
312: 
313:         if subscribe
314:           # Actually the item *should* already be known now,
315:           # but we do it manually to exclude conditions.
316:           pres = Presence.new.set_type(:subscribe).set_to(jid.strip)
317:           @stream.send(pres)
318:         end
319:       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 85
85:       def add_presence_callback(prio = 0, ref = nil, &block)
86:         @presence_cbs.add(prio, ref, block)
87:       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 58
58:       def add_query_callback(prio = 0, ref = nil, &block)
59:         @query_cbs.add(prio, ref, block)
60:       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 100
100:       def add_subscription_callback(prio = 0, ref = nil, &block)
101:         @subscription_cbs.add(prio, ref, block)
102:       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 123
123:       def add_subscription_request_callback(prio = 0, ref = nil, &block)
124:         @subscription_request_cbs.add(prio, ref, block)
125:       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 71
71:       def add_update_callback(prio = 0, ref = nil, &block)
72:         @update_cbs.add(prio, ref, block)
73:       end

Decline a subscription request

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

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 341
341:       def decline_subscription(jid)
342:         pres = Presence.new.set_type(:unsubscribed).set_to(jid.strip)
343:         @stream.send(pres)
344:       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 241
241:       def find(jid)
242:         jid = JID.new(jid) unless jid.kind_of? JID
243: 
244:         j = jid.strip
245:         l = {}
246:         @items_lock.synchronize {
247:           @items.each_pair do |k, v|
248:             l[k] = v if k.strip == j
249:           end
250:         }
251:         l
252:       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 277
277:       def find_by_group(group)
278:         res = []
279:         @items_lock.synchronize {
280:           @items.each_pair do |jid,item|
281:             res.push(item) if item.groups.include?(group)
282:             res.push(item) if item.groups == [] and group.nil?
283:           end
284:         }
285:         res
286:       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 260
260:       def groups
261:         res = []
262:         @items_lock.synchronize {
263:           @items.each_pair do |jid,item|
264:             res += item.groups
265:             res += [nil] if item.groups == []
266:           end
267:         }
268:         res.uniq.sort { |a,b| a.to_s <=> b.to_s }
269:       end

Private Instance methods

Handle received <iq/> stanzas, used internally

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 132
132:       def handle_iq(iq)
133:         if iq.query.kind_of?(IqQueryRoster)
134:           # If the <iq/> contains <error/> we just ignore that
135:           # and assume an empty roster
136:           iq.query.each_element('item') do |item|
137:             # Handle deletion of item
138:             if item.subscription == :remove
139:               @items_lock.synchronize {
140:                 @items.delete(item.jid)
141:               }
142: 
143:             else
144:               olditem = nil
145:               @items_lock.synchronize {
146:                 if @items.has_key?(item.jid)
147:                   olditem = RosterItem.new(@stream).import(@items[item.jid])
148: 
149:                   # Clear first, because import doesn't
150:                   @items[item.jid].iname = nil
151:                   @items[item.jid].subscription = nil
152:                   @items[item.jid].ask = nil
153: 
154:                   @items[item.jid].import(item)
155:                 else
156:                   @items[item.jid] = RosterItem.new(@stream).import(item)
157:                 end
158:               }
159:               @update_cbs.process(olditem, @items[item.jid])
160:             end
161:           end
162: 
163:           @query_cbs.process(iq)
164:         else
165:           false
166:         end
167:       end

Handle received <presence/> stanzas, used internally

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 172
172:       def handle_presence(pres)
173:         item = self[pres.from]
174:         if [:subscribed, :unsubscribe, :unsubscribed].include?(pres.type)
175:           @subscription_cbs.process(item, pres)
176:           true
177:         elsif pres.type == :subscribe
178:           @subscription_request_cbs.process(item, pres)
179:           true
180:         else
181:           unless item.nil?
182:             update_presence(item, pres)
183:             true  # Callback consumed stanza
184:           else
185:             false # Callback did not consume stanza
186:           end
187:         end
188:       end

Update the presence of an item, used internally

Callbacks are called here

[Source]

     # File lib/xmpp4r/roster/helper/roster.rb, line 195
195:       def update_presence(item, pres)
196: 
197:         # This requires special handling, to announce all resources offline
198:         if pres.from.resource.nil? and pres.type == :error
199:           oldpresences = []
200:           item.each_presence do |oldpres|
201:             oldpresences << oldpres
202:           end
203: 
204:           item.add_presence(pres)
205:           oldpresences.each { |oldpres|
206:             @presence_cbs.process(item, oldpres, pres)
207:           }
208:         else
209:           oldpres = item.presence(pres.from).nil? ?
210:             nil :
211:             Presence.new.import(item.presence(pres.from))
212: 
213:           item.add_presence(pres)
214:           @presence_cbs.process(item, oldpres, pres)
215:         end
216:       end

[Validate]