xmpp4r 0.3.2 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. data/{ChangeLog → CHANGELOG} +33 -0
  2. data/LICENSE +9 -9
  3. data/README.rdoc +110 -0
  4. data/README_ruby19.txt +43 -0
  5. data/Rakefile +235 -74
  6. data/data/doc/xmpp4r/examples/advanced/adventure/README +0 -1
  7. data/data/doc/xmpp4r/examples/advanced/adventure/adventure.rb +1 -1
  8. data/data/doc/xmpp4r/examples/advanced/adventure/adventuremuc.rb +12 -12
  9. data/data/doc/xmpp4r/examples/advanced/adventure/world.rb +10 -11
  10. data/data/doc/xmpp4r/examples/advanced/fileserve.rb +11 -11
  11. data/data/doc/xmpp4r/examples/advanced/getonline.rb +7 -7
  12. data/data/doc/xmpp4r/examples/advanced/gtkmucclient.rb +3 -3
  13. data/data/doc/xmpp4r/examples/advanced/migrate.rb +21 -22
  14. data/data/doc/xmpp4r/examples/advanced/minimuc.rb +22 -22
  15. data/data/doc/xmpp4r/examples/advanced/pep-aggregator/index.xsl +235 -0
  16. data/data/doc/xmpp4r/examples/advanced/pep-aggregator/pep-aggregator.rb +147 -0
  17. data/data/doc/xmpp4r/examples/advanced/recvfile.rb +0 -1
  18. data/data/doc/xmpp4r/examples/advanced/rosterdiscovery.rb +2 -3
  19. data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr.rb +3 -3
  20. data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_jabber.rb +10 -10
  21. data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_test.rb +2 -2
  22. data/data/doc/xmpp4r/examples/advanced/versionpoll.rb +12 -12
  23. data/data/doc/xmpp4r/examples/advanced/xmpping.rb +2 -3
  24. data/data/doc/xmpp4r/examples/basic/change_password.rb +3 -3
  25. data/data/doc/xmpp4r/examples/basic/client.rb +5 -3
  26. data/data/doc/xmpp4r/examples/basic/component.rb +1 -1
  27. data/data/doc/xmpp4r/examples/basic/{echo_threaded.rb → echo.rb} +8 -7
  28. data/data/doc/xmpp4r/examples/basic/jabbersend.rb +5 -5
  29. data/data/doc/xmpp4r/examples/basic/mass_sender.rb +11 -11
  30. data/data/doc/xmpp4r/examples/basic/muc_owner_config.rb +0 -1
  31. data/data/doc/xmpp4r/examples/basic/mucinfo.rb +3 -1
  32. data/data/doc/xmpp4r/examples/basic/mucsimplebot.rb +0 -1
  33. data/data/doc/xmpp4r/examples/basic/register.rb +21 -4
  34. data/data/doc/xmpp4r/examples/basic/roster.rb +7 -5
  35. data/data/doc/xmpp4r/examples/basic/rosterprint.rb +0 -0
  36. data/data/doc/xmpp4r/examples/basic/rosterrename.rb +2 -2
  37. data/data/doc/xmpp4r/examples/basic/rosterwatch.rb +6 -7
  38. data/data/doc/xmpp4r/examples/basic/send_vcard.rb +3 -4
  39. data/data/doc/xmpp4r/examples/basic/tune_client.rb +56 -0
  40. data/data/doc/xmpp4r/examples/basic/tune_server.rb +58 -0
  41. data/data/doc/xmpp4r/examples/basic/versionbot.rb +1 -1
  42. data/lib/xmpp4r.rb +4 -4
  43. data/lib/xmpp4r/base64.rb +32 -0
  44. data/lib/xmpp4r/bytestreams/helper/filetransfer.rb +10 -11
  45. data/lib/xmpp4r/bytestreams/helper/ibb/base.rb +6 -8
  46. data/lib/xmpp4r/bytestreams/helper/ibb/initiator.rb +3 -6
  47. data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +0 -1
  48. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb +8 -11
  49. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb +4 -7
  50. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb +7 -3
  51. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb +10 -5
  52. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +14 -4
  53. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb.orig +62 -0
  54. data/lib/xmpp4r/bytestreams/iq/bytestreams.rb +0 -1
  55. data/lib/xmpp4r/callbacks.rb +5 -5
  56. data/lib/xmpp4r/caps.rb +1 -0
  57. data/lib/xmpp4r/caps/c.rb +53 -0
  58. data/lib/xmpp4r/caps/helper/generator.rb +160 -0
  59. data/lib/xmpp4r/caps/helper/helper.rb +87 -0
  60. data/lib/xmpp4r/client.rb +111 -40
  61. data/lib/xmpp4r/command/iq/command.rb +1 -1
  62. data/lib/xmpp4r/component.rb +8 -8
  63. data/lib/xmpp4r/connection.rb +25 -9
  64. data/lib/xmpp4r/dataforms/x/data.rb +17 -5
  65. data/lib/xmpp4r/debuglog.rb +13 -5
  66. data/lib/xmpp4r/delay/x/delay.rb +1 -1
  67. data/lib/xmpp4r/discovery.rb +3 -2
  68. data/lib/xmpp4r/discovery/helper/responder.rb +165 -0
  69. data/lib/xmpp4r/discovery/iq/discoinfo.rb +11 -12
  70. data/lib/xmpp4r/discovery/iq/discoitems.rb +12 -4
  71. data/lib/xmpp4r/{error.rb → errors.rb} +66 -10
  72. data/lib/xmpp4r/framework/base.rb +55 -0
  73. data/lib/xmpp4r/framework/bot.rb +148 -0
  74. data/lib/xmpp4r/httpbinding/client.rb +1 -1
  75. data/lib/xmpp4r/idgenerator.rb +1 -1
  76. data/lib/xmpp4r/iq.rb +34 -23
  77. data/lib/xmpp4r/jid.rb +2 -2
  78. data/lib/xmpp4r/message.rb +1 -1
  79. data/lib/xmpp4r/muc.rb +2 -0
  80. data/lib/xmpp4r/muc/helper/mucbrowser.rb +4 -19
  81. data/lib/xmpp4r/muc/helper/mucclient.rb +54 -23
  82. data/lib/xmpp4r/muc/helper/simplemucclient.rb +107 -1
  83. data/lib/xmpp4r/muc/iq/mucadmin.rb +23 -0
  84. data/lib/xmpp4r/muc/iq/mucadminitem.rb +20 -0
  85. data/lib/xmpp4r/muc/iq/mucowner.rb +5 -1
  86. data/lib/xmpp4r/muc/item.rb +143 -0
  87. data/lib/xmpp4r/muc/x/mucuserinvite.rb +2 -2
  88. data/lib/xmpp4r/muc/x/mucuseritem.rb +3 -117
  89. data/lib/xmpp4r/presence.rb +2 -1
  90. data/lib/xmpp4r/pubsub.rb +7 -0
  91. data/lib/xmpp4r/pubsub/children/configuration.rb +86 -0
  92. data/lib/xmpp4r/pubsub/{stanzas → children}/event.rb +13 -13
  93. data/lib/xmpp4r/pubsub/{stanzas → children}/item.rb +9 -1
  94. data/lib/xmpp4r/pubsub/{stanzas → children}/items.rb +10 -1
  95. data/lib/xmpp4r/pubsub/children/node_config.rb +48 -0
  96. data/lib/xmpp4r/pubsub/children/publish.rb +24 -0
  97. data/lib/xmpp4r/pubsub/{stanzas → children}/subscription.rb +16 -12
  98. data/lib/xmpp4r/pubsub/children/subscription_config.rb +67 -0
  99. data/lib/xmpp4r/pubsub/children/unsubscribe.rb +48 -0
  100. data/lib/xmpp4r/pubsub/helper/nodebrowser.rb +49 -93
  101. data/lib/xmpp4r/pubsub/helper/nodehelper.rb +39 -36
  102. data/lib/xmpp4r/pubsub/helper/servicehelper.rb +253 -162
  103. data/lib/xmpp4r/pubsub/iq/pubsub.rb +1 -1
  104. data/lib/xmpp4r/rexmladdons.rb +56 -28
  105. data/lib/xmpp4r/roster.rb +0 -1
  106. data/lib/xmpp4r/roster/helper/roster.rb +26 -15
  107. data/lib/xmpp4r/roster/iq/roster.rb +19 -19
  108. data/lib/xmpp4r/roster/x/roster.rb +10 -10
  109. data/lib/xmpp4r/rpc/helper/client.rb +17 -8
  110. data/lib/xmpp4r/rpc/helper/server.rb +1 -2
  111. data/lib/xmpp4r/rpc/helper/xmlrpcaddons.rb +14 -4
  112. data/lib/xmpp4r/rpc/iq/rpc.rb +0 -1
  113. data/lib/xmpp4r/sasl.rb +27 -6
  114. data/lib/xmpp4r/stream.rb +39 -44
  115. data/lib/xmpp4r/streamparser.rb +4 -4
  116. data/lib/xmpp4r/tune.rb +2 -0
  117. data/lib/xmpp4r/tune/helper/helper.rb +58 -0
  118. data/lib/xmpp4r/tune/tune.rb +113 -0
  119. data/lib/xmpp4r/vcard.rb +0 -1
  120. data/lib/xmpp4r/vcard/helper/vcard.rb +1 -3
  121. data/lib/xmpp4r/vcard/iq/vcard.rb +14 -0
  122. data/lib/xmpp4r/version/iq/version.rb +0 -1
  123. data/lib/xmpp4r/x.rb +1 -1
  124. data/lib/xmpp4r/xhtml.rb +1 -0
  125. data/lib/xmpp4r/xhtml/html.rb +115 -0
  126. data/lib/xmpp4r/xmpp4r.rb +7 -5
  127. data/lib/xmpp4r/xmppelement.rb +21 -5
  128. data/lib/xmpp4r/xmppstanza.rb +6 -6
  129. data/setup.rb +4 -4
  130. data/test/bytestreams/tc_ibb.rb +2 -2
  131. data/test/bytestreams/tc_socks5bytestreams.rb +12 -2
  132. data/test/caps/tc_helper.rb +156 -0
  133. data/test/dataforms/tc_data.rb +0 -0
  134. data/test/delay/tc_xdelay.rb +2 -2
  135. data/test/discovery/tc_responder.rb +91 -0
  136. data/test/lib/assert_equal_xml.rb +14 -0
  137. data/test/lib/clienttester.rb +31 -24
  138. data/test/muc/tc_muc_mucclient.rb +249 -13
  139. data/test/muc/tc_muc_simplemucclient.rb +41 -2
  140. data/test/muc/tc_mucowner.rb +0 -0
  141. data/test/pubsub/tc_helper.rb +486 -51
  142. data/test/pubsub/tc_nodeconfig.rb +54 -0
  143. data/test/pubsub/tc_subscriptionconfig.rb +41 -0
  144. data/test/roster/tc_helper.rb +6 -7
  145. data/test/roster/tc_iqqueryroster.rb +16 -16
  146. data/test/roster/tc_xroster.rb +1 -1
  147. data/test/rpc/tc_helper.rb +15 -3
  148. data/test/tc_callbacks.rb +7 -7
  149. data/test/tc_class_names.rb +15 -6
  150. data/test/tc_client.rb +3 -3
  151. data/test/{tc_error.rb → tc_errors.rb} +54 -12
  152. data/test/tc_idgenerator.rb +0 -0
  153. data/test/tc_iq.rb +32 -29
  154. data/test/tc_iqquery.rb +2 -2
  155. data/test/tc_jid.rb +44 -42
  156. data/test/tc_message.rb +13 -12
  157. data/test/tc_presence.rb +25 -24
  158. data/test/tc_rexml.rb +81 -2
  159. data/test/tc_stream.rb +15 -13
  160. data/test/tc_streamComponent.rb +6 -5
  161. data/test/tc_streamError.rb +21 -15
  162. data/test/tc_streamSend.rb +9 -9
  163. data/test/tc_streamparser.rb +112 -0
  164. data/test/tc_xmppstanza.rb +19 -9
  165. data/test/ts_xmpp4r.rb +10 -1
  166. data/test/tune/tc_helper_recv.rb +84 -0
  167. data/test/tune/tc_helper_send.rb +74 -0
  168. data/test/tune/tc_tune.rb +79 -0
  169. data/test/vcard/tc_helper.rb +2 -2
  170. data/test/vcard/tc_iqvcard.rb +13 -3
  171. data/test/version/tc_helper.rb +2 -2
  172. data/test/version/tc_iqqueryversion.rb +10 -10
  173. data/test/xhtml/tc_html.rb +41 -0
  174. data/tools/gen_requires.bash +29 -8
  175. data/tools/xmpp4r-gemspec-test.rb +11 -0
  176. data/xmpp4r.gemspec +291 -0
  177. metadata +277 -218
  178. data/README +0 -28
  179. data/UPDATING +0 -40
  180. data/data/doc/xmpp4r/examples/buggy/jabber2jabber/jabber2jabber.rb +0 -18
  181. data/data/doc/xmpp4r/examples/buggy/miniedgarr_cgi.rb +0 -192
  182. data/data/doc/xmpp4r/examples/buggy/miniedgarr_watch.rb +0 -82
  183. data/lib/xmpp4r/authenticationfailure.rb +0 -13
  184. data/lib/xmpp4r/errorexception.rb +0 -32
  185. data/tools/doctoweb.bash +0 -30
