blather 0.4.16 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gemtest +0 -0
 - data/CHANGELOG +12 -5
 - data/README.md +1 -1
 - data/Rakefile +1 -3
 - data/blather.gemspec +11 -24
 - data/examples/echo.rb +1 -0
 - data/examples/execute.rb +1 -0
 - data/examples/ping_pong.rb +1 -0
 - data/examples/print_hierarchy.rb +1 -0
 - data/examples/rosterprint.rb +1 -0
 - data/examples/stream_only.rb +1 -0
 - data/examples/xmpp4r/echo.rb +1 -0
 - data/lib/blather.rb +5 -1
 - data/lib/blather/client/client.rb +29 -154
 - data/lib/blather/client/dsl.rb +9 -3
 - data/lib/blather/client/dsl/pubsub.rb +2 -0
 - data/lib/blather/core_ext/eventmachine.rb +4 -1
 - data/lib/blather/core_ext/ipaddr.rb +2 -1
 - data/lib/blather/core_ext/nokogiri.rb +3 -1
 - data/lib/blather/errors/sasl_error.rb +1 -0
 - data/lib/blather/errors/stanza_error.rb +3 -1
 - data/lib/blather/errors/stream_error.rb +1 -0
 - data/lib/blather/file_transfer.rb +4 -1
 - data/lib/blather/file_transfer/s5b.rb +3 -4
 - data/lib/blather/jid.rb +2 -0
 - data/lib/blather/roster_item.rb +13 -3
 - data/lib/blather/stanza.rb +11 -3
 - data/lib/blather/stanza/disco/capabilities.rb +161 -0
 - data/lib/blather/stanza/disco/disco_info.rb +3 -1
 - data/lib/blather/stanza/disco/disco_items.rb +0 -1
 - data/lib/blather/stanza/iq.rb +8 -2
 - data/lib/blather/stanza/iq/command.rb +18 -3
 - data/lib/blather/stanza/iq/ibb.rb +6 -3
 - data/lib/blather/stanza/iq/s5b.rb +6 -3
 - data/lib/blather/stanza/iq/si.rb +6 -1
 - data/lib/blather/stanza/iq/vcard.rb +3 -1
 - data/lib/blather/stanza/message.rb +5 -0
 - data/lib/blather/stanza/presence.rb +1 -0
 - data/lib/blather/stanza/presence/c.rb +1 -0
 - data/lib/blather/stanza/presence/status.rb +1 -0
 - data/lib/blather/stanza/pubsub/event.rb +2 -4
 - data/lib/blather/stanza/pubsub/subscription.rb +1 -0
 - data/lib/blather/stanza/x.rb +8 -0
 - data/lib/blather/stream.rb +2 -0
 - data/lib/blather/stream/client.rb +1 -0
 - data/lib/blather/stream/component.rb +1 -0
 - data/lib/blather/stream/features.rb +4 -3
 - data/lib/blather/stream/features/resource.rb +4 -3
 - data/lib/blather/stream/features/sasl.rb +9 -6
 - data/lib/blather/stream/features/session.rb +5 -4
 - data/lib/blather/stream/features/tls.rb +4 -3
 - data/lib/blather/stream/parser.rb +4 -5
 - data/lib/blather/version.rb +2 -1
 - data/lib/blather/xmpp_node.rb +9 -0
 - data/spec/blather/client/client_spec.rb +14 -1
 - data/spec/blather/stanza/iq_spec.rb +16 -0
 - data/spec/blather/stanza/presence_spec.rb +1 -1
 - data/spec/blather/stanza_spec.rb +18 -0
 - data/spec/blather/stream/client_spec.rb +2 -2
 - metadata +52 -35
 - data/lib/blather/core_ext/active_support.rb +0 -45
 - data/lib/blather/core_ext/active_support/inheritable_attributes.rb +0 -117
 
    
        data/lib/blather/client/dsl.rb
    CHANGED
    
    | 
         @@ -217,8 +217,7 @@ module Blather 
     | 
|
| 
       217 
217 
     | 
    
         
             
                #
         
     | 
| 
       218 
218 
     | 
    
         
             
                # Use this to stop the propogation of the stanza though the handler chain.
         
     | 
| 
       219 
219 
     | 
    
         
             
                #
         
     | 
| 
       220 
     | 
    
         
            -
                # @example
         
     | 
| 
       221 
     | 
    
         
            -
                # Ignore all IQ stanzas
         
     | 
