/*
* Copyright (c) 2009 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 CEmailClientApi.
*
*/
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include <viewclipartner.h>
#include <vwsdefpartner.h>
#else
#include <viewcli.h>
#include <vwsdef.h>
#endif // SYMBIAN_ENABLE_SPLIT_HEADERS
#include <coemain.h> // CCoeEnv
#include <coeaui.h> // CCoeAppUi
#include <centralrepository.h>
#include "emailclientapiimpl.h"
#include "emailapiutils.h"
#include "emailmailbox.h"
#include <memailaddress.h>
#include "cfsmailplugin.h"
#include "cfsclientapi.h"
#include "emailclientapiimpldefs.h"
#include "emailmailboxcache.h"
#include "FreestyleEmailUiConstants.h"
#include "emailclientapi.hrh"
#include "freestyleemailcenrepkeys.h"
#include "FreestyleEmailUiConstants.h"
// ---------------------------------------------------------------------------
// CEmailClientApi::MailboxL
// ---------------------------------------------------------------------------
//
MEmailMailbox* CEmailClientApi::MailboxL( const TMailboxId& aId )
{
UpdateMailboxInfoCacheL();
CPluginData* pluginData = MailboxInfoCacheL().PluginDataL( aId );
MEmailMailbox* mailbox = NULL;
if ( pluginData )
{
mailbox = CEmailMailbox::NewL( *pluginData, aId );
}
return mailbox;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
MEmailMailbox* CEmailClientApi::MailboxL( const TPtrC& aAddress )
{
MEmailMailbox* mailbox = NULL;
REmailMailboxIdArray mailboxes;
CleanupClosePushL( mailboxes );
TInt count( GetMailboxIdsL( mailboxes ) );
while ( count-- )
{
const TMailboxId mailboxId = mailboxes[count];
MEmailMailbox* refMailbox = MailboxL( mailboxId );
if ( refMailbox )
{
TPtrC address( refMailbox->AddressL()->Address() );
if ( !address.Compare( aAddress ) )
{
mailbox = refMailbox; // addresses match
count = 0;
}
else
{
refMailbox->Release();
}
}
}
CleanupStack::PopAndDestroy();
// find mailbox or leave KErrNotFound
if ( !mailbox)
{
User::Leave( KErrNotFound );
}
return mailbox;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
TInt CEmailClientApi::GetMailboxIdsL(
REmailMailboxIdArray& aMailboxes )
{
UpdateMailboxInfoCacheL();
aMailboxes.Reset();
CEmailMailboxCache& mbcache = MailboxInfoCacheL();
mbcache.GetIdsL( aMailboxes );
const TInt mailboxesFound( aMailboxes.Count() );
return mailboxesFound;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
TInt CEmailClientApi::GetMailboxesL( RMailboxPtrArray& aMailboxes )
{
REmailMailboxIdArray mailboxIdArray;
CleanupClosePushL( mailboxIdArray );
// note! GetMailboxIdsL loads plugin and keeps loaded if it contains at
// least one mailbox
TInt count = GetMailboxIdsL( mailboxIdArray );
while ( count-- )
{
// mailbox creation increases plugin ref count by one
MEmailMailbox* mailbox = MailboxL( mailboxIdArray[count] );
CleanupReleasePushL( *mailbox );
aMailboxes.AppendL( mailbox );
CleanupStack::Pop( mailbox );
}
// Created mailboxes still hold plugin references so we can decrease
// ref count.
ReleaseAllPlugins();
CleanupStack::PopAndDestroy(); // mailboxIdArray
return aMailboxes.Count();
}
// -----------------------------------------------------------------------------
// implement this
// -----------------------------------------------------------------------------
void CEmailClientApi::LaunchEmailL( const TLaunchPolicy aPolicy )
{
if ( aPolicy == EShowLastUnseenMailbox)
{
CRepository* emailRepository = CRepository::NewL( KFreestyleEmailCenRep );
CleanupStack::PushL(emailRepository);
TInt numberOfMailboxes(0);
TInt inboxId(0);
TInt pluginId(0);
emailRepository->Get(KNumberOfMailboxesWithNewEmails,numberOfMailboxes);
if(numberOfMailboxes > 0)
{
emailRepository->Get(KNumberOfMailboxesWithNewEmails+(numberOfMailboxes*2-1),pluginId);
emailRepository->Get(KNumberOfMailboxesWithNewEmails+(numberOfMailboxes*2),inboxId);
TUid pluginUid = {pluginId};
TMailListActivationData activationData;
activationData.iMailBoxId.SetId(inboxId);
activationData.iMailBoxId.SetPluginId(pluginUid);
activationData.iFolderId.SetPluginId(pluginUid);
TPckgBuf<TMailListActivationData> pkgBuf(activationData);
CCoeEnv::Static()->AppUi()->CreateActivateViewEventL(
TVwsViewId(KFSEmailUiUid, MailListId), KStartListWithFolderId,
pkgBuf );
}
else
{
// We should never come here since the mailbox count should be more than 0 if launchemailL is called
// but just to be safe launch the email in launchergrid if something went wrong with the repository
const TUid dummy = {0};
CCoeEnv::Static()->AppUi()->CreateActivateViewEventL(TVwsViewId(KFSEmailUiUid, AppGridId),
dummy, KNullDesC8() );
}
CleanupStack::PopAndDestroy();//emailRepository
}
else if ( aPolicy == EDefault )
{
const TUid dummy = {0};
CCoeEnv::Static()->AppUi()->CreateActivateViewEventL(TVwsViewId(KFSEmailUiUid, AppGridId),
dummy, KNullDesC8() );
}
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
CPluginData* CEmailClientApi::TPluginIterator::Next()
{
CPluginData* item = NULL;
if ( iIndex < iArray.Count() )
{
item = iArray[ iIndex++ ];
}
return item;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
CEmailClientApi* CEmailClientApi::NewL()
{
CEmailClientApi* instance = static_cast<CEmailClientApi*>( Dll::Tls() );
if ( instance == NULL )
{
instance = new ( ELeave ) CEmailClientApi();
CleanupStack::PushL( instance );
instance->ConstructL();
User::LeaveIfError( Dll::SetTls( instance ) );
CleanupStack::Pop();
}
instance->iInstanceCounter++;
return instance;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
CEmailClientApi::~CEmailClientApi()
{
// ensure this doesn't held plugin references
ReleaseAllPlugins();
// ResetAndDestroy doesn't work because ~CPluginData is private
TInt count( iPluginDataArray.Count() );
while ( count-- )
{
delete iPluginDataArray[count];
}
iPluginDataArray.Close();
iLoadedPluginsArray.Close();
delete iMailboxCache;
delete iClientAPI;
Dll::FreeTls();
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
CEmailClientApi::CEmailClientApi() : iInstanceCounter( 0 )
{
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CEmailClientApi::CleanupImplInfoPushL( RPointerArray<CImplementationInformation>& aArray )
{
TCleanupItem item( &CEmailClientApi::CleanupImplInfo, &aArray );
CleanupStack::PushL( item );
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CEmailClientApi::CleanupImplInfo( TAny* aAny )
{
RPointerArray<CImplementationInformation>* array =
reinterpret_cast<RPointerArray<CImplementationInformation>*>( aAny );
array->ResetAndDestroy();
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CEmailClientApi::ConstructL()
{
RPointerArray<CImplementationInformation> implInfoArray;
REComSession::ListImplementationsL( KFSMailPluginInterface, implInfoArray );
CleanupImplInfoPushL( implInfoArray );
TInt err = KErrNone;
TInt count( implInfoArray.Count() );
// add implementation UIDs to plugin info array, no instantiation at this
// phase
while ( count-- )
{
const CImplementationInformation* info = implInfoArray[count];
CPluginData* pluginData = new ( ELeave ) CPluginData( info->ImplementationUid() );
err = iPluginDataArray.Append( pluginData );
if ( err != KErrNone )
{
// failed to append, give up
delete pluginData;
count = 0;
}
}
iClientAPI = CFSClientAPI::NewL(this);
CleanupStack::PopAndDestroy(); // CleanupImplInfoPushL
User::LeaveIfError( err );
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
TEmailTypeId CEmailClientApi::InterfaceId() const
{
return KEmailClientApiInterface;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CEmailClientApi::Release()
{
if( this->iInstanceCounter == 1 )
{
delete this;
}
else
{
this->iInstanceCounter--;
}
}
// -----------------------------------------------------------------------------
// Returns plugin instance from plugin data. If we already have "claimed"
// instance once, prevent increment of reference count
// -----------------------------------------------------------------------------
CFSMailPlugin* CEmailClientApi::UsePlugin( CPluginData& aPluginData )
{
// use 'data' as search key for IndexOfLoadedPluginData()
TPluginData data( aPluginData.Uid() );
TPluginData* pluginDataPtr = &data;
// check if we have plugin already "in use".
const TInt index( IndexOfLoadedPluginData( data ) );
if ( index == KErrNotFound )
{ // we don't have plugin instance so take it and add to loaded plugins
data.iPlugin = aPluginData.ClaimInstance();
if ( data.iPlugin && iLoadedPluginsArray.Append( data ) != KErrNone )
{
aPluginData.ReleaseInstance(); // failed to append, don't proceed..
data.iPlugin = NULL; // but return null
}
}
else
{
// already in use, obtain plugin pointer from the array
pluginDataPtr = &iLoadedPluginsArray[index];
}
return pluginDataPtr->iPlugin;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CEmailClientApi::ReleasePlugin( CPluginData& aPluginData )
{
// release plugin but only if it is not already claimed
TPluginData data( aPluginData.Uid() );
const TInt index( IndexOfLoadedPluginData( data ) );
if ( index != KErrNotFound )
{
aPluginData.ReleaseInstance();
iLoadedPluginsArray.Remove( index );
}
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CEmailClientApi::ReleaseAllPlugins()
{
for ( TInt i = 0; i < iPluginDataArray.Count(); i++ )
{
CPluginData* pdata = iPluginDataArray[i];
ReleasePlugin( *pdata );
}
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
CEmailMailboxCache& CEmailClientApi::MailboxInfoCacheL()
{
if ( !iMailboxCache)
{
iMailboxCache = CEmailMailboxCache::NewL();
}
return *iMailboxCache;
}
// -----------------------------------------------------------------------------
// Lists all mailboxes in protocol plugins and adds them to cache. Plugins may
// not be loaded so loading is done. The plugin is kept in memory if it contains
// at least one mailbox to avoid loading again later as typical use case is
// creation of a mailbox object => the plugin is again needed
//( see ::GetMailboxesL which calls ReleaseAllPlugins()
// -----------------------------------------------------------------------------
void CEmailClientApi::UpdateMailboxInfoCacheL()
{
CEmailMailboxCache& mbcache = MailboxInfoCacheL();
if ( !mbcache.IsCached() )
{
// cache update needed
mbcache.StartCachingPushL();
TPluginIterator iter( iPluginDataArray );
CPluginData* pluginData = iter.Next();
while ( pluginData )
{
TBool containsMailbox( EFalse );
// loads plugin if needed
CFSMailPlugin* plugin = UsePlugin( *pluginData );
if ( plugin )
{
// if one plugin fails, it should not block other plugins
// ==> trap it
TRAPD( err, containsMailbox = CachePluginMailboxesL(
*pluginData,
*plugin ) );
if ( !containsMailbox || err )
{
// plugins with no mailboxes (or failed to cache) is
// released (unloaded) to optimize RAM usage.
ReleasePlugin( *pluginData );
}
}
else if ( pluginData->iPluginLoadError == KErrNoMemory )
{
// don't continue if OOM
User::Leave( KErrNoMemory );
}
pluginData = iter.Next();
}
mbcache.EndCachingPop();
}
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
TBool CEmailClientApi::CachePluginMailboxesL( CPluginData& aPluginData, CFSMailPlugin& aPlugin )
{
TBool containsMailbox( EFalse );
RArray<TFSMailMsgId> pluginMailboxes;
CleanupClosePushL( pluginMailboxes );
aPlugin.ListMailBoxesL( pluginMailboxes );
TInt mailboxCount = pluginMailboxes.Count();
while ( mailboxCount-- )
{
const TFSMailMsgId& mailboxId = pluginMailboxes[mailboxCount];
TMailboxId id( mailboxId.Id() );
MailboxInfoCacheL().AddMailboxL( aPluginData, id );
containsMailbox = ETrue;
}
CleanupStack::PopAndDestroy(); // pluginMailboxes
return containsMailbox;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
TInt CEmailClientApi::IndexOfLoadedPluginData( const TPluginData& aPluginData ) const
{
TIdentityRelation<TPluginData> relation( CEmailClientApi::PluginDataEquals );
return iLoadedPluginsArray.Find( aPluginData, relation );
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
TBool CEmailClientApi::PluginDataEquals( const TPluginData& a1, const TPluginData& a2 )
{
return ( a1.iUid == a2.iUid );
}
CFSMailPlugin* CEmailClientApi::GetPluginByUid(TUid aUid)
{
CPluginData *p = NULL;
CFSMailPlugin* plugin = NULL;
TRAP_IGNORE( p = iMailboxCache->PluginDataL(aUid) );
if ( p )
{
plugin = p->ClaimInstance();
p->ReleaseInstance();
}
return plugin;
}
// End of file.