@@ -69,7 +69,7 @@ class IBBTest < Test::Unit::TestCase
69
69
 
70
70
  assert_equal(buffer, received)
71
71
  end
72
-
72
+
73
73
  def test_ibb_pingpong
74
74
  ignored_stanzas = 0
75
75
  wait = Semaphore.new
@@ -174,7 +174,7 @@ class IBBTest < Test::Unit::TestCase
174
174
  assert_equal(:close, i1.type)
175
175
  assert_nil(i1.seq)
176
176
 
177
- i2 = Bytestreams::IBBQueueItem.new(:data, 1, Base64::encode64('blah'))
177
+ i2 = Bytestreams::IBBQueueItem.new(:data, 1, ['blah'].pack('m'))
178
178
  assert_equal(:data, i2.type)
179
179
  assert_equal(1, i2.seq)
180
180
  assert_equal('blah', i2.data)
@@ -30,7 +30,7 @@ class SOCKS5BytestreamsTest < Test::Unit::TestCase
30
30
  buf1 = create_buffer(8192)
31
31
  buf2 = create_buffer(8192)
32
32
 
33
- Thread.new do
33
+ Thread.new do
34
34
  target1.accept
35
35
  target1.write(buf1)
36
36
  target1.flush
@@ -99,5 +99,15 @@ class SOCKS5BytestreamsTest < Test::Unit::TestCase
99
99
 