| 
      
 220 
     | 
    
         
            +
                # @example Ignore all IQ stanzas
         
     | 
| 
       222 
221 
     | 
    
         
             
                #
         
     | 
| 
       223 
222 
     | 
    
         
             
                #     before(:iq) { halt }
         
     | 
| 
       224 
223 
     | 
    
         
             
                def halt
         
     | 
| 
         @@ -230,7 +229,8 @@ module Blather 
     | 
|
| 
       230 
229 
     | 
    
         
             
                # Use this to jump out of the current handler and let the next registered
         
     | 
| 
       231 
230 
     | 
    
         
             
                # handler take care of the stanza
         
     | 
| 
       232 
231 
     | 
    
         
             
                #
         
     | 
| 
       233 
     | 
    
         
            -
                # @example
         
     | 
| 
      
 232 
     | 
    
         
            +
                # @example Pass a message to the next handler
         
     | 
| 
      
 233 
     | 
    
         
            +
                #
         
     | 
| 
       234 
234 
     | 
    
         
             
                # This is contrive and should be handled with guards, but pass a message
         
     | 
| 
       235 
235 
     | 
    
         
             
                # to the next handler based on the content
         
     | 
| 
       236 
236 
     | 
    
         
             
                #
         
     | 
| 
         @@ -252,12 +252,18 @@ module Blather 
     | 
|
| 
       252 
252 
     | 
    
         
             
                  client.write stanza
         
     | 
| 
       253 
253 
     | 
    
         
             
                end
         
     | 
| 
       254 
254 
     | 
    
         | 
| 
      
 255 
     | 
    
         
            +
                # Set the capabilities of the client
         
     | 
| 
      
 256 
     | 
    
         
            +
                #
         
     | 
| 
      
 257 
     | 
    
         
            +
                # @param [String] node the URI
         
     | 
| 
      
 258 
     | 
    
         
            +
                # @param [Array<Hash>] identities an array of identities
         
     | 
| 
      
 259 
     | 
    
         
            +
                # @param [Array<Hash>] features an array of features
         
     | 
| 
       255 
260 
     | 
    
         
             
                def set_caps(node, identities, features)
         
     | 
| 
       256 
261 
     | 
    
         
             
                  client.caps.node = node
         
     | 
| 
       257 
262 
     | 
    
         
             
                  client.caps.identities = identities
         
     | 
| 
       258 
263 
     | 
    
         
             
                  client.caps.features = features
         
     | 
| 
       259 
264 
     | 
    
         
             
                end
         
     | 
| 
       260 
265 
     | 
    
         | 
| 
      
 266 
     | 
    
         
            +
                # Send capabilities to the server
         
     | 
| 
       261 
267 
     | 
    
         
             
                def send_caps
         
     | 
| 
       262 
268 
     | 
    
         
             
                  client.register_handler :disco_info, :type => :get, :node => client.caps.node do |s|
         
     | 
| 
       263 
269 
     | 
    
         
             
                    r = client.caps.dup
         
     | 
| 
         @@ -1,4 +1,6 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # @private
         
     | 
| 
       1 
2 
     | 
    
         
             
            module EventMachine
         
     | 
| 
      
 3 
     | 
    
         
            +
              # @private
         
     | 
| 
       2 
4 
     | 
    
         
             
              module Protocols
         
     | 
| 
       3 
5 
     | 
    
         
             
                # Basic SOCKS v5 client implementation
         
     | 
| 
       4 
6 
     | 
    
         
             
                #
         
     | 
| 
         @@ -16,6 +18,7 @@ module EventMachine 
     | 
|
| 
       16 
18 
     | 
    
         
             
                #
         
     | 
| 
       17 
19 
     | 
    
         
             
                # EM.connect socks_host, socks_port, MyConn, host, port
         
     | 
| 
       18 
20 
     | 
    
         
             
                #
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @private
         
     | 
| 
       19 
22 
     | 
    
         
             
                class Socks5 < Connection
         
     | 
| 
       20 
23 
     | 
    
         
             
                  def initialize(host, port)
         
     | 
| 
       21 
24 
     | 
    
         
             
                    @host = host
         
     | 
| 
         @@ -119,4 +122,4 @@ module EventMachine 
     | 
|
| 
       119 
122 
     | 
    
         
             
                  end
         
     | 
| 
       120 
123 
     | 
    
         
             
                end
         
     | 
| 
       121 
124 
     | 
    
         
             
              end
         
     | 
| 
       122 
     | 
    
         
            -
            end
         
     | 
