plugins/contacts/symbiansim/src/cntsymbiansimengine.cpp
changeset 5 603d3f8b6302
parent 0 876b1a06bc25
--- 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<QContactPhoneNumber> pns = contact.details<QContactPhoneNumber>();
             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<const TUint16*>(numberToMatch.utf16()));
+    TPtrC matchNumberPtr(reinterpret_cast<const TUint16*>(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<QString, QString>& parameters, QContactManager::Error* error)
 {
     CntSymbianSimEngine *engine = new CntSymbianSimEngine(parameters, error);