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
@@ -2,7 +2,7 @@
2
2
  # License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
3
3
  # Website::http://home.gna.org/xmpp4r/
4
4
 
5
- require 'callbacks'
5
+ require 'xmpp4r/callbacks'
6
6
  require 'thread'
7
7
  require 'xmpp4r/roster/iq/roster'
8
8
 
@@ -45,12 +45,20 @@ module Jabber
45
45
 
46
46
  # Register cbs
47
47
  stream.add_iq_callback(120, self) { |iq|
48
- Thread.new do
49
- handle_iq(iq)
48
+ if iq.query.kind_of?(IqQueryRoster)
49
+ Thread.new do
50
+ Thread.current.abort_on_exception = true
51
+ handle_iq_query_roster(iq)
52
+ end
53
+
54
+ true
55
+ else
56
+ false
50
57
  end
51
58
  }
52
59
  stream.add_presence_callback(120, self) { |pres|
53
60
  Thread.new do
61
+ Thread.current.abort_on_exception = true
54
62
  handle_presence(pres)
55
63
  end
56
64
  }
@@ -141,43 +149,28 @@ module Jabber
141
149
  ##
142
150
  # Handle received <tt><iq/></tt> stanzas,
143
151
  # used internally
144
- def handle_iq(iq)
145
- if iq.query.kind_of?(IqQueryRoster)
146
- # If the <iq/> contains <error/> we just ignore that
147
- # and assume an empty roster
148
- iq.query.each_element('item') do |item|
152
+ def handle_iq_query_roster(iq)
153
+ # If the <iq/> contains <error/> we just ignore that
154
+ # and assume an empty roster
155
+ iq.query.each_element('item') do |item|
156
+ olditem, newitem = nil, nil
157
+
158
+ @items_lock.synchronize {
159
+ olditem = @items[item.jid]
160
+
149
161
  # Handle deletion of item
150
162
  if item.subscription == :remove
151
- @items_lock.synchronize {
152
- @items.delete(item.jid)
153
- }
154
-
163
+ @items.delete(item.jid)
155
164
  else
156
- olditem = nil
157
- @items_lock.synchronize {
158
- if @items.has_key?(item.jid)
159
- olditem = RosterItem.new(@stream).import(@items[item.jid])
160
-
161
- # Clear first, because import doesn't
162
- @items[item.jid].iname = nil
163
- @items[item.jid].subscription = nil
164
- @items[item.jid].ask = nil
165
-
166
- @items[item.jid].import(item)
167
- else
168
- @items[item.jid] = RosterItem.new(@stream).import(item)
169
- end
170
- }
171
- @update_cbs.process(olditem, @items[item.jid])
165
+ newitem = @items[item.jid] = RosterItem.new(@stream).import(item)
172
166
  end
173
- end
174
-
175
- @query_cbs.process(iq)
176
- else
177
- false
167
+ }
168
+ @update_cbs.process(olditem, newitem)
178
169
  end
170
+
171
+ @query_cbs.process(iq)
179
172
  end
180
-
173
+
181
174
  ##
182
175
  # Handle received <tt><presence/></tt> stanzas,
183
176
  # used internally
@@ -322,7 +315,7 @@ module Jabber
322
315
  request = Iq.new_rosterset
323
316
  request.query.add(Jabber::Roster::RosterItem.new(jid, iname))
324
317
  @stream.send_with_id(request) { true }
325
- # Adding to list is handled by handle_iq
318
+ # Adding to list is handled by handle_iq_query_roster
326
319
  end
327
320
 
328
321
  if subscribe
@@ -375,20 +368,6 @@ module Jabber
375
368
  @presences_lock = Mutex.new
376
369
  end
377
370
 
378
- ##
379
- # Import another element,
380
- # also import presences if xe is a RosterItem
381
- # return:: [RosterItem] self
382
- def import(xe)
383
- super
384
- if xe.kind_of?(RosterItem)
385
- xe.each_presence { |pres|
386
- add_presence(Presence.new.import(pres))
387
- }
388
- end
389
- self
390
- end
391
-
392
371
  ##