| 
      
 125 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,12 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # @private
         
     | 
| 
       1 
2 
     | 
    
         
             
            module Nokogiri
         
     | 
| 
       2 
3 
     | 
    
         
             
            module XML
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
      
 5 
     | 
    
         
            +
              # Nokogiri::Node extensions
         
     | 
| 
       4 
6 
     | 
    
         
             
              class Node
         
     | 
| 
       5 
7 
     | 
    
         
             
                # Alias #name to #element_name so we can use #name in an XMPP Stanza context
         
     | 
| 
       6 
8 
     | 
    
         
             
                alias_method :element_name, :name
         
     | 
| 
       7 
9 
     | 
    
         
             
                alias_method :element_name=, :name=
         
     | 
| 
       8 
10 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
                alias_method :attr_set, :[]= 
     | 
| 
      
 11 
     | 
    
         
            +
                alias_method :attr_set, :[]=
         
     | 
| 
       10 
12 
     | 
    
         
             
                # Override Nokogiri's attribute setter to add the ability to kill an attribute
         
     | 
| 
       11 
13 
     | 
    
         
             
                # by setting it to nil and to be able to lookup an attribute by symbol
         
     | 
| 
       12 
14 
     | 
    
         
             
                #
         
     | 
| 
         @@ -5,7 +5,9 @@ module Blather 
     | 
|
| 
       5 
5 
     | 
    
         
             
            #
         
     | 
| 
       6 
6 
     | 
    
         
             
            # @handler :stanza_error
         
     | 
| 
       7 
7 
     | 
    
         
             
            class StanzaError < BlatherError
         
     | 
| 
      
 8 
     | 
    
         
            +
              # @private
         
     | 
| 
       8 
9 
     | 
    
         
             
              STANZA_ERR_NS = 'urn:ietf:params:xml:ns:xmpp-stanzas'
         
     | 
| 
      
 10 
     | 
    
         
            +
              # @private
         
     | 
| 
       9 
11 
     | 
    
         
             
              VALID_TYPES = [:cancel, :continue, :modify, :auth, :wait].freeze
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
              register :stanza_error
         
     | 
| 
         @@ -105,4 +107,4 @@ class StanzaError < BlatherError 
     | 
|
| 
       105 
107 
     | 
    
         
             
              alias_method :to_s, :inspect
         
     | 
| 
       106 
108 
     | 
    
         
             
            end  # StanzaError
         
     | 
| 
       107 
109 
     | 
    
         | 
| 
       108 
     | 
    
         
            -
            end  # Blather
         
     | 
| 
      
 110 
     | 
    
         
            +
            end  # Blather
         
     | 
| 
         @@ -82,19 +82,22 @@ module Blather 
     | 
|
| 
       82 
82 
     | 
    
         
             
                    @transferred = 0
         
     | 
| 
       83 
83 
     | 
    
         
             
                  end
         
     | 
| 
       84 
84 
     | 
    
         | 
| 
      
 85 
     | 
    
         
            +
                  # @private
         
     | 
| 
       85 
86 
     | 
    
         
             
                  def post_init
         
     | 
| 
       86 
87 
     | 
    
         
             
                    @file = File.open(@path, "w")
         
     | 
| 
       87 
88 
     | 
    
         
             
                  end
         
     | 
| 
       88 
89 
     | 
    
         | 
| 
      
 90 
     | 
    
         
            +
                  # @private
         
     | 
| 
       89 
91 
     | 
    
         
             
                  def receive_data(data)
         
     | 
| 
       90 
92 
     | 
    
         
             
                    @transferred += data.size
         
     | 
| 
       91 
93 
     | 
    
         
             
                    @file.write data
         
     | 
| 
       92 
94 
     | 
    
         
             
                  end
         
     | 
| 
       93 
95 
     | 
    
         | 
| 
      
 96 
     | 
    
         
            +
                  # @private
         
     | 
| 
       94 
97 
     | 
    
         
             
                  def unbind
         
     | 
| 
       95 
98 
     | 
    
         
             
                    @file.close
         
     | 
| 
       96 
99 
     | 
    
         
             
                    File.delete(@path) unless @transferred == @size
         
     | 
| 
       97 
100 
     | 
    
         
             
                  end
         
     | 
| 
       98 
101 
     | 
    
         
             
                end
         
     | 
| 
       99 
102 
     | 
    
         
             
              end
         
     | 
| 
       100 
     | 
    
         
            -
            end
         
     | 
