# =XMPP4R - XMPP Library for Ruby # License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option. # Website::http://home.gna.org/xmpp4r/ module Jabber # CUSTOM ERROR CLASSES # All of our custom errors are superclassed by JabberError < StandardError class JabberError < StandardError; end # A client-side only argument error class ArgumentError < JabberError; end # Server disconnected us class ServerDisconnected < JabberError; end ## # An error returned from the server # # e.g. This exception can be raised by helpers when they # receive a server reply with type='error' # # The ServerError carries a Jabber::ErrorResponse element # class ServerError < JabberError #:nodoc: ## # The error element which caused this exception attr_reader :error ## # Initialize a ServerError by passing an ErrorResponse instance # error:: [Error] def initialize(error) @error = error end ## # Sample output: # 'subscription-required: Please subscribe first' def to_s "#{@error.error}: #{@error.text}" end end class ClientAuthenticationFailure < JabberError; end class ComponentAuthenticationFailure < JabberError; end class NoNameXmlnsRegistered < JabberError def initialize(klass) super "Class #{klass} has not set name and xmlns" end end class SOCKS5Error < JabberError; end class InvalidChatState < JabberError; end ## # A class used to build/parse elements. # Look at XEP-0086 for explanation: # http://www.xmpp.org/extensions/xep-0086.html # # FIXME : XEP-0086 is officially deprecated. What effect does that have on this class? Any? # class ErrorResponse < XMPPElement name_xmlns 'error' ## # errorcondition:: [nil] or [String] of the following: # * "bad-request" # * "conflict" # * "feature-not-implemented" # * "forbidden" # * "gone" # * "internal-server-error" # * "item-not-found" # * "jid-malformed" # * "not-acceptable" # * "not-allowed" # * "not-authorized" # * "payment-required" # * "recipient-unavailable" # * "redirect" # * "registration-required" # * "remote-server-not-found" # * "remote-server-timeout" # * "resource-constraint" # * "service-unavailable" # * "subscription-required" # * "undefined-condition" # * "unexpected-request" # Will raise an [Exception] if not [nil] and none of the above # # Also sets type and code to appropriate values according to errorcondition # # text: [nil] or [String] ErrorResponse text def initialize(errorcondition=nil, text=nil) if errorcondition.nil? super() set_text(text) unless text.nil? else errortype = nil errorcode = nil @@Errors.each { |cond,type,code| if errorcondition == cond errortype = type errorcode = code end } if errortype.nil? || errorcode.nil? raise ArgumentError, "Unknown error condition when initializing ErrorReponse" end super() set_error(errorcondition) set_type(errortype) set_code(errorcode) set_text(text) unless text.nil? end end ## # Get the 'Legacy error code' or nil # result:: [Integer] Error code def code if attributes['code'] attributes['code'].to_i else nil end end ## # Set the 'Legacy error code' or nil # i:: [Integer] Error code def code=(i) if i.nil? attributes['code'] = nil else attributes['code'] = i.to_s end end ## # Set the 'Legacy error code' (chaining-friendly) def set_code(i) self.code = i self end ## # Get the 'XMPP error condition' # # This can be anything that possess the specific namespace, # checks don't apply here def error name = nil each_element { |e| name = e.name if (e.namespace == 'urn:ietf:params:xml:ns:xmpp-stanzas') && (e.name != 'text') } name end ## # Set the 'XMPP error condition' # # One previous element with that namespace will be deleted before # # s:: [String] Name of the element to be added, # namespace will be added automatically, checks don't apply here def error=(s) xe = nil each_element { |e| xe = e if (e.namespace == 'urn:ietf:params:xml:ns:xmpp-stanzas') && (e.name != 'text') } unless xe.nil? delete_element(xe) end add_element(s).add_namespace('urn:ietf:params:xml:ns:xmpp-stanzas') end ## # Set the 'XMPP error condition' (chaining-friendly) def set_error(s) self.error = s self end ## # Get the errors element text # result:: [String] or nil def text first_element_text('text') || super end ## # Set the errors element text # (Previous elements will be deleted first) # s:: [String] content or [nil] if no element def text=(s) delete_elements('text') unless s.nil? e = add_element('text') e.add_namespace('urn:ietf:params:xml:ns:xmpp-stanzas') e.text = s end end ## # Set the errors element text (chaining-friendly) def set_text(s) self.text = s self end ## # Get the type of error # (meaning how to proceed) # result:: [Symbol] or [nil] as following: # * :auth # * :cancel # * :continue # * :modify # * :wait def type case attributes['type'] when 'auth' then :auth when 'cancel' then :cancel when 'continue' then :continue when 'modify' then :modify when 'wait' then :wait else nil end end ## # Set the type of error (see ErrorResponse#type) def type=(t) case t when :auth then attributes['type'] = 'auth' when :cancel then attributes['type'] = 'cancel' when :continue then attributes['type'] = 'continue' when :modify then attributes['type'] = 'modify' when :wait then attributes['type'] = 'wait' else attributes['type'] = nil end end ## # Set the type of error (chaining-friendly) def set_type(t) self.type = t self end ## # Possible XMPP error conditions, types and codes (XEP-0086) @@Errors = [['bad-request', :modify, 400], ['conflict', :cancel, 409], ['feature-not-implemented', :cancel, 501], ['forbidden', :auth, 403], ['gone', :modify, 302], ['internal-server-error', :wait, 500], ['item-not-found', :cancel, 404], ['jid-malformed', :modify, 400], ['not-acceptable', :modify, 406], ['not-allowed', :cancel, 405], ['not-authorized', :auth, 401], ['payment-required', :auth, 402], ['recipient-unavailable', :wait, 404], ['redirect', :modify, 302], ['registration-required', :auth, 407], ['remote-server-not-found', :cancel, 404], ['remote-server-timeout', :wait, 504], ['resource-constraint', :wait, 500], ['service-unavailable', :cancel, 503], ['subscription-required', :auth, 407], ['undefined-condition', nil, 500], ['unexpected-request', :wait, 400]] end end