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
@@ -13,13 +13,17 @@ module Jabber
13
13
  class Connection < Stream
14
14
  attr_reader :host, :port
15
15
 
16
- # Allow TLS negotiation? Defaults to true
17
- attr_accessor :allow_tls
18
-
19
16
  # How many seconds to wait for <stream:features/>
20
17
  # before proceeding
21
18
  attr_accessor :features_timeout
22
19
 
20
+ # Keep-alive interval in seconds, defaults to 60
21
+ # (see private method keepalive_loop for implementation details)
22
+ attr_accessor :keepalive_interval
23
+
24
+ # Allow TLS negotiation? Defaults to true
25
+ attr_accessor :allow_tls
26
+
23
27
  # Optional CA-Path for TLS-handshake
24
28
  attr_accessor :ssl_capath
25
29
 
@@ -38,11 +42,14 @@ module Jabber
38
42
  @ssl_capath = nil
39
43
  @ssl_verifycb = nil
40
44
  @features_timeout = 10
45
+ @keepalive_interval = 60
41
46
  end
42
47
 
43
48
  ##
44
- # Connects to the Jabber server through a TCP Socket and
45
- # starts the Jabber parser.
49
+ # Connect to the Jabber server through a TCP Socket,
50
+ # start the Jabber parser,
51
+ # invoke to accept_features to wait for TLS,
52
+ # start the keep-alive thread
46
53
  def connect(host, port)
47
54
  @host = host
48
55
  @port = port
@@ -54,14 +61,26 @@ module Jabber
54
61
  start
55
62
 
56
63
  accept_features
64
+
65
+ @keepaliveThread = Thread.new do
66
+ Thread.current.abort_on_exception = true
67
+ keepalive_loop
68
+ end
69
+ end
70
+
71
+ ##
72
+ # Closing connection:
73
+ # first kill keepaliveThread, then call Stream#close!
74
+ def close!
75
+ @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive?
76
+ super
57
77
  end
58
78
 
59
79
  def accept_features
60
80
  begin
61
81
  Timeout::timeout(@features_timeout) {
62
82
  Jabber::debuglog("FEATURES: waiting...")
63
- @features_lock.lock
64
- @features_lock.unlock
83
+ @features_sem.wait
65
84
  Jabber::debuglog("FEATURES: waiting finished")
66
85
  }
67
86
  rescue Timeout::Error
@@ -80,8 +99,6 @@ module Jabber
80
99
  ##
81
100
  # Start the parser on the previously connected socket
82
101
  def start
83
- @features_lock.lock
84
-
85
102
  super(@socket)
86
103
  end
87
104
 
@@ -154,13 +171,33 @@ module Jabber
154
171
  stream_start_string += "xmlns='#{xmlns}' " unless xmlns.nil?
155
172
  stream_start_string += "to='#{to}' " unless to.nil?
156
173
  stream_start_string += "from='#{from}' " unless from.nil?
157
- stream_start_string += "id='#{id}' " unless id.nil?
174
+ stream_start_string += "id='#{id}' " unless id.nil?
158
175
  stream_start_string += "xml:lang='#{xml_lang}' " unless xml_lang.nil?
159
176
  stream_start_string += "version='#{version}' " unless version.nil?
160
177
  stream_start_string += ">"
161
178
  stream_start_string
162
179
  end
163
180
  private :generate_stream_start
164
-
165
- end
181
+
182
+ ##
183
+ # A loop to send "keep alive" data to prevent
184
+ # the Jabber connection from closing for inactivity.
185
+ #
186
+ # This loop sends a single white-space character if
187
+ # no other data has been sent in the last @keepalive_interval
188
+ # seconds.
189
+ def keepalive_loop
190
+ loop do
191
+ difference = @last_send + @keepalive_interval - Time.now
192
+ if difference <= 0
193
+ send(' ')
194
+ sleep @keepalive_interval
195
+ else
196
+ sleep(difference)
197
+ end
198
+ end
199
+ end
200
+ private :keepalive_loop
201
+
202
+ end
166
203
  end
@@ -10,27 +10,13 @@ module Jabber
10
10
  ##