100
100
  initiator.close
101
101
  end
102
-
102
+
103
+ def test_timeout
104
+ target = Bytestreams::SOCKS5BytestreamsTarget.new(@server, '1', '1@a.com/1', '1@a.com/2')
105
+
106
+ assert_nothing_raised do
107
+ Timeout::timeout(2) do
108
+ target.connect_timeout = 1
109
+ assert target.accept == false
110
+ end
111
+ end
112
+ end
103
113
  end
@@ -0,0 +1,156 @@
1
+
2
+ $:.unshift File::dirname(__FILE__) + '/../../lib'
3
+
4
+ require 'test/unit'
5
+ require File::dirname(__FILE__) + '/../lib/clienttester'
6
+
7
+ require 'xmpp4r/discovery'
8
+ require 'xmpp4r/caps/helper/helper'
9
+ require 'xmpp4r/dataforms'
10
+ include Jabber
11
+
12
+ class Caps::HelperTest < Test::Unit::TestCase
13
+ include ClientTester
14
+
15
+ ##
16
+ # Walk through the client/ server conversation defined
17
+ # in http://www.xmpp.org/extensions/xep-0115.html#usecases
18
+ # and assert conformance.
19
+ def test_caps_reply
20
+ # This will be invoked by 'wait_state' below...
21
+ state { |presence|
22
+ assert_kind_of(Jabber::Presence, presence)
23
+ c = presence.first_element('c')
24
+ assert_kind_of(Jabber::Caps::C, c)
25
+
26
+ # see http://www.xmpp.org/extensions/xep-0115.html#ver
27
+ assert_equal('SrFo9ar2CCk2EnOH4q4QANeuxLQ=', c.ver)
28
+
29
+ # version 1.5 of xep 0115 indicates that the <c /> stanzq MUST feature a 'hash' attribute
30
+ assert_equal('sha-1', c.hash)
31
+
32
+ assert_equal("http://home.gna.org/xmpp4r/##{Jabber::XMPP4R_VERSION}", c.node)
33
+
34
+ send(iq_discovering_capabilities)
35
+ }
36
+
37
+ # Construct Caps::Helper which will send a <presence>
38
+ # stanza (with embedded <c/> advert) to the 'server'
39
+ h = Caps::Helper.new(@client, identities, features)
40
+
41
+ # The 'server' will receive the <presence> stanza and
42
+ # yield it to the 'state' block above, where an <iq> query
43
+ # will be sent back to the 'client,' to discover its capabilities.
44
+ # Wait here until the block has been executed.
45
+ wait_state
46
+
47
+ # The Caps::Helper will process the <iq> query from the 'server'
48
+ # and reply with an <iq> result providing the details of its
49
+ # identities and features.
50
+
51
+ state { |iq|
52
+ assert_kind_of(Jabber::Iq, iq)
53
+ assert_equal(:result, iq.type)
54
+ assert_equal('1867999907', iq.id)
55
+ assert_equal('new-big-computer.local', iq.to.to_s)
56
+
57
+ assert_kind_of(Jabber::Discovery::IqQueryDiscoInfo, iq.query)
58
+ assert_equal(iq.query.identities.size, identities.size)
59
+ get_category_iname_type = lambda{ |i| [i.category,i.iname,i.type] }
60
+ assert_equal(iq.query.identities.map(&get_category_iname_type).sort!, identities.map(&get_category_iname_type).sort!)
61
+
62
+ assert_equal(3, iq.query.features.size)
63
+ get_var = lambda { |f| f.var }
64
+ assert_equal(iq.query.features.sort, features.map(&get_var).sort)
65
+ }
66
+
67
+ # The 'server' will receive the <iq> result from the
68
+ # 'client' and yield it to the block above. Wait here
69
+ # until that block exits.
70
+ wait_state
71
+ end
72
+
73
+ def test_custom_node
74
+ client_id='http://new-big-computer.local/client#321'
75
+
76
+ state { |presence|
77
+ c = presence.first_element('c')
78
+ assert_kind_of(Jabber::Caps::C, c)
79
+ assert_equal(client_id, c.node)
80
+ assert_equal('SrFo9ar2CCk2EnOH4q4QANeuxLQ=', c.ver)
81
+ }
82
+ h = Caps::Helper.new(@client, identities, features, client_id)
83
+ wait_state
84
+ end
85
+
86
+ def identities
87
+ [Jabber::Discovery::Identity.new('client', 'Exodus 0.9.1', 'pc')]
88
+ end
89
+
90
+ def features
91
+ [Jabber::Discovery::Feature.new("http://jabber.org/protocol/disco#info"),
92
+ Jabber::Discovery::Feature.new("http://jabber.org/protocol/disco#items"),
93
+ Jabber::Discovery::Feature.new("http://jabber.org/protocol/muc")]
94
+ end
95
+
96
+ def iq_discovering_capabilities
97
+ "<iq from='new-big-computer.local' type='get' to='matt@new-big-computer.local/capable_client' id='1867999907' xmlns='jabber:client'><query xmlns='http://jabber.org/protocol/disco#info'/></iq>"
98
+ end
99
+
100
+ ##
101
+ # http://www.xmpp.org/extensions/xep-0115.html#ver-gen-complex
102
+ def test_caps_complex
103
+ form = Dataforms::XData.new(:result)
104
+ form.add(Dataforms::XDataField.new('FORM_TYPE', :hidden)).value = 'urn:xmpp:dataforms:softwareinfo'
105
+ form.add(Dataforms::XDataField.new('ip_version')).values = ['ipv4', 'ipv6']
106
+ form.add(Dataforms::XDataField.new('software')).value = 'Psi' # re-ordered
107
+ form.add(Dataforms::XDataField.new('software_version')).value = '0.11'
108
+ form.add(Dataforms::XDataField.new('os')).value = 'Mac'
109
+ form.add(Dataforms::XDataField.new('os_version')).value = '10.5.1'
110
+ ver = Caps::generate_ver([Discovery::Identity.new('client', 'Psi 0.9.1', 'pc').set_xml_lang('en'),
111
+ Discovery::Identity.new('client', 'Ψ 0.9.1', 'pc').set_xml_lang('el')],
112
+ [Discovery::Feature.new('http://jabber.org/protocol/muc'), # re-ordered
113
+ Discovery::Feature.new('http://jabber.org/protocol/disco#info'),
114
+ Discovery::Feature.new('http://jabber.org/protocol/disco#items')],
115
+ [form])
116
+ assert_equal('8lu+88MRxmKM7yO3MEzY7YmTsWs=', ver)
117
+ end
118
+
119
+ ##
120
+ # http://www.xmpp.org/extensions/xep-0115.html#ver-gen-complex
121
+ def test_caps_complex_imported
122
+ query = IqQuery::import(REXML::Document.new(<<END).root)
123
+ <query xmlns='http://jabber.org/protocol/disco#info'
124
+ node='http://psi-im.org#8lu+88MRxmKM7yO3MEzY7YmTsWs='>
125
+ <identity xml:lang='en' category='client' name='Psi 0.9.1' type='pc'/>
126
+ <identity xml:lang='el' category='client' name='Ψ 0.9.1' type='pc'/>
127
+ <feature var='http://jabber.org/protocol/disco#info'/>
128
+ <feature var='http://jabber.org/protocol/disco#items'/>
129
+ <feature var='http://jabber.org/protocol/muc'/>
130
+ <x xmlns='jabber:x:data' type='result'>
131
+ <field var='FORM_TYPE' type='hidden'>
132
+ <value>urn:xmpp:dataforms:softwareinfo</value>
133
+ </field>
134
+ <field var='ip_version'>
135
+ <value>ipv4</value>
136
+ <value>ipv6</value>
137
+ </field>
138
+ <field var='os'>
139
+ <value>Mac</value>
140
+ </field>
141
+ <field var='os_version'>
142
+ <value>10.5.1</value>
143
+ </field>
144
+ <field var='software'>
145
+ <value>Psi</value>
146
+ </field>
147
+ <field var='software_version'>
148
+ <value>0.11</value>
149
+ </field>
150
+ </x>
151
+ </query>
152
+ END
153
+ assert_equal('8lu+88MRxmKM7yO3MEzY7YmTsWs=',
154
+ Caps::generate_ver_from_discoinfo(query))
155
+ end
156
+ end
File without changes
@@ -26,8 +26,8 @@ class XDelayTest < Test::Unit::TestCase
26
26
  def test_from
