xmpp4r 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/ChangeLog +12 -0
  2. data/Rakefile +2 -4
  3. data/data/doc/xmpp4r/examples/advanced/adventure/adventuremuc.rb +6 -6
  4. data/data/doc/xmpp4r/examples/advanced/adventure/world.rb +3 -3
  5. data/data/doc/xmpp4r/examples/advanced/minimuc.rb +5 -5
  6. data/data/doc/xmpp4r/examples/advanced/xmpping.rb +17 -4
  7. data/data/doc/xmpp4r/examples/advanced/xmppingrc.sample +5 -0
  8. data/data/doc/xmpp4r/examples/basic/echo_threaded.rb +6 -2
  9. data/data/doc/xmpp4r/examples/basic/muc_owner_config.rb +13 -0
  10. data/lib/xmpp4r.rb +0 -6
  11. data/lib/xmpp4r/bytestreams/helper/filetransfer.rb +6 -7
  12. data/lib/xmpp4r/bytestreams/helper/ibb/base.rb +5 -6
  13. data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +3 -5
  14. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb +1 -1
  15. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb +10 -8
  16. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +3 -5
  17. data/lib/xmpp4r/bytestreams/iq/bytestreams.rb +11 -17
  18. data/lib/xmpp4r/bytestreams/iq/si.rb +13 -32
  19. data/lib/xmpp4r/callbacks.rb +124 -0
  20. data/lib/xmpp4r/client.rb +2 -5
  21. data/lib/xmpp4r/command/helper/responder.rb +53 -0
  22. data/lib/xmpp4r/command/iq/command.rb +154 -0
  23. data/lib/xmpp4r/connection.rb +49 -12
  24. data/lib/xmpp4r/dataforms/x/data.rb +66 -29
  25. data/lib/xmpp4r/delay/x/delay.rb +2 -3
  26. data/lib/xmpp4r/discovery/iq/discoinfo.rb +20 -33
  27. data/lib/xmpp4r/discovery/iq/discoitems.rb +5 -28
  28. data/lib/xmpp4r/error.rb +5 -10
  29. data/lib/xmpp4r/feature_negotiation/iq/feature.rb +2 -20
  30. data/lib/xmpp4r/httpbinding.rb +5 -0
  31. data/lib/xmpp4r/httpbinding/client.rb +285 -0
  32. data/lib/xmpp4r/iq.rb +22 -41
  33. data/lib/xmpp4r/message.rb +8 -38
  34. data/lib/xmpp4r/muc.rb +2 -0
  35. data/lib/xmpp4r/muc/helper/mucclient.rb +50 -1
  36. data/lib/xmpp4r/muc/helper/simplemucclient.rb +2 -2
  37. data/lib/xmpp4r/muc/iq/mucowner.rb +11 -0
  38. data/lib/xmpp4r/muc/x/muc.rb +2 -30
  39. data/lib/xmpp4r/muc/x/mucuserinvite.rb +4 -2
  40. data/lib/xmpp4r/muc/x/mucuseritem.rb +4 -2
  41. data/lib/xmpp4r/presence.rb +7 -35
  42. data/lib/xmpp4r/pubsub.rb +1 -0
  43. data/lib/xmpp4r/pubsub/helper/nodebrowser.rb +174 -0
  44. data/lib/xmpp4r/pubsub/helper/nodehelper.rb +153 -0
  45. data/lib/xmpp4r/pubsub/helper/servicehelper.rb +326 -0
  46. data/lib/xmpp4r/pubsub/iq/pubsub.rb +19 -0
  47. data/lib/xmpp4r/pubsub/stanzas/event.rb +49 -0
  48. data/lib/xmpp4r/pubsub/stanzas/item.rb +27 -0
  49. data/lib/xmpp4r/pubsub/stanzas/items.rb +35 -0
  50. data/lib/xmpp4r/pubsub/stanzas/subscription.rb +58 -0
  51. data/lib/xmpp4r/query.rb +4 -32
  52. data/lib/xmpp4r/rexmladdons.rb +7 -772
  53. data/lib/xmpp4r/roster/helper/roster.rb +29 -50
  54. data/lib/xmpp4r/roster/iq/roster.rb +6 -35
  55. data/lib/xmpp4r/roster/x/roster.rb +13 -30
  56. data/lib/xmpp4r/rpc.rb +2 -0
  57. data/lib/xmpp4r/rpc/helper/client.rb +114 -0
  58. data/lib/xmpp4r/rpc/helper/server.rb +75 -0
  59. data/lib/xmpp4r/rpc/helper/xmlrpcaddons.rb +57 -0
  60. data/lib/xmpp4r/rpc/iq/rpc.rb +24 -0
  61. data/lib/xmpp4r/sasl.rb +1 -1
  62. data/lib/xmpp4r/semaphore.rb +38 -0
  63. data/lib/xmpp4r/stream.rb +104 -165
  64. data/lib/xmpp4r/streamparser.rb +2 -2
  65. data/lib/xmpp4r/vcard/iq/vcard.rb +5 -12
  66. data/lib/xmpp4r/version/helper/responder.rb +2 -1
  67. data/lib/xmpp4r/version/iq/version.rb +6 -18
  68. data/lib/xmpp4r/x.rb +20 -26
  69. data/lib/xmpp4r/xmpp4r.rb +1 -1
  70. data/lib/xmpp4r/xmppelement.rb +152 -0
  71. data/lib/xmpp4r/{xmlstanza.rb → xmppstanza.rb} +17 -29
  72. data/setup.rb +1 -0
  73. data/test/bytestreams/tc_ibb.rb +8 -8
  74. data/test/dataforms/tc_data.rb +81 -0
  75. data/test/lib/clienttester.rb +20 -17
  76. data/test/muc/tc_muc_mucclient.rb +48 -23
  77. data/test/muc/tc_muc_simplemucclient.rb +7 -4
  78. data/test/muc/tc_mucowner.rb +50 -0
  79. data/test/pubsub/tc_helper.rb +227 -0
  80. data/test/roster/tc_helper.rb +181 -55
  81. data/test/roster/tc_iqqueryroster.rb +33 -0
  82. data/test/roster/tc_xroster.rb +6 -3
  83. data/test/rpc/tc_helper.rb +84 -0
  84. data/test/tc_callbacks.rb +2 -1
  85. data/test/tc_class_names.rb +9 -1
  86. data/test/tc_error.rb +1 -0
  87. data/test/tc_iq.rb +13 -12
  88. data/test/tc_message.rb +1 -0
  89. data/test/tc_presence.rb +1 -0
  90. data/test/tc_rexml.rb +1 -1
  91. data/test/tc_stream.rb +147 -102
  92. data/test/tc_streamComponent.rb +94 -0
  93. data/test/tc_streamError.rb +67 -29
  94. data/test/tc_streamSend.rb +1 -1
  95. data/test/tc_xmppstanza.rb +125 -0
  96. data/test/ts_xmpp4r.rb +37 -28
  97. data/test/version/tc_helper.rb +14 -0
  98. data/test/version/tc_iqqueryversion.rb +4 -3
  99. metadata +163 -123
  100. data/data/doc/xmpp4r/examples/basic/echo_nonthreaded.rb +0 -32
  101. data/lib/callbacks.rb +0 -122
  102. data/test/tc_streamThreaded.rb +0 -168
  103. data/test/tc_xmlstanza.rb +0 -76
