Example #1
0
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);
}
Example #2
0
EndpointDescriptor*
SessionContext::createCallerEndpointDescriptor( const SipMessage& sipRequest, const NatTraversalRules& natTraversalRules )
{
   // The Caller endpoint descriptor is initialized based on the information contained in the
   // contact URI.  This is where the NAT traversal feature encodes location information about
   // the caller for dialog-forming requests.
   UtlString tmpString;
   sipRequest.getContactEntry( 0, &tmpString );
   Url contactUri( tmpString );
   return new EndpointDescriptor( contactUri, natTraversalRules );
}
Example #3
0
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);
}
Example #4
0
/**
 * Process a redirection.  The caller sets up our processing, but we
 * carry it through to the generation of the response, queuing of the
 * suspend object, etc.  We send the response if we finish processing.
 *
 * message is the message to be processed.  Its memory is owned by our
 * caller, or is attached to the suspend object.
 *
 * method is the request's SIP method.  Its memory is owned by our caller.
 *
 * seqNo is the sequence number to be used for this request.  (If this
 * request is to be suspended and seqNo == mNextSeqNo, we must increment
 * mNextSeqNo.)
 *
 * suspendObject is the suspend object for this request (if it already
 * exists) or NULL.  It is passed as an argument to avoid attempting to
 * look it up if the caller knows that it does not exist (because this
 * is a first processing attempt).
 */
