/* * Returns an sql query to fetch contact item IDs for all the contact items which may contain * the specified telephone number in a telephone, fax or SMS type field. * * This is improved version of createMatchPhoneNumberQuery method. * The number is compared starting from the right side of the number and * the method returns an array of candidate matches. * Punctuation (e.g. spaces) and other alphabetic characters are ignored * when comparing. Leading zeros are removed. Digits are compared up to * the length of shorter number. */ void CntFilterDetail::bestMatchPhoneNumberQuery(const QContactFilter& filter, QString& sqlQuery, QContactManager::Error* error) { if (!filterSupported(filter) ) { *error = QContactManager::NotSupportedError; return; } QContactDetailFilter detailFilter(filter); QString number((detailFilter.value()).toString()); TPtrC numberPtr(reinterpret_cast<const TUint16*>(number.utf16())); const TInt KUpperMaxLength = KMaxPhoneMatchLength - KLowerSevenDigits; TMatch phoneDigits = createPaddedPhoneDigits(numberPtr, KLowerSevenDigits, KUpperMaxLength, error); if (*error == QContactManager::NoError) { // select fields for contacts that match phone lookup // SELECT contact_id, extra_value FROM comm_addr // WHERE value = [value string] AND type = [type value]; // QString type = QString(" type = %1").arg(CntDbInfo::EPhoneNumber); QString value = QString(" value = %1").arg(phoneDigits.iLowerSevenDigits); QString whereClause = " WHERE" + value + " AND" + type; sqlQuery = "SELECT contact_id, extra_value FROM comm_addr" + whereClause; QList<QPair<QContactLocalId, QString> > contactMatches = m_srvConnection.searchPhoneNumbers(sqlQuery, error); // Check if search query was successful if (*error != QContactManager::NoError) { return; } QStringList list; for (int i=0; i<contactMatches.count(); ++i) { // Check the upper digits... TInt32 number = phoneDigits.iUpperDigits; QString extraValue = contactMatches.at(i).second; TPtrC extValString(reinterpret_cast<const TUint16*>(extraValue.utf16())); TInt32 storedUpperDigits(0); if (TLex(extValString).Val(storedUpperDigits) == KErrNone) { TInt32 stored = storedUpperDigits; TBool nonZeroInStoredFound = EFalse; TBool nonZeroInNumberFound = EFalse; while ((number != 0) && (stored != 0)) { nonZeroInNumberFound |= (number % 10 != 0); nonZeroInStoredFound |= (stored % 10 != 0); if (nonZeroInStoredFound && nonZeroInNumberFound) { break; } number /= 10; stored /= 10; } if ((phoneDigits.iUpperDigits == 0) || (storedUpperDigits == 0) || (number == stored)) { list.append(QString("%1").arg(contactMatches.at(i).first)); } } else { *error = QContactManager::UnspecifiedError; return; } } // Recreate query to fetch all match ids // SELECT DISTINCT contact_id FROM contact WHERE contact_id in ( // .. // ) QString ids = list.join(" ,"); sqlQuery = "SELECT DISTINCT contact_id FROM contact WHERE contact_id in ("; sqlQuery += ids; sqlQuery += ')'; } }
/* * Creates an sql query to fetch contact item IDs for all the contact items * which may contain the specified telephone number in a telephone, fax * or SMS type field. * * The comparison method used is not exact. The number is compared starting from * the right side of the number and the method returns an array of candidate * matches. Punctuation (e.g. spaces) and other alphabetic characters are ignored * when comparing. * * Note that due to the way numbers are stored in the database, it is recommended * that at least 7 match digits are specified even when matching a number * containing fewer digits. Failure to follow this guideline may (depending on the * database contents) mean that the function will not return the expected Contact * IDs. */ void CntFilterDetail::createMatchPhoneNumberQuery( const QContactFilter& filter, QString& sqlQuery, QContactManager::Error* error) { if (!filterSupported(filter) ) { *error = QContactManager::NotSupportedError; return; } QContactDetailFilter detailFilter(filter); QString number((detailFilter.value()).toString()); TPtrC numberPtr(reinterpret_cast<const TUint16*>(number.utf16())); TInt matchLengthFromRight(KDefaultMatchLength); // no need to propagate error, we can use the default match length TRAP_IGNORE(getMatchLengthL(matchLengthFromRight)); TInt numLowerDigits = matchLengthFromRight; TInt numUpperDigits = 0; if (numLowerDigits > KLowerSevenDigits) { numLowerDigits = KLowerSevenDigits; numUpperDigits = matchLengthFromRight - KLowerSevenDigits; } else if (numLowerDigits == 0) { // best match phonenumbers numLowerDigits = KLowerSevenDigits; } TMatch phoneDigits = createPaddedPhoneDigits( numberPtr, numLowerDigits, numUpperDigits, error); if (*error == QContactManager::NoError) { // select fields for contacts that match phone lookup // SELECT contact_id FROM comm_addr // WHERE value = [value string] AND type = [type value]; // QString type = QString(" type = %1").arg(CntDbInfo::EPhoneNumber); QString value = QString(" value = %1").arg(phoneDigits.iLowerSevenDigits); QString whereClause = " WHERE" + value + " AND" + type; if (matchLengthFromRight <= KLowerSevenDigits) { // Matching 7 or less digits... sqlQuery = "SELECT contact_id FROM comm_addr" + whereClause; } else { // Checking the upper digits... // select fields for contacts that match phone lookup // SELECT contact_id, extra_value FROM comm_addr // WHERE value = [value string] AND type = [type value]; // QString type = QString(" type = %1").arg(CntDbInfo::EPhoneNumber); QString value = QString(" value = %1").arg(phoneDigits.iLowerSevenDigits); QString whereClause = " WHERE" + value + " AND" + type; sqlQuery = "SELECT contact_id, extra_value FROM comm_addr" + whereClause; QList<QPair<QContactLocalId, QString> > contactMatches = m_srvConnection.searchPhoneNumbers(sqlQuery, error); // Check if search query was successful if (*error != QContactManager::NoError) { return; } QStringList list; for (int i=0; i<contactMatches.count(); ++i) { // Check the upper digits... TInt32 storedUpperDigits(0); QString extraValue = contactMatches.at(i).second; TPtrC extValString(reinterpret_cast<const TUint16*>(extraValue.utf16())); if (TLex(extValString).Val(storedUpperDigits) == KErrNone) { const TInt KDigitsToRemove = KMaxPhoneMatchLength - KLowerSevenDigits - phoneDigits.iNumUpperDigits; for (TInt j = 0; j < KDigitsToRemove; ++j) { // repeatedly divide by 10 to lop off the appropriate number of digits from the right storedUpperDigits /= 10; } storedUpperDigits = TMatch::padOutPhoneMatchNumber(storedUpperDigits, KDigitsToRemove); if (phoneDigits.iUpperDigits == storedUpperDigits) { list.append(QString("%1").arg(contactMatches.at(i).first)); } } else { *error = QContactManager::UnspecifiedError; } } // Recreate query to fetch all match ids // SELECT DISTINCT contact_id FROM contact WHERE contact_id in ( // .. // ) QString ids = list.join(" ,"); sqlQuery = "SELECT DISTINCT contact_id FROM contact WHERE contact_id in ("; sqlQuery += ids; sqlQuery += ')'; } // refine search if (bestMatchingEnabled()) { QList<QContactLocalId> list = m_srvConnection.searchContacts(sqlQuery,error); QList<QContactLocalId> bestMatchingIds; if (*error == QContactManager::NoError) { TRAP_IGNORE( bestMatchingIds = getBestMatchPhoneNumbersL(number, list, error); ) if (bestMatchingIds.count()>0) { // recreate query QString selectQuery = " SELECT contact_id FROM comm_addr WHERE contact_id in ("; QString ids = QString("%1").arg(bestMatchingIds.at(0)); for(int i=1; i<bestMatchingIds.count(); ++i) { ids += QString(" ,%1").arg(bestMatchingIds.at(i)); } selectQuery += ids + ')'; sqlQuery = selectQuery; } else { // empty list QString selectQuery = " SELECT contact_id FROM comm_addr WHERE contact_id in (null)"; sqlQuery = selectQuery; } }
/** Returns an array of contact item IDs for all the contact items which may contain the specified telephone number in a telephone, fax or SMS type field. The comparison method used is not exact. The number is compared starting from the right side of the number and the method returns an array of candidate matches. Punctuation (e.g. spaces) and other alphabetic characters are ignored when comparing. Additionally, if the Contacts Model Phone Parser (CNTPHONE.DLL) is available, then any DTMF digits are also excluded from the comparision. Note that due to the way numbers are stored in the database, it is recommended that at least 7 match digits are specified even when matching a number containing fewer digits. Failure to follow this guideline may (depending on the database contents) mean that the function will not return the expected Contact IDs. @param aNumber Phone number string. @param aMatchLengthFromRight Number of digits from the right of the phone number to use. Up to 15 digits can be specified, and it is recommended that at least 7 match digits are specified. @param aDatabase The database. @return Array of contact IDs which are candidate matches. */ CContactIdArray* CPplCommAddrTable::MatchPhoneNumberL(const TDesC& aNumber, const TInt aMatchLengthFromRight) { CContactIdArray* phoneMatchArray = CContactIdArray::NewLC(); TInt numLowerDigits = aMatchLengthFromRight; TInt numUpperDigits = 0; if(numLowerDigits > KLowerSevenDigits) { // New style matching. numLowerDigits = KLowerSevenDigits; numUpperDigits = aMatchLengthFromRight - KLowerSevenDigits; } TMatch phoneDigits = CreatePaddedPhoneDigitsL(aNumber, numLowerDigits, numUpperDigits); if (phoneDigits.iNumLowerDigits + phoneDigits.iNumUpperDigits > 0) { // build statement RSqlStatement stmnt; CleanupClosePushL(stmnt); stmnt.PrepareL(iDatabase, iMatchSelectStmnt->SqlStringL() ); const TInt KValueParamIndex(KFirstParam); // first parameter in query... const TInt KTypeParamIndex(KValueParamIndex + 1); // ...and the second. User::LeaveIfError(stmnt.BindInt(KValueParamIndex, phoneDigits.iLowerSevenDigits )); User::LeaveIfError(stmnt.BindInt(KTypeParamIndex, EPhoneNumber )); // fetch the list of any matching contact ids TInt err(KErrNone); const TInt KContactIdIdx(iMatchSelectStmnt->ParameterIndex(KCommAddrContactId() ) ); const TInt KExtraValueIdx(iMatchSelectStmnt->ParameterIndex(KCommAddrExtraValue() ) ); while ((err = stmnt.Next() ) == KSqlAtRow) { if (aMatchLengthFromRight <= KLowerSevenDigits) { // Matching 7 or less digits...we've already matched. phoneMatchArray->AddL(stmnt.ColumnInt(KContactIdIdx) ); } else { // Check the upper digits... TInt32 storedUpperDigits(0); TPtrC extValString = stmnt.ColumnTextL(KExtraValueIdx); User::LeaveIfError(TLex(extValString).Val(storedUpperDigits) ); const TInt KDigitsToRemove = KMaxPhoneMatchLength - KLowerSevenDigits - phoneDigits.iNumUpperDigits; for(TInt i = 0; i < KDigitsToRemove; ++i) { // repeatedly divide by 10 to lop off the appropriate number of digits from the right storedUpperDigits /= 10; } storedUpperDigits = TMatch::PadOutPhoneMatchNumber(storedUpperDigits, KDigitsToRemove); if (phoneDigits.iUpperDigits == storedUpperDigits) { phoneMatchArray->AddL(stmnt.ColumnInt(KContactIdIdx) ); } } } // leave if we didn't complete going through the results properly if(err != KSqlAtEnd) { User::Leave(err); } CleanupStack::PopAndDestroy(&stmnt); } CleanupStack::Pop(phoneMatchArray); return phoneMatchArray; }