@@ -4,12 +4,14 @@
4
4
 
5
5
  module Jabber
6
6
  module Bytestreams
7
+ NS_BYTESTREAMS = 'http://jabber.org/protocol/bytestreams'
8
+
7
9
  ##
8
10
  # Class for accessing <query/> elements with
9
11
  # xmlns='http://jabber.org/protocol/bytestreams'
10
12
  # in <iq/> stanzas.
11
13
  class IqQueryBytestreams < IqQuery
12
- NS_BYTESTREAMS = 'http://jabber.org/protocol/bytestreams'
14
+ name_xmlns 'query', NS_BYTESTREAMS
13
15
 
14
16
  ##
15
17
  # Initialize such a <query/>
@@ -17,21 +19,10 @@ module Jabber
17
19
  # mode:: [Symbol] :tcp or :udp
18
20
  def initialize(sid=nil, mode=nil)
19
21
  super()
20
- add_namespace(IqQueryBytestreams::NS_BYTESTREAMS)
21
22
  self.sid = sid
22
23
  self.mode = mode
23
24
  end
24
25
 
25
- def typed_add(xe)
26
- if xe.kind_of?(REXML::Element) and xe.name == 'streamhost'
27
- super StreamHost.new.import(xe)
28
- elsif xe.kind_of?(REXML::Element) and xe.name == 'streamhost-used'
29
- super StreamHostUsed.new.import(xe)
30
- else
31
- super xe
32
- end
33
- end
34
-
35
26
  ##