11
11
  # Data Forms (JEP-0004) implementation
12
12
  class XData < X
13
+ name_xmlns 'x', 'jabber:x:data'
14
+
13
15
  def initialize(type=nil)
14
16
  super()
15
- add_namespace('jabber:x:data')
16
17
  self.type = type
17
18
  end
18
19
 
19
- def typed_add(xe)
20
- if xe.kind_of?(REXML::Element)
21
- case xe.name
22
- when 'instructions' then super XDataInstructions.new.import(xe)
23
- when 'title' then super XDataTitle.new.import(xe)
24
- when 'field' then super XDataField.new.import(xe)
25
- when 'reported' then super XDataReported.new.import(xe)
26
- #when 'item' then super XDataItem.new.import(xe)
27
- else super xe
28
- end
29
- else
30
- super xe
31
- end
32
- end
33
-
34
20
  ##
35
21
  # Search a field by it's var-name
36
22
  # var:: [String]
@@ -42,6 +28,16 @@ module Jabber
42
28
  nil
43
29
  end
44
30
 
31
+ def fields
32
+ fields = []
33
+ each_element do |xe|
34
+ if xe.kind_of?(XDataField) and xe.type != :hidden and xe.type != :fixed
35
+ fields << xe
36
+ end
37
+ end
38
+ fields
39
+ end
40
+
45
41
  ##
46
42
  # Type of this Data Form
47
43
  # result:: * :cancel
@@ -70,16 +66,53 @@ module Jabber
70
66
  else attributes['type'] = nil
71
67
  end
72
68
  end
69
+
70
+ ##
71
+ # Get the Data Form title
72
+ # return:: [XDataTitle] or nil
73
+ def title
74
+ first_element('title')
75
+ end
76
+
77
+ ##
78
+ # Set the Data Form title
79
+ # title:: [String]
80
+ def title=(title)
81
+ delete_elements('title')
82
+ add_element(XDataTitle.new(title))
83
+ end
84
+
85
+ ##
86
+ # Get the Data Form instructions
87
+ # return:: [Array] of [XDataInstructions] or nil
88
+ def instructions
89
+ fields = []
90
+ each_element('instructions') do |xe|
91
+ fields << xe
92
+ end
93
+ fields
94
+ end
95
+
96
+ ##
97
+ # Add Data Form instructions
98
+ # i:: [String]
99
+ def instructions=(i)
100
+ add(XDataInstructions.new(i))
101
+ end
102
+
73
103
  end
74
104
 
75
- X.add_namespaceclass('jabber:x:data', XData)
76
105
 
77
106
  ##
78
107
  # Child of XData, contains the title of this Data Form
79
- class XDataTitle < REXML::Element
80
- def initialize
81
- super('title')
108
+ class XDataTitle < XMPPElement
109
+ name_xmlns 'title', 'jabber:x:data'
110
+
111
+ def initialize(title=nil)
112
+ super()
113
+ add_text(title)
82
114
  end
115
+
83
116
  def to_s
84
117
  text.to_s
85
118
  end
@@ -90,13 +123,18 @@ module Jabber
90
123
 
91
124
  ##
92
125
  # Child of XData, contains the instructions of this Data Form
93
- class XDataInstructions < REXML::Element
94
- def initialize
95
- super('instructions')
126
+ class XDataInstructions < XMPPElement
127
+ name_xmlns 'instructions', 'jabber:x:data'
128
+
129
+ def initialize(instructions=nil)
130
+ super()
131
+ add_text(instructions)
96
132
  end
133
+
97
134
  def to_s
98
135
  text.to_s
99
136
  end
137
+
100
138
  def instructions
101
139
  text
102
140
  end
@@ -104,9 +142,10 @@ module Jabber
104
142
 
105
143
  ##
106
144
  # Child of XData, contains configurable/configured options of this Data Form
107
- class XDataField < REXML::Element
145
+ class XDataField < XMPPElement
146
+ name_xmlns 'field', 'jabber:x:data'
108
147
  def initialize(var=nil, type=nil)
109
- super('field')
148
+ super()
110
149
  self.var = var