| 
      
 103 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -85,6 +85,7 @@ module Blather 
     | 
|
| 
       85 
85 
     | 
    
         
             
                    end
         
     | 
| 
       86 
86 
     | 
    
         
             
                  end
         
     | 
| 
       87 
87 
     | 
    
         | 
| 
      
 88 
     | 
    
         
            +
                  # @private
         
     | 
| 
       88 
89 
     | 
    
         
             
                  class SocketConnection < EM::P::Socks5
         
     | 
| 
       89 
90 
     | 
    
         
             
                    include EM::Deferrable
         
     | 
| 
       90 
91 
     | 
    
         | 
| 
         @@ -96,9 +97,7 @@ module Blather 
     | 
|
| 
       96 
97 
     | 
    
         | 
| 
       97 
98 
     | 
    
         
             
                    def post_init
         
     | 
| 
       98 
99 
     | 
    
         
             
                      self.succeed
         
     | 
| 
       99 
     | 
    
         
            -
                      class << self
         
     | 
| 
       100 
     | 
    
         
            -
                        include @@handler
         
     | 
| 
       101 
     | 
    
         
            -
                      end
         
     | 
| 
      
 100 
     | 
    
         
            +
                      (class << self; self; end).include(@@handler)
         
     | 
| 
       102 
101 
     | 
    
         
             
                      send(:initialize, *@params)
         
     | 
| 
       103 
102 
     | 
    
         
             
                      post_init
         
     | 
| 
       104 
103 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -109,4 +108,4 @@ module Blather 
     | 
|
| 
       109 
108 
     | 
    
         
             
                  end
         
     | 
| 
       110 
109 
     | 
    
         
             
                end
         
     | 
| 
       111 
110 
     | 
    
         
             
              end
         
     | 
| 
       112 
     | 
    
         
            -
            end
         
     | 
| 
      
 111 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/blather/jid.rb
    CHANGED
    
    | 
         @@ -46,12 +46,14 @@ module Blather 
     | 
|
| 
       46 
46 
     | 
    
         
             
              class JID
         
     | 
| 
       47 
47 
     | 
    
         
             
                include Comparable
         
     | 
| 
       48 
48 
     | 
    
         | 
| 
      
 49 
     | 
    
         
            +
                # Validating pattern for JID string
         
     | 
| 
       49 
50 
     | 
    
         
             
                PATTERN = /^(?:([^@]*)@)??([^@\/]*)(?:\/(.*?))?$/.freeze
         
     | 
| 
       50 
51 
     | 
    
         | 
| 
       51 
52 
     | 
    
         
             
                attr_reader :node,
         
     | 
| 
       52 
53 
     | 
    
         
             
                            :domain,
         
     | 
| 
       53 
54 
     | 
    
         
             
                            :resource
         
     | 
| 
       54 
55 
     | 
    
         | 
| 
      
 56 
     | 
    
         
            +
                # @private
         
     | 
| 
       55 
57 
     | 
    
         
             
                def self.new(node, domain = nil, resource = nil)
         
     | 
| 
       56 
58 
     | 
    
         
             
                  node.is_a?(JID) ? node : super
         
     | 
| 
       57 
59 
     | 
    
         
             
                end
         
     | 
    
        data/lib/blather/roster_item.rb
    CHANGED
    
    | 
         @@ -3,6 +3,7 @@ module Blather 
     | 
|
| 
       3 
3 
     | 
    
         
             
              # RosterItems hold internal representations of the user's roster
         
     | 
| 
       4 
4 
     | 
    
         
             
              # including each JID's status.
         
     | 
| 
       5 
5 
     | 
    
         
             
              class RosterItem
         
     | 
| 
      
 6 
     | 
    
         
            +
                # @private
         
     | 
| 
       6 
7 
     | 
    
         
             
                VALID_SUBSCRIPTION_TYPES = [:both, :from, :none, :remove, :to].freeze
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
9 
     | 
    
         
             
                attr_reader :jid,
         
     | 
| 
         @@ -12,6 +13,7 @@ module Blather 
     | 
|
| 
       12 
13 
     | 
    
         
             
                attr_accessor :name,
         
     | 
| 
       13 
14 
     | 
    
         
             
                              :groups
         
     | 
| 
       14 
15 
     | 
    
         | 
| 
      
 16 
     | 
    
         
            +
                # @private
         
     | 
| 
       15 
17 
     | 
    
         
             
                def self.new(item)
         
     | 
| 
       16 
