xmpp4r 0.3

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.
Files changed (142) hide show
  1. data/COPYING +340 -0
  2. data/ChangeLog +28 -0
  3. data/LICENSE +59 -0
  4. data/README +20 -0
  5. data/Rakefile +103 -0
  6. data/UPDATING +40 -0
  7. data/data/doc/xmpp4r/examples/advanced/adventure/README +57 -0
  8. data/data/doc/xmpp4r/examples/advanced/adventure/adventure.rb +23 -0
  9. data/data/doc/xmpp4r/examples/advanced/adventure/adventuremuc.rb +136 -0
  10. data/data/doc/xmpp4r/examples/advanced/adventure/cube.xml +15 -0
  11. data/data/doc/xmpp4r/examples/advanced/adventure/tower.xml +69 -0
  12. data/data/doc/xmpp4r/examples/advanced/adventure/world.rb +425 -0
  13. data/data/doc/xmpp4r/examples/advanced/fileserve.conf +11 -0
  14. data/data/doc/xmpp4r/examples/advanced/fileserve.rb +344 -0
  15. data/data/doc/xmpp4r/examples/advanced/getonline.rb +56 -0
  16. data/data/doc/xmpp4r/examples/advanced/gtkmucclient.rb +315 -0
  17. data/data/doc/xmpp4r/examples/advanced/migrate.rb +89 -0
  18. data/data/doc/xmpp4r/examples/advanced/minimuc.rb +266 -0
  19. data/data/doc/xmpp4r/examples/advanced/recvfile.rb +83 -0
  20. data/data/doc/xmpp4r/examples/advanced/rosterdiscovery.rb +130 -0
  21. data/data/doc/xmpp4r/examples/advanced/sendfile.conf +10 -0
  22. data/data/doc/xmpp4r/examples/advanced/sendfile.rb +72 -0
  23. data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr.rb +51 -0
  24. data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_jabber.rb +43 -0
  25. data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_test.rb +10 -0
  26. data/data/doc/xmpp4r/examples/advanced/versionpoll.rb +90 -0
  27. data/data/doc/xmpp4r/examples/advanced/xmpping.rb +134 -0
  28. data/data/doc/xmpp4r/examples/advanced/xmppingrc.sample +9 -0
  29. data/data/doc/xmpp4r/examples/basic/change_password.rb +41 -0
  30. data/data/doc/xmpp4r/examples/basic/client.rb +68 -0
  31. data/data/doc/xmpp4r/examples/basic/component.rb +11 -0
  32. data/data/doc/xmpp4r/examples/basic/echo_nonthreaded.rb +32 -0
  33. data/data/doc/xmpp4r/examples/basic/echo_threaded.rb +32 -0
  34. data/data/doc/xmpp4r/examples/basic/jabbersend.rb +41 -0
  35. data/data/doc/xmpp4r/examples/basic/mass_sender.rb +67 -0
  36. data/data/doc/xmpp4r/examples/basic/mucinfo.rb +39 -0
  37. data/data/doc/xmpp4r/examples/basic/mucsimplebot.rb +83 -0
  38. data/data/doc/xmpp4r/examples/basic/register.rb +25 -0
  39. data/data/doc/xmpp4r/examples/basic/remove_registration.rb +18 -0
  40. data/data/doc/xmpp4r/examples/basic/roster.rb +42 -0
  41. data/data/doc/xmpp4r/examples/basic/rosterprint.rb +50 -0
  42. data/data/doc/xmpp4r/examples/basic/rosterrename.rb +34 -0
  43. data/data/doc/xmpp4r/examples/basic/rosterwatch.rb +172 -0
  44. data/data/doc/xmpp4r/examples/basic/send_vcard.rb +68 -0
  45. data/data/doc/xmpp4r/examples/basic/versionbot.rb +75 -0
  46. data/data/doc/xmpp4r/examples/buggy/jabber2jabber/jabber2jabber.rb +18 -0
  47. data/data/doc/xmpp4r/examples/buggy/miniedgarr_cgi.rb +192 -0
  48. data/data/doc/xmpp4r/examples/buggy/miniedgarr_watch.rb +82 -0
  49. data/lib/callbacks.rb +122 -0
  50. data/lib/xmpp4r/authenticationfailure.rb +13 -0
  51. data/lib/xmpp4r/bytestreams/helper/filetransfer.rb +315 -0
  52. data/lib/xmpp4r/bytestreams/helper/ibb/base.rb +256 -0
  53. data/lib/xmpp4r/bytestreams/helper/ibb/initiator.rb +30 -0
  54. data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +46 -0
  55. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb +151 -0
  56. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb +85 -0
  57. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb +178 -0
  58. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb +56 -0
  59. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +61 -0
  60. data/lib/xmpp4r/bytestreams/iq/bytestreams.rb +177 -0
  61. data/lib/xmpp4r/bytestreams/iq/si.rb +221 -0
  62. data/lib/xmpp4r/bytestreams.rb +11 -0
  63. data/lib/xmpp4r/client.rb +249 -0
  64. data/lib/xmpp4r/component.rb +103 -0
  65. data/lib/xmpp4r/connection.rb +166 -0
  66. data/lib/xmpp4r/dataforms/x/data.rb +248 -0
  67. data/lib/xmpp4r/dataforms.rb +1 -0
  68. data/lib/xmpp4r/debuglog.rb +34 -0
  69. data/lib/xmpp4r/delay/x/delay.rb +100 -0
  70. data/lib/xmpp4r/delay.rb +1 -0
  71. data/lib/xmpp4r/discovery/iq/discoinfo.rb +225 -0
  72. data/lib/xmpp4r/discovery/iq/discoitems.rb +162 -0
  73. data/lib/xmpp4r/discovery.rb +2 -0
  74. data/lib/xmpp4r/error.rb +230 -0
  75. data/lib/xmpp4r/errorexception.rb +32 -0
  76. data/lib/xmpp4r/feature_negotiation/iq/feature.rb +42 -0
  77. data/lib/xmpp4r/feature_negotiation.rb +1 -0
  78. data/lib/xmpp4r/idgenerator.rb +37 -0
  79. data/lib/xmpp4r/iq.rb +229 -0
  80. data/lib/xmpp4r/jid.rb +167 -0
  81. data/lib/xmpp4r/message.rb +171 -0
  82. data/lib/xmpp4r/muc/helper/mucbrowser.rb +107 -0
  83. data/lib/xmpp4r/muc/helper/mucclient.rb +382 -0
  84. data/lib/xmpp4r/muc/helper/simplemucclient.rb +222 -0
  85. data/lib/xmpp4r/muc/x/muc.rb +98 -0
  86. data/lib/xmpp4r/muc/x/mucuserinvite.rb +58 -0
  87. data/lib/xmpp4r/muc/x/mucuseritem.rb +148 -0
  88. data/lib/xmpp4r/muc.rb +6 -0
  89. data/lib/xmpp4r/presence.rb +255 -0
  90. data/lib/xmpp4r/query.rb +43 -0
  91. data/lib/xmpp4r/rexmladdons.rb +826 -0
  92. data/lib/xmpp4r/roster/helper/roster.rb +514 -0
  93. data/lib/xmpp4r/roster/iq/roster.rb +244 -0
  94. data/lib/xmpp4r/roster/x/roster.rb +155 -0
  95. data/lib/xmpp4r/roster.rb +4 -0
  96. data/lib/xmpp4r/sasl.rb +167 -0
  97. data/lib/xmpp4r/stream.rb +543 -0
  98. data/lib/xmpp4r/streamparser.rb +77 -0
  99. data/lib/xmpp4r/vcard/helper/vcard.rb +86 -0
  100. data/lib/xmpp4r/vcard/iq/vcard.rb +102 -0
  101. data/lib/xmpp4r/vcard.rb +3 -0
  102. data/lib/xmpp4r/version/helper/responder.rb +71 -0
  103. data/lib/xmpp4r/version/helper/simpleresponder.rb +44 -0
  104. data/lib/xmpp4r/version/iq/version.rb +118 -0
  105. data/lib/xmpp4r/version.rb +3 -0
  106. data/lib/xmpp4r/x.rb +43 -0
  107. data/lib/xmpp4r/xmlstanza.rb +174 -0
  108. data/lib/xmpp4r/xmpp4r.rb +16 -0
  109. data/lib/xmpp4r.rb +122 -0
  110. data/setup.rb +1360 -0
  111. data/test/bytestreams/tc_ibb.rb +186 -0
  112. data/test/bytestreams/tc_socks5bytestreams.rb +57 -0
  113. data/test/delay/tc_xdelay.rb +51 -0
  114. data/test/lib/clienttester.rb +110 -0
  115. data/test/muc/tc_muc_mucclient.rb +569 -0
  116. data/test/muc/tc_muc_simplemucclient.rb +72 -0
  117. data/test/roster/.tc_helper.rb.swp +0 -0
  118. data/test/roster/tc_helper.rb +389 -0
  119. data/test/roster/tc_iqqueryroster.rb +140 -0
  120. data/test/roster/tc_xroster.rb +70 -0
  121. data/test/tc_callbacks.rb +128 -0
  122. data/test/tc_class_names.rb +129 -0
  123. data/test/tc_client.rb +30 -0
  124. data/test/tc_error.rb +103 -0
  125. data/test/tc_idgenerator.rb +30 -0
  126. data/test/tc_iq.rb +109 -0
  127. data/test/tc_iqquery.rb +31 -0
  128. data/test/tc_jid.rb +202 -0
  129. data/test/tc_message.rb +114 -0
  130. data/test/tc_presence.rb +148 -0
  131. data/test/tc_stream.rb +182 -0
  132. data/test/tc_streamError.rb +87 -0
  133. data/test/tc_streamSend.rb +59 -0
  134. data/test/tc_streamThreaded.rb +168 -0
  135. data/test/tc_xmlstanza.rb +76 -0
  136. data/test/ts_xmpp4r.rb +34 -0
  137. data/test/vcard/tc_iqvcard.rb +52 -0
  138. data/test/version/tc_helper.rb +46 -0
  139. data/test/version/tc_iqqueryversion.rb +96 -0
  140. data/tools/doctoweb.bash +30 -0
  141. data/tools/gen_requires.bash +10 -0
  142. metadata +232 -0
