diff -r ebe688cedc25 -r 7fdbb852d323 mmsengine/genutils/src/mmsgenutils.cpp --- a/mmsengine/genutils/src/mmsgenutils.cpp Tue Aug 31 15:11:31 2010 +0300 +++ b/mmsengine/genutils/src/mmsgenutils.cpp Wed Sep 01 12:31:54 2010 +0100 @@ -28,22 +28,39 @@ #include // resource file #include #include // e-mail utilities -#include "cimconvertcharconv.h" -#include "cimconvertheader.h" + #include // CharConv #include #include #include +#ifndef SYMBIAN_ENABLE_SPLIT_HEADERS #include +#else +#include +#include +#endif #include #include -// #include +#include #include #include #include - -#include "telconfigcrkeys.h" +#include +#include +#include +#include // Contact store configuration +#include // contact match wrapper +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "mmsgenutils.h" #include "MmsEnginePrivateCRKeys.h" @@ -52,17 +69,16 @@ // EXTERNAL FUNCTION PROTOTYPES // CONSTANTS - +const TInt KLogBufferLength = 256; #ifdef _DEBUG -const TInt KLogBufferLength = 256; _LIT( KLogDir, "mmsc" ); _LIT( KLogFile, "mmsc.txt" ); #endif - +const TUint KMinAliasMaxLength = 14; const TUint KExtraSpaceForConversion10 = 10; const TUint KExtraSpaceForConversion30 = 30; - +const TInt KErrMultipleMatchFound = KErrGeneral; // MACROS // LOCAL CONSTANTS AND MACROS @@ -419,12 +435,18 @@ // --------------------------------------------------------- // EXPORT_C TInt TMmsGenUtils::GetAlias( - const TDesC& /*aAddress*/, - TDes& /*aAlias*/, - TInt /*aMaxLength*/, - RFs& /*aFs*/ ) + const TDesC& aAddress, + TDes& aAlias, + TInt aMaxLength, + RFs& aFs ) { - return KErrNone; + TInt err = KErrNone; + TRAP( err, DoGetAliasL( aFs, aAddress, aAlias, aMaxLength ) ); + if ( err == KErrNotFound ) + { + err = KErrNone; + } + return err; } @@ -437,13 +459,59 @@ // --------------------------------------------------------- // EXPORT_C void TMmsGenUtils::GetAliasForAllL( - const CDesCArray& /*aAddress*/, - CDesCArray& /*aAlias*/, - TInt /*aMaxLength*/, - RFs& /*aFs*/ ) + const CDesCArray& aAddress, + CDesCArray& aAlias, + TInt aMaxLength, + RFs& aFs ) { - + if ( aMaxLength <= 0 ) + { + User::Leave( KErrArgument ); + } + + TUint stack = 0; + + //Let's find the number of digits to match + TInt digitsToMatch = DigitsToMatch(); + TInt err = KErrNone; + + // Use contact wrapper to open all databases + CContactMatcher* contactMatcher = OpenAllStoresL( aFs ); + CleanupStack::PushL( contactMatcher ); + stack++; + + HBufC* helpBuffer = HBufC::NewL( aMaxLength ); + CleanupStack::PushL( helpBuffer ); + stack++; + + TPtr pHelpBuffer = helpBuffer->Des(); + + for ( TInt i = 0; i < aAddress.MdcaCount(); i++ ) + { + // We trap these one by one in order to be able + // to continue to next match in case of error (not found) + + // make sure the alias is empty if nothing found + pHelpBuffer.Zero(); + + TRAP( err, DoGetAliasL( + aAddress.MdcaPoint(i), + pHelpBuffer, + aMaxLength, + *contactMatcher, + digitsToMatch ) ); + + // if alias is not found, we'll have an empty buffer + // We have to insert it anyway to keep the indexes correct + // as we have two parallel arrays + aAlias.InsertL( i, pHelpBuffer ); + } + + // closing is best effort only. + TRAP_IGNORE( contactMatcher->CloseStoresL() ); + CleanupStack::PopAndDestroy( stack, contactMatcher ); //contactMatcher, helpBuffer + } // --------------------------------------------------------- @@ -736,12 +804,40 @@ // --------------------------------------------------------- // void TMmsGenUtils::DoGetAliasL( - RFs& /*aFs*/, - const TDesC& /*aAddress*/, - TDes& /*aAlias*/, - TInt /*aMaxLength*/ ) + RFs& aFs, + const TDesC& aAddress, + TDes& aAlias, + TInt aMaxLength ) { - + + //Let's find the number of digits to match + TInt digitsToMatch = DigitsToMatch(); + + // We have only one address and one alias to put into the array + CDesCArray* aliasArray = new ( ELeave )CDesCArrayFlat( 1 ); + CleanupStack::PushL( aliasArray ); + + CDesCArray* realAddressArray = new ( ELeave )CDesCArrayFlat( 1 ); + CleanupStack::PushL( realAddressArray ); + + realAddressArray->InsertL( 0, aAddress ); + + // GetAliasForAllL opens contact matcher + GetAliasForAllL( *realAddressArray, *aliasArray, aMaxLength, aFs ); + + TInt size = aliasArray->MdcaCount(); + + if ( size > 0 ) + { + // only one item in our array + aAlias.Copy( aliasArray->MdcaPoint( 0 ).Left( Min( aMaxLength, aAlias.MaxLength() ) ) ); + } + + CleanupStack::PopAndDestroy( realAddressArray ); + CleanupStack::PopAndDestroy( aliasArray ); + + return; + } @@ -750,12 +846,151 @@ // --------------------------------------------------------- // void TMmsGenUtils::DoGetAliasL( - const TDesC& /*aAddress*/, - TDes& /*aAlias*/, - TInt /*aMaxLength*/, - CContactMatcher& /*aContactMatcher*/, - TInt /*aDigitsToMatch*/ ) + const TDesC& aAddress, + TDes& aAlias, + TInt aMaxLength, + CContactMatcher& aContactMatcher, + TInt aDigitsToMatch ) { + // It appears that with the new phonebook system with multiple phonebooks, + // TContactItemId type id cannot be extracted. + // The result contains MVPbkContactLink type objects. + + // The given descriptor has to be at least 14 in length + // (otherwise this method would leave later) + if( aAlias.MaxLength() < KMinAliasMaxLength ) + { + User::Leave( KErrBadDescriptor ); + } + + // These should be inline with each other, but if necessary, + // size down aMaxLength. + // aMaxLength, however, can be smaller than the buffer + if ( aMaxLength > aAlias.MaxLength() ) + { + aMaxLength = aAlias.MaxLength(); + } + + if ( aMaxLength > 0 ) + { + // set length of alias to 0 + // this can be used to determine if alias was found + // contact id not needed or used + aAlias.Zero(); + } + + // Convert to real address just in case. The address should be pure already, + // but we are just being paranoid... + + TPtrC realAddress; + realAddress.Set( PureAddress( aAddress, KSepaOpen, KSepaClose ) ); + CVPbkContactLinkArray* linkArray = CVPbkContactLinkArray::NewL(); + CleanupStack::PushL( linkArray ); + + // Check if the address is phone number or EMail address + if ( IsValidMMSPhoneAddress( realAddress, ETrue ) ) + { + // Lookup the telephone number in the contact database + // For numbers shorter than 7 digits, only exact matches are returned + + aContactMatcher.MatchPhoneNumberL( realAddress, aDigitsToMatch, + CVPbkPhoneNumberMatchStrategy::EVPbkMatchFlagsNone, *linkArray ); + + // If more than one matches have been found, + // the first one will be used. + } + else if ( IsValidEmailAddress( realAddress ) ) + { + // Try to match with EMail address + + TVPbkFieldVersitProperty prop; + CVPbkFieldTypeRefsList* fieldTypes = CVPbkFieldTypeRefsList::NewL(); + CleanupStack::PushL( fieldTypes ); + + const MVPbkFieldTypeList& fieldTypeList = aContactMatcher.FieldTypes(); + const MVPbkFieldType* foundType = NULL; + + prop.SetName( EVPbkVersitNameEMAIL ); +/* + // Remove code because matching matches properies, too. + // We don't care about properties. + + // The phonebook should provide a function that allows mathcing name only + foundType = fieldTypeList.FindMatch( prop, 0 ); + + if ( foundType ) + { + fieldTypes->AppendL( *foundType ); + } +*/ + + // The field type matching does not work because it tries to match + // parameters we are not interested in. + // We try to generate a list that has all entries with versit type EMAIL + + TInt i; + for ( i = 0; i < fieldTypeList.FieldTypeCount(); i++ ) + { + foundType = &(fieldTypeList.FieldTypeAt( i )); + if ( foundType->VersitProperties().Count() > 0 + && foundType->VersitProperties()[0].Name() == prop.Name() ) + { + fieldTypes->AppendL( *foundType ); + } + } + + + // Here we stop at first match - email addresses should be unique + aContactMatcher.MatchDataL( realAddress, *fieldTypes, *linkArray ); + CleanupStack::PopAndDestroy( fieldTypes ); + } + else + { + User::Leave( KErrNotFound ); + } + + TInt nameIndex = 0; //correct index if only one match is found + if( linkArray->Count() == 0 ) + { + Log( _L( "No match found" ) ); + User::Leave( KErrNotFound ); + } + else if( linkArray->Count() > 1 ) + { + //Multiple matches found. Get the current store single match index if any. + nameIndex = GetCurrentStoreIndexL( *linkArray ); + if( nameIndex == KErrMultipleMatchFound ) + { + /* No unique match in current store, Hence show the name only if all the matches have + * identical names + */ + if( ShowContactNameL( linkArray, nameIndex, aContactMatcher) == EFalse) + { + Log( _L( "No (Perfect) match found" ) ); + User::Leave( KErrMultipleMatchFound ); + } + } + } + + // if not interested in alias, skip this + if ( aMaxLength > 0 ) + { + HBufC* alias = GetContactNameL( linkArray->At(nameIndex), aContactMatcher ); + if ( alias && alias->Des().Length() > 0 ) + { + aAlias.Copy( alias->Des().Left( aMaxLength ) ); + } + else + { + aAlias.Copy( TPtrC() ); + } + delete alias; + alias = NULL; + // end of part skipped if not interested in alias + } + + linkArray->ResetAndDestroy(); + CleanupStack::PopAndDestroy( linkArray ); } // --------------------------------------------------------- @@ -1193,17 +1428,16 @@ // TMmsGenUtils::OpenAllStoresL // // --------------------------------------------------------- -CContactMatcher* TMmsGenUtils::OpenAllStoresL( RFs& /*aFs*/ ) +CContactMatcher* TMmsGenUtils::OpenAllStoresL( RFs& aFs ) { // Use contact wrapper to open all databases - /* CContactMatcher* contactMatcher = CContactMatcher::NewL( &aFs ); + CContactMatcher* contactMatcher = CContactMatcher::NewL( &aFs ); CleanupStack::PushL( contactMatcher ); contactMatcher->OpenDefaultMatchStoresL(); CleanupStack::Pop( contactMatcher ); - return contactMatcher;*/ - return NULL; + return contactMatcher; } // ----------------------------------------------------------------------------- @@ -1211,11 +1445,21 @@ // ----------------------------------------------------------------------------- // HBufC* TMmsGenUtils::GetContactNameL( - const MVPbkContactLink& /*aContactLink*/, - CContactMatcher& /*aContactMatcher*/) + const MVPbkContactLink& aContactLink, + CContactMatcher &aContactMatcher) { - - return NULL; + Log(_L( "- TMmsGenUtils::GetContactNameL -> start" ) ); + MVPbkStoreContact* tempContact; + aContactMatcher.GetStoreContactL(aContactLink, &tempContact); + tempContact->PushL(); + + MVPbkStoreContactFieldCollection& coll = tempContact->Fields(); + HBufC* nameBuff = aContactMatcher.GetNameL( coll ); + + CleanupStack::PopAndDestroy(tempContact); // tempContact + + Log( _L( "- TMmsGenUtils::GetContactNameL <- end" ) ); + return nameBuff; } // ----------------------------------------------------------------------------- @@ -1243,21 +1487,154 @@ // ----------------------------------------------------------------------------- // TBool TMmsGenUtils::ShowContactNameL( - CVPbkContactLinkArray* /*aLinkArray*/, - TInt& /*aNameIndex*/, - CContactMatcher& /*aContactMatcher*/) + CVPbkContactLinkArray* aLinkArray, + TInt &aNameIndex, + CContactMatcher &aContactMatcher) { - return 0; + Log( _L("- TMmsGenUtils::ShowContactName -> start") ); + Log( _L("Contact Match statistics to follow..." ) ); + Log( _L("Match count: %d"), aLinkArray->Count() ); + /* TODO:: compare the names upto standard + * 1. if all the names are same - display the name + * eg: "abcdef xyz" && "abcdef xyz" + * 2. find min name legth among all,(if ONLY Part-match is needed ) + * if this length is > standard length and matches upto standard length - display the larger name. + * eg: abcdef xyz123, abcdef xyz12, abcdef xyz and std length is 10, + * since match upto 10 chars is fine, display abcdef xyz123 + * 3. in any other case do not show name + * eg: abcdef xyz , abcde xyz + * abcdef xyz , abcdef xy + * abcdef xyz , abcde + */ + TInt i, minLength = 999, maxLength = 0, length = 0, maxLengthIndex = 0, stdLength = 14; + TBool retVal = ETrue ; + + for( i = 0 ; i < aLinkArray->Count(); i++ ) + { + HBufC* alias = GetContactNameL( aLinkArray->At(i), aContactMatcher ); + Log( _L(":-> %s" ), alias->Des().PtrZ()); + length = alias->Des().Length(); + if(minLength > length) + { + minLength = length; + } + if(maxLength < length) + { + maxLength = length; + maxLengthIndex = i; + } + delete alias; + alias = NULL; + } + + Log( _L( "Contact Lengths: Std Length : %d\n MinLength : %d\n MaxLength : %d\n MaxLen index: %d" ), + stdLength, + minLength, + maxLength, + maxLengthIndex); + + if(minLength != maxLength) + { + //complete length match not possible + retVal = EFalse; + + /* NOTE: + * Uncomment below code if partial length(upto stdLength) match is sufficient, + * ensure stdLength is correct + */ + /* + if(minLength < stdLength) + { + retVal = EFalse; + } + */ + } + + if( retVal ) + { + TInt ret; + HBufC* longestName = GetContactNameInLowerCaseL( aLinkArray->At(maxLengthIndex), aContactMatcher ); + Log( _L( "Longest name:-> %s" ), longestName->Des().PtrZ()); + for ( i = 0; i < aLinkArray->Count() && retVal; i++ ) + { + HBufC* nameI = GetContactNameInLowerCaseL( aLinkArray->At(i), aContactMatcher ); + Log( _L( "compared with -> %s" ), nameI->Des().PtrZ()); + ret = longestName->Find(nameI->Des()); + if(ret == KErrNotFound || ret != 0) + { + Log( _L( "Part/Full Match error/offset: %d" ), ret); + retVal = EFalse; + } + delete nameI; + nameI = NULL; + } + delete longestName; + longestName = NULL; + } + + aNameIndex = maxLengthIndex; + + Log( _L( "Final Match result : %d\n Final Match index : %d" ), retVal, maxLengthIndex); + Log( _L( "- TMmsGenUtils::ShowContactName <- end" ) ); + + return retVal; } // ----------------------------------------------------------------------------- // TMmsGenUtils::GetCurrentStoreIndexL // ----------------------------------------------------------------------------- // -TInt TMmsGenUtils::GetCurrentStoreIndexL( CVPbkContactLinkArray& /*aLinkArray*/ ) +TInt TMmsGenUtils::GetCurrentStoreIndexL( CVPbkContactLinkArray& aLinkArray ) { - - return 0; + TInt curStoreIndex( KErrMultipleMatchFound ); + TInt curStoreMatchCount = 0; + RArray otherStoreMatchIndices; + CleanupClosePushL( otherStoreMatchIndices ); + + //Get the current configured contact store array(s) + CPbk2StoreConfiguration* storeConfiguration = CPbk2StoreConfiguration::NewL(); + CleanupStack::PushL( storeConfiguration ); + CVPbkContactStoreUriArray* currStoreArray = storeConfiguration->CurrentConfigurationL(); + CleanupStack::PopAndDestroy(storeConfiguration); + + if ( currStoreArray ) + { + /* Contact's store is compared against user selected stores. + * If contact is from such store, found index is incremented + * else, other store contact indices are populated into array for further use + */ + for ( TInt i = 0; i < aLinkArray.Count(); i++ ) + { + TVPbkContactStoreUriPtr uri = aLinkArray.At(i).ContactStore().StoreProperties().Uri(); + if ( currStoreArray->IsIncluded( uri ) ) + { + // Set index to found contact and increment the count. + curStoreIndex = i; + curStoreMatchCount++; + } + else + { + otherStoreMatchIndices.AppendL(i); + } + } + + delete currStoreArray; + if ( curStoreMatchCount > 1) + { + /* Multiple matches found from current user selected store(s) + * Delete match from other stores in aLinkArray. New aLinkArray should only contain + * current store contact matches, so that next level pruning can be done(e.g, names can be + * compared and displayed if they are identical). + */ + for(TInt i = otherStoreMatchIndices.Count() - 1; i >= 0; i--) + { + aLinkArray.Delete( otherStoreMatchIndices[i] ); + } + curStoreIndex = KErrMultipleMatchFound; + } + } + CleanupStack::PopAndDestroy( &otherStoreMatchIndices ); + return curStoreIndex; } // ================= OTHER EXPORTED FUNCTIONS ==============