コード例 #1
0
void SipRedirectorPresenceRouting::removeNonVoicemailContacts( ContactList& contactList )
{
   // walk the list to find the contact entry for voicemail
   size_t index;
   Url contactUrl;
   bool bVoicemailContactFound = false;
   for( index = 0; index < contactList.entries(); index++ )
   {
      if( contactList.get( index, contactUrl ) )
      {
         UtlString userPart;
         contactUrl.getUserId( userPart );
         if( userPart.index( VOICEMAIL_CONTACT_PREFIX ) == 0 )
         {
            bVoicemailContactFound = true;
            break;
         }
      }
   }

   // if vm contact found, remove all and put vm contact back in.
   if( bVoicemailContactFound )
   {
      contactList.removeAll( *this );
      contactList.add( contactUrl, *this );
   }
}
コード例 #2
0
 virtual RedirectPlugin::LookUpStatus lookUp(
    const SipMessage& message,
    const UtlString& requestString,
    const Url& requestUri,
    const UtlString& method,
    ContactList& contactList,
    RequestSeqNo requestSeqNo,
    int redirectorNo,
    SipRedirectorPrivateStorage*& privateStorage,
    ErrorDescriptor& errorDescriptor)
 {
    char diagMessage[100];
    sprintf( diagMessage, "%s::lookUp: contactList Size=%d", mLogName.data(), contactList.entries() );
    globalList.push_back( diagMessage );
    if( mBehavior.compareTo("ADD_SELF_AS_CONTACT") == 0 )
    {
       contactList.add( mLogName, *this );
       return RedirectPlugin::SUCCESS;
    }
    else if( mBehavior.compareTo("DONT_ADD_CONTACT") == 0 )
    {
       return RedirectPlugin::SUCCESS;
    }
    else if( mBehavior.compareTo("RETURN_ERROR") == 0 )
    {
       return RedirectPlugin::ERROR;
    }
    return RedirectPlugin::SUCCESS;
 }