27
27
  d = Delay::XDelay.new
28
28
  assert_equal(nil, d.from)
29
- d.from = JID::new('astro@spaceboyz.net')
30
- assert_equal(JID::new('astro@spaceboyz.net'), d.from)
29
+ d.from = JID.new('astro@spaceboyz.net')
30
+ assert_equal(JID.new('astro@spaceboyz.net'), d.from)
31
31
  assert_equal(d, d.set_from(nil))
32
32
  assert_equal(nil, d.from)
33
33
  end
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift File::dirname(__FILE__) + '/../../lib'
4
+
5
+ require 'test/unit'
6
+ require File::dirname(__FILE__) + '/../lib/clienttester'
7
+
8
+ require 'xmpp4r/discovery/helper/responder'
9
+ include Jabber
10
+
11
+ class Discovery::ResponderTest < Test::Unit::TestCase
12
+ include ClientTester
13
+
14
+ def test_new
15
+ r = Discovery::Responder.new(@client)
16
+ assert_nil(r.node)
17
+ assert_equal([], r.identities)
18
+ assert_equal([], r.features)
19
+ assert_equal([], r.forms)
20
+ assert_equal([], r.items)
21
+ end
22
+
23
+ def test_new2
24
+ r = Discovery::Responder.new(@client, 'xmpp4r',
25
+ [Discovery::Identity.new('client', 'XMPP4R', 'bot'),
26
+ Discovery::Identity.new('pubsub', 'Personal events', 'pep')],
27
+ ['ipv6', Discovery::Feature.new('sslc2s')],
28
+ [Discovery::Item.new('foo@bar', 'Foo', nil), Discovery::Item.new('bar@baz', 'Bar', 'barbaz')])
29
+ assert_equal('xmpp4r', r.node)
30
+ assert_equal([Discovery::Identity.new('client', 'XMPP4R', 'bot'),
31
+ Discovery::Identity.new('pubsub', 'Personal events', 'pep')], r.identities)
32
+ assert_equal([Discovery::Feature.new('ipv6'), Discovery::Feature.new('sslc2s')], r.features)
33
+ assert_equal([], r.forms)
34
+ assert_equal([Discovery::Item.new('foo@bar', 'Foo', nil), Discovery::Item.new('bar@baz', 'Bar', 'barbaz')], r.items)
35
+ end
36
+
37
+ def test_generate_item
38
+ r = Discovery::Responder.new(@client, nil, [Discovery::Identity.new('client', 'XMPP4R', 'bot')])
39
+ assert_equal(Discovery::Item.new(@client.jid, 'XMPP4R'), r.generate_item)
40
+ end
41
+
42
+ def test_query
43
+ Discovery::Responder.new(@client, nil,
44
+ [Discovery::Identity.new('client', 'XMPP4R', 'bot')],
45
+ ['ipv6'],
46
+ [Discovery::Item.new('foo@bar', 'Foo', nil)])
47
+
48
+ iq1 = Iq.new(:get)
49
+ iq1.add(Discovery::IqQueryDiscoInfo.new)
50
+ reply1 = @server.send_with_id(iq1)
51
+ assert_equal(:result, reply1.type)
52
+ assert_kind_of(Discovery::IqQueryDiscoInfo, reply1.query)
53
+ assert_nil(reply1.query.node)
54
+ assert_equal(1, reply1.query.identities.size)
55
+ assert_equal('XMPP4R', reply1.query.identities[0].iname)
56
+ assert_equal(['ipv6'], reply1.query.features)
57
+
58
+ iq2 = Iq.new(:get)
59
+ iq2.add(Discovery::IqQueryDiscoItems.new)
60
+ reply2 = @server.send_with_id(iq2)
61
+ assert_equal(:result, reply2.type)
62
+ assert_kind_of(Discovery::IqQueryDiscoItems, reply2.query)
63
+ assert_nil(reply2.query.node)
64
+ assert_equal(1, reply2.query.items.size)
65
+ assert_equal(JID.new('foo@bar'), reply2.query.items[0].jid)
66
+ end
67
+
68
+ def test_linked
69
+ class << @client
70
+ remove_method(:jid) # avoids warning
71
+ def jid
72
+ JID.new('foo@bar/baz')
73
+ end
74
+ end
75
+ r1 = Discovery::Responder.new(@client, 'child',
76
+ [Discovery::Identity.new('client', 'Child', 'bot')])
77
+ r2 = Discovery::Responder.new(@client, nil,
78
+ [], [],
79
+ [r1])
80
+
81
+ iq = Iq.new(:get)
82
+ iq.add(Discovery::IqQueryDiscoItems.new)
83
+ reply = @server.send_with_id(iq)
84
+ assert_kind_of(Discovery::IqQueryDiscoItems, reply.query)
85
+ assert_nil(reply.query.node)
86
+ assert_equal(1, reply.query.items.size)
87
+ assert_equal(JID.new('foo@bar/baz'), reply.query.items[0].jid)
88
+ assert_equal('Child', reply.query.items[0].iname)
89
+ assert_equal('child', reply.query.items[0].node)
90
+ end
91
+ end
@@ -0,0 +1,14 @@
1
+ module Test::Unit::Assertions
2
+ public
3
+ ##
4
+ # Like assert_equal, but actual comparision switches parameters to
5
+ # make use of our attribute order agnostic REXML#==
6
+ def assert_equal_xml(expected, actual, message=nil)
7
+ full_message = build_message(message, <<EOT, expected, actual)
8
+ <?> expected but was
9
+ <?>.
10
+ EOT
11
+ assert_block(full_message) { actual == expected }
12
+ end
13
+ end
14
+
@@ -1,9 +1,16 @@
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
+
1
5
  $:.unshift '../lib'
