diff -r 000000000000 -r 094583676ce7 wvuing/wvuieng/EngSrc/CCAGroupManager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wvuing/wvuieng/EngSrc/CCAGroupManager.cpp Thu Dec 17 08:41:52 2009 +0200 @@ -0,0 +1,1991 @@ +/* +* Copyright (c) 2002-2005 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Network operations for chat group handling. + * +*/ + +// INCLUDE FILES +#include "ChatDebugPrint.h" + +#include "CCAGroupManager.h" + +#include "CCAStorageManagerFactory.h" +#include "MCASettings.h" +#include "MCASearchData.h" +#include "MCASearchInterface.h" +#include "MCAStoredGroups.h" +#include "MCAStoredGroup.h" +#include "MCAExtendedStoredGroup.h" +#include "MCAGroupOperations.h" +#include "CCAGroupWrapper.h" +#include "PrivateEngineDefinitions.h" +#include "TStorageManagerGlobals.h" +#include "CCARequest.h" +#include "CCARequestMapper.h" +#include "MCAChatInterface.h" +#include "MCAMessagesWriteInterface.h" +#include "MCAMessageUtils.h" +#include "MCAMessageCreator.h" +#include "ImpsCSPAllErrors.h" +#include "MCAImpsFactory.h" + +#include "CAUtils.h" +#include "camessageutil.h" + +#include +#include +#include + +// for resources +#include +#include + +// CONSTANTS +const TInt KCCAGMGroupWrappersGranularity = 5; +const TInt KSearchPairsSmallGranularity = 1; +const TInt KMaxUserSearchLimit = 100; + +// indexes to additional data array inside request +const TInt KReqCreateIndexGroupId = 0; +const TInt KReqCreateIndexScreenName = 2; +const TInt KReqCreateIndexWelcomeMsg = 3; +const TInt KReqCreateIndexGroupTopic = 4; + +const TInt KReqJoinIndexGroupId = 0; +const TInt KReqJoinIndexScreenName = 1; + +// how many times should we try to generate unique group id +const TInt KMaxGroupIds = 100; + +// maximum groups in search result. If search results +// exceeds this then "too many search results" is shown +const TInt KMaxGroupSearchLimit = 50; + + +// ================= MEMBER FUNCTIONS ======================= + +// Symbian OS default constructor can leave. +void CCAGroupManager::ConstructL() + { + iStoredGroups = CCAStorageManagerFactory::GroupListInterfaceL(); + } + +// Two-phased constructor. +CCAGroupManager* CCAGroupManager::NewL( + MCASearchInterface& aSearchAPI, + MCASettings& aSettingsAPI, + CCARequestMapper& aRequestMapper, + MCAImpsFactory* aIMPSFactory, + MCAChatInterface& aChatInterface, + MCAMessageUtils& aMessageUtils ) + { + CCAGroupManager* self = new ( ELeave ) CCAGroupManager( aSearchAPI, + aSettingsAPI, aRequestMapper, aIMPSFactory, + aChatInterface, aMessageUtils ); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + + return self; + } + +// Destructor +CCAGroupManager::~CCAGroupManager() + { + iGroupWrappers.ResetAndDestroy(); + delete iProperties; + delete iPrivProperties; + } + +// C++ default constructor can NOT contain any code, that +// might leave. +// +CCAGroupManager::CCAGroupManager( + MCASearchInterface& aSearchAPI, + MCASettings& aSettingsAPI, + CCARequestMapper& aRequestMapper, + MCAImpsFactory* aIMPSFactory, + MCAChatInterface& aChatInterface, + MCAMessageUtils& aMessageUtils ) + : iRequestMapper( aRequestMapper ), + iSettingsAPI( aSettingsAPI ), + iSearchAPI( aSearchAPI ), + iImpsFactory( aIMPSFactory ), + iChatInterface( aChatInterface ), + iMessageUtils( aMessageUtils ), + iGroupWrappers( KCCAGMGroupWrappersGranularity ) + { + } + +// --------------------------------------------------------- +// CCAGroupManager::PopulateCreatedGroupsL +// --------------------------------------------------------- +// +TInt CCAGroupManager::PopulateCreatedGroupsL( CDesCArray& aGroupList ) const + { + CHAT_DP_FUNC_ENTER( "PopulateCreatedGroupsL" ); + + // Reset the given array to be sure that it will be valid + aGroupList.Reset(); + + HBufC* loggedUserId = iSettingsAPI.ValueL( MCASettings::EOwnWVUserID ); + CleanupStack::PushL( loggedUserId ); + + CSearchPairs* pairs = + new ( ELeave ) CSearchPairs( KSearchPairsSmallGranularity ); + CleanupStack::PushL( pairs ); + + CImpsSearchRequest* request = CImpsSearchRequest::NewL(); + CleanupStack::PushL( request ); + + request->SetRequestL( EImpsGroupUserIDOwner, *loggedUserId ); + pairs->AppendL( request ); + + // If there is error in search, return so we don't send stop error request + TInt searchError( KErrNone ); + searchError = iSearchAPI.StartSearchL( *pairs, KMaxUserSearchLimit, NULL ); + if ( searchError != KErrNone ) + { + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::PopulateCreatedGroupsL - error \ + from StartSearchL %d" ), searchError ); + // request, pairs, loggedUserId + CleanupStack::PopAndDestroy( 3, loggedUserId ); + return searchError; + } + + TInt resultCount( iSearchAPI.SearchDataInterface()->SearchDataCount() ); + + // just add all found groups to the group list + for ( TInt counter( 0 ); counter < resultCount; counter++ ) + { + TPtrC pGroupId( + iSearchAPI.SearchDataInterface()->SearchData( counter ) ); + aGroupList.AppendL( pGroupId ); + } + + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::PopulateCreatedGroupsL - found %d \ + groups from joined user" ), aGroupList.Count() ); + + CleanupStack::PopAndDestroy( 3, loggedUserId ); + + CHAT_DP_FUNC_DONE( "PopulateCreatedGroupsL" ); + + return KErrNone; + } + +// --------------------------------------------------------- +// CCAGroupManager::JoinedGroups +// --------------------------------------------------------- +// +TInt CCAGroupManager::JoinedGroups() + { + return iNumJoinedGroups; + } + + +// we just wrap the Handle*L routines by passing them +// on to the correct group wrapper + +// --------------------------------------------------------- +// CCAGroupManager::HandleErrorL +// --------------------------------------------------------- +// +void CCAGroupManager::HandleErrorL( + TInt aStatus, + TInt aOpId, + const TDesC* /* aDescription */, + const CImpsDetailed* /* aDetailedRes */, + TImpsCspIdentifier& /*aCspId*/ ) + { + CHAT_DP_FUNC_ENTER( "HandleErrorL" ); + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleErrorL - opid=%d, status=%d" ), + aOpId, aStatus ); + + CHAT_DP_FUNC_DONE( "HandleErrorL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::HandleCompleteL() +// --------------------------------------------------------- +// +void CCAGroupManager::HandleCompleteL( + TInt aOpId, + TImpsCspIdentifier& aCspId ) + { + CHAT_DP_FUNC_ENTER( "HandleCompleteL" ); + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleCompleteL - opid=%d" ), aOpId ); + + CCAGroupWrapper* wrapper = FindGroupWrapper( aOpId ); + + if ( ! wrapper ) + { + // no such wrapper + CHAT_DP_FUNC_DP( "HandleCompleteL", "No wrapper, leaving" ); + User::Leave( KErrNotFound ); + } + + CCARequest* request = wrapper->Request(); + __ASSERT_DEBUG( request, User::Panic( KCAEnginePanicCategory, + KErrNotFound ) ); + if ( !request ) + { + User::Leave( KErrNotFound ); + } + const MDesCArray* dataArray = request->AdditionalData(); + + switch ( request->RequestType() ) + { + case ECreateAndJoinGroup : + { + __ASSERT_DEBUG( dataArray, User::Panic( KCAEnginePanicCategory, + KErrNotFound ) ); + if ( !dataArray ) + { + // can't use User::LeaveIfNull for const pointers + User::Leave( KErrGeneral ); + } + + CHAT_DP_FUNC_DP( "HandleCompleteL", "Creating chat data for group" ); + + MCAMessagesWriteInterface& groupChat = + iChatInterface.MessageWriteInterfaceL( KNullDesC, KNullDesC, + dataArray->MdcaPoint( KReqCreateIndexGroupId ), + MCAMessagesReadInterface::EGroupContainer ); + + groupChat.SetScreenNameL( dataArray->MdcaPoint( + KReqCreateIndexScreenName ) ); + + // Write welcome message to chat + TPtrC welcome = dataArray->MdcaPoint( KReqCreateIndexWelcomeMsg ); + TPtrC topic = dataArray->MdcaPoint( KReqCreateIndexGroupTopic ); + + CHAT_DP_FUNC_DP( "HandleCompleteL", "Showing welcome message" ); + MCAStoredGroup& group = wrapper->Group(); + TPtrC groupIdentifier = + group.GroupName().Length() > 0 ? group.GroupName() : + CAUtils::DisplayId( group.GroupId() ); + + WriteWelcomeMessageL( welcome, groupIdentifier, topic, groupChat ); + + // note, it suffices to increase the number of created groups + // when CreateGroupL is called + break; + } + + default: + { + break; + } + + } + + wrapper->HandleCompleteL( aOpId, aCspId ); + + CHAT_DP_FUNC_DONE( "HandleCompleteL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::HandleJoinL() +// --------------------------------------------------------- +// +void CCAGroupManager::HandleJoinL( + TInt aOpId, + const MDesCArray& aUserList, + const MDesCArray& aScreenNames, + const TDesC& aWelcomeText, + TImpsCspIdentifier& aCspId ) + { + CHAT_DP_FUNC_ENTER( "HandleJoinL" ); + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleJoinL - opid=%d" ), aOpId ); + + CCAGroupWrapper* wrapper = FindGroupWrapper( aOpId ); + + if ( ! wrapper ) + { + // no wrapper + CHAT_DP_FUNC_DP( "HandleJoinL", "No wrapper, leaving" ); + User::Leave( KErrNotFound ); + } + + CCARequest* request = wrapper->Request(); + __ASSERT_DEBUG( request, User::Panic( KCAEnginePanicCategory, + KErrNotFound ) ); + if ( !request ) + { + User::Leave( KErrNotFound ); + } + const MDesCArray* dataArray = request->AdditionalData(); + + __ASSERT_DEBUG( dataArray, User::Panic( KCAEnginePanicCategory, + KErrNotFound ) ); + if ( !dataArray ) + { + // can't use User::LeaveIfError for const pointers + User::Leave( KErrGeneral ); + } + + CHAT_DP_FUNC_DP( "HandleJoinL", "Creating chat data for group" ); + + MCAMessagesWriteInterface& groupChat = + iChatInterface.MessageWriteInterfaceL( KNullDesC, KNullDesC, + dataArray->MdcaPoint( KReqJoinIndexGroupId ), + MCAMessagesReadInterface::EGroupContainer ); + groupChat.SetScreenNameL( dataArray->MdcaPoint( KReqJoinIndexScreenName ) ); + + + CImpsCommonGroupProps* commonProps = NULL; + CImpsPrivateGroupProps* privProps = NULL; + // ownership is preserved in wrapper + wrapper->LocalProperties( commonProps, privProps ); + + TPtrC topic( KNullDesC ); + if ( commonProps ) + { + topic.Set( commonProps->Topic() ); + } + + // Show welcome message + MCAStoredGroup& group = wrapper->Group(); + TPtrC groupIdentifier = + group.GroupName().Length() > 0 ? group.GroupName() : + CAUtils::DisplayId( group.GroupId() ); + TRAPD( err, WriteWelcomeMessageL( aWelcomeText, groupIdentifier, topic, groupChat ) ); + if ( err == KErrNoMemory ) + { + // Handle no memory error here + request->SetErrorCode( err ); + request->StopWaitIfNeeded(); + return; + } + else + { + User::LeaveIfError( err ); + } + + // Topic was shown in WriteWelcomeMessageL + if ( topic.Length() > 0 ) + { + wrapper->SetTopicShown( ETrue ); + } + + // make sure it's marked as joined in the UI + MCAExtendedStoredGroup& grp = + static_cast( wrapper->Group() ); + if ( !grp.IsJoined() ) + { + grp.SetJoined( ETrue ); + iNumJoinedGroups++; + } + + CHAT_DP_FUNC_DP( "HandleJoinL", "Passing on to wrapper" ); + wrapper->HandleJoinL( aOpId, aUserList, aScreenNames, + aWelcomeText, aCspId ); + + // show the joined-messages + TInt numNames = aScreenNames.MdcaCount(); + for ( TInt index = 0; index < numNames; index++ ) + { + HBufC* newUser = aScreenNames.MdcaPoint( index ).AllocLC(); + + HBufC* finalNewUserText = + StringLoader::LoadLC( R_SYSTEM_MESSAGE_JOIN, + *newUser ); + + CHAT_DP_FUNC_DP( "HandleJoinL", "Initiating new users message" ); + + MCAMessage* newUserMsg = + iMessageUtils.MessageCreator().CreateSystemMessageL( + MCAMessage::ESystemMessageNewUsers, + *finalNewUserText ); + + // Append message + TRAPD( err, CAMessageUtil::AppendMessageWithDateStampL( + *newUserMsg, + groupChat, + iMessageUtils.MessageCreator() ) ); + + if ( err == KErrNoMemory ) + { + // Handle no memory error here + CleanupStack::PopAndDestroy( 2, newUser ); // finalNewUserText, newUser + request->SetErrorCode( err ); + request->StopWaitIfNeeded(); + return; + } + else + { + User::LeaveIfError( err ); + } + + CleanupStack::PopAndDestroy( 2, newUser ); // finalNewUserText, newUser + } + + CHAT_DP_FUNC_DONE( "HandleJoinL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::HandleGroupMembersL() +// --------------------------------------------------------- +// +void CCAGroupManager::HandleGroupMembersL( + TInt aOpId, + const MDesCArray& aUserList, + const MDesCArray& aScreenNames, + const MDesCArray& aModers, + const MDesCArray& aAdmins, + TImpsCspIdentifier& aCspId ) + { + CHAT_DP_FUNC_ENTER( "HandleGroupMembersL" ); + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleGroupMembersL - opid=%d" ), + aOpId ); + + CCAGroupWrapper* wrapper = FindGroupWrapper( aOpId ); + if ( ! wrapper ) + { + CHAT_DP_FUNC_DP( "HandleGroupMembersL", "No wrapper, leaving" ); + User::Leave( KErrNotFound ); + } + + CHAT_DP_FUNC_DP( "HandleGroupMembersL", "Passing on to wrapper" ); + wrapper->HandleGroupMembersL( aOpId, aUserList, aScreenNames, aModers, + aAdmins, aCspId ); + + CHAT_DP_FUNC_DONE( "HandleGroupMembersL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::HandleGroupPropertiesL() +// --------------------------------------------------------- +// +void CCAGroupManager::HandleGroupPropertiesL( + TInt aOpId, + const TDesC& aGroupId, + const CImpsCommonGroupProps& aGroupProps, + const CImpsPrivateGroupProps& aOwnProps, + TImpsCspIdentifier& aCspId ) + { + CHAT_DP_FUNC_ENTER( "HandleGroupPropertiesL" ); + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleGroupPropertiesL - opid=%d" ), + aOpId ); + + CCAGroupWrapper* wrapper = NULL; + TPtrC groupId( aGroupId ); + + if ( aOpId != 0 ) + { + // aGroupId is empty + wrapper = FindGroupWrapper( aOpId ); + + if ( !wrapper ) + { + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", "No wrapper, leaving" ); + User::Leave( KErrNotFound ); + } + + groupId.Set( wrapper->Group().GroupId() ); + } + else + { + // aGroupId is valid + wrapper = FindGroupWrapper( aGroupId ); + } + + if ( ! wrapper ) + { + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", "No wrapper, leaving" ); + User::Leave( KErrNotFound ); + } + + CImpsCommonGroupProps* common = NULL; + CImpsPrivateGroupProps* priv = NULL; + + // does the wrapper have the properties already? + wrapper->LocalProperties( common, priv ); + + if ( ( !common ) && ( !priv ) ) + { + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", "No existing properties" ); + + // no existing properties, so create new ones + common = CImpsCommonGroupProps::NewL(); + CleanupStack::PushL( common ); + + priv = CImpsPrivateGroupProps::NewL(); + CleanupStack::Pop( common ); + + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", "Created new properties" ); + + // transfer ownership + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", "Setting the properties" ); + wrapper->SetLocalProperties( common, priv ); + } + + // set the admin status + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", "Setting administrator status" ); + MCAExtendedStoredGroup& group = + static_cast( wrapper->Group() ); + + if ( aOwnProps.Privileges() == EImpsAdmin ) + { + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", + "User is administrator in group" ); + group.SetAdmin( ETrue ); + } + else if ( aOwnProps.Privileges() != EImpsUserUndef ) + { + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", + "User is not administrator in group" ); + group.SetAdmin( EFalse ); + } + + if ( aGroupProps.GroupName().Length() > 0 ) + { + if ( aGroupProps.GroupName().CompareC( group.GroupName() ) != 0 ) + { + // group name has changed, so update it and signal UI + group.SetGroupNameL( aGroupProps.GroupName() ); + iStoredGroups->SignalGroupChangedL( group.GroupId() ); + } + } + // if the group is stored in persistent storage, save changes to disk also + if ( group.StorageType() == TStorageManagerGlobals::EStoragePersistent ) + { + group.SaveChangesL(); + } + + + // see if anything changed + MCAMessagesWriteInterface& groupChat = + iChatInterface.MessageWriteInterfaceL( KNullDesC, KNullDesC, groupId ); + + // Ignore empty topics. We must only react to push messages + // React also when topic was not shown in HandleJoinL while joining + if ( ( ( aOpId == 0 ) && ( aGroupProps.Topic().Length() > 0 ) ) + || ( !( wrapper->IsTopicShown() ) && ( aOpId == iPropsOpIdWhileJoining ) ) ) + { + // there is a topic, but has it changed? + + if ( ( ( 0 != aGroupProps.Topic().CompareC( common->Topic() ) ) || + !( wrapper->IsTopicShown() ) // Topic changed by user, compare gives 0 + ) + && aOpId == 0 ) + { + // Check the group topic again, if length > 0, then display the topic + if ( aGroupProps.Topic().Length() > 0 ) + { + // it has changed + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", "Topic has changed" ); + + // Topic has changed so initiate system message + HBufC* newTopic = aGroupProps.Topic().AllocLC(); + + HBufC* finalNewTopic = + StringLoader::LoadLC( R_SYSTEM_MESSAGE_TOPIC, + *newTopic ); + + MCAMessage* topicChgMsg = + iMessageUtils.MessageCreator().CreateSystemMessageL( + MCAMessage::ESystemMessageTopicChanged, + *finalNewTopic ); + + // Append message + CAMessageUtil::AppendMessageWithDateStampL( + *topicChgMsg, + groupChat, + iMessageUtils.MessageCreator() ); + + wrapper->SetTopicShown( ETrue ); + + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleGroupPropertiesL - \ + topic is %S" ), finalNewTopic ); + + CleanupStack::PopAndDestroy( 2, newTopic );//finalNewTopic, newTopic + } + } + else if ( aGroupProps.Topic().Length() > 0 + && aOpId == iPropsOpIdWhileJoining ) + { + // Show topic of group when joining + iPropsOpIdWhileJoining = KErrNotFound; + HBufC* topicText = + StringLoader::LoadLC( R_SYSTEM_MESSAGE_TOPIC_TEXT, + aGroupProps.Topic() ); + groupChat.AppendL( + iMessageUtils.MessageCreator().CreateSystemMessageL( + MCAMessage::ESystemMessageWelcome, *topicText ) ); + + wrapper->SetTopicShown( ETrue ); + CleanupStack::PopAndDestroy( topicText ); + } + } + + // Private (whispering) state change. We must only react to push messages + if ( ( aOpId == 0 ) && ( aGroupProps.IsPrivateAllowed() == EImpsPropYes ) ) + { + // The state is active, but has it changed? + if ( aGroupProps.IsPrivateAllowed() != common->IsPrivateAllowed() ) + { + // private flag has changed + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", + "Private messaging turn on" ); + HBufC* privatMessaging = + StringLoader::LoadLC( R_SYSTEM_MESSAGE_PRIVAT_ON ); + + MCAMessage* privateChgMsg = + iMessageUtils.MessageCreator().CreateSystemMessageL( + MCAMessage::ESystemMessagePrivatChanged, + *privatMessaging ); + + // Append message + CAMessageUtil::AppendMessageWithDateStampL( + *privateChgMsg, + groupChat, + iMessageUtils.MessageCreator() ); + + CleanupStack::PopAndDestroy( privatMessaging ); + } + } + else + { + // we must only react to push messages + if ( ( aOpId == 0 ) && + ( aGroupProps.IsPrivateAllowed() != EImpsPropUndef ) ) + { + // the flag is in some non-empty, valid, non-Yes state + // (currently only one such possibility) + + if ( aGroupProps.IsPrivateAllowed() != common->IsPrivateAllowed() ) + { + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", + "Private messaging turn off" ); + + HBufC* privatMessaging = StringLoader::LoadLC( + R_SYSTEM_MESSAGE_PRIVAT_OFF ); + + MCAMessage* privateChgMsg = + iMessageUtils.MessageCreator().CreateSystemMessageL( + MCAMessage::ESystemMessagePrivatChanged, + *privatMessaging ); + + // Append message + CAMessageUtil::AppendMessageWithDateStampL( + *privateChgMsg, + groupChat, + iMessageUtils.MessageCreator() ); + + CleanupStack::PopAndDestroy( privatMessaging ); + } + } + } + + CHAT_DP_FUNC_DP( "HandleGroupPropertiesL", "Passing on to wrapper" ); + wrapper->HandleGroupPropertiesL( aOpId, groupId, aGroupProps, + aOwnProps, aCspId ); + + CHAT_DP_FUNC_DONE( "HandleGroupPropertiesL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::HandleRejectListL() +// --------------------------------------------------------- +// +void CCAGroupManager::HandleRejectListL( + TInt aOpId, + const MDesCArray& aUserList, + TImpsCspIdentifier& aCspId ) + { + CHAT_DP_FUNC_ENTER( "HandleRejectListL" ); + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleRejectListL - opid=%d" ), + aOpId ); + + CCAGroupWrapper* wrapper = FindGroupWrapper( aOpId ); + if ( ! wrapper ) + { + CHAT_DP_FUNC_DP( "HandleRejectListL", "No wrapper, leaving" ); + User::Leave( KErrNotFound ); + } + + CHAT_DP_FUNC_DP( "HandleRejectListL", "Passing on to wrapper" ); + wrapper->HandleRejectListL( aOpId, aUserList, aCspId ); + + CHAT_DP_FUNC_DONE( "HandleRejectListL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::HandleSubscriptionL() +// --------------------------------------------------------- +// +void CCAGroupManager::HandleSubscriptionL( + TInt aOpId, + TBool aIsSubscribed, + TImpsCspIdentifier& aCspId ) + { + CHAT_DP_FUNC_ENTER( "HandleSubscriptionL" ); + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleSubscriptionL - opid=%d" ), + aOpId ); + + // can't be a push message + CCAGroupWrapper* wrapper = FindGroupWrapper( aOpId ); + if ( ! wrapper ) + { + CHAT_DP_FUNC_DP( "HandleSubscriptionL", "No wrapper, leaving" ); + User::Leave( KErrNotFound ); + } + + CHAT_DP_FUNC_DP( "HandleSubscriptionL", "Passing on to wrapper" ); + wrapper->HandleSubscriptionL( aOpId, aIsSubscribed, aCspId ); + + CHAT_DP_FUNC_DONE( "HandleSubscriptionL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::HandleNewUsersL() +// --------------------------------------------------------- +// +void CCAGroupManager::HandleNewUsersL( + const TDesC& aGroupId, + const MDesCArray& aUserList, + const MDesCArray& aScreenNames, + TImpsCspIdentifier& aCspId ) + { + CHAT_DP_FUNC_ENTER( "HandleNewUsersL" ); + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleNewUsersL " ) ); + + CCAGroupWrapper* wrapper = FindGroupWrapper( aGroupId ); + + if ( ! wrapper ) + { + CHAT_DP_FUNC_DP( "HandleNewUsersL", "No wrapper, leaving" ); + User::Leave( KErrNotFound ); + } + + // print the user and screen names list +#ifdef _DEBUG + TInt i( 0 ); + TInt count( aUserList.MdcaCount() ); + CHAT_DP_FUNC_DP( "HandleNewUsersL", "User list:" ); + for ( i = 0; i < count; i++ ) + { + TPtrC p = TPtrC( aUserList.MdcaPoint( i ) ); + CHAT_DP( D_CHAT_LIT( " %S" ), &p ); + } + + count = aScreenNames.MdcaCount(); + CHAT_DP_FUNC_DP( "HandleNewUsersL", "Screen names list:" ); + for ( i = 0; i < count; i++ ) + { + TPtrC p = TPtrC( aScreenNames.MdcaPoint( i ) ); + CHAT_DP( D_CHAT_LIT( " %S" ), &p ); + } +#endif + + // get the list of participants + MCAStoredGroup& group = wrapper->Group(); + + // this granularity is as good as any + CDesCArrayFlat* participants = + new ( ELeave ) CDesCArrayFlat( KJoinedMembersArrayGranularity ); + CleanupStack::PushL( participants ); + group.GetParticipantsL( *participants ); + + TInt numNames( aScreenNames.MdcaCount() ); + + // list has names + for ( TInt index = 0; index < numNames; index++ ) + { + // don't show joined-message for persons already joined to the group + TInt posIgnored = 0; + if ( participants->Find( aScreenNames.MdcaPoint( index ), + posIgnored, ECmpFolded ) ) + { + // a new user, show the message + HBufC* newUser = aScreenNames.MdcaPoint( index ).AllocLC(); + + HBufC* finalNewUserText = + StringLoader::LoadLC( R_SYSTEM_MESSAGE_JOIN, + *newUser ); + + CHAT_DP_FUNC_DP( "HandleNewUsersL", + "Initiating new users message" ); + + MCAMessagesWriteInterface& groupChat = + iChatInterface.MessageWriteInterfaceL( KNullDesC, + KNullDesC, aGroupId ); + + MCAMessage* newUserMsg = + iMessageUtils.MessageCreator().CreateSystemMessageL( + MCAMessage::ESystemMessageNewUsers, + *finalNewUserText ); + + // Append message + CAMessageUtil::AppendMessageWithDateStampL( + *newUserMsg, + groupChat, + iMessageUtils.MessageCreator() ); + + // finalNewUserText, newUser + CleanupStack::PopAndDestroy( 2, newUser ); + } + } + + CleanupStack::PopAndDestroy( participants ); + + CHAT_DP_FUNC_DP( "HandleNewUsersL", "Passing on to wrapper" ); + wrapper->HandleNewUsersL( aGroupId, aUserList, aScreenNames, aCspId ); + + CHAT_DP_FUNC_DONE( "HandleNewUsersL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::HandleLeftUsersL() +// --------------------------------------------------------- +// +void CCAGroupManager::HandleLeftUsersL( + const TDesC& aGroupId, + const MDesCArray& aUserList, + const MDesCArray& aScreenNames, + TImpsCspIdentifier& aCspId ) + { + CHAT_DP_FUNC_ENTER( "HandleLeftUsersL" ); + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleLeftUsersL" ) ); + + CCAGroupWrapper* wrapper = FindGroupWrapper( aGroupId ); + + if ( ! wrapper ) + { + CHAT_DP_FUNC_DP( "HandleLeftUsersL", "No wrapper, leaving" ); + User::Leave( KErrNotFound ); + } + + CHAT_DP_FUNC_DP( "HandleLeftUsersL", "Passing on to wrapper" ); + wrapper->HandleLeftUsersL( aGroupId, aUserList, aScreenNames, aCspId ); + + TInt numNames( aScreenNames.MdcaCount() ); + // list has names + for ( TInt index = 0; index < numNames; index++ ) + { + HBufC* leftUser = aScreenNames.MdcaPoint( index ).AllocLC(); + + HBufC* finalLeftUserText = + StringLoader::LoadLC( R_SYSTEM_MESSAGE_LEAVE, + *leftUser ); + + CHAT_DP_FUNC_DP( "HandleLeftUsersL", "Initiating left users message" ); + + MCAMessagesWriteInterface& groupChat = + iChatInterface.MessageWriteInterfaceL( KNullDesC, + KNullDesC, aGroupId ); + + MCAMessage* userLeftMsg = + iMessageUtils.MessageCreator().CreateSystemMessageL( + MCAMessage::ESystemMessageLeftUsers, *finalLeftUserText ); + + // Append message + CAMessageUtil::AppendMessageWithDateStampL( + *userLeftMsg, + groupChat, + iMessageUtils.MessageCreator() ); + + CleanupStack::PopAndDestroy( 2, leftUser ); // finalLeftUserText, leftUser + } + + CHAT_DP_FUNC_DONE( "HandleLeftUsersL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::HandleLeaveL() +// --------------------------------------------------------- +// +void CCAGroupManager::HandleLeaveL( + TInt aOpId, + const TDesC& aGroupId, + const TDesC& aDescription, + TImpsCspIdentifier& aCspId ) + { + CHAT_DP_FUNC_ENTER( "HandleLeaveL" ); + CHAT_DP( D_CHAT_LIT( "CCAGroupManager::HandleLeaveL - opid=%d" ), aOpId ); + + CCAGroupWrapper* wrapper = NULL; + if ( aOpId != 0 ) + { + // operation id is valid + wrapper = FindGroupWrapper( aOpId ); + } + else + { + // group id is valid + wrapper = FindGroupWrapper( aGroupId ); + } + + if ( ! wrapper ) + { + CHAT_DP_FUNC_DP( "HandleLeaveL", "No wrapper, leaving" ); + User::Leave( KErrNotFound ); + } + + // handle the leave in wrapper + MCAExtendedStoredGroup& gr = + static_cast( wrapper->Group() ); + + // Work with copy of group id, as wrapper gets deleted soon. + // Also, group id is not valid in push. + HBufC* grId = gr.GroupId().AllocLC(); + + CHAT_DP_FUNC_DP( "HandleLeaveL", "Passing on to wrapper" ); + + wrapper->LastImpsError( iLastImpsError ); + //reset/consume last error + iLastImpsError = KErrNone; + + wrapper->HandleLeaveL( aOpId, *grId, aDescription, aCspId ); + + if ( aOpId == 0 ) + { + CHAT_DP_FUNC_DP( "HandleLeaveL", + "Push message, cleaning up in HandleLeaveL" ); + // push messages we cleanup here, + // pull messages in the LeaveGroupL which originated + // this call chain + CleanupLeaveGroupL( *grId ); + } + + CleanupStack::PopAndDestroy( grId ); + CHAT_DP_FUNC_DONE( "HandleLeaveL" ); + } + +// set group as un-joined, and delete wrapper, group and associated +// group chat data +void CCAGroupManager::CleanupLeaveGroupL( const TDesC& aGroupId ) + { + CHAT_DP_FUNC_ENTER( "CleanupLeaveGroupL" ); + + CCAGroupWrapper* wrapper = FindGroupWrapper( aGroupId ); + if ( !wrapper ) + { + CHAT_DP_FUNC_DP( "CleanupLeaveGroupL", "no wrapper, nothing to do!" ); + return; + } + MCAExtendedStoredGroup& gr = + static_cast( wrapper->Group() ); + + CHAT_DP_FUNC_DP( "CleanupLeaveGroupL", "Leaving group" ); + + if ( gr.IsJoined() ) + { + gr.SetJoined( EFalse ); + iNumJoinedGroups--; + } + + if ( ( !gr.IsOwnGroup() ) && + ( gr.StorageType() != TStorageManagerGlobals::EStoragePersistent ) ) + { + // not own, not stored and not joined (after CleanupLeaveGroupL) + // aWrappers shouldn't be on the list, so delete also from storage + // (not from server) + CHAT_DP_FUNC_DP( "CleanupLeaveGroupL", "Deleting aWrapper and group" ); + // delete returns error code of network delete operation + // in case of group leave it is not import if group deleting fails + // from server, return code ignored + DeleteGroupL( aGroupId, EFalse ); + } + else + { + // delete all server-related things: + // members, participants, admin status, whispering, etc. + gr.ResetMembersLocally(); + gr.ResetParticipantsL(); + + gr.SetAdmin( EFalse ); + + // delete wrapper + DeleteGroupWrapper( aGroupId ); + RemoveChatDataL( aGroupId ); + } + + CHAT_DP_FUNC_DONE( "CleanupLeaveGroupL" ); + } + + + +// --------------------------------------------------------- +// CCAGroupManager::NumberOfCreatedGroupsDuringSession +// --------------------------------------------------------- +// +TInt CCAGroupManager::NumberOfCreatedGroupsDuringSession() const + { + return iNumCreatedGroups; + } + +// --------------------------------------------------------- +// CCAGroupManager::GroupOperations +// --------------------------------------------------------- +// +MCAGroupOperations* CCAGroupManager::GroupOperationsL( const TDesC& aId ) + { + CHAT_DP_FUNC_ENTER( "GroupOperationsL" ); + + CCAGroupWrapper* groupWrapper = FindGroupWrapper( aId ); + if ( groupWrapper ) + { + // found an existing wrapper + CHAT_DP_FUNC_DONE( "GroupOperationsL" ); + return groupWrapper; + } + + CHAT_DP_FUNC_DONE( "GroupOperationsL" ); + + // no existing wrapper. make a new one, store it and return it + return CreateWrapperL( aId ); + } + +// --------------------------------------------------------- +// CCAGroupManager::SetGroupEventObserver +// Call with NULL observer is safely handled at all times +// --------------------------------------------------------- +// +void CCAGroupManager::SetGroupEventObserverL( const TDesC& aId, + MCAGroupEventObserver* aObserver ) + { + CHAT_DP_FUNC_ENTER( "SetGroupEventObserverL" ); + + CCAGroupWrapper* groupWrapper = FindGroupWrapper( aId ); + + if ( ! groupWrapper ) + { + // not found + if ( aObserver ) + { + // valid observer + CHAT_DP_FUNC_DP( "SetGroupEventObserverL", "Creating new wrapper" ); + groupWrapper = CreateWrapperL( aId ); + } + } + + if ( groupWrapper ) + { + // no new wrappers are to be created for null observers - in + // such a case there's no observer anyway! + CHAT_DP_FUNC_DP( "SetGroupEventObserverL", "Setting event observer" ); + groupWrapper->RegisterEventObserver( aObserver ); + } + + CHAT_DP_FUNC_DONE( "SetGroupEventObserverL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::CreateGroupL +// --------------------------------------------------------- +// +HBufC* CCAGroupManager::CreateGroupL( + CImpsCommonGroupProps* aProperties, + CImpsPrivateGroupProps* aPrivProperties, + const TDesC& aScreenName, + TBool aJoinGroup, + TBool aIsWhisperingEnabled, + TInt& aErrorCode +) + { + CHAT_DP_FUNC_ENTER( "CreateGroupL" ); + + if ( !aProperties || !aPrivProperties ) + { + User::Leave( KErrArgument ); + } + // 1. create group to storage + // 2. invent a group name for the newly created group + // 3. create a group wrapper + // 4. pass this method on to the group wrapper + // 5. return the group id + + + // deleting old values, just in case that previous CreateGroup has failed + delete iProperties; + delete iPrivProperties; + iProperties = aProperties; + iPrivProperties = aPrivProperties; + + // create group + MCAExtendedStoredGroup* exGrp = iStoredGroups->CreateGroupL(); + // Check memory level, leaves group creation with KErrDiskFull + // now if new group cannot be added to persistent database + TRAPD( err, iStoredGroups->CheckFreespaceLevelL( exGrp ) ); + if ( err == KErrDiskFull ) + { + // Make sure nothing is left to storage + iStoredGroups->DeleteGroupL( exGrp ); + User::Leave( err ); + } + exGrp->SetAdmin( ETrue ); + exGrp->SetGroupNameL( aProperties->GroupName() ); + + CHAT_DP( D_CHAT_LIT( "Group whisper, common=%d, priv=%d" ), + aProperties->IsPrivateAllowed(), + aPrivProperties->IsPrivateAllowed() ); + + TBool allDone = EFalse; + TInt maxTries( KMaxGroupIds ); // fail-safe to prevent infinite loop + + CCAGroupWrapper* grOp = NULL; + while ( ( ! allDone ) && ( maxTries > 0 ) ) + { + HBufC* groupId = NULL; + while ( !groupId ) + { + groupId = GenerateGroupIdLC( aProperties->GroupName() ); + if ( iStoredGroups->FindGroup( *groupId ) ) + { + // group was found from storage, so let's + // delete it and try next one + CleanupStack::PopAndDestroy( groupId ); + groupId = NULL; + } + } + + // now we have a unique group id that is not in storage, + exGrp->SetGroupIdL( *groupId ); + CleanupStack::PopAndDestroy( groupId ); + groupId = NULL; + + if ( !grOp ) + { + // we don't have a wrapper yet, so let's + // create it for the group and set the properties + grOp = static_cast( GroupOperationsL( + exGrp->GroupId() ) ); + // wrapper takes the ownership of properties from now on + grOp->SetLocalProperties( aProperties, aPrivProperties ); + iProperties = NULL; + iPrivProperties = NULL; + } + + + // finalize group creation to the network + CHAT_DP_FUNC_DP( "CreateGroupL", "Creating group to network" ); + aErrorCode = grOp->CreateGroupL( aScreenName, aJoinGroup ); + + if ( ( aErrorCode == KErrNone ) + || ( aErrorCode == ECSPPartiallySuccessful ) ) + { + // search groups from server, in order to get the new groupid + // begin + HBufC* loggedUserId = iSettingsAPI.ValueL( MCASettings::EOwnWVUserID ); + CleanupStack::PushL( loggedUserId ); + + CSearchPairs* tempPairs = + new ( ELeave ) CSearchPairs( KSearchPairsSmallGranularity ); + CleanupStack::PushL( tempPairs ); + CImpsSearchRequest* tempRequest = CImpsSearchRequest::NewL(); + CleanupStack::PushL( tempRequest ); + tempRequest->SetRequestL( EImpsGroupUserIDOwner, *loggedUserId ); + tempPairs->AppendL( tempRequest ); + + // If there is error in search, return so we don't send stop error request + TInt searchError( KErrNone ); + TInt err( KErrNone ); + TRAP( err, searchError = + iSearchAPI.StartSearchL( *tempPairs, KMaxGroupSearchLimit, NULL ) ); + + CleanupStack::PopAndDestroy( 3, loggedUserId );// tempRequest, tempPairs, loggedUserId + + if ( err != KErrNone ) + { + User::LeaveIfError( err ); + } + else if ( searchError != KErrNone ) + { + User::LeaveIfError( searchError ); + } + + TInt resultCount( + iSearchAPI.SearchDataInterface()->SearchDataCount() ); + + for ( TInt counter( 0 ); counter < resultCount; counter++ ) + { + // see if this group is already in storage + TPtrC groupId( iSearchAPI.SearchDataInterface()->SearchData( + counter ) ); + MCAStoredGroup* group = iStoredGroups->FindGroup( groupId ); + + if ( !group ) + { + exGrp->SetGroupIdL( groupId ); + break; + } + } + // end + + // must update to the server + if ( aIsWhisperingEnabled ) + { + SetPrivateAllowedL( *grOp, *aPrivProperties ); + } + + // this is our group + exGrp->SetOwnGroup( ETrue ); + + if ( !exGrp->IsJoined() && aJoinGroup ) + { + iNumJoinedGroups++; + } + // set the joined status + exGrp->SetJoined( aJoinGroup ); + + // make it a favorite, automatically + exGrp->SaveChangesL(); + + // tell the UI the group has been added + iStoredGroups->SignalGroupAddedL( exGrp->GroupId() ); + + aErrorCode = KErrNone; // it's fully successful now... + allDone = ETrue; // get out too + } + else + { + if ( aErrorCode == ECSPGroupAlreadyExists ) + { + // group already exists + CHAT_DP_FUNC_DP( "CreateGroupL", + "Wrapper's CreateGroupL failed, trying with another groupid" ); + + maxTries--; + } + else + { + // delete the group from storage if CreateGroupL failed, + // aErrorCode is already set for use after return + CHAT_DP_FUNC_DP( "CreateGroupL", + "Wrapper's CreateGroupL failed, aborting" ); + // delete return value is network operation error code + // we are not interested it, + // because group creation already failed + DeleteGroupL( exGrp->GroupId(), EFalse ); + // group got deleted, return NULL + return NULL; + } + } + } + + // failsafe, if we reached the maximum number of tries + if ( maxTries == 0 ) + { + // everything is cleaned up in the loop + return NULL; + } + + // Add creator of group as participant to group. + // Just because creator is participating group. + // Server does not always inform us for this one. + CDesCArrayFlat* participants = + new ( ELeave ) CDesCArrayFlat( KJoinedMembersArrayGranularity ); + CleanupStack::PushL( participants ); + participants->AppendL( aScreenName ); + exGrp->AddParticipantL( *participants ); + CleanupStack::PopAndDestroy( participants ); + + iNumCreatedGroups++; + + CHAT_DP_FUNC_DONE( "CreateGroupL" ); + + return exGrp->GroupId().AllocL(); // ownership is transferred + } + +// --------------------------------------------------------- +// CCAGroupManager::JoinGroupL +// We must wrap JoinL to make sure the properties are +// in place. It can't be done in wrapper as it will +// mess up the message sequences. +// --------------------------------------------------------- +// +TInt CCAGroupManager::JoinGroupL( const TDesC& aGroupId, + const TDesC& aScreenName, TBool aUsers, + TBool aIsFavourite, TBool aIsWhisperingEnabled ) + { + CHAT_DP_FUNC_ENTER( "JoinGroupL" ); + + CCAGroupWrapper* wrapper = FindGroupWrapper( aGroupId ); + + if ( ! wrapper ) + { + // no wrapper, create one + // exists in a internal list, so no need to use cleanupstack + wrapper = CreateWrapperL( aGroupId ); + } + + // check if we need to fetch the properties from the network + CImpsCommonGroupProps* commonProps = NULL; + CImpsPrivateGroupProps* privateProps = NULL; + wrapper->LocalProperties( commonProps, privateProps ); + // ownership is kept in wrapper + + // now we can join the group + TInt joinStatus = KErrNone; + joinStatus = wrapper->JoinL( aScreenName, aUsers, aIsFavourite ); + if ( joinStatus == EOperationCancelled) + { + return joinStatus; + } + TInt retStatus( KErrNone ); + if ( ( !commonProps ) || ( !privateProps ) ) + { + // no properties, so request from network + // Store op id of properties request + iPropsOpIdWhileJoining = wrapper->OperationId() + 1; + retStatus = wrapper->GetPropertiesL( commonProps, privateProps ); + if ( retStatus == EOperationCancelled) + { + return retStatus; + } + if ( retStatus != ECSPInsufficientGroupPrivileges ) + { + if ( ( retStatus != ECSPSuccessful ) && ( retStatus != KErrNone ) ) + { + // got some failure + iPropsOpIdWhileJoining = KErrNotFound; // Init to -1 + return retStatus; + } + + // fail-safe for buggy server returning NULL to these for some reason + if ( ( ! commonProps ) || ( ! privateProps ) ) + { + iPropsOpIdWhileJoining = KErrNotFound; // Init to -1 + return ECSPInsufficientGroupPrivileges; + } + } + } + + // Note! ChatData is created in HandleJoinL, but HandleJoinL + // is not called if we get 807 ECSPGroupAlreadyJoined. So we must work + // around to recover from that. + + if ( joinStatus == ECSPGroupAlreadyJoined ) + { + // Make sure our status is in sync with server + // status, then we can recover from 807 ECSPGroupAlreadyJoined. + // If we get ECSPGroupAlreadyJoined, HandleJoinL is never called, + // but HandleErrorL (Engine) instead! + + // create the chat data, if we don't have it + + MCAMessagesWriteInterface& groupChat = + iChatInterface.MessageWriteInterfaceL( + KNullDesC, KNullDesC, aGroupId, + MCAMessagesReadInterface::EGroupContainer ); + groupChat.SetScreenNameL( aScreenName ); + + // make sure it's marked as joined in the UI + MCAExtendedStoredGroup& grp = + static_cast( wrapper->Group() ); + if ( !grp.IsJoined() ) + { + grp.SetJoined( ETrue ); + iNumJoinedGroups++; + } + } + + // also update private properties to the group + if ( ( joinStatus == ECSPGroupAlreadyJoined ) + || ( joinStatus == ECSPSuccessful ) + || ( joinStatus == KErrNone ) ) + { + if ( aIsWhisperingEnabled && privateProps ) + { + joinStatus = SetPrivateAllowedL( *wrapper, *privateProps ); + if ( joinStatus == EOperationCancelled ) + { + return joinStatus; + } + } + joinStatus = KErrNone; + } + + CHAT_DP_FUNC_DONE( "JoinGroupL" ); + + return joinStatus; + } + +// --------------------------------------------------------- +// CCAGroupManager::LeaveJoinedGroups +// --------------------------------------------------------- +// +void CCAGroupManager::LeaveJoinedGroupsL() + { + TInt count = iGroupWrappers.Count(); + for ( TInt i = count - 1; i >= 0; --i ) + { + MCAStoredGroup& group = iGroupWrappers[ i ]->Group(); + if ( group.IsJoined() ) + { + iGroupWrappers[ i ]->LeaveL(); + CleanupLeaveGroupL( group.GroupId() ); + } + } + } + +// --------------------------------------------------------- +// CCAGroupManager::LeaveGroupL +// We must wrap LeaveL to make sure the UI and +// IMPS engine running in different threads do not +// cause race conditions when UI calls LeaveL directly +// and IMPS engine informs via HandleLeaveL. +// --------------------------------------------------------- +// +TInt CCAGroupManager::LeaveGroupL( const TDesC& aGroupId ) + { + CHAT_DP_FUNC_ENTER( "LeaveGroupL" ); + + CCAGroupWrapper* wrapper = FindGroupWrapper( aGroupId ); + + if ( ! wrapper ) + { + // not Leaving with KErrNone due to popular request + return KErrNone; + } + + // leave the group + TInt retStatus = wrapper->LeaveL(); + + // nuke the wrappers etc. + CleanupLeaveGroupL( aGroupId ); + + CHAT_DP_FUNC_DONE( "LeaveGroupL" ); + return retStatus; + } + +// --------------------------------------------------------- +// CCAGroupManager::GenerateGroupIdLC +// XXX cleaned up the forbidden char removal part, +// but can this be cleaned up any more? +// --------------------------------------------------------- +// +HBufC* CCAGroupManager::GenerateGroupIdLC( const TDesC& aResourcePart ) + { + + HBufC* groupId = HBufC::NewLC( KMaxGroupIDLength ); + TPtr groupIdPtr( groupId->Des() ); + + // Retrieve logged user information + HBufC* loggedUserId = iSettingsAPI.ValueL( MCASettings::EOwnWVUserID ); + CleanupStack::PushL( loggedUserId ); + + // find "@" + TInt atIndex( loggedUserId->FindC( KAt ) ); + if ( atIndex == KErrNotFound ) + { + atIndex = loggedUserId->Length(); + } + + // Find string between ":" and "@" + // If there is no "wv:" start from beginning of user id + TInt startPosition = 0; + if ( KWV().CompareC( loggedUserId->Left( KWV().Length() ), + KCollationLevel, NULL ) == 0 ) + { + startPosition = KWV().Length(); + } + + TPtrC userBaseName( loggedUserId->Mid( + startPosition, atIndex - startPosition ) ); + + // We must get rid of the unneeded "@" characters + TPtrC groupBaseName; + HBufC* temp = CAUtils::GenerateIdLC( aResourcePart ); + TPtr tempPtr( temp->Des() ); + + // group name empty? If it is, use userBaseName after "/" in group id + if ( aResourcePart.Length() < 1 ) + { + groupBaseName.Set( userBaseName ); + } + else + { + // Sanity check. We removed characters, is there anything in the string? + if ( tempPtr.Length() < 1 ) + { + groupBaseName.Set( userBaseName ); + } + else + { + groupBaseName.Set( tempPtr ); + } + + CHAT_DP( D_CHAT_LIT( "Group base name is %S" ), &groupBaseName ); + } + + // Add "wv:" at the beginning + groupIdPtr.Copy( KWV ); + + // Add "middle" part of WV user ID + // + // EXAMPLE 1: + // User id = wv:jari20@domain.com + // Group name = grouppi + // Group id becomes wv:jari20/grouppi + // + // EXAMPLE 2: + // User id = wv:jari20@domain.com + // Group name is empty + // Group id becomes wv:jari20/jari20 + + groupIdPtr += userBaseName; + + // Add separator "/" + groupIdPtr += KResourceSeparator; + + TInt groupInsertIndex( groupIdPtr.Length() ); + + // don't add ordinal the first time + if ( iGroupIdOrdinal > 0 ) + { + // Format ordinal, 5 is enough + TBuf<5> ordinal; + ordinal.Num( iGroupIdOrdinal ); + // Add ordinal + groupIdPtr += ordinal; + } + + // Add domain part + groupIdPtr += loggedUserId->Mid( atIndex ); + + // Add groupId last so we can know how much it can be inserted. + groupIdPtr.Insert( groupInsertIndex, + groupBaseName.Left( + KMaxGroupIDLength - groupIdPtr.Length() ) ); + + CleanupStack::PopAndDestroy( temp ); + CleanupStack::PopAndDestroy( loggedUserId ); + + // Increase ordinal + ++iGroupIdOrdinal; + + return groupId; + } + + +// --------------------------------------------------------- +// CCAGroupManager::DeleteGroupL +// --------------------------------------------------------- +// +TInt CCAGroupManager::DeleteGroupL( const TDesC& aGroupId, + TBool aDeleteFromNetwork ) + { + CHAT_DP_FUNC_ENTER( "DeleteGroupL" ); + + TBuf groupid; + groupid.Copy( aGroupId.Left( groupid.MaxLength() ) ); + + TInt retVal( KErrNone ); + CCAGroupWrapper* wrapper = NULL; + + if ( aDeleteFromNetwork ) + { + // delete from network + + wrapper = FindGroupWrapper( aGroupId ); + + if ( ! wrapper ) + { + // no wrapper, create one + wrapper = CreateWrapperL( aGroupId ); // CSI: 35 # Ownership is not transferred to caller. + } + + retVal = wrapper->DeleteFromNetworkL(); + } + else + { + // deleting locally, see if we have a wrapper + wrapper = FindGroupWrapper( aGroupId ); + } + + if ( wrapper ) + { + // have wrapper, delete it + DeleteGroupWrapper( aGroupId ); + } + + // delete from storage manager + CHAT_DP_FUNC_DP( "DeleteGroupL", "Deleting from storage" ); + + MCAStoredGroup* group = iStoredGroups->FindGroup( aGroupId ); + + if ( retVal == KErrNone || retVal == ECSPGroupDoesNotExist ) + { + if ( group ) + { + iStoredGroups->DeleteGroupL( group ); + } + } + + // delete the chat data + RemoveChatDataL( groupid ); + CHAT_DP_FUNC_DONE( "DeleteGroupL" ); + + return retVal; + } + +// --------------------------------------------------------- +// CCAGroupManager::IsAllowedAccessL +// check access to given group +// --------------------------------------------------------- +// +TBool CCAGroupManager::IsAllowedAccessL( const TDesC& aGroupId, + const CDesCArray& aCheckUsers, + CDesCArray& aNotInList ) + { + CCAGroupWrapper* wrapper = FindGroupWrapper( aGroupId ); + if ( !wrapper ) + { + // This should never happen, but just in case... + CHAT_DP_TXT( "CCAGroupManager::IsAllowedAccessL - \ + wrapper doesn't exist" ); + return EFalse; + } + MCAStoredGroup& group = wrapper->Group(); + + aNotInList.Reset(); + + // all users, including administrators + CDesCArray* allGroupUsers = + new ( ELeave ) CDesCArrayFlat( KJoinedMembersArrayGranularity ); + CleanupStack::PushL( allGroupUsers ); + group.GetMembersL( *allGroupUsers ); + + TInt checkCount( aCheckUsers.Count() ); + TInt position( 0 ); + + if ( ! IsGroupOpenL( aGroupId ) ) + { + // closed group, so check access + + CHAT_DP_TXT( "IsAllowedAccessL, checking for valid access" ); + // Go through list of users to check and see if + // they're in the list of all users + for ( TInt i( 0 ); i < checkCount; ++i ) + { + if ( allGroupUsers->Find( aCheckUsers[i], position, ECmpCollated ) ) + { + aNotInList.AppendL( aCheckUsers[i] ); + } + } + } + + CImpsCommonGroupProps* commonProps = NULL; + CImpsPrivateGroupProps* privProps = NULL; + GetPropertiesL( aGroupId, commonProps, privProps ); + + TBool isLoggedUserAdmin = group.IsAdmin(); + + CleanupStack::PopAndDestroy( allGroupUsers ); + + return isLoggedUserAdmin; + } + +// check if group is open or closed +TBool CCAGroupManager::IsGroupOpenL( const TDesC& aGroupId ) + { + CImpsCommonGroupProps* commonProps = NULL; + CImpsPrivateGroupProps* privProps = NULL; + GetPropertiesL( aGroupId, commonProps, privProps ); + + return commonProps->IsOpen(); + } + +// map group id to group name +HBufC* CCAGroupManager::GroupNameL( const TDesC& aGroupId ) + { + CImpsCommonGroupProps* commonProps = NULL; + CImpsPrivateGroupProps* privProps = NULL; + GetPropertiesL( aGroupId, commonProps, privProps ); + + HBufC* buf = NULL; + if ( commonProps ) + { + buf = commonProps->GroupName().AllocL(); // CSI: 35 # No leaving code after allocation, ownership transferred to caller. + } + else + { + // can't get group name from properties + // returning empty groupname + buf = KNullDesC().AllocL(); + } + + return buf; + } + +// handles logout event +void CCAGroupManager::HandleNetworkStateChangeL( TNetworkState aState ) + { + if ( aState == ELoggedOut ) + { + RPointerArray groups; + CleanupClosePushL( groups ); + iStoredGroups->PopulateGroupsListL( groups ); + + // loop through all the groups + TInt count( groups.Count() ); + for ( TInt i( 0 ); i < count; i++ ) + { + MCAExtendedStoredGroup* exGrp = + static_cast( groups[ i ] ); + if ( exGrp->IsJoined() ) + { + // the group is joined, so leave it and perform cleanup + exGrp->SetJoined( EFalse ); + iNumJoinedGroups--; + CleanupLeaveGroupL( exGrp->GroupId() ); + } + } + CleanupStack::PopAndDestroy(); // groups.Close() + } + } + +// --------------------------------------------------------- +// CCAGroupManager::LastImpsError +// --------------------------------------------------------- +// +void CCAGroupManager::LastImpsError( TInt aError ) + { + iLastImpsError = aError; + } + +// used internally to find the proper group wrapper +CCAGroupWrapper* CCAGroupManager::FindGroupWrapper( TInt aOpId ) + { + TInt count( iGroupWrappers.Count() ); + + for ( TInt i( 0 ); i < count; i++ ) + { + CCAGroupWrapper* wrapper = iGroupWrappers[i]; + if ( aOpId == wrapper->OperationId() ) + { + // found it + return wrapper; + } + } + + // didn't find it + return NULL; + } + +// used internally to find the proper group wrapper based on group id +CCAGroupWrapper* CCAGroupManager::FindGroupWrapper( const TDesC& aGroupId ) + { + TInt count( iGroupWrappers.Count() ); + + for ( TInt i( 0 ); i < count; i++ ) + { + CCAGroupWrapper* wrapper = iGroupWrappers[i]; + + // get the group the wrapper wraps + MCAStoredGroup& g = wrapper->Group(); + + if ( 0 == CAUtils::NeutralCompare( g.GroupId(), aGroupId ) ) + { + // found it + return wrapper; + } + } + + // didn't find it + return NULL; + } + +// used internally to delete the proper group wrapper based on group id +void CCAGroupManager::DeleteGroupWrapper( const TDesC& aGroupId ) + { + CHAT_DP_FUNC_ENTER( "DeleteGroupWrapper" ); + + TInt count( iGroupWrappers.Count() ); + + for ( TInt i( 0 ); i < count; i++ ) + { + CCAGroupWrapper* wrapper = iGroupWrappers[i]; + + // get the group the wrapper wraps + MCAStoredGroup& g = wrapper->Group(); + + if ( 0 == g.GroupId().CompareC( aGroupId, KCollationLevel, NULL ) ) + { + CHAT_DP_FUNC_DP( "DeleteGroupWrapper", "Found wrapper, deleting it" ); + // found it! delete it + iGroupWrappers.Remove( i ); + delete wrapper; + iGroupWrappers.Compress(); + return; + } + } + + // didn't find it + CHAT_DP_TXT( "CCAGroupManager::DeleteGroupWrapper tried to delete wrapper \ + that doesn't exist!" ); + + CHAT_DP_FUNC_DONE( "DeleteGroupWrapper" ); + } + +// get properties for the given group +void CCAGroupManager::GetPropertiesL( const TDesC& aGroupId, + CImpsCommonGroupProps*& aCommonProps, + CImpsPrivateGroupProps*& aPrivProps ) + { + CHAT_DP_FUNC_ENTER( "PropertiesL" ); + + TBool tempGroup( EFalse ); + MCAStoredGroup* group = iStoredGroups->FindGroup( aGroupId ); + if ( !group ) + { + group = iStoredGroups->CreateGroupL(); // CSI: 35 # Ownership is not transferred to caller. + static_cast( group )->SetGroupIdL( aGroupId ); + static_cast( group )->SetVisible( EFalse ); + tempGroup = ETrue; + } + + CCAGroupWrapper* wrapper = FindGroupWrapper( aGroupId ); + if ( ! wrapper ) + { + wrapper = CreateWrapperL( aGroupId ); // CSI: 35 # Ownership is not transferred to caller. + } + + // ownership does not get transferred + wrapper->GetPropertiesL( aCommonProps, aPrivProps ); + + if ( tempGroup ) + { + DeleteGroupL( aGroupId, EFalse ); + } + + CHAT_DP_FUNC_DONE( "PropertiesL" ); + } + +// create a group wrapper +CCAGroupWrapper* CCAGroupManager::CreateWrapperL( const TDesC& aGroupId ) + { + CHAT_DP_FUNC_ENTER( "CreateWrapperL" ); + + // wrapper needs a group + MCAStoredGroup* group = iStoredGroups->FindGroup( aGroupId ); + if ( !group ) + { + // no such group at all + CHAT_DP_FUNC_DP( "CreateWrapperL", "No group!!" ); + User::Leave( KErrNotFound ); + } + + CHAT_DP_FUNC_DP( "CreateWrapperL", "Found group" ); + + // create a new wrapper + CHAT_DP_FUNC_DP( "CreateWrapperL", "Creating group wrapper" ); + + CCAGroupWrapper* groupWrapper = CCAGroupWrapper::NewL( iSettingsAPI, + static_cast( *group ), iRequestMapper, + iImpsFactory->CreateGroupClientL() ); + CleanupStack::PushL( groupWrapper ); + + // ownership transferred to array + TInt retVal( iGroupWrappers.Append( groupWrapper ) ); + + User::LeaveIfError( retVal ); + CleanupStack::Pop( groupWrapper ); + + CHAT_DP_FUNC_DONE( "CreateWrapperL" ); + + // that's it + return groupWrapper; + } + +// set the private messaging to allowed +TInt CCAGroupManager::SetPrivateAllowedL( CCAGroupWrapper& aWrapper, + CImpsPrivateGroupProps& aPrivProps ) + { + aPrivProps.SetPrivateAllowed( EImpsPropYes ); + // the return value of updateproperties can be ignored because + // there's no point showing "server error" note if the joining + // process was otherwise successful. + TInt operationvalue = aWrapper.UpdatePropertiesL( NULL, &aPrivProps ); + + return operationvalue; + } + +// remove the given chat data +void CCAGroupManager::RemoveChatDataL( const TDesC& aGroupId ) + { + CHAT_DP_FUNC_ENTER( "RemoveChatDataL" ); + iChatInterface.DeleteChatL( KNullDesC, KNullDesC, aGroupId ); + CHAT_DP_FUNC_DONE( "RemoveChatDataL" ); + } + +// --------------------------------------------------------- +// CCAGroupManager::WriteWelcomeMessageL +// --------------------------------------------------------- +// +void CCAGroupManager::WriteWelcomeMessageL( + const TDesC& aWelcomeMessage, + const TDesC& aGroup, + const TDesC& aTopic, + MCAMessagesWriteInterface& aMessages ) + { + // I can't figure out a situation in which these would require a + // datestamp. But if that is the case at some point, use + // CAMessageUtil::AppendMessageWithDateStampL for appending. + + // show customized welcome message + if ( aWelcomeMessage.Length() > 0 ) + { + aMessages.AppendL( + iMessageUtils.MessageCreator().CreateSystemMessageL( + MCAMessage::ESystemMessageWelcome, aWelcomeMessage ) ); + } + // show default welcome message + else + { + HBufC* welcome = + StringLoader::LoadLC( R_SYSTEM_MESSAGE_WELCOME_TEXT, aGroup ); + + aMessages.AppendL( + iMessageUtils.MessageCreator().CreateSystemMessageL( + MCAMessage::ESystemMessageWelcome, *welcome ) ); + + CleanupStack::PopAndDestroy( welcome ); + } + + // Only show real topic + if ( aTopic.Length() > 0 ) + { + // load & show default topic string + HBufC* topicText = + StringLoader::LoadLC( R_SYSTEM_MESSAGE_TOPIC_TEXT, aTopic ); + aMessages.AppendL( + iMessageUtils.MessageCreator().CreateSystemMessageL( + MCAMessage::ESystemMessageWelcome, *topicText ) ); + CleanupStack::PopAndDestroy( topicText ); + } + } +// --------------------------------------------------------- +// CCAGroupManager::CancelGroupOperationL +// --------------------------------------------------------- +// +void CCAGroupManager::CancelGroupOperationL( const TDesC& aGroupId ) + { + CCAGroupWrapper* wrapper = FindGroupWrapper( aGroupId ); + if ( !wrapper ) + { + return; + } + CCARequest* request = wrapper->Request(); + if ( request ) + { + request->StopWaitIfNeeded(); + request->SetErrorCode( EOperationCancelled ); + } + } +// End of File