393
372
  # Send the updated RosterItem to the server,
394
373
  # i.e. if you modified iname, groups, ...
@@ -410,7 +389,7 @@ module Jabber
410
389
  request = Iq.new_rosterset
411
390
  request.query.add(Jabber::Roster::RosterItem.new(jid, nil, :remove))
412
391
  @stream.send_with_id(request) { true }
413
- # Removing from list is handled by Roster#handle_iq
392
+ # Removing from list is handled by Roster#handle_iq_query_roster
414
393
  end
415
394
 
416
395
  ##
@@ -19,29 +19,7 @@ module Jabber
19
19
  #
20
20
  # This <query/> contains multiple <item/> children. See RosterItem.
21
21
  class IqQueryRoster < IqQuery
22
- ##
23
- # Create a new <query xmlns='jabber:iq:roster'/>
24
- # stream:: [Stream] Stream to handle
25
- def initialize
26
- super
27
- add_namespace('jabber:iq:roster')
28
- end
29
-
30
- ##
31
- # Add an element to the roster
32
- #
33
- # Converts <item/> elements to RosterItem
34
- #
35
- # Previous RosterItems with the same JID will
36
- # *not* be deleted!
37
- def typed_add(element)
38
- if element.kind_of?(REXML::Element) && (element.name == 'item')
39
- item = RosterItem::new.import(element)
40
- super(item)
41
- else
42
- super(element)
43
- end
44
- end
22
+ name_xmlns 'query', 'jabber:iq:roster'
45
23
 
46
24
  ##
47
25
  # Iterate through all items
@@ -105,7 +83,9 @@ module Jabber
105
83
  # The 'name' attribute has been renamed to 'iname' here
106
84
  # as 'name' is already used by REXML::Element for the
107
85
  # element's name. It's still name='...' in XML.
108
- class RosterItem < REXML::Element
86
+ class RosterItem < XMPPElement
87
+ name_xmlns 'item', 'jabber:iq:roster'
88
+
109
89
  ##
110
90
  # Construct a new roster item
111
91
  # jid:: [JID] Jabber ID
@@ -113,19 +93,12 @@ module Jabber
113
93
  # subscription:: [Symbol] Type of subscription (see RosterItem#subscription=)
114
94
  # ask:: [Symbol] or [Nil] Can be :subscribe
115
95
  def initialize(jid=nil, iname=nil, subscription=nil, ask=nil)
116
- super('item')
96
+ super()
117
97
  self.jid = jid
118
98
  self.iname = iname
119
99
  self.subscription = subscription
120
100
  self.ask = ask
121
101
  end
122
-
123
- ##
124
- # Create new RosterItem from REXML::Element
125
- # item:: [REXML::Element] source element to copy attributes and children from
126
- def RosterItem.import(item)
127
- RosterItem::new.import(item)
128
- end
129
102
 
130
103
  ##
131
104
  # Get name of roster item
@@ -219,7 +192,7 @@ module Jabber
219
192
  each_element('group') { |group|
220
193
  result.push(group.text)
221
194
  }
222
- result
195
+ result.uniq
223
196
  end
224
197
 
225
198
  ##
@@ -238,7 +211,5 @@ module Jabber
238
211
  }
239
212
  end
240
213
  end
241
-
242
- IqQuery.add_namespaceclass('jabber:iq:roster', IqQueryRoster)
243
214
  end #Module Roster
244
215
  end #Module Jabber
@@ -17,28 +17,12 @@ module Jabber
17
17
  # Pay attention to the namespace which is <tt>jabber:x:roster</tt>
18
18
  # for JEP-0093!
19
19
  class XRoster < X
20
- ##
21
- # Initialize a new XRoster element
22
- def initialize
23
- super()
24
- add_namespace('http://jabber.org/protocol/rosterx')
25
- end
26
-
27
- ##
28
- # Add an element to the roster attachment
29
- #
30
- # Converts <item/> elements to XRosterItem
31
- def typed_add(element)
32
- if element.kind_of?(REXML::Element) && (element.name == 'item')
33
- super(XRosterItem::new.import(element))
34
- else
35
- super(element)
36
- end
37
- end
20
+ name_xmlns 'x', 'jabber:x:roster'
38
21
  end #Class XRoster