18 
     | 
    
         
             
                  return item if item.is_a?(self)
         
     | 
| 
       17 
19 
     | 
    
         
             
                  super
         
     | 
| 
         @@ -118,8 +120,12 @@ module Blather 
     | 
|
| 
       118 
120 
     | 
    
         
             
                  r
         
     | 
| 
       119 
121 
     | 
    
         
             
                end
         
     | 
| 
       120 
122 
     | 
    
         | 
| 
       121 
     | 
    
         
            -
                 
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
      
 123 
     | 
    
         
            +
                # Compare two RosterItems by their JID
         
     | 
| 
      
 124 
     | 
    
         
            +
                #
         
     | 
| 
      
 125 
     | 
    
         
            +
                # @param [Blather::JID] other the JID to compare against
         
     | 
| 
      
 126 
     | 
    
         
            +
                # @return [Fixnum<-1, 0, 1>]
         
     | 
| 
      
 127 
     | 
    
         
            +
                def <=>(other)
         
     | 
| 
      
 128 
     | 
    
         
            +
                  JID.new(self.jid) <=> JID.new(other.jid)
         
     | 
| 
       123 
129 
     | 
    
         
             
                end
         
     | 
| 
       124 
130 
     | 
    
         | 
| 
       125 
131 
     | 
    
         
             
                # Compare two RosterItem objects by name, type and category
         
     | 
| 
         @@ -130,7 +136,11 @@ module Blather 
     | 
|
| 
       130 
136 
     | 
    
         
             
                  o.jid == self.jid &&
         
     | 
| 
       131 
137 
     | 
    
         
             
                  o.groups == self.groups
         
     | 
| 
       132 
138 
     | 
    
         
             
                end
         
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 141 
     | 
    
         
            +
                def ==(o)
         
     | 
| 
      
 142 
     | 
    
         
            +
                  eql?(o)
         
     | 
| 
      
 143 
     | 
    
         
            +
                end
         
     | 
| 
       134 
144 
     | 
    
         
             
              end #RosterItem
         
     | 
| 
       135 
145 
     | 
    
         | 
| 
       136 
146 
     | 
    
         
             
            end
         
     | 
    
        data/lib/blather/stanza.rb
    CHANGED
    
    | 
         @@ -54,16 +54,24 @@ module Blather 
     | 
|
| 
       54 
54 
     | 
    
         | 
| 
       55 
55 
     | 
    
         
             
                # Creates a copy with to and from swapped
         
     | 
| 
       56 
56 
     | 
    
         
             
                #
         
     | 
| 
      
 57 
     | 
    
         
            +
                # @param [Hash] opts options to pass to reply!
         
     | 
| 
      
 58 
     | 
    
         
            +
                # @option opts [Boolean] :remove_children Wether or not to remove child nodes when replying
         
     | 
| 
      
 59 
     | 
    
         
            +
                #
         
     | 
| 
       57 
60 
     | 
    
         
             
                # @return [Blather::Stanza]
         
     | 
| 
       58 
     | 
    
         
            -
                def reply
         
     | 
| 
       59 
     | 
    
         
            -
                  self.dup.reply!
         
     | 
| 
      
 61 
     | 
    
         
            +
                def reply(opts = {})
         
     | 
| 
      
 62 
     | 
    
         
            +
                  self.dup.reply! opts
         
     | 
| 
       60 
63 
     | 
    
         
             
                end
         
     | 
| 
       61 
64 
     | 
    
         | 
| 
       62 
65 
     | 
    
         
             
                # Swaps from and to
         
     | 
| 
       63 
66 
     | 
    
         
             
                #
         
     | 
| 
      
 67 
     | 
    
         
            +
                # @param [Hash] opts Misc options
         
     | 
| 
      
 68 
     | 
    
         
            +
                # @option opts [Boolean] :remove_children Wether or not to remove child nodes when replying
         
     | 
| 
      
 69 
     | 
    
         
            +
                #
         
     | 
| 
       64 
70 
     | 
    
         
             
                # @return [self]
         
     | 
| 
       65 
     | 
    
         
            -
                def reply!
         
     | 
| 
      
 71 
     | 
    
         
            +
                def reply!(opts = {})
         
     | 
| 
      
 72 
     | 
    
         
            +
                  opts = {:remove_children => false}.merge opts
         
     | 
| 
       66 
73 
     | 
    
         
             
                  self.to, self.from = self.from, self.to
         
     | 