void SipRedirectServer::processRedirect(const SipMessage* pMessage,
                                        UtlString& method,
                                        RedirectPlugin::RequestSeqNo seqNo,
                                        RedirectSuspend* suspendObject)
{
   ErrorDescriptor errorDescriptor;

   // Extract the request URI.

   // This code is not strictly correct, as the request could have:
   //    Route: <registrar [added by proxy]>,
   //           sip:[user]@[domain],
   //           [more]
   // due to an element Record-Routing with its AOR, but no element seems
   // to do that.
   // If we desire to handle that case, we have to correct the code here
   // to remove/skip any top routes that refer to the Registrar, then examine
   // the topmost remaining route (if any).
   // It would also require changing the code for routing ACKs that we forward
   // to modify the topmost route if present, instead of the request-URI.
   // There may be further complications due to strict routing.
   // All of this would be much like the Proxy forwarding requests.
   // Currently, we trust that all Route values refer to the registrar
   // and blindly remove them from any ACK that we must forward directly.

   UtlString stringUri;
   pMessage->getRequestUri(&stringUri);
   // The requestUri is an addr-spec, not a name-addr.
   Url requestUri(stringUri, TRUE);
   Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                 "SipRedirectServer::processRedirect "
                 "Starting to process request URI '%s'",
                 stringUri.data());

   /*
    * Normalize the port in the Request URI
    *   This is not strictly kosher, but it solves interoperability problems.
    *   Technically, user@foo:5060 != user@foo , but many implementations
    *   insist on including the explicit port even when they should not, and
    *   it causes registration mismatches, so we normalize the URI when inserting
    *   and looking up in the database so that if explicit port is the same as
    *   the proxy listening port, then we remove it.
    *   (Since our proxy has mProxyNormalPort open, no other SIP entity
    *   can use sip:user@domain:mProxyNormalPort, so this normalization
    *   cannot interfere with valid addresses.)
    *
    * For the strict rules, set the configuration parameter
    *   SIP_REGISTRAR_PROXY_PORT : PORT_NONE
    */
   if (   mProxyNormalPort != PORT_NONE
       && requestUri.getHostPort() == mProxyNormalPort
       )
   {
      requestUri.setHostPort(PORT_NONE);
   }

   // Seize the lock that protects the list of suspend objects.
   OsLock lock(mRedirectorMutex);

   // Process with the redirectors.
   // Set to TRUE if any of the redirectors requests suspension.
   UtlBoolean willSuspend = FALSE;
   // Set to TRUE if any of the redirectors requests an error response.
   UtlBoolean willError = FALSE;
   PluginIterator iterator(mRedirectPlugins);
   RedirectPlugin* redirector;
   // Authority level of the last redirector to have modified the contact list.
   ssize_t contactListAuthorityLevel = LOWEST_AUTHORITY_LEVEL;
   ContactList contactList( stringUri );

   int i;                       // Iterator sequence number.
   for (i = 0; (redirector = static_cast <RedirectPlugin*> (iterator.next())) && !willError;
        i++)
   {
      if (mpConfiguredRedirectors[i].bActive)
      {
         // verify if the redirector has a suitable authority level to perform a look-up
         if( mpConfiguredRedirectors[i].authorityLevel >= contactListAuthorityLevel )
         {
            // Place to store the private storage pointer.
            SipRedirectorPrivateStorage* privateStorageP;
            // Initialize it.
            privateStorageP = (suspendObject ?
                               suspendObject->mRedirectors[i].privateStorage :
                               NULL);

            // Call the redirector to process the request.
            contactList.resetWasModifiedFlag();
            RedirectPlugin::LookUpStatus status =
               redirector->lookUp(*pMessage, stringUri, requestUri, method,
                                  contactList, seqNo, i, privateStorageP, errorDescriptor);

            // Create the suspend object if it does not already exist and we need it.
            if (!suspendObject &&
                (status == RedirectPlugin::SEARCH_PENDING || privateStorageP))
            {
               suspendObject = new RedirectSuspend(mRedirectorCount);
               // Insert it into mSuspendList, keyed by seqNo.
               UtlInt* containableSeqNo = new UtlInt(seqNo);
               mSuspendList.insertKeyAndValue(containableSeqNo, suspendObject);
               // Save in it a copy of the message.  (*pMessage is
               // dependent on the OsMsg bringing the message to us, and
               // will be freed when we are done with that OsMsg.)
               suspendObject->mMessage = *pMessage;
               // Use the next sequence number for the next request.
               if (seqNo == mNextSeqNo)
               {
                  // Increment to the next value (and roll over if necessary).
                  mNextSeqNo++;
               }
            }
            // Store the private storage pointer.
            if (suspendObject)
            {
               suspendObject->mRedirectors[i].privateStorage = privateStorageP;
            }

            int statusCode;
            UtlString reasonPhrase;

            // Dispatch on status.
            switch (status)
            {
            case RedirectPlugin::SUCCESS:
               // Processing was successful. If the plug-in modified the Contact list then
               // raise the authority level required to modify the contact list to the
               // authority level of this plug-in.
               if( contactList.wasListModified() )
               {
                  contactListAuthorityLevel = mpConfiguredRedirectors[i].authorityLevel;
               }
               break;

            case RedirectPlugin::ERROR:
               // Processing detected an error.  Log it and set the 'error' flag.
               errorDescriptor.getStatusLineData( statusCode, reasonPhrase );

               Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                             "SipRedirectServer::processRedirect "
                             "ERROR returned by redirector "
                             "'%s' while processing method '%s' URI '%s': "
                             "Status code = %d (%s)",
                             redirector->name().data(), method.data(), stringUri.data(), statusCode, reasonPhrase.data() );
               willError = TRUE;
               break;

            case RedirectPlugin::SEARCH_PENDING:
               Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                             "SipRedirectServer::processRedirect "
                             "SEARCH_PENDING returned by redirector "
                             "'%s' while processing method '%s' URI '%s'",
                             redirector->name().data(), method.data(), stringUri.data());
               willSuspend = TRUE;
               // Mark that this redirector has requested suspension.
               suspendObject->mRedirectors[i].suspended = TRUE;
               suspendObject->mRedirectors[i].needsCancel = TRUE;
               suspendObject->mSuspendCount++;
               break;

            default:
               Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                             "SipRedirectServer::processRedirect "
                             "Invalid status value %d returned by redirector "
                             "'%s' while processing method '%s' URI '%s'",
                             status, redirector->name().data(), method.data(), stringUri.data());
               break;
            }  // end status switch
         } // end authorityLevel >= contactListAuthorityLevel
         else
         {
            // redirector plug-in does not have a suitable authority level to look up the
            // request - it is only allowed to observe it.
            redirector->observe(*pMessage, stringUri, requestUri, method,
                               contactList, seqNo, i);
         }
      }  // end mpConfiguredRedirectors[i]
   }  // end Redirector plug-in iterator

   if (willError || !willSuspend)   // redirector has done all it can
   {
       int numContacts = 0;
       if (method.compareTo(SIP_ACK_METHOD, UtlString::ignoreCase) == 0)
       {
          // See if location server has returned an address to use
          // to forward or just drop the ACK here.
           if (!willError && ((numContacts = contactList.entries()) == 1))
           {
               Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                             "SipRedirectServer::processRedirect "
                             "Forwarding ACK for URI '%s': ",
                             stringUri.data());

               UtlString contactNameAddr;
               UtlString routeEntries;
               int maxForwards;

               // Get the (single) contact.
               contactList.get(0, contactNameAddr);
               // Convert from name-addr format (which is what is in
               // contactList) to addr-spec (which is what is needed
               // for a request-URI.
               Url contactUri(contactNameAddr, Url::NameAddr);
               UtlString contactAddrSpec;
               contactUri.getUri(contactAddrSpec);

               // create the message to forward -
               // change reqUri to located value, add route for debugging info, decrement max-forwards
               // leave last via since we are circling back, not responding
               SipMessage ackCopy(*pMessage);    // copy original ACK
               ackCopy.setRequestFirstHeaderLine(SIP_ACK_METHOD,
                                                 contactAddrSpec,
                                                 SIP_PROTOCOL_VERSION);

               // Remove any existing Route headers.
               // See the comment at the top of this method ("Extract
               // the request URI") for discussion.
               while (ackCopy.removeHeader(SIP_ROUTE_FIELD, 0))
               {
                  // empty
               }

               // Process header parameters in the request URI,
               // especially moving any Route parameters to Route headers.
               ackCopy.applyTargetUriHeaderParams();

               // Put Route to proxy in the first position, so the proxy
               // can see the ACK.
               ackCopy.addRouteUri(mAckRouteToProxy.data());

               // Update or create the Max-Forwards header.
               if (!ackCopy.getMaxForwards(maxForwards))
               {
                   maxForwards = SIP_DEFAULT_MAX_FORWARDS;
               }
               maxForwards--;
               ackCopy.setMaxForwards(maxForwards);

               // get send-to address/port/protocol from top via
               UtlString lastViaAddress;
               int lastViaPort;
               UtlString lastViaProtocol;
               OsSocket::IpProtocolSocketType viaProtocol = OsSocket::UNKNOWN;

               ackCopy.getTopVia(&lastViaAddress, &lastViaPort, &lastViaProtocol);
               SipMessage::convertProtocolStringToEnum(lastViaProtocol.data(), viaProtocol);


               Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                             "SipRedirectServer::processRedirect "
                             "sending ACK to '%s':%d using '%s' "
                             "location service returned '%s', "
                             "converted into '%s'",
                             lastViaAddress.data(),
                             lastViaPort,
                             lastViaProtocol.data(),
                             contactNameAddr.data(),
                             contactAddrSpec.data());

               // This ACK has no matching INVITE, special case
               mpSipUserAgent->sendStatelessAck(ackCopy,            // this will add via
                                                lastViaAddress,
                                                lastViaPort,
                                                viaProtocol);
           }
           else  // locater must return EXACTLY one value to forward
           {
               Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                             "SipRedirectServer::processRedirect "
                             "Cannot redirect ACK for URI '%s', dropping: "
                             "number of contacts=%d  ",
                             stringUri.data(), numContacts);
           }
       }   // end handle ACK redirection
       else     // build and send the proper (error) response
       {
          // The response we will compose and, hopefully, send.
          SipMessage response;

          // Send a response and terminate processing now if an error has
          // been found or if no redirector has requested suspension.
          if (willError)
          {
             buildResponseFromRequestAndErrorDescriptor( response, *pMessage, errorDescriptor );
          }
          else
          {
             // If request processing is finished, construct a response,
             // either 302 or 404.
             if (contactList.entries() > 0)
             {
                // There are contacts, so send a 302 Moved Temporarily.
                Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                              "SipRedirectServer::processRedirect "
                              "Contacts added, sending 302 response");
                response.setResponseData(pMessage,
                                         SIP_TEMPORARY_MOVE_CODE,
                                         SIP_TEMPORARY_MOVE_TEXT);

                // add contacts collected in the contactList to the response
                size_t index;
                size_t numEntries = contactList.entries();

                for( index = 0; index < numEntries; index++ )
                {
                   UtlString contactString;
                   if( contactList.get( index, contactString ) )
                   {
                      response.setContactField(contactString, index );
                   }
                   else
                   {
                      Os::Logger::instance().log(FAC_SIP, PRI_CRIT,
                                    "SipRedirectServer::processRedirect "
                                    "Failed to retrieve contact index %zu", index );
                   }
                }
             }
             else
             {
                // There are no contacts, send back a 404 Not Found.
                Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                              "SipRedirectServer::processRedirect "
                              "No contacts added, sending 404 response");
                response.setResponseData(pMessage,
                                         SIP_NOT_FOUND_CODE,
                                         SIP_NOT_FOUND_TEXT);
             }
          }

          // Identify ourselves in the response
          mpSipUserAgent->setUserAgentHeader(response);

          // Now that we've set the right code into the response, send the
          // response.
          mpSipUserAgent->send(response);
       }    // end sending response to Invite

       // If the suspend object exists, remove it from mSuspendList
       // and delete it.
       if (suspendObject)
       {
          Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                        "SipRedirectServer::processRedirect "
                        "Cleaning up suspense of request %d", seqNo);
          UtlInt containableSeqNo(seqNo);
          cancelRedirect(containableSeqNo, suspendObject);
       }
   }    // end redirector did all it could
   else
   {
      // Request is suspended.
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "SipRedirectServer::processRedirect "
                    "Suspending request %d", seqNo);
   }
}
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;
}
Example #6
0
RedirectPlugin::LookUpStatus
SipRedirectorRegDB::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const 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);
   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);
         _dataStore.regDB().getUnexpiredContactsUserInstrument(identity.str(), instrumentp, timeNow, registrations);
      }
      else
      {
         // This is a ~~in~[instrument] URI.
         const char* instrumentp = user.data() + sizeof (URI_IN_PREFIX) - 1;

          _dataStore.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);
     _dataStore.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;

          foundUserCfwdTimer = _dataStore.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());
   }

   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;
}
Example #9
0
RedirectPlugin::LookUpStatus
SipRedirectorMapping::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const Url& requestUri,
   const UtlString& method,
   ContactList& contactList,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   ErrorDescriptor& errorDescriptor)
{
   UtlString callTag = "UNK";
   UtlString permissionName;
   ResultSet urlMappingRegistrations;
   ResultSet urlMappingPermissions;

   // @JC This variable is strangely overloaded
   // If we have no permissions then add any encountered
   // contacts. If we do have permissions then the
   // permission must match
   UtlBoolean permissionFound = TRUE;

   if (mMappingRulesLoaded == OS_SUCCESS)
   {
      mMap.getContactList(
         requestUri,
         urlMappingRegistrations,
         urlMappingPermissions,
         callTag);
   }

   int numUrlMappingPermissions = urlMappingPermissions.getSize();

   Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp "
                 "got %d UrlMapping Permission requirements for %d contacts",
                 mLogName.data(), numUrlMappingPermissions,
                 urlMappingRegistrations.getSize());

   if (numUrlMappingPermissions > 0)
   {
      // check if we have field parameter that indicates that some permissions should be ignored
      UtlString ignorePermissionStr;
      // :KLUDGE: remove const_cast and uri declaration after XSL-88 gets fixed
      Url& uri = const_cast<Url&>(requestUri);
      uri.getUrlParameter("sipx-noroute", ignorePermissionStr);

      EntityRecord entity;
     std::set<std::string> permissions;
     if (_dataStore.entityDB().findByIdentityOrAlias(requestUri, entity))
        permissions = entity.permissions();
     size_t numDBPermissions = permissions.size();

      for (int i = 0; i<numUrlMappingPermissions; i++)
      {
         UtlHashMap record;
         urlMappingPermissions.getIndex(i, record);
         UtlString permissionKey("permission");
         UtlString urlMappingPermissionStr =
            *((UtlString*) record.findValue(&permissionKey));
         Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                       "%s::lookUp checking permissions DB for "
                       "urlMappingPermissions[%d] = '%s'",
                       mLogName.data(), i,
                       urlMappingPermissionStr.data());

         // Try to match the permission
         // so assume it cannot be found unless we
         // see a match in the IMDB
         permissionFound = FALSE;

         // if the permission we are looking for is the one the we are supposed to ignore,
         // than assume that permission is not found
         if (urlMappingPermissionStr.compareTo(ignorePermissionStr, UtlString::ignoreCase) == 0)
         {
             Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                           "%s::lookUp ignoring permission '%s'",
                           mLogName.data(),
                           ignorePermissionStr.data());
             continue;
         }



         
         
         UtlString permissionsFound;
         for (std::set<std::string>::const_iterator iter = permissions.begin();
             iter != permissions.end(); iter++)
         {
            UtlString dbPermissionStr = iter->c_str();

            bool equal = dbPermissionStr.compareTo(urlMappingPermissionStr, UtlString::ignoreCase) == 0;
 
            if (Os::Logger::instance().willLog(FAC_SIP, PRI_DEBUG))
            {
               permissionsFound.append(" ");
               permissionsFound.append(dbPermissionStr);
               if (equal)
               {
                  permissionsFound.append("[matches]");
               }
            }
            if (equal)
            {
               // matching permission found in IMDB
               permissionFound = TRUE;
               break;
            }
            dbPermissionStr.remove(0);
         }
         Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                       "%s::lookUp %d permissions configured for request URI '%s'.  Checking: %s",
                       mLogName.data(), numDBPermissions,
                       requestUri.toString().data(),
                       permissionsFound.data());

         if (permissionFound)
         {
            break;
         }
         urlMappingPermissionStr.remove(0);
      }
   }

   // either there were no requirements to match against voicemail
   // or there were and we found a match in the IMDB for the URI
   // so now add the contacts to the SIP message
   if (permissionFound)
   {
      int numUrlMappingRegistrations = urlMappingRegistrations.getSize();

      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "%s::lookUp got %d UrlMapping Contacts",
                    mLogName.data(), numUrlMappingRegistrations);

      if (numUrlMappingRegistrations > 0)
      {
         for (int i = 0; i < numUrlMappingRegistrations; i++)
         {
            UtlHashMap record;
            urlMappingRegistrations.getIndex(i, record);
            UtlString contactKey("contact");
            UtlString contact= *(dynamic_cast <UtlString*> (record.findValue(&contactKey)));

            Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                          "%s::lookUp contact = '%s'",
                          mLogName.data(), contact.data());
            Url contactUri(contact);
            Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                          "%s::lookUp contactUri = '%s'",
                          mLogName.data(), contactUri.toString().data());
            // We no longer check for recursive loops here because we
            // have comprehensive loop detection in the proxy.
            UtlString recordRoute;
            UtlString curCallDest;
            if (message.getRecordRouteField(0,&recordRoute)) {
               Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                          "%s::lookUp RecordRouteField = '%s'",
                          mLogName.data(), recordRoute.data());
            }
            contactUri.setUrlParameter(SIP_SIPX_CALL_DEST_FIELD, callTag.data());

            // 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;
}
RedirectPlugin::LookUpStatus
SipRedirectorFallback::lookUp(
   const SipMessage& message,
   UtlString& requestString,
   Url& requestUri,
   const UtlString& method,
   ContactList& contactList,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   ErrorDescriptor& errorDescriptor)
{
   ResultSet urlMappingRegistrations;

   UtlString callTag = "UNK";

   if (mMappingRulesLoaded == OS_SUCCESS)
   {      
      UtlString callerLocation;
      determineCallerLocation( message, callerLocation );
    
#ifndef __USE_OLD_FALLBACKRULES_SCHEMA__      
      mMap.getContactList(
         requestUri,
         callerLocation,
         urlMappingRegistrations,
         callTag );
#else
      ResultSet dummyMappingPermissions;
      mMap.getContactList(
         requestUri,
         urlMappingRegistrations, 
         dummyMappingPermissions );
#endif      
      
      int numUrlMappingRegistrations = urlMappingRegistrations.getSize();
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "%s::lookUp got %d UrlMapping Contacts for %s @ location '%s'",
                    mLogName.data(), numUrlMappingRegistrations, requestString.data(), callerLocation.data() );

      if (numUrlMappingRegistrations > 0)
      {
         for (int i = 0; i < numUrlMappingRegistrations; i++)
         {
            UtlHashMap record;
            urlMappingRegistrations.getIndex(i, record);
            UtlString contactKey("contact");
            UtlString contact= *(dynamic_cast <UtlString*> (record.findValue(&contactKey)));
            UtlString callTagKey("callTag");
            Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                          "%s::lookUp contact = '%s'",
                          mLogName.data(), contact.data());
            Url contactUri(contact);
            Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                          "%s::lookUp contactUri = '%s'",
                          mLogName.data(), contactUri.toString().data());

            contactUri.setUrlParameter(SIP_SIPX_CALL_DEST_FIELD, callTag.data());

            // Add the contact.
            contactList.add( contactUri, *this );
         }
      }
   }
   return RedirectPlugin::SUCCESS;
}
Example #12
0
RedirectPlugin::LookUpStatus
SipRedirectorAliasDB::lookUp(
    const SipMessage& message,
    const UtlString& requestString,
    const 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 its aliases
    UtlString disableForwarding;
    requestUri.getUrlParameter("sipx-userforward", disableForwarding);
    if (disableForwarding.compareTo("false", UtlString::ignoreCase) == 0)
    {
        OsSysLog::add(FAC_SIP, PRI_DEBUG, "%s::lookUp user forwarding disabled by parameter",
                      mLogName.data());
    }
    else
    {
        UtlString requestIdentity;
        requestUri.getIdentity(requestIdentity);

        OsSysLog::add(FAC_SIP, PRI_DEBUG, "%s::lookUp identity '%s'",
                      mLogName.data(), requestIdentity.data());

        ResultSet aliases;
        AliasDB::getInstance()->getContacts(requestUri, aliases);
        int numAliasContacts = aliases.getSize();
        if (numAliasContacts > 0)
        {
            OsSysLog::add(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;
            bool isUserIdentity =
                CredentialDB::getInstance()->isUriDefined(requestUri, realm, authType);
            SipXauthIdentity authIdentity;
            authIdentity.setIdentity(requestIdentity);

            for (int i = 0; i < numAliasContacts; i++)
            {
                static UtlString contactKey("contact");

                UtlHashMap record;
                if (aliases.getIndex(i, record))
                {
                    UtlString contact = *((UtlString*)record.findValue(&contactKey));
                    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");
                    // Add the contact.
                    contactList.add( contactUri, *this );
                }
            }
        }
    }

    return RedirectPlugin::SUCCESS;
}