sl@0: // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "TEquiv.h" sl@0: #include sl@0: #include sl@0: #include "UriUtilsInternal.h" sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: _LIT8(KParamUserFull, ";user="); sl@0: _LIT8(KParamTtlFull, ";ttl="); sl@0: _LIT8(KParamMethodFull, ";method="); sl@0: _LIT8(KParamMaddrFull, ";maddr="); sl@0: _LIT8(KParamMaddr, "maddr"); sl@0: sl@0: _LIT8(KHeaderId, "call-id"); sl@0: _LIT8(KHeaderIdAbbr, "i"); sl@0: _LIT8(KHeaderContact, "contact"); sl@0: _LIT8(KHeaderContactAbbr, "m"); sl@0: _LIT8(KHeaderEncoding, "content-encoding"); sl@0: _LIT8(KHeaderEncodingAbbr, "e"); sl@0: _LIT8(KHeaderLength, "content-length"); sl@0: _LIT8(KHeaderLengthAbbr, "l"); sl@0: _LIT8(KHeaderType, "content-type"); sl@0: _LIT8(KHeaderTypeAbbr, "c"); sl@0: _LIT8(KHeaderFrom, "from"); sl@0: _LIT8(KHeaderFromAbbr, "f"); sl@0: _LIT8(KHeaderSubject, "subject"); sl@0: _LIT8(KHeaderSubjectAbbr, "s"); sl@0: _LIT8(KHeaderTo, "to"); sl@0: _LIT8(KHeaderToAbbr, "t"); sl@0: sl@0: TEquiv::TEquiv(const TUriC8& aLhs, const TUriC8& aRhs) sl@0: : iLhs(aLhs), iRhs(aRhs) sl@0: { sl@0: } sl@0: sl@0: TBool TEquiv::EquivalentL() const sl@0: { sl@0: if (!IsMatchSchemeL()) sl@0: return KUriUtilsErrDifferentScheme; sl@0: sl@0: if (!IsMatchUserInfoL()) sl@0: return KUriUtilsErrDifferentUserInfo; sl@0: sl@0: if (!IsMatchHostL()) sl@0: return KUriUtilsErrDifferentHost; sl@0: sl@0: if (!IsMatchPortL()) sl@0: return KUriUtilsErrDifferentPort; sl@0: sl@0: if (!IsMatchPathL()) sl@0: return KUriUtilsErrDifferentPath; sl@0: sl@0: if (!IsMatchQueryL()) sl@0: return KUriUtilsErrDifferentQuery; sl@0: sl@0: if (!IsMatchFragmentL()) sl@0: return KUriUtilsErrDifferentFragment; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: TBool TEquiv::IsMatchSchemeL() const sl@0: { sl@0: HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriScheme); sl@0: HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriScheme); sl@0: TBool result = IsMatchCaseless(*lhsDes, *rhsDes); sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: TBool TEquiv::IsMatchUserInfoL() const sl@0: { sl@0: HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriUserinfo); sl@0: HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriUserinfo); sl@0: TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: TBool TEquiv::IsMatchHostL() const sl@0: { sl@0: HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost); sl@0: HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost); sl@0: TBool result = IsMatchCaseless(*lhsDes, *rhsDes); sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: TBool TEquiv::IsMatchPortL() const sl@0: { sl@0: HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPort); sl@0: HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPort); sl@0: TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: TBool TEquiv::IsMatchPathL() const sl@0: { sl@0: HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPath); sl@0: HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPath); sl@0: TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: TBool TEquiv::IsMatchQueryL() const sl@0: { sl@0: HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriQuery); sl@0: HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriQuery); sl@0: TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: TBool TEquiv::IsMatchFragmentL() const sl@0: { sl@0: HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriFragment); sl@0: HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriFragment); sl@0: TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: HBufC8* TEquiv::DecodedSegmentLC(const TUriC8& aUri, TUriComponent aSegmentType) const sl@0: { sl@0: HBufC8* decoded = EscapeUtils::EscapeDecodeL(aUri.Extract(aSegmentType)); sl@0: CleanupStack::PushL(decoded); sl@0: return decoded; sl@0: } sl@0: sl@0: TEquivSip::TEquivSip(const TUriC8& aLhs, const TUriC8& aRhs) sl@0: : TEquiv(aLhs, aRhs) sl@0: { sl@0: } sl@0: sl@0: void TEquivSip::RemoveLeadingZeros(TPtr8 aHost) const sl@0: { sl@0: for (TInt i=0; i < aHost.Length(); i++) sl@0: { sl@0: TBool startOfNumber = (i == 0 || aHost[i-1] < '0' || aHost[i-1] > '9'); sl@0: if (aHost[i] == '0' && startOfNumber) sl@0: { sl@0: // The character is a zero and is either at the start of the string sl@0: // or the fist number in a sequence. sl@0: aHost.Delete(i--,1); sl@0: } sl@0: } sl@0: } sl@0: sl@0: TBool TEquivSip::IsMatchHostL(const TDesC8& aLhs, const TDesC8& aRhs) const sl@0: { sl@0: UriUtils::TUriHostType lhsType = UriUtils::HostType(aLhs); sl@0: UriUtils::TUriHostType rhsType = UriUtils::HostType(aRhs); sl@0: if (lhsType != rhsType) sl@0: return EFalse; sl@0: if (lhsType != UriUtils::ETextHost) sl@0: { sl@0: // Host is IPv4 or IPv6 sl@0: // Create a copy of the hosts and remove any leading '0's sl@0: HBufC8* lhsCopy = aLhs.AllocLC(); sl@0: HBufC8* rhsCopy = aRhs.AllocLC(); sl@0: RemoveLeadingZeros(lhsCopy->Des()); sl@0: RemoveLeadingZeros(rhsCopy->Des()); sl@0: TBool result = IsMatchCaseSensitive(*lhsCopy, *rhsCopy); sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: return IsMatchCaseless(aLhs, aRhs); sl@0: } sl@0: sl@0: TBool TEquivSip::IsMatchHostL() const sl@0: { sl@0: HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost); sl@0: HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost); sl@0: TBool result = IsMatchHostL(*lhsDes, *rhsDes); sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: TBool TEquivSip::IsParamCompatibleL(const TDesC8& aLhsName, const TDesC8& aLhsValue, const TDesC8& aRhsName, const TDesC8& aRhsValue) const sl@0: { sl@0: // Were're just checking that if the segments have the same name part sl@0: // that their values are the same. This method only returns false if the lhs and rhs sl@0: // have the same name but their values are different. sl@0: if (!IsMatchCaseless(aLhsName, aRhsName)) sl@0: { sl@0: // Names don't match so we're OK sl@0: return ETrue; sl@0: } sl@0: sl@0: // The maddr parameter needs to be handled differently from the others sl@0: // The address is checked for equivalence not just a straight string compare. sl@0: if (IsMatchCaseless(aLhsName, KParamMaddr)) sl@0: { sl@0: return IsMatchHostL(aLhsValue, aRhsValue); sl@0: } sl@0: else sl@0: { sl@0: if (!IsMatchCaseless(aLhsValue, aRhsValue)) sl@0: { sl@0: // Names are the same but the values are different sl@0: // We have a incompatible parameter sl@0: return EFalse; sl@0: } sl@0: } sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: TBool TEquivSip::IsParamListCompatibleL(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const sl@0: sl@0: { sl@0: TPtrC8 lhsName; sl@0: TPtrC8 lhsValue; sl@0: TPtrC8 rhsName; sl@0: TPtrC8 rhsValue; sl@0: sl@0: TPtrC8 lhsSegment; sl@0: TPtrC8 rhsSegment; sl@0: sl@0: // roll back to the start of the lhs segment parser sl@0: aLhsParser.Reset(); sl@0: sl@0: while( aLhsParser.GetNext(lhsSegment) == KErrNone ) sl@0: { sl@0: // roll back to the start of the rhs segment parser sl@0: aRhsParser.Reset(); sl@0: sl@0: GetNameValuePair(lhsSegment, lhsName, lhsValue); sl@0: while( aRhsParser.GetNext(rhsSegment) == KErrNone ) sl@0: { sl@0: GetNameValuePair(rhsSegment, rhsName, rhsValue); sl@0: if (!IsParamCompatibleL(lhsName, lhsValue, rhsName, rhsValue)) sl@0: return EFalse; sl@0: } sl@0: } sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: TInt TEquivSip::ListLength(const TDelimitedParserBase8& aParser) const sl@0: { sl@0: aParser.Reset(); sl@0: sl@0: TInt result = 0; sl@0: while (!aParser.Eos()) sl@0: { sl@0: aParser.Inc(); sl@0: ++result; sl@0: } sl@0: sl@0: aParser.Reset(); sl@0: return result; sl@0: } sl@0: sl@0: TBool TEquivSip::IsMatchPathL() const sl@0: { sl@0: HBufC8* lhs = DecodedSegmentLC(iLhs, EUriPath); sl@0: HBufC8* rhs = DecodedSegmentLC(iRhs, EUriPath); sl@0: sl@0: TDelimitedPathSegmentParser8 lhsParser; sl@0: lhsParser.Parse(*lhs); sl@0: TDelimitedPathSegmentParser8 rhsParser; sl@0: rhsParser.Parse(*rhs); sl@0: sl@0: // Check each parameter in the lhs parameter list with those in sl@0: // the rhs parameter list. If at any point a parameter is incompatible sl@0: // we'll return false. sl@0: TBool result = ETrue; sl@0: sl@0: // Alway check the parameter list with the most parameters against the other sl@0: // so that we don't miss any sl@0: TInt lhsLength = ListLength(lhsParser); sl@0: TInt rhsLength = ListLength(rhsParser); sl@0: sl@0: if (lhsLength > rhsLength) sl@0: { sl@0: result = IsParamListCompatibleL(lhsParser, rhsParser); sl@0: } sl@0: else sl@0: { sl@0: result = IsParamListCompatibleL(rhsParser, lhsParser); sl@0: } sl@0: sl@0: // check that the special parameters, if present, are present in both sl@0: if (result) sl@0: { sl@0: if ((lhs->Find(KParamUserFull) == KErrNotFound) != (rhs->Find(KParamUserFull) == KErrNotFound) || sl@0: (lhs->Find(KParamTtlFull) == KErrNotFound) != (rhs->Find(KParamTtlFull) == KErrNotFound) || sl@0: (lhs->Find(KParamMethodFull) == KErrNotFound) != (rhs->Find(KParamMethodFull) == KErrNotFound) || sl@0: (lhs->Find(KParamMaddrFull) == KErrNotFound) != (rhs->Find(KParamMaddrFull) == KErrNotFound) ) sl@0: { sl@0: result = EFalse; sl@0: } sl@0: } sl@0: sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: sl@0: TEquivSip::THeaderType TEquivSip::HeaderType(const TDesC8& aHeaderName) const sl@0: { sl@0: if (IsMatchCaseless(aHeaderName, KHeaderId) || IsMatchCaseless(aHeaderName, KHeaderIdAbbr)) sl@0: return EHeaderId; sl@0: if (IsMatchCaseless(aHeaderName, KHeaderContact) || IsMatchCaseless(aHeaderName, KHeaderContactAbbr)) sl@0: return EHeaderContact; sl@0: if (IsMatchCaseless(aHeaderName, KHeaderEncoding) || IsMatchCaseless(aHeaderName, KHeaderEncodingAbbr)) sl@0: return EHeaderEncoding; sl@0: if (IsMatchCaseless(aHeaderName, KHeaderLength) || IsMatchCaseless(aHeaderName, KHeaderLengthAbbr)) sl@0: return EHeaderLength; sl@0: if (IsMatchCaseless(aHeaderName, KHeaderType) || IsMatchCaseless(aHeaderName, KHeaderTypeAbbr)) sl@0: return EHeaderType; sl@0: if (IsMatchCaseless(aHeaderName, KHeaderFrom) || IsMatchCaseless(aHeaderName, KHeaderFromAbbr)) sl@0: return EHeaderFrom; sl@0: if (IsMatchCaseless(aHeaderName, KHeaderSubject) || IsMatchCaseless(aHeaderName, KHeaderSubjectAbbr)) sl@0: return EHeaderSubject; sl@0: if (IsMatchCaseless(aHeaderName, KHeaderTo) || IsMatchCaseless(aHeaderName, KHeaderToAbbr)) sl@0: return EHeaderTo; sl@0: sl@0: return EHeaderNormal; sl@0: } sl@0: sl@0: TBool TEquivSip::IsMatchHeader(const TDesC8& aLhs, const TDesC8& aRhs) const sl@0: { sl@0: if (IsMatchCaseless(aLhs, aRhs)) sl@0: { sl@0: // identical headers are always OK sl@0: return ETrue; sl@0: } sl@0: sl@0: // We now need to check for abbreviated headers sl@0: TPtrC8 lhsName; sl@0: TPtrC8 lhsValue; sl@0: TPtrC8 rhsName; sl@0: TPtrC8 rhsValue; sl@0: sl@0: GetNameValuePair(aLhs, lhsName, lhsValue); sl@0: GetNameValuePair(aRhs, rhsName, rhsValue); sl@0: sl@0: if (!IsMatchCaseless(lhsValue, rhsValue)) sl@0: { sl@0: // headers with different values can never match sl@0: return EFalse; sl@0: } sl@0: sl@0: // We now have only those with different header names but with the same value sl@0: // The last check is to see if the headers are in abbreviated forms sl@0: THeaderType lhsType = HeaderType(lhsName); sl@0: THeaderType rhsType = HeaderType(rhsName); sl@0: if (lhsType != EHeaderNormal && (lhsType == rhsType)) sl@0: { sl@0: // They are both special headers of the same type sl@0: // Everything matches sl@0: return ETrue; sl@0: } sl@0: sl@0: return EFalse; sl@0: } sl@0: sl@0: TBool TEquivSip::IsQueryListCompatible(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const sl@0: sl@0: { sl@0: TPtrC8 lhsSegment; sl@0: TPtrC8 rhsSegment; sl@0: sl@0: TBool found = EFalse; sl@0: // roll back to the start of the lhs segment parser sl@0: aLhsParser.Reset(); sl@0: sl@0: while( aLhsParser.GetNext(lhsSegment) == KErrNone ) sl@0: { sl@0: // roll back to the start of the rhs segment parser sl@0: aRhsParser.Reset(); sl@0: sl@0: found = EFalse; sl@0: sl@0: while( aRhsParser.GetNext(rhsSegment) == KErrNone ) sl@0: { sl@0: if (IsMatchHeader(lhsSegment, rhsSegment)) sl@0: { sl@0: // a match has been found for this header so move to the next sl@0: // header in the lhs list sl@0: found = ETrue; sl@0: break; sl@0: } sl@0: } sl@0: if (!found) sl@0: { sl@0: // no match has been found so the headers are not equvalent sl@0: return EFalse; sl@0: } sl@0: } sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: TBool TEquivSip::IsMatchQueryL() const sl@0: { sl@0: HBufC8* lhs = DecodedSegmentLC(iLhs, EUriQuery); sl@0: HBufC8* rhs = DecodedSegmentLC(iRhs, EUriQuery); sl@0: sl@0: TDelimitedQueryParser8 lhsParser; sl@0: lhsParser.Parse(*lhs); sl@0: TDelimitedQueryParser8 rhsParser; sl@0: rhsParser.Parse(*rhs); sl@0: sl@0: TBool result = EFalse; sl@0: sl@0: // first check that the number of headers are the same in both lists. sl@0: TInt lhsLength = ListLength(lhsParser); sl@0: TInt rhsLength = ListLength(rhsParser); sl@0: if (lhsLength == rhsLength) sl@0: { sl@0: // Check each parameter in the lhs parameter list with those in sl@0: // the rhs parameter list. If at any point a parameter is incompatible sl@0: // we'll return false. sl@0: result = IsQueryListCompatible(lhsParser, rhsParser); sl@0: } sl@0: sl@0: CleanupStack::PopAndDestroy(2); sl@0: return result; sl@0: } sl@0: sl@0: TBool TEquivSip::IsMatchFragmentL() const sl@0: { sl@0: // We don't care about the fragment for SIP URIs sl@0: return ETrue; sl@0: }