| 
      
 74 
     | 
    
         
            +
                  self.children.remove if opts[:remove_children]
         
     | 
| 
       67 
75 
     | 
    
         
             
                  self
         
     | 
| 
       68 
76 
     | 
    
         
             
                end
         
     | 
| 
       69 
77 
     | 
    
         | 
| 
         @@ -0,0 +1,161 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Blather
         
     | 
| 
      
 2 
     | 
    
         
            +
            class Stanza
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              # # Capabilities Stanza
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              # [XEP-0115 Entity Capabilities](http://xmpp.org/extensions/xep-0115.html)
         
     | 
| 
      
 7 
     | 
    
         
            +
              #
         
     | 
| 
      
 8 
     | 
    
         
            +
              # XMPP protocol extension for broadcasting and dynamically discovering client, device, or generic entity capabilities.
         
     | 
| 
      
 9 
     | 
    
         
            +
              #
         
     | 
| 
      
 10 
     | 
    
         
            +
              class Capabilities < Blather::Stanza::DiscoInfo
         
     | 
| 
      
 11 
     | 
    
         
            +
                def self.new
         
     | 
| 
      
 12 
     | 
    
         
            +
                  super :result
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                # A string that is used to verify the identity and supported features of the entity.
         
     | 
| 
      
 16 
     | 
    
         
            +
                #
         
     | 
| 
      
 17 
     | 
    
         
            +
                # @return [String]
         
     | 
| 
      
 18 
     | 
    
         
            +
                def ver
         
     | 
| 
      
 19 
     | 
    
         
            +
                  generate_ver identities, features
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                # A URI that uniquely identifies a software application, typically a URL at the
         
     | 
| 
      
 23 
     | 
    
         
            +
                # website of the project or company that produces the software.
         
     | 
| 
      
 24 
     | 
    
         
            +
                #
         
     | 
| 
      
 25 
     | 
    
         
            +
                # @param [String] node the node URI
         
     | 
| 
      
 26 
     | 
    
         
            +
                def node=(node)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @bare_node = node
         
     | 
| 
      
 28 
     | 
    
         
            +
                  super "#{node}##{ver}"
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                # Add an array of identities
         
     | 
| 
      
 32 
     | 
    
         
            +
                # @param identities the array of identities, passed directly to Identity.new
         
     | 
| 
      
 33 
     | 
    
         
            +
                def identities=(identities)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  super identities
         
     | 
| 
      
 35 
     | 
    
         
            +
                  regenerate_full_node
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                # Add an array of features
         
     | 
| 
      
 39 
     | 
    
         
            +
                # @param features the array of features, passed directly to Feature.new
         
     | 
| 
      
 40 
     | 
    
         
            +
                def features=(features)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  super features
         
     | 
| 
      
 42 
     | 
    
         
            +
                  regenerate_full_node
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                # The generated Presence::C node
         
     | 
| 
      
 46 
     | 
    
         
            +
                #
         
     | 
| 
      
 47 
     | 
    
         
            +
                # @return [Blather::Stanza::Presence::C]
         
     | 
| 
      
 48 
     | 
    
         
            +
                def c
         
     | 
| 
      
 49 
     | 
    
         
            +
                  Blather::Stanza::Presence::C.new @bare_node, ver
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                private
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def regenerate_full_node
         
     | 
| 
      
 55 
     | 
    
         
            +
                  self.node = @bare_node
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                def generate_ver_str(identities, features, forms = [])
         
     | 
| 
      
 59 
     | 
    
         
            +
                  # 1.  Initialize an empty string S.
         
     | 
| 
      
 60 
     | 
    
         
            +
                  s = ''
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  # 2. Sort the service discovery identities by category and
         
     | 
| 
      
 63 
     | 
    
         
            +
                  # then by type (if it exists) and then by xml:lang (if it
         
     | 
| 
      
 64 
     | 
    
         
            +
                  # exists), formatted as CATEGORY '/' [TYPE] '/' [LANG] '/'
         
     | 
| 
      
 65 
     | 
    
         
            +
                  # [NAME]. Note that each slash is included even if the TYPE,
         
     | 
| 
      
 66 
     | 
    
         
            +
                  # LANG, or NAME is not included.
         
     | 
| 
      
 67 
     | 
    
         
            +
                  identities.sort! do |identity1, identity2|
         
     | 
| 
      
 68 
     | 
    
         
            +
                    cmp_result = nil
         
     | 
| 
      
 69 
     | 
    
         
            +
                    [:category, :type, :xml_lang, :name].each do |field|
         
     | 
