diff -r 000000000000 -r 72b543305e3a mmsengine/mmsconninit/src/mmsconninit.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmsengine/mmsconninit/src/mmsconninit.cpp Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,902 @@ +/* +* Copyright (c) 2002-2004 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: mmsconninit implementation +* +*/ + + + +// INCLUDE FILES +#include +#include +#include +#include +#include + +// USERINCLUDE FILES +#include "mmsconninit.h" + +// EXTERNAL DATA STRUCTURES +// EXTERNAL FUNCTION PROTOTYPES +// CONSTANTS +const TInt32 KMmsShortTimeout = 30; // seconds +// Interval must be long enough to give the connection time to recover +const TInt32 KMmsRetryInterval = 10; // seconds +const TInt KMmsSecondsToMilliseconds = 1000000; +// Only one retry - if that does not work, better reschedule the operation normally +const TInt KMmsMaxRetryCount = 1; +const TInt KMaxProxyPortLength = 6; +_LIT( KHttpSchemePart1, "http" ); +_LIT( KHttpSchemePart2, "://" ); +const TInt KMmsScheme1Length = 4; +const TInt KMmsHTTPSchemeLength = 7; + + +// MACROS +// LOCAL CONSTANTS AND MACROS +// MODULE DATA STRUCTURES +// LOCAL FUNCTION PROTOTYPES +// ============================== LOCAL FUNCTIONS ============================== +// ============================== MEMBER FUNCTIONS ============================= + +// ----------------------------------------------------------------------------- +// CMmsConnectionInitiator +// ----------------------------------------------------------------------------- +// +CMmsConnectionInitiator::CMmsConnectionInitiator() : + CActive( EPriorityStandard ) + { + } + +// ----------------------------------------------------------------------------- +// ConstructL +// ----------------------------------------------------------------------------- +// +void CMmsConnectionInitiator::ConstructL() + { + CActiveScheduler::Add( this ); + iTimerRunning = EFalse; + } + +// ----------------------------------------------------------------------------- +// NewL +// ----------------------------------------------------------------------------- +// +EXPORT_C CMmsConnectionInitiator* CMmsConnectionInitiator::NewL() + { + CMmsConnectionInitiator* self = new ( ELeave ) CMmsConnectionInitiator; + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + #ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("MmsConnInit constructed ") ); + #endif + return self; + } + +// ----------------------------------------------------------------------------- +// ~CMmsConnectionInitiator +// ----------------------------------------------------------------------------- +// +CMmsConnectionInitiator::~CMmsConnectionInitiator() + { + // cancel closes our timer if it is running + Cancel(); + // iConnection, iClientStatus and iArray are owned by caller + + // Just to be sure the Access point property goes, delete it + // Never mind the error - this is the best effort. + // If it does not work, what can we do. Question mark. (To avoid "worrying commets") +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("deleting KMPMPropertyKey") ); +#endif + RProperty::Delete( KMPMCathegory, KMPMPropertyKeyMMS ); + + #ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("MmsConnInit destroyed ") ); + #endif + } + +// ----------------------------------------------------------------------------- +// ConnectL +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMmsConnectionInitiator::ConnectL( + RConnection& aConnection, + CArrayFixFlat& aAccessPointArray, + TRequestStatus& aStatus ) + { +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("MmsConnInit::ConnectL") ); +#endif + iClientStatus = &aStatus; + iConnection = &aConnection; + iArray = &aAccessPointArray; + *iClientStatus = KRequestPending; + iIndex = 0; + iTimerRunning = EFalse; + iRetryCount = 0; + + // No reason to continue if the array is empty + if( aAccessPointArray.Count() == 0 ) + { + User::RequestComplete( iClientStatus, KErrArgument ); + return; + } + + if ( !CheckNetworkL() ) + { + User::RequestComplete( iClientStatus, KErrCouldNotConnect ); + return; + } + + // Let's not start the AO if we do not find IAP + for( iIndex = 0; iIndex < iArray->Count(); iIndex++ ) + { + TUint32 ap; // IAP to be resolved + // index is safe + if( ( FindIapL( iArray->At( iIndex ), ap ) ) ) + { + // Let's override the preferences + iPrefs.SetDialogPreference(ECommDbDialogPrefDoNotPrompt); + //Start the connection + StartConnectionL( ap ); + iStartTime.UniversalTime(); + SetActive(); + return; + } + // IAP not found but let's keep on looping + } + //We looped through the array and did not succeed + //We do not have any error value in the iStatus because we + //did not even try to connect + User::RequestComplete( iClientStatus, KErrCouldNotConnect ); + return; + } + +// ----------------------------------------------------------------------------- +// GetParametersL +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMmsConnectionInitiator::GetParametersL( + TUint32 aAccessPointLink, + TUint32& aAccessPoint, + HBufC*& aServerUri, + TBool& aProxyUsed, + HBufC8*& aProxyAddress ) + { + // Every function reading the commsDB are trapped because + // they may leave if the field is empty. We still may be + // able to continue browsing the DB further. + // Exception: Functions reading long text are not trapped + // because they allocate memory. + +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("MmsConnInit::GetParametersL") ); +#endif + + // Initialise OUT parameters + aServerUri = NULL; + aAccessPoint = 0; + aProxyUsed = EFalse; + aProxyAddress = NULL; + + // Initialise used variables + TInt error = KErrNone; + TUint32 num32Value = 0; + TBuf textValue; + TInt length = 0; + CCommsDbTableView* view = NULL; + + // Connect to Database server and CommDb + CCommsDatabase* db = CCommsDatabase::NewL( EDatabaseTypeUnspecified ); + CleanupStack::PushL( db ); + + // Start from WAP_ACCESS_POINT table -> opening view to it + view = db->OpenViewMatchingUintLC( + TPtrC( WAP_ACCESS_POINT ), + TPtrC( COMMDB_ID ), + aAccessPointLink ); + + // If no record for 'aAccessPointLink' there's nothing to look for + if( view->GotoFirstRecord() != KErrNone ) + { + CleanupStack::PopAndDestroy( view ); + CleanupStack::PopAndDestroy( db ); + return; + } + + // Get aServerUri (WAP_START_PAGE in CommDb) + // ReadColumnLengthL only leaves if the column does not exist at all - + // that means that the database structure is totally wrong, and we can't continue + view->ReadColumnLengthL( TPtrC( WAP_START_PAGE ), length ); + // ReadLongTextL only leaves if the column does not exist in the table + // or we are out of memory. + aServerUri = view->ReadLongTextLC( TPtrC( WAP_START_PAGE ) ); + // If the function did not leave, we have aServerUri on the cleanup stack + // It's length may be 0, but the pointer itself is not NULL + if( length != 0 ) + { + CheckWapStartPageL( aServerUri ); // tries to ensure proper syntax + } + + // Get link to bearer + // This function only leaves if the column does not exist in the table + // This means the structure of the database is incorrect, and we cannot continue + view->ReadTextL( TPtrC( WAP_CURRENT_BEARER ), textValue ); + + // view must be deleted, but it is not on top of the CleanupStack + CleanupStack::Pop( aServerUri ); + CleanupStack::PopAndDestroy( view ); + view = NULL; + + if( textValue.Length() == 0 ) + { + // Impossible to continue because bearer (textValue) is needed to browse further + CleanupStack::PopAndDestroy( db ); + return; + } + + // Put aServerUri back on the cleanup stack + CleanupStack::PushL( aServerUri ); + + // Create new view to bearer table + view = db->OpenViewMatchingUintLC( + textValue, + TPtrC( WAP_ACCESS_POINT_ID ), + aAccessPointLink ); + + // There should be only one record with aAccessPointLink + if( view->GotoFirstRecord() != KErrNone ) + { + // If no record for 'aAccessPointLink' there's nothing to look for + CleanupStack::PopAndDestroy( view ); // view + CleanupStack::Pop( aServerUri ); + CleanupStack::PopAndDestroy( db ); + return; + } + + // Get AccessPoint + // This function leaves if the column has NULL value + TRAP( error, view->ReadUintL( TPtrC( WAP_IAP ), num32Value ) ); + + // Current view not needed any more + CleanupStack::PopAndDestroy( view ); // view + view = NULL; + + if( error == KErrNone ) + { + aAccessPoint = num32Value; + } + else + { + CleanupStack::Pop( aServerUri ); + CleanupStack::PopAndDestroy( db ); + return; + } + + // Create view to IAP table + view = db->OpenViewMatchingUintLC( TPtrC( IAP ), TPtrC( COMMDB_ID ), aAccessPoint ); + + // There should be only one record with aAccessPoint + if( view->GotoFirstRecord() != KErrNone ) + { + // no record found + CleanupStack::PopAndDestroy( view ); // view + CleanupStack::Pop( aServerUri ); + CleanupStack::PopAndDestroy( db ); + aAccessPoint = 0; // Client will know that the procedure failed + return; + } + + // Get servicetype and -identifier + TRAP( error, + { + view->ReadTextL( TPtrC( IAP_SERVICE_TYPE ), textValue ); // read service type + view->ReadUintL( TPtrC( IAP_SERVICE ), num32Value ); // read service identifier + }); + if( error ) + { + // Leave occurred, cleaning up + CleanupStack::PopAndDestroy( view ); // view + CleanupStack::Pop( aServerUri ); + CleanupStack::PopAndDestroy( db ); + aAccessPoint = 0; // Client will know that the procedure failed + return; + } + + // Current view not needed any more + CleanupStack::PopAndDestroy( view ); + view = NULL; + + // Create view to Proxy table + view = db->OpenViewOnProxyRecordLC( num32Value, textValue ); + // There should be only one record matching service identifier and service type + if( view->GotoFirstRecord() != KErrNone ) + { + CleanupStack::PopAndDestroy( view ); // view + CleanupStack::Pop( aServerUri ); + CleanupStack::PopAndDestroy( db ); + return; + } + + // Get information whether proxy is used or not + TRAP( error, view->ReadBoolL( TPtrC( PROXY_USE_PROXY_SERVER ), aProxyUsed ) ); + if ( error != KErrNone ) + { + CleanupStack::PopAndDestroy( view ); // view + CleanupStack::Pop( aServerUri ); + CleanupStack::PopAndDestroy( db ); + return; + } + + // If proxy is to be used, get the related information + if( aProxyUsed ) + { + // Get proxy port number + TRAP( error, view->ReadUintL( TPtrC( PROXY_PORT_NUMBER ), num32Value ) ); + if( error != KErrNone ) + { + CleanupStack::PopAndDestroy( view ); // view + CleanupStack::Pop( aServerUri ); + CleanupStack::PopAndDestroy( db ); + return; + } + + if( num32Value > KMaxTUint16 ) + { + // Proxy port has too big value, access point is invalid + CleanupStack::PopAndDestroy( view ); // view + CleanupStack::Pop( aServerUri ); + CleanupStack::PopAndDestroy( db ); + + User::Leave( KErrTooBig ); + } + + // Following LIT is the proxy port number beginning with ":" + _LIT( KProxyPort,":%d" ); + HBufC* tempProxyPort = NULL; + HBufC* tempProxyServerName = NULL; + tempProxyServerName = view->ReadLongTextLC( TPtrC( PROXY_SERVER_NAME ) ); + tempProxyServerName->Des().Trim(); // remove possible spaces + + tempProxyPort = HBufC::NewLC( KMaxProxyPortLength ); + TPtr ptr2( tempProxyPort -> Des() ); + ptr2.Format( KProxyPort,num32Value ); + + // Create a TPtr object to aProxyAddress + // Proxy address must always be us-ascii or we are in trouble. + TPtr ptr( tempProxyServerName -> Des() ); + aProxyAddress = HBufC8::NewLC( + ( tempProxyServerName->Length() ) + ( tempProxyPort->Length() ) ); + aProxyAddress->Des().Copy( ptr ); + aProxyAddress->Des().Append( ptr2 ); + CleanupStack::Pop( aProxyAddress ); + CleanupStack::PopAndDestroy( tempProxyPort ); + CleanupStack::PopAndDestroy( tempProxyServerName ); + } // aProxyUsed + + CleanupStack::PopAndDestroy( view ); // view + view = NULL; + CleanupStack::Pop( aServerUri ); + CleanupStack::PopAndDestroy( db ); + +#ifdef _MMSCONNINIT_LOGGING_ + TPtr temp = aServerUri->Des(); + TMmsConnInitLogger::Log( _L("aServerUri: %S"), &temp ); + TMmsConnInitLogger::Log( _L("aAccessPoint: %d"), aAccessPoint ); + TMmsConnInitLogger::Log( _L("aProxyUsed: %d"), aProxyUsed ); + /* + if( aProxyAddress != NULL ) + { + TMmsConnInitLogger::Log( _L("aProxyAddress: %S"), &temp ); + } + */ +#endif + } + +// ----------------------------------------------------------------------------- +// CheckNetworkL +// ----------------------------------------------------------------------------- +// +TBool CMmsConnectionInitiator::CheckNetworkL() + { +#ifdef __WINS__ + // Emulator has network always "available" + return ETrue; +#endif // __WINS__ + + TInt value = 0; + TInt error = RProperty::Get( KUidSystemCategory, KUidNetworkStatus.iUid, value ); + User::LeaveIfError( error ); + +#ifdef _MMSCONNINIT_LOGGING_ + if ( value == ESANetworkAvailable ) + { + TMmsConnInitLogger::Log( _L("Network available") ); + } + else + { + TMmsConnInitLogger::Log( _L("Network NOT available, value = %d"), value ); + } +#endif + + return ( value == ESANetworkAvailable ); + } + +// ----------------------------------------------------------------------------- +// CMmsConnectionInitiator::CheckWapStartPageL +// +// Private fuction used only by GetParametersL. Made just for splitting too big +// GetParameters function. +// Adds http scheme in the beginning of wap start page if it is missing. It does +// not add it into comms database. +// +// ----------------------------------------------------------------------------- +// +void CMmsConnectionInitiator::CheckWapStartPageL(HBufC*& aUri) + { + + aUri->Des().Trim(); // remove spaces + + if ( aUri->Find(KHttpSchemePart2) > 0) + { + ;// OK, nothing needs to be done; + } + else if (aUri->Find(KHttpSchemePart2) == 0) + { + // NOK, adding 'KHttpSchemePart1' to the beginning of the uri + HBufC* tmp = HBufC::NewMaxLC( aUri->Length() + KMmsScheme1Length ); + tmp->Des().Copy( KHttpSchemePart1() ); + tmp->Des().Append( aUri->Des() ); + CleanupStack::Pop( tmp ); + CleanupStack::PopAndDestroy( aUri ); + aUri = tmp; + CleanupStack::PushL(aUri); + + } + else // HttpScheme2 not found in this case + { + // NOK, adding 'KHttpScheme' to the beginning of the uri + + HBufC* tmp = HBufC::NewMaxLC( aUri->Length() + KMmsHTTPSchemeLength ); + tmp->Des().Copy( KHttpSchemePart1() ); + tmp->Des().Append( KHttpSchemePart2() ); + tmp->Des().Append( aUri->Des() ); + + CleanupStack::Pop( tmp ); + CleanupStack::PopAndDestroy( aUri ); + aUri = tmp; + CleanupStack::PushL(aUri); + } + } + +// ----------------------------------------------------------------------------- +// CMmsConnectionInitiator::FindIapL +// WAP Acces Point is given as in-parameter and IAP is +// retruned as out-parameter +// Return value is EFalse if something goes wrong +// Leavings are trapped in case of error in reading CommsDb +// ----------------------------------------------------------------------------- +// +TBool CMmsConnectionInitiator::FindIapL( TUint32 aWapAP, TUint32& aIap ) + { + aIap = 0; + TUint32 num32Value = 0; + TInt error = KErrNone; + CCommsDatabase* db = CCommsDatabase::NewL( EDatabaseTypeUnspecified ); + CleanupStack::PushL( db ); + CCommsDbTableView* view; + + TBuf textValue; // Max limit defined by database + + // Start from the WAP access point table + // If there is no WAP access point table, the function leaves. + view=db->OpenViewMatchingUintLC( + TPtrC( WAP_ACCESS_POINT ), + TPtrC( COMMDB_ID ), + aWapAP ); + if ( view->GotoFirstRecord() != KErrNone ) + { + CleanupStack::PopAndDestroy( view ); + CleanupStack::PopAndDestroy( db ); + return EFalse; + } + + // Link to bearer table + TRAP( error, view->ReadTextL( TPtrC( WAP_CURRENT_BEARER ), textValue ) ); + if ( error != KErrNone) + { + CleanupStack::PopAndDestroy( view ); + CleanupStack::PopAndDestroy( db ); + return EFalse; + } + + CleanupStack::PopAndDestroy( view ); // view + view = NULL; + + // Found WAP access point. Now we need the WAP bearer + view=db->OpenViewMatchingUintLC( textValue, TPtrC( WAP_ACCESS_POINT_ID ), + aWapAP ); + if ( view->GotoFirstRecord() != KErrNone ) + { + CleanupStack::PopAndDestroy( view ); + CleanupStack::PopAndDestroy( db ); + return EFalse; + } + + //Let's trap the leave if there is no IAP and try to continue normally + TRAP( error, view->ReadUintL( TPtrC( WAP_IAP ), num32Value ) ); + CleanupStack::PopAndDestroy( view ); + CleanupStack::PopAndDestroy( db ); + if ( error == KErrNone ) + { + aIap = num32Value; + return ETrue; + } + else + { + return EFalse; + } + } + +// ----------------------------------------------------------------------------- +// CMmsConnectionInitiator::StartConnectionL +// Checks if there is already connections open and checks if the +// connection could be reused or not. +// ----------------------------------------------------------------------------- +// +void CMmsConnectionInitiator::StartConnectionL(TUint32 aIap) + { +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("CMmsConnectionInitiator::StartConnectionL") ); +#endif + TUint count; + TPckgBuf connInfo; + TUint i; + TUint32 iap; + HBufC* gprsApn1 = NULL; + HBufC* gprsApn2 = NULL; + TUint32 pdpType1 = 0; + TUint32 pdpType2 = 0; + iap = aIap; + +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("iConnection->EnumerateConnections") ); +#endif + iConnection->EnumerateConnections( count ); + +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("Connection count: %d"),count); +#endif + + if ( count > 0 && FindGprsParametersL( aIap,pdpType1,gprsApn1 ) ) + { + CleanupStack::PushL(gprsApn1); + for ( i=1; i<=count; i++ ) + { + if ( gprsApn2 ) + { + delete gprsApn2; + gprsApn2 = NULL; + } +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("iConnection->GetConnectionInfo ") ); +#endif + iConnection->GetConnectionInfo( i,connInfo ); +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("FindGprsParametersL ") ); +#endif + if ( FindGprsParametersL( connInfo().iIapId,pdpType2,gprsApn2 ) + && pdpType1 == pdpType2 + && *gprsApn1 == *gprsApn2 ) + { +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("APN MATCH !!!!!!!") ); +#endif + iap = connInfo().iIapId; + } + } + } + if ( gprsApn2 ) + { + delete gprsApn2; + } + if ( gprsApn1 ) + { + CleanupStack::PopAndDestroy( gprsApn1 ); + } + + iPrefs.SetIapId( iap ); +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("iConnection->Start ") ); +#endif + TInt error = RProperty::Define( KMPMCathegory, KMPMPropertyKeyMMS, KMPMPropertyTypeMMS ); + if ( error == KErrNone || error == KErrAlreadyExists ) + { + // If the setting of the value does not succeed, a disconnect dialog + // may be displayed - but there is nothing we can do about it. + // We try our best. +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("setting KMPMProperty key to %d "), iap ); +#endif + error = RProperty::Set( KMPMCathegory, KMPMPropertyKeyMMS, iap ); + } + // iConnection cannot be active when we come here. + // And it is not possible to ask ir RConnection is active + iConnection->Start( iPrefs, iStatus ); + return; + } + +// ----------------------------------------------------------------------------- +// CMmsConnectionInitiator::FindGprsParametersL +// Solves PDP type and GPRS Access Point. +// ----------------------------------------------------------------------------- + +TBool CMmsConnectionInitiator::FindGprsParametersL( + TUint32 aIap, TUint32& aPdpType, HBufC*& aGprsApn ) + { +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("CMmsConnectionInitiator::FindGprsParameters") ); + TMmsConnInitLogger::Log( _L("IAP to analyze: %d"),aIap); +#endif + TUint32 service=0; + TBuf textValue; + CCommsDbTableView* view = NULL; + + CCommsDatabase* db = CCommsDatabase::NewL( EDatabaseTypeUnspecified ); + CleanupStack::PushL( db ); + view = db->OpenViewMatchingUintLC( TPtrC( IAP ), TPtrC( COMMDB_ID ), aIap ); + if ( view->GotoFirstRecord() == KErrNone ) + { + view->ReadTextL( TPtrC( IAP_SERVICE_TYPE ), textValue ); +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log (_L("IAP_SERVICE_TYPE: ")); + TMmsConnInitLogger::Log(textValue); +#endif + if ( textValue.Compare( TPtrC( OUTGOING_GPRS ) ) != 0 ) + { + CleanupStack::PopAndDestroy( view ); + CleanupStack::PopAndDestroy( db ); + return EFalse; + } + view->ReadUintL( TPtrC( IAP_SERVICE ), service ); + } + else + { + CleanupStack::PopAndDestroy( view ); + CleanupStack::PopAndDestroy( db ); + return EFalse; + } + CleanupStack::PopAndDestroy( view ); //view + view = NULL; + + view = db->OpenViewMatchingUintLC( textValue, TPtrC( COMMDB_ID ), service ); + if ( view->GotoFirstRecord() == KErrNone ) + { + aGprsApn = view->ReadLongTextLC( TPtrC( GPRS_APN ) ); + view->ReadUintL( TPtrC( GPRS_PDP_TYPE ),aPdpType ); +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("GPRS_APN: ")); + TMmsConnInitLogger::Log(aGprsApn->Des()); + TMmsConnInitLogger::Log( _L("aPdpType: %d"),aPdpType); +#endif + CleanupStack::Pop( aGprsApn ); + CleanupStack::PopAndDestroy( view ); + CleanupStack::PopAndDestroy( db ); + } + else + { + CleanupStack::PopAndDestroy( view ); + CleanupStack::PopAndDestroy( db ); + return EFalse; + } + return ETrue; + } + +// ----------------------------------------------------------------------------- +// RunL +// ----------------------------------------------------------------------------- +// +void CMmsConnectionInitiator::RunL() + { + // immediately release the access point +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("deleting KMPMPropertyKeyMMS") ); +#endif + RProperty::Delete( KMPMCathegory, KMPMPropertyKeyMMS ); + + iConnection->Progress( iProgress ); +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("MmsConnInit::RunL, status: %d"), iStatus.Int() ); + TMmsConnInitLogger::Log( _L(" - progress stage: %d, progress error: %d"), iProgress.iStage, iProgress.iError ); +#endif + + // In error situation, set iStatus to the error + // error form iProgress overrides status only if status is KErrNone + // The behavior of lower level components has changed. + // We are trying to adjust our behavior to the new situation. + + if ( iTimerRunning ) + { + // own timer timed out + iTimer.Close(); + iStatus = KErrCompletion; + iTimerRunning = EFalse; + } + + if ( iStatus.Int() == KErrNone ) + { + iStatus = iProgress.iError; + } + + if ( iStatus.Int() == KErrNotFound || iStatus.Int() == KErrGeneral ) + { + // We should never pass KErrNotFound upwards as it will + // prevent retry loop, and might prevent fetching altogether. + // KErrGeneral does not mean anything, so we try if we can find + // a better error code from progress. + if ( iProgress.iError < KErrGeneral ) + { + // We have some error code in iProgress, and it is not + // KErrNotFound or KErrGeneral + iStatus = iProgress.iError; + } + else + { + // This is better than KErrNotFound. + // It does not tell why the connection was not created, + // but at least it leads to retry loop + iStatus = KErrCouldNotConnect; + } + } + + if( iStatus.Int() == KErrNone ) + { + // iConnection.start completes with no error + // In this succesfull case we set the client status + // to index+1 of the AP array +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("- Connected") ); +#endif + User::RequestComplete( iClientStatus, ( iIndex + 1 ) ); + return; + } + else // status not equal to KErrNone + { + TTime now; + now.UniversalTime(); + TTimeIntervalSeconds timeout = 0; + TInt overflow; + if ( iStatus.Int() == KErrTimedOut ) + { +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("- Timed out") ); +#endif + overflow = now.SecondsFrom( iStartTime, timeout ); + if ( overflow == KErrNone && + timeout.Int() < KMmsShortTimeout && + iRetryCount < KMmsMaxRetryCount ) + { + // worth retrying after a few seconds + iRetryCount++; + TInt error = iTimer.CreateLocal(); + if ( error == KErrNone ) + { + // timer wants microseconds + // iTimer cannot be running as it was closed just a while ago + // And we just said "CreateLocal()" so this is a brand new timer. + iTimer.After( iStatus, KMmsRetryInterval * KMmsSecondsToMilliseconds ); + iTimerRunning = ETrue; + SetActive(); + return; + } + } + } + +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("- Not connected") ); +#endif + // Because we now completed with an error we must re-issue the + // request if there are still items in the array + TUint32 ap; //IAP to be resolved + if ( iStatus != KErrCompletion ) + { + // KErrCompletion means our timer completed + // and we must retry the same access point. + // If we have some other error, we must try next access point + iIndex++; + } + else + { +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("- Timer completed - retry %d"), iRetryCount ); +#endif + } + for( iIndex = iIndex; iIndex < iArray->Count(); iIndex++ ) + { + // index is safe + if( ( FindIapL( iArray->At( iIndex ), ap ) ) ) + { + StartConnectionL( ap ); + SetActive(); + return; + } + // Loop until AP found + } + // Looped through the whole array with no success + User::RequestComplete( iClientStatus, iStatus.Int() ); + return; + } + } + +// --------------------------------------------------------- +// +// --------------------------------------------------------- +// +TInt CMmsConnectionInitiator::RunError(TInt aError) + { + User::RequestComplete( iClientStatus, aError ); + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CMmsConnectionInitiator::DoCancel +// Cancels any outstanding request +// ----------------------------------------------------------------------------- +// +void CMmsConnectionInitiator::DoCancel() + { + //This function is called by Cancel() if there is an + //request outstanding. +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("deleting KMPMPropertyKeyMMS") ); +#endif + RProperty::Delete( KMPMCathegory, KMPMPropertyKeyMMS ); + if ( iTimerRunning ) + { + iTimer.Cancel(); + iTimer.Close(); + iTimerRunning = EFalse; + } + iConnection->Close(); + User::RequestComplete( iClientStatus, KErrCancel ); +#ifdef _MMSCONNINIT_LOGGING_ + TMmsConnInitLogger::Log( _L("MmsConnInit cancelled") ); +#endif + } + +// ----------------------------------------------------------------------------- +#ifdef _MMSCONNINIT_LOGGING_ +const TInt KLogBufferLength = 256; +_LIT(KLogDir, "mmss"); +_LIT(KLogFile, "mmsconninit.txt"); + +void TMmsConnInitLogger::Log(TRefByValue aFmt,...) + { + VA_LIST list; + VA_START(list, aFmt); + + // Print to log file + TBuf buf; + buf.FormatList(aFmt, list); + + // Write to log file + RFileLogger::Write(KLogDir, KLogFile, EFileLoggingModeAppend, buf); + } +#endif + +// =========================== OTHER EXPORTED FUNCTIONS ======================== + +// End of File