2
6
  require 'xmpp4r'
3
7
  require 'test/unit'
4
8
  require 'socket'
5
9
  require 'xmpp4r/semaphore'
6
10
 
11
+ # This is sane for tests:
12
+ Thread::abort_on_exception = true
13
+
7
14
  # Turn $VERBOSE off to suppress warnings about redefinition
8
15
  oldverbose = $VERBOSE
9
16
  $VERBOSE = false
@@ -11,10 +18,9 @@ $VERBOSE = false
11
18
  module Jabber
12
19
  ##
13
20
  # The ClientTester is a mix-in which provides a setup and teardown
14
- # method to prepare a Stream object (@client) and two methods
21
+ # method to prepare a Stream object (@client) and the method
15
22
  # interfacing as the "server side":
16
23
  # * send(xml):: Send a stanza to @client
17
- # * receive:: (Wait and) retrieve a stanza sent by the client (in order)
18
24
  #
19
25
  # The server side is a stream, too: add your callbacks to @server
20
26
  #
@@ -25,15 +31,17 @@ module Jabber
25
31
  def setup
26
32
  servlisten = TCPServer.new(@@SOCKET_PORT)
27
33
  serverwait = Semaphore.new
34
+ stream = '<stream:stream xmlns:stream="http://etherx.jabber.org/streams">'
35
+
28
36
  Thread.new do
