text: /*
   * libjingle
   * Copyright 2004--2005, Google Inc.
   *
   * Redistribution and use in source and binary forms, with or without 
   * modification, are permitted provided that the following conditions are met:
   *
   *  1. Redistributions of source code must retain the above copyright notice, 
   *     this list of conditions and the following disclaimer.
   *  2. Redistributions in binary form must reproduce the above copyright notice,
   *     this list of conditions and the following disclaimer in the documentation
   *     and/or other materials provided with the distribution.
   *  3. The name of the author may not be used to endorse or promote products 
   *     derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
   * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  #ifndef _xmppengine_h_
  #define _xmppengine_h_
  
  // also part of the API
  #include "talk/xmpp/jid.h"
  #include "talk/xmllite/qname.h"
  #include "talk/xmllite/xmlelement.h"
  
  
  namespace buzz {
  
  class XmppEngine;
  class SaslHandler;
  typedef void * XmppIqCookie;
  
  //! XMPP stanza error codes.
  //! Used in XmppEngine.SendStanzaError().
  enum XmppStanzaError {
    XSE_BAD_REQUEST,
    XSE_CONFLICT,
    XSE_FEATURE_NOT_IMPLEMENTED,
    XSE_FORBIDDEN,
    XSE_GONE,
    XSE_INTERNAL_SERVER_ERROR,
    XSE_ITEM_NOT_FOUND,
    XSE_JID_MALFORMED,
    XSE_NOT_ACCEPTABLE,
    XSE_NOT_ALLOWED,
    XSE_PAYMENT_REQUIRED,
    XSE_RECIPIENT_UNAVAILABLE,
    XSE_REDIRECT,
    XSE_REGISTRATION_REQUIRED,
    XSE_SERVER_NOT_FOUND,
    XSE_SERVER_TIMEOUT,
    XSE_RESOURCE_CONSTRAINT,
    XSE_SERVICE_UNAVAILABLE,
    XSE_SUBSCRIPTION_REQUIRED,
    XSE_UNDEFINED_CONDITION,
    XSE_UNEXPECTED_REQUEST,
  };
  
  // XmppReturnStatus
  //    This is used by API functions to synchronously return status.
  enum XmppReturnStatus {
    XMPP_RETURN_OK,
    XMPP_RETURN_BADARGUMENT,
    XMPP_RETURN_BADSTATE,
    XMPP_RETURN_PENDING,
    XMPP_RETURN_UNEXPECTED,
    XMPP_RETURN_NOTYETIMPLEMENTED,
  };
  
  //! Callback for socket output for an XmppEngine connection.
  //! Register via XmppEngine.SetOutputHandler.  An XmppEngine
  //! can call back to this handler while it is processing
  //! Connect, SendStanza, SendIq, Disconnect, or HandleInput.
  class XmppOutputHandler {
  public:
    virtual ~XmppOutputHandler() {}
  
    //! Deliver the specified bytes to the XMPP socket.
    virtual void WriteOutput(const char * bytes, size_t len) = 0;
  
    //! Initiate TLS encryption on the socket.
    //! The implementation must verify that the SSL
    //! certificate matches the given domainname.
    virtual void StartTls(const std::string & domainname) = 0;
  
    //! Called when engine wants the connecton closed.
    virtual void CloseConnection() = 0;
  };
  
  //! Callback to deliver engine state change notifications
  //! to the object managing the engine.
  class XmppSessionHandler {
  public:
    virtual ~XmppSessionHandler() {}
    //! Called when engine changes state. Argument is new state.
    virtual void OnStateChange(int state) = 0;
  };
  
  //! Callback to deliver stanzas to an Xmpp application module.
  //! Register via XmppEngine.SetDefaultSessionHandler or via
  //! XmppEngine.AddSessionHAndler.  
  class XmppStanzaHandler {
  public:
    virtual ~XmppStanzaHandler() {}
    //! Process the given stanza.
    //! The handler must return true if it has handled the stanza.
    //! A false return value causes the stanza to be passed on to
    //! the next registered handler.
    virtual bool HandleStanza(const XmlElement * stanza) = 0;
  };
  
  //! Callback to deliver iq responses (results and errors).
  //! Register while sending an iq via XmppEngine.SendIq.
  //! Iq responses are routed to matching XmppIqHandlers in preference
  //! to sending to any registered SessionHandlers.
  class XmppIqHandler {
  public:
    virtual ~XmppIqHandler() {}
    //! Called to handle the iq response.
    //! The response may be either a result or an error, and will have
    //! an 'id' that matches the request and a 'from' that matches the
    //! 'to' of the request.  Called no more than once; once this is
    //! called, the handler is automatically unregistered.
    virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0;
  };
  
  //! The XMPP connection engine.
  //! This engine implements the client side of the 'core' XMPP protocol.
  //! To use it, register an XmppOutputHandler to handle socket output
  //! and pass socket input to HandleInput.  Then application code can
  //! set up the connection with a user, password, and other settings,
  //! and then call Connect() to initiate the connection.
  //! An application can listen for events and receive stanzas by
  //! registering an XmppStanzaHandler via AddStanzaHandler().
  class XmppEngine {
  public:
    static XmppEngine * Create();
    virtual ~XmppEngine() {}
  
    //! Error codes. See GetError().
    enum Error {
      ERROR_NONE = 0,         //!< No error
      ERROR_XML,              //!< Malformed XML or encoding error
      ERROR_STREAM,           //!< XMPP stream error - see GetStreamError()
      ERROR_VERSION,          //!< XMPP version error
      ERROR_UNAUTHORIZED,     //!< User is not authorized (rejected credentials)
      ERROR_TLS,              //!< TLS could not be negotiated
      ERROR_AUTH,             //!< Authentication could not be negotiated
      ERROR_BIND,             //!< Resource or session binding could not be negotiated
      ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler.
      ERROR_DOCUMENT_CLOSED,  //!< Closed by </stream:stream>
      ERROR_SOCKET,           //!< Socket error
      ERROR_NETWORK_TIMEOUT,  //!< Some sort of timeout (eg., we never got the roster)
      ERROR_MISSING_USERNAME  //!< User has a Google Account but no nickname
    };
  
    //! States.  See GetState().
    enum State {
      STATE_NONE = 0,        //!< Nonexistent state
      STATE_START,           //!< Initial state.
      STATE_OPENING,         //!< Exchanging stream headers, authenticating and so on.
      STATE_OPEN,            //!< Authenticated and bound.
      STATE_CLOSED,          //!< Session closed, possibly due to error.
    };
  
    // SOCKET INPUT AND OUTPUT ------------------------------------------------
  
    //! Registers the handler for socket output
    virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
  
    //! Provides socket input to the engine
    virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0;
  
    //! Advises the engine that the socket has closed
    virtual XmppReturnStatus ConnectionClosed(int subcode) = 0;
  
    // SESSION SETUP ---------------------------------------------------------
  
    //! Indicates the (bare) JID for the user to use.
    virtual XmppReturnStatus SetUser(const Jid & jid)= 0;
  
    //! Get the login (bare) JID.
    virtual const Jid & GetUser() = 0;
  
    //! Provides different methods for credentials for login.
    //! Takes ownership of this object; deletes when login is done
    virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0;
  
    //! Sets whether TLS will be used within the connection (default true).
    virtual XmppReturnStatus SetUseTls(bool useTls) = 0;
  
    //! Sets an alternate domain from which we allows TLS certificates.
    //! This is for use in the case where a we want to allow a proxy to
    //! serve up its own certificate rather than one owned by the underlying
    //! domain.
    virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname, 
                                          const std::string & proxy_domain) = 0;
  
    //! Gets whether TLS will be used within the connection.
    virtual bool GetUseTls() = 0;
  
    //! Sets the request resource name, if any (optional).
    //! Note that the resource name may be overridden by the server; after
    //! binding, the actual resource name is available as part of FullJid().
    virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0;
  
    //! Gets the request resource name.
    virtual const std::string & GetRequestedResource() = 0;
  
    //! Sets language
    virtual void SetLanguage(const std::string & lang) = 0;
  
    // SESSION MANAGEMENT ---------------------------------------------------
  
    //! Set callback for state changes.
    virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0;
  
    //! Initiates the XMPP connection.
    //! After supplying connection settings, call this once to initiate,
    //! (optionally) encrypt, authenticate, and bind the connection.
    virtual XmppReturnStatus Connect() = 0;
  
    //! The current engine state.
    virtual State GetState() = 0;
  
    //! Returns true if the connection is encrypted (under TLS)
    virtual bool IsEncrypted() = 0;
  
    //! The error code.
    //! Consult this after XmppOutputHandler.OnClose().
    virtual Error GetError(int *subcode) = 0;
  
    //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
    //! Notice the stanza returned is owned by the XmppEngine and
    //! is deleted when the engine is destroyed.
    virtual const XmlElement * GetStreamError() = 0;
  
    //! Closes down the connection.
    //! Sends CloseConnection to output, and disconnects and registered
    //! session handlers.  After Disconnect completes, it is guaranteed
    //! that no further callbacks will be made.
    virtual XmppReturnStatus Disconnect() = 0;
  
    // APPLICATION USE -------------------------------------------------------
  
    enum HandlerLevel {
      HL_NONE = 0,
      HL_PEEK,   //!< Sees messages before all other processing; cannot abort
      HL_SINGLE, //!< Watches for a single message, e.g., by id and sender
      HL_SENDER, //!< Watches for a type of message from a specific sender
      HL_TYPE,   //!< Watches a type of message, e.g., all groupchat msgs
      HL_ALL,    //!< Watches all messages - gets last shot
      HL_COUNT,  //!< Count of handler levels
    };
  
    //! Adds a listener for session events.
    //! Stanza delivery is chained to session handlers; the first to
    //! return 'true' is the last to get each stanza.
    virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
  
    //! Removes a listener for session events.
    virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
  
    //! Sends a stanza to the server.
    virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0;
  
    //! Sends raw text to the server
    virtual XmppReturnStatus SendRaw(const std::string & text) = 0;
  
    //! Sends an iq to the server, and registers a callback for the result.
    //! Returns the cookie passed to the result handler.
    virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
                                    XmppIqHandler* iq_handler,
                                    XmppIqCookie* cookie) = 0;
  
    //! Unregisters an iq callback handler given its cookie.
    //! No callback will come to this handler after it's unregistered.
    virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
                                        XmppIqHandler** iq_handler) = 0;
  
  
    //! Forms and sends an error in response to the given stanza.
    //! Swaps to and from, sets type to "error", and adds error information
    //! based on the passed code.  Text is optional and may be STR_EMPTY.
    virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
                                             XmppStanzaError code,
                                             const std::string & text) = 0;
  
    //! The fullly bound JID.
    //! This JID is only valid after binding has succeeded.  If the value
    //! is JID_NULL, the binding has not succeeded.
    virtual const Jid & FullJid() = 0;
  
    //! The next unused iq id for this connection.
    //! Call this when building iq stanzas, to ensure that each iq
    //! gets its own unique id.
    virtual std::string NextId() = 0;
  
  };
  
  }
  
  
  // Move these to a better location
  
  #define XMPP_FAILED(x)                      \
    ( (x) == buzz::XMPP_RETURN_OK ? false : true)   \
  
  
  #define XMPP_SUCCEEDED(x)                   \
    ( (x) == buzz::XMPP_RETURN_OK ? true : false)   \
  
  #define IFR(x)                        \
    do {                                \
      xmpp_status = (x);                \
      if (XMPP_FAILED(xmpp_status)) {   \
        return xmpp_status;             \
      }                                 \
    } while (false)                     \
  
  
  #define IFC(x)                        \
    do {                                \
      xmpp_status = (x);                \
      if (XMPP_FAILED(xmpp_status)) {   \
        goto Cleanup;                   \
      }                                 \
    } while (false)                     \
  
  
  #endif
  