36
27
  # Session-ID
37
28
  def sid
@@ -87,19 +78,20 @@ module Jabber
87
78
  end
88
79
  end
89
80
 
90
- IqQuery.add_namespaceclass(IqQueryBytestreams::NS_BYTESTREAMS, IqQueryBytestreams)
91
81
 
92
82
  ##
93
83
  # <streamhost/> element, normally appear
94
84
  # as children of IqQueryBytestreams
95
- class StreamHost < REXML::Element
85
+ class StreamHost < XMPPElement
86
+ name_xmlns 'streamhost', NS_BYTESTREAMS
87
+
96
88
  ##
97
89
  # Initialize a <streamhost/> element
98
90
  # jid:: [JID]
99
91
  # host:: [String] Hostname or IP address
100
92
  # port:: [Fixnum] Port number
101
93
  def initialize(jid=nil, host=nil, port=nil)
102
- super('streamhost')
94
+ super()
103
95
  self.jid = jid
104
96
  self.host = host
105
97
  self.port = port
@@ -158,9 +150,11 @@ module Jabber
158
150
  ##
159
151
  # <streamhost-used/> element, normally appears
160
152
  # as child of IqQueryBytestreams
161
- class StreamHostUsed < REXML::Element
153
+ class StreamHostUsed < XMPPElement
154
+ name_xmlns 'streamhost-used', NS_BYTESTREAMS
155
+
162
156
  def initialize(jid=nil)
163
- super('streamhost-used')
157
+ super()
164
158
  self.jid = jid
165
159
  end
166
160
 
@@ -8,34 +8,22 @@ require 'xmpp4r/feature_negotiation/iq/feature'
8
8
 
9
9
  module Jabber
10
10
  module Bytestreams
11
+ PROFILE_FILETRANSFER = 'http://jabber.org/protocol/si/profile/file-transfer'
12
+
11
13
  ##
12
14
  # Iq child 'si' for Stream-Initiation
13
- class IqSi < REXML::Element
14
- PROFILE_FILETRANSFER = 'http://jabber.org/protocol/si/profile/file-transfer'
15
+ class IqSi < XMPPElement
16
+ name_xmlns 'si', 'http://jabber.org/protocol/si'
17
+ force_xmlns true
15
18
 
16
19
  def initialize(id=nil, profile=nil, mime_type=nil)
17
- super('si')
20
+ super()
18
21
 
19
- add_namespace 'http://jabber.org/protocol/si'
20
22
  self.id = id
21
23
  self.profile = profile
22
24
  self.mime_type = mime_type
23
25
  end
24
26
 
25
- def IqSi.import(element)
26
- IqSi::new.import(element)
27
- end
28
-
29
- def typed_add(element)
30
- if element.kind_of?(REXML::Element) and element.name == 'file'
31
- super IqSiFile.new.import(element)
32
- elsif element.kind_of?(REXML::Element) and element.name == 'feature'
33
- super FeatureNegotiation::IqFeature.new.import(element)
34
- else
35
- super element
36
- end
37
- end
38
-
39
27
  ##
40
28
  # Session ID of this stream
41
29
  def id
@@ -87,27 +75,19 @@ module Jabber
87
75
  end
88
76
  end
89
77
 
90
- Iq.add_elementclass('si', IqSi)
91
78
 
92
79
  ##
93
80
  # File-transfer meta-information,
94
81
  # may appear as <file/> in IqSi
95
- class IqSiFile < REXML::Element
82
+ class IqSiFile < XMPPElement
83
+ name_xmlns 'file', PROFILE_FILETRANSFER
84
+
96
85
  def initialize(fname=nil, size=nil)
