remotestoragefw/remotefileengine/src/rsfwmountstatemachine.cpp
branchRCL_3
changeset 20 1aa8c82cb4cb
parent 0 3ad9d5175a89
equal deleted inserted replaced
19:88ee4cf65e19 20:1aa8c82cb4cb
       
     1 /*
       
     2 * Copyright (c) 2005-2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  State machine for mounting
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <rsfwmountman.h>
       
    20 #include "rsfwmountstatemachine.h"
       
    21 #include "rsfwwaitnotemanager.h"
       
    22 #include "rsfwvolumetable.h"
       
    23 #include "rsfwvolume.h"
       
    24 #include "rsfwfileengine.h"
       
    25 #include "rsfwrferequest.h"
       
    26 #include "rsfwnotpluginrequest.h"
       
    27 #include "mdebug.h"
       
    28 #include <ecomerrorcodes.h>
       
    29 
       
    30 // CONSTANTS
       
    31 // errors returned by connection layer
       
    32 const TInt KRsfwErrNoNetworkCoverage = -4159; // device out of range
       
    33 const TInt KRsfwErrOfflineNotPossible = -4180; // device in off-line mode
       
    34 
       
    35 /*************************************
       
    36  * CRsfwMountStateMachine
       
    37  *
       
    38  * Note that EnteredConnectionState() in CompleteL
       
    39  * may start reintegration.
       
    40  * However instead of writing special reintegration states here
       
    41  * it is better to later implement a reintegration thread.
       
    42  *
       
    43  ***************************************/
       
    44 
       
    45 
       
    46 // ----------------------------------------------------------------------------
       
    47 // CRsfwMountStateMachine::NewL
       
    48 // ----------------------------------------------------------------------------
       
    49 // 
       
    50 CRsfwMountStateMachine* 
       
    51 CRsfwMountStateMachine::NewL(TRsfwMountConfig aMountConfig,
       
    52                              TInt aMountState,
       
    53                              CRsfwVolumeTable* aVolumeTable)
       
    54     {
       
    55     CRsfwMountStateMachine* self = new (ELeave) CRsfwMountStateMachine();
       
    56     CleanupStack::PushL(self);
       
    57     self->ConstructL(aMountConfig, aMountState, aVolumeTable);
       
    58     CleanupStack::Pop(self);
       
    59     return self;
       
    60     }
       
    61 
       
    62 // ----------------------------------------------------------------------------
       
    63 // CRsfwMountStateMachine::ConstructL
       
    64 // ----------------------------------------------------------------------------
       
    65 // 
       
    66 void CRsfwMountStateMachine::ConstructL(TRsfwMountConfig aMountConfig, 
       
    67                                         TInt aMountState,
       
    68                                         CRsfwVolumeTable* aVolumeTable)
       
    69     {
       
    70     DEBUGSTRING16(("Mounting drive '%c' with uri '%S', flags=0x%x, to=%d",
       
    71                    TUint(aMountConfig.iDriveLetter),
       
    72                    &(aMountConfig).iUri,
       
    73                    aMountConfig.iFlags,
       
    74                    aMountConfig.iInactivityTimeout));
       
    75 
       
    76     iMountConfig = aMountConfig;
       
    77     iMountState = aMountState;
       
    78     iFriendlyName = iMountConfig.iName; 
       
    79     SetVolumes(aVolumeTable);    
       
    80         
       
    81     iVolumeId = Volumes()->VolumeIdByDriveLetter(iMountConfig.iDriveLetter);        
       
    82     if (iVolumeId == KErrNotFound)
       
    83         {
       
    84         User::Leave(KErrArgument);
       
    85         }
       
    86     
       
    87     // set volume and file engine
       
    88     if (iMountState == KMountStateDormant)
       
    89         {
       
    90         // volume and file engine must exist
       
    91         CRsfwVolume* volume = Volumes()->VolumeByVolumeId(iVolumeId);
       
    92         if (volume) 
       
    93             {
       
    94             iVolume = volume;
       
    95             }
       
    96         else 
       
    97             {
       
    98             User::Leave(KErrNotFound);
       
    99             }
       
   100         }
       
   101     else 
       
   102         {
       
   103         // create volume 
       
   104         iVolume = new (ELeave) CRsfwVolume();   
       
   105         iVolume->iVolumeTable = Volumes();
       
   106         
       
   107         // set mountinfo for the volume
       
   108          TRsfwMountInfo& mountInfo = iVolume->iMountInfo;
       
   109          mountInfo.iMountConfig = iMountConfig;
       
   110          mountInfo.iMountStatus.iVolumeId = iVolumeId;
       
   111          iVolume->iVolumeTable = Volumes();
       
   112 
       
   113         if (mountInfo.iMountConfig.iInactivityTimeout < 0)
       
   114             {
       
   115             // Negative value means that we don't want to time out
       
   116             mountInfo.iMountConfig.iInactivityTimeout = 0;
       
   117              }
       
   118         else if (mountInfo.iMountConfig.iInactivityTimeout > 0)
       
   119             {
       
   120             // Positive means using system default
       
   121             mountInfo.iMountConfig.iInactivityTimeout =
       
   122                      Volumes()->iInactivityTimeout;
       
   123             }
       
   124         // Just copy the adapted parameter
       
   125         mountInfo.iMountStatus.iInactivityTimeout =
       
   126             mountInfo.iMountConfig.iInactivityTimeout;
       
   127 
       
   128         mountInfo.iMountStatus.iPermanence = Volumes()->iPermanence;
       
   129         if (iMountConfig.iFlags & KMountFlagOffLine)
       
   130             {
       
   131             // We are working offline
       
   132             mountInfo.iMountStatus.iConnectionState = KMountNotConnected;
       
   133             }
       
   134         else
       
   135             {
       
   136             mountInfo.iMountStatus.iConnectionState = KMountStronglyConnected;
       
   137             }
       
   138         
       
   139         // create fileengine and attack to volume
       
   140         iVolume->iFileEngine = CRsfwFileEngine::NewL(iVolume);
       
   141         }
       
   142         
       
   143     // set also fileengine pointer in the operation state machine, 
       
   144     // so that the operation can be cancelled
       
   145     SetFileEngine(iVolume->iFileEngine); 
       
   146     
       
   147         
       
   148     }
       
   149 
       
   150 // ----------------------------------------------------------------------------
       
   151 // CRsfwMountStateMachine::CompleteRequestL
       
   152 // ----------------------------------------------------------------------------
       
   153 // 
       
   154 CRsfwRfeStateMachine::TState* CRsfwMountStateMachine::CompleteRequestL(TInt aError) 
       
   155     { 
       
   156     DEBUGSTRING16(("CRsfwMountStateMachine:::CompleteRequestL error %d", aError));
       
   157     // Attach volume to the table
       
   158     // Note that this is always done, even if "request_connection_state"
       
   159     // returned an error.
       
   160     // This is because sending packets to remote server required construction
       
   161     // of CRsfwFileEngine etc. anyway, and they will be deleted from elsewhere
       
   162     // (deleting the mount configuration or the inactivity timeout)
       
   163     if (!(iMountState == KMountStateDormant)) 
       
   164         {
       
   165         Volumes()->iVolumes[iVolumeId] = iVolume;
       
   166         }
       
   167     
       
   168     // make sure engine disconnects if there was an error
       
   169     if (aError != KErrNone) 
       
   170         {
       
   171         iVolume->iFileEngine->RequestConnectionStateL(
       
   172                     KMountNotConnected,
       
   173                     NULL);
       
   174         }
       
   175 
       
   176     return CRsfwWaitNoteStateMachine::CompleteRequestL(aError);
       
   177     }
       
   178 
       
   179 // ----------------------------------------------------------------------------
       
   180 // CRsfwMountStateMachine::ErrorOnStateEntry
       
   181 // ----------------------------------------------------------------------------
       
   182 // 
       
   183 CRsfwWaitNoteStateMachine::TState* CRsfwMountStateMachine::ErrorOnStateEntry(TInt aError) 
       
   184     {
       
   185     DEBUGSTRING16(("CRsfwMountStateMachine::ErrorOnStateEntry %d", aError));
       
   186    
       
   187     if (aError == KEComErrNoInterfaceIdentified)
       
   188         {
       
   189         aError = KErrNotFound;
       
   190         }
       
   191 
       
   192     // If error when connecting: 
       
   193     // For most errors we have to show "drive not available, retry?"
       
   194     // or some other connection error dialog
       
   195     // for this we must first dismiss the current wait note and then show
       
   196     // a new note.
       
   197     // Hower, if user presses Cancel or the red button we return immediately
       
   198     if ((iRequestingConnection) && (aError != KErrCancel))
       
   199         {
       
   200         iRequestingConnection = EFalse;
       
   201         iConnectingError = aError;
       
   202         return new CRsfwMountStateMachine::TDismissConnectionWaitNoteState(this);
       
   203         }
       
   204     else
       
   205         {
       
   206         return CRsfwWaitNoteStateMachine::ErrorOnStateEntry(aError);    
       
   207         }    
       
   208     }
       
   209 
       
   210 // ----------------------------------------------------------------------------
       
   211 // CRsfwMountStateMachine::TRequestConnectionState::TRequestConnectionState
       
   212 // ----------------------------------------------------------------------------
       
   213 // 
       
   214 CRsfwMountStateMachine::
       
   215 TRequestConnectionState::TRequestConnectionState(CRsfwMountStateMachine* aParent)
       
   216     : iOperation(aParent)
       
   217     {
       
   218     }
       
   219 
       
   220 // ----------------------------------------------------------------------------
       
   221 // CRsfwMountStateMachine::TRequestConnectionState::EnterL
       
   222 // ----------------------------------------------------------------------------
       
   223 // 
       
   224 void CRsfwMountStateMachine::TRequestConnectionState::EnterL()
       
   225     {
       
   226     DEBUGSTRING16(("CRsfwMountStateMachine::TRequestConnectionState::EnterL"));
       
   227     
       
   228     // set volume mountconfig 
       
   229     iOperation->iVolume->iMountInfo.iMountConfig = iOperation->iMountConfig;
       
   230        
       
   231     // put up a 'Connecting...' global wait note
       
   232 
       
   233     iOperation->ShowWaitNoteL( ERemoteOpConnecting );
       
   234 
       
   235     // mark mount connection state as KMountConnecting
       
   236     // this is done, because will prevent engine from shutdown
       
   237     iOperation->FileEngine()->EnteredConnectionStateL(KMountConnecting, EFalse);
       
   238    
       
   239     // request KMountStronglyConnected state
       
   240     // this will open connection to the server
       
   241     iOperation->iRequestingConnection = ETrue;
       
   242     TUint transactionId = iOperation->FileEngine()
       
   243 	          ->RequestConnectionStateL(KMountStronglyConnected,
       
   244                                         iOperation);
       
   245         
       
   246     // transactionId = 0 means syncronous non-cancellable operation  
       
   247     if (transactionId > 0) 
       
   248         {
       
   249         iOperation->iRequestingConnection = EFalse;    
       
   250     	iOperation->iTransactionId = transactionId;
       
   251         }
       
   252     
       
   253     }
       
   254    
       
   255 // ----------------------------------------------------------------------------
       
   256 // CRsfwMountStateMachine::TRequestConnectionState::CompleteL
       
   257 // This function should be able to do what CRsfwVolumeTable::MountL normally does
       
   258 // after fileEngine->RequestConnectionStateL() has returned
       
   259 // (with non-error return code)
       
   260 // ----------------------------------------------------------------------------
       
   261 //     
       
   262 CRsfwRfeStateMachine::TState*
       
   263 CRsfwMountStateMachine::TRequestConnectionState::CompleteL()
       
   264     {  
       
   265     DEBUGSTRING16(("CRsfwMountStateMachine::TRequestConnectionState::CompleteL"));
       
   266         
       
   267     if (iOperation->iRequestingConnection)
       
   268         {
       
   269         iOperation->iRequestingConnection = EFalse;
       
   270         }
       
   271        
       
   272     if (!(iOperation->iMountState == KMountStateDormant)) 
       
   273         {
       
   274         // Attach volume to the table
       
   275         iOperation->Volumes()->iVolumes[iOperation->iVolumeId] =
       
   276             iOperation->iVolume;
       
   277         }
       
   278         
       
   279     // Attach volume to the request
       
   280     // (such that the request can notify File Engine of operation completion)
       
   281     iOperation->Request()->iVolume = iOperation->iVolume;
       
   282 
       
   283     iOperation->FileEngine()->EnteredConnectionStateL(KMountStronglyConnected, EFalse);
       
   284 
       
   285     // publish the new connection state (P&S notification)
       
   286     iOperation->Volumes()->PublishConnectionStatus(iOperation->iVolume);
       
   287          
       
   288     // Remember the volume id for the next root setup
       
   289     iOperation->Volumes()->iLastVolumeId = iOperation->iVolumeId;
       
   290    
       
   291     // remember why the connection attempt failed
       
   292     iOperation->iConnectingError = KErrNone;
       
   293  
       
   294    // dismiss the connecting dialog
       
   295      return new CRsfwMountStateMachine::TDismissConnectionWaitNoteState(
       
   296             iOperation);  
       
   297    
       
   298     }
       
   299 
       
   300 
       
   301 // ----------------------------------------------------------------------------
       
   302 // CRsfwMountStateMachine::TRequestConnectionState::ErrorL
       
   303 // ----------------------------------------------------------------------------
       
   304 // 
       
   305 CRsfwRfeStateMachine::TState*
       
   306 CRsfwMountStateMachine::TRequestConnectionState::ErrorL(TInt aCode)
       
   307     {
       
   308     DEBUGSTRING16(("CRsfwMountStateMachine::TRequestConnectionState error=%d", aCode));
       
   309 
       
   310     if (iOperation->iRequestingConnection)
       
   311         {
       
   312         iOperation->iRequestingConnection = EFalse;
       
   313         }
       
   314     
       
   315     // remember why the connection attempt failed
       
   316     iOperation->iConnectingError = aCode;
       
   317     
       
   318     if ((aCode == KErrNone) || (aCode == KErrCancel)) 
       
   319         {
       
   320         // immediately return 
       
   321         return iOperation->CompleteRequestL(aCode);
       
   322         }
       
   323 
       
   324     // else remove wait note dialog first
       
   325      return new CRsfwMountStateMachine::TDismissConnectionWaitNoteState(
       
   326             iOperation);  
       
   327     }
       
   328 
       
   329 
       
   330 // *************
       
   331 
       
   332 // ----------------------------------------------------------------------------
       
   333 // CRsfwMountStateMachine::
       
   334 // TDismissConnectionWaitNoteState::TDismissConnectionWaitNoteState
       
   335 // ----------------------------------------------------------------------------
       
   336 // 
       
   337 CRsfwMountStateMachine::
       
   338 TDismissConnectionWaitNoteState::TDismissConnectionWaitNoteState(CRsfwMountStateMachine* aParent)
       
   339     : iOperation(aParent)
       
   340         {
       
   341         }
       
   342 
       
   343 // ----------------------------------------------------------------------------
       
   344 // CRsfwMountStateMachine::TDismissConnectionWaitNoteState::EnterL
       
   345 // ----------------------------------------------------------------------------
       
   346 // 
       
   347 void CRsfwMountStateMachine::TDismissConnectionWaitNoteState::EnterL() 
       
   348     {
       
   349     DEBUGSTRING16(("CRsfwMountStateMachine::TDismissConnectionWaitNoteState::EnterL"));	  
       
   350     iOperation->DeleteWaitNoteL(EFalse);    
       
   351     }
       
   352 
       
   353 // ----------------------------------------------------------------------------
       
   354 // CRsfwMountStateMachine::TDismissConnectionWaitNoteState::CompleteL
       
   355 // ----------------------------------------------------------------------------
       
   356 // 
       
   357 CRsfwRfeStateMachine::TState*
       
   358 CRsfwMountStateMachine::TDismissConnectionWaitNoteState::CompleteL()
       
   359     {
       
   360     DEBUGSTRING16(("CRsfwMountStateMachine::TDismissConnectionWaitNoteState::CompleteL"));
       
   361     switch (iOperation->iConnectingError) 
       
   362         {
       
   363         case KErrNone:
       
   364            return iOperation->CompleteRequestL(KErrNone);
       
   365         case KErrCancel:
       
   366            return iOperation->CompleteRequestL(KErrCancel);
       
   367         case KErrAccessDenied:
       
   368            return new CRsfwMountStateMachine::TGetAuthCredentials(iOperation);
       
   369         case KErrNoMemory:
       
   370             iOperation->Volumes()->WaitNoteManager()
       
   371                 ->ShowOutOfMemoryNoteL();
       
   372             return iOperation->CompleteRequestL(KErrNoMemory);
       
   373         case KErrNotFound:
       
   374         case KErrPathNotFound:
       
   375             iOperation->Volumes()->WaitNoteManager()
       
   376                 ->ShowAddressNotFoundErrorL(iOperation->iFriendlyName);
       
   377             return iOperation->CompleteRequestL(iOperation->iConnectingError);
       
   378         case KRsfwErrNoNetworkCoverage:
       
   379             iOperation->Volumes()->WaitNoteManager()
       
   380 	            ->ShowNoNetworkCoverageNoteL();
       
   381 	        return iOperation->CompleteRequestL(KRsfwErrNoNetworkCoverage);    
       
   382         case KRsfwErrOfflineNotPossible:
       
   383             iOperation->Volumes()->WaitNoteManager()
       
   384 	            ->ShowOfflineNotPossibleNoteL(); 
       
   385 	        return iOperation->CompleteRequestL(KRsfwErrOfflineNotPossible);
       
   386         default:
       
   387            // ask user whether to retry
       
   388             return new CRsfwMountStateMachine::TUnavailableRetry(iOperation);
       
   389         }
       
   390     }
       
   391     
       
   392 //-----------------------------------------------------------------------------
       
   393 // CRsfwMountStateMachine::TDismissConnectionWaitNoteState::ErrorL
       
   394 // ----------------------------------------------------------------------------
       
   395 // 
       
   396 CRsfwRfeStateMachine::TState*
       
   397 CRsfwMountStateMachine::TDismissConnectionWaitNoteState::ErrorL(TInt /*aCode*/)
       
   398     {
       
   399     DEBUGSTRING16(("CRsfwMountStateMachine::TDismissConnectionWaitNoteState::ErrorL"));		
       
   400     // dismissing the dialog failed
       
   401     // no code for this case
       
   402     return CompleteL();
       
   403     }
       
   404 
       
   405 // *************
       
   406 
       
   407 // ----------------------------------------------------------------------------
       
   408 // CRsfwMountStateMachine::TGetAuthCredentials::TGetAuthCredentials
       
   409 // ----------------------------------------------------------------------------
       
   410 // 
       
   411 CRsfwMountStateMachine::
       
   412 TGetAuthCredentials::TGetAuthCredentials(CRsfwMountStateMachine* aParent)
       
   413     : iOperation(aParent)
       
   414     {
       
   415     }
       
   416 
       
   417 // ----------------------------------------------------------------------------
       
   418 // CRsfwMountStateMachine::TGetAuthCredentials::EnterL
       
   419 // ----------------------------------------------------------------------------
       
   420 // 
       
   421 void CRsfwMountStateMachine::TGetAuthCredentials::EnterL()
       
   422     {
       
   423     DEBUGSTRING16(("CRsfwMountStateMachine::TGetAuthCredentials::EnterL"));
       
   424     iAuthRequest.iMethod = TRsfwNotPluginRequest::EAuthenticationDlg;
       
   425     iAuthRequest.iDriveName = iOperation->iFriendlyName;
       
   426     iAuthRequest.iUserName = iOperation->iMountConfig.iUserName;
       
   427     iAuthRequest.iPassword = iOperation->iMountConfig.iPassword;
       
   428            
       
   429     iOperation->Volumes()->WaitNoteManager()->SetAuthenticationDialogL(iAuthRequest);
       
   430     iOperation->Volumes()->WaitNoteManager()
       
   431             ->StartWaitNoteL(ERemoteOpAuthDialog, iOperation);    
       
   432     }
       
   433 
       
   434 // ----------------------------------------------------------------------------
       
   435 // CRsfwMountStateMachine::TGetAuthCredentials::CompleteL
       
   436 // ----------------------------------------------------------------------------
       
   437 //     
       
   438 CRsfwRfeStateMachine::TState*
       
   439 CRsfwMountStateMachine::TGetAuthCredentials::CompleteL()
       
   440     {
       
   441     DEBUGSTRING16(("CRsfwMountStateMachine::TGetAuthCredentials::CompleteL"));
       
   442     // re-set username and password and try connecting again
       
   443     iOperation->iMountConfig.iUserName = iAuthRequest.iUserName;
       
   444     iOperation->iMountConfig.iPassword = iAuthRequest.iPassword;   
       
   445      
       
   446     return new CRsfwMountStateMachine::TRequestConnectionState(iOperation);  
       
   447     }
       
   448     
       
   449 // ----------------------------------------------------------------------------
       
   450 // CRsfwMountStateMachine::TGetAuthCredentials::ErrorL
       
   451 // ----------------------------------------------------------------------------
       
   452 // 
       
   453 CRsfwRfeStateMachine::TState*
       
   454 CRsfwMountStateMachine::TGetAuthCredentials::ErrorL(TInt /*aCode*/)
       
   455     {    
       
   456     DEBUGSTRING16(("CRsfwMountStateMachine::TGetAuthCredentials::ErrorL"));
       
   457     return iOperation->CompleteRequestL(KErrAccessDenied);
       
   458     }
       
   459     
       
   460 // **************
       
   461 
       
   462 
       
   463 // ----------------------------------------------------------------------------
       
   464 // CRsfwMountStateMachine::TUnavailableRetry::TGetAuthCredentials
       
   465 // ----------------------------------------------------------------------------
       
   466 // 
       
   467 CRsfwMountStateMachine::
       
   468 TUnavailableRetry::TUnavailableRetry(CRsfwMountStateMachine* aParent)
       
   469     : iOperation(aParent)
       
   470     {
       
   471     }
       
   472 
       
   473 // ----------------------------------------------------------------------------
       
   474 // CRsfwMountStateMachine::TUnavailableRetry::EnterL
       
   475 // ----------------------------------------------------------------------------
       
   476 // 
       
   477 void CRsfwMountStateMachine::TUnavailableRetry::EnterL()
       
   478     {
       
   479     DEBUGSTRING16(("CRsfwMountStateMachine::TUnavailableRetry::EnterL"));
       
   480     iRetryRequest.iMethod = TRsfwNotPluginRequest::EUnavailableRetryDlg;
       
   481     iRetryRequest.iDriveName = iOperation->iFriendlyName;
       
   482     
       
   483     iOperation->Volumes()->WaitNoteManager()->SetGlobalNoteRequestL(iRetryRequest);
       
   484     iOperation->Volumes()->WaitNoteManager()
       
   485             ->StartWaitNoteL(ERemoteUnavailableRetry, iOperation);         
       
   486     }
       
   487 
       
   488 // ----------------------------------------------------------------------------
       
   489 // CRsfwMountStateMachine::TUnavailableRetry::CompleteL
       
   490 // ----------------------------------------------------------------------------
       
   491 //     
       
   492 CRsfwRfeStateMachine::TState*
       
   493 CRsfwMountStateMachine::TUnavailableRetry::CompleteL()
       
   494     {
       
   495     DEBUGSTRING16(("CRsfwMountStateMachine::TUnavailableRetry::CompleteL"));	
       
   496     // retry
       
   497     return new CRsfwMountStateMachine::TRequestConnectionState(iOperation);  
       
   498     }
       
   499     
       
   500 // ----------------------------------------------------------------------------
       
   501 // CRsfwMountStateMachine::TUnavailableRetry::ErrorL
       
   502 // ----------------------------------------------------------------------------
       
   503 // 
       
   504 CRsfwRfeStateMachine::TState*
       
   505 CRsfwMountStateMachine::TUnavailableRetry::ErrorL(TInt aCode)
       
   506     {
       
   507     DEBUGSTRING16(("CRsfwMountStateMachine::TUnavailableRetry::ErrorL"));
       
   508     if (aCode == KErrCancel) 
       
   509         {
       
   510         // user cancelled the a dialog
       
   511         return iOperation->CompleteRequestL(KErrCancel);
       
   512         }
       
   513     else 
       
   514         {
       
   515         return iOperation->CompleteRequestL(aCode);
       
   516         }
       
   517     }