| 
      
 70 
     | 
    
         
            +
                      value1 = identity1.send(field)
         
     | 
| 
      
 71 
     | 
    
         
            +
                      value2 = identity2.send(field)
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                      if value1 != value2
         
     | 
| 
      
 74 
     | 
    
         
            +
                        cmp_result = value1 <=> value2
         
     | 
| 
      
 75 
     | 
    
         
            +
                        break
         
     | 
| 
      
 76 
     | 
    
         
            +
                      end
         
     | 
| 
      
 77 
     | 
    
         
            +
                    end
         
     | 
| 
      
 78 
     | 
    
         
            +
                    cmp_result
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  # 3. For each identity, append the 'category/type/lang/name' to
         
     | 
| 
      
 82 
     | 
    
         
            +
                  # S, followed by the '<' character.
         
     | 
| 
      
 83 
     | 
    
         
            +
                  s += identities.collect do |identity|
         
     | 
| 
      
 84 
     | 
    
         
            +
                    [:category, :type, :xml_lang, :name].collect do |field|
         
     | 
| 
      
 85 
     | 
    
         
            +
                      identity.send(field).to_s
         
     | 
| 
      
 86 
     | 
    
         
            +
                    end.join('/') + '<'
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end.join
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  # 4. Sort the supported service discovery features.
         
     | 
| 
      
 90 
     | 
    
         
            +
                  features.sort! { |feature1, feature2| feature1.var <=> feature2.var }
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  # 5. For each feature, append the feature to S, followed by the
         
     | 
| 
      
 93 
     | 
    
         
            +
                  # '<' character.
         
     | 
| 
      
 94 
     | 
    
         
            +
                  s += features.collect { |feature| feature.var.to_s + '<' }.join
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  # 6. If the service discovery information response includes
         
     | 
| 
      
 97 
     | 
    
         
            +
                  # XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e., by
         
     | 
| 
      
 98 
     | 
    
         
            +
                  # the XML character data of the <value/> element).
         
     | 
| 
      
 99 
     | 
    
         
            +
                  forms.sort! do |form1, form2|
         
     | 
| 
      
 100 
     | 
    
         
            +
                    fform_type1 = form1.field 'FORM_TYPE'
         
     | 
| 
      
 101 
     | 
    
         
            +
                    fform_type2 = form2.field 'FORM_TYPE'
         
     | 
| 
      
 102 
     | 
    
         
            +
                    form_type1 = fform_type1 ? fform_type1.values.to_s : nil
         
     | 
| 
      
 103 
     | 
    
         
            +
                    form_type2 = fform_type2 ? fform_type2.values.to_s : nil
         
     | 
| 
      
 104 
     | 
    
         
            +
                    form_type1 <=> form_type2
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  # 7. For each extended service discovery information form:
         
     | 
| 
      
 108 
     | 
    
         
            +
                  forms.each do |form|
         
     | 
| 
      
 109 
     | 
    
         
            +
                    # 7.1. Append the XML character data of the FORM_TYPE field's
         
     | 
| 
      
 110 
     | 
    
         
            +
                    # <value/> element, followed by the '<' character.
         
     | 
| 
      
 111 
     | 
    
         
            +
                    fform_type = form.field 'FORM_TYPE'
         
     | 
| 
      
 112 
     | 
    
         
            +
                    form_type = fform_type ? fform_type.values.to_s : nil
         
     | 
| 
      
 113 
     | 
    
         
            +
                    s += "#{form_type}<"
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                    # 7.2. Sort the fields by the value of the "var" attribute
         
     | 
| 
      
 116 
     | 
    
         
            +
                    fields = form.fields.sort { |field1, field2| field1.var <=> field2.var }
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                    # 7.3. For each field:
         
     | 
| 
      
 119 
     | 
    
         
            +
                    fields.each do |field|
         
     | 
| 
      
 120 
     | 
    
         
            +
                      # 7.3.1. Append the value of the "var" attribute, followed by
         
     | 
| 
      
 121 
     | 
    
         
            +
                      # the '<' character.
         
     | 
| 
      
 122 
     | 
    
         
            +
                      s += "#{field.var}<"
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                      # 7.3.2. Sort values by the XML character data of the <value/> element
         
     | 
| 
      
 125 
     | 
    
         
            +
                      # values = field.values.sort { |value1, value2| value1 <=> value2 }
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                      # 7.3.3. For each <value/> element, append the XML character
         
     | 
