UtlBoolean SipRefreshManager::getAcceptedExpiration(RefreshDialogState* state,
                                                    const SipMessage& sipResponse, 
                                                    int& expirationPeriod)
{
    UtlString method;
    UtlBoolean foundExpiration = FALSE;
    int cseq;
    sipResponse.getCSeqField(&cseq, &method);

    if(method.compareTo(SIP_REGISTER_METHOD) == 0)
    {

        // Get the presumably first contact in the REGISTER request
        // so that we can find the same contact in the response and
        // find out what the expiration is
        UtlString requestContact;
        Url requestContactUri;
        if(state && state->mpLastRequest &&
           state->mpLastRequest->getContactEntry(0, &requestContact))
        {
           requestContactUri = requestContact;
        }

        // Register could have it in the Contact header
        UtlString responseContactValue;
        int contactIndex = 0;
        while(sipResponse.getContactEntry(contactIndex , &responseContactValue))
        {
            // Get the expires parameter for the contact if it exists
            Url contactUri(responseContactValue);

            if(requestContactUri.isUserHostPortEqual(contactUri))
            {
                UtlString contactExpiresParameter;
                if(contactUri.getFieldParameter(SIP_EXPIRES_FIELD, 
                        contactExpiresParameter) &&
                   !contactExpiresParameter.isNull())
                {
                    foundExpiration = TRUE;

                    // Convert to int
                    expirationPeriod = atoi(contactExpiresParameter);
                }
            }
            contactIndex++;
        }
    }

    if(!foundExpiration)
    {
        // Not sure if we care if this is a request or response
        foundExpiration = sipResponse.getExpiresField(&expirationPeriod);
    }

    return(foundExpiration);
}
UtlBoolean SipRefreshManager::getInitialExpiration(const SipMessage& sipRequest, 
                                            int& expirationPeriod)
{
    UtlString method;
    UtlBoolean foundExpiration = FALSE;
    sipRequest.getRequestMethod(&method);

    if(method.compareTo(SIP_REGISTER_METHOD) == 0)
    {
        // Register could have it in the Contact header
        UtlString requestContactValue;
        if(sipRequest.getContactEntry(0 , &requestContactValue))
        {
            // Get the expires parameter for the contact if it exists
            Url contactUri(requestContactValue);
            UtlString contactExpiresParameter;
            if(contactUri.getFieldParameter(SIP_EXPIRES_FIELD, 
                    contactExpiresParameter) &&
               !contactExpiresParameter.isNull())
            {
                foundExpiration = TRUE;

                // Convert to int
                expirationPeriod = atoi(contactExpiresParameter);
            }
        }
    }

    if(!foundExpiration)
    {
        // Not sure if we care if this is a request or response
        foundExpiration = sipRequest.getExpiresField(&expirationPeriod);
    }

    return(foundExpiration);
}
AuthPlugin::AuthResult
TransferControl::authorizeAndModify(const UtlString& id,    /**< The authenticated identity of the
                                                             *   request originator, if any (the null
                                                             *   string if not).
                                                             *   This is in the form of a SIP uri
                                                             *   identity value as used in the
                                                             *   credentials database (user@domain)
                                                             *   without the scheme or any parameters.
                                                             */
                                    const Url&  requestUri, ///< parsed target Uri
                                    RouteState& routeState, ///< the state for this request.  
                                    const UtlString& method,///< the request method
                                    AuthResult  priorResult,///< results from earlier plugins.
                                    SipMessage& request,    ///< see AuthPlugin wrt modifying
                                    bool bSpiralingRequest, ///< request spiraling indication 
                                    UtlString&  reason      ///< rejection reason
                                    )
{
   AuthResult result = CONTINUE;
   
   // get the call-id to use in logging
   UtlString callId;
   request.getCallIdField(&callId);

   UtlString hostAddress;
   int hostPort;
   UtlString hostProtocols;
   //requestUri.getHostAddress(hostAddress);
   //request.getContactUri(0, &hostAddress);;
   request.getContactAddress(0, &hostAddress,&hostPort,&hostProtocols);
   if (DENY != priorResult)
   {
      if (method.compareTo(SIP_REFER_METHOD) == 0)
      {
         UtlString targetStr;
         if (request.getReferToField(targetStr))
         {
            Url target(targetStr, Url::NameAddr);  // parse the target URL

            UtlString targetMethod; 
            if (   Url::SipUrlScheme == target.getScheme() 
                /* REFER can create requests other than INVITE: we don't care about those       *
                 * so check that the method is INVITE or is unspecified (INVITE is the default) */
                && (   ! target.getUrlParameter(SIP_METHOD_URI_PARAMETER, targetMethod)
                    || (0==targetMethod.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase))
                    ))
            {
               if (id.isNull())
               {
                  // UnAuthenticated REFER. Do challenge the REFER to confirm the 
                  // identity of the transferor.  Note:  prior to XECS-2487, we used to challenge
                  // only the unauthenticated REFERs that didn't carry a Replaces header.
                  // The fix for XECS-2487 now requires that all unauthenticated REFERs
                  // be challenged so that consultative transfers get routed properly
                  // when user-based gateway section is used.  See tracker for the details
                  if (mpSipRouter->isLocalDomain(target))
                  {
			//White list of two servets to let Exchange REFER to sipXecs endpoints
			if (hostAddress.compareTo(server1, UtlString::ignoreCase) == 0 || hostAddress.compareTo(server2, UtlString::ignoreCase) == 0)
			{
			     Os::Logger::instance().log(FAC_AUTH, PRI_INFO, "TransferControl[%s]::authorizeAndModify "
					   "Whitelist host '%s' in call '%s'",
					   mInstanceName.data(),hostAddress.data(),callId.data()
					   );
			     result = ALLOW; //Whitelist matched so allow the transfer
			}else{
			     Os::Logger::instance().log(FAC_AUTH, PRI_INFO, "TransferControl[%s]::authorizeAndModify "
					   "challenging transfer in call '%s' from host '%s'",
					   mInstanceName.data(), callId.data(),hostAddress.data()
					   );
			     result = DENY; // we need an identity to attach to the Refer-To URI
			}
                  }
                  else
                  {
                     /*
                      * This is a transfer to a target outside our domain, so let it go
                      * unchallenged.  See XECS-806
                      */
                     Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "TransferControl[%s]::authorizeAndModify "
                                   "allowing foriegn transfer in call '%s'",
                                   mInstanceName.data(), callId.data()
                                   );
                     // Add the References to the refer-to. Adding the callId field as a reference
                     // header (will be used in resulting INVITE) in the Refer-To provides us
                     // with enough information to be able to logically tie the calls together.
                     // Useful for CDR records.  
                     UtlString refcallId(callId);
                     refcallId.append(";rel=refer");
                     target.setHeaderParameter(SIP_REFERENCES_FIELD, refcallId.data());
                  
                     Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "TransferControl[%s]::authorizeAndModify "
                                   "adding Reference field [%s] to refer-to",
                                   mInstanceName.data(), callId.data()
                                  );
                     request.setReferToField(target.toString().data());

                     result = ALLOW;
                  }
               }
               else
               {
                   UtlString  contactString;
                   request.getContactEntry(0, &contactString);
                   Url contactUri( contactString );
                   UtlString userId;
                   contactUri.getUserId(contactString);

            	   Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "TransferControl::authorizeAndModify - Contact field is: %s ", contactString.data());

                   if (contactString != "callcontroller") {
                	   // Authenticated REFER
                	   // annotate the refer-to with the authenticated controller identity
                	   SipXauthIdentity controllerIdentity;
                	   controllerIdentity.setIdentity(id);
                	   controllerIdentity.encodeUri(target);

                	   // add the References to the refer-to.
                	   UtlString refcallId(callId);
                	   refcallId.append(";rel=refer");
                	   target.setHeaderParameter(SIP_REFERENCES_FIELD, refcallId.data());
                  
                	   Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "TransferControl[%s]::authorizeAndModify "
                                "adding Reference field [%s] to refer-to",
                                mInstanceName.data(), callId.data()
                               );
                	   request.setReferToField(target.toString().data());
                   }
               }
            }
            else
            {
               Os::Logger::instance().log(FAC_AUTH, PRI_WARNING, "TransferControl[%s]::authorizeAndModify "
                             "unrecognized refer target '%s' for call '%s'",
                             mInstanceName.data(), targetStr.data(), callId.data()
                             );
            }
         }
         else
         {
            // REFER without a Refer-To header... incorrect, but just ignore it.
            Os::Logger::instance().log(FAC_AUTH, PRI_WARNING,
                          "TransferControl[%s]::authorizeAndModify "
                          "REFER method without Refer-To in call '%s'",
                          mInstanceName.data(), callId.data()
                          );
         }
      }
      else if (method.compareTo(SIP_INVITE_METHOD) == 0)
      {
         UtlString targetCallId;
         UtlString targetFromTag;
         UtlString targetToTag;

         if (request.getReplacesData(targetCallId, targetToTag, targetFromTag))
         {
            /*
             * This is an INVITE with Replaces: probably either the completion
             * of a call pickup or a consultative transfer.
             * In any case, it will not create a new call - just connect something
             * to an existing call - so we don't need to make any new authorization
             * decisions.
             */
            result = ALLOW;
         }
         else
         {
            // INVITE without Replaces: is not a transfer - ignore it.
         }
      }
      else
      {
         // neither REFER nor INVITE, so is not a transfer - ignore it.
      }
   }
   else
   {
      // Some earlier plugin already denied this - don't waste time figuring it out.
      Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "TransferControl[%s]::authorizeAndModify "
                    "prior authorization result %s for call %s",
                    mInstanceName.data(), AuthResultStr(priorResult), callId.data()
                    );
   }
   
   return result;
}
UtlBoolean SipPersistentSubscriptionMgr::updateDialogInfo(
   const SipMessage& subscribeRequest,
   UtlString& resourceId,
   UtlString& eventTypeKey,
   UtlString& eventType,
   UtlString& subscribeDialogHandle,
   UtlBoolean& isNew,
   UtlBoolean& isSubscriptionExpired,
   SipMessage& subscribeResponse,
   SipSubscribeServerEventHandler& handler)
{
   OsSysLog::add(FAC_SIP, PRI_DEBUG,
                 "SipPersistentSubscriptionMgr::updateDialogInfo "
                 "resourceId = '%s', eventTypeKey = '%s'",
                 resourceId.data(), eventTypeKey.data());

   UtlBoolean ret;

   // Call SipSubscriptionMgr to update the in-memory data.
   ret = SipSubscriptionMgr::updateDialogInfo(subscribeRequest,
                                              resourceId,
                                              eventTypeKey,
                                              eventType,
                                              subscribeDialogHandle,
                                              isNew,
                                              isSubscriptionExpired,
                                              subscribeResponse,
                                              handler);

   // If that succeeded, update the IMDB.
   if (ret)
   {
      UtlString requestUri;
      UtlString callId;
      UtlString contactEntry;
      UtlString to;
      UtlString from;
      UtlString route;
      UtlString accept;

      subscribeRequest.getRequestUri(&requestUri);
      subscribeRequest.getCallIdField(&callId);
      subscribeRequest.getContactEntry(0, &contactEntry);
      subscribeRequest.getToField(&to);
      subscribeRequest.getFromField(&from);
      subscribeRequest.buildRouteField(&route);
      accept.append(subscribeRequest.getHeaderValue(0, SIP_ACCEPT_FIELD));

      int expires = 0;
      subscribeResponse.getExpiresField(&expires);
      expires += OsDateTime::getSecsSinceEpoch();

      int subscribeCseq;
      UtlString subscribeCseqMethod;
      subscribeRequest.getCSeqField(&subscribeCseq, &subscribeCseqMethod);

      OsSysLog::add(FAC_SIP, PRI_DEBUG,
                    "SipPersistentSubscriptionMgr::updateDialogInfo "
                    "mComponent = '%s', requestUri = '%s', callId = '%s', contactEntry = '%s', expires = %d, to = '%s', from = '%s', key = '%s', route = '%s', accept = '%s'",
                    mComponent.data(), requestUri.data(),
                    callId.data(), contactEntry.data(), expires,
                    to.data(), from.data(), resourceId.data(), route.data(),
                    accept.data());

      // Attempt to update an existing row.
      int now = (int)OsDateTime::getSecsSinceEpoch();
      ret = mSubscriptionDBInstance->updateSubscribeUnexpiredSubscription(
         mComponent, to, from, callId, eventTypeKey, "",
         now, expires, subscribeCseq);
      
      if (!ret)
      {
         // Add a new row.

         // This call assumes that eventTypeKey is OK for use as the <eventtype>,
         // and that the NOTIFY CSeq's will start at 1.  0 is used as
         // the initial XML version.
         ret = mSubscriptionDBInstance->insertRow(
            mComponent, requestUri, callId, contactEntry,
            expires, subscribeCseq, eventTypeKey, "",
            to, from, resourceId, route, 1, accept, 0);

         if (!ret)
         {
            OsSysLog::add(FAC_SIP, PRI_ERR,
                          "SipPersistantSubscriptionMgr::addSubscription "
                          "Could not update or insert record in database");
         }
      }

      // Start the save timer.
      mPersistenceTimer.oneshotAfter(sPersistInterval);
   }

   return ret;
}
UtlBoolean SipXProxyCseObserver::handleMessage(OsMsg& eventMessage)
{
   int msgType = eventMessage.getMsgType();
   switch (msgType)
   {
   case OsMsg::OS_EVENT:
      switch (eventMessage.getMsgSubType())
      {
      case OsEventMsg::NOTIFY:
         if (mpWriter)
         {
            mpWriter->flush();
         }
         break;
      }
      break ;
      
   case OsMsg::PHONE_APP:
   {
      SipMessage* sipMsg;

      if(SipMessageEvent::TRANSPORT_ERROR == ((SipMessageEvent&)eventMessage).getMessageStatus())
      {
         OsSysLog::add(FAC_SIP, PRI_ERR,
                       "SipXProxyCseObserver::handleMessage transport error");
      }
      else if((sipMsg = (SipMessage*)((SipMessageEvent&)eventMessage).getMessage()))
      {
         UtlString method;
         int       rspStatus = 0;
         UtlString rspText;
         UtlString contact;
         UtlString toTag;
         
         enum 
            {
               UnInteresting,
               aCallRequest,
               aCallSetup,
               aCallFailure,
               aCallEnd,
               aCallTransfer
            } thisMsgIs = UnInteresting;
         
         Url toUrl;
         sipMsg->getToUrl(toUrl);
         // explicitly, an INVITE Request
         toUrl.getFieldParameter("tag", toTag);

         if (!sipMsg->isResponse())
         {

            // sipMsg is a Request
            sipMsg->getRequestMethod(&method);

            if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase))
            {
               if (toTag.isNull())
               {
                  thisMsgIs = aCallRequest;
               }
            }
            else if (0==method.compareTo(SIP_REFER_METHOD, UtlString::ignoreCase))
            {
               thisMsgIs = aCallTransfer;
               sipMsg->getContactEntry(0, &contact);               
            }
            else if (0==method.compareTo(SIP_BYE_METHOD, UtlString::ignoreCase))
            {
               thisMsgIs = aCallEnd; // no additional information needed
            }
            else
            {
               // other request methods are not interesting
            }
         }
         else // this is a response
         {
            int seq;
            if (sipMsg->getCSeqField(&seq, &method)) // get the method out of cseq field
            {
               if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase))
               {
                  // Responses to INVITES are handled differently based on whether
                  // or not the INVITE is dialog-forming.  If dialog-forming,
                  // any final response above 400 is considered a failure for CDR
                  // purposes.  If not dialog-forming, then any final response above 400
                  // except 401 Unauthorized, 407 Proxy Authentication Required and 
                  // 408 Request Timeout will terminate.  If we're in a dialog then
            	  // only 408 (Request Timeout) and 481 (Call/Transaction does not exist)
            	  // will terminate the dialog.

                  rspStatus = sipMsg->getResponseStatusCode();
                  if (rspStatus >= SIP_4XX_CLASS_CODE) // any failure
                  {
                     // a failure code - this is a potential CallFailure - Call Resolver will determine.
                     thisMsgIs = aCallFailure;
                     sipMsg->getResponseStatusText(&rspText);
                  }
                  else if (   ( rspStatus >= SIP_2XX_CLASS_CODE )
                           && ( rspStatus <  SIP_3XX_CLASS_CODE )
                           )
                  {
                     thisMsgIs = aCallSetup;
                     sipMsg->getContactEntry(0, &contact);
                  }
               }
               else
               {
                  // responses to non-INVITES are not interesting
               }
            }
            else
            {
               OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no Cseq in response");
            }
         }

