emailservices/emailstore/base_plugin/src/basepluginparts.cpp
changeset 0 8466d47a6819
child 8 e1b6206813b4
equal deleted inserted replaced
-1:000000000000 0:8466d47a6819
       
     1 /*
       
     2 * Copyright (c) 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:   Multi-part support.
       
    15 *
       
    16 */
       
    17 #include "BasePlugin.h"
       
    18 #include "baseplugincommonutils.h"
       
    19 #include "baseplugindelayedopsprivate.h"
       
    20 
       
    21 
       
    22 /**
       
    23  *
       
    24  */
       
    25 EXPORT_C void CBasePlugin::ChildPartsL(
       
    26     const TFSMailMsgId& aMailBoxId,
       
    27     const TFSMailMsgId& /*aParentFolderId*/,
       
    28 	const TFSMailMsgId& aMessageId,
       
    29 	const TFSMailMsgId& aParentId,
       
    30 	RPointerArray<CFSMailMessagePart>& aParts )
       
    31 
       
    32     {
       
    33     __LOG_ENTER( "ChildPartsL" )
       
    34     
       
    35     CMsgStoreMessage* message = GetCachedMsgL( aMailBoxId.Id(), aMessageId.Id() );
       
    36     
       
    37     RPointerArray<CMsgStoreMessagePart>* parts;
       
    38     if ( aParentId.IsNullId() )
       
    39         {
       
    40         parts = &GetCachedMsgChildrenL();
       
    41         }
       
    42     else
       
    43         {
       
    44         __LOG_WRITE_INFO( "Looking for the child parts of a part." )
       
    45         GetCachedBodyL( aParentId.Id() );
       
    46         parts = &GetCachedBodyChildrenL();
       
    47         }
       
    48 
       
    49     __LOG_WRITE8_FORMAT1_INFO( "No of child parts : %d.", parts->Count() );
       
    50     
       
    51     TFSMailMsgId fsId( GetPluginId(), 0 );
       
    52     TInt count = parts->Count();
       
    53     for ( TInt i = 0; i < count; i++ )
       
    54         {
       
    55         CMsgStoreMessagePart& thePart = *((*parts)[i]); 
       
    56         fsId.SetId( thePart.Id() );
       
    57 
       
    58         CFSMailMessagePart* fsPart = CFSMailMessagePart::NewLC( aMessageId, fsId );
       
    59         TranslateMsgStorePropsL( aMailBoxId, thePart, *fsPart );
       
    60         fsPart->SetMailBoxId( aMailBoxId );
       
    61 
       
    62         aParts.AppendL( fsPart );
       
    63         CleanupStack::Pop( fsPart );
       
    64         }
       
    65     
       
    66     __LOG_EXIT
       
    67     }
       
    68 
       
    69 
       
    70 /**
       
    71  * @param aInsertBefore msgstore does not support that.
       
    72  */
       
    73 EXPORT_C CFSMailMessagePart* CBasePlugin::NewChildPartL(
       
    74     const TFSMailMsgId& aMailBoxId,
       
    75     const TFSMailMsgId& aParentFolderId,
       
    76 	const TFSMailMsgId& aMessageId,
       
    77 	const TFSMailMsgId& aParentPartId,
       
    78 	const TFSMailMsgId& /*aInsertBefore*/,
       
    79 	const TDesC& aContentType )
       
    80 	
       
    81     {
       
    82     return NewChildPartFromFileL(
       
    83         aMailBoxId, aParentFolderId, aMessageId, aParentPartId,
       
    84         aContentType, KNullDesC );
       
    85     }
       
    86 
       
    87 
       
    88 /**
       
    89  *
       
    90  */
       
    91 EXPORT_C void CBasePlugin::RemoveChildPartL(
       
    92     const TFSMailMsgId& aMailBoxId,
       
    93     const TFSMailMsgId& /*aParentFolderId*/,
       
    94 	const TFSMailMsgId& aMessageId,
       
    95     const TFSMailMsgId& /*aParentPartId*/,
       
    96     const TFSMailMsgId& aPartId )
       
    97 
       
    98     {
       
    99     CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
       
   100     
       
   101     CMsgStoreMessage* message = mailBox().FetchMessageL(
       
   102         aMessageId.Id(), KMsgStoreInvalidId );
       
   103     CleanupStack::PushL( message );
       
   104     
       
   105     message->RemoveChildPartL( aPartId.Id() );
       
   106 
       
   107     CleanupStack::PopAndDestroy( message );
       
   108     }
       
   109 
       
   110 
       
   111 /**
       
   112  *
       
   113  */
       
   114 EXPORT_C void CBasePlugin::SetPartContentFromFileL(
       
   115     const TFSMailMsgId& aMailBoxId,
       
   116     const TFSMailMsgId& /*aParentFolderId*/,
       
   117     const TFSMailMsgId& aMessageId,
       
   118     const TFSMailMsgId& aMessagePartId,
       
   119     const TDesC& aFilePath )
       
   120 
       
   121     {
       
   122     CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
       
   123     
       
   124     CMsgStoreMessage* message = mailBox().FetchMessageL(
       
   125         aMessageId.Id(), KMsgStoreInvalidId );
       
   126     CleanupStack::PushL( message );
       
   127     
       
   128     CMsgStoreMessagePart* part = message->ChildPartL( aMessagePartId.Id(), ETrue );
       
   129     CleanupStack::PushL( part );
       
   130     
       
   131     part->ReplaceContentWithFileL( aFilePath );
       
   132 
       
   133     CleanupStack::PopAndDestroy( part );
       
   134     CleanupStack::PopAndDestroy( message );
       
   135     }
       
   136 
       
   137 
       
   138 /**
       
   139  * Goes through all the part props and stores them in the msg store.
       
   140  *
       
   141  * @param aMailBoxId
       
   142  * @param aParentFolderId - not needed for the msg store.
       
   143  * @param aMessageId
       
   144  * @param aMessagePart
       
   145  */
       
   146 EXPORT_C void CBasePlugin::StoreMessagePartL(
       
   147     const TFSMailMsgId& aMailBoxId,
       
   148     const TFSMailMsgId& /*aParentFolderId*/,
       
   149  	const TFSMailMsgId& aMessageId,
       
   150  	CFSMailMessagePart& aMessagePart )
       
   151 
       
   152     {
       
   153     __LOG_ENTER( "StoreMessagePartL" )
       
   154     
       
   155     CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
       
   156     
       
   157     CMsgStoreMessage* message = mailBox().FetchMessageL(
       
   158         aMessageId.Id(), KMsgStoreInvalidId );
       
   159     CleanupStack::PushL( message );
       
   160     
       
   161     CMsgStoreMessagePart* part = message->ChildPartL(
       
   162         aMessagePart.GetPartId().Id(), ETrue );
       
   163     CleanupStack::PushL( part );
       
   164 
       
   165     TranslateEmailFwMessageL( aMessagePart, *part, EFalse );
       
   166     part->StorePropertiesL();
       
   167 
       
   168     CleanupStack::PopAndDestroy( part );
       
   169     CleanupStack::PopAndDestroy( message );
       
   170     
       
   171     __LOG_EXIT
       
   172     }
       
   173 
       
   174 
       
   175 /**
       
   176  *
       
   177  */
       
   178 EXPORT_C CFSMailMessagePart* CBasePlugin::CopyMessageAsChildPartL(
       
   179     const TFSMailMsgId& /*aMailBoxId*/,
       
   180 	const TFSMailMsgId& /*aMessageId*/,
       
   181 	const TFSMailMsgId& /*aParentFolderId*/,
       
   182 	const TFSMailMsgId& /*aParentPartId*/,
       
   183 	const TFSMailMsgId& /*aInsertBefore*/,
       
   184 	const CFSMailMessage& /*aMessage*/ )
       
   185     {
       
   186     /*
       
   187     Regarding
       
   188 
       
   189     1. Check the need of the function from UI, CopyMessageAsChildPartL(), that copies given
       
   190     message as new child part to this part.
       
   191 
       
   192     Currently UI will enable only adding attachment files from file system so implementing
       
   193     this in FW/plugins is not high priority and can be postponed.
       
   194 
       
   195     // Jouni
       
   196     */
       
   197 
       
   198     /**@ implement.*/
       
   199     return NULL;
       
   200     }
       
   201 
       
   202 /**
       
   203  *
       
   204  */
       
   205 EXPORT_C CFSMailMessagePart* CBasePlugin::MessagePartL(
       
   206     const TFSMailMsgId& aMailBoxId,
       
   207     const TFSMailMsgId& /*aParentFolderId*/,
       
   208     const TFSMailMsgId& aMessageId,
       
   209     const TFSMailMsgId& aMessagePartId )
       
   210     
       
   211     {
       
   212     CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
       
   213 
       
   214     CMsgStoreMessage* message = mailBox().FetchMessageL(
       
   215         aMessageId.Id(), KMsgStoreInvalidId );
       
   216     CleanupStack::PushL( message );
       
   217 
       
   218     CMsgStoreMessagePart* part = message->ChildPartL( aMessagePartId.Id(), ETrue );
       
   219     CleanupStack::PushL( part );
       
   220 
       
   221     TFSMailMsgId msgPartId( GetPluginId(), part->Id() );    
       
   222     CFSMailMessagePart* result = CFSMailMessagePart::NewLC( aMessageId, msgPartId );
       
   223     TranslateMsgStorePropsL( aMailBoxId, *part, *result );
       
   224     result->SetMailBoxId( aMailBoxId );
       
   225 
       
   226     CleanupStack::Pop( result );
       
   227     CleanupStack::PopAndDestroy( part );
       
   228     CleanupStack::PopAndDestroy( message );
       
   229     
       
   230     return result;
       
   231     }
       
   232 
       
   233 
       
   234 /**
       
   235  * The method will leave with KErrNotSupported if the msgstore is encrypted.
       
   236  */
       
   237 EXPORT_C TInt CBasePlugin::GetMessagePartFileL(
       
   238     const TFSMailMsgId& aMailBoxId,
       
   239     const TFSMailMsgId& /*aParentFolderId*/,
       
   240     const TFSMailMsgId& aMessageId,
       
   241     const TFSMailMsgId& aMessagePartId,
       
   242     RFile& aFileHandle )
       
   243 
       
   244     {
       
   245     CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
       
   246     
       
   247     CMsgStoreMessage* msg = mailBox().FetchMessageL( aMessageId.Id(), KMsgStoreInvalidId );
       
   248     CleanupStack::PushL( msg );
       
   249     
       
   250     CMsgStoreMessagePart* part = msg->ChildPartL( aMessagePartId.Id(), ETrue );
       
   251     CleanupStack::PushL( part );
       
   252     
       
   253     //will leave with KErrNotSupported if encrypted.
       
   254     part->OpenOriginalContentFileL( aFileHandle );
       
   255 
       
   256     CleanupStack::PopAndDestroy( part );
       
   257     CleanupStack::PopAndDestroy( msg );
       
   258     
       
   259     return KErrNone;
       
   260     }
       
   261 
       
   262 
       
   263 /**
       
   264  * @param aParentFolderId not used
       
   265  */
       
   266 EXPORT_C void CBasePlugin::CopyMessagePartFileL(
       
   267     const TFSMailMsgId& aMailBoxId,
       
   268     const TFSMailMsgId& /*aParentFolderId*/,
       
   269     const TFSMailMsgId& aMessageId,
       
   270     const TFSMailMsgId& aMessagePartId,
       
   271     const TDesC& aFilePath )
       
   272 
       
   273     {
       
   274     CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
       
   275 
       
   276     CMsgStoreMessage* msg = mailBox().FetchMessageL( aMessageId.Id(), KMsgStoreInvalidId );
       
   277     CleanupStack::PushL( msg );
       
   278     
       
   279     CMsgStoreMessagePart* part = msg->ChildPartL( aMessagePartId.Id(), ETrue );
       
   280     CleanupStack::PushL( part );
       
   281     
       
   282     TUint idx = 0;
       
   283     if ( part->FindProperty( KMsgStorePropertyName, idx ) )
       
   284         {
       
   285         const TDesC& name = part->PropertyValueDesL( idx );
       
   286         
       
   287         HBufC* buf = HBufC::NewLC( name.Length() + aFilePath.Length() );
       
   288         *buf = aFilePath;
       
   289         buf->Des().Append( name );
       
   290         
       
   291         part->FetchContentToFileL( *buf );
       
   292         
       
   293         CleanupStack::PopAndDestroy( buf );
       
   294         }
       
   295 
       
   296     CleanupStack::PopAndDestroy( part );
       
   297     CleanupStack::PopAndDestroy( msg );
       
   298     }
       
   299 
       
   300 
       
   301 /**
       
   302  *
       
   303  */
       
   304 EXPORT_C void CBasePlugin::GetContentToBufferL(
       
   305     const TFSMailMsgId& aMailBoxId,
       
   306     const TFSMailMsgId& /*aParentFolderId*/,
       
   307     const TFSMailMsgId& aMessageId,
       
   308     const TFSMailMsgId& aMessagePartId,
       
   309     TDes& aBuffer,
       
   310     const TUint aStartOffset )
       
   311     
       
   312     {
       
   313     __LOG_ENTER( "GetContentToBufferL" )
       
   314     
       
   315     CMsgStoreMessage* msg = GetCachedMsgL( aMailBoxId.Id(), aMessageId.Id() );
       
   316     
       
   317     //could the cache be extended to cache the child parts in this case ?
       
   318     CMsgStoreMessagePart* part = msg->ChildPartL( aMessagePartId.Id(), ETrue );
       
   319     CleanupStack::PushL( part );
       
   320 
       
   321     TUint outSize = aBuffer.MaxSize();
       
   322 
       
   323     /**@ look for ways to avoid the copying.*/
       
   324     __LOG_WRITE8_FORMAT1_INFO( "Output buffer size: %d bytes.", outSize );
       
   325 
       
   326     HBufC8* buf = HBufC8::NewLC( outSize );
       
   327     TPtr8 ptr = buf->Des();
       
   328     part->FetchContentToBufferL( ptr, aStartOffset );
       
   329     __LOG_WRITE8_FORMAT1_INFO(
       
   330         "Msgstore content buffer size: %d bytes.", buf->Size() );
       
   331     
       
   332 	TUint msgStoreSize = ptr.Size();
       
   333 	TUint theSize = outSize > msgStoreSize ? msgStoreSize : outSize;
       
   334 	
       
   335 	TPtrC16 convert( reinterpret_cast<const TUint16*>( buf->Ptr() ), theSize/2 );
       
   336 	aBuffer = convert;
       
   337 
       
   338     CleanupStack::PopAndDestroy( buf );
       
   339     CleanupStack::PopAndDestroy( part );
       
   340     
       
   341     __LOG_EXIT
       
   342     } //GetContentToBufferL.
       
   343 
       
   344 
       
   345 /**
       
   346  *
       
   347  */
       
   348 EXPORT_C void CBasePlugin::SetContentL(
       
   349     const TDesC& aBuffer,
       
   350     const TFSMailMsgId& aMailBoxId,
       
   351     const TFSMailMsgId& /*aParentFolderId*/,
       
   352     const TFSMailMsgId& aMessageId,
       
   353     const TFSMailMsgId& aMessagePartId )
       
   354 
       
   355     {
       
   356     __LOG_ENTER( "SetContentL" )
       
   357         
       
   358     TMsgStoreId partId = aMessagePartId.IsNullId()
       
   359         ? KMsgStoreInvalidId : aMessagePartId.Id();
       
   360     
       
   361     //part one, sets the content.
       
   362     CDelayedSetContentOp* op = CDelayedSetContentOp::NewLC(
       
   363         aMailBoxId.Id(), aMessageId.Id(), partId, aBuffer );
       
   364     iDelayedOpsManager->EnqueueOpL( op );
       
   365     CleanupStack::Pop( op );
       
   366 
       
   367     //part two, then updates the part's properties.
       
   368     op = CDelayedSetContentOp::NewLC(
       
   369         aMailBoxId.Id(), aMessageId.Id(), partId, aBuffer.Length() );
       
   370     iDelayedOpsManager->EnqueueOpL( op );
       
   371     CleanupStack::Pop( op );
       
   372 
       
   373     __LOG_EXIT
       
   374     } //SetContentL.
       
   375 
       
   376 
       
   377 /**
       
   378  * @param aPartIds ids of the parts to be removed from the message with id aMessageId.
       
   379  */
       
   380 EXPORT_C void CBasePlugin::RemovePartContentL(
       
   381     const TFSMailMsgId& aMailBoxId,
       
   382     const TFSMailMsgId& /*aParentFolderId*/,
       
   383     const TFSMailMsgId& aMessageId,
       
   384     const RArray<TFSMailMsgId>& aPartIds )
       
   385 
       
   386     {
       
   387     __LOG_ENTER( "RemovePartContentL" )
       
   388 
       
   389     CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
       
   390 
       
   391     CMsgStoreMessage* message = mailBox().FetchMessageL(
       
   392         aMessageId.Id(), KMsgStoreInvalidId );
       
   393     CleanupStack::PushL( message );
       
   394 
       
   395     for ( TInt i = 0; i < aPartIds.Count(); i++ )
       
   396         {
       
   397         CMsgStoreMessagePart* part = message->ChildPartL( aPartIds[i].Id() );
       
   398         CleanupStack::PushL( part );
       
   399 
       
   400         HandleRemovePartContentL( *message, *part );
       
   401         
       
   402         CleanupStack::PopAndDestroy( part );
       
   403         }
       
   404 
       
   405     CleanupStack::PopAndDestroy( message );
       
   406     __LOG_EXIT
       
   407     }
       
   408 
       
   409 
       
   410 /**
       
   411  *
       
   412  */
       
   413 EXPORT_C CFSMailMessagePart* CBasePlugin::NewChildPartFromFileL(
       
   414     const TFSMailMsgId& aMailBoxId,
       
   415     const TFSMailMsgId& aParentFolderId,
       
   416     const TFSMailMsgId& aMessageId,
       
   417     const TFSMailMsgId& aParentPartId,
       
   418 	const TDesC& aContentType,
       
   419     const TDesC& aFilePath )
       
   420     {
       
   421     RFile dummyFile;
       
   422     return NewChildPartFromFilePathOrHandleL( 
       
   423     		aMailBoxId,
       
   424     		aParentFolderId,
       
   425     		aMessageId,
       
   426     		aParentPartId,
       
   427     		aContentType,
       
   428     		aFilePath,
       
   429     		EFalse,
       
   430     		dummyFile
       
   431     		);
       
   432     } //NewChildPartFromFileL.
       
   433 
       
   434 
       
   435 /**
       
   436  *
       
   437  */
       
   438 EXPORT_C CFSMailMessagePart* CBasePlugin::NewChildPartFromFileL(
       
   439     const TFSMailMsgId& aMailBoxId,
       
   440     const TFSMailMsgId& aParentFolderId,
       
   441     const TFSMailMsgId& aMessageId,
       
   442     const TFSMailMsgId& aParentPartId,
       
   443 	const TDesC& aContentType,
       
   444 	RFile& aFile )
       
   445 
       
   446     {
       
   447     RFile dummyFile;
       
   448     return NewChildPartFromFilePathOrHandleL( 
       
   449     		aMailBoxId,
       
   450     		aParentFolderId,
       
   451     		aMessageId,
       
   452     		aParentPartId,
       
   453     		aContentType,
       
   454     		KNullDesC,
       
   455     		ETrue,
       
   456     		aFile
       
   457     		);
       
   458     } //NewChildPartFromFileL.
       
   459 
       
   460 
       
   461 /**
       
   462  * Helper method to avoid duplicated code
       
   463  */
       
   464 CFSMailMessagePart* CBasePlugin::NewChildPartFromFilePathOrHandleL(
       
   465     const TFSMailMsgId& aMailBoxId,
       
   466     const TFSMailMsgId& /*aParentFolderId*/,
       
   467     const TFSMailMsgId& aMessageId,
       
   468     const TFSMailMsgId& aParentPartId,
       
   469 	const TDesC& aContentType,
       
   470     const TDesC& aFilePath,
       
   471     TBool  aUseFileHandle, 
       
   472     RFile& aFile )
       
   473 	{
       
   474     CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
       
   475     
       
   476     CMsgStoreMessage* message = mailBox().FetchMessageL(
       
   477         aMessageId.Id(), KMsgStoreInvalidId );
       
   478     CleanupStack::PushL( message );
       
   479 
       
   480     //determine the parent part - could be the message or any of its parts.
       
   481     CMsgStoreMessagePart* parent;
       
   482     if ( aParentPartId.IsNullId() )
       
   483         {
       
   484         parent = message;
       
   485         CleanupStack::Pop( message );
       
   486         }
       
   487     else
       
   488         {
       
   489         parent = message->ChildPartL( aParentPartId.Id(), ETrue );
       
   490         CleanupStack::PopAndDestroy( message );
       
   491         }
       
   492     CleanupStack::PushL( parent );
       
   493 
       
   494     //msgstore's message content type.
       
   495     CMsgStorePropertyContainer* props = CMsgStorePropertyContainer::NewL();
       
   496     CleanupStack::PushL( props );
       
   497     
       
   498     if ( aContentType != KNullDesC )
       
   499         {
       
   500         props->AddOrUpdatePropertyL( KMsgStorePropertyContentType, aContentType );
       
   501         }
       
   502     
       
   503     CMsgStoreMessagePart* part = NULL;
       
   504     if ( aUseFileHandle )
       
   505     	{
       
   506     	part = parent->AddChildPartL( *props, aFile );
       
   507     	}
       
   508     else
       
   509     	{
       
   510     	part = parent->AddChildPartL( *props, aFilePath );
       
   511     	}
       
   512     CleanupStack::PopAndDestroy( props );
       
   513     CleanupStack::PushL( part );
       
   514 
       
   515     //update the size and the fetched size.
       
   516     TUint contentLength = part->ContentLengthL();
       
   517     if ( 0 != contentLength )
       
   518         {
       
   519         part->AddOrUpdatePropertyL(
       
   520             KMsgStorePropertySize, static_cast<TUint32>( contentLength ) );
       
   521         part->AddOrUpdatePropertyL(
       
   522             KMsgStorePropertyRetrievedSize, static_cast<TUint32>( contentLength ) );
       
   523         
       
   524         part->StorePropertiesL();
       
   525         }
       
   526     
       
   527     TFSMailMsgId fsId( GetPluginId(), part->Id() );
       
   528     CleanupStack::PopAndDestroy( part );
       
   529 
       
   530     //prepare the fw object.
       
   531     CFSMailMessagePart* result = CFSMailMessagePart::NewL( aMessageId, fsId );
       
   532 
       
   533     if ( aContentType != KNullDesC )
       
   534         {
       
   535         result->SetContentType( aContentType );
       
   536         }
       
   537     result->SetContentSize( contentLength );
       
   538     result->SetFetchedContentSize( contentLength );
       
   539     result->SetMailBoxId( aMailBoxId );
       
   540 
       
   541     CleanupStack::PopAndDestroy( parent );
       
   542 
       
   543     return result;
       
   544 	} //NewChildPartFromFileNameOrHandleL
       
   545 
       
   546 
       
   547 /**
       
   548  * 
       
   549  */
       
   550 EXPORT_C /*virtual*/ void CBasePlugin::HandleRemovePartContentL(
       
   551 	CMsgStoreMessage& /* aMsg */,
       
   552 	CMsgStoreMessagePart& aPart )
       
   553 
       
   554 	{
       
   555     TUint idx = 0;
       
   556     idx = aPart.AddOrUpdatePropertyL(
       
   557     	KMsgStorePropertyRetrievedSize, static_cast<TUint32>( 0 ) );
       
   558 	aPart.StorePropertyL( idx );
       
   559     
       
   560     aPart.RemoveContentL();
       
   561 	}
       
   562