diff -r e4ebb16b39ea -r 603d3f8b6302 plugins/contacts/symbiansim/src/cntsymbiansimengine.cpp --- a/plugins/contacts/symbiansim/src/cntsymbiansimengine.cpp Fri Sep 17 08:34:34 2010 +0300 +++ b/plugins/contacts/symbiansim/src/cntsymbiansimengine.cpp Mon Oct 04 01:37:06 2010 +0300 @@ -529,12 +529,26 @@ f.detailFieldName() == QContactPhoneNumber::FieldNumber && f.matchFlags() == QContactFilter::MatchPhoneNumber) { - QString matchNumber = f.value().toString().right(d->m_phoneNumberMatchLen); QList pns = contact.details(); foreach (QContactPhoneNumber pn, pns) { - QString number = pn.number().right(d->m_phoneNumberMatchLen); - if (number == matchNumber) - return true; + // Best matching enabled + if(d->m_phoneNumberMatchLen == 0) { + bool bestMatchFound(false); + QString matchingNumber = f.value().toString(); + QString numberToMatch = pn.number(); + TRAP_IGNORE( + bestMatchFound = CntSymbianSimPhoneNumberMatching::isBestMatchL(numberToMatch,matchingNumber); + ) + if (bestMatchFound) + return true; + } + else { + // Default matching + QString matchNumber = f.value().toString().right(d->m_phoneNumberMatchLen); + QString number = pn.number().right(d->m_phoneNumberMatchLen); + if (number == matchNumber) + return true; + } } return false; } @@ -543,6 +557,21 @@ } /*! + Returns whether the supplied \a phonenumber is the best matching number. + */ +TBool CntSymbianSimPhoneNumberMatching::isBestMatchL(const QString& numberToMatch, const QString& matchingNumber) +{ + bool bestMatchFound(false); + TPtrC numberPtr(reinterpret_cast(numberToMatch.utf16())); + TPtrC matchNumberPtr(reinterpret_cast(matchingNumber.utf16())); + + if (CntSymbianSimPhoneNumberMatching::validateBestMatchingRulesL(numberPtr,matchNumberPtr)) { + bestMatchFound = true; + } + return bestMatchFound; +} + +/*! * Executes an asynchronous request so that it will appear synchronous. This is * used internally in all synchronous functions. This way we only need to * implement the matching asynchronous request. @@ -593,6 +622,197 @@ CleanupStack::PopAndDestroy(repository); } +/*! + Validates the supplied \a phonenumber against best matching rules. + */ +TBool CntSymbianSimPhoneNumberMatching::validateBestMatchingRulesL(const TDesC& phoneNumber, const TDesC& matchNumber) + { + RBuf numberA; + numberA.CleanupClosePushL(); + numberA.CreateL(matchNumber); + TNumberType numberAType = (TNumberType) CntSymbianSimPhoneNumberMatching::formatAndCheckNumberType(numberA); + RBuf numberB; + numberB.CleanupClosePushL(); + numberB.CreateL(phoneNumber); + TNumberType numberBType = (TNumberType) CntSymbianSimPhoneNumberMatching::formatAndCheckNumberType(numberB); + + TBool match = (!numberB.Compare(numberA) || + CntSymbianSimPhoneNumberMatching::checkBestMatchingRules(numberA, numberAType, numberB, numberBType) || + CntSymbianSimPhoneNumberMatching::checkBestMatchingRules(numberB, numberBType, numberA, numberAType)); + + // cleanup + CleanupStack::PopAndDestroy(2); + return match; + } + +/*! + Removes non-digit chars except plus form the beginning. + Checks if number matches to one of defined types. + */ +TInt CntSymbianSimPhoneNumberMatching::formatAndCheckNumberType(TDes& number) + { + _LIT( KOneZeroPattern, "0*" ); + _LIT( KTwoZerosPattern, "00*" ); + _LIT( KPlusPattern, "+*" ); + const TChar KPlus = TChar('+'); + const TChar KZero = TChar('0'); + const TChar KAsterisk = TChar('*'); + const TChar KHash = TChar('#'); + + for( TInt pos = 0; pos < number.Length(); ++pos ) { + TChar chr = number[pos]; + if ( !chr.IsDigit() && !( pos == 0 && chr == KPlus ) + && !( chr == KAsterisk ) && !( chr == KHash ) ) { + number.Delete( pos, 1 ); + --pos; + } + } + + TInt format; + + if (!number.Match(KTwoZerosPattern) && number.Length() > 2 && number[2] != KZero) { + format = ETwoZeros; + } + else if (!number.Match(KOneZeroPattern)&& number.Length() > 1 && number[1] != KZero) { + format = EOneZero; + } + else if (!number.Match(KPlusPattern) && number.Length() > 1 && number[1] != KZero) { + format = EPlus; + } + else if (number.Length() > 0 && number[0] != KZero && ( ( TChar ) number[0] ).IsDigit()) { + format = EDigit; + } + else { + format = EUnknown; + } + + return format; + } + +TBool CntSymbianSimPhoneNumberMatching::checkBestMatchingRules( + const TDesC& numberA, TNumberType numberAType, + const TDesC& numberB, TNumberType numberBType ) + { + TBool result = EFalse; + + // Rules for matching not identical numbers + // Rules details are presented in Best_Number_Matching_Algorithm_Description.doc + + // rule International-International 1 + if (!result && numberAType == EPlus && numberBType == ETwoZeros) { + TPtrC numberAPtr = numberA.Right(numberA.Length() - 1); + TPtrC numberBPtr = numberB.Right(numberB.Length() - 2); + result = !(numberAPtr.Compare(numberBPtr)); + if (result) { + return result; + } + } + + // rule International-International 2 + if (numberAType == EPlus && numberBType == EDigit) { + TPtrC numberAPtr = numberA.Right( numberA.Length() - 1 ); + if (numberAPtr.Length() < numberB.Length()) { + TPtrC numberBPtr = numberB.Right( numberAPtr.Length() ); + result = !(numberAPtr.Compare(numberBPtr)); + if (result) { + return result; + } + } + } + + // rule International-International 3 + if (numberAType == ETwoZeros && numberBType == EDigit) { + TPtrC numberAPtr = numberA.Right(numberA.Length() - 2); + if (numberAPtr.Length() < numberB.Length()) { + TPtrC numberBPtr = numberB.Right(numberAPtr.Length()); + result = !(numberAPtr.Compare(numberBPtr)); + if (result) { + return result; + } + } + } + + // rule International-Operator 1 + if (numberAType == EOneZero && numberBType == EPlus + || numberAType == EDigit && numberBType == EPlus) { + TPtrC numberAPtr; + if (numberAType == EOneZero) { + numberAPtr.Set(numberA.Right(numberA.Length() - 1)); + } + else { + numberAPtr.Set(numberA); + } + if (numberAPtr.Length() < numberB.Length() - 1) { + TPtrC numberBPtr = numberB.Right(numberAPtr.Length()); + result = !(numberAPtr.Compare(numberBPtr)); + if (result) { + return result; + } + } + } + + // rule International-Operator 2 + if (numberAType == EOneZero && numberBType == ETwoZeros + || numberAType == EDigit && numberBType == ETwoZeros) { + TPtrC numberAPtr; + if (numberAType == EOneZero) { + numberAPtr.Set(numberA.Right(numberA.Length() - 1)); + } + else { + numberAPtr.Set(numberA); + } + if (numberAPtr.Length() < numberB.Length() - 2) { + TPtrC numberBPtr = numberB.Right(numberAPtr.Length()); + result = !(numberAPtr.Compare(numberBPtr)); + if (result) { + return result; + } + } + } + + // rule International-Operator 3 + if (numberAType == EOneZero && numberBType == EDigit + || numberAType == EDigit && numberBType == EDigit) { + TPtrC numberAPtr; + if (numberAType == EOneZero) { + numberAPtr.Set(numberA.Right( numberA.Length() - 1)); + } + else { + numberAPtr.Set(numberA); + } + if (numberAPtr.Length() < numberB.Length()) { + TPtrC numberBPtr = numberB.Right(numberAPtr.Length()); + result = !(numberAPtr.Compare(numberBPtr)); + if (result) { + return result; + } + } + } + + // rule Operator-Operator 1 + if (numberAType == EOneZero && numberBType == EDigit) { + TPtrC numberAPtr = numberA.Right(numberA.Length() - 1); + result = !(numberAPtr.Compare(numberB)); + if (result) { + return result; + } + } + + // rule North America Numbering Plan 1 + if (numberAType == EDigit && numberBType == EPlus) { + TPtrC numberBPtr = numberB.Right(numberB.Length() - 1); + result = !(numberA.Compare(numberBPtr)); + if (result) { + return result; + } + } + + // More exceptional acceptance rules can be added here + // Keep rules updated in the document Best_Number_Matching_Algorithm_Description.doc + + return result; + } + QContactManagerEngine* CntSymbianSimFactory::engine(const QMap& parameters, QContactManager::Error* error) { CntSymbianSimEngine *engine = new CntSymbianSimEngine(parameters, error);