29
37
  Thread.current.abort_on_exception = true
30
38
  serversock = servlisten.accept
31
39
  servlisten.close
32
40
  serversock.sync = true
33
- @server = Stream.new(true)
41
+ @server = Stream.new
34
42
  @server.add_xml_callback do |xml|
35
43
  if xml.prefix == 'stream' and xml.name == 'stream'
36
- send('<stream:stream>')
44
+ send(stream)
37
45
  true
38
46
  else
39
47
  false
@@ -46,10 +54,21 @@ module Jabber
46
54
 
47
55
  clientsock = TCPSocket.new('localhost', @@SOCKET_PORT)
48
56
  clientsock.sync = true
49
- @client = Stream.new(true)
57
+ @client = Stream.new
58
+ #=begin
59
+ class << @client
60
+ def jid
61
+ begin
62
+ #raise
63
+ rescue
64
+ puts $!.backtrace.join("\n")
65
+ end
66
+ JID.new('test@test.com/test')
67
+ end
68
+ end
69
+ #=end
50
70
  @client.start(clientsock)
51
-
52
- @client.send('<stream:stream>') { |reply| true }
71
+ @client.send(stream) { |reply| true }
53
72
 
54
73
  @state = 0
55
74
  @states = []
@@ -57,7 +76,11 @@ module Jabber
57
76
  @state_wait2 = Semaphore.new
