qtcontactsmobility/plugins/contacts/symbian/src/filtering/cntfilterdetail.cpp
changeset 37 fd64c38c277d
parent 27 de1630741fbe
child 40 b46a585f6909
equal deleted inserted replaced
31:2a11b5b00470 37:fd64c38c277d
    58 CntFilterDetail::CntFilterDetail(CContactDatabase& contactDatabase,CntSymbianSrvConnection &cntServer,CntDbInfo& dbInfo) 
    58 CntFilterDetail::CntFilterDetail(CContactDatabase& contactDatabase,CntSymbianSrvConnection &cntServer,CntDbInfo& dbInfo) 
    59                                         : m_contactdatabase(contactDatabase),
    59                                         : m_contactdatabase(contactDatabase),
    60                                           m_srvConnection(cntServer),
    60                                           m_srvConnection(cntServer),
    61                                           m_dbInfo(dbInfo)
    61                                           m_dbInfo(dbInfo)
    62 {
    62 {
    63 
       
    64 }
    63 }
    65 
    64 
    66 CntFilterDetail::~CntFilterDetail()
    65 CntFilterDetail::~CntFilterDetail()
    67 {
    66 {
    68     
       
    69 }
    67 }
    70 
    68 
    71 
    69 
    72 QList<QContactLocalId> CntFilterDetail::contacts(
    70 QList<QContactLocalId> CntFilterDetail::contacts(
    73         const QContactFilter &filter,
    71         const QContactFilter &filter,
    75         bool &filterSupportedflag,
    73         bool &filterSupportedflag,
    76         QContactManager::Error* error)
    74         QContactManager::Error* error)
    77 {
    75 {
    78     Q_UNUSED(filterSupportedflag);
    76     Q_UNUSED(filterSupportedflag);
    79     //Check if any invalid filter is passed 
    77     //Check if any invalid filter is passed 
    80     if(!filterSupported(filter) )
    78     if (!filterSupported(filter) ) {
    81         {
       
    82         *error =  QContactManager::NotSupportedError;
    79         *error =  QContactManager::NotSupportedError;
    83         return QList<QContactLocalId>();
    80         return QList<QContactLocalId>();
    84         }
    81     }
    85     QList<QContactLocalId> idList;
    82     QList<QContactLocalId> idList;
    86     QContactDetailFilter detailFilter(filter);
    83     QContactDetailFilter detailFilter(filter);
    87     QString sqlQuery;
    84     QString sqlQuery;
    88     //Check for phonenumber. Special handling needed
    85     //Check for phonenumber. Special handling needed
    89     if( (detailFilter.detailDefinitionName() == QContactPhoneNumber::DefinitionName ) &&
    86     if ( (detailFilter.detailDefinitionName() == QContactPhoneNumber::DefinitionName ) &&
    90             (detailFilter.detailFieldName() != QContactPhoneNumber::FieldSubTypes))
    87             (detailFilter.detailFieldName() != QContactPhoneNumber::FieldSubTypes)) {
    91     {
       
    92         //Handle phonenumber ...
    88         //Handle phonenumber ...
    93         idList = HandlePhonenumberDetailFilter(filter);
    89         createMatchPhoneNumberQuery(filter,sqlQuery,error);
       
    90         if (*error == QContactManager::NoError) {
       
    91             //fetch the contacts
       
    92             idList =  m_srvConnection.searchContacts(sqlQuery, error);
       
    93         }
    94         
    94         
    95     }
    95     }
    96     else if (detailFilter.matchFlags() == QContactFilter::MatchKeypadCollation) 
    96     else if (detailFilter.matchFlags() == QContactFilter::MatchKeypadCollation) {
    97     {
       
    98         //predictive search filter
    97         //predictive search filter
    99         idList = HandlePredictiveSearchFilter(filter,error);
    98         idList = HandlePredictiveSearchFilter(filter,error);
   100     }
    99     }
   101             
   100             
   102     // handle other cases
   101     // handle other cases
   103     else 
   102     else {
   104     {
       
   105         createSelectQuery(filter,sqlQuery,error);
   103         createSelectQuery(filter,sqlQuery,error);
   106         QString sortQuery = m_dbInfo.getSortQuery(sortOrders, sqlQuery, error);
   104         QString sortQuery = m_dbInfo.getSortQuery(sortOrders, sqlQuery, error);
   107         
   105         
   108         if(*error == QContactManager::NoError)
   106         if (*error == QContactManager::NoError) {
   109             {
       
   110             //fetch the contacts
   107             //fetch the contacts
   111             idList =  m_srvConnection.searchContacts(sortQuery, error);
   108             idList =  m_srvConnection.searchContacts(sortQuery, error);
   112             }
   109         }
   113     }
   110     }
   114     
       
   115     return idList;
   111     return idList;
   116 
   112 }
   117     
       
   118     
       
   119 }
       
   120 
       
   121 
   113 
   122 bool CntFilterDetail::filterSupported(const QContactFilter& filter) 
   114 bool CntFilterDetail::filterSupported(const QContactFilter& filter) 
   123 {
   115 {
   124     bool result = false;
   116     bool result = false;
   125     if(QContactFilter::ContactDetailFilter == filter.type())
   117     if (QContactFilter::ContactDetailFilter == filter.type()) {
   126         {
       
   127         result = true;
   118         result = true;
   128         }
   119     }
   129  
       
   130     return result;
   120     return result;
   131 }
   121 }
   132 
   122 
   133 void CntFilterDetail::createSelectQuery(const QContactFilter& filter,
   123 void CntFilterDetail::createSelectQuery(const QContactFilter& filter,
   134                               QString& sqlQuery,
   124                                         QString& sqlQuery,
   135                               QContactManager::Error* error)
   125                                         QContactManager::Error* error)
   136 
   126 
   137 {
   127 {
   138       if(!filterSupported(filter) )
   128     if (!filterSupported(filter)) {
   139       {
   129       *error = QContactManager::NotSupportedError;
   140           *error = QContactManager::NotSupportedError;
   130       return;
   141           return;
   131     }
   142       }
   132     QContactDetailFilter detailFilter(filter);
   143       QContactDetailFilter detailFilter(filter);
   133     //display label
   144       //display label
   134     if (detailFilter.detailDefinitionName() == QContactDisplayLabel::DefinitionName) {
   145       if (detailFilter.detailDefinitionName() == QContactDisplayLabel::DefinitionName)
   135       CntFilterDetailDisplayLabel displayLabelFilter;
   146        {
   136       displayLabelFilter.createSelectQuery(filter, sqlQuery, error);
   147           CntFilterDetailDisplayLabel displayLabelFilter;
   137     }
   148           displayLabelFilter.createSelectQuery(filter, sqlQuery, error);
   138     //type
       
   139     else if (detailFilter.detailDefinitionName() == QContactType::DefinitionName) {
       
   140        if (detailFilter.value().toString() == QContactType::TypeContact)
       
   141            sqlQuery = "SELECT contact_id FROM contact WHERE (type_flags>>24)=0";
       
   142        else if (detailFilter.value().toString() == QContactType::TypeGroup)
       
   143            sqlQuery = "SELECT contact_id FROM contact WHERE (type_flags>>24)=3";
       
   144     }
       
   145     else if (detailFilter.detailDefinitionName() == QContactGuid::DefinitionName) {
       
   146        if (detailFilter.detailFieldName() == QContactGuid::FieldGuid) {
       
   147            QStringList fullGuidValue = detailFilter.value().toString().split('-');
       
   148            if (fullGuidValue.count() == 3) {
       
   149                QString localGuidValue = fullGuidValue.at(1);
       
   150                sqlQuery = "SELECT contact_id FROM contact WHERE guid_string = '" + localGuidValue + '\'';
       
   151            }
   149        }
   152        }
   150        
   153     }
   151        //type
   154     //everything else
   152        else if(detailFilter.detailDefinitionName() == QContactType::DefinitionName)
   155     else {   
   153        {
   156        QString tableName;
   154            if(detailFilter.value().toString() == QContactType::TypeContact)
   157        QString sqlWhereClause;
   155                sqlQuery = "SELECT contact_id FROM contact WHERE (type_flags>>24)=0";
   158        getTableNameWhereClause(detailFilter,tableName,sqlWhereClause,error);
   156            else if(detailFilter.value().toString() == QContactType::TypeGroup)
   159        //Create the sql query
   157                sqlQuery = "SELECT contact_id FROM contact WHERE (type_flags>>24)=3";
   160        sqlQuery += "SELECT DISTINCT contact_id FROM " + tableName + " WHERE " + sqlWhereClause;
   158        }
   161     }
   159        else if(detailFilter.detailDefinitionName() == QContactGuid::DefinitionName)
   162 }
   160        {
       
   161            if(detailFilter.detailFieldName() == QContactGuid::FieldGuid)
       
   162            {
       
   163                QStringList fullGuidValue = detailFilter.value().toString().split('-');
       
   164                if (fullGuidValue.count() == 3) {
       
   165                    QString localGuidValue = fullGuidValue.at(1);
       
   166                    sqlQuery = "SELECT contact_id FROM contact WHERE guid_string = '" + localGuidValue + '\'';
       
   167                 }
       
   168             }
       
   169        }
       
   170        //everything else
       
   171        else
       
   172        {   
       
   173            QString tableName;
       
   174            QString sqlWhereClause;
       
   175            getTableNameWhereClause(detailFilter,tableName,sqlWhereClause,error);
       
   176            //Create the sql query
       
   177            sqlQuery += "SELECT DISTINCT contact_id FROM " + tableName + " WHERE " + sqlWhereClause;
       
   178        }
       
   179 }
       
   180 
       
   181 
   163 
   182 /*!
   164 /*!
   183  * Updates match flage for columns.
   165  * Updates match flags for columns.
   184  */
   166  */
   185 void CntFilterDetail::updateForMatchFlag( const QContactDetailFilter& filter,
   167 void CntFilterDetail::updateForMatchFlag(const QContactDetailFilter& filter,
   186                                           QString& fieldToUpdate ,
   168                                          QString& fieldToUpdate ,
   187                                           QContactManager::Error* error) const
   169                                          QContactManager::Error* error) const
   188 {
   170 {
   189     // Modify the filed depending on the query
   171     // Modify the filed depending on the query
   190     switch(filter.matchFlags())
   172     switch (filter.matchFlags()) {
   191         {
   173         case QContactFilter::MatchExactly: {
   192             case QContactFilter::MatchExactly:
   174             // Pattern for MatchExactly:
   193                 {
   175             // " ='xyz'"
   194                 // Pattern for MatchExactly:
   176             fieldToUpdate = " ='"
   195                 // " ='xyz'"
   177                            + filter.value().toString() + '\'';
   196                 fieldToUpdate = " ='"
   178             *error = QContactManager::NoError;
   197                                + filter.value().toString() + '\'';
   179             break;
   198                 *error = QContactManager::NoError;
   180         }
   199                 break;
   181         case QContactFilter::MatchContains: {
   200                 }
   182             // Pattern for MatchContains:
   201             case QContactFilter::MatchContains:
   183             // " LIKE '%xyz%'"
   202                 {
   184             fieldToUpdate = " LIKE '%" + filter.value().toString() + "%'" ;
   203                 // Pattern for MatchContains:
   185             *error = QContactManager::NoError;
   204                 // " LIKE '%xyz%'"
   186             break;
   205                 fieldToUpdate = " LIKE '%" + filter.value().toString() + "%'" ;
   187         }
   206                 *error = QContactManager::NoError;
   188         case QContactFilter::MatchStartsWith: {
   207                 break;
   189             // Pattern for MatchStartsWith:
   208                 }
   190             // " LIKE 'xyz%'"
   209             case QContactFilter::MatchStartsWith:
   191             fieldToUpdate = " LIKE '" +  filter.value().toString() + "%'"  ;
   210                 {
   192             *error = QContactManager::NoError;
   211                 // Pattern for MatchStartsWith:
   193             break;
   212                 // " LIKE 'xyz%'"
   194         }
   213                 fieldToUpdate = " LIKE '" +  filter.value().toString() + "%'"  ;
   195         case QContactFilter::MatchEndsWith: {
   214                 *error = QContactManager::NoError;
   196             // Pattern for MatchEndsWith:
   215                 break;
   197             // " LIKE '%xyz'"
   216                 }
   198             fieldToUpdate = " LIKE '%" + filter.value().toString() + '\'' ;
   217             case QContactFilter::MatchEndsWith:
   199             *error = QContactManager::NoError;
   218                 {
   200             break;
   219                 // Pattern for MatchEndsWith:
   201         }
   220                 // " LIKE '%xyz'"
   202         case QContactFilter::MatchFixedString: {
   221                 fieldToUpdate = " LIKE '%" + filter.value().toString() + '\'' ;
   203             *error = QContactManager::NotSupportedError;
   222                 *error = QContactManager::NoError;
   204             break;
   223                 break;
   205         }
   224                 }
   206         case QContactFilter::MatchCaseSensitive: {
   225             case QContactFilter::MatchFixedString:
   207             *error = QContactManager::NotSupportedError;
   226                 {
   208             break;
   227                 *error = QContactManager::NotSupportedError;
   209         }
   228                 break;
   210         default: {
   229                 }
   211             *error = QContactManager::NotSupportedError;
   230             case QContactFilter::MatchCaseSensitive:
   212             break;
   231                 {
   213         }
   232                 *error = QContactManager::NotSupportedError;
   214     }
   233                 break;
   215 }
   234                 }
   216 
   235             default:
   217 void CntFilterDetail::getTableNameWhereClause(const QContactDetailFilter& detailfilter,
   236                 {
   218                                               QString& tableName,
   237                 *error = QContactManager::NotSupportedError;
   219                                               QString& sqlWhereClause ,
   238                 break;
   220                                               QContactManager::Error* error) const
   239                 }
       
   240         }
       
   241         
       
   242 }
       
   243 
       
   244 void CntFilterDetail::getTableNameWhereClause( const QContactDetailFilter& detailfilter,
       
   245                                                QString& tableName,
       
   246                                                QString& sqlWhereClause ,
       
   247                                                QContactManager::Error* error) const
       
   248 {
   221 {
   249     //Get the table name and the column name
   222     //Get the table name and the column name
   250     QString columnName;
   223     QString columnName;
   251     bool isSubType;
   224     bool isSubType;
   252 
   225 
   253     m_dbInfo.getDbTableAndColumnName(detailfilter.detailDefinitionName(), detailfilter.detailFieldName(), tableName, columnName, isSubType);
   226     m_dbInfo.getDbTableAndColumnName(detailfilter.detailDefinitionName(), detailfilter.detailFieldName(), tableName, columnName, isSubType);
   254 
   227 
   255     // return if tableName is empty
   228     // return if tableName is empty
   256     if(tableName.isEmpty())
   229     if (tableName.isEmpty()) {
   257         {
       
   258         *error = QContactManager::NotSupportedError;
   230         *error = QContactManager::NotSupportedError;
   259         return;
   231         return;
   260         }
   232     }
   261 
   233 
   262     //check columnName
   234     //check columnName
   263     if(columnName.isEmpty())
   235     if (columnName.isEmpty()) {
   264         {
       
   265         *error = QContactManager::NotSupportedError;
   236         *error = QContactManager::NotSupportedError;
   266         return;
   237         return;
   267         }
   238     }
   268     else if (isSubType) 
   239     else if (isSubType) {
   269         {
       
   270         sqlWhereClause += columnName;
   240         sqlWhereClause += columnName;
   271         sqlWhereClause += " NOT NULL ";
   241         sqlWhereClause += " NOT NULL ";
   272         }
   242     }
   273     else 
   243     else {
   274         {
       
   275         sqlWhereClause += ' ' + columnName + ' ';
   244         sqlWhereClause += ' ' + columnName + ' ';
   276         QString fieldToUpdate;
   245         QString fieldToUpdate;
   277         //Update the value depending on the match flag
   246         //Update the value depending on the match flag
   278         updateForMatchFlag(detailfilter,fieldToUpdate,error);
   247         updateForMatchFlag(detailfilter,fieldToUpdate,error);
   279         sqlWhereClause +=  fieldToUpdate;
   248         sqlWhereClause +=  fieldToUpdate;
   280         }
   249     }
   281 }
   250 }
   282 
   251 
   283 QList<QContactLocalId>  CntFilterDetail::HandlePredictiveSearchFilter(const QContactFilter& filter,QContactManager::Error* error)
   252 QList<QContactLocalId>  CntFilterDetail::HandlePredictiveSearchFilter(const QContactFilter& filter,
   284     {
   253                                                                       QContactManager::Error* error)
   285     
   254 {
   286     QString sqlQuery;
   255     QString sqlQuery;
   287     
   256     
   288     if(filter.type() == QContactFilter::ContactDetailFilter){
   257     if (filter.type() == QContactFilter::ContactDetailFilter) {
   289        const QContactDetailFilter detailFilter(filter);
   258        const QContactDetailFilter detailFilter(filter);
   290        if(  detailFilter.matchFlags() == QContactFilter::MatchKeypadCollation ){
   259        if (detailFilter.matchFlags() == QContactFilter::MatchKeypadCollation) {
   291        CntSqlSearch sqlSearch;
   260            CntSqlSearch sqlSearch;
   292           //convert string to numeric format
   261            //convert string to numeric format
   293             QString pattern = detailFilter.value().toString();
   262             QString pattern = detailFilter.value().toString();
   294             sqlQuery = sqlSearch.CreatePredictiveSearch(pattern);
   263             sqlQuery = sqlSearch.CreatePredictiveSearch(pattern);
   295             return  m_srvConnection.searchContacts(sqlQuery, error);  
   264             return  m_srvConnection.searchContacts(sqlQuery, error);  
   296            }
   265        }
   297        else
   266        else {
   298            {
       
   299            return QList<QContactLocalId>();
   267            return QList<QContactLocalId>();
   300            }
   268        }
   301         }
   269     }
   302     else
   270     else {
   303         {
       
   304         return QList<QContactLocalId>();
   271         return QList<QContactLocalId>();
   305         }
   272     }
   306     }
   273 }
   307 
   274 
   308 QList<QContactLocalId> CntFilterDetail::HandlePhonenumberDetailFilter(const QContactFilter& filter)
   275 /*
   309     {
   276  * Creates an sql query to fetch contact item IDs for all the contact items
   310     QList<QContactLocalId> matches;
   277  * which may contain the specified telephone number in a telephone, fax
   311     QContactDetailFilter detailFilter(filter);
   278  * or SMS type field.
   312     // Phone numbers need separate handling
   279  *
   313 
   280  * The comparison method used is not exact.  The number is compared starting from
   314     QString number((detailFilter.value()).toString());
   281  * the right side of the number and the method returns an array of candidate
   315     TPtrC commPtr(reinterpret_cast<const TUint16*>(number.utf16()));
   282  * matches.  Punctuation (e.g. spaces) and other alphabetic characters are ignored
   316 
   283  * when comparing.
   317     TInt matchLength(KDefaultMatchLength);
   284  */
   318     // no need to propagate error, we can use the default match length
   285 void CntFilterDetail::createMatchPhoneNumberQuery(
   319     TRAP_IGNORE(getMatchLengthL(matchLength));
   286                                       const QContactFilter& filter,
   320     int actualLength = number.length();
   287                                       QString& sqlQuery,
   321 
   288                                       QContactManager::Error* error)
   322     //call the search
   289 
   323     CContactIdArray* idArray(0);
   290 {
   324     TInt err = searchPhoneNumbers(idArray, commPtr, matchLength);
   291   if (!filterSupported(filter) ) {
   325     if( idArray && (err == KErrNone)){
   292       *error = QContactManager::NotSupportedError;
   326         // copy the matching contact ids
   293       return;
   327         for(int i(0); i < idArray->Count(); i++) {
   294   }
   328             matches.append(QContactLocalId((*idArray)[i]));
   295   
   329         }
   296   QContactDetailFilter detailFilter(filter);
   330         delete idArray;
   297   QString number((detailFilter.value()).toString());
   331     }
   298   TPtrC numberPtr(reinterpret_cast<const TUint16*>(number.utf16()));
   332     else{
   299 
   333         //CntSymbianTransformError::transformError(err, error);
   300   TInt matchLengthFromRight(KDefaultMatchLength);
   334         }
   301   // no need to propagate error, we can use the default match length
   335 
   302   TRAP_IGNORE(getMatchLengthL(matchLengthFromRight));
   336 
   303   
   337     
   304   TInt numLowerDigits = matchLengthFromRight;
   338     return matches;
   305   TInt numUpperDigits = 0;
   339 
   306 
   340     }
   307   if (numLowerDigits > KLowerSevenDigits) {
       
   308       // New style matching.
       
   309       numLowerDigits = KLowerSevenDigits;
       
   310       numUpperDigits = matchLengthFromRight - KLowerSevenDigits;
       
   311   }
       
   312 
       
   313   TMatch phoneDigits = createPaddedPhoneDigits(
       
   314                           numberPtr, numLowerDigits, numUpperDigits, error);
       
   315 
       
   316   if (*error == QContactManager::NoError) {
       
   317       // select fields for contacts that match phone lookup
       
   318       //  SELECT contact_id FROM comm_addr
       
   319       //      WHERE value = [value string] AND type = [type value];
       
   320       //
       
   321       QString type =  QString(" type = %1").arg(CntDbInfo::EPhoneNumber);
       
   322       QString value =  QString(" value = %1").arg(phoneDigits.iLowerSevenDigits);
       
   323       QString extraValue =  QString(" extra_value = %1").arg(phoneDigits.iUpperDigits);
       
   324       QString whereClause = " WHERE" + value + " AND" + type;
       
   325       if (matchLengthFromRight <= KLowerSevenDigits) {
       
   326           // Matching 7 or less digits...
       
   327           sqlQuery = "SELECT contact_id FROM comm_addr" + whereClause;
       
   328       }
       
   329       else {
       
   330           // Checking the upper digits...
       
   331           whereClause += " AND" + extraValue;
       
   332           sqlQuery = "SELECT contact_id FROM comm_addr" + whereClause;
       
   333       }
       
   334   }
       
   335 }
   341 /*
   336 /*
   342  * Get the match length setting. Digits to be used in matching (counted from
   337  * Get the match length setting. Digits to be used in matching (counted from
   343  * right).
   338  * right).
   344  */
   339  */
   345 void CntFilterDetail::getMatchLengthL(TInt& matchLength)
   340 bool CntFilterDetail::getMatchLengthL(TInt& matchLength)
   346 {
   341 {
   347     //Get number of digits used to match
   342     //Get number of digits used to match
       
   343     bool result = false;
   348     CRepository* repository = CRepository::NewL(KCRUidTelConfiguration);
   344     CRepository* repository = CRepository::NewL(KCRUidTelConfiguration);
   349     CleanupStack::PushL(repository);
   345     TInt err = repository->Get(KTelMatchDigits, matchLength);
   350     User::LeaveIfError(repository->Get(KTelMatchDigits, matchLength));
   346     delete repository;
   351     CleanupStack::PopAndDestroy(repository);
   347     
       
   348     result = (err == KErrNone);
       
   349     return result;
   352 }
   350 }
   353 
   351 
   354 /*
   352 /*
   355  * Find contacts based on a phone number.
   353  * Convert the supplied string to a matchable phone number.
   356  * \a idArray On return contains the ids of the contacts that match the phonenumber.
   354  *
   357  * \a phoneNumber The phone number to match
   355  * \param text Descriptor containing phone number.
   358  * \a matchLength Match length; digits from right.
   356  * \param lowerMatchlength Number of least significant phone digits to use.
       
   357  * \param upperMatchLength Number of most significant phone digits to use.
       
   358  * \param error Qt error code.
       
   359  * \return The hash code(s) to use when matching the supplied phone number.
   359  */
   360  */
   360 TInt CntFilterDetail::searchPhoneNumbers(
   361 CntFilterDetail::TMatch CntFilterDetail::createPaddedPhoneDigits(
   361         CContactIdArray*& idArray,
   362                                             const TDesC& number, 
   362         const TDesC& phoneNumber,
   363                                             const TInt numLowerDigits, 
   363         const TInt matchLength)
   364                                             const TInt numUpperDigits,
   364 {
   365                                             QContactManager::Error* error)
   365     CContactIdArray* idArrayTmp(0);
   366 {
   366     TRAPD( err, idArrayTmp = m_contactdatabase.MatchPhoneNumberL(phoneNumber, matchLength));
   367     TMatch phoneNumber = createPhoneMatchNumber(
   367     if(err == KErrNone){
   368                                             number, numLowerDigits, numUpperDigits, error);
   368        idArray = idArrayTmp;
   369     if (*error == QContactManager::NoError) {
   369     }
   370         if (phoneNumber.iNumLowerDigits + phoneNumber.iUpperDigits == 0) {
   370     return 0;
   371             // No digits, do nothing
   371 }
   372         }
       
   373         else if (phoneNumber.iNumLowerDigits < KLowerSevenDigits) {
       
   374             // Only the lower-digits hash is used, pad out the number to
       
   375             // KLowerSevenDigits.
       
   376             TInt pad = KLowerSevenDigits - phoneNumber.iNumLowerDigits;
       
   377             phoneNumber.iLowerSevenDigits = TMatch::padOutPhoneMatchNumber(phoneNumber.iLowerSevenDigits,pad);
       
   378         }
       
   379         else if (phoneNumber.iNumUpperDigits < (KMaxPhoneMatchLength - KLowerSevenDigits) ) {
       
   380             // The lower-digits hash is full, pad out the upper hash if less than 15
       
   381             // digits total.
       
   382             TInt pad = KMaxPhoneMatchLength - KLowerSevenDigits - phoneNumber.iNumUpperDigits;
       
   383             phoneNumber.iUpperDigits = TMatch::padOutPhoneMatchNumber(phoneNumber.iUpperDigits,pad);
       
   384         }
       
   385     }
       
   386     return phoneNumber;
       
   387 }
       
   388 
       
   389 /*
       
   390  * Returns the hash code(s) to use when matching the supplied phone number.  If the
       
   391  * number supplied has more actual phone digits (i.e. not including spaces) than
       
   392  * KLowerSevenDigits, a second hash is generated to hold the remaining most
       
   393  * significant phone digits. Removes the non-digit characters.
       
   394 
       
   395  * \param text Descriptor containing contacts phone number field.
       
   396  * \param lowerMatchlength Number of least significant phone digits to use.
       
   397  * \param upperMatchLength Number of most significant phone digits to use.
       
   398  * \param error Qt error code.
       
   399  * \return The hash code(s) to use when matching the supplied phone number.
       
   400  */
       
   401 CntFilterDetail::TMatch CntFilterDetail::createPhoneMatchNumber(
       
   402                                             const TDesC& text, 
       
   403                                             TInt lowerMatchLength, 
       
   404                                             TInt upperMatchLength,
       
   405                                             QContactManager::Error* error)
       
   406 {
       
   407     const TInt KBufLength = KCntMaxTextFieldLength+1;
       
   408     TBuf<KBufLength> buf;
       
   409     
       
   410     if (text.Length() <= KBufLength) {
       
   411         buf = text;
       
   412     }
       
   413     else {
       
   414         buf = text.Right(KBufLength);
       
   415     }
       
   416     TMatch::stripOutNonDigitChars(buf);
       
   417     
       
   418     TMatch phoneNumber;
       
   419     if (buf.Length() == 0) {
       
   420         *error = QContactManager::BadArgumentError;
       
   421         return phoneNumber;
       
   422     }
       
   423     
       
   424     // Generate a hash for the upper digits only if the phone number string is
       
   425     // large enough and more than 7 digits are to be matched.
       
   426     TInt phoneNumberlength = buf.Length();
       
   427     if ((phoneNumberlength > KLowerSevenDigits) && (upperMatchLength > 0)) {
       
   428         TPtrC upperPart = buf.Left(phoneNumberlength - KLowerSevenDigits);
       
   429         phoneNumber.iUpperDigits = TMatch::createHash(upperPart,
       
   430             upperMatchLength, phoneNumber.iNumUpperDigits);
       
   431     }
       
   432     // Generate a hash of the lower digits.
       
   433     phoneNumber.iLowerSevenDigits = TMatch::createHash(buf, 
       
   434             lowerMatchLength, phoneNumber.iNumLowerDigits);
       
   435     
       
   436     return phoneNumber;
       
   437 }
       
   438 
       
   439 //CntFilterDetail::TMatch constructor.
       
   440 CntFilterDetail::TMatch::TMatch()
       
   441     :
       
   442     iLowerSevenDigits(0),
       
   443     iUpperDigits(0),
       
   444     iNumLowerDigits(0),
       
   445     iNumUpperDigits(0)
       
   446 {
       
   447 }
       
   448 
       
   449 /*
       
   450  * Generates a hash value by reversing the matchLength least significant digits,
       
   451  * ignoring non-digits and zeroes at the end of the number.  Returns error if no phone
       
   452  * digits are supplied.
       
   453 
       
   454  * \param phoneNumberString A descriptor containing a phone number.
       
   455  * \param matchLength The number of digits from the right of the phone number to use.
       
   456  * \param numPhoneDigits The number of digits found in the phone number string.
       
   457  * \param error Qt error code.*
       
   458  * \return An integer representation of the phone number string in reverse.
       
   459  */
       
   460 TInt32 CntFilterDetail::TMatch::createHash(
       
   461                                     const TDesC& phoneNumberString, 
       
   462                                     TInt matchLength, 
       
   463                                     TInt& numPhoneDigits)
       
   464 {
       
   465     TInt phoneNumberLength = phoneNumberString.Length();
       
   466     TInt startIndex = 0;
       
   467     if (phoneNumberLength > matchLength) {
       
   468         startIndex = phoneNumberLength - matchLength;
       
   469     }
       
   470     
       
   471     numPhoneDigits = 0;
       
   472     TUint reversedDigits = 0;
       
   473     TInt mult = 1;
       
   474     
       
   475     for (TInt chrIndex = startIndex; (numPhoneDigits < matchLength) && (chrIndex < phoneNumberLength); chrIndex++) {
       
   476         TChar chr = phoneNumberString[chrIndex];
       
   477         if (chr.IsDigit()) {
       
   478             reversedDigits += (chr.GetNumericValue()) * mult;
       
   479             mult = mult * 10;
       
   480             ++numPhoneDigits;
       
   481         }
       
   482     }
       
   483     return reversedDigits ;
       
   484 }
       
   485 
       
   486 void CntFilterDetail::TMatch::stripOutNonDigitChars(TDes& text)
       
   487 {
       
   488     for (TInt chrPos = 0; chrPos < text.Length(); ++chrPos) {
       
   489         TChar chr = text[chrPos];
       
   490         if (!chr.IsDigit()) {
       
   491             text.Delete(chrPos, 1);
       
   492             --chrPos;
       
   493         }
       
   494     }
       
   495 }
       
   496 
       
   497 TInt32 CntFilterDetail::TMatch::padOutPhoneMatchNumber(TInt32& phoneNumber,
       
   498                                                        TInt padOutLength)
       
   499 {
       
   500     TInt32 result(phoneNumber);
       
   501     const TInt KMult(10);
       
   502     for (TInt i = 0; i < padOutLength; ++i) {
       
   503         result *= KMult;
       
   504     }
       
   505     phoneNumber = result;
       
   506     return result;
       
   507 }