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 ); } }
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; }
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; }
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; }
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; }
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; }
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; } }
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 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(®, 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(®, 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(®); } 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; }
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; }
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; }
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; }
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; }