emailservices/emailserver/cmailhandlerplugin/src/fsnotificationhandlerbaseimpl.cpp
/*
* Copyright (c) 2007 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: This file implements class CFSNotificationHandlerBase.
*
*/
#include <centralrepository.h>
#include "emailtrace.h"
#include "cfsmailclient.h"
#include "fsnotificationhandlermgr.h"
#include "fsnotificationhandlerbase.h"
#include "cmailhandlerpluginpanic.h"
#include "commonemailcrkeys.h"
#include "freestyleemailcenrepkeys.h"
#include "FreestyleEmailUiConstants.h"
const TInt KTimerDelay = 20;
// ======== MEMBER FUNCTIONS ========
CFSNotificationHandlerBase::CFSNotificationHandlerBase(
MFSNotificationHandlerMgr& aOwner ) :
iOwner( aOwner ),
iObserving( EFalse )
{
FUNC_LOG;
}
void CFSNotificationHandlerBase::ConstructL()
{
FUNC_LOG;
iTimer = CNewMailNotificationTimer::NewL( *this );
}
CFSNotificationHandlerBase::~CFSNotificationHandlerBase()
{
FUNC_LOG;
REComSession::DestroyedImplementation( iDestructorKey );
delete iTimer;
iNewInboxEntries.Reset();
}
CFSMailClient& CFSNotificationHandlerBase::MailClient() const
{
FUNC_LOG;
return iOwner.MailClient();
}
void CFSNotificationHandlerBase::EventL( TFSMailEvent aEvent, TFSMailMsgId aMailbox,
TAny* aParam1, TAny* aParam2, TAny* aParam3 )
{
FUNC_LOG;
if ( !iObserving )
{
return;
}
HandleEventL( aEvent, aMailbox, aParam1, aParam2, aParam3 );
}
void CFSNotificationHandlerBase::SetObserving( TBool aNewValue )
{
FUNC_LOG;
iObserving = aNewValue;
}
TBool CFSNotificationHandlerBase::MsgIsUnread( CFSMailMessage& aMessage ) const
{
FUNC_LOG;
TBool read( aMessage.IsFlagSet( EFSMsgFlag_Read ) );
TBool read_locally( aMessage.IsFlagSet( EFSMsgFlag_Read_Locally ) );
if ( !read && !read_locally )
{
return ETrue;
}
else
{
return EFalse;
}
}
TBool CFSNotificationHandlerBase::MessagesCauseNotificationL( TFSMailMsgId aMailboxId,
TFSMailMsgId aParentFolderId,
const RArray<TFSMailMsgId>& aMsgIdList )
{
FUNC_LOG;
CFSMailFolder* parentFolder(
MailClient().GetFolderByUidL( aMailboxId, aParentFolderId ) );
if ( !parentFolder )
{
// by some reason the folder could not be found..
return EFalse;
}
CleanupStack::PushL( parentFolder );
CFSMailMessage* newestMsg( NULL );
TRAPD( notFoundError,
newestMsg =
NewestMsgInFolderL( *parentFolder ) );
if ( notFoundError == KErrNotFound )
{
// For some odd reason we are not able to get the newest
// message from the folder. This should not be possible
// as we just received notification of a new message.
// Possibly something has moved/deleted the message?
return EFalse;
}
User::LeaveIfError( notFoundError );
TTime dateOfNewest( newestMsg->GetDate() );
delete newestMsg;
newestMsg = NULL;
CleanupStack::PopAndDestroy( parentFolder );
const TInt entriesCount( aMsgIdList.Count() );
TInt index( entriesCount-1 );
// go from back of list, as messages are coming from earliest to latest..
while ( index >= 0 )
{
// Let's get the message. We need to check from it that
// it is really unread. This info is stored in the
// flags. Also check that the message is newest.
// EFSMsgDataEnvelope is used as TFSMailDetails
// so that we get enough data.
CFSMailMessage*
currentMessage( MailClient().GetMessageByUidL(
aMailboxId,
aParentFolderId,
aMsgIdList[index],
EFSMsgDataEnvelope ) );
if ( currentMessage )
{
const TTime dateOfCurrentMsg( currentMessage->GetDate() );
const TBool msgIsUnread( MsgIsUnread( *currentMessage ) );
delete currentMessage;
currentMessage = NULL;
if ( msgIsUnread &&
( dateOfCurrentMsg >= dateOfNewest ) )
{
// At least one of the messages is unread and newest.
return ETrue;
}
}
--index;
}
return EFalse;
}
TBool CFSNotificationHandlerBase::Observing() const
{
FUNC_LOG;
return iObserving;
}
TBool CFSNotificationHandlerBase::CapabilitiesToContinueL(
TFSMailEvent aEvent,
TFSMailMsgId aMailbox,
TAny* /*aParam1*/,
TAny* /*aParam2*/,
TAny* /*aParam3*/ ) const
{
FUNC_LOG;
if ( aEvent != TFSEventMailboxDeleted )
{
CFSMailBox* mailBox( MailClient().GetMailBoxByUidL( aMailbox ) );
if ( !mailBox )
{
User::Leave( KErrArgument );
}
if ( mailBox->HasCapability( EFSMBoxCapaNewEmailNotifications ) )
{
delete mailBox;
return EFalse;
}
else
{
delete mailBox;
return ETrue;
}
}
else
{
return ETrue;
}
}
void CFSNotificationHandlerBase::HandleEventL(
TFSMailEvent aEvent,
TFSMailMsgId aMailbox,
TAny* aParam1,
TAny* aParam2,
TAny* /*aParam3*/ )
{
FUNC_LOG;
// Only event TFSEventNewMail means that the mail is completely new.
if ( aEvent == TFSEventNewMail )
{
// In case of TFSEventNewMail we have parent folder id
// in aParam2
TFSMailMsgId* parentFolderId( NULL );
parentFolderId = static_cast< TFSMailMsgId* >( aParam2 );
if ( !parentFolderId )
{
User::Leave( KErrArgument );
}
// Set the notification on only in cases that the new mail is
// in folder of type EFSInbox
if ( iOwner.GetFolderTypeL( aMailbox, parentFolderId ) == EFSInbox )
{
RArray<TFSMailMsgId>* newEntries(
static_cast< RArray<TFSMailMsgId>* >( aParam1 ) );
TInt count = newEntries->Count();
for ( TInt i = 0; i<count;i++ )
{
TFSMailMsgId msgId = newEntries->operator []( i );
TNewMailInfo info( msgId, aMailbox, *parentFolderId );
iNewInboxEntries.AppendL( info );
}
if (iTimer->IsActive() )
{
iTimer->Cancel();
}
iTimer->After( KTimerDelay );
}
else
{
// If messages are in some other folder than in inbox
// they have no effect on the notification
}
}
else
{
// No other events than new mail are handled. For example
// moving of messages and changing message status has no
// effect on the notification.
}
}
void CFSNotificationHandlerBase::TimerExpiredL()
{
// process collected insert requests
RArray<TFSMailMsgId> msgIds;
CleanupClosePushL( msgIds );
TFSMailMsgId mailBoxId;
TFSMailMsgId parentFolderId;
for ( TInt i = 0; i< iNewInboxEntries.Count(); i++ )
{
TNewMailInfo& info = iNewInboxEntries[ i ];
if ( mailBoxId.IsNullId() && parentFolderId.IsNullId() )
{
// starting new group is starting to collect
mailBoxId = info.iMailBox;
parentFolderId = info.iParentFolderId;
}
if ( mailBoxId == info.iMailBox && parentFolderId == info.iParentFolderId )
{
// collect message ids for the same mailbox and parent folder
msgIds.Append( info.iMsgId );
}
else
{
// process collected message ids for the same mailbox and parent folder
if ( msgIds.Count()&& MessagesCauseNotificationL( mailBoxId, parentFolderId, msgIds ) )
{
TurnNotificationOn();
}
// clear data and start collecting again
msgIds.Reset();
mailBoxId = TFSMailMsgId();
parentFolderId = TFSMailMsgId();
}
}
// process collected message ids for the same mailbox and parent folder
if ( msgIds.Count() && MessagesCauseNotificationL( mailBoxId, parentFolderId, msgIds ) )
{
TurnNotificationOn();
}
// clear processed entries
msgIds.Reset();
CleanupStack::PopAndDestroy( &msgIds );
iNewInboxEntries.Reset();
}
CFSMailMessage* CFSNotificationHandlerBase::NewestMsgInFolderL(
CFSMailFolder& aFolder ) const
{
FUNC_LOG;
// Load info only necessary for sorting by date into the messages.
TFSMailDetails details( EFSMsgDataDate );
// Want to sort mails so that the newest is in the beginning
TFSMailSortCriteria criteriaDate;
criteriaDate.iField = EFSMailSortByDate;
criteriaDate.iOrder = EFSMailDescending;
RArray<TFSMailSortCriteria> sorting;
CleanupClosePushL( sorting );
// First criteria appended would be the primary criteria
// but here we don't have any other criteria
sorting.Append( criteriaDate );
MFSMailIterator* iterator = aFolder.ListMessagesL( details, sorting );
// Resetting array of sort criteria already here because
// the iterator does not need it anymore.
CleanupStack::PopAndDestroy( &sorting );
// CleanupStack::PushL doesn't work for M-class
CleanupDeletePushL( iterator );
RPointerArray<CFSMailMessage> messages;
CleanupClosePushL( messages );
// Let's get only the first and therefore the newest message.
TInt amount( 1 );
iterator->NextL( TFSMailMsgId(), amount, messages );
if ( messages.Count() < 1 )
{
messages.ResetAndDestroy();
User::Leave( KErrNotFound );
}
CFSMailMessage* outcome = messages[0];
messages.Remove( 0 ); // remove from array to prevent destruction of element
messages.ResetAndDestroy();
CleanupStack::PopAndDestroy( &messages );
CleanupStack::PopAndDestroy( iterator );
return outcome;
}
CNewMailNotificationTimer::CNewMailNotificationTimer( MFSTimerObserver& aObserver ) :
CTimer( EPriorityIdle ), iObserver( aObserver )
{
FUNC_LOG;
}
void CNewMailNotificationTimer::ConstructL()
{
FUNC_LOG;
CTimer::ConstructL();
CActiveScheduler::Add( this );
}
CNewMailNotificationTimer* CNewMailNotificationTimer::NewL(
MFSTimerObserver& aObserver )
{
FUNC_LOG;
CNewMailNotificationTimer* self =
new( ELeave ) CNewMailNotificationTimer( aObserver );
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
CNewMailNotificationTimer::~CNewMailNotificationTimer()
{
FUNC_LOG;
Cancel();
}
void CNewMailNotificationTimer::DoCancel()
{
FUNC_LOG;
// Cancel Base class
CTimer::DoCancel();
}
void CNewMailNotificationTimer::RunL()
{
FUNC_LOG;
iObserver.TimerExpiredL();
}
TInt CNewMailNotificationTimer::RunError(TInt aError)
{
if( aError )
{
INFO_1( "CNewMailNotificationTimer::RunError( aError: %d )", aError );
}
return KErrNone;
}
void Panic( TCmailhandlerPanic aPanic )
{
_LIT( KPanicText, "emailhandlerplugin" );
User::Panic( KPanicText, aPanic );
}
// End of file