コード例 #3
0
RedirectPlugin::LookUpStatus
SipRedirectorGateway::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const Url& requestUri,
   const UtlString& method,
   ContactList& contactList,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   ErrorDescriptor& errorDescriptor)
{
   UtlString userId;
   requestUri.getUserId(userId);
   OsSysLog::add(FAC_SIP, PRI_DEBUG, "%s::lookUp "
                 "userId = '%s'",
                 mLogName.data(), userId.data());

   // Test for the presence of the prefix.
   const char* user = userId.data();
   int prefix_length = mPrefix.length();
   // Compare the prefix.
   if (strncmp(user, mPrefix.data(), prefix_length) == 0)
   {
      // Extract the full routing prefix.
      UtlString routing_prefix(userId.data(), prefix_length + mDigits);

      // Look up the routing prefix in the map.
      mMapLock.acquire();
      UtlContainable* value = mMapUserToContacts.findValue(&routing_prefix);
      if (value)
      {
         // Have to make a copy of the string, as the map entry might get
         // changed later.
         UtlString hostpart(*(dynamic_cast <UtlString*> (value)));

         mMapLock.release();

         if (!hostpart.isNull())
         {            
            // Add the contact.
            UtlString s("sip:");
            s.append(hostpart);
            Url uri(s);
            // The remainder of userId becomes the userId to the gateway.
            uri.setUserId(&userId.data()[prefix_length + mDigits]);
            // Add the contact.
            contactList.add( uri, *this );
         }
      }
      else
      {
         mMapLock.release();
      }
   }

   return RedirectPlugin::SUCCESS;
}
コード例 #4
0
RedirectPlugin::LookUpStatus
SipRedirectorUserParam::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const Url& requestUri,
   const UtlString& method,
   ContactList& contactList,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   ErrorDescriptor& errorDescriptor)
{
   if (mStripAll)
   {
      if (SipRedirectServer::getInstance()->sipUserAgent()->isMyHostAlias(requestUri))
      {
         UtlString userpart;
         requestUri.getUserId(userpart);

         ssize_t semiColonIndex;
         if ((semiColonIndex = userpart.index(';')) != UTL_NOT_FOUND)
         {
            UtlString strippedUser(userpart);
            strippedUser.remove(semiColonIndex);

            Url strippedUrl(requestUri);
            strippedUrl.setUserId(strippedUser);

            OsSysLog::add(FAC_SIP, PRI_INFO,
                          "%s::lookUp stripped parameters from '%s' -> '%s'",
                          mLogName.data(), userpart.data(), strippedUser.data());

            contactList.add(strippedUrl, *this);
         }
      }
      else
      {
         if (OsSysLog::willLog(FAC_SIP, PRI_DEBUG))
         {
            UtlString logUri;
            requestUri.getUri(logUri);
            OsSysLog::add(FAC_SIP, PRI_DEBUG, "%s::lookUp '%s' not in my domain - not modified",
                          mLogName.data(), logUri.data());
         }
      }
   }
   else
   {
      OsSysLog::add(FAC_SIP, PRI_DEBUG, "%s::lookUp disabled by configuration",
                    mLogName.data());
   }

   return RedirectPlugin::SUCCESS;
}
コード例 #5
0
ファイル: SipRedirectorMPT.cpp プロジェクト: chemeris/sipxecs
SipRedirector::LookUpStatus
SipRedirectorMPT::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const Url& requestUri,
   const UtlString& method,
   ContactList& contactList,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   ErrorDescriptor& errorDescriptor)
{
   UtlString userId;
   requestUri.getUserId(userId);
   OsSysLog::add(FAC_SIP, PRI_DEBUG, "%s::lookUp "
                 "userId = '%s'", mLogName.data(),
                 userId.data());

   // Look up the user ID in the map.
   mMapLock.acquire();
   UtlContainable* v = mMapUserToContacts.findValue(&userId);
   mMapLock.release();
   // If found, add the contacts.
   if (v)
   {
      // Extract all the contacts out of the contact string.
      const char* s;
      const char* s1;
      for (s = (dynamic_cast<UtlString*> (v))->data();
           *s != '\0';
           s = s1+1)
      {
         // Find the ending newline, if any.
         // (Beware that Tiny XML trims trailing newlines off text contents!)
         s1 = strchr(s, '\n');
         if (!s1)
         {
            s1 = s + strlen(s);
         }
         // Ignore it if it is null
         if (s1-s != 0)
         {
            // Construct a UtlString of this contact.
            UtlString c(s, s1-s);
            // Construct a Url of this contact.
            Url url(c.data(), FALSE);
            // Add the contact.
            contactList.add( url, *this );
         }
      }
   }

   return SipRedirector::SUCCESS;
}
コード例 #6
0
RedirectPlugin::LookUpStatus
SipRedirectorPresenceRouting::doLookUp(
   const Url& toUrl,
   ContactList& contactList)
{
   // check if we have unified presence info for this user
   const UnifiedPresence* pUp;
   UtlString to;
   UtlString username;
   toUrl.getIdentity( to );
   toUrl.getUserId( username );
   OsSysLog::add(FAC_SIP, PRI_INFO, "%s::LookUpStatus is looking up '%s'",
                                    mLogName.data(),to.data() );
   pUp = UnifiedPresenceContainer::getInstance()->lookup( &to );

   if( pUp )
   {
      // unified presence data is available for the called party.
      // Use it to make call routing decisions.
       OsSysLog::add(FAC_SIP, PRI_INFO, "%s::LookUpStatus "
                                        "Presence information for '%s':\r\n"
                                        "    Telephony presence: '%s'"
                                        "    XMPP presence: '%s'"
                                        "    Custom presence message: '%s'",
                                        mLogName.data(),
                                        to.data(), pUp->getSipState().data(),
                                        pUp->getXmppPresence().data(),
                                        pUp->getXmppStatusMessage().data() );

       // look for tel uri in the custom presence message

       RegEx telUri( TelUri );
       telUri.Search( pUp->getXmppStatusMessage().data() );
       UtlString targetUri;
       if( telUri.MatchString( &targetUri, 1 ) )
       {
         // prepend 'sip:' and add target as contact
         targetUri.insert( 0, "sip:" );
         contactList.add( targetUri, *this );
      }
      else
      {
         // If user is busy then call goes directly to voicemail.
         if( ( pUp->getSipState().compareTo("BUSY", UtlString::ignoreCase ) == 0 && mbForwardToVmOnBusy ) ||
             ( pUp->getXmppPresence().compareTo("BUSY", UtlString::ignoreCase ) == 0 && mUserPrefs.forwardToVoicemailOnDnd( username ) ) )
         {
            // prune all non-voicemail contacts from the list
            removeNonVoicemailContacts( contactList );
         }
      }
   }
   return RedirectPlugin::SUCCESS;
}
コード例 #7
0
RedirectPlugin::LookUpStatus
SipRedirectorJoin::lookUpDialog(
   const UtlString& requestString,
   const UtlString& incomingCallId,
   ContactList& contactList,
   RedirectPlugin::RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   const char* subscribeUser,
   State stateFilter)
{
   Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                 "%s::lookUpDialog requestString = '%s', "
                 "requestSeqNo = %d, redirectorNo = %d, privateStorage = %p, "
                 "subscribeUser = '******', stateFilter = %d",
                 mLogName.data(),
                 requestString.data(), requestSeqNo, redirectorNo,
                 privateStorage, subscribeUser, stateFilter);

   // If the private storage is already allocated, then this is a
   // reprocessing cycle, and the dialog to pick up (if any) is
   // recorded in private storage.
   if (privateStorage)
   {
      // Cast the private storage pointer to the right type so we can
      // access the needed dialog information.
      SipRedirectorPrivateStorageJoin* dialog_info =
         dynamic_cast<SipRedirectorPrivateStorageJoin*> (privateStorage);

      if (dialog_info->mTargetDialogDuration !=
          SipRedirectorPrivateStorageJoin::TargetDialogDurationAbsent)
      {
         // A dialog has been recorded.  Construct a contact for it.
         // Beware that as recorded in the dialog event notice, the
         // target URI is in addr-spec format; any parameters are URI
         // parameters.  (Field parameters have been broken out in
         // param elements.)
         Url contact_URI(dialog_info->mTargetDialogLocalURI, TRUE);

         // Construct the Join: header value the caller should use.
         UtlString header_value(dialog_info->mTargetDialogCallId);
         // Note that according to RFC 3891, the to-tag parameter is
         // the local tag at the destination of the INVITE/Join.
         // But the INVITE/Join goes to the end of the call that
         // we queried with SUBSCRIBE, so the to-tag in the
         // Join: header is the *local* tag from the NOTIFY.
         header_value.append(";to-tag=");
         header_value.append(dialog_info->mTargetDialogLocalTag);
         header_value.append(";from-tag=");
         header_value.append(dialog_info->mTargetDialogRemoteTag);
         // Add a header parameter to specify the Join: header.
         contact_URI.setHeaderParameter("Join", header_value.data());

         // We add a header parameter to cause the redirection to
         // include a "Require: join" header.  Then if the caller
         // phone does not support INVITE/Join:, the pick-up will
         // fail entirely.  Without it, if the caller phone does not
         // support INVITE/Join, the caller will get a
         // simultaneous incoming call from the executing phone.
         // Previously, we thought the latter behavior was better, but
         // it is not -- Consider if the device is a gateway from the
         // PSTN.  Then the INVITE/Join will generate an outgoing
         // call to the calling phone.
         contact_URI.setHeaderParameter(SIP_REQUIRE_FIELD,
                                        SIP_JOIN_EXTENSION);

         // Record the URI as a contact.
         contactList.add( contact_URI, *this );
      }

      // We do not need to suspend this time.
      return RedirectPlugin::SUCCESS;
   }
   else
   {
      UtlString userId;
      Url requestUri(requestString);
      requestUri.getUserId(userId);
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "%s::lookUpDialog userId '%s'",
                    mLogName.data(), userId.data());

      // Construct the SUBSCRIBE for the call join.
      SipMessage subscribe;
      UtlString subscribeRequestUri("sip:");
      // The user of the request URI is our subscribeUser parameter.
      subscribeRequestUri.append(subscribeUser);
      subscribeRequestUri.append("@");
      subscribeRequestUri.append(mDomain);

      // Construct a Call-Id for the SUBSCRIBE.
      UtlString callId;
      CallId::getNewCallId(callId);

      // Construct the From: value.
      UtlString fromUri;
      {
         // Get the local address and port.
         UtlString address;
         int port;
         mpSipUserAgent->getLocalAddress(&address, &port);
         // Use the first 8 chars of the MD5 of the Call-Id as the from-tag.
         NetMd5Codec encoder;
         UtlString tag;
         encoder.encode(callId.data(), tag);
         tag.remove(8);
         // Assemble the URI.
         SipMessage::buildSipUri(&fromUri,
                                 address.data(),
                                 port,
                                 NULL, // protocol
                                 NULL, // user
                                 NULL, // userLabel,
                                 tag.data());
      }

      // Set the standard request headers.
      // Allow the SipUserAgent to fill in Contact:.
      subscribe.setRequestData(
         SIP_SUBSCRIBE_METHOD,
         subscribeRequestUri.data(), // request URI
         fromUri, // From:
         subscribeRequestUri.data(), // To:
         callId,
         mCSeq);
      // Increment CSeq and roll it over if necessary.
      mCSeq++;
      mCSeq &= 0x0FFFFFFF;
      // Set the Expires header.
      // If "1 second subscriptions" is set (needed for some versions
      // of Snom phones), use a 1-second subscription.  Otherwise, use
      // a 0-second subscription, so we get just one NOTIFY.
      subscribe.setExpiresField(mOneSecondSubscription ? 1 : 0);
      // Set the "Event: dialog" header.
      subscribe.setEventField("dialog");
      // Set the "Accept: application/dialog-info+xml" header.
      // Not strictly necessary (per the I-D), but it makes the SUBSCRIBE
      // more strictly compliant.
      subscribe.setHeaderValue(SIP_ACCEPT_FIELD,
                               DIALOG_EVENT_CONTENT_TYPE);
      // Set the References header for tracing dialog associations.
      {
         UtlString referencesValue(incomingCallId);
         referencesValue.append(";rel=inquiry");
         subscribe.setHeaderValue(SIP_REFERENCES_FIELD,
                                  referencesValue);
      }

      // Send the SUBSCRIBE.
      mpSipUserAgent->send(subscribe);

      // Allocate private storage.
      SipRedirectorPrivateStorageJoin *storage =
         new SipRedirectorPrivateStorageJoin(requestSeqNo,
                                             redirectorNo);
      privateStorage = storage;

      // Record the Call-Id of the SUBSCRIBE, so we can correlated the
      // NOTIFYs with it.
      storage->mSubscribeCallId = callId;
      // Record the state filtering criterion.
      storage->mStateFilter = stateFilter;

      // If we are printing debug messages, record when the SUBSCRIBE
      // was sent, so we can report how long it took to get the NOTIFYs.
      if (Os::Logger::instance().willLog(FAC_SIP, PRI_DEBUG))
      {
         OsDateTime::getCurTime(storage->mSubscribeSendTime);
      }

      // Set the timer to resume.
      storage->mTimer.oneshotAfter(OsTime(mWaitSecs, mWaitUSecs));

      // Suspend processing the request.
      return RedirectPlugin::SEARCH_PENDING;
   }
}
コード例 #8
0
ファイル: SipRedirectorRegDB.cpp プロジェクト: ciuc/sipxecs
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;
}
コード例 #9
0
ファイル: SipRedirectorISN.cpp プロジェクト: LordGaav/sipxecs
RedirectPlugin::LookUpStatus
SipRedirectorISN::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const Url& requestUri,
   const UtlString& method,
   ContactList& contactList,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   ErrorDescriptor& errorDescriptor)
{
   bool status = false;

   // Get the user part.
   UtlString userId;
   requestUri.getUserId(userId);

   // Test if the user part is in the right format -- prefix followed by digits*digits
   const char* user = userId.data();
   int prefix_length = mPrefix.length();
   // Compare the prefix.
   int i;                       // Length of the extension part.
   if (strncmp(user, mPrefix.data(), prefix_length) == 0)
   {
      // Effectively delete the prefix from the user part.
      user += prefix_length;
      // Check the syntax of the remainder of the user.
      i = strspn(user, "0123456789");
      int j = 0;
      if (i > 0)
      {
         if (user[i] == '*')
         {
            j = strspn(user + i + 1, "0123456789");
            if (user[i + 1 + j] == '\0')
            {
               status = true;
            }
         }
      }
   }

   if (status)
   {
      // Format of user part is correct.  Look for NAPTR records.

      // Create the domain to look up.
      char domain[2 * strlen(user) + mBaseDomain.length()];
      {
         char* p = &domain[0];
         // Copy the extension, reversing it and following each digit with a period.
         for (int k = i; --k >= 0; )
         {
            *p++ = user[k];
            *p++ = '.';
         }
         // Append the ITAD and a period.
         strcpy(p, user + i + 1);
         strcat(p, ".");
         // Append the ITAD root domain.
         strcat(p, mBaseDomain.data());
      }
      OsSysLog::add(FAC_SIP, PRI_DEBUG,
                    "%s::lookUp user '%s' has ISN format, domain is '%s'",
                    mLogName.data(), user, domain);

      // To hold the return of res_query_and_parse.
      res_response* dns_response;
      const char* canonical_name;

      // Make the query and parse the response.
      SipSrvLookup::res_query_and_parse(domain, T_NAPTR, NULL, canonical_name, dns_response);

      if (dns_response != NULL)
      {
         // Search the list of RRs for the 'best' answer.
         // Initialize to values at least 2**16.
         int lowest_order_seen = 1 << 16, lowest_preference_seen = 1 << 16;
         int best_response = -1; // No response found..
         // Search the answer list.
         for (unsigned int i = 0; i < dns_response->header.ancount; i++)
         {
            if (dns_response->answer[i]->rclass == C_IN &&
                dns_response->answer[i]->type == T_NAPTR &&
                // Note we look for the canonical name now.
                strcasecmp(canonical_name, dns_response->answer[i]->name) == 0)
            {
               // A NAPTR record has been found.
               OsSysLog::add(FAC_SIP, PRI_DEBUG,
                             "%s::LookUp "
                             "NAPTR record found '%s' %d %d %d %d '%s' '%s' '%s' '%s'",
                             mLogName.data(),
                             dns_response->answer[i]->name,
                             dns_response->answer[i]->rclass,
                             dns_response->answer[i]->type,
                             dns_response->answer[i]->rdata.naptr.order,
                             dns_response->answer[i]->rdata.naptr.preference,
                             dns_response->answer[i]->rdata.naptr.flags,
                             dns_response->answer[i]->rdata.naptr.services,
                             dns_response->answer[i]->rdata.naptr.regexp,
                             dns_response->answer[i]->rdata.naptr.replacement);
               // Accept the record if flags are 'u' and services are 'E2U+sip'.
               // Note that the value 'E2U+sip' is defined by RFC 3764
               // (SIP enumservice) not RFC 2915 (the original NAPTR RFC).
               if (strcasecmp(dns_response->answer[i]->rdata.naptr.flags, "u") == 0 &&
                   strcasecmp(dns_response->answer[i]->rdata.naptr.services, "E2U+sip") == 0)
               {
                  // Check that it has the lowest order and preference values seen so far.
                  if (dns_response->answer[i]->rdata.naptr.order < lowest_order_seen ||
                      (dns_response->answer[i]->rdata.naptr.order == lowest_order_seen &&
                       dns_response->answer[i]->rdata.naptr.preference < lowest_preference_seen))
                  {
                     best_response = i;
                     lowest_order_seen = dns_response->answer[i]->rdata.naptr.order;
                     lowest_preference_seen = dns_response->answer[i]->rdata.naptr.preference;
                  }
               }
            }
         }

         // At this point, best_response (if any) is the response we chose.
         if (best_response != -1)
         {
            char* p = dns_response->answer[best_response]->rdata.naptr.regexp;
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "%s::LookUp Using NAPTR rewrite '%s' for '%s'",
                          mLogName.data(), p, domain);
            // Enough space for the 'match' part of the regexp field.
            char match[strlen(p) + 1];
            // Pointer to the 'replace' part of the regexp field.
            char delim;
            const char* replace;
            int i_flag;
            if (res_naptr_split_regexp(p, &delim, match, &replace, &i_flag))
            {
               OsSysLog::add(FAC_SIP, PRI_DEBUG,
                             "%s::LookUp match = '%s', replace = '%s', i_flag = %d",
                             mLogName.data(), match, replace, i_flag);
               // Split operation was successful.  Try to match.
               regex_t reg;
               int ret = regcomp(&reg, match, REG_EXTENDED | (i_flag ? REG_ICASE : 0));
               if (ret == 0)
               {
                  // NAPTR matches can have only 9 substitutions.
                  regmatch_t pmatch[9];
                  // regexec returns 0 for success.
                  // Though RFC 3761 and the ISN Cookbook don't say, it appears
                  // that the regexp is matched against the user-part of the SIP URI.
                  if (regexec(&reg, user, 9, pmatch, 0) == 0)
                  {
                     // Match was successful.  Construct the replacement string.
                     // Current usage is that the replacement string is the resulting URI,
                     // not the replacement into the original application-string.
                     char* result = res_naptr_replace(replace, delim, pmatch, user, 0);
                     OsSysLog::add(FAC_SIP, PRI_DEBUG,
                                   "%s::LookUp result = '%s'",
                                   mLogName.data(), result);
                     // Note that the replacement string is not
                     // substituted back into the original string, but used
                     // alone as the destination URI.
                     // Parse result string into URI.
                     Url contact(result, TRUE);
                     // Almost all strings are parsable as SIP URIs with a sufficient
                     // number of components missing.  But we can check that a scheme
                     // was identified, and that a host name was found.
                     // (A string with sufficiently few punctuation characters appears to
                     // be a sip: URI with the scheme missing and only a host name, but
                     // the legal character set for host names is fairly narrow.)
                     UtlString h;
                     contact.getHostAddress(h);
                     if (contact.getScheme() != Url::UnknownUrlScheme && !h.isNull())
                     {
                        contactList.add(contact, *this);
                     }
                     else
                     {
                        OsSysLog::add(FAC_SIP, PRI_ERR,
                                      "%s::LookUp Bad result string '%s' - "
                                      "could not identify URI scheme and/or host name is null - "
                                      "for ISN translation of '%s'",
                                      mLogName.data(), result, requestString.data());
                     }
                     // Free the result string.
                     free(result);
                  }
                  else
                  {
                     OsSysLog::add(FAC_SIP, PRI_WARNING,
                                   "%s::LookUp NAPTR regexp '%s' does not match "
                                   "for ISN translation of '%s' - no contact generated",
                                   mLogName.data(), match, requestString.data());
                  }
                  // Free the parsed regexp structure.
                  regfree(&reg);
               }
               else
               {
                  OsSysLog::add(FAC_SIP, PRI_WARNING,
                                "%s::LookUp NAPTR regexp '%s' is syntactially invalid "
                                   "for ISN translation of '%s'",
                                mLogName.data(), match, requestString.data());
               }
            }
            else
            {
               OsSysLog::add(FAC_SIP, PRI_ERR,
                             "%s::LookUp cannot parse NAPTR regexp field '%s' "
                             "for ISN translation of '%s'",
                             mLogName.data(), p, requestString.data());
            }
         }
         else
         {
            OsSysLog::add(FAC_SIP, PRI_WARNING,
                          "%s::LookUp No usable NAPTR found for '%s'"
                          "for ISN translation of '%s'",
                          mLogName.data(), domain, requestString.data());
         }
      }
      else
      {
         OsSysLog::add(FAC_SIP, PRI_WARNING,
                       "%s::LookUp no NAPTR record found for domain '%s' "
                       "for ISN translation of '%s'",
                       mLogName.data(), domain, requestString.data());
      }

      // Free the result of res_parse if necessary.
      if (dns_response != NULL)
      {
         res_free(dns_response);
      }
      if (canonical_name != NULL && canonical_name != domain)
      {
         free((void*) canonical_name);
      }
   }

   return RedirectPlugin::SUCCESS;
}
コード例 #10
0
int main() {

	ContactList list;

	cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!

	sampleFunction(3);

	cout << "\n\nContactList Printing:\n";
	unsigned char testVID[constants::VID_SIZE] = "123456789101112131415";
	Contact a = Contact(testVID, "Scooby");
	Contact b = Contact(testVID, "Sam");
	Contact c = Contact(testVID, "Paula");
	Contact d = Contact(testVID, "Andrew");

	list.add(a);
	list.add(b);
	list.add(c);
	list.add(d);

	cout << list.toString();

	cout << "\n\nContactList Removing Scooby:\n";
	list.remove("Scooby");
	cout << list.toString();

	cout << "\n\nContactList Writing:\n";
	ofstream file;
	file.open("testwritefile.txt");
	cout << "wrote to file\n";
	list.write(file);
	file.close();


	cout << "\n\nContactList Reading:\n";
	ContactList list2 = readContactList("testwritefile.txt");
	cout << list2.toString();
	cout << "read from file";

	cout << "\n\nHistoryEntry toString:\n";
	HistoryEntry e1 = HistoryEntry("Sam", "This is a test message");
	e1.setSourceVID(testVID);
	cout << e1.toString().c_str();

	cout << "\n\nHistoryLog Printing:\n";
	HistoryEntry e2 = HistoryEntry ("Sam", "This is another test message.");
	e2.setSourceVID(testVID);

	HistoryEntry e3 = HistoryEntry ("Sam", "This is a third test message.");
	e3.setSourceVID(testVID);

	HistoryLog historyLog = HistoryLog("Sam", testVID);
	historyLog.addEntry(e1);
	historyLog.addEntry(e2);
	historyLog.addEntry(e3);

	historyLog.print();


	cout << "\n\nHistoryLog Writing:\n";
	ofstream historyLogFile;
	historyLogFile.open("testHistoryLogWrite");
	historyLog.write(historyLogFile);
	cout << "wrote to historyLogFile\n";
	historyLogFile.close();


	cout << "\n\nHistoryLog Reading:\n";
	HistoryLog testLogFromRead = readHistoryLog("testHistoryLogWrite");
	testLogFromRead.print();

	return 0;
}
コード例 #11
0
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;
}
コード例 #12
0
ファイル: SipRedirectorMapping.cpp プロジェクト: ciuc/sipxecs
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;
}
コード例 #13
0
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;
}
コード例 #14
0
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;
}
コード例 #15
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;
}