/***********************************************************************
 * 
 *  Copyright (C) 2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 *  Author: Juan Carlos Luciani <jluciani@novell.com>
 *
 ***********************************************************************/


//===[ Include files ]=====================================================

#include "internal.h"

//===[ Type definitions ]==================================================

//
// Parse states
//
#define AWAITING_ROOT_ELEMENT_START             0x0
#define AWAITING_ROOT_ELEMENT_END               0x1
#define AWAITING_STATUS_ELEMENT_START           0x2
#define AWAITING_STATUS_ELEMENT_END             0x3
#define AWAITING_STATUS_DATA                    0x4
#define AWAITING_DESCRIPTION_ELEMENT_START      0x5
#define AWAITING_DESCRIPTION_ELEMENT_END        0x6
#define AWAITING_DESCRIPTION_DATA               0x7
#define AWAITING_LIFETIME_DATA                  0x8
#define AWAITING_LIFETIME_ELEMENT_START         0x9
#define AWAITING_LIFETIME_ELEMENT_END           0xA
#define AWAITING_AUTH_TOKEN_ELEMENT_START       0xB
#define AWAITING_AUTH_TOKEN_ELEMENT_END         0xC
#define AWAITING_AUTH_TOKEN_DATA                0xD
#define DONE_PARSING                            0xE

//
// Get Authentication Token Response Parse Structure
//
typedef struct _GetAuthTokenRespParse
{
   XML_Parser           p;
   int                  state;
   size_t               elementDataProcessed;
   char                 *pStatusData;
   size_t               statusDataLen;
   char                 *pLifetimeData;
   size_t               lifetimeDataLen;
   GetAuthTokenResp     *pGetAuthTokenResp;
   CasaStatus           status;

} GetAuthTokenRespParse, *PGetAuthTokenRespParse;


//===[ Function prototypes ]===============================================

//===[ Global variables ]==================================================

//++=======================================================================
char*
BuildGetAuthTokenMsg(
   IN    const char *pServiceName,
   IN    const char *pHostName,
   IN    char *pSessionToken)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   char     *pMsg = NULL;
   size_t   bufferSize;

   DbgTrace(1, "-BuildGetAuthTokenMsg- Start\n", 0);

   /*
   * The format of the get authentication token request message
   * is as follows:
   * 
   * <?xml version="1.0" encoding="ISO-8859-1"?>
   * <get_auth_token_req>
   * <service>service name</service>
   * <host>host name</host>
   * <session_token>session token data</session_token>
   * </get_auth_token_req>
   *
   */

   // Determine the buffer size necessary to hold the msg
   bufferSize = strlen(XML_DECLARATION)
                + 2  // crlf
                + 1  // <
                + strlen(GET_AUTH_TOKEN_REQUEST_ELEMENT_NAME)
                + 3  // >crlf
                + 1  // <
                + strlen(SERVICE_ELEMENT_NAME)
                + 1  // >
                + strlen(pServiceName)
                + 2  // </
                + strlen(SERVICE_ELEMENT_NAME)
                + 3  // >crlf
                + 1  // <
                + strlen(HOST_ELEMENT_NAME)
                + 1  // >
                + strlen(pHostName)
                + 2  // </
                + strlen(HOST_ELEMENT_NAME)
                + 3  // >crlf
                + 1  // <
                + strlen(SESSION_TOKEN_ELEMENT_NAME)
                + 1  // >
                + strlen(pSessionToken)
                + 2  // </
                + strlen(SESSION_TOKEN_ELEMENT_NAME)
                + 3  // >crlf
                + 2  // </
                + strlen(GET_AUTH_TOKEN_REQUEST_ELEMENT_NAME)
                + 2; // >null

   // Allocate the msg buffer
   pMsg = (char*) malloc(bufferSize);
   if (pMsg)
   {
      // Now build the message
      memset(pMsg, 0, bufferSize);
      strcat(pMsg, XML_DECLARATION);
      strcat(pMsg, "\r\n");
      strcat(pMsg, "<");
      strcat(pMsg, GET_AUTH_TOKEN_REQUEST_ELEMENT_NAME);
      strcat(pMsg, ">\r\n");
      strcat(pMsg, "<");
      strcat(pMsg, SERVICE_ELEMENT_NAME);
      strcat(pMsg, ">");
      strcat(pMsg, pServiceName);
      strcat(pMsg, "</");
      strcat(pMsg, SERVICE_ELEMENT_NAME);
      strcat(pMsg, ">\r\n");
      strcat(pMsg, "<");
      strcat(pMsg, HOST_ELEMENT_NAME);
      strcat(pMsg, ">");
      strcat(pMsg, pHostName);
      strcat(pMsg, "</");
      strcat(pMsg, HOST_ELEMENT_NAME);
      strcat(pMsg, ">\r\n");
      strcat(pMsg, "<");
      strcat(pMsg, SESSION_TOKEN_ELEMENT_NAME);
      strcat(pMsg, ">");
      strcat(pMsg, pSessionToken);
      strcat(pMsg, "</");
      strcat(pMsg, SESSION_TOKEN_ELEMENT_NAME);
      strcat(pMsg, ">\r\n");
      strcat(pMsg, "</");
      strcat(pMsg, GET_AUTH_TOKEN_REQUEST_ELEMENT_NAME);
      strcat(pMsg, ">");
   }
   else
   {
      DbgTrace(0, "-BuildGetAuthTokenMsg- Buffer allocation error\n", 0);
   }

   DbgTrace(1, "-BuildGetAuthTokenMsg- End, pMsg = 0x%X\n", pMsg);

   return pMsg;
}