#        ifdef LOG_DEBUG
         OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipXProxyCseObserver message is %s",
                       (  thisMsgIs == UnInteresting ? "UnInteresting"
                        : thisMsgIs == aCallEnd      ? "a Call End"
                        : thisMsgIs == aCallFailure  ? "a Call Failure"
                        : thisMsgIs == aCallRequest  ? "a call Request"      
                        : thisMsgIs == aCallSetup    ? "a Call Setup"
                        : thisMsgIs == aCallTransfer ? "a Call Transfer"
                        : "BROKEN"
                        )); 
#        endif

         if (thisMsgIs != UnInteresting)
         {
            // collect the sequence data
            mSequenceNumber++;
            
            OsTime timeNow;
            OsDateTime::getCurTime(timeNow); 

            // collect the dialog information
            UtlString callId;
            sipMsg->getCallIdField(&callId);
         
            Url toUrl;
            sipMsg->getToUrl(toUrl);
            UtlString toTag;
            toUrl.getFieldParameter("tag", toTag);

            Url fromUrl;
            sipMsg->getFromUrl(fromUrl);
            UtlString fromTag;
            fromUrl.getFieldParameter("tag", fromTag);

            // collect the To and From
            UtlString toField;
            sipMsg->getToField(&toField);
            
            UtlString fromField;
            sipMsg->getFromField(&fromField);

            UtlString referTo;
            UtlString referredBy;
            UtlString requestUri;
            sipMsg->getReferToField(referTo);
            sipMsg->getReferredByField(referredBy);   
            sipMsg->getRequestUri(&requestUri);
            
            UtlString responseMethod;
            int cseqNumber;
            sipMsg->getCSeqField(&cseqNumber, &responseMethod);            

            // generate the call state event record
            if (mpBuilder)
            {
               switch (thisMsgIs)
               {
               case aCallRequest:
                  mpBuilder->callRequestEvent(mSequenceNumber, timeNow, contact);
                  break;
                  
               case aCallSetup:
                  mpBuilder->callSetupEvent(mSequenceNumber, timeNow, contact);
                  break;
   
               case aCallFailure:
                  mpBuilder->callFailureEvent(mSequenceNumber, timeNow, rspStatus, rspText);
                  break;
                  
               case aCallEnd:
                  mpBuilder->callEndEvent(mSequenceNumber, timeNow);
                  break;
                  
               case aCallTransfer:
                  mpBuilder->callTransferEvent(mSequenceNumber, timeNow, 
                                               contact, referTo, referredBy, requestUri);
                  break;   
   
               default:
                  // shouldn't be possible to get here
                  OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid thisMsgIs");
                  break;
               }
   
               mpBuilder->addCallData(cseqNumber, callId, fromTag, toTag, fromField, toField);
               UtlString via;
               for (int i=0; sipMsg->getViaField(&via, i); i++)
               {
                  mpBuilder->addEventVia(via);
               }
   
               mpBuilder->completeCallEvent();
                 
               // get the completed record
               UtlString event;
               mpBuilder->finishElement(event);
               
               if (mpWriter)
               {
                 mpWriter->writeLog(event.data());
               }
            }
            else
            {
               OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no CallStateEventBuilder!");               
            }
         }
      }
      else
      {
         OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver getMessage returned NULL");
      }
   }
   break;
   
   default:
   {
      OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid message type %d", msgType );
   }
   } // end switch (msgType)
   
   return(TRUE);
}
UtlBoolean SipXProxyCseObserver::handleMessage(OsMsg& eventMessage)
{
   int msgType = eventMessage.getMsgType();
   switch (msgType)
   {
   case OsMsg::OS_EVENT:
      switch (eventMessage.getMsgSubType())
      {
      case OsEventMsg::NOTIFY:
         if (mpWriter)
         {
            mpWriter->flush();
         }
         break;
      }
      break ;
      
   case OsMsg::PHONE_APP:
   {
      SipMessage* sipMsg;

      if(SipMessageEvent::TRANSPORT_ERROR == ((SipMessageEvent&)eventMessage).getMessageStatus())
      {
         Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                       "SipXProxyCseObserver::handleMessage transport error");
      }
      else if((sipMsg = (SipMessage*)((SipMessageEvent&)eventMessage).getMessage()))
      {
         UtlString method;
         int       rspStatus = 0;
         UtlString rspText;
         UtlString contact;
         UtlString toTag;
         
         enum 
            {
               UnInteresting,
               aCallRequest,
               aCallSetup,
               aCallFailure,
               aCallEnd,
               aCallTransfer
            } thisMsgIs = UnInteresting;
         
         Url toUrl;

         sipMsg->getToUrl(toUrl);

         // explicitly, an INVITE Request
         toUrl.getFieldParameter("tag", toTag);

         if (!sipMsg->isResponse())
         {

            // sipMsg is a Request
            sipMsg->getRequestMethod(&method);

            if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase))
            {
               if (toTag.isNull())
               {
                  sipMsg->getContactEntry(0, &contact);               
                  thisMsgIs = aCallRequest;
               }
            }
            else if (0==method.compareTo(SIP_REFER_METHOD, UtlString::ignoreCase))
            {
               thisMsgIs = aCallTransfer;
               sipMsg->getContactEntry(0, &contact);               
            }
            else if (0==method.compareTo(SIP_BYE_METHOD, UtlString::ignoreCase))
            {
               thisMsgIs = aCallEnd; // no additional information needed
            }
            else
            {
               // other request methods are not interesting
            }
         }
         else // this is a response
         {
            int seq;
            if (sipMsg->getCSeqField(&seq, &method)) // get the method out of cseq field
            {
               if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase))
               {
                  // Responses to INVITES are handled differently based on whether
                  // or not the INVITE is dialog-forming.  If dialog-forming,
                  // any final response above 400 is considered a failure for CDR
                  // purposes.  If not dialog-forming, then any final response above 400
                  // except 401 Unauthorized, 407 Proxy Authentication Required and 
                  // 408 Request Timeout will terminate.  If we're in a dialog then
            	  // only 408 (Request Timeout) and 481 (Call/Transaction does not exist)
            	  // will terminate the dialog.

                  rspStatus = sipMsg->getResponseStatusCode();
                  if (rspStatus >= SIP_4XX_CLASS_CODE) // any failure
                  {
                     // a failure code - this is a potential CallFailure - Call Resolver will determine.
                     thisMsgIs = aCallFailure;
                     sipMsg->getResponseStatusText(&rspText);
                  }
                  else if (   ( rspStatus >= SIP_2XX_CLASS_CODE )
                           && ( rspStatus <  SIP_3XX_CLASS_CODE )
                           )
                  {
                     thisMsgIs = aCallSetup;
                     sipMsg->getContactEntry(0, &contact);
                  }
               }
               else
               {
                  // responses to non-INVITES are not interesting
               }
            }
            else
            {
               Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no Cseq in response");
            }
         }

