emailservices/emailserver/cmailhandlerplugin/src/fsnotificationhandlerbaseimpl.cpp
branchRCL_3
changeset 64 3533d4323edc
child 80 726fba06891a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/emailserver/cmailhandlerplugin/src/fsnotificationhandlerbaseimpl.cpp	Wed Sep 01 12:28:57 2010 +0100
@@ -0,0 +1,403 @@
+/*
+* 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 ) );
+    User::LeaveIfNull( parentFolder );
+    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 ) );
+        User::LeaveIfNull( 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 == NULL )
+            {
+            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 == NULL )
+            {
+            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;
+    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();
+    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();
+    }
+
+
+void Panic( TCmailhandlerPanic aPanic )
+    {
+    _LIT( KPanicText, "emailhandlerplugin" );
+    User::Panic( KPanicText, aPanic );
+    }
+
+// End of file
+