// If this is an expires line, then modify it by adding timeNow to the expiration time value. // Otherwise don't mess with it. void RegistrationDbTestContext::timeShiftExpiresLine(UtlString& line, long timeNow) { const char* EXPIRES_BEGIN = "<expires>"; const int EXPIRES_TAG_LENGTH = 9; const char* EXPIRES_END = "</expires>"; ssize_t pos1, pos2; // If the line has an expiration value, then time-shift it if (((pos1 = line.index(EXPIRES_BEGIN)) != UTL_NOT_FOUND) && ((pos2 = line.index(EXPIRES_END)) != UTL_NOT_FOUND)) { pos1 += EXPIRES_TAG_LENGTH; // skip past the tag, to the expires value CPPUNIT_ASSERT(pos2 > pos1); // expires value cannot be empty UtlString timeText(line(pos1, pos2 - pos1)); char* endptr = NULL; long timeNumber = strtol(timeText, &endptr, 10); CPPUNIT_ASSERT_EQUAL(*endptr, '\0'); char newTime[20]; // room for up to a 64-bit number, may have minus sign int newTimeLen = sprintf(newTime, "%ld", timeNow + timeNumber); CPPUNIT_ASSERT(newTimeLen > 0); // Replace the old expiration value with the new shifted value UtlString lineEnd(line(pos2, line.length() - pos2)); line.replace(pos1, newTimeLen, newTime); line.replace(pos1 + newTimeLen, lineEnd.length(), lineEnd); } }
// Static callback routine used to find and replace variable string values in // subscription content. // For example the NOTIFY message in the SIP stack contains "&version;" rather // than an actual version number [like "22"]. // The content provided by publish() provides the "context // independent" part of the content, and the SIP stack keeps knowledge // of the version number sequence for each subscription. This // callback combines these sources of information. UtlBoolean SipSubscribeServer::standardVersionCallback(SipMessage& notifyRequest, int version) { // Search and replace the version number in the Notify. UtlBoolean result = FALSE; if (notifyRequest.getBody() != NULL) { UtlString msgBytes; ssize_t msgLength; // Extract the NOTIFY body as a UtlString. notifyRequest.getBody()->getBytes(&msgBytes, &msgLength); const char* contentType = notifyRequest.getBody()->getContentType(); // Look for the placeholder for the version number, "&version;". ssize_t msgIndex = msgBytes.index(VERSION_PLACEHOLDER); if (msgIndex != UTL_NOT_FOUND) { char buffer[20]; sprintf(buffer, "%d", version); msgBytes.replace(msgIndex, sizeof (VERSION_PLACEHOLDER) - 1, buffer); HttpBody* tempBody = new HttpBody(msgBytes.data(), msgBytes.length(), contentType); // Write the new message contents (this deletes the old body) notifyRequest.setBody(tempBody); result = TRUE; } } return result; }
void CallStateEventBuilder_DB::replaceSingleQuotes(const UtlString& value, UtlString& newValue) { size_t startIndex = 0; ssize_t newIndex = 0; newValue = value; newIndex = newValue.index('\'', startIndex); while ((newIndex = newValue.index('\'', startIndex)) != UTL_NOT_FOUND) { startIndex = newIndex + 2; newValue = newValue.replace(newIndex, 1, "\\'"); } }
// Extract the contents of an HttpBody. UtlString extract_contents(HttpBody* body) { UtlString res; res.append("Content-Type: "); res.append(body->getContentType()); res.append("\r\n\r\n"); res.append(body->getBytes()); // Replace the boundary string with "[boundary]". const char* boundary_string = body->getMultipartBoundary(); ssize_t location; while ((location = res.index(boundary_string)) != UTL_NOT_FOUND) { res.replace(location, strlen(boundary_string), "[boundary]"); } return res; }
// Initialize the chain value. void CallId::initialize() { // Get the start time. OsTime currentTime; OsDateTime::getCurTime(currentTime); // Get the process ID. PID processId; processId = OsProcess::getCurrentPID(); // Get the host identity. UtlString thisHost; OsSocket::getHostIp(&thisHost); // Ensure it does not contain @. thisHost.replace('@','*'); // Force usecs. to be 6 digits with leading zeros so that we do // not have to do 64 bit integer math just to build a big unique // string. char buffer[256]; sprintf(buffer, "%d/%d.%.6d/%s", processId, currentTime.seconds(), currentTime.usecs(), thisHost.data()); OsSysLog::add(FAC_SIP, PRI_DEBUG, "CallId::initialize sChainValue generated from '%s'", buffer); // Hash them. NetMd5Codec encoder; encoder.encode(buffer, sChainValue); // Truncate the hash to CHAIN_VALUE_LENGTH characters. sChainValue.remove(CHAIN_VALUE_LENGTH); // Note initialization is done. sChainValueInitialized = TRUE; }
void Url::gen_value_unescape(UtlString& escapedText) { #if 0 printf("Url::gen_value_unescape before escapedText = '%s'\n", escapedText.data()); #endif //UtlString unescapedText; int numUnescapedChars = 0; const char* unescapedTextPtr = escapedText; // The number of unescaped characters is always less than // or equal to the number of escaped characters. Therefore // we will cheat a little and used the escapedText as // the destiniation to directly write characters in place // as the append method is very expensive char* resultPtr = new char[escapedText.length() + 1]; // Skip initial whitespace, which may be before the starting double-quote // of a quoted string. Tokens and hosts are not allowed to start with // whitespace. while (*unescapedTextPtr && (*unescapedTextPtr == ' ' || *unescapedTextPtr == '\t')) { // Consume the whitespace character. unescapedTextPtr++; numUnescapedChars++; } // Examine the first character to see if it is a double-quote. if (*unescapedTextPtr == '"') { // Skip the initial double-quote. unescapedTextPtr++; while (*unescapedTextPtr) { // Substitute a (backslash-)quoted-pair. if (*unescapedTextPtr == '\\') { // Get the next char. unescapedTextPtr++; // Don't get deceived if there is no next character. if (*unescapedTextPtr) { // The next character is copied unchanged. resultPtr[numUnescapedChars] = *unescapedTextPtr; numUnescapedChars++; } } // A double-quote without backslash ends the string. else if (*unescapedTextPtr == '"') { break; } // Char is face value. else { resultPtr[numUnescapedChars] = *unescapedTextPtr; numUnescapedChars++; } // Go to the next character unescapedTextPtr++; } } else { // It is a token or host, and can be copied unchanged. while (*unescapedTextPtr) { resultPtr[numUnescapedChars] = *unescapedTextPtr; numUnescapedChars++; // Go to the next character unescapedTextPtr++; } } // Copy back into the UtlString. resultPtr[numUnescapedChars] = '\0'; escapedText.replace(0, numUnescapedChars, resultPtr); escapedText.remove(numUnescapedChars); delete[] resultPtr; #if 0 printf("Url::gen_value_unescape after escapedText = '%s'\n", escapedText.data()); #endif }
AuthPlugin::AuthResult CallerAlias::authorizeAndModify(const UtlString& id, /**< The authenticated identity of the * request originator, if any (the null * string if not). * This is in the form of a SIP uri * identity value as used in the * credentials database (user@domain) * without the scheme or any parameters. */ const Url& requestUri, ///< parsed target Uri RouteState& routeState, ///< the state for this request. const UtlString& method,///< the request method AuthResult priorResult,///< results from earlier plugins. SipMessage& request, ///< see AuthPlugin regarding modifying bool bSpiralingRequest, ///< spiraling indication UtlString& reason ///< rejection reason ) { // get the call-id to use in logging UtlString callId; request.getCallIdField(&callId); if ( (priorResult != DENY) // no point in modifying a request that won't be sent ) { UtlString callerFrom; UtlString callerFromTagOffsetStr; UtlString aliasFrom; UtlString aliasFromTagOffsetStr; UtlString originalFromTag; if ( !routeState.getParameter(mInstanceName.data(), CALLER_FROM_PARAM, callerFrom) || !routeState.getParameter(mInstanceName.data(), CALLER_TAG_OFFSET_PARAM, callerFromTagOffsetStr) || !routeState.getParameter(mInstanceName.data(), ALIAS_FROM_PARAM, aliasFrom) || !routeState.getParameter(mInstanceName.data(), ALIAS_TAG_OFFSET_PARAM, aliasFromTagOffsetStr) || !routeState.originalCallerFromTagValue(mInstanceName.data(), originalFromTag) ) { if ( routeState.isMutable() && routeState.directionIsCallerToCalled(mInstanceName.data()) ) // a new dialog? { /* * Get the callers identity by getting the caller URI and: * remove all parameters * remove the scheme name */ UtlString callerIdentity; UtlString originalFromField; request.getFromField(&originalFromField); Url originalFromUrl(originalFromField); /* * Extract the from identity as a key for the caller alias table * Start with the From header field (someday we should use the Identity if present) */ Url fromUrl(originalFromUrl); fromUrl.removeParameters(); // parameters are not relevant for this Url::Scheme fromUrlScheme = fromUrl.getScheme(); switch (fromUrlScheme) { case Url::SipsUrlScheme: // sips and sip are equivalent for identity purposes, // so just set to sip fromUrl.setScheme(Url::SipUrlScheme); // and fall through to extract the identity... case Url::SipUrlScheme: // case Url::TelUrlScheme: will go here, since 'tel' and 'sip' are the same length fromUrl.getUri(callerIdentity); callerIdentity.remove(0,4 /* strlen("sip:") */); // strip off the scheme name break; default: // for all other schemes, treat identity as null Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "CallerAlias[%s]::check4andApplyAlias From uses unsupported scheme '%s'" " - using null identity", mInstanceName.data(), Url::schemeName(fromUrlScheme) ); break; } /* * Determine whether the identity is one for which this proxy * is authoritative; if not, we will not use wildcard matches. */ bool identityIsLocal = mpSipRouter->isLocalDomain(fromUrl); // now we have callerIdentity set; use for looking up each contact. Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "CallerAlias[%s]::check4andApplyAlias " "\n caller '%s' %s", mInstanceName.data(), callerIdentity.data(), identityIsLocal ? "is local" : "is not local" ); /* * Examine the request URI, * checking for a caller alias set for its domain(including asssociated gateway sipxecsLineid) with callerIdentity */ UtlString sipxecsLineIdField; requestUri.getUrlParameter(SIPX_SIPXECS_LINEID_URI_PARAM, sipxecsLineIdField); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "getUrlParameter: sipxecsLineid[%s]" " in CallerAlias", sipxecsLineIdField.data() ); UtlString targetDomain; requestUri.getHostWithPort(targetDomain); if (!(sipxecsLineIdField.isNull())) { targetDomain.append(";").append(SIPX_SIPXECS_LINEID_URI_PARAM).append("=").append(sipxecsLineIdField.data()); } Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "CallerAlias::targetDomain [%s]", targetDomain.data() ); // look up any caller alias for this identity and contact domain UtlString callerAlias; if (identityIsLocal && getCallerAlias(callerIdentity, targetDomain, callerAlias) ) { // found a caller alias, so rewrite the From information /* * The From header requires special handling * - we need to preserve the tag, if any, from the original header */ originalFromUrl.getFieldParameter("tag", originalFromTag); Url newFromUrl(callerAlias.data()); newFromUrl.removeFieldParameter("tag"); // specifying a tag is a no-no if ( !originalFromTag.isNull() ) { newFromUrl.setFieldParameter("tag", originalFromTag.data()); } UtlString newFromFieldValue; newFromUrl.toString(newFromFieldValue); // log the change we are making before stripping the tag from the field values Os::Logger::instance().log( FAC_SIP, PRI_INFO, "CallerAlias[%s]::check4andApplyAlias call %s set caller alias\n" " Original-From: %s\n" " Aliased-From: %s", mInstanceName.data(), callId.data(), originalFromField.data(), newFromFieldValue.data() ); // rewrite the caller identity with the aliased value request.setRawFromField(newFromFieldValue.data()); // Factor the tag values out of the field values stored in the RouteState // We do this because otherwise we'll end up encoding and sending two copies // of the tag; since some phones send really long tag values (no one knows why), // this can cause such large Record-Route headers that they cause interop problems. if ( ! originalFromTag.isNull() ) { // find the offset of the tag value in the callers from field ssize_t callerFromTagOffset; callerFromTagOffset = originalFromField.index(originalFromTag); callerFromTagOffsetStr.appendNumber(callerFromTagOffset); // strip the tag value from the original From value to be stored in the RouteState originalFromField.replace(callerFromTagOffset, originalFromTag.length(), ""); // find the offset of the tag value in the aliased from field ssize_t aliasFromTagOffset; aliasFromTagOffset = newFromFieldValue.index(originalFromTag); aliasFromTagOffsetStr.appendNumber(aliasFromTagOffset); // strip the tag value from the aliased From value to be stored in the RouteState newFromFieldValue.replace(aliasFromTagOffset, originalFromTag.length(), ""); } // save the original and new values so that we can fix them later routeState.setParameter(mInstanceName.data(), CALLER_FROM_PARAM,originalFromField); routeState.setParameter(mInstanceName.data(), CALLER_TAG_OFFSET_PARAM,callerFromTagOffsetStr); routeState.setParameter(mInstanceName.data(), ALIAS_FROM_PARAM,newFromFieldValue); routeState.setParameter(mInstanceName.data(), ALIAS_TAG_OFFSET_PARAM,aliasFromTagOffsetStr); } else { Os::Logger::instance().log( FAC_SIP, PRI_DEBUG, "CallerAlias[%s]::check4andApplyAlias call %s found no alias", mInstanceName.data(), callId.data() ); } } else { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "CallerAlias[%s]::authorizeAndModify " "not mutable - no rewrite", mInstanceName.data() ); } } else // the callerFrom and aliasFrom parameters were found { /* * This request has had its From rewritten, so fix either the From * or the To depending on which direction this request is going. */ if (!request.isResponse()) // can't modify responses, so don't bother { size_t tagOffset; if (routeState.directionIsCallerToCalled(mInstanceName.data())) { // replace the from tag value in the stored aliased header tagOffset = strtol(aliasFromTagOffsetStr.data(), NULL, 10); aliasFrom.insert(tagOffset, originalFromTag); // put the aliased header into the message request.setRawFromField(aliasFrom); Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "CallerAlias[%s]::authorizeAndModify " "call %s reset From", mInstanceName.data(), callId.data() ); } else // direction is Called to Caller { // replace the from tag value in the stored original header tagOffset = strtol(callerFromTagOffsetStr.data(), NULL, 10); callerFrom.insert(tagOffset, originalFromTag); request.setRawToField(callerFrom.data()); Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "CallerAlias[%s]::authorizeAndModify " "call %s reset To", mInstanceName.data(), callId.data() ); } } } } return AuthPlugin::CONTINUE; }