//++=======================================================================
static
void XMLCALL
GetAuthTokenRespStartElementHandler(
   IN    GetAuthTokenRespParse *pGetAuthTokenRespParse,
   IN    const XML_Char *name,
   IN    const XML_Char **atts)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   DbgTrace(2, "-GetAuthTokenRespStartElementHandler- Start\n", 0);

   // Proceed based on the state
   switch (pGetAuthTokenRespParse->state)
   {
      case AWAITING_ROOT_ELEMENT_START:

         // In this state, we are only expecting the Get Authentication
         // Token Response Element.
         if (strcmp(name, GET_AUTH_TOKEN_RESPONSE_ELEMENT_NAME) == 0)
         {
            // Good, advance to the next state.
            pGetAuthTokenRespParse->state = AWAITING_STATUS_ELEMENT_START;
         }
         else
         {
            DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected element\n", 0);
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;

      case AWAITING_STATUS_ELEMENT_START:
   
         // In this state, we are only expecting the Status Element.
         if (strcmp(name, STATUS_ELEMENT_NAME) == 0)
         {
            // Good, advance to the next state.
            pGetAuthTokenRespParse->state = AWAITING_DESCRIPTION_ELEMENT_START;
         }
         else
         {
            DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected element\n", 0);
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;

      case AWAITING_DESCRIPTION_ELEMENT_START:
   
         // In this state, we are only expecting the Description Element.
         if (strcmp(name, DESCRIPTION_ELEMENT_NAME) == 0)
         {
            // Good, advance to the next state.
            pGetAuthTokenRespParse->state = AWAITING_DESCRIPTION_DATA;
         }
         else
         {
            DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected element\n", 0);
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;

      case AWAITING_AUTH_TOKEN_ELEMENT_START:
   
         // In this state, we are only expecting the Authentication Token Element.
         if (strcmp(name, AUTH_TOKEN_ELEMENT_NAME) == 0)
         {
            // Good, advance to the next state.
            pGetAuthTokenRespParse->state = AWAITING_LIFETIME_ELEMENT_START;
         }
         else
         {
            DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected element\n", 0);
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;
   
      case AWAITING_LIFETIME_ELEMENT_START:
   
         // In this state, we are only expecting the Lifetime Element.
         if (strcmp(name, LIFETIME_ELEMENT_NAME) == 0)
         {
            // Good, advance to the next state.
            pGetAuthTokenRespParse->state = AWAITING_LIFETIME_DATA;
         }
         else
         {
            DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected element\n", 0);
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;

      default:
         DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected state = %d\n", pGetAuthTokenRespParse->state);
         XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         break;
   }

   DbgTrace(2, "-GetAuthTokenRespStartElementHandler- End\n", 0);
}


//++=======================================================================
static
CasaStatus
ConsumeElementData(
   IN    GetAuthTokenRespParse *pGetAuthTokenRespParse,
   IN    const XML_Char *s,
   IN    int len,
   INOUT char **ppElementData,
   INOUT size_t *pElementDataLen)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   CasaStatus  retStatus = CASA_STATUS_SUCCESS;

   DbgTrace(3, "-ConsumeElementData- Start\n", 0);

   // Proceed based on whether or not we have already consumed data
   // for this element.
   if (*ppElementData == NULL)
   {
      // We have not yet consumed data for this element
      pGetAuthTokenRespParse->elementDataProcessed = len;

      // Allocate a buffer to hold this element data (null terminated).
      *ppElementData = (char*) malloc(len + 1);
      if (*ppElementData)
      {
         memset(*ppElementData, 0, len + 1);
         memcpy(*ppElementData, s, len);

         // Return the length of the element data buffer
         *pElementDataLen = pGetAuthTokenRespParse->elementDataProcessed + 1;
      }
      else
      {
         DbgTrace(0, "-ConsumeElementData- Buffer allocation failure\n", 0);
         retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                     CASA_FACILITY_AUTHTOKEN,
                                     CASA_STATUS_INSUFFICIENT_RESOURCES);
      }
   }
   else
   {
      char  *pNewBuf;

      // We have already received token data, append this data to it.
      pNewBuf = (char*) malloc((size_t)(pGetAuthTokenRespParse->elementDataProcessed + len + 1));
      if (pNewBuf)
      {
         memset(pNewBuf,
                0,
                pGetAuthTokenRespParse->elementDataProcessed + len + 1);
         memcpy(pNewBuf,
                *ppElementData,
                pGetAuthTokenRespParse->elementDataProcessed);
         memcpy(pNewBuf + pGetAuthTokenRespParse->elementDataProcessed, s, len);
         pGetAuthTokenRespParse->elementDataProcessed += len;

         // Swap the buffers after clearing and freeing the original
         // buffer since it may contain sensitive information.
         memset(*ppElementData, 0, pGetAuthTokenRespParse->elementDataProcessed - len);
         *ppElementData = pNewBuf;

         // Return the length of the element data buffer
         *pElementDataLen = pGetAuthTokenRespParse->elementDataProcessed + 1;
      }
      else
      {
         DbgTrace(0, "-ConsumeElementData- Buffer allocation failure\n", 0);
         retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                     CASA_FACILITY_AUTHTOKEN,
                                     CASA_STATUS_INSUFFICIENT_RESOURCES);
      }
   }

   DbgTrace(3, "-ConsumeElementData- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
static
void XMLCALL
GetAuthTokenRespCharDataHandler(
   IN    GetAuthTokenRespParse *pGetAuthTokenRespParse,
   IN    const XML_Char *s,
   IN    int len)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   CasaStatus  status;

   DbgTrace(2, "-GetAuthTokenRespCharDataHandler- Start\n", 0);

   // Just exit if being called to process white space
   if (*s == '\n' || *s == '\r' || *s == '\t' || *s == ' ')
   {
      goto exit;
   }

   // Proceed based on the state
   switch (pGetAuthTokenRespParse->state)
   {
      case AWAITING_DESCRIPTION_DATA:
      case AWAITING_DESCRIPTION_ELEMENT_END:

         // Ignore the status description data for now.
         // tbd

         // Advanced to the next state
         pGetAuthTokenRespParse->state = AWAITING_DESCRIPTION_ELEMENT_END;
         break;

      case AWAITING_STATUS_DATA:
      case AWAITING_STATUS_ELEMENT_END:

         // Consume the data
         status = ConsumeElementData(pGetAuthTokenRespParse,
                                     s,
                                     len,
                                     &pGetAuthTokenRespParse->pStatusData,
                                     &pGetAuthTokenRespParse->statusDataLen);
         if (CASA_SUCCESS(status))
         {
            // Advanced to the next state
            pGetAuthTokenRespParse->state = AWAITING_STATUS_ELEMENT_END;
         }
         else
         {
            pGetAuthTokenRespParse->status = status;
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;

      case AWAITING_LIFETIME_DATA:
      case AWAITING_LIFETIME_ELEMENT_END:

         // Consume the data
         status = ConsumeElementData(pGetAuthTokenRespParse,
                                     s,
                                     len,
                                     &pGetAuthTokenRespParse->pLifetimeData,
                                     &pGetAuthTokenRespParse->lifetimeDataLen);
         if (CASA_SUCCESS(status))
         {
            // Advanced to the next state
            pGetAuthTokenRespParse->state = AWAITING_LIFETIME_ELEMENT_END;
         }
         else
         {
            pGetAuthTokenRespParse->status = status;
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;

      case AWAITING_AUTH_TOKEN_DATA:
      case AWAITING_AUTH_TOKEN_ELEMENT_END:

         // Consume the data
         status = ConsumeElementData(pGetAuthTokenRespParse,
                                     s,
                                     len,
                                     &pGetAuthTokenRespParse->pGetAuthTokenResp->pToken,
                                     &pGetAuthTokenRespParse->pGetAuthTokenResp->tokenLen);
         if (CASA_SUCCESS(status))
         {
            // Advanced to the next state
            pGetAuthTokenRespParse->state = AWAITING_AUTH_TOKEN_ELEMENT_END;
         }
         else
         {
            pGetAuthTokenRespParse->status = status;
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;

      default:
         DbgTrace(0, "-GetAuthTokenRespCharDataHandler- Un-expected state = %d\n", pGetAuthTokenRespParse->state);
         XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         break;
   }

exit:

   DbgTrace(2, "-GetAuthTokenRespCharDataHandler- End\n", 0);
}


//++=======================================================================
static
void XMLCALL
GetAuthTokenRespEndElementHandler(
   IN    GetAuthTokenRespParse *pGetAuthTokenRespParse,
   IN    const XML_Char *name)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   DbgTrace(2, "-GetAuthTokenRespEndElementHandler- Start\n", 0);

   // Proceed based on the state
   switch (pGetAuthTokenRespParse->state)
   {
      case AWAITING_ROOT_ELEMENT_END:

         // In this state, we are only expecting the Get Authentication
         // Token Response Element.
         if (strcmp(name, GET_AUTH_TOKEN_RESPONSE_ELEMENT_NAME) == 0)
         {
            // Done.
            pGetAuthTokenRespParse->state = DONE_PARSING;
         }
         else
         {
            DbgTrace(0, "-GetAuthTokenRespEndHandler- Un-expected element\n", 0);
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;

      case AWAITING_DESCRIPTION_ELEMENT_END:
   
         // In this state, we are only expecting the Description Element.
         if (strcmp(name, DESCRIPTION_ELEMENT_NAME) == 0)
         {
            // Good, advance to the next state.
            pGetAuthTokenRespParse->state = AWAITING_STATUS_DATA;
         }
         else
         {
            DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected element\n", 0);
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;

      case AWAITING_STATUS_ELEMENT_END:
   
         // In this state, we are only expecting the Status Element.
         if (strcmp(name, STATUS_ELEMENT_NAME) == 0)
         {
            // Set the appropriate status in the GetAuthTokenResp based on the returned status data
            if (strncmp(HTTP_OK_STATUS_CODE,
                        pGetAuthTokenRespParse->pStatusData,
                        pGetAuthTokenRespParse->statusDataLen) == 0)
            {
               pGetAuthTokenRespParse->status = CASA_STATUS_SUCCESS;
            }
            else if (strncmp(HTTP_UNAUTHORIZED_STATUS_CODE,
                             pGetAuthTokenRespParse->pStatusData,
                             pGetAuthTokenRespParse->statusDataLen) == 0)
            {
               pGetAuthTokenRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                                                CASA_FACILITY_AUTHTOKEN,
                                                                CASA_STATUS_AUTHENTICATION_FAILURE);
            }
            else if (strncmp(HTTP_SERVER_ERROR_STATUS_CODE,
                             pGetAuthTokenRespParse->pStatusData,
                             pGetAuthTokenRespParse->statusDataLen) == 0)
            {
               pGetAuthTokenRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                                                CASA_FACILITY_AUTHTOKEN,
                                                                CASA_STATUS_SERVER_ERROR);
            }
            else
            {
               DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected status\n", 0);
               pGetAuthTokenRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                                                CASA_FACILITY_AUTHTOKEN,
                                                                CASA_STATUS_UNSUCCESSFUL);
            }

            // Good, advance to the next state based on the status code.
            if (CASA_SUCCESS(pGetAuthTokenRespParse->status))
            {
               // The request completed successfully
               pGetAuthTokenRespParse->state = AWAITING_AUTH_TOKEN_ELEMENT_START;
            }
            else
            {
               pGetAuthTokenRespParse->state = AWAITING_ROOT_ELEMENT_END;
            }
         }
         else
         {
            DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected element\n", 0);
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;
   
      case AWAITING_LIFETIME_ELEMENT_END:
   
         // In this state, we are only expecting the Lifetime Element.
         if (strcmp(name, LIFETIME_ELEMENT_NAME) == 0)
         {
            // Convert the lifetime string to a numeric value
            pGetAuthTokenRespParse->pGetAuthTokenResp->tokenLifetime = dtoul(pGetAuthTokenRespParse->pLifetimeData,
                                                                             pGetAuthTokenRespParse->lifetimeDataLen);

            // Good, advance to the next state.
            pGetAuthTokenRespParse->state = AWAITING_AUTH_TOKEN_DATA;
         }
         else
         {
            DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected element\n", 0);
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;
   
      case AWAITING_AUTH_TOKEN_ELEMENT_END:
   
         // In this state, we are only expecting the Authentication Token Element.
         if (strcmp(name, AUTH_TOKEN_ELEMENT_NAME) == 0)
         {
            // Good, advance to the next state.
            pGetAuthTokenRespParse->state = AWAITING_ROOT_ELEMENT_END;
         }
         else
         {
            DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected element\n", 0);
            XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         }
         break;
   
      default:
         DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected state = %d\n", pGetAuthTokenRespParse->state);
         XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
         break;
   }

   DbgTrace(2, "-GetAuthTokenRespEndElementHandler- End\n", 0);
}


//++=======================================================================
CasaStatus
CreateGetAuthTokenResp(
   IN    char *pRespMsg,
   IN    size_t respLen,
   INOUT GetAuthTokenResp **ppGetAuthTokenResp)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   CasaStatus              retStatus = CASA_STATUS_SUCCESS;
   GetAuthTokenRespParse   getAuthTokenRespParse = {0};
   GetAuthTokenResp        *pGetAuthTokenResp;

   DbgTrace(1, "-CreateGetAuthTokenResp- Start\n", 0);

   /*
   * When a get authentication token request is processed successfully, the
   * server replies to the client with a message with the following format:
   * 
   * <?xml version="1.0" encoding="ISO-8859-1"?>
   * <get_auth_token_resp>
   * <status><description>ok</description>200</status>
   * <auth_token><lifetime>lifetime value</lifetime>session token data</auth_token>
   * </get_auth_token_resp>
   * 
   * When a get authentication token request fails to be successfully processed,
   * the server responds with an error and an error description string. The message
   * format of an unsuccessful reply is as follows:
   * 
   * <?xml version="1.0" encoding="ISO-8859-1"?>
   * <get_auth_token_resp>
   * <status><description>status description</description>status code</status>
   * </get_auth_token_resp>
   * 
   * Plase note that the protocol utilizes the status codes defined
   * in the HTTP 1.1 Specification.
   *
   */

   // Verify that the response is not too large for the parser
   if (respLen > INT_MAX)
   {
      DbgTrace(0, "-CreateGetAuthTokenResp- Response too large\n", 0);
      retStatus = CasaStatusBuild(CASA_SEVERITY_INFORMATIONAL,
                                  CASA_FACILITY_AUTHTOKEN,
                                  CASA_STATUS_UNSUCCESSFUL);
      goto exit;
   }

   // Allocate GetAuthTokenResp object
   pGetAuthTokenResp = malloc(sizeof(*pGetAuthTokenResp));
   if (pGetAuthTokenResp)
   {
      XML_Parser  p;

      // Initialize the GetAuthTokenResp object and set it in the
      // parse oject.
      memset(pGetAuthTokenResp, 0, sizeof(*pGetAuthTokenResp));
      getAuthTokenRespParse.pGetAuthTokenResp = pGetAuthTokenResp;

      // Create parser
      p = XML_ParserCreate(NULL);
      if (p)
      {
         // Keep track of the parser in our parse object
         getAuthTokenRespParse.p = p;

         // Initialize the status within the parse object
         getAuthTokenRespParse.status = CASA_STATUS_SUCCESS;

         // Set the start and end element handlers
         XML_SetElementHandler(p,
                               (XML_StartElementHandler) GetAuthTokenRespStartElementHandler,
                               (XML_EndElementHandler) GetAuthTokenRespEndElementHandler);

         // Set the character data handler
         XML_SetCharacterDataHandler(p, (XML_CharacterDataHandler) GetAuthTokenRespCharDataHandler);

         // Set our user data
         XML_SetUserData(p, &getAuthTokenRespParse);

         // Parse the document
         if (XML_Parse(p, pRespMsg, (int) respLen, 1) == XML_STATUS_OK)
         {
            // Verify that the parse operation completed successfully
            if (getAuthTokenRespParse.state == DONE_PARSING)
            {
               // The parse operation succeded, obtain the status returned
               // by the server.
               retStatus = getAuthTokenRespParse.status;
            }
            else
            {
               DbgTrace(0, "-CreateGetAuthTokenResp- Parse operation did not complete\n", 0);

               // Check if a status has been recorded
               if (getAuthTokenRespParse.status != CASA_STATUS_SUCCESS)
               {
                  retStatus = getAuthTokenRespParse.status;
               }
               else
               {
                  retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                              CASA_FACILITY_AUTHTOKEN,
                                              CASA_STATUS_PROTOCOL_ERROR);
               }
            }
         }
         else
         {
            DbgTrace(0, "-CreateGetAuthTokenResp- Parse error %d\n", XML_GetErrorCode(p));
            retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                        CASA_FACILITY_AUTHTOKEN,
                                        CASA_STATUS_PROTOCOL_ERROR);
         }

         // Free the parser
         XML_ParserFree(p);

         // Free any buffers associated with the parse
         if (getAuthTokenRespParse.pStatusData)
            free(getAuthTokenRespParse.pStatusData);

         if (getAuthTokenRespParse.pLifetimeData)
            free(getAuthTokenRespParse.pLifetimeData);
      }
      else
      {
         DbgTrace(0, "-CreateGetAuthTokenResp- Parser creation error\n", 0);
         retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                     CASA_FACILITY_AUTHTOKEN,
                                     CASA_STATUS_INSUFFICIENT_RESOURCES);
      }

      // Return the AuthenticationResp object to the caller if necessary
      if (CASA_SUCCESS(retStatus))
      {
         *ppGetAuthTokenResp = pGetAuthTokenResp;
      }
      else
      {
         free(pGetAuthTokenResp);
      }
   }
   else
   {
      DbgTrace(0, "-CreateGetAuthTokenResp- Memory allocation error\n", 0);
      retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                  CASA_FACILITY_AUTHTOKEN,
                                  CASA_STATUS_INSUFFICIENT_RESOURCES);
   }

exit:

   DbgTrace(1, "-CreateGetAuthTokenResp- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
void
RelGetAuthTokenResp(
   IN    GetAuthTokenResp *pGetAuthTokenResp)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   DbgTrace(1, "-RelGetAuthTokenResp- Start\n", 0);

   // Free the resources associated with the object
   if (pGetAuthTokenResp->pToken)
   {
      // Clear the memory associated with the token since it is
      // sensitive data.
      memset(pGetAuthTokenResp->pToken, 0, pGetAuthTokenResp->tokenLen);
      free(pGetAuthTokenResp->pToken);
   }

   free(pGetAuthTokenResp);

   DbgTrace(1, "-RelGetAuthTokenResp- End\n", 0);
}


//++=======================================================================
//++=======================================================================
//++=======================================================================