xmpp4r 0.3

Sign up to get free protection for your applications and to get access to all the features.
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