#        ifdef LOG_DEBUG
         Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipXProxyCseObserver message is %s",
                       (  thisMsgIs == UnInteresting ? "UnInteresting"
                        : thisMsgIs == aCallEnd      ? "a Call End"
                        : thisMsgIs == aCallFailure  ? "a Call Failure"
                        : thisMsgIs == aCallRequest  ? "a call Request"      
                        : thisMsgIs == aCallSetup    ? "a Call Setup"
                        : thisMsgIs == aCallTransfer ? "a Call Transfer"
                        : "BROKEN"
                        )); 
#        endif

         if (thisMsgIs != UnInteresting)
         {
            // collect the sequence data
            mSequenceNumber++;
            
            OsTime timeNow;
            OsDateTime::getCurTime(timeNow); 

            // collect the dialog information
            UtlString callId;
            sipMsg->getCallIdField(&callId);
         
            Url toUrl;
            sipMsg->getToUrl(toUrl);
            UtlString toTag;
            toUrl.getFieldParameter("tag", toTag);

            Url fromUrl;
            sipMsg->getFromUrl(fromUrl);
            UtlString fromTag;
            fromUrl.getFieldParameter("tag", fromTag);

            // collect the To and From
            UtlString toField;
            sipMsg->getToField(&toField);
            
            UtlString fromField;
            sipMsg->getFromField(&fromField);


            // collect the branch Id (i.e. transaction id) and via count.
            UtlString viaValue;
            int viaCount;
            UtlString branchId;
            viaCount = sipMsg->getCountHeaderFields(SIP_VIA_FIELD);
            viaCount = viaCount + sipMsg->getCountHeaderFields(SIP_SHORT_VIA_FIELD);
            if ( sipMsg->getViaFieldSubField( &viaValue, 0 ) ) {
               sipMsg->getViaTag( viaValue, "branch", branchId );
            }
            UtlString referTo;
            UtlString referredBy;
            UtlString requestUri;
            UtlString references;
            UtlString replaces_callId;
            UtlString replaces_toTag;
            UtlString replaces_fromTag;
            UtlString matchingIdentityHeader;
            SipXauthIdentity sipxIdentity(*sipMsg, matchingIdentityHeader, true,SipXauthIdentity::allowUnbound);

            sipMsg->getReferToField(referTo);
            sipMsg->getReferredByField(referredBy);   
            sipMsg->getRequestUri(&requestUri);
            sipMsg->getReferencesField(&references);
            if (sipMsg->getReplacesData(replaces_callId, replaces_toTag, replaces_fromTag)) {
               if (references.length() != 0) {
                  references.append(",");
               }
               references.append(replaces_callId);
               references.append(";rel=xfer");
            }
            
            UtlString responseMethod;
            UtlString calleeRoute;

            int cseqNumber;
            sipMsg->getCSeqField(&cseqNumber, &responseMethod);            

            BranchTimePair* callIdBranchIdTime;
            // generate the call state event record
            if (mpBuilder)
            {
               UtlString identity;
               UtlString recordRoute;
               bool routeFound = false;
               bool paiPresent = false;

               switch (thisMsgIs)
               {
               case aCallRequest:
                 
                  if (sipxIdentity.getIdentity(identity)) {
                     paiPresent = true;
                  }

                  if ( branchId && branchId.data() ) {
                     mCallTransMutex.acquire();
                     unsigned long currentTime = OsDateTime::getSecsSinceEpoch();

                     UtlString* keyCallId = new UtlString(callId);
                     BranchTimePair* valBranchTimePair = new BranchTimePair(branchId.data(), &currentTime, &paiPresent);
                     if (NULL == mCallTransMap.insertKeyAndValue(keyCallId, valBranchTimePair) ) {
                        // Unable to add callId to map so it must already be present.  
                        delete keyCallId;
                        delete valBranchTimePair;

                        // Check if the paiPresent value is set to true or not.
                        // If not set and we now have a PAI for this call, set it and generate another call request state event 
                        // with this info. Otherwise skip over.
                        if ( paiPresent ) {
                           callIdBranchIdTime = (BranchTimePair*) mCallTransMap.findValue(&callId);
                           if ( callIdBranchIdTime && (*callIdBranchIdTime->getPaiPresent() == false) ) {
                              // need to generate another call request event in order to state originator is internal.
                              callIdBranchIdTime->setPaiPresent(&paiPresent);
                           }
                           else {
                              mCallTransMutex.release();
                              return(TRUE);
                           }
                        }
                        else {
                           mCallTransMutex.release();
                           return(TRUE);
                        }
                     }
                     mCallTransMutex.release();
                  }
                  mpBuilder->callRequestEvent(mSequenceNumber, timeNow, contact, references, branchId, viaCount, paiPresent);
                  break;
                  
               case aCallSetup:
                  // Clear out from the map only if rspStatus is higher than 200 as its possible to receive multiple 200 messages.
                  // If the response is 200, the call in the map will be cleared out when the call ends.
                  mCallTransMutex.acquire();
                  callIdBranchIdTime = (BranchTimePair*) mCallTransMap.findValue(&callId);
                  if ( callIdBranchIdTime && (0 == branchId.compareTo(callIdBranchIdTime)) ) {
                     if ( rspStatus > SIP_2XX_CLASS_CODE ) {
                           mCallTransMap.destroy(&callId);
                        }
                     mCallTransMutex.release();
                  }
                  else
                  {
                     // CallId/BranchId are either not found or doesn't match.  Not a final response.
                     mCallTransMutex.release();
                     return(TRUE);
                  }
                  for (int rrNum = 0;
                       (!routeFound && sipMsg->getRecordRouteUri(rrNum, &recordRoute));
                       rrNum++
                  )
                  {
                     Url recordRouteUrl(recordRoute);
                     if (mpSipUserAgent->isMyHostAlias(recordRouteUrl)) {
                        // This is a record route for our proxy, extract Call tags if they exist.
                        recordRouteUrl.getUrlParameter(SIP_SIPX_CALL_DEST_FIELD, calleeRoute, 0);
                        routeFound = true;
                     }
                  }
                  mpBuilder->callSetupEvent(mSequenceNumber, timeNow, contact, calleeRoute, branchId, viaCount);
                  break;
   
               case aCallFailure:
                  // Failure case means that the response code is > 400.  If the call is found
                  // in the map, then this is a final response.  Delete from the map and build an event.
                  mCallTransMutex.acquire();
                  callIdBranchIdTime = (BranchTimePair*) mCallTransMap.findValue(&callId);
                  if ( callIdBranchIdTime && (0 == branchId.compareTo(callIdBranchIdTime)) ) {
                     mCallTransMap.destroy(&callId);
                     mCallTransMutex.release();
                     if ( rspStatus != SIP_PROXY_AUTH_REQ_CODE ) {
                        mpBuilder->callFailureEvent(mSequenceNumber, timeNow, branchId, viaCount, rspStatus, rspText);
                     }
                     else {
                        // response was an authentication required.  Don't build a CSE for these as a new Invite will
                        // occur.
                        return(TRUE);
                     }
                  }
                  else
                  {
                     // Call was not found in the map so this is not a final response.  Ignore it.
                     mCallTransMutex.release();
                     return(TRUE);
                  }
                  break;
                  
               case aCallEnd:
                  mCallTransMutex.acquire();
                  mCallTransMap.destroy(&callId);
                  mCallTransMutex.release();
                  mpBuilder->callEndEvent(mSequenceNumber, timeNow);
                  break;
                  
               case aCallTransfer:
                  mpBuilder->callTransferEvent(mSequenceNumber, timeNow, 
                                               contact, referTo, referredBy, requestUri);
                  break;   
   
               default:
                  // shouldn't be possible to get here
                  Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid thisMsgIs");
                  break;
               }
   
               mpBuilder->addCallData(cseqNumber, callId, fromTag, toTag, fromField, toField);
               UtlString via;
               for (int i=0; sipMsg->getViaField(&via, i); i++)
               {
                  mpBuilder->addEventVia(via);
               }
   
               mpBuilder->completeCallEvent();
                 
               // get the completed record
               UtlString event;
               mpBuilder->finishElement(event);
               
               if (mpWriter)
               {
                 mpWriter->writeLog(event.data());
               }
            }
            else
            {
               Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no CallStateEventBuilder!");               
            }
         }
      }
      else
      {
         Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver getMessage returned NULL");
      }
   }
   break;
   
   default:
   {
      Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid message type %d", msgType );
   }
   } // end switch (msgType)
   
   return(TRUE);
}