39
-
40
- X.add_namespaceclass('jabber:x:roster', XRoster)
41
- X.add_namespaceclass('http://jabber.org/protocol/rosterx', XRoster)
22
+
23
+ class RosterX < XRoster
24
+ name_xmlns 'x', 'http://jabber.org/protocol/rosterx'
25
+ end
42
26
 
43
27
  ##
44
28
  # Class containing an <item/> element
@@ -50,24 +34,19 @@ module Jabber
50
34
  # This is all a bit analoguous to Jabber::RosterItem, used by
51
35
  # Jabber::IqQueryRoster. But this class lacks the subscription and
52
36
  # ask attributes.
53
- class XRosterItem < REXML::Element
37
+ class XRosterItem < XMPPElement
38
+ name_xmlns 'item', 'jabber:x:roster'
39
+
54
40
  ##
55
41
  # Construct a new roster item
56
42
  # jid:: [JID] Jabber ID
57
43
  # iname:: [String] Name in the roster
58
44
  def initialize(jid=nil, iname=nil)
59
- super('item')
45
+ super()
60
46
  self.jid = jid
61
47
  self.iname = iname
62
48
  end
63
49
 
64
- ##
65
- # Create new XRosterItem from REXML::Element
66
- # item:: [REXML::Element] source element to copy attributes and children from
67
- def XRosterItem.import(item)
68
- XRosterItem::new.import(item)
69
- end
70
-
71
50
  ##
72
51
  # Get name of roster item
73
52
  #
@@ -151,5 +130,9 @@ module Jabber
151
130
  }
152
131
  end
153
132
  end #Class XRosterItem
133
+
134
+ class RosterXItem < XRosterItem
135
+ name_xmlns 'item', 'http://jabber.org/protocol/rosterx'
136
+ end
154
137
  end #Module Roster
155
138
  end #Module Jabber