58
77
  @server.add_stanza_callback { |stanza|
59
78
  if @state < @states.size
60
- @states[@state].call(stanza)
79
+ begin
80
+ @states[@state].call(stanza)
81
+ rescue
82
+ puts "Exception in state: #{$!.class}: #{$!}\n#{$!.join("\n")}"
83
+ end
61
84
  @state += 1
62
85
  @state_wait2.wait
63
86
  @state_wait.run
@@ -78,22 +101,6 @@ module Jabber
78
101
  @server.send(xml)
79
102
  end
80
103
 
81
- def receive
82
- @receive_lock.lock
83
-
84
- loop {
85
- @stanzas_lock.synchronize {
86
- if @stanzas.size > 0
87
- @receive_lock.unlock
88
- return @stanzas.shift
89
- end
90
- }
91
-
92
- @receive_lock.lock
93
- @receive_lock.unlock
94
- }
95
- end
96
-
97
104
  def state(&block)
98
105
  @states << block
99
106
  end
@@ -26,7 +26,7 @@ class MUCClientTest < Test::Unit::TestCase
26
26
  assert_kind_of(Presence, pres)
27
27
  assert_equal(JID.new('hag66@shakespeare.lit/pda'), pres.from)
28
28
  assert_equal(JID.new('darkcave@macbeth.shakespeare.lit/thirdwitch'), pres.to)
29
- send("<presence from='darkcave@macbeth.shakespeare.lit' to='hag66@shakespeare.lit/pda' type='error'>" +
29
+ send("<presence from='darkcave@macbeth.shakespeare.lit' to='hag66@shakespeare.lit/pda' type='error'>" +
30
30
  "<error code='400' type='modify'>" +
31
31
  "<jid-malformed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" +
32
32
  "</error></presence>")
@@ -52,7 +52,7 @@ class MUCClientTest < Test::Unit::TestCase
52
52
  assert(!m.active?)
53
53
  assert_nil(m.room)
54
54
 
55
- assert_raises(ErrorException) {
55
+ assert_raises(ServerError) {
56
56
  m.join('darkcave@macbeth.shakespeare.lit/thirdwitch')
57
57
  }
58
58
  wait_state
@@ -110,7 +110,7 @@ class MUCClientTest < Test::Unit::TestCase
110
110
 
111
111
  m = MUC::MUCClient.new(@client)
112
112
  m.my_jid = 'hag66@shakespeare.lit/pda'
113
- assert_raises(ErrorException) {
113
+ assert_raises(ServerError) {
114
114
  m.join('darkcave@macbeth.shakespeare.lit/thirdwitch')
115
115
  }
116
116
  wait_state
@@ -131,7 +131,7 @@ class MUCClientTest < Test::Unit::TestCase
131
131
 
132
132
  m = MUC::MUCClient.new(@client)
133
133
  m.my_jid = 'hag66@shakespeare.lit/pda'
134
- assert_raises(ErrorException) {
134
+ assert_raises(ServerError) {
135
135
  m.join('darkcave@macbeth.shakespeare.lit/thirdwitch')
136
136
  }
137
137
  assert(!m.active?)
@@ -149,7 +149,7 @@ class MUCClientTest < Test::Unit::TestCase
149
149
 
150
150
  m = MUC::MUCClient.new(@client)
151
151
  m.my_jid = 'hag66@shakespeare.lit/pda'
152
- assert_raises(ErrorException) {
152
+ assert_raises(ServerError) {
153
153
  m.join('darkcave@macbeth.shakespeare.lit/thirdwitch')
154
154
  }
155
155
  assert(!m.active?)
@@ -167,7 +167,7 @@ class MUCClientTest < Test::Unit::TestCase
167
167
 
168
168
  m = MUC::MUCClient.new(@client)
169
169
  m.my_jid = 'hag66@shakespeare.lit/pda'
170
- assert_raises(ErrorException) {
170
+ assert_raises(ServerError) {
171
171
  m.join('darkcave@macbeth.shakespeare.lit/thirdwitch')
172
172
  }
173
173
  assert(!m.active?)
@@ -185,7 +185,7 @@ class MUCClientTest < Test::Unit::TestCase
185
185
 
186
186
  m = MUC::MUCClient.new(@client)
187
187
  m.my_jid = 'hag66@shakespeare.lit/pda'
188
- assert_raises(ErrorException) {
188
+ assert_raises(ServerError) {
189
189
  m.join('darkcave@macbeth.shakespeare.lit/thirdwitch')
190
190
  }
191
191
  assert(!m.active?)
@@ -195,14 +195,14 @@ class MUCClientTest < Test::Unit::TestCase
195
195
 
196
196
  def test_locked_room
197
197
  state { |pres|
198
- send("<presence from='darkcave@macbeth.shakespeare.lit' to='hag66@shakespeare.lit/pda' type='error'>" +
198
+ send("<presence from='darkcave@macbeth.shakespeare.lit' to='hag66@shakespeare.lit/pda' type='error'>" +
199
199
  "<error code='404' type='cancel'><item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>" +
200
200
  "</presence>")
201
201
  }
202
202
 
203
203
  m = MUC::MUCClient.new(@client)
204
204
  m.my_jid = 'hag66@shakespeare.lit/pda'
205
- assert_raises(ErrorException) {
205
+ assert_raises(ServerError) {
206
206
  m.join('darkcave@macbeth.shakespeare.lit/thirdwitch')
207
207
  }
208
208
  assert(!m.active?)
@@ -365,7 +365,7 @@ class MUCClientTest < Test::Unit::TestCase
365
365
  messages_client += 1
366
366
  message_lock.run
367
367
  }
368
-
368
+
369
369
  m = MUC::MUCClient.new(@client)
370
370
  m.my_jid = 'hag66@shakespeare.lit/pda'
371
371
  messages_muc = 0
@@ -425,7 +425,7 @@ class MUCClientTest < Test::Unit::TestCase
425
425
  @client.add_presence_callback { |pres|
426
426
  presences_client += 1
427
427
  presence_lock.run
428
- }
428
+ }
429
429
  m = MUC::MUCClient.new(@client)
430
430
  m.my_jid = 'hag66@shakespeare.lit/pda'
431
431
  presences_join = 0
@@ -522,7 +522,7 @@ class MUCClientTest < Test::Unit::TestCase
522
522
  assert_equal(JID.new('darkcave@macbeth.shakespeare.lit/firstwitch'), stanza.to)
523
523
  assert_equal('Third message', stanza.body)
524
524
  }
525
-
525
+
526
526
  m = MUC::MUCClient.new(@client)
527
527
  m.my_jid = 'hag66@shakespeare.lit/pda'
528
528
 
@@ -579,7 +579,7 @@ class MUCClientTest < Test::Unit::TestCase
579
579
  assert(m.active?)
580
580
  assert_equal('thirdwitch', m.nick)
581
581
 
582
- assert_raises(ErrorException) {
582
+ assert_raises(ServerError) {
583
583
  m.nick = 'secondwitch'
584
584
  }
585
585
  wait_state
@@ -591,4 +591,240 @@ class MUCClientTest < Test::Unit::TestCase
591
591
  assert(m.active?)
592
592
  assert_equal('oldhag', m.nick)
593
593
  end
594
+
595
+ # JEP-0045: 10.2 Room Configuration
596
+ def test_configuration
597
+ room = JID.new('darkcave@macbeth.shakespeare.lit/thirdwitch')
598
+ jid = JID.new('hag66@shakespeare.lit/pda')
599
+
600
+ state { |pres|
601
+ send(
602
+ "<presence from='darkcave@macbeth.shakespeare.lit/thirdwitch' to='hag66@shakespeare.lit/pda'>" +
603
+ "<x xmlns='http://jabber.org/protocol/muc#user'><item affiliation='owner' role='moderator'/></x>" +
604
+ "</presence>"
605
+ )
606
+ }
607
+
608
+ state { |iq|
609
+ assert_kind_of(Jabber::Iq,iq)
610
+ assert_equal(jid, iq.from)
611
+ assert_equal(room.strip, iq.to)
612
+ assert_equal(:get, iq.type)
613
+
614
+ assert_kind_of(Jabber::MUC::IqQueryMUCOwner, iq.first_element('query'))
615
+
616
+ send(muc_config_form.sub("id='config1'","id='#{iq.id}'"))
617
+ }
618
+
619
+ state { |room_config|
620
+ assert_kind_of(Jabber::Iq, room_config)
621
+ assert_equal(room.strip, room_config.to)
622
+ assert_equal(:set, room_config.type)
623
+
624
+ assert_kind_of(Jabber::MUC::IqQueryMUCOwner, room_config.first_element('query'))
625
+
626
+ form = room_config.first_element('query/x')
627
+ assert_kind_of(Dataforms::XData, form)
628
+ assert_equal(:submit, form.type)
629
+ assert_equal(1, form.elements.size)
630
+ assert_equal('muc#roomconfig_roomname', form.first_element('field').var)
631
+ assert_equal(['Dunsinane'], form.first_element('field').values)
632
+
633
+ send(muc_config_acknowledgement.sub("id='config1'","id='#{room_config.id}'"))
634
+ }
635
+
636
+ m = MUC::MUCClient.new(@client)
637
+ m.my_jid = jid
638
+ m.join(room)
639
+ wait_state
640
+ assert_equal(true, m.owner?)
641
+
642
+ assert_equal(%w{muc#roomconfig_roomname muc#roomconfig_roomdesc
643
+ muc#roomconfig_enablelogging muc#roomconfig_changesubject muc#roomconfig_allowinvites
644
+ muc#roomconfig_maxusers muc#roomconfig_presencebroadcast muc#roomconfig_getmemberlist
645
+ muc#roomconfig_publicroom muc#roomconfig_persistentroom muc#roomconfig_moderatedroom
646
+ muc#roomconfig_membersonly muc#roomconfig_passwordprotectedroom muc#roomconfig_roomsecret
647
+ muc#roomconfig_whois muc#roomconfig_roomadmins muc#roomconfig_roomowners}, m.get_room_configuration)
648
+ wait_state
649
+
650
+ m.submit_room_configuration( 'muc#roomconfig_roomname' => 'Dunsinane' )
651
+ wait_state
652
+ end
653
+
654
+ # example 150 from XEP-0045
655
+ def muc_config_form
656
+ "<iq from='darkcave@macbeth.shakespeare.lit'
657
+ id='config1'
658
+ to='crone1@shakespeare.lit/desktop'
659
+ type='result'>
660
+ <query xmlns='http://jabber.org/protocol/muc#owner'>
661
+ <x xmlns='jabber:x:data' type='form'>
662
+ <title>Configuration for \"darkcave\" Room</title>
663
+ <instructions>
664
+ Complete this form to make changes to
665
+ the configuration of your room.
666
+ </instructions>
667
+ <field
668
+ type='hidden'
669
+ var='FORM_TYPE'>
670
+ <value>http://jabber.org/protocol/muc#roomconfig</value>
671
+ </field>
672
+ <field
673
+ label='Natural-Language Room Name'
674
+ type='text-single'
675
+ var='muc#roomconfig_roomname'>
676
+ <value>A Dark Cave</value>
677
+ </field>
678
+ <field
679
+ label='Short Description of Room'
680
+ type='text-single'
681
+ var='muc#roomconfig_roomdesc'>
682
+ <value>The place for all good witches!</value>
683
+ </field>
684
+ <field
685
+ label='Enable Public Logging?'
686
+ type='boolean'
687
+ var='muc#roomconfig_enablelogging'>
688
+ <value>0</value>
689
+ </field>
690
+ <field
691
+ label='Allow Occupants to Change Subject?'
692
+ type='boolean'
693
+ var='muc#roomconfig_changesubject'>
694
+ <value>0</value>
695
+ </field>
696
+ <field
697
+ label='Allow Occupants to Invite Others?'
698
+ type='boolean'
699
+ var='muc#roomconfig_allowinvites'>
700
+ <value>0</value>
701
+ </field>
702
+ <field
703
+ label='Maximum Number of Occupants'
704
+ type='list-single'
705
+ var='muc#roomconfig_maxusers'>
706
+ <value>10</value>
707
+ <option label='10'><value>10</value></option>
708
+ <option label='20'><value>20</value></option>
709
+ <option label='30'><value>30</value></option>
710
+ <option label='50'><value>50</value></option>
711
+ <option label='100'><value>100</value></option>
712
+ <option label='None'><value>none</value></option>
713
+ </field>
714
+ <field
715
+ label='Roles for which Presence is Broadcast'
716
+ type='list-multi'
717
+ var='muc#roomconfig_presencebroadcast'>
718
+ <value>moderator</value>
719
+ <value>participant</value>
720
+ <value>visitor</value>
721
+ <option label='Moderator'><value>moderator</value></option>
722
+ <option label='Participant'><value>participant</value></option>
723
+ <option label='Visitor'><value>visitor</value></option>
724
+ </field>
725
+ <field
726
+ label='Roles and Affiliations that May Retrieve Member List'
727
+ type='list-multi'
728
+ var='muc#roomconfig_getmemberlist'>
729
+ <value>moderator</value>
730
+ <value>participant</value>
731
+ <value>visitor</value>
732
+ <option label='Moderator'><value>moderator</value></option>
733
+ <option label='Participant'><value>participant</value></option>
734
+ <option label='Visitor'><value>visitor</value></option>
735
+ </field>
736
+ <field
737
+ label='Make Room Publicly Searchable?'
738
+ type='boolean'
739
+ var='muc#roomconfig_publicroom'>
740
+ <value>0</value>
741
+ </field>
742
+ <field
743
+ label='Make Room Persistent?'
744
+ type='boolean'
745
+ var='muc#roomconfig_persistentroom'>
746
+ <value>0</value>
747
+ </field>
748
+ <field
749
+ label='Make Room Moderated?'
750
+ type='boolean'
751
+ var='muc#roomconfig_moderatedroom'>
752
+ <value>0</value>
753
+ </field>
754
+ <field
755
+ label='Make Room Members Only?'
756
+ type='boolean'
757
+ var='muc#roomconfig_membersonly'>
758
+ <value>0</value>
759
+ </field>
760
+ <field
761
+ label='Password Required for Entry?'
762
+ type='boolean'
763
+ var='muc#roomconfig_passwordprotectedroom'>
764
+ <value>1</value>
765
+ </field>
766
+ <field type='fixed'>
767
+ <value>
768
+ If a password is required to enter this room,
769
+ you must specify the password below.
770
+ </value>
771
+ </field>
772
+ <field
773
+ label='Password'
774
+ type='text-private'
775
+ var='muc#roomconfig_roomsecret'>
776
+ <value>cauldronburn</value>
777
+ </field>
778
+ <field
779
+ label='Who May Discover Real JIDs?'
780
+ type='list-single'
781
+ var='muc#roomconfig_whois'>
782
+ <value>moderators</value>
783
+ <option label='Moderators Only'>
784
+ <value>moderators</value>
785
+ </option>
786
+ <option label='Anyone'>
787
+ <value>anyone</value>
788
+ </option>
789
+ </field>
790
+ <field type='fixed'>
791
+ <value>
792
+ You may specify additional people who have
793
+ administrative privileges in the room. Please
794
+ provide one Jabber ID per line.
795
+ </value>
796
+ </field>
797
+ <field
798
+ label='Room Admins'
799
+ type='jid-multi'
800
+ var='muc#roomconfig_roomadmins'>
801
+ <value>wiccarocks@shakespeare.lit</value>
802
+ <value>hecate@shakespeare.lit</value>
803
+ </field>
804
+ <field type='fixed'>
805
+ <value>
806
+ You may specify additional owners for this
807
+ room. Please provide one Jabber ID per line.
808
+ </value>
809
+ </field>
810
+ <field
811
+ label='Room Owners'
812
+ type='jid-multi'
813
+ var='muc#roomconfig_roomowners'/>
814
+ </x>
815
+ </query>
816
+ </iq>"
817
+ end
818
+
819
+ def muc_config_acknowledgement
820
+ "<iq from='darkcave@macbeth.shakespeare.lit'
821
+ id='config1'
822
+ to='crone1@shakespeare.lit/desktop'>
823
+ <query xmlns='http://jabber.org/protocol/muc#owner'>
824
+ <x xmlns='jabber:x:data' type='result'>
825
+ <field var='muc#roomconfig_roomname'><value>Dunsinane</value></field>
826
+ </x>
827
+ </query>
828
+ </iq>"
829
+ end
594
830
  end