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,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
+