111
150
  self.type = type
112
151
  end
@@ -238,10 +277,8 @@ module Jabber
238
277
 
239
278
  ##
240
279
  # The <reported/> element, can contain XDataField elements
241
- class XDataReported < REXML::Element
242
- def initialize
243
- super('reported')
244
- end
280
+ class XDataReported < XMPPElement
281
+ name_xmlns 'reported', 'jabber:x:data'
245
282
  end
246
283
  end
247
284
  end
@@ -21,13 +21,14 @@ module Jabber
21
21
  # <x/> elements with the specific namespace will then be
22
22
  # converted to XDelay automatically.
23
23
  class XDelay < X
24
+ name_xmlns 'x', 'jabber:x:delay'
25
+
24
26
  ##
25
27
  # Initialize a new XDelay element
26
28
  #
27
29
  # insertnow:: [Boolean] Set the stamp to [Time::now]
28
30
  def initialize(insertnow=true)
29
31
  super()
30
- add_namespace('jabber:x:delay')
31
32
 
32
33
  if insertnow
33
34
  set_stamp(Time.now)
@@ -94,7 +95,5 @@ module Jabber
94
95
  self
95
96
  end
96
97
  end
97
-
98
- X.add_namespaceclass('jabber:x:delay', XDelay)
99
98
  end
100
99
  end
@@ -15,34 +15,7 @@ module Jabber
15
15
  # elements, describing the type and the supported namespaces of
16
16
  # the service.
17
17
  class IqQueryDiscoInfo < IqQuery
18
- ##
19
- # Create a new query
20
- # with namespace http://jabber.org/protocol/disco#info
21
- def initialize
22
- super
23
- add_namespace('http://jabber.org/protocol/disco#info')
24
- end
25
-
26
- ##
27
- # Add a children element
28
- #
29
- # Converts <identity/> elements to [Identity]
30
- # and <feature/> elements to [Feature]
31
- def typed_add(element)
32
- if element.kind_of?(REXML::Element)
33
-
34
- if element.name == 'identity'
35
- super(Identity::new.import(element))
36
- elsif element.name == 'feature'
37
- super(Feature::new.import(element))
38
- else
39
- super(element)
40
- end
41
-
42
- else
43
- super(element)
44
- end
45
- end
18
+ name_xmlns 'query', 'http://jabber.org/protocol/disco#info'
46
19
 
47
20
  ##
48
21
  # Get the queried Service Discovery node or nil
@@ -76,6 +49,17 @@ module Jabber
76
49
  first_element('identity')
77
50
  end
78
51
 
52
+ ##
53
+ # Get list of identities
54
+ # result:: [Array] of [Identity]
55
+ def identities
56
+ res = []
57
+ each_element('identity') { |id|
58
+ res.push(id)
59
+ }
60
+ res
61
+ end
62
+
79
63
  ##
80
64
  # Get list of features
81
65
  # result:: [Array] of [String]
@@ -88,20 +72,21 @@ module Jabber
88
72
  end
89
73
  end
90
74
 
91
- IqQuery.add_namespaceclass('http://jabber.org/protocol/disco#info', IqQueryDiscoInfo)
92
75
 
93
76
  ##
94
77
  # Service Discovery identity to add() to IqQueryDiscoInfo
95
78
  #
96
79
  # Please note that JEP 0030 requires both category and type to occur
97
- class Identity < REXML::Element
80
+ class Identity < XMPPElement
81
+ name_xmlns 'identity', 'http://jabber.org/protocol/disco#info'
82
+
98
83
  ##
99
84
  # Initialize a new Identity
100
85
  # category:: [String] Initial category or nil
101
86
  # iname:: [String] Initial identity name or nil
102
87
  # type:: [String] Initial type or nil
103
88
  def initialize(category=nil, iname=nil, type=nil)
104
- super('identity')
89
+ super()
105
90
  set_category(category)
106
91
  set_iname(iname)
107
92
  set_type(type)
@@ -187,12 +172,14 @@ module Jabber
187
172
  # Service Discovery feature to add() to IqQueryDiscoInfo
188
173
  #