| 
      
 128 
     | 
    
         
            +
                      # data, followed by the '<' character.
         
     | 
| 
      
 129 
     | 
    
         
            +
                      # s += values.collect { |value| "#{value}<" }.join
         
     | 
| 
      
 130 
     | 
    
         
            +
                      s += "#{field.value}<"
         
     | 
| 
      
 131 
     | 
    
         
            +
                    end
         
     | 
| 
      
 132 
     | 
    
         
            +
                  end
         
     | 
| 
      
 133 
     | 
    
         
            +
                  s
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                def generate_ver(identities, features, forms = [], hash = 'sha-1')
         
     | 
| 
      
 137 
     | 
    
         
            +
                  s = generate_ver_str identities, features, forms
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                  # 9. Compute the verification string by hashing S using the
         
     | 
| 
      
 140 
     | 
    
         
            +
                  # algorithm specified in the 'hash' attribute (e.g., SHA-1 as
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # defined in RFC 3174). The hashed data MUST be generated
         
     | 
| 
      
 142 
     | 
    
         
            +
                  # with binary output and encoded using Base64 as specified in
         
     | 
| 
      
 143 
     | 
    
         
            +
                  # Section 4 of RFC 4648 (note: the Base64 output MUST NOT
         
     | 
| 
      
 144 
     | 
    
         
            +
                  # include whitespace and MUST set padding bits to zero).
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                  # See http://www.iana.org/assignments/hash-function-text-names
         
     | 
| 
      
 147 
     | 
    
         
            +
                  hash_klass = case hash
         
     | 
| 
      
 148 
     | 
    
         
            +
                                 when 'md2' then nil
         
     | 
| 
      
 149 
     | 
    
         
            +
                                 when 'md5' then Digest::MD5
         
     | 
| 
      
 150 
     | 
    
         
            +
                                 when 'sha-1' then Digest::SHA1
         
     | 
| 
      
 151 
     | 
    
         
            +
                                 when 'sha-224' then nil
         
     | 
| 
      
 152 
     | 
    
         
            +
                                 when 'sha-256' then Digest::SHA256
         
     | 
| 
      
 153 
     | 
    
         
            +
                                 when 'sha-384' then Digest::SHA384
         
     | 
| 
      
 154 
     | 
    
         
            +
                                 when 'sha-512' then Digest::SHA512
         
     | 
| 
      
 155 
     | 
    
         
            +
                               end
         
     | 
| 
      
 156 
     | 
    
         
            +
                  hash_klass ? [hash_klass::digest(s)].pack('m').strip : nil
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
              end # Caps
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
            end # Stanza
         
     | 
| 
      
 161 
     | 
    
         
            +
            end # Blather
         
     | 
| 
         @@ -66,8 +66,9 @@ class Stanza 
     | 
|
| 
       66 
66 
     | 
    
         
             
                  super o, *(fields + [:identities, :features])
         
     | 
| 
       67 
67 
     | 
    
         
             
                end
         
     | 
| 
       68 
68 
     | 
    
         | 
| 
      
 69 
     | 
    
         
            +
                # DiscoInfo::Identity
         
     | 
| 
       69 
70 
     | 
    
         
             
                class Identity < XMPPNode
         
     | 
| 
       70 
     | 
    
         
            -
                  # Create a new DiscoInfo 
     | 
| 
      
 71 
     | 
    
         
            +
                  # Create a new DiscoInfo::Identity
         
     | 
| 
       71 
72 
     | 
    
         
             
                  # @overload new(node)
         
     | 
| 
       72 
73 
     | 
    
         
             
                  #   Imports the XML::Node to create a Identity object
         
     | 
| 
       73 
74 
     | 
    
         
             
                  #   @param [XML::Node] node the node object to import
         
     | 
| 
         @@ -158,6 +159,7 @@ class Stanza 
     | 
|
| 
       158 
159 
     | 
    
         
             
                  end
         
     | 
| 
       159 
160 
     | 
    
         
             
                end # Identity
         
     | 
| 
       160 
161 
     | 
    
         | 
| 
      
 162 
     | 
    
         
            +
                # DiscoInfo::Feature
         
     | 
| 
       161 
163 
     | 
    
         
             
                class Feature < XMPPNode
         
     | 
| 
       162 
164 
     | 
    
         
             
                  # Create a new DiscoInfo::Feature object
         
     | 
| 
       163 
165 
     | 
    
         
             
                  # @overload new(node)
         
     |