97
- super 'file'
98
- add_namespace IqSi::PROFILE_FILETRANSFER
86
+ super()
99
87
  self.fname = fname
100
88
  self.size = size
101
89
  end
102
90
 
103
- def typed_add(element)
104
- if element.kind_of?(REXML::Element) and element.name == 'range'
105
- super IqSiFileRange.new.import(element)
106
- else
107
- super element
108
- end
109
- end
110
-
111
91
  ##
112
92
  # Get filename (attribute 'name')
113
93
  def fname
@@ -189,9 +169,10 @@ module Jabber
189
169
 
190
170
  ##
191
171
  # Information for ranged transfers
192
- class IqSiFileRange < REXML::Element
172
+ class IqSiFileRange < XMPPElement
173
+ name_xmlns 'range', PROFILE_FILETRANSFER
193
174
  def initialize(offset=nil, length=nil)
194
- super('range')
175
+ super()
195
176
 
196
177
  self.offset = offset
197
178
  self.length = length
@@ -0,0 +1,124 @@
1
+ # =XMPP4R - XMPP Library for Ruby
2
+ # License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
3
+ # Website::http://home.gna.org/xmpp4r/
4
+
5
+ module Jabber
6
+ ##
7
+ # This class manages a list of callbacks.
8
+ #
9
+ # ==Callbacks management and priority
10
+ #
11
+ # Callbacks are managed by the class CallbackList. When they are added, a
12
+ # priority (just a number or anything Comparable with other priorities) is
13
+ # specified. The biggest the priority is, the earliest the callback will be
14
+ # considered.
15
+ #
16
+ # Callbacks are processed for a given set of objects as long as they return
17
+ # false. If you want to stop processing, you must return true. Example :
18
+ # cbl = CallbackList::new
19
+ # c1 = false
20
+ # c2 = false
21
+ # c3 = false
22
+ # cbl.add(10) { c1 = true; 1 }
23
+ # cbl.add(5) { c2 = true; true }
24
+ # cbl.add(0) { c3 = true }
25
+ # cbl.process('aa')
26
+ # puts "#{c1} #{c2} #{c3}"
27
+ # This example would display "true true false" as callbacks processing was
28
+ # stopped after the second callback returned true.
29
+ #
30
+ # In XMPP4R, callbacks' priorities are quite normalized since we want to be
31
+ # able to "cascade" callbacks in a clean way. Here are values your code should
32
+ # take into account :
33
+ #
34
+ # >= 200:: logging & debugging callbacks. Those callbacks should not consume
35
+ # elements.
36
+ # 100-199:: Where Helpers register their callbacks. The normal value is 100,
37
+ # and Helpers shouldn't register something else unless there's a
38
+ # very good reason to.
39
+ # < 100:: all those numbers are normally available for your application.
40
+ # That's enough, don't you think ?
41
+ class CallbackList
42
+
43
+ # Create a new list of callbacks
44
+ def initialize
45
+ @list = []
46
+ end
47
+
48
+ ##
49
+ # Add a callback to the list
50
+ #
51
+ # List will be sorted afterwards
52
+ #
53
+ # prio:: [Integer] the callback's priority, the higher, the sooner.
54
+ # ref:: [String] the callback's reference
55
+ # block:: [Block] a block to execute
56
+ # return:: [Jabber::CallbackList] The list, for chaining
57
+ def add(prio = 0, ref = nil, proc = nil, &block)
58
+ block = proc if proc
59
+ @list.push(Callback::new(prio, ref, block))
60
+ @list.sort! { |a, b| b.priority <=> a.priority }
61
+ self
62
+ end
63
+
64
+ ##
65
+ # Delete a callback by reference
66
+ # ref:: [String] the reference of the callback to delete
67
+ # return:: [CallBackList] The list, for chaining
68
+ def delete(ref)
69
+ @list.delete_if { |item| item.ref == ref }
70
+ self
71
+ end
72
+
73
+ ##
74
+ # Number of elements in the list
75
+ # return:: [Integer] The number of elements
76
+ def length
77
+ @list.length
78
+ end
79
+
80
+ ##
81
+ # Process an element through all my callbacks. returns e.consumed?
82
+ # e:: [Object] The elements to pass to the callback. You can pass
83
+ # several, but of course, you block must know how to handle them.
84
+ # return:: [Boolean] true if the element has been consumed
85
+ def process(*e)
86
+ # If somebody adds a new callback the list will get modified
87
+ # and sorted(!) while still iterating through it. So we use a
88
+ # local copy of @list. Any freshly added callback will receive
89
+ # the next stanzas, not the current.
90
+ list = @list.dup
91
+
92
+ # process through callbacks
93
+ list.each do |item|
94
+ return true if item.block.call(*e) == true
95
+ end
96
+ false
97
+ end
98
+ end
99
+
100
+ # This class is used to store callbacks inside CallbackList. See the
101
+ # CallbackList class for more detailed explanations.
102
+ class Callback
103
+
104
+ # The Callback's priority
105
+ attr_reader :priority
106
+
107
+ # The Callback's reference, using for deleting purposes
108
+ attr_reader :ref
109
+
110
+ # The Callback's block to execute
111
+ attr_reader :block
112
+
113
+ ##
114
+ # Create a new callback
115
+ # priority:: [Integer] the callback's priority. The higher, the sooner it
116
+ # will be executed
117
+ # ref:: [String] The callback's reference
118
+ def initialize(priority = 0, ref = nil, block = Proc::new {})
119
+ @priority = priority
120
+ @ref = ref
121
+ @block = block
122
+ end
123
+ end
124
+ end
@@ -23,9 +23,7 @@ module Jabber
23
23
  attr_reader :jid