@@ -0,0 +1,2 @@
1
+ require 'xmpp4r/rpc/helper/client'
2
+ require 'xmpp4r/rpc/helper/server'
@@ -0,0 +1,114 @@
1
+ require 'xmlrpc/server'
2
+ require 'xmlrpc/parser'
3
+ require 'xmlrpc/create'
4
+ require 'xmlrpc/config'
5
+ require 'xmlrpc/utils' # ParserWriterChooseMixin
6
+
7
+ require 'xmpp4r/dataforms/x/data'
8
+ require 'xmpp4r/rpc/iq/rpc'
9
+ require 'xmpp4r/rpc/helper/xmlrpcaddons'
10
+
11
+ module Jabber
12
+ module RPC
13
+
14
+ ##
15
+ # XMLRPC Client
16
+ class Client
17
+
18
+ include XMLRPC::ParserWriterChooseMixin
19
+ include XMLRPC::ParseContentType
20
+
21
+ attr_accessor :my_jid
22
+
23
+ ##
24
+ # xmppstream
25
+ # stream:: [Stream]
26
+ # jid where you want to send the rpc requests to
27
+ # jid:: [JID] rpcserver@jabberserver/ressource
28
+ def initialize(stream,jid)
29
+ @jid = JID.new(jid)
30
+ @my_jid = stream.jid
31
+ @stream = stream
32
+ @parser = nil
33
+ @create = XMLRPC::Create.new
34
+ end
35
+
36
+ def call(method, *args)
37
+ ok, param = call2(method, *args)
38
+ if ok
39
+ param
40
+ else
41
+ raise param
42
+ end
43
+ end
44
+
45
+ def call2(method, *args)
46
+ request = @create.methodCall(method, *args)
47
+ data = do_rpc(request)
48
+ parser().parseMethodResponse(data)
49
+ end
50
+
51
+ ##
52
+ # adds multi rpcalls to the query
53
+ # methods:: [Array]
54
+ def multicall(*methods)
55
+ ok, params = multicall2(*methods)
56
+ if ok
57
+ params
58
+ else
59
+ raise params
60
+ end
61
+ end
62
+
63
+ ##
64
+ # generate a multicall
65
+ # methods:: [Array]
66
+ def multicall2(*methods)
67
+ gen_multicall(methods)
68
+ end
69
+
70
+ def do_rpc(xmlrpc)
71
+ iq = Iq.new(:set, @jid)
72
+ iq.from = @my_jid
73
+ iq.id = IdGenerator::generate_id
74
+ rpcquery = iq.add(IqQueryRPC.new)
75
+ rpcquery.typed_add(xmlrpc)
76
+
77
+ result = nil
78
+ @stream.send_with_id(iq) { |iqreply|
79
+ if iqreply.type == :result and iqreply.query.kind_of?(IqQueryRPC)
80
+ result = iqreply.query.to_s
81
+ true
82
+ else
83
+ false
84
+ end
85
+ }
86
+
87
+ result
88
+ end
89
+
90
+ private
91
+
92
+ def gen_multicall(methods=[])
93
+ ok, params = call2("system.multicall",
94
+ methods.collect { |m| {'methodName' => m[0], 'params' => m[1..-1]} }
95
+ )
96
+
97
+ if ok
98
+ params = params.collect{ |param|
99
+ if param.is_a? Array
100
+ param[0]
101
+ elsif param.is_a? Hash
102
+ XMLRPC::FaultException.new(param["faultCode"], param["faultString"])
103
+ else
104
+ raise "Wrong multicall return value"
105
+ end
106
+ }
107
+ end
108
+
109
+ return ok, params
110
+ end
111
+ end
112
+ end # Helpers
113
+ end # Jabber
114
+
@@ -0,0 +1,75 @@
1
+ require 'xmlrpc/server'
2
+ require 'xmlrpc/parser'
3
+ require 'xmlrpc/create'
4
+ require 'xmlrpc/config'
5
+ require 'xmlrpc/utils' # ParserWriterChooseMixin
6
+
7
+ require 'xmpp4r/dataforms/x/data'
8
+ require 'xmpp4r/rpc/iq/rpc'
9
+ require 'xmpp4r/rpc/helper/xmlrpcaddons'
10
+
11
+ module Jabber
12
+ module RPC
13
+
14
+ ##
15
+ # XMLRPC Server
16
+ class Server < XMLRPC::BasicServer
17
+
18
+ include XMLRPC::ParserWriterChooseMixin
19
+ include XMLRPC::ParseContentType
20
+
21
+ ##
22
+ # new - creates a new server
23
+ #
24
+ def initialize(stream,class_delim=".")
25
+ super(class_delim)
26
+ @stream = stream
27
+ @stream.add_iq_callback(120,"Helpers::RPCServer") { |iq|
28
+ if iq.type == :set and iq.type != :result
29
+ handle_iq(iq)
30
+ true
31
+ else
32
+ false
33
+ end
34
+ }
35
+ end
36
+
37
+ ##
38
+ # handles incoming iqs
39
+ # iq:: [Jabber::IQ] - the jabber iq
40
+ def handle_iq(iq)
41
+ if iq.type == :set
42
+ if iq.query.kind_of?(IqQueryRPC)
43
+ data = iq.query
44
+ response = IqQueryRPC.new
45
+ data.elements.each { |rpc|
46
+ if rpc
47
+ response.typed_add(handle_rpc_requests(rpc))
48
+ end
49
+ }
50
+
51
+ respiq = iq.answer(false)
52
+ respiq.type = :result
53
+ respiq.add(response)
54
+ @stream.send(respiq)
55
+ end
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ ##
62
+ # handles the rpc requests
63
+ # takes rpcdata:: [String]
64
+ def handle_rpc_requests(rpcdata)
65
+ resp = process(rpcdata.to_s)
66
+ if resp == nil or resp.size <= 0
67
+ raise Jabber::Error.new(:forbidden)
68
+ else
69
+ return resp
70
+ end
71
+ end
72
+ end # RPCServer
73
+ end # Helpers
74
+ end # Jabber
75
+