OsStatus 
SipRedirectorFallback::determineCallerLocationFromProvisionedUserLocation(
   const SipMessage& message,
   UtlString& callerLocation )
{
   OsStatus result = OS_FAILED;
   callerLocation.remove( 0 );


  // First, determine the identity of the caller.  This is done by looking for
  // a properly signed P-Asserted identity in the request message.
  // If the request contains a P-Asserted-Identity header and is not signed,
  // we will not trust it the returned location will be blank.
  UtlString matchedIdentityHeader;
  SipXauthIdentity sipxIdentity;
  Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRedirectorFallback:: unbound entities allowing: %s", mAllowUnbound ? "TRUE" : "FALSE");
  if (!mAllowUnbound) {
	  SipXauthIdentity sipxIdentity( message, matchedIdentityHeader, false );
  } else {
	  SipXauthIdentity sipxIdentity( message, matchedIdentityHeader, false, SipXauthIdentity::allowUnbound);
  }

  if( !matchedIdentityHeader.isNull() )
  {

     UtlString authenticatedUserIdentity;
     bool bRequestIsAuthenticated;
     bRequestIsAuthenticated = sipxIdentity.getIdentity( authenticatedUserIdentity );
     if( bRequestIsAuthenticated )
     {
        // we now have the autheticated identity of the caller.  Look up the user location
        // database to find out the location that is mapped to it.
        //ResultSet userLocationsResult;

        // Check in User Location database if user has locations
        //mpUserLocationDbInstance->getLocations( authenticatedUserIdentity, userLocationsResult );

        // Get the caller's site location. Only the first returned location is used.
        // This is not a problem given that a user should only belong to one location.

         EntityRecord entity;
         EntityDB* entityDb = SipRegistrar::getInstance(NULL)->getEntityDB();
         if (entityDb->findByIdentity(authenticatedUserIdentity.str(), entity))
        {

              callerLocation = entity.location().c_str();
              result = OS_SUCCESS;
              Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                            "%s::determineCallerLocationFromProvisionedUserLocation mapped user '%s' taken from header '%s' to location '%s' based on its provisioned location",
                            mLogName.data(), authenticatedUserIdentity.data(),
                            authenticatedUserIdentity.data(),
                            entity.location().c_str() );
        }
     }
  }
   return result;
}
// Get and add the credentials for sipXregistrar
SipLineMgr*
SipRedirectorJoin::addCredentials (UtlString domain, UtlString realm)
{
   SipLine* line = NULL;
   SipLineMgr* lineMgr = NULL;
   UtlString user;


      Url identity;

      identity.setUserId(REGISTRAR_ID_TOKEN);
      identity.setHostAddress(domain);
      UtlString ha1_authenticator;
      UtlString authtype;
      bool bSuccess = false;

      EntityDB* entityDb = SipRegistrar::getInstance(NULL)->getEntityDB();
      if (entityDb->getCredential(identity, realm, user, ha1_authenticator, authtype))
      {
         if ((line = new SipLine( identity // user entered url
                                 ,identity // identity url
                                 ,user     // user
                                 ,TRUE     // visible
                                 ,SipLine::LINE_STATE_PROVISIONED
                                 ,TRUE     // auto enable
                                 ,FALSE    // use call handling
                                 )))
         {
            if ((lineMgr = new SipLineMgr()))
            {
               if (lineMgr->addLine(*line))
               {
                  if (lineMgr->addCredentialForLine( identity, realm, user, ha1_authenticator
                                                    ,HTTP_DIGEST_AUTHENTICATION
                                                    )
                      )
                  {
                     lineMgr->setDefaultOutboundLine(identity);
                     bSuccess = true;

                     Os::Logger::instance().log(FAC_SIP, PRI_INFO,
                                   "Added identity '%s': user='******' realm='%s'"
                                   ,identity.toString().data(), user.data(), realm.data()
                                   );
                  }
                  else
                  {
                     Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                                   "Error adding identity '%s': user='******' realm='%s'\n"
                                   "Call Join feature will not work!",
                                   identity.toString().data(), user.data(), realm.data()
                                   );
                  }
               }
               else
               {
                  Os::Logger::instance().log(FAC_SIP, PRI_ERR, "addLine failed. Call Join feature will not work!" );
               }
            }
            else
            {
               Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                             "Constructing SipLineMgr failed. Call Join feature will not work!" );
            }
         }
         else
         {
            Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                          "Constructing SipLine failed. Call Join feature will not work!" );
         }
      }
      else
      {
         Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                       "No credential found for '%s' in realm '%s'. "
                       "Call Join feature will not work!"
                       ,identity.toString().data(), realm.data()
                       );
      }

      if( !bSuccess )
      {
         delete line;
         line = NULL;

         delete lineMgr;
         lineMgr = NULL;
      }


   return lineMgr;
}
RedirectPlugin::LookUpStatus
SipRedirectorAliasDB::lookUp(
   const SipMessage& message,
   UtlString& requestString,
   Url& requestUri,
   const UtlString& method,
   ContactList& contactList,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   ErrorDescriptor& errorDescriptor)
{
   // If url param sipx-userforward = false, do not redirect to user-forward
   // aliases.
   UtlString userforwardParam;
   requestUri.getUrlParameter("sipx-userforward", userforwardParam);
   bool disableForwarding =
      userforwardParam.compareTo("false", UtlString::ignoreCase) == 0;
   if (disableForwarding)
   {
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp user forwarding disabled by parameter",
                    mLogName.data());
   }

   if (_enableEarlyAliasResolution)
   {
     resolveAlias(message, requestString, requestUri);
   }


   UtlString requestIdentity;
   requestUri.getIdentity(requestIdentity);


   EntityDB::Aliases aliases;
   bool isUserIdentity = false;
   EntityDB* entityDb = SipRegistrar::getInstance(NULL)->getEntityDB();
   entityDb->getAliasContacts(requestUri, aliases, isUserIdentity);
   int numAliasContacts = aliases.size();

   if (numAliasContacts > 0)
   {
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp "
                    "got %d AliasDB contacts", mLogName.data(),
                    numAliasContacts);

      // Check if the request identity is a real user/extension
      UtlString realm;
      UtlString authType;
      

      SipXauthIdentity authIdentity;
      authIdentity.setIdentity(requestIdentity);

      for (EntityDB::Aliases::iterator iter = aliases.begin(); iter != aliases.end(); iter++)
      {

            // If disableForwarding and the relation value is "userforward",
            // do not record this contact.
            if (!(disableForwarding && iter->relation == ALIASDB_RELATION_USERFORWARD))
            {
               UtlString contact = iter->contact.c_str();
               Url contactUri(contact);

               // if the request identity is a real user
               if (isUserIdentity)
               {
                  // Encode AuthIdentity into the URI
                  authIdentity.encodeUri(contactUri, message);
               }

               contactUri.setUrlParameter(SIP_SIPX_CALL_DEST_FIELD, "AL");
               contactList.add( contactUri, *this );

                if (_enableDiversionHeader && contactList.getDiversionHeader().empty())
                {
                  //
                  // Add a Diversion header for all deflections
                  //
                  UtlString stringUri;
                  message.getRequestUri(&stringUri);
                  // The requestUri is an addr-spec, not a name-addr.
                  Url diversionUri(stringUri, TRUE);
                  UtlString userId;
                  diversionUri.getUserId(userId);
                  UtlString host;
                  diversionUri.getHostWithPort(host);


                  std::ostringstream strm;
                  strm << "<sip:";
                  if (!userId.isNull())
                    strm << userId.data() << "@";
                  strm << host.data();
                  strm << ">;reason=unconditional;sipxfwd=" << iter->relation;
                  UtlString diversion = strm.str().c_str();
                  OS_LOG_INFO(FAC_SIP, "SipRedirectorAliasDB::lookUp inserting diversion from " << diversion.data());
                  contactList.setDiversionHeader(diversion.data());
                }
            }
      }
   }
   
   return RedirectPlugin::SUCCESS;
}
bool
SipRedirectorAliasDB::resolveAlias(
   const SipMessage& message,
   UtlString& requestString,
   Url& requestUri
)
{
  bool isDomainAlias = false;
  bool isUserAlias = false;

  UtlString domain;
  UtlString hostAlias;
  UtlString userAlias;

  requestUri.getHostAddress(domain);
  UtlBoolean isMyHostAlias = mpSipUserAgent->isMyHostAlias(requestUri);
  if (mpSipUserAgent && domain != _localDomain && isMyHostAlias)
  {
    isDomainAlias = true;
    hostAlias = domain;
  }

  UtlString requestIdentity;
  requestUri.getIdentity(requestIdentity);

  EntityDB::Aliases aliases;
  bool isUserIdentity = false;
  EntityDB* entityDb = SipRegistrar::getInstance(NULL)->getEntityDB();
  entityDb->getAliasContacts(requestUri, aliases, isUserIdentity);
  int numAliasContacts = aliases.size();
  EntityDB::Aliases::iterator iter = aliases.begin();

  if (numAliasContacts == 1 && iter != aliases.end())
  {
    // If disableForwarding and the relation value is "userforward",
    // do not record this contact.
    if (isUserIdentity && iter->relation != ALIASDB_RELATION_USERFORWARD && iter->relation != "callgroup")
    {
      UtlString contact = iter->contact.c_str();
      Url contactUri(contact);
      isUserAlias = true;
      contactUri.getUserId(userAlias);
    }
  }


  if (isUserAlias)
  {
    requestUri.setUserId(userAlias.data());
    requestUri.getUri(requestString);
  }

  if (isDomainAlias)
  {
    requestUri.setHostAddress(hostAlias);
    requestUri.getUri(requestString);
  }

  if (isUserAlias || isDomainAlias)
  {
    OS_LOG_NOTICE(FAC_SIP, "SipRedirectorAliasDB::lookUp normalized request-uri to " << requestString.data());
  }


  return isUserAlias || isDomainAlias;
}
RedirectPlugin::LookUpStatus
SipRedirectorRegDB::lookUp(
   const SipMessage& message,
   UtlString& requestString,
   Url& requestUri,
   const UtlString& method,
   ContactList& contactList,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   ErrorDescriptor& errorDescriptor)
{
   unsigned long timeNow = OsDateTime::getSecsSinceEpoch();
   
   // Local copy of requestUri
   Url requestUriCopy = requestUri;

   // Look for any grid parameter and remove it.
   UtlString gridParameter;
   UtlBoolean gridPresent =
      requestUriCopy.getUrlParameter("grid", gridParameter, 0);
   if (gridPresent)
   {
      requestUriCopy.removeUrlParameter("grid");
   }
   if (Os::Logger::instance().willLog(FAC_SIP, PRI_DEBUG))
   {
      UtlString temp;
      requestUriCopy.getUri(temp);
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "%s::lookUp gridPresent = %d, gridParameter = '%s', "
                    "requestUriCopy after removing grid = '%s'",
                    mLogName.data(), gridPresent, gridParameter.data(),
                    temp.data());
   }

   RegDB::Bindings registrations;

   // Give the ~~in~ URIs separate processing.
   UtlString user;
   requestUriCopy.getUserId(user);
   RegDB* regDb = SipRegistrar::getInstance(NULL)->getRegDB();
   if (user.index(URI_IN_PREFIX) == 0)
   {
      // This is a ~~in~ URI.
      // Check for an '&' separator.
      ssize_t s = user.last('&');
      if (s != UTL_NOT_FOUND)
      {
         // This is a ~~in~[user]&[instrument] URI.
         const char* instrumentp = user.data() + s + 1;
         UtlString u;
         u.append(user,
                  sizeof (URI_IN_PREFIX) - 1,
                  s - (sizeof (URI_IN_PREFIX) - 1));
         requestUriCopy.setUserId(u);

         //regDB->
         //   getUnexpiredContactsUserInstrument(requestUriCopy, instrumentp, timeNow, registrations);
         UtlString identity;
         requestUriCopy.getIdentity(identity);
         regDb->getUnexpiredContactsUserInstrument(identity.str(), instrumentp, timeNow, registrations);
      }
      else
      {
         // This is a ~~in~[instrument] URI.
         const char* instrumentp = user.data() + sizeof (URI_IN_PREFIX) - 1;
         regDb->getUnexpiredContactsInstrument(instrumentp, timeNow, registrations);
      }         
   }
   else
   {
      // Note that getUnexpiredContactsUser will reduce the requestUri to its
      // identity (user/host/port) part before searching in the
      // database.  The requestUri identity is matched against the
      // "identity" column of the database, which is the identity part of
      // the "uri" column which is stored in registration.xml.

      UtlString identity;
     requestUriCopy.getIdentity(identity);
     regDb->getUnexpiredContactsUser(identity.str(), timeNow, registrations);

   }

   int numUnexpiredContacts = registrations.size();

   Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                 "%s::lookUp got %d unexpired contacts",
                 mLogName.data(), numUnexpiredContacts);

   // Check for a per-user call forward timer.
   // Don't set timer if we're not going to forward to voicemail.
   std::ostringstream userCfwdTimer;
   bool foundUserCfwdTimer = false;

   if (method.compareTo(SIP_INVITE_METHOD) == 0)
   {
      UtlString noRoute;
      requestUriCopy.getUrlParameter("sipx-noroute", noRoute);

      if ((!noRoute.isNull()) && (noRoute.compareTo("Voicemail") == 0))
      {
          // This is not a call scenerio controlled by this users "forward to voicemail" timer
      }
      else
      {
          UtlString identity;
          requestUriCopy.getIdentity(identity);
          EntityRecord entity;

          EntityDB* entityDb = SipRegistrar::getInstance(NULL)->getEntityDB();
          foundUserCfwdTimer = entityDb->findByIdentity(identity.str(), entity);
          if (foundUserCfwdTimer)
            userCfwdTimer << entity.callForwardTime();
      }
   }

   for (RegDB::Bindings::const_iterator iter = registrations.begin(); iter != registrations.end(); iter++)
   {
      // Query the Registration DB for the contact, expires and qvalue columns.

      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "%s::lookUp contact = '%s', qvalue = '%s', path = '%s'",
                    mLogName.data(), iter->getContact().c_str(), iter->getQvalue().c_str(), iter->getPath().c_str() );
      Url contactUri(iter->getContact().c_str());

      // If available set the per-user call forward timer.
      if (foundUserCfwdTimer)
      {
          contactUri.setHeaderParameter("expires", userCfwdTimer.str().c_str());
      }

      // If the contact URI is the same as the request URI, ignore it.
      if (!contactUri.isUserHostPortEqual(requestUriCopy))
      {
         // Check if the q-value from the database is valid, and if so,
         // add it into contactUri.
         if (!iter->getQvalue().empty())
         {
            // :TODO: (XPL-3) need a RegEx copy constructor here
            // Check if q value is numeric and between the range 0.0 and 1.0.
            static RegEx qValueValid("^(0(\\.\\d{0,3})?|1(\\.0{0,3})?)$");
            if (qValueValid.Search(iter->getQvalue().c_str()))
            {
               contactUri.setFieldParameter(SIP_Q_FIELD, iter->getQvalue().c_str());
            }
         }

         // Re-apply any grid parameter.
         if (gridPresent)
         {
            contactUri.setUrlParameter("grid", gridParameter);
         }

         contactUri.setUrlParameter(SIP_SIPX_CALL_DEST_FIELD, "INT");
         // Check if database contained a Path value.  If so, add a Route
         // header parameter to the contact with the Path vector taken from
         // the registration data.
         if (!iter->getPath().empty())
         {
            UtlString existingRouteValue;
            std::string pathVector = iter->getPath();
            if ( contactUri.getHeaderParameter(SIP_ROUTE_FIELD, existingRouteValue))
            {
               // there is already a Route header parameter in the contact; append it to the
               // Route derived from the Path vector.
                pathVector += SIP_MULTIFIELD_SEPARATOR;
                pathVector += existingRouteValue.str();
            }
            contactUri.setHeaderParameter(SIP_ROUTE_FIELD, pathVector.c_str());
         }

         // Add the contact.
         contactList.add( contactUri, *this );
      }
   }

   return RedirectPlugin::SUCCESS;
}
RedirectPlugin::LookUpStatus
SipRedirectorAliasDB::lookUp(
   const SipMessage& message,
   UtlString& requestString,
   Url& requestUri,
   const UtlString& method,
   ContactList& contactList,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   ErrorDescriptor& errorDescriptor)
{
   // If url param sipx-userforward = false, do not redirect to user-forward
   // aliases.
   UtlString userforwardParam;
   requestUri.getUrlParameter("sipx-userforward", userforwardParam);
   bool disableForwarding =
      userforwardParam.compareTo("false", UtlString::ignoreCase) == 0;
   if (disableForwarding)
   {
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp user forwarding disabled by parameter",
                    mLogName.data());
   }

   bool isDomainAlias = false;
   UtlString domain;
   UtlString hostAlias;
   requestUri.getHostAddress(domain);
   UtlBoolean isMyHostAlias = mpSipUserAgent->isMyHostAlias(requestUri);
   if (mpSipUserAgent && domain != _localDomain && isMyHostAlias)
   {
     isDomainAlias = true;
     hostAlias = domain;
     requestUri.setHostAddress(_localDomain);
   }

   UtlString requestIdentity;
   requestUri.getIdentity(requestIdentity);

   OS_LOG_DEBUG(FAC_SIP, mLogName.data() << "::lookUp identity: " << requestIdentity.data()
           << " domain: " << domain.data()
           << " local-domain: " << _localDomain.data()
           << " isHostAlias: " << isMyHostAlias);

   
   //ResultSet aliases;
   //AliasDB::getInstance()->getContacts(requestUri, aliases);
   //int numAliasContacts = aliases.getSize();

   EntityDB::Aliases aliases;
   bool isUserIdentity = false;
   EntityDB* entityDb = SipRegistrar::getInstance(NULL)->getEntityDB();
   entityDb->getAliasContacts(requestUri, aliases, isUserIdentity);
   int numAliasContacts = aliases.size();

   if (numAliasContacts > 0)
   {
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp "
                    "got %d AliasDB contacts", mLogName.data(),
                    numAliasContacts);

      // Check if the request identity is a real user/extension
      UtlString realm;
      UtlString authType;
      

      SipXauthIdentity authIdentity;
      authIdentity.setIdentity(requestIdentity);

      for (EntityDB::Aliases::iterator iter = aliases.begin(); iter != aliases.end(); iter++)
      {

            // If disableForwarding and the relation value is "userforward",
            // do not record this contact.
            if (!(disableForwarding && iter->relation == ALIASDB_RELATION_USERFORWARD))
            {
               UtlString contact = iter->contact.c_str();
               Url contactUri(contact);

               // if the request identity is a real user
               if (isUserIdentity)
               {
                  // Encode AuthIdentity into the URI
                  authIdentity.encodeUri(contactUri, message);
               }

               contactUri.setUrlParameter(SIP_SIPX_CALL_DEST_FIELD, "AL");
               
               
               if (numAliasContacts == 1 && isDomainAlias && isUserIdentity)
               {

                 UtlString userId;
                 contactUri.getUserId(userId);
                 requestUri.setUserId(userId.data());
                 requestUri.getUri(requestString);
                 OS_LOG_NOTICE(FAC_SIP, "SipRedirectorAliasDB::lookUp normalized request-uri to " << requestString.data());
               }
               else
               {
                 // Add the contact.
                 contactList.add( contactUri, *this );
               }
            }
      }
   }
   else if (isDomainAlias)
   {
     //
     // No alias found.  If this is was towards a domain alias, make sure to reset it back to
     // the old value prior to feeding it to the rest of the redirectors.
     //
     requestUri.setHostAddress(hostAlias);
     requestUri.getUri(requestString);
   }

   return RedirectPlugin::SUCCESS;
}
UtlBoolean
SubscribeServerThread::isAuthenticated (const SipMessage* message,
                                        SipMessage *responseMessage,
                                        UtlString& authenticatedUser,
                                        UtlString& authenticatedRealm )
{
    UtlBoolean retIsAuthenticated = FALSE;

    // if we are not using a database we must assume authenticated
    if ( !mIsCredentialDB )
    {
        Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated() "
            ":: No Credential DB - request is always AUTHENTICATED");
        retIsAuthenticated = TRUE;
    } else
    {
        // realm and auth type should be default for server
        // if URI not defined in DB, the user is not authorized to modify bindings -
        Os::Logger::instance().log( FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated():TRUE realm=\"%s\" ",
                mRealm.data());

        UtlString requestNonce;
        UtlString requestCnonce;
        UtlString requestNonceCount;
        UtlString requestQop;
        UtlString requestRealm;
        UtlString requestUser;
        UtlString requestUserBase;
        UtlString requestUriParam;
        int requestAuthIndex = 0;
        EntityDB* entityDb = StatusServer::getInstance()->getEntityDb();
        // can have multiple authorization / authorization-proxy headers
        // headers search for a realm match
        while ( message->getDigestAuthorizationData ( &requestUser,
                                                      &requestRealm,
                                                      &requestNonce,
                                                      NULL, // opaque
                                                      NULL, // response
                                                      &requestUriParam,
                                                      &requestCnonce,
                                                      &requestNonceCount,
                                                      &requestQop,
                                                      HttpMessage::SERVER,
                                                      requestAuthIndex,
                                                      &requestUserBase) )
        {
            Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, 
                          "SubscribeServerThread::isAuthenticated() "
                          "- Authorization header set in message, validate it.\n"
                          "- reqRealm=\"%s\", reqUser=\"%s\", reqUserBase=\"%s\"",
                          requestRealm.data(), requestUser.data(),
                          requestUserBase.data());

            UtlString qopType;
            UtlString callId;
            UtlString fromTag;
            long     nonceExpires = (5*60); // five minutes

            Url fromUrl;
            message->getFromUrl(fromUrl);
            fromUrl.getFieldParameter("tag", fromTag);
            UtlString reqUri;
            message->getRequestUri(&reqUri);
            Url mailboxUrl(reqUri);

            message->getCallIdField(&callId);

            if (mRealm.compareTo(requestRealm) ) // case sensitive check that realm is correct
            {
               Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG,
                             "SubscribeServerThread::isAuthenticated() "
                             "Realm does not match");
            }

            // See if the nonce is valid - see net/SipNonceDb.cpp
            else if (!mNonceDb.isNonceValid(requestNonce, callId, fromTag, mRealm, nonceExpires))
            {
                Os::Logger::instance().log(FAC_AUTH, PRI_INFO,
                              "SubscribeServerThread::isAuthenticated() "
                              "Invalid NONCE: '%s' found for mailboxUrl '%s' "
                              "realm: '%s' user: '******' "
                              "cnonce: '%s' nc: '%s' qop: '%s' "
                              "expiration: %ld",
                              requestNonce.data(), mailboxUrl.toString().data(),
                              mRealm.data(), requestUser.data(), 
                              requestCnonce.data(), requestNonceCount.data(), 
                              requestQop.data(), nonceExpires);
            }

            // verify that qop,cnonce, nonceCount are compatible
            else if (message->verifyQopConsistency(requestCnonce.data(),
                                                     requestNonceCount.data(),
                                                     &requestQop,
                                                     qopType)
                     >= HttpMessage::AUTH_QOP_NOT_SUPPORTED)
            {
                Os::Logger::instance().log(FAC_AUTH, PRI_INFO,
                              "SubscribeServerThread::isAuthenticated() "
                              "Invalid combination of QOP('%s'), cnonce('%s') and nonceCount('%s')",
                              requestQop.data(), requestCnonce.data(), requestNonceCount.data());
            }

            else // realm, nonce and qop are all ok
            {    
                UtlString authTypeDB;
                UtlString passTokenDB;

                // then get the credentials for this realm
                if (entityDb->getCredential(mailboxUrl, mRealm, requestUserBase, passTokenDB, authTypeDB))
                {
                    // the Digest Password is calculated from the request
                    // user, passtoken, nonce and request URI

                    retIsAuthenticated =
                       message->verifyMd5Authorization(requestUser.data(),
                                                       passTokenDB.data(),
                                                       requestNonce.data(),
                                                       requestRealm.data(),
                                                       requestCnonce.data(),
                                                       requestNonceCount.data(),
                                                       requestQop.data(),
                                                       requestUriParam.data());
                    if (retIsAuthenticated)
                    {
                        // can have multiple credentials for same realm so only break out
                        // when we have a positive match
                        Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, 
                                      "SubscribeServerThread::isAuthenticated() "
                                      "- request is AUTHENTICATED");
                        // copy the authenticated user/realm for subsequent authorization
                        authenticatedUser = requestUserBase;
                        authenticatedRealm = requestRealm;
                        break;
                    }
                    else
                    {
                        Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG,
                                      "SubscribeServerThread::isAuthenticated() "
                                      "- digest authorization failed "
                                      "nonce \"%s\", cnonce \"%s\" for "
                                      "mailboxUrl=\"%s\", reqRealm=\"%s\", reqUser=\"%s\"",
                                      requestNonce.data(),
                                      requestCnonce.data(),
                                      mailboxUrl.toString().data(),
                                      requestRealm.data(),
                                      requestUser.data());
                    }
                }
                else
                {
                    Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, 
                                  "SubscribeServerThread::isAuthenticated() "
                                  "- No Credentials for mailboxUrl=\"%s\", reqRealm=\"%s\", reqUser=\"%s\"",
                        mailboxUrl.toString().data(),
                        requestRealm.data(),
                        requestUser.data());
                }  // end check credentials
            }
            requestAuthIndex++;
        } //end while

        if ( !retIsAuthenticated )
        {
            // Generate the 401 Unauthorized response to challenge for credentials
            // Use the SipNonceDB to generate a nonce
            UtlString newNonce;
            UtlString callId;
            UtlString fromTag;

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

            message->getCallIdField(&callId);

            mNonceDb.createNewNonce(callId,
                                    fromTag,
                                    mRealm,
                                    newNonce);

            responseMessage->setRequestUnauthorized(message, HTTP_DIGEST_AUTHENTICATION,
                                                    mRealm, newNonce);
        }
    }  // end DB exists
    return retIsAuthenticated;
}
UtlBoolean
SubscribeServerThread::isAuthorized (
    const SipMessage* message,
    SipMessage *responseMessage,
    StatusPluginReference* pluginContainer)
{
    UtlBoolean retIsAuthorized = FALSE;
    UtlString  requestUser;
    Url       identityUrl;
    message->getUri(NULL, NULL, NULL, &requestUser);
    identityUrl.setUserId(requestUser);
    identityUrl.setHostAddress(mDefaultDomain);

    EntityDB* entityDb = StatusServer::getInstance()->getEntityDb();

    if( pluginContainer )
    {
        // if the plugin has permissions, we must match all these against the IMDB
        if( pluginContainer->hasPermissions() )
        {
            // permission required. Check for required permission in permission IMDB
            // All required permissions should match

            EntityRecord entity;
            entityDb->findByIdentity(identityUrl, entity);
            std::set<std::string> permissions = entity.permissions();

            int numDBPermissions = permissions.size();

            if( numDBPermissions > 0 )
            {
                UtlBoolean nextPermissionMatched = TRUE;

                UtlSListIterator* pluginPermissionIterator = pluginContainer->permissionsIterator();
                UtlString* pluginPermission;
                // Iterated through the plugin permissions matching
                // them one by one against the IMDB
                while(   (pluginPermission = (UtlString*)(*pluginPermissionIterator)())
                      && nextPermissionMatched
                      )
                {
                    //check againt all permissions in IMDB
                    nextPermissionMatched = FALSE;
                    UtlString identity, permission;
                    for ( std::set<std::string>::iterator iter = permissions.begin(); iter != permissions.end(); iter++ )

                    {

                        permission = iter->c_str();
                        if (pluginPermission->compareTo(permission, UtlString::ignoreCase ) == 0)
                        {
                            nextPermissionMatched = TRUE;
                            break;
                        }
                    }
                }
                delete pluginPermissionIterator;

                // after going thru all permissions find out if all matched or not
                if( nextPermissionMatched )
                {
                   Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthorized() -"
                        " All permissions matched - request is AUTHORIZED");
                    retIsAuthorized = TRUE;
                }
                else
                {
                    Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthorized() -"
                        " One or more Permissions did not match - request is UNAUTHORIZED");
                    retIsAuthorized = FALSE;
                }
            }
            else
            {
                // one or more permissions needed by plugin and none in IMDB => UNAUTHORIZED
                Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthorized() -"
                    " No Permissions in IMDB - request is UNAUTHORIZED");
                retIsAuthorized = FALSE;
            }
        }
        else
        {
            Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthorized() -"
                " No Permissions required - request is always AUTHORIZED");
            retIsAuthorized = TRUE;
        }
    }
    //set the error response message id unauthorized
    if(!retIsAuthorized)
    {
        responseMessage->setResponseData(message,SIP_FORBIDDEN_CODE, SIP_FORBIDDEN_TEXT);
    }
    return retIsAuthorized;
}