diff -r 000000000000 -r 8466d47a6819 emailservices/emailstore/base_plugin/src/basepluginnotifications.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emailservices/emailstore/base_plugin/src/basepluginnotifications.cpp Thu Dec 17 08:39:21 2009 +0200 @@ -0,0 +1,680 @@ +/* +* Copyright (c) 2006 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: Email interface notification systems implementation. +* +*/ + + + +// +#include "MsgStore.h" +#include "MsgStoreFolder.h" +// + +#include "BasePlugin.h" +#include "baseplugincommonutils.h" + + +/** + * + */ +EXPORT_C void CBasePlugin::SubscribeMailboxEventsL( + const TFSMailMsgId& aMailboxId, + MFSMailEventObserver& aObserver ) + + { + CMailboxInfo& mailBox = GetMailboxInfoL( aMailboxId.Id() ); + + if ( KErrNotFound == mailBox.iObservers.Find( &aObserver ) ) + { + mailBox.iObservers.AppendL( &aObserver ); + } + } + + +/** + * + */ +EXPORT_C void CBasePlugin::UnsubscribeMailboxEvents( + const TFSMailMsgId& aMailboxId, + MFSMailEventObserver& aObserver ) + + { + TRAP_IGNORE( UnsubscribeMailboxEventsL( aMailboxId, aObserver ) ); + } + + +/** + * + */ +EXPORT_C void CBasePlugin::AddObserverL( + MFSMailEventObserver& aObserver ) + { + + if ( KErrNotFound == iObservers.Find( &aObserver ) ) + { + iObservers.AppendL( &aObserver ); + } + + if ( iObservers.Count() == 1 ) + { + iMsgStore->AddObserverL( this ); + } + } + + +/** + * + */ +EXPORT_C void CBasePlugin::RemoveObserver( + MFSMailEventObserver& aObserver ) + { + + TInt idx = iObservers.Find( &aObserver ); + + if ( KErrNotFound != idx ) + { + iObservers.Remove( idx ); + } + + if ( iObservers.Count() == 0 ) + { + TRAP_IGNORE( iMsgStore->RemoveObserverL( this ) ); + } + } + + +/** + * + */ +EXPORT_C void CBasePlugin::UnregisterRequestObserver( + TInt /*aRequestId*/ ) + { + + } + + +#pragma mark - +#pragma mark --- MSGSTORE OBSERVERS --- + + +/** + * + */ +EXPORT_C void CBasePlugin::SystemEventNotify( TMsgStoreSystemEvent aEvent ) + { + TRAP_IGNORE( SystemEventNotifyL( aEvent ) ); + } + + +/** + * + */ +void CBasePlugin::SystemEventNotifyL( TMsgStoreSystemEvent aEvent ) + + { + switch ( aEvent ) + { + // A backup or restore is in progress. The message store is unavailable. + case EMsgStoreBackupOrRestoreInProgress: + // The message store has been wiped, including the password. + case EMsgStoreDatabaseWiped: + // The message store has transitioned from an authenticated state to an unauthenticated state. + case EMsgStoreNotAuthenticated: + { + NotifyGlobalEventL( TFSMailboxUnavailable ); + } + break; + + // The backup or restore completed. The message store is available again. + case EMsgStoreBackupOrRestoreCompleted: + // The message store has transitioned from an unauthenticated state to an authenticated state. + case EMsgStoreAuthenticated: + { + NotifyGlobalEventL( TFSMailboxAvailable ); + } + break; + + // The observer event queue has overflowed and has been reset, so events have been lost. This + // shouldn't happen unless the client thread has been starved for an extended period of time, during + // which many message store operations have occurred. + case EObserverEventQueueOverflow: + //don't see anything meaningful to do here. + break; + }; + } + + +/** + * + */ +EXPORT_C void CBasePlugin::AccountEventNotify( + TMsgStoreAccountEvent aEvent, + TInt32 aOwnerId, + const TDesC& aName, + const TDesC& aNewName, + TMsgStoreId aMailboxId ) + + { + if ( GetPluginId() == aOwnerId ) + { + TRAP_IGNORE( AccountEventNotifyL( aEvent, aOwnerId, aName, aNewName, aMailboxId ) ); + } + } + + +/** + * + */ +void CBasePlugin::AccountEventNotifyL( + TMsgStoreAccountEvent aEvent, + TInt32 /*aOwnerId*/, + const TDesC& /*aName*/, + const TDesC& /*aNewName*/, + TMsgStoreId aMailboxId ) + + { + switch ( aEvent ) + { + case EMsgStoreAccountCreated: + { + TFSMailMsgId mailBox( GetPluginId(), aMailboxId ); + NotifyGlobalEventL( TFSEventNewMailbox, mailBox ); + } + break; + + case EMsgStoreAccountDeleted: + { + //remove from the cache. + if ( KErrNotFound != iMailboxes.Find( aMailboxId ) ) + { + iMailboxes.RemoveL( aMailboxId ); + } + + TFSMailMsgId mailBox( GetPluginId(), aMailboxId ); + + HandleMailboxDeleteL( mailBox ); + + NotifyGlobalEventL( TFSEventMailboxDeleted, mailBox ); + } + break; + + case EMsgStoreAccountRenamed: + { + } + break; + }; + } + + +EXPORT_C void CBasePlugin::HandleMailboxDeleteL( const TFSMailMsgId& /*aMailboxId*/ ) + { + //nothing to do + } + +/** + * + */ +EXPORT_C void CBasePlugin::ModificationNotify( + TMsgStoreId aMailBoxId, + TMsgStoreOperation aOperation, + TMsgStoreContainerType aType, + TUint32 aFlags, + TMsgStoreId aId, + TMsgStoreId aParentId, + TMsgStoreId aOtherId ) + + { + TRAP_IGNORE( ModificationNotifyL( aMailBoxId, aOperation, aType, aFlags, aId, aParentId, aOtherId ) ); + } + + +/** + * + */ +void CBasePlugin::ModificationNotifyL( + TMsgStoreId aMailBoxId, + TMsgStoreOperation aOperation, + TMsgStoreContainerType aType, + TUint32 /*aFlags*/, + TMsgStoreId aId, + TMsgStoreId aParentId, + TMsgStoreId aOtherId ) + + { + __LOG_ENTER( "ModificationNotifyL" ); + CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId ); + + __LOG_WRITE_FORMAT1_INFO( "aMailBoxId = 0x%X.", aMailBoxId ); + __LOG_WRITE_FORMAT1_INFO( "aId = 0x%X.", aId ); + __LOG_WRITE_FORMAT1_INFO( "aParentId = 0x%X.", aParentId ); + + InvalidateCacheIfNecessary( aId, aParentId, aOtherId ); + + if ( mailBox.iObservers.Count() > 0 ) + { + switch ( aOperation ) + { + + case EMsgStoreAdd: + { + __LOG_WRITE_INFO( "EMsgStoreAdd." ); + if ( EMsgStoreMessageContainer == aType ) + { + NotifyEventL( aMailBoxId, aId, aParentId, TFSEventNewMail ); + } + else if ( EMsgStoreFolderContainer == aType ) + { + NotifyEventL( aMailBoxId, aId, aParentId, TFSEventNewFolder ); + } + } + break; + + case EMsgStoreDelete: + { + __LOG_WRITE_INFO( "EMsgStoreDelete." ); + if ( EMsgStoreMessageContainer == aType ) + { + NotifyEventL( aMailBoxId, aId, aParentId, TFSEventMailDeleted ); + } + else if ( EMsgStoreFolderContainer == aType ) + { + TRAPD( err, CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId ) ); + + if ( KErrNone == err ) + { + for ( TInt i = EFSInbox; i <= EFSDeleted; i++ ) + { + if ( mailBox.iRootFolders.iFolders[i] == aId ) + { + TMsgStoreId newId = 0; + + /**@ this behavior is forced by the UI for some reason and should be revisited + * in the future as it allows more than one inbox folder which is not recommended. */ + + //loop over all of the root folders looking for a replacement. + RPointerArray folders; + CleanupResetAndDestroyClosePushL( folders ); + + mailBox().FoldersL( aMailBoxId, folders ); + + for ( int j = 0; j < folders.Count(); j++ ) + { + CMsgStoreFolder* folder = folders[j]; + + TUint index = 0; + if ( folder->FindProperty( KMsgStorePropertyFolderType, index ) ) + { + TUint32 type = folder->PropertyValueUint32L( index ); + + if ( type == i ) //i is a value in the folder type enum. + { + newId = folder->Id(); + break; + } + } + } + + CleanupStack::PopAndDestroy( &folders ); + + //set the new root folder info. + mailBox.iRootFolders.iFolders[i] = newId; + break; + } + } + } + + NotifyEventL( aMailBoxId, aId, aParentId, TFSEventFoldersDeleted ); + } + } + break; + + case EMsgStoreMove: + { + __LOG_WRITE_INFO( "EMsgStoreMove." ); + NotifyEventL( aMailBoxId, aId, aOtherId, TFSEventMailMoved, aParentId ); + break; + } + + case EMsgStoreUpdateProperties: + { + __LOG_WRITE_INFO( "EMsgStoreUpdateProperties." ); + if ( EMsgStoreMessageContainer == aType ) + { + NotifyEventL( aMailBoxId, aId, aParentId, TFSEventMailChanged ); + } + else if ( EMsgStoreFolderContainer == aType ) + { + NotifyEventL( aMailBoxId, aId, aParentId, TFSEventFolderChanged ); + } + else if ( EMsgStoreMailboxContainer == aType ) + { + TBool mailBoxNameHasChanged( EFalse ); + TRAP_IGNORE( RefreshCachedMailBoxDisplayNameL( mailBoxNameHasChanged, aMailBoxId ) ); + + if ( mailBoxNameHasChanged ) + { + NotifyEventL( aMailBoxId, aId, aParentId, TFSEventMailboxRenamed ); + } + } + } + break; + + case EMsgStoreRemoveContent: + break; + + default: + break; + } + } + /* Reporting request status moved from above if-statement here. Now, request status is reported even there is no + * mailbox observers. + */ + switch ( aOperation ) + { + case EMsgStoreUpdateProperties: + { + if ( EMsgStorePartContainer == aType ) + { + ReportRequestStatusL( aMailBoxId, aOtherId, aParentId, aId ); + } + } + break; + /**@ check whether the ui removes the observer - then the observer must be kept + until there are pending reqs ?*/ + //attachment download request handling. + case EMsgStoreUpdateContent: + { + __LOG_WRITE_INFO( "EMsgStoreUpdateContent." ); + ReportRequestStatusL( aMailBoxId, aOtherId, aParentId, aId, ETrue ); + } + break; + + default: + break; + } + + + __LOG_EXIT; + } //ModificationNotifyL. + + +/** + * + */ +void CBasePlugin::NotifyEventL( + TMsgStoreId aMailBoxId, + TMsgStoreId aId, + TMsgStoreId aParentId, + TFSMailEvent aFsEvent, + TMsgStoreId aOtherId /*=KMsgStoreInvalidId*/ ) + + { + CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId ); + + TFSMailMsgId mailBoxId( GetPluginId(), aMailBoxId ); + TFSMailMsgId parent( GetPluginId(), aParentId ); + TFSMailMsgId other( GetPluginId(), aOtherId ); + + TFSMailMsgId* param3 = NULL; + if ( KMsgStoreInvalidId != aOtherId ) + { + param3 = &other; + } + + RArray entries; + CleanupClosePushL( entries ); + + TFSMailMsgId entry( GetPluginId(), aId ); + entries.AppendL( entry ); + + TInt count = mailBox.iObservers.Count(); + for ( TInt i = 0; i < count; i++ ) + { + mailBox.iObservers[i]->EventL( aFsEvent, mailBoxId, &entries, &parent, param3 ); + } + + CleanupStack::PopAndDestroy( &entries ); + } + + +/** + * + */ +void CBasePlugin::NotifyGlobalEventL( + TFSMailEvent aEvent, + TFSMailMsgId aMailBox /*=TFSMailMsgId()*/, //defaults to a null id. + TAny* aParam1 /*=NULL*/, + TAny* aParam2 /*=NULL*/, + TAny* aParam3 /*=NULL*/ ) + + { + TInt count = iObservers.Count(); + + for ( TInt i = 0; i < count; i++ ) + { + iObservers[i]->EventL( aEvent, aMailBox, aParam1, aParam2, aParam3 ); + } + } + +/** + * + */ +EXPORT_C void CBasePlugin::NotifyMailboxEventL( + TFSMailEvent aEvent, + TFSMailMsgId aMailBox, + TAny* aParam1 /*=NULL*/, + TAny* aParam2 /*=NULL*/, + TAny* aParam3 /*=NULL*/ ) + { + CMailboxInfo& mailBox = GetMailboxInfoL( aMailBox.Id() ); + + for ( TInt i = 0; i < mailBox.iObservers.Count(); i++ ) + { + mailBox.iObservers[i]->EventL( aEvent, aMailBox, aParam1, aParam2, aParam3 ); + } + } + + +/** + * + */ +EXPORT_C /*protected virtual*/ void CBasePlugin::ReportRequestStatusL( + TMsgStoreId aMailBox, + TMsgStoreId aOtherId, + TMsgStoreId aMsgId, + TMsgStoreId aPartId, + TBool aCanReportCompletion /*=EFalse*/ ) + + { + __LOG_ENTER( "ReportRequestStatusL" ); + + __LOG_WRITE_FORMAT1_INFO( "aMailBox : 0x%X.", aMailBox ); + __LOG_WRITE_FORMAT1_INFO( "aMsgId : 0x%X.", aMsgId ); + __LOG_WRITE_FORMAT1_INFO( "aPartId : 0x%X.", aPartId ); + + TOngoingFetchInfo fetchInfo; + if ( FindFetchRequestL( aMailBox, aOtherId, aMsgId, aPartId, fetchInfo ) ) + { + __LOG_WRITE_INFO( "Request match found." ); + + CMailboxInfo& mailBox = GetMailboxInfoL( aMailBox ); + + //get the fetched and the server sizes. + CMsgStoreMessage* msg = mailBox().FetchMessageL( + fetchInfo.iMessageId, KMsgStoreInvalidId ); + CleanupStack::PushL( msg ); + CMsgStoreMessagePart* part = msg->ChildPartL( aPartId, ETrue ); + CleanupStack::PushL( part ); + + TUint32 size = 0; + TUint idx = 0; + if ( part->FindProperty( KMsgStorePropertySize, idx ) ) + { + size = part->PropertyValueUint32L( idx ); + } + + TUint32 fetchedSize = 0; + idx = 0; + if ( part->FindProperty( KMsgStorePropertyRetrievedSize, idx ) ) + { + fetchedSize = part->PropertyValueUint32L( idx ); + } + + CleanupStack::PopAndDestroy( part ); + CleanupStack::PopAndDestroy( msg ); + + TFSProgress progress; + progress.iError = KErrNone; + progress.iMaxCount = size; + progress.iCounter = fetchedSize; + + __LOG_WRITE_FORMAT2_INFO( + "Size: %d, fetched size: %d.", size, fetchedSize ); + + if ( fetchedSize < size ) + { + __LOG_WRITE_INFO( "Download in progress, about to notify the UI." ); + + progress.iProgressStatus = TFSProgress::EFSStatus_Status; + fetchInfo.iRequest->iObserver.RequestResponseL( + progress, fetchInfo.iRequest->iRequestId ); + } + else if ( aCanReportCompletion ) + { + if ( DeleteFetchRequestForPart( fetchInfo ) ) + { + //no more parts left for downloading thus completed. + progress.iProgressStatus + = TFSProgress::EFSStatus_RequestComplete; + __LOG_WRITE_INFO( "Download completed for all parts." ); + + fetchInfo.iRequest->iObserver.RequestResponseL( + progress, fetchInfo.iRequest->iRequestId ); + DeleteFetchRequest( fetchInfo ); + } + else + { + progress.iProgressStatus + = TFSProgress::EFSStatus_Status; + __LOG_WRITE_INFO( "A part download completed, more is left." ); + + fetchInfo.iRequest->iObserver.RequestResponseL( + progress, fetchInfo.iRequest->iRequestId ); + } + } + } + + __LOG_EXIT; + } + + +/** + * @return ETrue in case there are no more parts left for downloading. + */ +EXPORT_C /*protected*/ TBool CBasePlugin::DeleteFetchRequestForPart( + TOngoingFetchInfo& aFetchInfo ) + { + //remove the downloaded part from the request object. + aFetchInfo.iRequest->iParts.Remove( aFetchInfo.iPartIndex ); + + return 0 == aFetchInfo.iRequest->iParts.Count(); + } + + +/** + * + */ +EXPORT_C /*protected*/ void CBasePlugin::DeleteFetchRequest( + TOngoingFetchInfo& aFetchInfo ) + { + iReqs.Remove( aFetchInfo.iRequestIndex ); + delete aFetchInfo.iRequest; + } + + +/** + * + */ +EXPORT_C TBool CBasePlugin::FindFetchRequestL( + TMsgStoreId aMailBox, + TMsgStoreId aOtherId, + TMsgStoreId aMsgId, + TMsgStoreId aPartId, + CBasePlugin::TOngoingFetchInfo& aOngoingFetchInfo ) + { + + for ( TInt count = iReqs.Count(); aOngoingFetchInfo.iRequestIndex < count; + aOngoingFetchInfo.iRequestIndex++ ) + { + TFSMailMsgId fsId( GetPluginId(), aPartId ); + CFetchRequester* request = iReqs[aOngoingFetchInfo.iRequestIndex]; + + //a request might specify more than one part for download, find the + //index of the currently processed part. + TInt partsCount = request->iParts.Count(); + for ( TInt i = 0; i < partsCount; i++ ) + { + if ( fsId == request->iParts[i] ) + { + aOngoingFetchInfo.iPartIndex = i; + break; + } + } + + //there are MsgStore notification that receive the message id in the + //"other" id, determine for sure the id of the message this part belongs + //to. + if ( aMsgId == request->iMessageId.Id() ) + { + aOngoingFetchInfo.iMessageId = aMsgId; + } + else if ( aOtherId + == request->iMessageId.Id() ) + { + aOngoingFetchInfo.iMessageId = aOtherId; + } + + //final check before choosing the download request object that + //identifies this part download request. + if ( aMailBox == request->iMailBoxId.Id() + && KMsgStoreInvalidId != aOngoingFetchInfo.iMessageId + && KErrNotFound != aOngoingFetchInfo.iPartIndex ) + { + aOngoingFetchInfo.iRequest = request; + break; + } + } + + return NULL != aOngoingFetchInfo.iRequest; + } //FindRequestL. + + +/** + * + */ +void CBasePlugin::UnsubscribeMailboxEventsL( + const TFSMailMsgId& aMailboxId, + MFSMailEventObserver& aObserver ) + + { + CMailboxInfo& mailBox = GetMailboxInfoL( aMailboxId.Id() ); + + TInt idx = mailBox.iObservers.Find( &aObserver ); + + if ( KErrNotFound != idx ) + { + mailBox.iObservers.Remove( idx ); + } + }