diff -r 000000000000 -r 72b543305e3a messagingappbase/msgerrorwatcher/src/MsgErrorWatcher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/messagingappbase/msgerrorwatcher/src/MsgErrorWatcher.cpp Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,1961 @@ +/* +* Copyright (c) 2002 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: +* CMsgErrorWatcher implementation file +* +*/ + + + +// INCLUDE FILES +#include + +#include +#include //Msv index entry ID's +#include +#include //EMmsScheduledReceiveForced +#include //Notification folder +#include //MTM Uids +#include //ClientMtmRegistry +#include +#include +#include +#include +#include // resouce identifiers +#include // resouce identifiers +#include + +#include +#include +#include +#include + +#include +#include +#include +#include // KErrIfAuthenticationFailure +#include // KErrGprsInsufficientResources, etc. +#include // KErrGsmMMServiceOptionTemporaryOutOfOrder +#include + +#include // link against centralrepository.lib +#include // for Central Repository keys + +#include // Variation + +#include "MsgErrorWatcher.h" +#include "MsgErrorWatcher.hrh" +#include "MsgSentItemsObserver.h" +#include "MsgErrorCommDbObserver.h" +#include "MsgCenRepObserver.h" +#include "MsgErrorConnectionObserver.h" +#include "MsgErrorDiskSpaceObserver.h" +#include "MsgErrorSmsDiskSpaceObserver.h" +#include "MsgErrorExtSmsDiskSpaceObserver.h" +#include "MsgErrorRoamingObserver.h" +#include "MsgErrorGlobalQuery.h" +#include "MsgErrorDisconnectDlg.h" +#include "MsgErrorStartupObserver.h" +#include "MsgLogsObserver.h" +#include "MsgGarbageCollection.h" + +#include "MsgErrorWatcherLogging.h" + +#include + +// LOCAL CONSTANTS AND MACROS +_LIT( KMsgErrorWatcherResourceFileName, "msgerrorwatcherdata.rsc" ); +const TUint KArrayGranularity = 5; +const TInt KDelayBetweenNotes = 2000000; //2 seconds +const TInt KDelayAfterDisconnect = 3000000; //3 seconds +const TInt KConnectionRetries = 3; +const TInt KIntMaxLength = 10; //2~32 =~ 4000000000 +const TUint KInitialDelayBetweenSessionConnectRetries = 5000000; //five seconds +const TUint KMaxTimerRetries = 50; +//Total delay between first and last retry is +//( A * (B^2 + B) ) / 2 +// - where A is KInitialDelayBetweenSessionConnectRetries +// - and B is KMaxTimerRetries +//If A = 5 seconds and B = 50 times last retry is made +//after about 106 minutes from the first one. +const TMsvId KWatcherInboxFolderId = KMsvGlobalInBoxIndexEntryIdValue; +const TMsvId KWatcherOutboxFolderId = KMsvGlobalOutBoxIndexEntryIdValue; +const TUid KMessageEntryUid = { KUidMsvMessageEntryValue }; +// This is more than what we need, but we are cautious +const TInt KExtraSpaceForDirectionalityMarkers = 6; +// ==================== LOCAL FUNCTIONS ==================== + + +const TImplementationProxy ImplementationTable[] = + { + IMPLEMENTATION_PROXY_ENTRY( 0x100059CF, CMsgErrorWatcher::NewL ) //lint !e611 + }; + +EXPORT_C const TImplementationProxy* ImplementationGroupProxy( TInt& aTableCount ) + { + aTableCount = sizeof( ImplementationTable ) / sizeof( TImplementationProxy ); + return ImplementationTable; + } + +// ================= MEMBER FUNCTIONS ======================= + +// --------------------------------------------------------- +// CMsgErrorWatcher::CMsgErrorWatcher +// +// C++ constructor can NOT contain any code, that +// might leave. +// --------------------------------------------------------- +// +CMsgErrorWatcher::CMsgErrorWatcher( RFs& aFs ) + : CActive( EPriorityStandard ), + iMmsServiceId( KMsvNullIndexEntryId ), + iNotificationFolderId( KMsvNullIndexEntryId ), + iCurrentEntryId ( KMsvNullIndexEntryId ), + iFs( aFs ) + { + CActiveScheduler::Add( this ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::ConstructL +// +// Symbian OS default constructor can leave. +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ConstructL() + { +MEWLOGGER_ENTERFN( "ConstructL" ); + User::LeaveIfError( iTimer.CreateLocal() ); + + TParse fileParse; + fileParse.Set( KMsgErrorWatcherResourceFileName, &KDC_RESOURCE_FILES_DIR, NULL ); + TFileName resource( fileParse.FullName() ); + iResourceReader = CStringResourceReader::NewL( resource ); + + TInt features = 0; + CRepository* repository = CRepository::NewL( KCRUidMuiuVariation ); + repository->Get( KMuiuMmsFeatures, features ); + delete repository; + repository = NULL; + if ( features & KMmsFeatureIdDelayDisconnectDialog ) + { + iWatcherFlags |= EReceivingDisconnectDelay; + } + + StartWatcherL(); +MEWLOGGER_LEAVEFN( "ConstructL" ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::NewL +// +// Two-phased constructor. +// --------------------------------------------------------- +// +CMsgErrorWatcher* CMsgErrorWatcher::NewL( TAny* aWatcherParams ) + { + TWatcherParams* params = reinterpret_cast( aWatcherParams ); + CMsgErrorWatcher* self = new ( ELeave ) CMsgErrorWatcher( params->iFs ); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + + return self; + } + + +// --------------------------------------------------------- +// CMsgErrorWatcher::~CMsgErrorWatcher +// +// Destructor +// --------------------------------------------------------- +// +CMsgErrorWatcher::~CMsgErrorWatcher() + { + StopWatcher(); + delete iResourceReader; + iTimer.Close(); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::StartWatcherL +// +// Does the actual construction of the watcher. +// --------------------------------------------------------- +// +void CMsgErrorWatcher::StartWatcherL() + { + MEWLOGGER_ENTERFN( "StartWatcherL" ); + iSession = CMsvSession::OpenSyncL( *this ); + iMmsReceiveErrorMessages = new ( ELeave ) CMsvEntrySelection; + iMmsSendErrorMessages = new ( ELeave ) CMsvEntrySelection; + iErrorMessages = new ( ELeave ) CMsvEntrySelection; + iErrorMsgNotes = new ( ELeave ) CMsvEntrySelection; + iNoteIds = new ( ELeave ) CArrayFixFlat( KArrayGranularity ); + + // Get message server session + iClientMtmRegistry = CClientMtmRegistry::NewL( *iSession ); + TRAPD( err, + { + iMmsClient = static_cast + ( iClientMtmRegistry->NewMtmL( KUidMsgTypeMultimedia ) ); + } ); + if ( err == KErrNotFound ) + { + MEWLOGGER_WRITE( "MmsClientMtm not found!" ); + // Make sure iMmsClient is NULL - just in case. + delete iMmsClient; + iMmsClient = NULL; + } + else + { + User::LeaveIfError( err ); + } + + if ( iMmsClient ) + { + // We're interested in roaming events only if MMS is enabled. + iRoamingObserver = CMsgErrorRoamingObserver::NewL( this ); + } + if ( iClientMtmRegistry->IsPresent( KSenduiMtmPushMtmUid ) ) + { + iGarbageCollection = CMsgGarbageCollection::NewL( *iClientMtmRegistry ); + } + + iSentItemsObserver = CMsgSentItemsObserver::NewL( this, iSession ); + iStartupObserver = CMsgErrorStartupObserver::NewL( this ); + + if(!( iWatcherFlags & EWatcherRunning)) + { + //if not yet created + iSmsDiskSpaceObserver = CMsgErrorSmsDiskSpaceObserver::NewL( this ); + iSmsExtDiskSpaceObserver = CMsgErrorExtSmsDiskSpaceObserver::NewL( this ); + } + // If log database is corrupted, logs observer start leaves. + // We ignore the leave, we can function otherwise, but we get no log events + TRAP_IGNORE( iLogsObserver = CMsgLogsObserver::NewL( this, iFs ) ); + + iWatcherFlags |= EWatcherRunning; + + if ( GetMmsServiceL() ) + { + CheckMmsReceivingModeL(); + } + + InitMessageArraysL(); + // Startup successful if we got this far. Reset retry counter. + iTimerRetries = 0; + MEWLOGGER_LEAVEFN( "StartWatcherL" ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::StopWatcher +// +// Stops (and destructs) the watcher. +// --------------------------------------------------------- +// +void CMsgErrorWatcher::StopWatcher() + { + MEWLOGGER_ENTERFN( "StopWatcher" ); + iWatcherFlags &= ~EWatcherRunning; + iWatcherFlags &= ~ENoAPErrorPending; + iMmsServiceId = KMsvNullIndexEntryId; + iNotificationFolderId = KMsvNullIndexEntryId; + + Cancel(); + delete iGarbageCollection; + iGarbageCollection = NULL; + delete iLogsObserver; + iLogsObserver = NULL; + delete iCommDbObserver; + iCommDbObserver = NULL; + delete iCenRepObserver; + iCenRepObserver = NULL; + delete iConnectionObserver; + iConnectionObserver = NULL; + delete iDiskSpaceObserver; + iDiskSpaceObserver = NULL; + delete iSmsDiskSpaceObserver; + iSmsDiskSpaceObserver = NULL; + delete iSmsExtDiskSpaceObserver; + iSmsExtDiskSpaceObserver = NULL; + delete iRoamingObserver; + iRoamingObserver = NULL; + delete iMmsClient; + iMmsClient = NULL; + delete iClientMtmRegistry; + iClientMtmRegistry = NULL; + delete iOperation; + iOperation = NULL; + delete iSentItemsObserver; + iSentItemsObserver = NULL; + delete iStartupObserver; + iStartupObserver = NULL; + delete iSession; + iSession = NULL; + delete iMmsReceiveErrorMessages; + iMmsReceiveErrorMessages = NULL; + delete iMmsSendErrorMessages; + iMmsSendErrorMessages = NULL; + delete iNoteIds; + iNoteIds = NULL; + + delete iErrorMsgText; + iErrorMsgText = NULL; + delete iErrorMsgDetails; + iErrorMsgDetails = NULL; + delete iErrorQuery; + iErrorQuery = NULL; + delete iDisconnectQuery; + iDisconnectQuery = NULL; + delete iDisconnectDlg; + iDisconnectDlg = NULL; + delete iErrorMsgNotes; + iErrorMsgNotes = NULL; + + delete iErrorMessages; + iErrorMessages = NULL; + + MEWLOGGER_LEAVEFN( "StopWatcher" ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::StartRestartTimer +// +// Start session reconnect timer. +// --------------------------------------------------------- +// +void CMsgErrorWatcher::StartRestartTimer() + { + if ( !IsActive() ) + { + MEWLOGGER_WRITE( "Starting timer" ); + iStatus = KRequestPending; + iRequestType = EMsgRequestStartingUp; + iTimerRetries++; + //The interval between retries comes longer every time + iTimer.After( iStatus, + iTimerRetries * KInitialDelayBetweenSessionConnectRetries ); + SetActive(); + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::InitMessageArraysL +// +// Initialise arrays +// --------------------------------------------------------- +// +void CMsgErrorWatcher::InitMessageArraysL() + { + MEWLOGGER_ENTERFN( "InitMessageArraysL" ); + CMsvEntry* outbox = iSession->GetEntryL( KWatcherOutboxFolderId ); + CleanupStack::PushL( outbox ); + CMsvEntrySelection* outboxMessages = + outbox->ChildrenWithTypeL( KMessageEntryUid ); + CleanupStack::PushL( outboxMessages ); + TInt count = outboxMessages->Count(); + while ( count-- ) + { + TMsvId dummy; + TMsvEntry entry; + TInt error = iSession->GetEntry( + outboxMessages->At( count ), dummy, entry ); + + TUid mtm = entry.iMtm; + if ( !error && + ( mtm == KSenduiMtmSmsUid || + mtm == KSenduiMtmMmsUid || + mtm == KSenduiMtmSmtpUid || + mtm == KUidMsgMMSNotification ) ) + { + iErrorMessages->AppendL( entry.Id() ); + MEWLOGGER_ENTERFN( "Send msg added" ); + } + } + CleanupStack::PopAndDestroy( outboxMessages ); + CleanupStack::PopAndDestroy( outbox ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::ResetWatcher +// +// Resets watcher. +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ResetWatcher() + { + MEWLOGGER_ENTERFN( "ResetWatcher" ); + + iWatcherFlags &= ~ENoAPErrorPending; + + //Drop all observers + delete iCommDbObserver; + iCommDbObserver = NULL; + delete iCenRepObserver; + iCenRepObserver = NULL; + delete iConnectionObserver; + iConnectionObserver = NULL; + delete iDiskSpaceObserver; + iDiskSpaceObserver = NULL; + delete iSmsDiskSpaceObserver; + iSmsDiskSpaceObserver = NULL; + delete iSmsExtDiskSpaceObserver; + iSmsExtDiskSpaceObserver = NULL; + //Reset disk space errors + iDiskSpaceErrors = 0; + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::GetMmsServiceL +// +// Retrieves MMS service id from MsgStore +// --------------------------------------------------------- +// +TBool CMsgErrorWatcher::GetMmsServiceL() + { + if ( !iMmsClient ) + { + return EFalse; + } + if ( iMmsServiceId == KMsvNullIndexEntryId ) + { + MEWLOGGER_WRITE( "Looking for MMS service" ); + iMmsClient->RestoreSettingsL(); + iMmsServiceId = iMmsClient->MmsSettings().Service(); + iNotificationFolderId = iMmsClient->MmsSettings().NotificationFolder(); + iMaxReceiveSize = iMmsClient->MmsSettings().MaximumReceiveSize(); + } + return ( iMmsServiceId != KMsvNullIndexEntryId ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::StartMmsFetchL +// +// Initiates MMS fetch +// --------------------------------------------------------- +// +void CMsgErrorWatcher::StartMmsFetchL() + { + MEWLOGGER_ENTERFN( "StartMmsFetchL" ); + if ( !IsActive() && iMmsReceiveErrorMessages->Count() ) + { + MEWLOGGER_WRITEF( _L("Fetching %d message(s)"), + iMmsReceiveErrorMessages->Count() ); + CancelNotesL(); + TCommandParameters parameters; // initialized to zero + TCommandParametersBuf paramPack( parameters ); + + //Add service entry as the first entry in the array + iMmsReceiveErrorMessages->InsertL( 0, iMmsServiceId ); + + // First remove existing schedules: + MEWLOGGER_WRITE( "Deleting old schedules" ); + // Calling synchronous TransferCommandL method + const TInt KBufSize = 256; + TBuf8 dummy; + iSession->TransferCommandL( *iMmsReceiveErrorMessages, + EMmsDeleteSchedule, + paramPack, + dummy ); + MEWLOGGER_WRITE( "Old schedules deleted!" ); + + // Then reschedule: + iStatus = KRequestPending; + iRequestType = EMsgRequestFetching; + delete iOperation; + iOperation = NULL; + MEWLOGGER_WRITE( "Request fetch" ); + iOperation = iSession->TransferCommandL( *iMmsReceiveErrorMessages, + EMmsScheduledReceive, + paramPack, + iStatus ); + SetActive(); + MEWLOGGER_WRITE( "Reset array" ); + iMmsReceiveErrorMessages->Reset(); + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::StartMmsSendL +// +// Initiates MMS fetch +// --------------------------------------------------------- +// +void CMsgErrorWatcher::StartMmsSendL() + { + MEWLOGGER_ENTERFN( "StartMmsSendL" ); + if ( !IsActive() && iMmsSendErrorMessages->Count() ) + { + MEWLOGGER_WRITEF( _L("Sending %d message(s)"), + iMmsSendErrorMessages->Count() ); + CancelNotesL(); + TCommandParameters parameters; // initialized to zero + TCommandParametersBuf paramPack( parameters ); + + //Add service entry as the first entry in the array + iMmsSendErrorMessages->InsertL( 0, iMmsServiceId ); + + iStatus = KRequestPending; + iRequestType = EMsgRequestSending; + delete iOperation; + iOperation = NULL; + MEWLOGGER_WRITE( "Request send" ); + iOperation = iSession->TransferCommandL( *iMmsSendErrorMessages, + EMmsScheduledSend, + paramPack, + iStatus ); + SetActive(); + MEWLOGGER_WRITE( "Reset array" ); + iMmsSendErrorMessages->Reset(); + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::CheckMmsReceivingModeL +// +// Checks MMS receiving mode +// --------------------------------------------------------- +// +void CMsgErrorWatcher::CheckMmsReceivingModeL() + { + if ( !( iWatcherFlags & EStartupReady ) || !GetMmsServiceL() ) + { + return; + } + TBool validAP = ValidateMmsServiceL(); //Refreshes MMS settings + MEWLOGGER_WRITEF( _L("ReceivingModeHome: %d"), iMmsClient->MmsSettings().ReceivingModeHome() ); + MEWLOGGER_WRITEF( _L("ReceivingModeForeign: %d"), iMmsClient->MmsSettings().ReceivingModeForeign() ); + + TInt fetchHome = iMmsClient->MmsSettings().ReceivingModeHome(); + TInt fetchRoam = iMmsClient->MmsSettings().ReceivingModeForeign(); + + if ( validAP && + fetchRoam == EMmsReceivingReject && + fetchHome != EMmsReceivingReject ) + { + MEWLOGGER_WRITE( "CheckMmsReceivingModeL, ShowNote flag enabled" ); + iWatcherFlags |= EShowRoamingNote; + } + else + { + //Reset roaming note flag + MEWLOGGER_WRITE( "CheckMmsReceivingModeL, ShowNote flag disabled" ); + iWatcherFlags &= ~EShowRoamingNote; + iWatcherFlags &= ~ERoamingNoteShown; + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::ValidateMmsServiceL +// +// Validates MMS service +// --------------------------------------------------------- +// +TBool CMsgErrorWatcher::ValidateMmsServiceL() + { + if ( !GetMmsServiceL() ) + { + return EFalse; + } + iMmsClient->RestoreSettingsL(); //Refreshes MMS settings + MEWLOGGER_WRITEF( _L("ValidateService: %d"), iMmsClient->ValidateService( iMmsServiceId ) ); + + TInt errorCode = iMmsClient->ValidateService( iMmsServiceId ); + + //TODO: check if the following is needed at all. + //Is ENoAPErrorPending needed and is it att all + //possible to go into there? + if ( iWatcherFlags & ENoAPErrorPending && + ( errorCode == KMmsErrorNoURI1 || + errorCode == KMmsErrorAP1Invalid ) ) + { + iWatcherFlags &= ~ENoAPErrorPending; + ShowGlobalNoteL( EInvalidAccessPointNote ); + } + return ( errorCode == KErrNone ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::ShowGlobalNoteL +// +// Shows AVKON global note +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ShowGlobalNoteL( TMsgErrorNoteIds aNoteId ) + { + if ( !( iWatcherFlags & EStartupReady ) ) + { + return; + } + MEWLOGGER_WRITEF( _L("ShowGlobalNoteL, id: %d"), aNoteId ); + + TPtrC string; + HBufC* text = NULL; + TAknGlobalNoteType noteType = EAknGlobalErrorNote; + TInt softkeys = R_AVKON_SOFTKEYS_OK_EMPTY; + + switch ( aNoteId ) + { + case ENoAccesPointsNote: + { + string.Set( iResourceReader->ReadResourceString( R_MSG_ERRH_NO_AP ) ); + } + break; + case EInvalidAccessPointNote: + { + string.Set( iResourceReader->ReadResourceString( R_MSG_ERRH_INVALID_AP ) ); + } + break; + case EDiskLowNote1: + { + string.Set( iResourceReader->ReadResourceString( R_MSG_ERRH_DISK_LOW_1 ) ); + } + break; + case EDiskLowNoteN: + { + string.Set( iResourceReader->ReadResourceString( R_MSG_ERRH_DISK_LOW_N ) ); + text = HBufC::NewLC( string.Length() + KIntMaxLength ); + TPtr tempPtr = text->Des(); + StringLoader::Format( tempPtr, string, -1, iDiskSpaceErrors ); + } + break; + case ESMSIncomingLowDiskSpace: + { + string.Set( iResourceReader->ReadResourceString( R_MEMLO_MEMORY_LOW_MESSAGES ) ); + } + break; + case EMemoryLowNote: + { + string.Set( iResourceReader->ReadResourceString( R_MSG_ERRH_MEMORY_LOW ) ); + } + break; + case ERoamingNote: + { + string.Set( iResourceReader->ReadResourceString( R_MSG_ERRH_ROAMING_REMINDER ) ); + noteType = EAknGlobalConfirmationNote; + } + break; + case ESendingMessageNote: + { + string.Set( iResourceReader->ReadResourceString( R_MSG_ERRH_SENDING_MESSAGE ) ); + noteType = EAknGlobalInformationNote; + softkeys = 0; + break; + } + default: + //Show nothing... + return; + } + if ( !text ) + { + text = string.AllocLC(); + } + + CAknGlobalNote* note = CAknGlobalNote::NewLC(); + if ( softkeys ) + { + // If softkeys are set the global note will be "waiting". + // If softkeys are NOT set the global note will be "non-waiting". + note->SetSoftkeys( softkeys ); + } + TInt id = note->ShowNoteL( noteType, *text ); + CleanupStack::PopAndDestroy( note ); + CleanupStack::PopAndDestroy( text ); + + iNoteIds->AppendL( id ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::CancelNotesL +// +// Cancels all AVKON global notes. +// --------------------------------------------------------- +// +void CMsgErrorWatcher::CancelNotesL() + { + TInt count = iNoteIds->Count(); + if ( count ) + { + CAknGlobalNote* note = CAknGlobalNote::NewLC(); + while ( count-- ) + { + //Does nothing if note is already dismissed. + note->CancelNoteL( iNoteIds->At( count ) ); + } + CleanupStack::PopAndDestroy( note ); // note + iNoteIds->Reset(); + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::ShowErrorMessageQueryL +// +// Shows AVKON global query +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ShowErrorMessageQueryL() + { + MEWLOGGER_ENTERFN( "ShowErrorMessageQueryL" ); + delete iErrorQuery; + iErrorQuery = NULL; + + TMsvEntry entry; + if ( GetNextErrorMsg( entry ) == KErrNone ) + { + ResolveErrorTextL( entry ); + ResolveErrorDetailsL( entry ); + TInt softkeys = ( iErrorMsgDetails != 0 ) ? + R_AVKON_SOFTKEYS_OK_DETAILS : + R_AVKON_SOFTKEYS_OK_EMPTY; + + MEWLOGGER_ENTERFN( "Displaying global query" ); + iErrorQuery = CMsgErrorGlobalQuery::NewL( this ); + iErrorQuery->ShowQueryL( + *iErrorMsgText, + softkeys, + ESendFailureNote ); + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::GetNextErrorMsg +// --------------------------------------------------------- +// +TInt CMsgErrorWatcher::GetNextErrorMsg( TMsvEntry& aEntry ) + { + if ( iErrorMsgNotes->Count() && + iWatcherFlags & EStartupReady ) + { + TMsvId dummy; + TInt error = iSession->GetEntry( iErrorMsgNotes->At( 0 ), dummy, aEntry ); + iErrorMsgNotes->Delete( 0 ); + return error; + } + else + { + return KErrNotFound; + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::ResolveErrorTextL +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ResolveErrorTextL( TMsvEntry& aEntry ) + { + MEWLOGGER_ENTERFN( "ResolveErrorTextL" ); + delete iErrorMsgText; + iErrorMsgText = NULL; + + HBufC* info = NULL; + if ( aEntry.iDetails.Length() ) + { + // Sender or recipient info + info = CAknPhoneNumberGrouping::CreateGroupedPhoneNumberL( aEntry.iDetails ); + CleanupStack::PushL( info ); + } + + TPtrC string; + if ( aEntry.iMtm == KUidMsgMMSNotification ) + { + if ( aEntry.Parent() == KWatcherInboxFolderId ) + { + MEWLOGGER_ENTERFN( "Retrieval failure." ); + string.Set( iResourceReader->ReadResourceString( info + ? R_MSG_ERRH_RETRIEVAL_ERROR_INFO + : R_MSG_ERRH_RETRIEVAL_ERROR ) ); + } + else + { + MEWLOGGER_ENTERFN( "Forward failure." ); + string.Set( iResourceReader->ReadResourceString( info + ? R_MSG_ERRH_FORWARD_ERROR_INFO + : R_MSG_ERRH_FORWARD_ERROR ) ); + } + } + else + { + MEWLOGGER_ENTERFN( "Send failure." ); + string.Set( iResourceReader->ReadResourceString( info + ? R_MSG_ERRH_SEND_ERROR_INFO + : R_MSG_ERRH_SEND_ERROR ) ); + } + + if ( info ) + { + iErrorMsgText = HBufC::NewL( string.Length() + info->Length() ); + TPtr tempPtr = iErrorMsgText->Des(); + + StringLoader::Format( tempPtr, string, -1, *info ); + CleanupStack::PopAndDestroy( info ); + } + else + { + iErrorMsgText = string.AllocL(); + } + MEWLOGGER_LEAVEFN( "ResolveErrorTextL" ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::ResolveErrorDetailsL +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ResolveErrorDetailsL( TMsvEntry& aEntry ) + { + MEWLOGGER_ENTERFN( "ResolveErrorDetailsL" ); + delete iErrorMsgDetails; + iErrorMsgDetails = NULL; + + TBool useResolver = EFalse; + TInt errorId = aEntry.iError; + + if ( iMmsClient && + ( aEntry.iMtm == KSenduiMtmMmsUid || aEntry.iMtm == KUidMsgMMSNotification ) ) + { + switch ( errorId ) + { + case KMmsErrorStatusMessageAddressUnresolved: + case KMmsErrorStatusTransientAddressUnresolved: + case KMmsErrorStatusMessageNotFound: + case KMmsErrorStatusTransientMessageNotFound: + case KMmsErrorStatusNetworkProblem: + case KMmsErrorStatusServiceDenied: + case KMmsErrorStatusMessageFormatCorrupt: + case KMmsErrorStatusContentNotAccepted: + case KMmsErrorStatusReplyChargingLimitationsNotMet: + case KMmsErrorStatusReplyChargingRequestNotAccepted: + case KMmsErrorStatusReplyChargingForwardingDenied: + case KMmsErrorStatusReplyChargingNotSupported: + case KMmsErrorStatusTransientFailure: + case KMmsErrorStatusUnspecified: + case KMmsErrorStatusPermanentFailure: + case KMmsErrorStatusUnsupportedMessage: + { + //See whether MMSC has delivered some + //response text and use it if found. + //Else use normal text resolver. + iMmsClient->SwitchCurrentEntryL( aEntry.Id() ); + iMmsClient->LoadMessageL(); + TPtrC responseText = iMmsClient->ResponseText(); + if ( responseText.Length() ) + { + MEWLOGGER_WRITEF( _L("Response text found: %d"), errorId ); + iErrorMsgDetails = responseText.AllocL(); + useResolver = EFalse; + } + else + { + useResolver = ETrue; + } + } + break; + case KErrCouldNotConnect: + errorId = KMmsErrorCouldNotConnect; + //lint -fallthrough + default: + useResolver = ETrue; + break; + } + } + else if ( aEntry.iMtm == KSenduiMtmSmsUid ) + { + useResolver = ETrue; + } + else + { + useResolver = EFalse; + } + + if ( useResolver ) + { + TInt textId; + TUint textFlags; + MEWLOGGER_WRITEF( _L("Resolving error: %d"), errorId ); + CTextResolver* resolver = CTextResolver::NewLC(); + const TDesC& error = resolver->ResolveErrorString( errorId, textId, textFlags ); + + if ( !( textFlags & EErrorResBlankErrorFlag || + textFlags & ETextResolverUnknownErrorFlag ) ) + { + iErrorMsgDetails = error.AllocL(); + } + CleanupStack::PopAndDestroy( resolver ); + } + MEWLOGGER_LEAVEFN( "ResolveErrorDetailsL" ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleNoAPErrorL +// +// Handles "no access point defined" error +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleNoAPErrorL( TMsvEntry& aEntry ) + { + MEWLOGGER_ENTERFN( "HandleNoAPErrorL" ); + iMmsReceiveErrorMessages->AppendL( aEntry.Id() ); + + iWatcherFlags |= ENoAPErrorPending; + + ShowGlobalNoteL( ENoAccesPointsNote ); + if ( !iCenRepObserver ) + { + MEWLOGGER_WRITE( "HandleNoAPErrorL, Creating CenRep observer" ); + iCenRepObserver = CMsgCenRepObserver::NewL( this ); + iCenRepObserver->SubscribeNotification(); + } + //Let's reset the TMsvEntry::iError to get rig of excess warning note + ResetErrorFieldL( aEntry ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleInvalidAPErrorL +// +// Handles "invalid access point" error +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleInvalidAPErrorL( TMsvEntry& aEntry, TBool aStartObserver ) + { + MEWLOGGER_ENTERFN( "HandleInvalidAPErrorL" ); + iMmsReceiveErrorMessages->AppendL( aEntry.Id() ); + ShowGlobalNoteL( EInvalidAccessPointNote ); + if ( aStartObserver && !iCommDbObserver ) + { + MEWLOGGER_WRITE( "HandleInvalidAPErrorL, Creating CommDB observer" ); + iCommDbObserver = CMsgErrorCommDbObserver::NewL( this ); + } + if ( aStartObserver && !iCenRepObserver ) + { + //We must also start cenrep observer + MEWLOGGER_WRITE( "HandleInvalidAPErrorL, Creating CenRep observer" ); + iCenRepObserver = CMsgCenRepObserver::NewL( this ); + iCenRepObserver->SubscribeNotification(); + } + + //Let's reset the TMsvEntry::iError to get rig of excess warning note + ResetErrorFieldL( aEntry ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleConnectionErrorL +// +// Handles "connection reserved" error +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleConnectionErrorL( TMsvEntry& aEntry, TBool aReceive ) + { + MEWLOGGER_ENTERFN( "HandleConnectionErrorL" ); + if ( !iConnectionObserver ) + { + MEWLOGGER_WRITE( "HandleConnectionErrorL, Creating connection observer" ); + iConnectionObserver = CMsgErrorConnectionObserver::NewL( this ); + } + if ( iConnectionObserver->ConnectionsOpen() ) + { + MEWLOGGER_WRITE( "HandleConnectionErrorL, Open connections detected" ); + if ( aReceive ) + { + iMmsReceiveErrorMessages->AppendL( aEntry.Id() ); + } + else + { + iMmsSendErrorMessages->AppendL( aEntry.Id() ); + } + //No matter if already started + iConnectionObserver->StartL(); + + delete iDisconnectQuery; + iDisconnectQuery = NULL; + + MEWLOGGER_ENTERFN( "Reading disconnect error text" ); + TPtrC string( iResourceReader->ReadResourceString( aReceive + ? R_MSG_ERRH_CONN_IN_USE_RECEIVE + : R_MSG_ERRH_CONN_IN_USE_SEND ) ); + + MEWLOGGER_ENTERFN( "Displaying global query" ); + iDisconnectQuery = CMsgErrorGlobalQuery::NewL( this ); + iDisconnectQuery->ShowQueryL( + string, + R_AVKON_SOFTKEYS_YES_NO, + EConnectionInUseNote ); + } + else + { + MEWLOGGER_WRITE( "HandleConnectionErrorL, No open connections" ); + delete iConnectionObserver; + iConnectionObserver = NULL; + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleDiskSpaceErrorL +// +// Handles "no disk space" error +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleDiskSpaceErrorL( TMsvEntry& aEntry ) + { + MEWLOGGER_ENTERFN( "HandleDiskSpaceErrorL" ); + iMmsReceiveErrorMessages->AppendL( aEntry.Id() ); + + iDiskSpaceErrors++; + if ( iDiskSpaceErrors == 1 ) + { + ShowGlobalNoteL( EDiskLowNote1 ); + } + else + { + ShowGlobalNoteL( EDiskLowNoteN ); + } + TUint triggerLevel = Max( KDefaultTriggerLevel, iMaxReceiveSize ); + //Activate DiskSpace observer + if ( !iDiskSpaceObserver ) + { + MEWLOGGER_WRITE( "HandleDiskSpaceErrorL, Creating disk space observer" ); + iDiskSpaceObserver = CMsgErrorDiskSpaceObserver::NewL( this, *iSession, iFs ); + } + MEWLOGGER_WRITEF( _L("Limit set to: %d"), + KCriticalLevel + triggerLevel + KTriggerMargin ); + iDiskSpaceObserver->SetLimitAndActivateL( KCriticalLevel + + triggerLevel + + KTriggerMargin ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleMemoryErrorL +// +// Handles "no memory" error +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleMemoryErrorL( TMsvEntry& aEntry ) + { + MEWLOGGER_ENTERFN( "HandleMemoryErrorL" ); + iMmsReceiveErrorMessages->AppendL( aEntry.Id() ); + ShowGlobalNoteL( EMemoryLowNote ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleRoamingEventL +// +// Handles events from roaming observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleRoamingEventL( TBool aRoaming ) + { + MEWLOGGER_ENTERFN( "HandleRoamingEventL" ); + if ( !iMmsClient ) + { + // We should never get here if MMS Client MTM is not present + // since roaming observer is not started in that case. + // This return is here just in case... + return; + } + + TInt fetchHome = iMmsClient->MmsSettings().ReceivingModeHome(); + TInt fetchRoam = iMmsClient->MmsSettings().ReceivingModeForeign(); + TBool fetchAll = EFalse; + + if ( aRoaming ) + { + //We are in roaming network + if ( fetchRoam == EMmsReceivingAutomatic && + fetchHome != EMmsReceivingAutomatic ) + { + fetchAll = ETrue; + } + if ( ( iWatcherFlags & EShowRoamingNote ) && + !( iWatcherFlags & ERoamingNoteShown ) ) + { + //Show roaming note if requested + ShowGlobalNoteL( ERoamingNote ); + iWatcherFlags |= ERoamingNoteShown; + } + } + else + { + //We are in home network + if ( fetchHome == EMmsReceivingAutomatic && + fetchRoam != EMmsReceivingAutomatic ) + { + fetchAll = ETrue; + } + //Reset roaming note flag + iWatcherFlags &= ~ERoamingNoteShown; + } + + if ( fetchAll && !IsActive() ) + { + MEWLOGGER_WRITE( "HandleRoamingEventL, starting fetch all" ); + iStatus = KRequestPending; + iRequestType = EMsgRequestFetchingAll; + delete iOperation; + iOperation = NULL; + iOperation = iMmsClient->FetchAllL( iStatus, EFalse ); + SetActive(); + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleCommDbEventL +// +// Handles events from CommDB observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleCommDbEventL() + { + if ( ValidateMmsServiceL() ) + { + MEWLOGGER_WRITE( "HandleCommDbEventL, starting fetch" ); + StartMmsFetchL(); + } + else + { + //Wait for another event + MEWLOGGER_WRITE( "HandleCommDbEventL, restart CommDB observer" ); + iCommDbObserver->Restart(); + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleConnectionEvent +// +// Handles events from connection observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleConnectionEvent() + { + if ( !IsActive() ) + { + MEWLOGGER_WRITE( "HandleConnectionEvent, Starting delay timer" ); + iStatus = KRequestPending; + iRequestType = EMsgRequestWaitingDisconnection; + iTimer.After( iStatus, KDelayAfterDisconnect ); + SetActive(); + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleDiskSpaceEventL +// +// Handles events from disk space observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleDiskSpaceEventL() + { + MEWLOGGER_WRITE( "HandleDiskSpaceEventL, starting fetch" ); + StartMmsFetchL(); + } + + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleDiskSpaceEvent2L +// +// Handles events from disk space observer +// -------k-------------------------------------------------- +// +void CMsgErrorWatcher::HandleDiskSpaceEvent2L() + { + MEWLOGGER_WRITE( "HandleDiskSpaceEvent2L, show note" ); + ShowGlobalNoteL( ESMSIncomingLowDiskSpace ); + + } +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleGlobalQueryEventL +// +// Handles events from global query observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleGlobalQueryEventL( TInt aQueryId, TInt aStatus ) + { + switch ( aQueryId ) + { + case ESendFailureNote: + { + if ( aStatus == EAknSoftkeyDetails && iErrorMsgDetails ) + { + CAknGlobalNote* note = CAknGlobalNote::NewLC(); + note->SetSoftkeys( R_AVKON_SOFTKEYS_OK_EMPTY ); + TInt id = note->ShowNoteL( EAknGlobalInformationNote, + *iErrorMsgDetails ); + CleanupStack::PopAndDestroy( note ); + iNoteIds->AppendL( id ); + } + if ( iErrorMsgNotes->Count() && !IsActive() ) + { + iStatus = KRequestPending; + iRequestType = EMsgRequestWaitingErrorNote; + if ( !IsActive() ) + { + iTimer.After( iStatus, KDelayBetweenNotes ); + SetActive(); + } + // Don't delete error query yet. If iErrorQuery + // exists other error notes are queued instead + // of shown. + } + else + { + delete iErrorQuery; + iErrorQuery = NULL; + } + } + break; + case EConnectionInUseNote: + { + MEWLOGGER_WRITEF( _L("ConnectionInUseNote return status: %d"), aStatus ); + if ( aStatus == EAknSoftkeyYes || + aStatus == EAknSoftkeyOk ) + { + delete iDisconnectDlg; + iDisconnectDlg = NULL; + MEWLOGGER_WRITE( "HandleGlobalQueryEventL, Starting disconnect dialog" ); + iDisconnectDlg = CMsgErrorDisconnectDlg::NewL(); + iDisconnectDlg->Start(); + } + delete iDisconnectQuery; + iDisconnectQuery = NULL; + } + break; + default: + break; + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleStartupReadyL +// +// Handles events from startup state observer (currently +// CMsgSentItemsObserver) +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleStartupReadyL() + { + MEWLOGGER_WRITE( "Startup ready!" ); + iWatcherFlags |= EStartupReady; + CheckMmsReceivingModeL(); + } + + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleCenRepNotificationL +// +// Handles events from Central Repository observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleCenRepNotificationL() + { + if ( ValidateMmsServiceL() ) + { + MEWLOGGER_WRITE( "HandleCenRepNotificationL, starting fetch" ); + StartMmsFetchL(); + } + else + { + //Wait for another event + MEWLOGGER_WRITE( "HandleCenRepNotificationL, restart CenRep observer" ); + iCenRepObserver->SubscribeNotification(); + } + } + + +// --------------------------------------------------------- +// CMsgErrorWatcher::ShowDeliveredNote +// +// Handles events from Logs observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ShowDeliveredNoteL( const TDesC& aRemoteParty ) + { + ShowReadOrDeliveredNoteL( aRemoteParty, R_MMS_DELIVERED ); + } + + +// --------------------------------------------------------- +// CMsgErrorWatcher::ShowReadNoteL +// +// Handles events from Logs observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ShowReadNoteL( const TDesC& aRemoteParty ) + { + ShowReadOrDeliveredNoteL( aRemoteParty, R_MMS_READ ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::ShowReadNoteL +// +// Handles events from Logs observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ShowReadOrDeliveredNoteL( const TDesC& aRemoteParty, TInt aResourceId ) + { + TPtrC original; + original.Set( iResourceReader->ReadResourceString( aResourceId ) ); + + HBufC* wholeTextBuf = HBufC::NewLC( original.Length() + aRemoteParty.Length() + + KExtraSpaceForDirectionalityMarkers ); + + TPtr wholeText = wholeTextBuf->Des(); + StringLoader::Format ( wholeText, original, -1, aRemoteParty ); + AknTextUtils::LanguageSpecificNumberConversion( wholeText ); + CAknGlobalNote* note = CAknGlobalNote::NewLC(); + note->ShowNoteL( EAknGlobalInformationNote, wholeText ); + CleanupStack::PopAndDestroy( note ); + CleanupStack::PopAndDestroy( wholeTextBuf ); + } + + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleSessionEventL +// +// Handles events from MsgServer observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleSessionEventL( TMsvSessionEvent aEvent, + TAny* aArg1, + TAny* aArg2, + TAny* aArg3 ) + { +#ifdef USE_LOGGER + if ( aEvent == EMsvServerReady ) + { + MEWLOGGER_WRITE( "Message Server Ready event." ); + } +#endif + if ( ( aEvent == EMsvCloseSession || + aEvent == EMsvServerTerminated || + aEvent == EMsvMediaUnavailable || + aEvent == EMsvMediaChanged ) && + iWatcherFlags & EWatcherRunning ) + { + MEWLOGGER_WRITEF( _L("StopWatcher event: %d"), aEvent ); + StopWatcher(); + //Start retry timer + StartRestartTimer(); + return; + } + if ( aEvent == EMsvServerReady && + !( iWatcherFlags & EWatcherRunning ) ) + { + TRAPD ( err, StartWatcherL() ); + if ( err ) //make sure watcher is not left in obscure state + { + StopWatcher(); + } + return; + } + if ( aArg1 == 0 || aArg2 == 0 || !( iWatcherFlags & EWatcherRunning ) ) + { + return; + } + // If for some reason MMS service is not yet found, + // we try to find it now... + GetMmsServiceL(); + + CMsvEntrySelection* entries = static_cast( aArg1 ); + TInt count = entries->Count(); + + // Mark the _original_ folder as parent for "entries moved" events (in "aArg3"). + // For other events the parent is in "aArg2". + TMsvId parentId = ( aEvent == EMsvEntriesMoved ) + ? *( static_cast( aArg3 ) ) + : *( static_cast( aArg2 ) ); + + + if ( count < 1 ) + { + return; + } + if ( parentId == KMsvRootIndexEntryIdValue && + iMmsServiceId != KMsvNullIndexEntryId ) + { + // We're not interested in these events if MMS Service is not present. + HandleRootEventL( aEvent, entries ); + } + else if ( parentId == KMsvLocalServiceIndexEntryIdValue ) + { + HandleLocalServiceEventL( aEvent, entries ); + } + else if ( parentId == KWatcherInboxFolderId ) + { + HandleInboxEventL( aEvent, entries ); + } + else if ( parentId == KWatcherOutboxFolderId ) + { + HandleOutboxEventL( aEvent, entries ); + } + else if ( ( iMmsServiceId != KMsvNullIndexEntryId && parentId == iMmsServiceId ) || + ( iNotificationFolderId != KMsvNullIndexEntryId && parentId == iNotificationFolderId ) ) + { + HandleMmsServiceEventL( aEvent, entries ); + } + else + { + //do nothing + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleRootEventL +// +// Handles root events from MsgServer observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleRootEventL( TMsvSessionEvent aEvent, + CMsvEntrySelection* aEntries ) + { + switch ( aEvent ) + { + case EMsvEntriesChanged: + { + TInt count = aEntries->Count(); + TInt i = 0; + while ( i < count ) + { + TMsvId dummy; + TMsvEntry entry; + TInt error = iSession->GetEntry( + aEntries->At( i ), dummy, entry ); + + //We're only interested in MMS service + if ( !error && + iMmsServiceId != KMsvNullIndexEntryId && + entry.Id() == iMmsServiceId ) + { + MEWLOGGER_WRITE( "HandleSessionEventL, MMS service changed" ); + //Check whether the roaming setting has changed + CheckMmsReceivingModeL(); + + //We're waiting for the the user to change access points + //if iCommDbObserver exists + if ( iCommDbObserver && ValidateMmsServiceL() ) + { + MEWLOGGER_WRITE( "HandleSessionEventL, deleting CommDB observer" ); + StartMmsFetchL(); + } + } + i++; + } + break; + } + default: + break; + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleLocalServiceEventL +// +// Handles local service events from MsgServer observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleLocalServiceEventL( TMsvSessionEvent aEvent, + CMsvEntrySelection* aEntries ) + { + if ( iNotificationFolderId == KMsvNullIndexEntryId && + aEvent == EMsvEntriesCreated ) + { + TInt count = aEntries->Count(); + TInt i = 0; + while ( i < count ) + { + TMsvId dummy; + TMsvEntry entry; + TInt error = iSession->GetEntry( + aEntries->At( i ), dummy, entry ); + if ( !error && + entry.iDetails.Compare( KMMSNotificationFolder ) == 0 ) + { + iNotificationFolderId = aEntries->At( i ); + MEWLOGGER_WRITEF( _L("Notification folder created: %d"), iNotificationFolderId ); + } + i++; + } + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleInboxEventL +// +// Handles outbox events from MsgServer observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleInboxEventL( TMsvSessionEvent aEvent, + CMsvEntrySelection* aEntries ) + { + switch (aEvent) + { + case EMsvEntriesChanged: + { + TInt count = aEntries->Count(); + TInt i = 0; + while ( i < count ) + { + TMsvId dummy; + TMsvEntry entry; + TInt error = iSession->GetEntry( + aEntries->At( i ), dummy, entry ); + TUid mtm = entry.iMtm; + //We're only interested in MMS notifications + if ( !error && + ( mtm == KUidMsgMMSNotification ) && + entry.iType == KMessageEntryUid ) + { + TUint sendingState = entry.SendingState(); + MEWLOGGER_WRITEF( _L("Sendstate: %d"), sendingState ); + MEWLOGGER_WRITEF( _L("Failed: %d"), (TInt)entry.Failed() ); + MEWLOGGER_WRITEF( _L("Error: %d"), entry.iError ); + TInt selectionId = iErrorMessages->Find( entry.Id() ); + + if ( sendingState == KMsvSendStateFailed && + selectionId == KErrNotFound ) + { + MEWLOGGER_WRITE( "Send msg added" ); + iErrorMessages->AppendL( entry.Id() ); + iErrorMsgNotes->AppendL( entry.Id() ); + if ( !iErrorQuery ) + { + ShowErrorMessageQueryL(); + } + } + else if ( sendingState != KMsvSendStateFailed && + selectionId != KErrNotFound ) + { + MEWLOGGER_WRITE( "Send msg removed" ); + iErrorMessages->Delete( selectionId ); + } + else + { + //Do nothing + } + } + i++; + } + break; + } + default: + break; + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleOutboxEventL +// +// Handles outbox events from MsgServer observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleOutboxEventL( TMsvSessionEvent aEvent, + CMsvEntrySelection* aEntries ) + { + TInt count = aEntries->Count(); + switch (aEvent) + { + case EMsvEntriesChanged: + { + TInt i = 0; + while ( i < count ) + { + TMsvId dummy; + TMsvEntry entry; + TInt error = iSession->GetEntry( + aEntries->At( i ), dummy, entry ); + TUid mtm = entry.iMtm; + + if ( mtm == KSenduiMtmMmsUid && + iMmsSendErrorMessages->Find( entry.Id() ) == KErrNotFound ) + { + if ( // the first error is activated again to synchronize + // with connection manager (MPM) + entry.iError == KErrPacketDataTsyMaxPdpContextsReached || + entry.iError == KErrUmtsMaxNumOfContextExceededByPhone || + entry.iError == KErrUmtsMaxNumOfContextExceededByNetwork || + // add the following error to the list to synchronize with + // connection manager (MPM) + entry.iError == KErrGprsInsufficientResources ) + { + MEWLOGGER_WRITE( "MMS send - connection active" ); + + //Let's now save the id. This way we can reset the entrys + //error field just before the fetch start. This prevents + //duplicate error notes because this case branch is reached many times. + iCurrentEntryId = entry.Id(); + + HandleConnectionErrorL( entry, EFalse ); + } + } + + //We're only interested in Mail, SMS & MMS messages + if ( !error && + ( mtm == KSenduiMtmSmsUid || + mtm == KSenduiMtmMmsUid || + mtm == KSenduiMtmSmtpUid || + mtm == KUidMsgMMSNotification ) && + entry.iType == KMessageEntryUid ) + { + TUint sendingState = entry.SendingState(); + MEWLOGGER_WRITEF( _L("Sendstate: %d"), sendingState ); + MEWLOGGER_WRITEF( _L("Failed: %d"), (TInt)entry.Failed() ); + MEWLOGGER_WRITEF( _L("Error: %d"), entry.iError ); + if ( mtm == KSenduiMtmSmtpUid && entry.Failed() ) + { + // special Failed flag handling for e-mail + sendingState = KMsvSendStateFailed; + } + TInt selectionId = iErrorMessages->Find( entry.Id() ); + + if ( sendingState == KMsvSendStateFailed && + selectionId == KErrNotFound ) + { + MEWLOGGER_WRITE( "Send msg added" ); + iErrorMessages->AppendL( entry.Id() ); + iErrorMsgNotes->AppendL( entry.Id() ); + if ( !iErrorQuery ) + { + ShowErrorMessageQueryL(); + } + } + else if ( sendingState != KMsvSendStateFailed && + selectionId != KErrNotFound ) + { + MEWLOGGER_WRITE( "Send msg removed" ); + iErrorMessages->Delete( selectionId ); + } + else + { + + } + } + i++; + } + } + break; + case EMsvEntriesMoved: // Messages are moved _from_ this folder. + case EMsvEntriesDeleted: + { + TInt i = 0; + MEWLOGGER_WRITEF( _L("Entries deleted: %d"), count ); + while ( i < count ) + { + TInt selectionId = iMmsSendErrorMessages->Find( aEntries->At( i ) ); + if ( selectionId != KErrNotFound ) + { + MEWLOGGER_WRITE( "MMS Send msg removed" ); + iMmsSendErrorMessages->Delete( selectionId ); + } + i++; + } + } + break; + default: + break; + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::HandleMmsServiceEventL +// +// Handles MMS service events from MsgServer observer +// --------------------------------------------------------- +// +void CMsgErrorWatcher::HandleMmsServiceEventL( TMsvSessionEvent aEvent, + CMsvEntrySelection* aEntries ) + { + TInt count = aEntries->Count(); + switch (aEvent) + { + case EMsvEntriesChanged: + { + TInt i = 0; + while ( i < count ) + { + TMsvId dummy; + TMsvEntry entry; + TInt error = iSession->GetEntry( + aEntries->At( i ), dummy, entry ); +#ifdef USE_LOGGER + if ( !error ) + { + MEWLOGGER_WRITEF( _L("FetchState: %d"), entry.SendingState() ); + MEWLOGGER_WRITEF( _L("Error: %d"), entry.iError ); + MEWLOGGER_WRITEF( _L("Retries: %d"), entry.iMtmData3 ); + MEWLOGGER_WRITEF( _L("Failed: %d"), (TInt)entry.Failed() ); + MEWLOGGER_WRITEF( _L("ArrayId: %d"), iMmsReceiveErrorMessages->Find( entry.Id() ) ); + } +#endif + //Check that reception has failed and that the entry is not + //already in iMmsReceiveErrorMessages + if ( !error && + iMmsReceiveErrorMessages->Find( entry.Id() ) == KErrNotFound ) + { + TInt entryErr = entry.iError; + if ( entryErr == KErrGprsMissingorUnknownAPN ) + { + // Map to "invalid ap" error. + entryErr = KMmsErrorAP1Invalid; + } + switch ( entryErr ) + { + case KErrDiskFull: + { + MEWLOGGER_WRITE( "MMS fetch - disk full" ); + HandleDiskSpaceErrorL( entry ); + } + break; + case KErrNoMemory: + { + MEWLOGGER_WRITE( "MMS fetch - out of memory" ); + HandleMemoryErrorL( entry ); + } + break; + // the first error is activated again to synchronize + // with connection manager (MPM) + case KErrPacketDataTsyMaxPdpContextsReached: + case KErrUmtsMaxNumOfContextExceededByPhone: + case KErrUmtsMaxNumOfContextExceededByNetwork: + // add the following error to the list to synchronize with + // connection manager (MPM) + case KErrGprsInsufficientResources: + { + //Let's now save the id. This way we can reset the entrys + //error field just before the fetch start. This prevents + //duplicate error notes because this case branch is reached many times. + iCurrentEntryId = entry.Id(); + //Connection already active should be "detected" + //only after third retry failure if "disconnect + //delay" feature is activated. + TInt retries = ( iWatcherFlags & EReceivingDisconnectDelay ) + ? KConnectionRetries + : 0; + if ( ( entry.iMtmData3 & KMmsRetryCountMask ) >= retries ) //lint !e574 + { + MEWLOGGER_WRITE( "MMS fetch - connection active" ); + + + HandleConnectionErrorL( entry, ETrue ); + } + } + + break; + + + + case KMmsErrorNoWAPAccessPoint: + { + MEWLOGGER_WRITE( "MMS fetch - no access point" ); + HandleNoAPErrorL( entry ); + } + break; + case KMmsErrorAP1Invalid: + case KMmsErrorNoURI1: + { + MEWLOGGER_WRITE( "MMS fetch - invalid access point" ); + HandleInvalidAPErrorL( entry, ETrue ); + } + break; + case KErrIfAuthenticationFailure: //username/passwd + { + MEWLOGGER_WRITE( "MMS fetch - username/passwd" ); + HandleInvalidAPErrorL( entry, EFalse ); + } + break; + default: + //nothing to do + break; + } + } + i++; + } + } + break; + case EMsvEntriesMoved: // Messages are moved _from_ this "folder". + case EMsvEntriesDeleted: + { + TInt i = 0; + TInt originalCount = iMmsReceiveErrorMessages->Count(); + +MEWLOGGER_WRITEF( _L("Entries deleted: %d"), count ); + + while ( i < count ) + { + TInt selectionId = iMmsReceiveErrorMessages->Find( aEntries->At( i ) ); + if ( selectionId != KErrNotFound ) + { +MEWLOGGER_WRITE( "Fetch msg removed" ); + iMmsReceiveErrorMessages->Delete( selectionId ); + } + i++; + } + if ( originalCount && !iMmsReceiveErrorMessages->Count() ) + { + // array was emptied + ResetWatcher(); + } + } + break; + default: + break; + } + } + + +// --------------------------------------------------------- +// CMsgErrorWatcher::ResetErrorFieldL +// +// Reset TMsvEntry::iError of the current notification +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ResetErrorFieldL( ) + { + //Makes sure the entry is set + if( iCurrentEntryId != KMsvNullIndexEntryId ) + { + CMsvEntry *cEntry( NULL ); + TRAPD( err, cEntry = iSession->GetEntryL( iCurrentEntryId ) ); + if ( err == KErrNotFound ) + { + iCurrentEntryId = KMsvNullIndexEntryId; + return; + } + CleanupStack::PushL( cEntry ); + TMsvEntry tEntry = cEntry->Entry(); + tEntry.iError = KErrNone; + cEntry -> ChangeL( tEntry ); + CleanupStack::PopAndDestroy( cEntry ); + //This prevents getting here to often + iCurrentEntryId = KMsvNullIndexEntryId; + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::ResetErrorFieldL +// +// Reset TMsvEntry::iError +// --------------------------------------------------------- +// +void CMsgErrorWatcher::ResetErrorFieldL( TMsvEntry& aEntry ) + { + CMsvEntry *cEntry = iSession->GetEntryL( aEntry.Id() ); + CleanupStack::PushL( cEntry ); + aEntry.iError = KErrNone; + cEntry -> ChangeL( aEntry ); + CleanupStack::PopAndDestroy( cEntry ); + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::DoCancel +// +// From active object framework +// --------------------------------------------------------- +// +void CMsgErrorWatcher::DoCancel() + { + iTimer.Cancel(); + if ( iOperation ) + { + iOperation->Cancel(); + } + } + +// --------------------------------------------------------- +// CMsgErrorWatcher::RunL +// +// From active object framework +// --------------------------------------------------------- +// +void CMsgErrorWatcher::RunL() + { +MEWLOGGER_WRITEF( _L("RunL, iStatus: %d"), iStatus.Int() ); +MEWLOGGER_WRITEF( _L("RunL, iRequestType: %d"), iRequestType ); + switch ( iRequestType ) + { + case EMsgRequestStartingUp: + { + if ( !( iWatcherFlags & EWatcherRunning ) ) + { + TRAPD ( err, StartWatcherL() ); + if ( err ) //make sure watcher is not left in obscure state + { +MEWLOGGER_WRITEF( _L("Leave from StartWatcherL: %d"), err ); + StopWatcher(); + if ( iTimerRetries < KMaxTimerRetries ) + { + StartRestartTimer(); + } + //else give up + } + } + } + break; + case EMsgRequestSending: + if ( iStatus.Int() == KErrNone ) + { + ShowGlobalNoteL( ESendingMessageNote ); + } + if ( iMmsReceiveErrorMessages->Count() ) + { + StartMmsFetchL(); + } + else + { + MEWLOGGER_WRITE( "RunL, Deleting connection observer" ); + delete iConnectionObserver; + iConnectionObserver = NULL; + ResetErrorFieldL(); + } + break; + case EMsgRequestFetching: + ResetErrorFieldL(); + ResetWatcher(); + break; + case EMsgRequestWaitingErrorNote: + ShowErrorMessageQueryL(); + break; + case EMsgRequestWaitingDisconnection: + { + MEWLOGGER_WRITE( "RunL, Disconnect delay passed" ); + if ( iMmsSendErrorMessages->Count() ) + { + StartMmsSendL(); + } + else + { + StartMmsFetchL(); + } + //ResetErrorFieldL(); + } + break; + case EMsgRequestFetchingAll: + default: + break; + } + } + +// ================= OTHER EXPORTED FUNCTIONS ============== + +// +// --------------------------------------------------------- +// Panic implements +// panic, for debug version only +// --------------------------------------------------------- +// +GLDEF_C void Panic( TInt aPanic ) // enum for panic codes + { + _LIT( KPanicText, "MsgErrorWatcher" ); + User::Panic( KPanicText, aPanic ); + } + +// End of File +