24
24
 
25
25
  ##
26
- # Create a new Client. If threaded mode is activated, callbacks are called
27
- # as soon as messages are received; If it isn't, you have to call
28
- # Stream#process from time to time.
26
+ # Create a new Client.
29
27
  #
30
28
  # Remember to *always* put a resource in your JID unless the server can do SASL.
31
29
  def initialize(jid, threaded = true)
@@ -137,8 +135,7 @@ module Jabber
137
135
  stop
138
136
  start
139
137
  # And wait for features - again
140
- @features_lock.lock
141
- @features_lock.unlock
138
+ @features_sem.wait
142
139
 
143
140
  # Resource binding (RFC3920 - 7)
144
141
  if @stream_features.has_key? 'bind'
@@ -0,0 +1,53 @@
1
+ module Jabber
2
+
3
+ module Command
4
+
5
+ ##
6
+ # The Responder Helper handles the low-level stuff of the
7
+ # Ad-hoc commands (JEP 0050).
8
+ class Responder
9
+
10
+ ##
11
+ # Initialize a Responder
12
+ def initialize(stream)
13
+ @stream = stream
14
+ @commandsdiscocbs = CallbackList.new
15
+ @commandexeccbs = CallbackList.new
16
+
17
+ stream.add_iq_callback(180, self) { |iq|
18
+ iq_callback(iq)
19
+ }
20
+ end
21
+
22
+ ##
23
+ # Add a callback for <query> stanzas asking for the list
24
+ # of ad-hoc commands
25
+ def add_commands_disco_callback(priority = 0, ref = nil, &block)
26
+ @commandsdiscocbs.add(priority, ref, block)
27
+ end
28
+
29
+ ##
30
+ # Add a callback for <command> stanzas asking for the execution
31
+ # of an ad-hoc command
32
+ def add_commands_exec_callback(priority = 0, ref = nil, &block)
33
+ @commandexeccbs.add(priority, ref, block)
34
+ end
35
+
36
+ ##
37
+ # Handles <iq> stanzas and execute callbacks
38
+ def iq_callback(iq)
39
+ if iq.type == :get
40
+ if iq.query.kind_of?(Jabber::Discovery::IqQueryDiscoItems) &&
41
+ iq.query.node == "http://jabber.org/protocol/commands"
42
+ @commandsdiscocbs.process(iq)
43
+ end
44
+ elsif iq.type == :set && iq.command
45
+ @commandexeccbs.process(iq)
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,154 @@
1
+ require 'xmpp4r/iq'
2
+
3
+ module Jabber
4
+
5
+ module Command
6
+
7
+ ##
8
+ # Class for handling ad-hoc commands
9
+ # (JEP 0050)
10
+ #
11
+ # A command is uniquely identified by its node attribute.
12
+ class IqCommand < Iq
13
+ name_xmlns 'command', 'http://jabber.org/protocol/commands'
14
+
15
+ def initialize(node=nil, action=nil)
16
+ super()
17
+ set_node(node)
18
+ set_action(action)
19
+ end
20
+
21
+ ##
22
+ # Get the node of the Command stanza
23
+ # result:: [String] or nil
24
+ def node
25
+ attributes['node']
26
+ end
27
+
28
+ ##
29
+ # Set the node of the Command stanza
30
+ # v:: [String] or nil
31
+ def node=(v)
32
+ attributes['node'] = v
33
+ end
34
+
35
+ ##
36
+ # Set the node of the Command stanza (chaining-friendly)
37
+ # v:: [String] or nil
38
+ def set_node(v)
39
+ self.node = v
40
+ self
41
+ end
42
+
43
+ ##
44
+ # Get the sessionid of the Command stanza
45
+ # result:: [String] or nil
46
+ def sessionid
47
+ attributes['sessionid']
48
+ end
49
+
50
+ ##
51
+ # Set the sessionid of the Command stanza
52
+ # v:: [String] or nil
53
+ def sessionid=(v)
54
+ attributes['sessionid'] = v
55
+ end
56
+
57
+ ##
58
+ # Set the sessionid of the Command stanza (chaining-friendly)
59
+ # v:: [String] or nil
60
+ def set_sessionid(v)
61
+ self.sessionid = v
62
+ self
63
+ end
64
+
65
+ ##
66
+ # Get the action of the Command stanza
67
+ #
68
+ # The following Symbols are allowed:
69
+ # * :execute
70
+ # * :cancel
71
+ # * :prev
72
+ # * :next
73
+ # * :complete
74
+ # return:: [Symbol] or nil
75
+ def action
76
+ case attributes['action']
77
+ when 'execute' then :execute
78
+ when 'cancel' then :cancel
79
+ when 'prev' then :prev
80
+ when 'next' then :next
81
+ when 'complete' then :complete
82
+ else nil
83
+ end
84
+ end
85
+
86
+ ##
87
+ # Set the action of the Command stanza (see IqCommand#action for details)
88
+ # v:: [Symbol] or nil
89
+ def action=(v)
90
+ attributes['action'] = case v
91
+ when :execute then 'execute'
92
+ when :cancel then 'cancel'
93
+ when :prev then 'prev'
94
+ when :next then 'next'
95
+ when :complete then 'complete'
96
+ else nil
97
+ end
98
+ end
99
+
100
+ ##
101
+ # Set the action of the Command stanza (chaining-friendly)
102
+ # v:: [Symbol] or nil
103
+ def set_action(v)
104
+ self.action = v
105
+ self
106
+ end
107
+
108
+ ##
109
+ # Get the status of the Command stanza
110
+ #
111
+ # The following Symbols are allowed:
112
+ # * :executing
113
+ # * :completed
114
+ # * :canceled
115
+ # return:: [Symbol] or nil
116
+ def status
117
+ case attributes['status']
118
+ when 'executing' then :executing
119
+ when 'completed' then :completed
120
+ when 'canceled' then :canceled
121
+ else nil
122
+ end
123
+ end
124
+
125
+ ##
126
+ # Set the status of the Command stanza (see IqCommand#status for details)
127
+ # v:: [Symbol] or nil
128
+ def status=(v)
129
+ attributes['status'] = case v
130
+ when :executing then 'executing'
131
+ when :completed then 'completed'
132
+ when :canceled then 'canceled'
133
+ else nil
134
+ end
135
+ end
136
+
137
+ ##
138
+ # Set the status of the Command stanza (chaining-friendly)
139
+ # v:: [Symbol] or nil
140
+ def set_status(v)
141
+ self.status = v
142
+ self
143
+ end
144
+
145
+ ##
146
+ # Get the actions allowed
147
+ # return:: [REXML::Element] or nil
148
+ def actions
149
+ first_element('actions')
150
+ end
151
+
152
+ end
153
+ end
154
+ end