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,37 @@
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 'singleton'
6
+
7
+ module Jabber
8
+ ##
9
+ # The Jabber::IdGenerator class generates unique IDs for use
10
+ # in XMMP stanzas. Jabber::IdGenerator includes the Singleton
11
+ # Mixin, usage as following:
12
+ # Jabber::IdGenerator.generate_id
13
+ # => "23"
14
+ class IdGenerator
15
+ include Singleton
16
+
17
+ def initialize
18
+ @last_id = 0
19
+ end
20
+
21
+ ##
22
+ # Generate an unique ID.
23
+ #
24
+ # This is kind of boring this way, as it just counts up
25
+ # a number. Maybe something more random somewhen...
26
+ def IdGenerator.generate_id
27
+ IdGenerator.instance.generate_id
28
+ end
29
+
30
+ def generate_id
31
+ @last_id += 1
32
+ timefrac = Time.new.to_f.to_s.split(/\./, 2).last[-3..-1]
33
+
34
+ "#{@last_id}#{timefrac}"
35
+ end
36
+ end
37
+ end
data/lib/xmpp4r/iq.rb ADDED
@@ -0,0 +1,229 @@
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/xmlstanza'
6
+ require 'xmpp4r/jid'
7
+ require 'digest/sha1'
8
+
9
+ module Jabber
10
+ ##
11
+ # IQ: Information/Query
12
+ # (see RFC3920 - 9.2.3
13
+ #
14
+ # A class used to build/parse IQ requests/responses
15
+ class Iq < XMLStanza
16
+ @@element_classes = {}
17
+
18
+ ##
19
+ # Build a new <iq/> stanza
20
+ # type:: [Symbol] or nil, see Iq#type
21
+ # to:: [JID] Recipient
22
+ def initialize(type = nil, to = nil)
23
+ super("iq")
24
+ if not to.nil?
25
+ set_to(to)
26
+ end
27
+ if not type.nil?
28
+ set_type(type)
29
+ end
30
+ end
31
+
32
+ ##
33
+ # Get the type of the Iq stanza
34
+ #
35
+ # The following values are allowed:
36
+ # * :get
37
+ # * :set
38
+ # * :result
39
+ # * :error
40
+ # result:: [Symbol] or nil
41
+ def type
42
+ case super
43
+ when 'get' then :get
44
+ when 'set' then :set
45
+ when 'result' then :result
46
+ when 'error' then :error
47
+ else nil
48
+ end
49
+ end
50
+
51
+ ##
52
+ # Set the type of the Iq stanza (see Iq#type)
53
+ # v:: [Symbol] or nil
54
+ def type=(v)
55
+ case v
56
+ when :get then super('get')
57
+ when :set then super('set')
58
+ when :result then super('result')
59
+ when :error then super('error')
60
+ else super(nil)
61
+ end
62
+ end
63
+
64
+ ##
65
+ # Set the type of the Iq stanza (chaining-friendly)
66
+ # v:: [Symbol] or nil
67
+ def set_type(v)
68
+ self.type = v
69
+ self
70
+ end
71
+
72
+ ##
73
+ # Returns the iq's query child, or nil
74
+ # result:: [IqQuery]
75
+ def query
76
+ first_element('query')
77
+ end
78
+
79
+ ##
80
+ # Delete old elements named newquery.name
81
+ #
82
+ # newquery:: [REXML::Element] will be added
83
+ def query=(newquery)
84
+ delete_elements(newquery.name)
85
+ add(newquery)
86
+ end
87
+
88
+ ##
89
+ # Returns the iq's query's namespace, or nil
90
+ # result:: [String]
91
+ def queryns
92
+ e = first_element('query')
93
+ if e
94
+ return e.namespace
95
+ else
96
+ return nil
97
+ end
98
+ end
99
+
100
+ ##
101
+ # Returns the iq's <vCard/> child, or nil
102
+ # result:: [IqVcard]
103
+ def vcard
104
+ first_element('vCard')
105
+ end
106
+
107
+ ##
108
+ # Create a new iq from a stanza,
109
+ # copies all attributes and children from xmlstanza
110
+ # xmlstanza:: [REXML::Element] Source stanza
111
+ # return:: [Iq] New stanza
112
+ def Iq.import(xmlstanza)
113
+ Iq::new.import(xmlstanza)
114
+ end
115
+
116
+ ##
117
+ # Add an element to the Iq stanza
118
+ # element:: [REXML::Element] Element to add.
119
+ # Will be automatically converted (imported) to
120
+ # a class registered with add_elementclass
121
+ def typed_add(element)
122
+ if element.kind_of?(REXML::Element) && @@element_classes.has_key?(element.name)
123
+ super(@@element_classes[element.name]::import(element))
124
+ else
125
+ super(element)
126
+ end
127
+ end
128
+
129
+ ##
130
+ # Create a new Iq stanza with an unspecified query child
131
+ # (<query/> has no namespace)
132
+ def Iq.new_query(type = nil, to = nil)
133
+ iq = Iq::new(type, to)
134
+ query = IqQuery::new
135
+ iq.add(query)
136
+ iq
137
+ end
138
+
139
+ ##
140
+ # Create a new jabber:iq:auth set Stanza.
141
+ def Iq.new_authset(jid, password)
142
+ iq = Iq::new(:set)
143
+ query = IqQuery::new
144
+ query.add_namespace('jabber:iq:auth')
145
+ query.add(REXML::Element::new('username').add_text(jid.node))
146
+ query.add(REXML::Element::new('password').add_text(password))
147
+ query.add(REXML::Element::new('resource').add_text(jid.resource)) if not jid.resource.nil?
148
+ iq.add(query)
149
+ iq
150
+ end
151
+
152
+ ##
153
+ # Create a new jabber:iq:auth set Stanza for Digest authentication
154
+ def Iq.new_authset_digest(jid, session_id, password)
155
+ iq = Iq::new(:set)
156
+ query = IqQuery::new
157
+ query.add_namespace('jabber:iq:auth')
158
+ query.add(REXML::Element::new('username').add_text(jid.node))
159
+ query.add(REXML::Element::new('digest').add_text(Digest::SHA1.new(session_id + password).hexdigest))
160
+ query.add(REXML::Element::new('resource').add_text(jid.resource)) if not jid.resource.nil?
161
+ iq.add(query)
162
+ iq
163
+ end
164
+
165
+ ##
166
+ # Create a new jabber:iq:register set stanza for service/server registration
167
+ # username:: [String] (Element will be ommited if unset)
168
+ # password:: [String] (Element will be ommited if unset)
169
+ def Iq.new_register(username=nil, password=nil)
170
+ iq = Iq::new(:set)
171
+ query = IqQuery::new
172
+ query.add_namespace('jabber:iq:register')
173
+ query.add(REXML::Element::new('username').add_text(username)) if username
174
+ query.add(REXML::Element::new('password').add_text(password)) if password
175
+ iq.add(query)
176
+ iq
177
+ end
178
+
179
+ ##
180
+ # Create a new jabber:iq:roster get Stanza.
181
+ #
182
+ # IqQueryRoster is unused here because possibly not require'd
183
+ def Iq.new_rosterget
184
+ iq = Iq::new(:get)
185
+ query = IqQuery::new
186
+ query.add_namespace('jabber:iq:roster')
187
+ iq.add(query)
188
+ iq
189
+ end
190
+
191
+ ##
192
+ # Create a new jabber:iq:roster get Stanza.
193
+ def Iq.new_browseget
194
+ iq = Iq::new(:get)
195
+ query = IqQuery::new
196
+ query.add_namespace('jabber:iq:browse')
197
+ iq.add(query)
198
+ iq
199
+ end
200
+
201
+ ##
202
+ # Create a new jabber:iq:roster set Stanza.
203
+ def Iq.new_rosterset
204
+ iq = Iq::new(:set)
205
+ query = IqQuery::new
206
+ query.add_namespace('jabber:iq:roster')
207
+ iq.add(query)
208
+ iq
209
+ end
210
+
211
+ ##
212
+ # Add a class by name.
213
+ # Elements with this name will be automatically converted
214
+ # to the specific class.
215
+ # Used for <query/>, <vCard>, <pubsub> etc.
216
+ # name:: [String] Element name
217
+ # elementclass:: [Class] Target class
218
+ def Iq.add_elementclass(name, elementclass)
219
+ @@element_classes[name] = elementclass
220
+ end
221
+ end
222
+ end
223
+
224
+ # Actually these should be included at the top,
225
+ # but then they would be unable to call Iq.add_elementclass
226
+ # because it hasn't just been defined.
227
+
228
+ require 'xmpp4r/query'
229
+ require 'xmpp4r/vcard/iq/vcard'
data/lib/xmpp4r/jid.rb ADDED
@@ -0,0 +1,167 @@
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
+ module Jabber
6
+ ##
7
+ # The JID class represents a Jabber Identifier as described by
8
+ # RFC3920 section 3.1.
9
+ #
10
+ # Note that you can use JIDs also for Sorting, Hash keys, ...
11
+ class JID
12
+ include Comparable
13
+
14
+ PATTERN = /^(?:([^@]*)@)??([^@\/]*)(?:\/(.*?))?$/
15
+
16
+ begin
17
+ require 'idn'
18
+ USE_STRINGPREP = true
19
+ rescue LoadError
20
+ USE_STRINGPREP = false
21
+ end
22
+
23
+ ##
24
+ # Create a new JID. If called as new('a@b/c'), parse the string and
25
+ # split (node, domain, resource)
26
+ def initialize(node = "", domain = nil, resource = nil)
27
+ @resource = resource
28
+ @domain = domain
29
+ @node = node
30
+ if @domain.nil? and @resource.nil? and @node
31
+ @node, @domain, @resource = @node.to_s.scan(PATTERN).first
32
+ end
33
+
34
+ if USE_STRINGPREP
35
+ @node = IDN::Stringprep.nodeprep(@node) if @node
36
+ @domain = IDN::Stringprep.nameprep(@domain) if @domain
37
+ @resource = IDN::Stringprep.resourceprep(@resource) if @resource
38
+ else
39
+ @node.downcase! if @node
40
+ @domain.downcase! if @domain
41
+ end
42
+
43
+ raise ArgumentError, 'Node too long' if (@node || '').length > 1023
44
+ raise ArgumentError, 'Domain too long' if (@domain || '').length > 1023
45
+ raise ArgumentError, 'Resource too long' if (@resource || '').length > 1023
46
+ end
47
+
48
+ ##
49
+ # Returns a string representation of the JID
50
+ # * ""
51
+ # * "domain"
52
+ # * "node@domain"
53
+ # * "domain/resource"
54
+ # * "node@domain/resource"
55
+ def to_s
56
+ s = @domain
57
+ s = "#{@node}@#{s}" if @node
58
+ s += "/#{@resource}" if @resource
59
+ return s
60
+ end
61
+
62
+ ##
63
+ # Returns a new JID with resource removed.
64
+ # return:: [JID]
65
+ def strip
66
+ JID::new(@node, @domain)
67
+ end
68
+ alias_method :bare, :strip
69
+
70
+ ##
71
+ # Removes the resource (sets it to nil)
72
+ # return:: [JID] self
73
+ def strip!
74
+ @resource = nil
75
+ self
76
+ end
77
+ alias_method :bare!, :strip!
78
+
79
+ ##
80
+ # Returns a hash value of the String representation
81
+ # (see JID#to_s)
82
+ def hash
83
+ return to_s.hash
84
+ end
85
+
86
+ ##
87
+ # Ccompare to another JID
88
+ #
89
+ # String representations are compared, see JID#to_s
90
+ def eql?(o)
91
+ to_s.eql?(o.to_s)
92
+ end
93
+
94
+ ##
95
+ # Ccompare to another JID
96
+ #
97
+ # String representations are compared, see JID#to_s
98
+ def ==(o)
99
+ to_s == o.to_s
100
+ end
101
+
102
+ ##
103
+ # Compare two JIDs,
104
+ # helpful for sorting etc.
105
+ #
106
+ # String representations are compared, see JID#to_s
107
+ def <=>(o)
108
+ to_s <=> o.to_s
109
+ end
110
+
111
+ # Get the JID's node
112
+ def node
113
+ @node
114
+ end
115
+
116
+ # Set the JID's node
117
+ def node=(v)
118
+ @node = v.to_s
119
+ if USE_STRINGPREP
120
+ @node = IDN::Stringprep.nodeprep(@node) if @node
121
+ end
122
+ end
123
+
124
+ # Get the JID's domain
125
+ def domain
126
+ return nil if @domain.empty?
127
+ @domain
128
+ end
129
+
130
+ # Set the JID's domain
131
+ def domain=(v)
132
+ @domain = v.to_s
133
+ if USE_STRINGPREP
134
+ @domain = IDN::Stringprep.nodeprep(@domain)
135
+ end
136
+ end
137
+
138
+ # Get the JID's resource
139
+ def resource
140
+ @resource
141
+ end
142
+
143
+ # Set the JID's resource
144
+ def resource=(v)
145
+ @resource = v.to_s
146
+ if USE_STRINGPREP
147
+ @resource = IDN::Stringprep.nodeprep(@resource)
148
+ end
149
+ end
150
+
151
+ # Escape JID
152
+ def JID::escape(jid)
153
+ return jid.to_s.gsub('@', '%')
154
+ end
155
+
156
+ # Test if jid is empty
157
+ def empty?
158
+ to_s.empty?
159
+ end
160
+
161
+ # Test id jid is strepped
162
+ def stripped?
163
+ @resource.nil?
164
+ end
165
+ alias_method :bared?, :stripped?
166
+ end
167
+ end
@@ -0,0 +1,171 @@
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/xmlstanza'
6
+ require 'xmpp4r/x'
7
+
8
+ module Jabber
9
+ ##
10
+ # The Message class manages the <message/> stanzas,
11
+ # which is used for all messaging communication.
12
+ class Message < XMLStanza
13
+
14
+ ##
15
+ # Create a new message
16
+ # >to:: a JID or a String object to send the message to.
17
+ # >body:: the message's body
18
+ def initialize(to = nil, body = nil)
19
+ super("message")
20
+ if not to.nil?
21
+ set_to(to)
22
+ end
23
+ if !body.nil?
24
+ add_element(REXML::Element::new("body").add_text(body))
25
+ end
26
+ end
27
+
28
+ ##
29
+ # Add a sub-element
30
+ #
31
+ # Will be converted to [X] if named "x"
32
+ # element:: [REXML::Element] to add
33
+ def typed_add(element)
34
+ if element.kind_of?(REXML::Element) && (element.name == 'x')
35
+ super(X::import(element))
36
+ else
37
+ super(element)
38
+ end
39
+ end
40
+
41
+ ##
42
+ # Get the type of the Message stanza
43
+ #
44
+ # The following Symbols are allowed:
45
+ # * :chat
46
+ # * :error
47
+ # * :groupchat
48
+ # * :headline
49
+ # * :normal
50
+ # result:: [Symbol] or nil
51
+ def type
52
+ case super
53
+ when 'chat' then :chat
54
+ when 'error' then :error
55
+ when 'groupchat' then :groupchat
56
+ when 'headline' then :headline
57
+ when 'normal' then :normal
58
+ else nil
59
+ end
60
+ end
61
+
62
+ ##
63
+ # Set the type of the Message stanza (see Message#type for details)
64
+ # v:: [Symbol] or nil
65
+ def type=(v)
66
+ case v
67
+ when :chat then super('chat')
68
+ when :error then super('error')
69
+ when :groupchat then super('groupchat')
70
+ when :headline then super('headline')
71
+ when :normal then super('normal')
72
+ else super(nil)
73
+ end
74
+ end
75
+
76
+ ##
77
+ # Set the type of the Message stanza (chaining-friendly)
78
+ # v:: [Symbol] or nil
79
+ def set_type(v)
80
+ self.type = v
81
+ self
82
+ end
83
+
84
+ ##
85
+ # Get the first <x/> element of this stanza, or nil if none found.
86
+ def x
87
+ first_element('x')
88
+ end
89
+
90
+ ##
91
+ # Returns the message's body, or nil.
92
+ # This is the message's plain-text content.
93
+ def body
94
+ first_element_text('body')
95
+ end
96
+
97
+ ##
98
+ # Create a new message from a stanza,
99
+ # by copying all attributes and children from it.
100
+ # xmlstanza:: [REXML::Element] Source
101
+ # return:: [Message] Result
102
+ def Message.import(xmlstanza)
103
+ Message::new.import(xmlstanza)
104
+ end
105
+
106
+ ##
107
+ # Sets the message's body
108
+ #
109
+ # b:: [String] body to set
110
+ def body=(b)
111
+ replace_element_text('body', b)
112
+ end
113
+
114
+ ##
115
+ # Sets the message's body
116
+ #
117
+ # b:: [String] body to set
118
+ # return:: [REXML::Element] self for chaining
119
+ def set_body(b)
120
+ self.body = b
121
+ self
122
+ end
123
+
124
+ ##
125
+ # sets the message's subject
126
+ #
127
+ # s:: [String] subject to set
128
+ def subject=(s)
129
+ replace_element_text('subject', s)
130
+ end
131
+
132
+ ##
133
+ # sets the message's subject
134
+ #
135
+ # s:: [String] subject to set
136
+ # return:: [REXML::Element] self for chaining
137
+ def set_subject(s)
138
+ self.subject = s
139
+ self
140
+ end
141
+
142
+ ##
143
+ # Returns the message's subject, or nil
144
+ def subject
145
+ first_element_text('subject')
146
+ end
147
+
148
+ ##
149
+ # sets the message's thread
150
+ # s:: [String] thread to set
151
+ def thread=(s)
152
+ delete_elements('thread')
153
+ replace_element_text('thread', s) unless s.nil?
154
+ end
155
+
156
+ ##
157
+ # gets the message's thread (chaining-friendly)
158
+ # Please note that this are not [Thread] but a [String]-Identifier to track conversations
159
+ # s:: [String] thread to set
160
+ def set_thread(s)
161
+ self.thread = s
162
+ self
163
+ end
164
+
165
+ ##
166
+ # Returns the message's thread, or nil
167
+ def thread
168
+ first_element_text('thread')
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,107 @@
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/discovery'
6
+
7
+ module Jabber
8
+ module MUC
9
+ ##
10
+ # The MUCBrowser helper can be used to discover
11
+ # Multi-User-Chat components via Service Discovery
12
+ #
13
+ # See JEP 0045 sections 6.1. and 6.2.
14
+ #
15
+ # Usage of its functions should be threaded as
16
+ # responses can take a while
17
+ class MUCBrowser
18
+ ##
19
+ # Initialize a new MUCBrowser helper
20
+ def initialize(stream)
21
+ @stream = stream
22
+ end
23
+
24
+ ##
25
+ # Retrieve the name of a MUC component,
26
+ # depending upon whether the target entity supports
27
+ # the MUC protocol.
28
+ #
29
+ # A return-value of nil does *not* mean that the entity
30
+ # does not exist or does not support Service Discovery!
31
+ # nil just means that this is not a MUC-compliant service.
32
+ #
33
+ # Throws an ErrorException when receiving
34
+ # <tt><iq type='error'/></tt>
35
+ # jid:: [JID] Target entity (set only domain!)
36
+ # return:: [String] or [nil]
37
+ def muc_name(jid)
38
+ iq = Iq.new(:get, jid)
39
+ iq.from = @stream.jid # Enable components to use this
40
+ iq.add(Discovery::IqQueryDiscoInfo.new)
41
+
42
+ res = nil
43
+
44
+ @stream.send_with_id(iq) do |answer|
45
+ if answer.type == :result
46
+ answer.query.each_element('feature') { |feature|
47
+ # Look if the component has a MUC or Groupchat feature
48
+ if feature.var == 'http://jabber.org/protocol/muc' or feature.var == 'gc-1.0'
49
+ # If so, get the identity
50
+ if answer.query.first_element('identity')
51
+ res = answer.query.first_element('identity').iname
52
+ end
53
+ end
54
+ }
55
+ true
56
+ else
57
+ false
58
+ end
59
+ end
60
+
61
+ res
62
+ end
63
+
64
+ ##
65
+ # Retrieve the existing rooms of a MUC component
66
+ #
67
+ # The resulting Hash contains pairs of room JID and room name
68
+ #
69
+ # Usage:
70
+ # my_mucbrowse_helper.muc_rooms('conference.jabber.org').each { |jid,name| ... }
71
+ #
72
+ # Throws an exception when receiving <tt><iq type='error'/></tt>
73
+ # jid:: [JID] Target entity (set only domain!)
74
+ # return:: [Hash]
75
+ def muc_rooms(jid)
76
+ iq = Iq.new(:get, jid)
77
+ iq.from = @stream.jid # Enable components to use this
78
+ iq.add(Discovery::IqQueryDiscoItems.new)
79
+
80
+ rooms = {}
81
+ err = nil
82
+
83
+ @stream.send_with_id(iq) do |answer|
84
+
85
+ if answer.type == :result
86
+ answer.query.each_element('item') { |item|
87
+ rooms[item.jid] = item.iname
88
+ }
89
+ true
90
+ elsif answer.type == :error
91
+ err = answer.error
92
+ true
93
+ else
94
+ false
95
+ end
96
+ end
97
+
98
+ if err
99
+ raise "Error getting MUC rooms: #{err.error}, #{err.text}"
100
+ end
101
+
102
+ rooms
103
+ end
104
+ end
105
+ end
106
+ end
107
+