189
174
  # Please note that JEP 0030 requires var to be set
190
- class Feature < REXML::Element
175
+ class Feature < XMPPElement
176
+ name_xmlns 'feature', 'http://jabber.org/protocol/disco#info'
177
+
191
178
  ##
192
179
  # Create a new <feature/> element
193
180
  # var:: [String] New var
194
181
  def initialize(var=nil)
195
- super('feature')
182
+ super()
196
183
  set_var(var)
197
184
  end
198
185
 
@@ -17,31 +17,7 @@ module Jabber
17
17
  # querying IqQueryDiscoInfo and further sub-items by querying
18
18
  # IqQueryDiscoItems.
19
19
  class IqQueryDiscoItems < IqQuery
20
- ##
21
- # Create a new query
22
- # with namespace http://jabber.org/protocol/disco#items
23
- def initialize
24
- super
25
- add_namespace('http://jabber.org/protocol/disco#items')
26
- end
27
-
28
- ##
29
- # Add a children element
30
- #
31
- # Converts <item/> elements to [Item]
32
- def typed_add(element)
33
- if element.kind_of?(REXML::Element)
34
-
35
- if element.name == 'item'
36
- super(Item::new.import(element))
37
- else
38
- super(element)
39
- end
40
-
41
- else
42
- super(element)
43
- end
44
- end
20
+ name_xmlns 'query', 'http://jabber.org/protocol/disco#items'
45
21
 
46
22
  ##
47
23
  # Get the queried Service Discovery node or nil
@@ -68,13 +44,14 @@ module Jabber
68
44
  end
69
45
  end
70
46
 
71
- IqQuery.add_namespaceclass('http://jabber.org/protocol/disco#items', IqQueryDiscoItems)
72
47
 
73
48
  ##
74
49
  # Service Discovery item to add() to IqQueryDiscoItems
75
50
  #
76
51
  # Please note that JEP 0030 requires the jid to occur
77
- class Item < REXML::Element
52
+ class Item < XMPPElement
53
+ name_xmlns 'item', 'http://jabber.org/protocol/disco#items'
54
+
78
55
  ##
79
56
  # Initialize a new Service Discovery <item/>
80
57
  # to be added to IqQueryDiscoItems
@@ -82,7 +59,7 @@ module Jabber
82
59
  # iname:: [String] Item name
83
60
  # node:: [String] Service Discovery node (_not_ JID#node)
84
61
  def initialize(jid=nil, iname=nil, node=nil)
85
- super('item')
62
+ super()
86
63
  set_jid(jid)
87
64
  set_iname(iname)
88
65
  set_node(node)
@@ -6,7 +6,9 @@ module Jabber
6
6
  ##
7
7
  # A class used to build/parse <error/> elements.
8
8
  # Look at JEP 0086 for explanation.
9
- class Error < REXML::Element
9
+ class Error < XMPPElement
10
+ name_xmlns 'error'
11
+
10
12
  ##
11
13
  # errorcondition:: [nil] or [String] of the following:
12
14
  # * "bad-request"
@@ -38,7 +40,7 @@ module Jabber
38
40
  # text: [nil] or [String] Error text
39
41
  def initialize(errorcondition=nil, text=nil)
40
42
  if errorcondition.nil?
41
- super('error')
43
+ super()
42
44
  set_text(text) unless text.nil?
43
45
  else
44
46
  errortype = nil
@@ -54,7 +56,7 @@ module Jabber
54
56
  raise("Unknown error condition when initializing Error")
55
57
  end
56
58
 
57
- super("error")
59
+ super()
58
60
  set_error(errorcondition)
59
61
  set_type(errortype)
60
62
  set_code(errorcode)
@@ -62,13 +64,6 @@ module Jabber
62
64
  end
63
65
  end
64
66
 
65
- ##
66
- # Create a new <error/> element and import from existing
67
- # element:: [REXML::Element] to import
68
- def Error.import(element)
69
- Error::new.import(element)
70
- end
71
-
72
67
  ##
73
68
  # Get the 'Legacy error code' or nil
74
69
  # result:: [Integer] Error code