Class: Blather::Stanza::Message
- Inherits:
-
Blather::Stanza
- Object
- Nokogiri::XML::Node
- XMPPNode
- Blather::Stanza
- Blather::Stanza::Message
- Defined in:
- lib/blather/stanza/message.rb
Overview
# Message Stanza
[RFC 3921 Section 2.1 - Message Syntax](xmpp.org/rfcs/rfc3921.html#rfc.section.2.1)
Exchanging messages is a basic use of XMPP and occurs when a user generates a message stanza that is addressed to another entity. The sender’s server is responsible for delivering the message to the intended recipient (if the recipient is on the same local server) or for routing the message to the recipient’s server (if the recipient is on a remote server). Thus a message stanza is used to “push” information to another entity.
## “To” Attribute
An instant messaging client specifies an intended recipient for a message by providing the JID of an entity other than the sender in the ‘to` attribute of the Message stanza. If the message is being sent outside the context of any existing chat session or received message, the value of the `to` address SHOULD be of the form “user@domain” rather than of the form “user@domain/resource”.
msg = Message.new '[email protected]/resource'
msg.to == '[email protected]/resource'
msg.to = '[email protected]/resource'
msg.to == '[email protected]/resource'
The ‘to` attribute on a Message stanza works like any regular ruby object attribute
## “Type” Attribute
Common uses of the message stanza in instant messaging applications include: single messages; messages sent in the context of a one-to-one chat session; messages sent in the context of a multi-user chat room; alerts, notifications, or other information to which no reply is expected; and errors. These uses are differentiated via the ‘type` attribute. If included, the `type` attribute MUST have one of the following values:
-
‘:chat` – The message is sent in the context of a one-to-one chat session. Typically a receiving client will present message of type `chat` in an interface that enables one-to-one chat between the two parties, including an appropriate conversation history.
-
‘:error` – The message is generated by an entity that experiences an error in processing a message received from another entity. A client that receives a message of type `error` SHOULD present an appropriate interface informing the sender of the nature of the error.
-
‘:groupchat` – The message is sent in the context of a multi-user chat environment (similar to that of [IRC]). Typically a receiving client will present a message of type `groupchat` in an interface that enables many-to-many chat between the parties, including a roster of parties in the chatroom and an appropriate conversation history.
-
‘:headline` – The message provides an alert, a notification, or other information to which no reply is expected (e.g., news headlines, sports updates, near-real-time market data, and syndicated content). Because no reply to the message is expected, typically a receiving client will present a message of type “headline” in an interface that appropriately differentiates the message from standalone messages, chat messages, or groupchat messages (e.g., by not providing the recipient with the ability to reply).
-
‘:normal` – The message is a standalone message that is sent outside the context of a one-to-one conversation or groupchat, and to which it is expected that the recipient will reply. Typically a receiving client will present a message of type `normal` in an interface that enables the recipient to reply, but without a conversation history. The default value of the `type` attribute is `normal`.
Blather provides a helper for each possible type:
Message#chat?
Message#error?
Message#groupchat?
Message#headline?
Message#normal?
Blather treats the ‘type` attribute like a normal ruby object attribute providing a getter and setter. The default `type` is `chat`.
msg = Message.new
msg.type # => :chat
msg.chat? # => true
msg.type = :normal
msg.normal? # => true
msg.chat? # => false
msg.type = :invalid # => RuntimeError
## “Body” Element
The ‘body` element contains human-readable XML character data that specifies the textual contents of the message; this child element is normally included but is optional.
Blather provides an attribute-like syntax for Message ‘body` elements.
msg = Message.new '[email protected]', 'message body'
msg.body # => 'message body'
msg.body = 'other message'
msg.body # => 'other message'
## “Subject” Element
The ‘subject` element contains human-readable XML character data that specifies the topic of the message.
Blather provides an attribute-like syntax for Message ‘subject` elements.
msg = Message.new '[email protected]', 'message body'
msg.subject = 'message subject'
msg.subject # => 'message subject'
## “Thread” Element
The primary use of the XMPP ‘thread` element is to uniquely identify a conversation thread or “chat session” between two entities instantiated by Message stanzas of type `chat`. However, the XMPP thread element can also be used to uniquely identify an analogous thread between two entities instantiated by Message stanzas of type `headline` or `normal`, or among multiple entities in the context of a multi-user chat room instantiated by Message stanzas of type `groupchat`. It MAY also be used for Message stanzas not related to a human conversation, such as a game session or an interaction between plugins. The `thread` element is not used to identify individual messages, only conversations or messagingg sessions. The inclusion of the `thread` element is optional.
The value of the ‘thread` element is not human-readable and MUST be treated as opaque by entities; no semantic meaning can be derived from it, and only exact comparisons can be made against it. The value of the `thread` element MUST be a universally unique identifier (UUID) as described in [UUID].
The ‘thread` element MAY possess a ’parent’ attribute that identifies another thread of which the current thread is an offshoot or child; the value of the ‘parent’ must conform to the syntax of the ‘thread` element itself.
Blather provides an attribute-like syntax for Message ‘thread` elements.
msg = Message.new
msg.thread = '12345'
msg.thread # => '12345'
Parent threads can be set using a hash:
msg.thread = {'parent-id' => 'thread-id'}
msg.thread # => 'thread-id'
msg.parent_thread # => 'parent-id'
Direct Known Subclasses
Constant Summary collapse
- VALID_TYPES =
[:chat, :error, :groupchat, :headline, :normal].freeze
- VALID_CHAT_STATES =
[:active, :composing, :gone, :inactive, :paused].freeze
- CHAT_STATE_NS =
'http://jabber.org/protocol/chatstates'.freeze
- HTML_NS =
'http://jabber.org/protocol/xhtml-im'.freeze
- HTML_BODY_NS =
'http://www.w3.org/1999/xhtml'.freeze
Constants inherited from XMPPNode
Class Method Summary collapse
- .import(node) ⇒ Object
-
.new(to = nil, body = nil, type = :chat) ⇒ Object
Create a new Message stanza.
Instance Method Summary collapse
-
#body ⇒ String
Get the message body.
-
#body=(body) ⇒ Object
Set the message body.
-
#chat? ⇒ true, false
Check if the Message is of type :chat.
-
#chat_state ⇒ Symbol
Get the message chat state.
-
#chat_state=(chat_state) ⇒ Object
Set the message chat state.
-
#error? ⇒ true, false
Check if the Message is of type :error.
-
#form ⇒ Object
Returns the message’s x:data form child.
-
#groupchat? ⇒ true, false
Check if the Message is of type :groupchat.
-
#headline? ⇒ true, false
Check if the Message is of type :headline.
-
#inherit(node) ⇒ Object
Overrides the parent method to ensure the current chat state is removed.
-
#normal? ⇒ true, false
Check if the Message is of type :normal.
-
#parent_thread ⇒ String?
Get the parent thread.
-
#subject ⇒ String
Get the message subject.
-
#subject=(subject) ⇒ Object
Set the message subject.
-
#thread ⇒ String
Get the message thread.
-
#thread=(thread) ⇒ Object
Set the thread.
-
#type=(type) ⇒ Object
Ensures type is :get, :set, :result or :error.
-
#xhtml ⇒ String
Get the message xhtml.
-
#xhtml=(xhtml_body) ⇒ Object
Set the message xhtml This will use Nokogiri to ensure the xhtml is valid.
-
#xhtml_node ⇒ XML::Node
Get the message xhtml node This will create the node if it doesn’t exist.
Methods inherited from Blather::Stanza
#as_error, #from, #from=, handler_list, #id, #id=, next_id, register, #reply, #reply!, #to, #to=, #type
Methods inherited from XMPPNode
class_from_registration, #content_from, #inherit_attrs, #inspect, #namespace=, #namespace_href, #nokogiri_namespace=, #read_attr, #read_content, register, #remove_child, #remove_children, #set_content_for, #to_stanza, #write_attr
Methods inherited from Nokogiri::XML::Node
#[]=, #attr_set, #find_first, #nokogiri_xpath, #xpath
Class Method Details
.import(node) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/blather/stanza/message.rb', line 171 def self.import(node) klass = nil node.children.detect do |e| ns = e.namespace ? e.namespace.href : nil klass = class_from_registration(e.element_name, ns) end if klass && klass != self && klass != Blather::Stanza::X klass.import(node) else new(node[:type]).inherit(node) end end |
.new(to = nil, body = nil, type = :chat) ⇒ Object
Create a new Message stanza
190 191 192 193 194 195 196 197 |
# File 'lib/blather/stanza/message.rb', line 190 def self.new(to = nil, body = nil, type = :chat) node = super :message node.to = to node.type = type node.body = body node.chat_state = :active if [:chat, :groupchat].include?(type) node end |
Instance Method Details
#body ⇒ String
Get the message body
255 256 257 |
# File 'lib/blather/stanza/message.rb', line 255 def body read_content :body end |
#body=(body) ⇒ Object
Set the message body
262 263 264 |
# File 'lib/blather/stanza/message.rb', line 262 def body=(body) set_content_for :body, body end |
#chat? ⇒ true, false
Check if the Message is of type :chat
210 211 212 |
# File 'lib/blather/stanza/message.rb', line 210 def chat? self.type == :chat end |
#chat_state ⇒ Symbol
Get the message chat state
351 352 353 354 355 |
# File 'lib/blather/stanza/message.rb', line 351 def chat_state if (elem = find_first('ns:*', :ns => CHAT_STATE_NS)) && VALID_CHAT_STATES.include?(name = elem.name.to_sym) name end end |
#chat_state=(chat_state) ⇒ Object
Set the message chat state
360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/blather/stanza/message.rb', line 360 def chat_state=(chat_state) if chat_state && !VALID_CHAT_STATES.include?(chat_state.to_sym) raise ArgumentError, "Invalid Chat State (#{chat_state}), use: #{VALID_CHAT_STATES*' '}" end xpath('ns:*', :ns => CHAT_STATE_NS).remove if chat_state state = XMPPNode.new(chat_state, self.document) state.namespace = CHAT_STATE_NS self << state end end |
#error? ⇒ true, false
Check if the Message is of type :error
217 218 219 |
# File 'lib/blather/stanza/message.rb', line 217 def error? self.type == :error end |
#form ⇒ Object
Returns the message’s x:data form child
344 345 346 |
# File 'lib/blather/stanza/message.rb', line 344 def form X.find_or_create self end |
#groupchat? ⇒ true, false
Check if the Message is of type :groupchat
224 225 226 |
# File 'lib/blather/stanza/message.rb', line 224 def groupchat? self.type == :groupchat end |
#headline? ⇒ true, false
Check if the Message is of type :headline
231 232 233 |
# File 'lib/blather/stanza/message.rb', line 231 def headline? self.type == :headline end |
#inherit(node) ⇒ Object
Overrides the parent method to ensure the current chat state is removed
202 203 204 205 |
# File 'lib/blather/stanza/message.rb', line 202 def inherit(node) xpath('ns:*', :ns => CHAT_STATE_NS).remove super end |
#normal? ⇒ true, false
Check if the Message is of type :normal
238 239 240 |
# File 'lib/blather/stanza/message.rb', line 238 def normal? self.type == :normal end |
#parent_thread ⇒ String?
Get the parent thread
324 325 326 327 |
# File 'lib/blather/stanza/message.rb', line 324 def parent_thread n = find_first('thread') n[:parent] if n end |
#subject ⇒ String
Get the message subject
303 304 305 |
# File 'lib/blather/stanza/message.rb', line 303 def subject read_content :subject end |
#subject=(subject) ⇒ Object
Set the message subject
310 311 312 |
# File 'lib/blather/stanza/message.rb', line 310 def subject=(subject) set_content_for :subject, subject end |
#thread ⇒ String
Get the message thread
317 318 319 |
# File 'lib/blather/stanza/message.rb', line 317 def thread read_content :thread end |
#thread=(hash) ⇒ Object #thread=(thread) ⇒ Object
Set the thread
337 338 339 340 341 |
# File 'lib/blather/stanza/message.rb', line 337 def thread=(thread) parent, thread = thread.to_a.flatten if thread.is_a?(Hash) set_content_for :thread, thread find_first('thread')[:parent] = parent end |
#type=(type) ⇒ Object
Ensures type is :get, :set, :result or :error
245 246 247 248 249 250 |
# File 'lib/blather/stanza/message.rb', line 245 def type=(type) if type && !VALID_TYPES.include?(type.to_sym) raise ArgumentError, "Invalid Type (#{type}), use: #{VALID_TYPES*' '}" end super end |
#xhtml ⇒ String
Get the message xhtml
288 289 290 |
# File 'lib/blather/stanza/message.rb', line 288 def xhtml self.xhtml_node.inner_html.strip end |
#xhtml=(xhtml_body) ⇒ Object
Set the message xhtml This will use Nokogiri to ensure the xhtml is valid
296 297 298 |
# File 'lib/blather/stanza/message.rb', line 296 def xhtml=(xhtml_body) self.xhtml_node.inner_html = Nokogiri::XML::DocumentFragment.parse(xhtml_body) end |
#xhtml_node ⇒ XML::Node
Get the message xhtml node This will create the node if it doesn’t exist
270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/blather/stanza/message.rb', line 270 def xhtml_node unless h = find_first('ns:html', :ns => HTML_NS) self << (h = XMPPNode.new('html', self.document)) h.namespace = HTML_NS end unless b = h.find_first('ns:body', :ns => HTML_BODY_NS) b = XMPPNode.new('body', self.document) b.namespace = HTML_BODY_NS h << b end b end |