@@ -0,0 +1,221 @@
1
+ require 'time' # For Time#xmlschema
2
+
3
+ require 'xmpp4r/feature_negotiation/iq/feature'
4
+
5
+ module Jabber
6
+ module Bytestreams
7
+ ##
8
+ # Iq child 'si' for Stream-Initiation
9
+ class IqSi < REXML::Element
10
+ PROFILE_FILETRANSFER = 'http://jabber.org/protocol/si/profile/file-transfer'
11
+
12
+ def initialize(id=nil, profile=nil, mime_type=nil)
13
+ super('si')
14
+
15
+ add_namespace 'http://jabber.org/protocol/si'
16
+ self.id = id
17
+ self.profile = profile
18
+ self.mime_type = mime_type
19
+ end
20
+
21
+ def IqSi.import(element)
22
+ IqSi::new.import(element)
23
+ end
24
+
25
+ def typed_add(element)
26
+ if element.kind_of?(REXML::Element) and element.name == 'file'
27
+ super IqSiFile.new.import(element)
28
+ elsif element.kind_of?(REXML::Element) and element.name == 'feature'
29
+ super FeatureNegotiation::IqFeature.new.import(element)
30
+ else
31
+ super element
32
+ end
33
+ end
34
+
35
+ ##
36
+ # Session ID of this stream
37
+ def id
38
+ attributes['id']
39
+ end
40
+
41
+ ##
42
+ # Set Session ID of this stream
43
+ def id=(s)
44
+ attributes['id'] = s
45
+ end
46
+
47
+ ##
48
+ # MIME type of this stream
49
+ def mime_type
50
+ attributes['mime-type']
51
+ end
52
+
53
+ ##
54
+ # Set MIME type of this stream
55
+ def mime_type=(s)
56
+ attributes['mime-type'] = s
57
+ end
58
+
59
+ ##
60
+ # Stream profile, can indicate file-transfer
61
+ def profile
62
+ attributes['profile']
63
+ end
64
+
65
+ ##
66
+ # Set stream profile
67
+ def profile=(s)
68
+ attributes['profile'] = s
69
+ end
70
+
71
+ ##
72
+ # <file/> child
73
+ # result:: [IqSiFile]
74
+ def file
75
+ first_element('file')
76
+ end
77
+
78
+ ##
79
+ # <feature/> child
80
+ # result:: [IqFeature]
81
+ def feature
82
+ first_element('feature')
83
+ end
84
+ end
85
+
86
+ Iq.add_elementclass('si', IqSi)
87
+
88
+ ##
89
+ # File-transfer meta-information,
90
+ # may appear as <file/> in IqSi
91
+ class IqSiFile < REXML::Element
92
+ def initialize(fname=nil, size=nil)
93
+ super 'file'
94
+ add_namespace IqSi::PROFILE_FILETRANSFER
95
+ self.fname = fname
96
+ self.size = size
97
+ end
98
+
99
+ def typed_add(element)
100
+ if element.kind_of?(REXML::Element) and element.name == 'range'
101
+ super IqSiFileRange.new.import(element)
102
+ else
103
+ super element
104
+ end
105
+ end
106
+
107
+ ##
108
+ # Get filename (attribute 'name')
109
+ def fname
110
+ attributes['name']
111
+ end
112
+
113
+ ##
114
+ # Set filename (attribute 'name')
115
+ def fname=(s)
116
+ attributes['name'] = s
117
+ end
118
+
119
+ ##
120
+ # Get MD5 hash
121
+ def hash
122
+ attributes['hash']
123
+ end
124
+
125
+ ##
126
+ # Set MD5 hash
127
+ def hash=(s)
128
+ attributes['hash'] = s
129
+ end
130
+
131
+ ##
132
+ # Get file date
133
+ # result:: [Time] or nil
134
+ def date
135
+ begin
136
+ Time.xmlschema(attributes['date'])
137
+ rescue ArgumentError
138
+ nil
139
+ end
140
+ end
141
+
142
+ ##
143
+ # Set file date
144
+ # d:: [Time] or nil
145
+ def date=(d)
146
+ attributes['date'] = (d ? d.xmlschema : nil)
147
+ end
148
+
149
+ ##
150
+ # File size in bytes
151
+ # result:: [Fixnum]
152
+ def size
153
+ (attributes['size'] =~ /^\d+$/) ? attributes['size'].to_i : nil
154
+ end
155
+
156
+ ##
157
+ # Set file size
158
+ def size=(s)
159
+ attributes['size'] = s ? s.to_s : nil
160
+ end
161
+
162
+ ##
163
+ # File description
164
+ def description
165
+ first_element_text('desc')
166
+ end
167
+
168
+ ##
169
+ # Set file description
170
+ def description=(s)
171
+ replace_element_text('desc', s)
172
+ end
173
+
174
+ ##
175
+ # <range/> child
176
+ #
177
+ # A file-transfer offer may contain this with
178
+ # no attributes set, indicating the ability to
179
+ # do ranged transfers.
180
+ # result:: [IqSiFileRange]
181
+ def range
182
+ first_element('range')
183
+ end
184
+ end
185
+
186
+ ##
187
+ # Information for ranged transfers
188
+ class IqSiFileRange < REXML::Element
189
+ def initialize(offset=nil, length=nil)
190
+ super('range')
191
+
192
+ self.offset = offset
193
+ self.length = length
194
+ end
195
+
196
+ ##
197
+ # File offset (for continuing an interrupted transfer)
198
+ def offset
199
+ (attributes['offset'] =~ /^\d+$/) ? attributes['offset'].to_i : nil
200
+ end
201
+
202
+ ##
203
+ # Set file offset
204
+ def offset=(o)
205
+ attributes['offset'] = (o ? o.to_s : nil)
206
+ end
207
+
208
+ ##
209
+ # File length (if not to transfer whole file)
210
+ def length
211
+ (attributes['length'] =~ /^\d+$/) ? attributes['length'].to_i : nil
212
+ end
213
+
214
+ ##
215
+ # Set file length
216
+ def length=(o)
217
+ attributes['length'] = (o ? o.to_s : nil)
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,11 @@
1
+ require 'xmpp4r/bytestreams/iq/si.rb'
2
+ require 'xmpp4r/bytestreams/iq/bytestreams.rb'
3
+ require 'xmpp4r/bytestreams/helper/ibb/base.rb'
4
+ require 'xmpp4r/bytestreams/helper/ibb/initiator.rb'
5
+ require 'xmpp4r/bytestreams/helper/ibb/target.rb'
6
+ require 'xmpp4r/bytestreams/helper/filetransfer.rb'
7
+ require 'xmpp4r/bytestreams/helper/socks5bytestreams/base.rb'
8
+ require 'xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb'
9
+ require 'xmpp4r/bytestreams/helper/socks5bytestreams/server.rb'
10
+ require 'xmpp4r/bytestreams/helper/socks5bytestreams/target.rb'
11
+ require 'xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb'
@@ -0,0 +1,249 @@
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
+ require 'resolv'
6
+
7
+ require 'xmpp4r/connection'
8
+ require 'xmpp4r/authenticationfailure'
9
+ require 'xmpp4r/sasl'
10
+
11
+ module Jabber
12
+
13
+ # The client class provides everything needed to build a basic XMPP
14
+ # Client.
15
+ #
16
+ # If you want your connection to survive disconnects and timeouts,
17
+ # catch exception in Stream#on_exception and re-call Client#connect
18
+ # and Client#auth. Don't forget to re-send initial Presence and
19
+ # everything else you need to setup your session.
20
+ class Client < Connection
21
+
22
+ # The client's JID
23
+ attr_reader :jid
24
+
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.
29
+ #
30
+ # Remember to *always* put a resource in your JID unless the server can do SASL.
31
+ def initialize(jid, threaded = true)
32
+ super(threaded)
33
+ @jid = (jid.kind_of?(JID) ? jid : JID.new(jid.to_s))
34
+ end
35
+
36
+ ##
37
+ # connect to the server
38
+ # (chaining-friendly)
39
+ #
40
+ # If you omit the optional host argument SRV records for your jid will
41
+ # be resolved. If none works, fallback is connecting to the domain part
42
+ # of the jid.
43
+ # host:: [String] Optional c2s host, will be extracted from jid if nil
44
+ # return:: self
45
+ def connect(host = nil, port = 5222)
46
+ if host.nil?
47
+ begin
48
+ srv = []
49
+ Resolv::DNS.open { |dns|
50
+ # If ruby version is too old and SRV is unknown, this will raise a NameError
51
+ # which is catched below
52
+ Jabber::debuglog("RESOLVING:\n_xmpp-client._tcp.#{@jid.domain} (SRV)")
53
+ srv = dns.getresources("_xmpp-client._tcp.#{@jid.domain}", Resolv::DNS::Resource::IN::SRV)
54
+ }
55
+ # Sort SRV records: lowest priority first, highest weight first
56
+ srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
57
+
58
+ srv.each { |record|
59
+ begin
60
+ connect(record.target.to_s, record.port)
61
+ # Success
62
+ return self
63
+ rescue SocketError
64
+ # Try next SRV record
65
+ end
66
+ }
67
+ rescue NameError
68
+ $stderr.puts "Resolv::DNS does not support SRV records. Please upgrade to ruby-1.8.3 or later!"
69
+ end
70
+ # Fallback to normal connect method
71
+ end
72
+
73
+ super(host.nil? ? jid.domain : host, port)
74
+ self
75
+ end
76
+
77
+ ##
78
+ # Close the connection,
79
+ # sends <tt></stream:stream></tt> tag first
80
+ def close
81
+ send("</stream:stream>")
82
+ super
83
+ end
84
+
85
+ ##
86
+ # Start the stream-parser and send the client-specific stream opening element
87
+ def start
88
+ super
89
+ send(generate_stream_start(@jid.domain)) { |e|
90
+ if e.name == 'stream'
91
+ true
92
+ else
93
+ false
94
+ end
95
+ }
96
+ end
97
+
98
+ ##
99
+ # Authenticate with the server
100
+ #
101
+ # Throws AuthenticationFailure
102
+ #
103
+ # Authentication mechanisms are used in the following preference:
104
+ # * SASL DIGEST-MD5
105
+ # * SASL PLAIN
106
+ # * Non-SASL digest
107
+ # password:: [String]
108
+ def auth(password)
109
+ begin
110
+ if @stream_mechanisms.include? 'DIGEST-MD5'
111
+ auth_sasl SASL.new(self, 'DIGEST-MD5'), password
112
+ elsif @stream_mechanisms.include? 'PLAIN'
113
+ auth_sasl SASL.new(self, 'PLAIN'), password
114
+ else
115
+ auth_nonsasl(password)
116
+ end
117
+ rescue
118
+ Jabber::debuglog("#{$!.class}: #{$!}\n#{$!.backtrace.join("\n")}")
119
+ raise AuthenticationFailure.new, $!.to_s
120
+ end
121
+ end
122
+
123
+ ##
124
+ # Use a SASL authentication mechanism and bind to a resource
125
+ #
126
+ # If there was no resource given in the jid, the jid/resource
127
+ # generated by the server will be accepted.
128
+ #
129
+ # This method should not be used directly. Instead, Client#auth
130
+ # may look for the best mechanism suitable.
131
+ # sasl:: Descendant of [Jabber::SASL::Base]
132
+ # password:: [String]
133
+ def auth_sasl(sasl, password)
134
+ sasl.auth(password)
135
+
136
+ # Restart stream after SASL auth
137
+ stop
138
+ start
139
+ # And wait for features - again
140
+ @features_lock.lock
141
+ @features_lock.unlock
142
+
143
+ # Resource binding (RFC3920 - 7)
144
+ if @stream_features.has_key? 'bind'
145
+ iq = Iq.new(:set)
146
+ bind = iq.add REXML::Element.new('bind')
147
+ bind.add_namespace @stream_features['bind']
148
+ if jid.resource
149
+ resource = bind.add REXML::Element.new('resource')
150
+ resource.text = jid.resource
151
+ end
152
+
153
+ send_with_id(iq) { |reply|
154
+ reported_jid = reply.first_element('jid')
155
+ if reply.type == :result and reported_jid and reported_jid.text
156
+ @jid = JID.new(reported_jid.text)
157
+ end
158
+
159
+ true
160
+ }
161
+ end
162
+
163
+ # Session starting
164
+ if @stream_features.has_key? 'session'
165
+ iq = Iq.new(:set)
166
+ session = iq.add REXML::Element.new('session')
167
+ session.add_namespace @stream_features['session']
168
+
169
+ send_with_id(iq) { true }
170
+ end
171
+ end
172
+
173
+ ##
174
+ # Send auth with given password and wait for result
175
+ # (non-SASL)
176
+ #
177
+ # Throws ErrorException
178
+ # password:: [String] the password
179
+ # digest:: [Boolean] use Digest authentication
180
+ def auth_nonsasl(password, digest=true)
181
+ authset = nil
182
+ if digest
183
+ authset = Iq::new_authset_digest(@jid, @streamid.to_s, password)
184
+ else
185
+ authset = Iq::new_authset(@jid, password)
186
+ end
187
+ send_with_id(authset) do |r|
188
+ true
189
+ end
190
+ $defout.flush
191
+
192
+ true
193
+ end
194
+
195
+ ##
196
+ # Register a new user account
197
+ # (may be used instead of Client#auth)
198
+ #
199
+ # This method may raise ErrorException if the registration was
200
+ # not successful.
201
+ def register(password)
202
+ reg = Iq.new_register(jid.node, password)
203
+ reg.to = jid.domain
204
+ send_with_id(reg) { |answer|
205
+ true
206
+ }
207
+ end
208
+
209
+ ##
210
+ # Remove the registration of a user account
211
+ #
212
+ # *WARNING:* this deletes your roster and everything else
213
+ # stored on the server!
214
+ def remove_registration
215
+ reg = Iq.new_register
216
+ reg.to = jid.domain
217
+ reg.query.add(REXML::Element.new('remove'))
218
+ send_with_id(reg) { |answer|
219
+ p answer.to_s
220
+ true
221
+ }
222
+ end
223
+
224
+ ##
225
+ # Change the client's password
226
+ #
227
+ # Threading is suggested, as this code waits
228
+ # for an answer.
229
+ #
230
+ # Raises an exception upon error response (ErrorException from
231
+ # Stream#send_with_id).
232
+ # new_password:: [String] New password
233
+ def password=(new_password)
234
+ iq = Iq::new_query(:set, @jid.domain)
235
+ iq.query.add_namespace('jabber:iq:register')
236
+ iq.query.add(REXML::Element.new('username')).text = @jid.node
237
+ iq.query.add(REXML::Element.new('password')).text = new_password
238
+
239
+ err = nil
240
+ send_with_id(iq) { |answer|
241
+ if answer.type == :result
242
+ true
243
+ else
244
+ false
245
+ end
246
+ }
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,103 @@
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
+ require 'xmpp4r/connection'
6
+
7
+ module Jabber
8
+ ##
9
+ # The component class provides everything needed to build a XMPP Component.
10
+ #
11
+ # Components are more flexible as they are only restricted in the use of a
12
+ # fixed domain. node and resource of JIDs are freely choosable for all stanzas.
13
+ class Component < Connection
14
+
15
+ # The component's JID
16
+ attr_reader :jid
17
+
18
+ # The server's address
19
+ attr_reader :server_address
20
+
21
+ # The server's port
22
+ attr_reader :server_port
23
+
24
+ # Create a new Component
25
+ # jid:: [JID]
26
+ def initialize(jid, server_address=nil, server_port=5347, threaded = true)
27
+ super(threaded)
28
+ @jid = (jid.kind_of?(JID) ? jid : JID.new(jid.to_s))
29
+
30
+ if server_address
31
+ $stderr.puts "Passing server and port to Jabber::Component::new is " +
32
+ "obsolete and will vanish in some later XMPP4R release. " +
33
+ "Please use these arguments when calling " +
34
+ "Jabber::Client#connect"
35
+ @server_address = server_address
36
+ @server_port = server_port
37
+ end
38
+ end
39
+
40
+ # Connect to the server
41
+ # (chaining-friendly)
42
+ # server:: [String] Hostname
43
+ # port:: [Integer] TCP port (5347)
44
+ # return:: self
45
+ def connect(server=nil, port=5347)
46
+ if server
47
+ super(server, port)
48
+ else
49
+ super(@server_address, @server_port)
50
+ end
51
+ self
52
+ end
53
+
54
+ ##
55
+ # Close the connection,
56
+ # sends <tt></stream:stream></tt> tag first
57
+ def close
58
+ send("</stream:stream>")
59
+ super
60
+ end
61
+
62
+ def generate_stream_start(to=nil, from=nil, id=nil, xml_lang="en", xmlns="jabber:component:accept", version="1.0")
63
+ super
64
+ end
65
+ private :generate_stream_start
66
+
67
+ ##
68
+ # Start the stream-parser and send the component-specific stream opening element
69
+ def start
70
+ super
71
+ send(generate_stream_start(@jid)) { |e|
72
+ if e.name == 'stream'
73
+ true
74
+ else
75
+ false
76
+ end
77
+ }
78
+ end
79
+
80
+ ##
81
+ # Send auth with given secret and wait for result
82
+ #
83
+ # Throws AuthenticationFailure
84
+ # secret:: [String] the shared secret
85
+ def auth(secret)
86
+ hash = Digest::SHA1::new(@streamid.to_s + secret).to_s
87
+ authenticated = false
88
+ send("<handshake>#{hash}</handshake>") { |r|
89
+ if r.prefix == 'stream' and r.name == 'error'
90
+ true
91
+ elsif r.name == 'handshake'
92
+ authenticated = true
93
+ true
94
+ else
95
+ false
96
+ end
97
+ }
98
+ unless authenticated
99
+ raise AuthenticationFailure.new, "Component authentication failed"
100
+ end
101
+ end
102
+ end
103
+ end