ncdengine/provider/purchasehistory/src/ncdpurchasehistorydbimpl.cpp
changeset 4 32704c33136d
equal deleted inserted replaced
-1:000000000000 4:32704c33136d
       
     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:  
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <eikenv.h>
       
    20 #include <f32file.h>
       
    21 #include <bautils.h>
       
    22 #include <s32mem.h>
       
    23 
       
    24 #include "ncdpurchasehistorydbimpl.h"
       
    25 #include "ncdpurchasedownloadinfo.h"
       
    26 #include "ncdpurchaseinstallinfo.h"
       
    27 #include "ncdpurchasehistoryfilter.h"
       
    28 #include "ncdnodefunctionids.h"
       
    29 #include "catalogssession.h"
       
    30 #include "catalogsbasemessage.h"
       
    31 #include "catalogsbigdes.h"
       
    32 #include "catalogsconstants.h"
       
    33 #include "catalogsutils.h"
       
    34 #include "ncdutils.h"
       
    35 
       
    36 #include "catalogsdebug.h"
       
    37 
       
    38 // Create a purchases table.
       
    39 // This column order is always used when inserting data or in queries.
       
    40 // Column numbering is stored in CNcdPurchaseHistoryDb::PurchaseColumns.
       
    41 _LIT( KSqlCreatePurchasesTable, "\
       
    42  CREATE TABLE purchases ( \
       
    43  purchase_id COUNTER,\
       
    44  event_id UNSIGNED INTEGER,\
       
    45  client_uid INTEGER,\
       
    46  namespace LONG VARCHAR,\
       
    47  entity_id LONG VARCHAR,\
       
    48  item_name LONG VARCHAR,\
       
    49  item_purpose UNSIGNED INTEGER,\
       
    50  catalog_name LONG VARCHAR,\
       
    51  download_info LONG VARBINARY,\
       
    52  purchase_option_id LONG VARCHAR,\
       
    53  purchase_option_name LONG VARCHAR,\
       
    54  purchase_option_price LONG VARCHAR,\
       
    55  final_price LONG VARCHAR,\
       
    56  payment_method_name LONG VARCHAR,\
       
    57  purchase_time BIGINT,\
       
    58  downloaded_files LONG VARBINARY,\
       
    59  file_install_infos LONG VARBINARY,\
       
    60  icon LONG VARBINARY,\
       
    61  downloadaccesspoint LONG VARCHAR,\
       
    62  description LONG VARCHAR,\
       
    63  version LONG VARCHAR,\
       
    64  server_uri LONG VARCHAR,\
       
    65  item_type INTEGER, \
       
    66  total_content_size INTEGER, \
       
    67  origin_node_id LONG VARCHAR, \
       
    68  last_operation_time BIGINT, \
       
    69  last_operation_error_code INTEGER, \
       
    70  has_icon INTEGER, \
       
    71  attributes LONG VARBINARY )" );
       
    72 
       
    73 
       
    74 // Create a event counter table.
       
    75 _LIT( KSqlCreateEventCounterTable,
       
    76     "CREATE TABLE event_counter_table ( event_counter UNSIGNED INTEGER )" );
       
    77 
       
    78 // Event counter column number.
       
    79 const TInt KEventCounterColumnNumber = 1;
       
    80 
       
    81 
       
    82 // Select purchases.
       
    83 _LIT( KSqlPurchasesStart,
       
    84      "SELECT purchase_id FROM purchases WHERE event_id >= " );
       
    85 _LIT( KSqlPurchasesNamespace, " AND namespace = '" );
       
    86 _LIT( KSqlPurchasesEntityId, " AND entity_id = '" );
       
    87 _LIT( KSqlPurchasesClientUid, " AND ( client_uid = " );
       
    88 _LIT( KSqlPurchasesOrClientUid, " OR client_uid = " );
       
    89 _LIT( KSqlPurchasesEndClientUid, " )" );
       
    90 _LIT( KSqlPurchasesEnd, "'" );
       
    91 _LIT( KSqlPurchasesOrderNewestFirst, " ORDER BY event_id DESC" );
       
    92 _LIT( KSqlPurchasesOrderOldestFirst, " ORDER BY event_id ASC" );
       
    93 
       
    94 // Select purchase to be updated.
       
    95 _LIT( KSqlPurchaseUpdateStart,
       
    96      "SELECT * FROM purchases WHERE client_uid = " );
       
    97 _LIT( KSqlPurchasesUpdateNamespace, " AND namespace = '" );
       
    98 _LIT( KSqlPurchasesUpdateEntityId, "' AND entity_id = '" );
       
    99 _LIT( KSqlPurchasesUpdatePurchaseTime, "' AND purchase_time = " );
       
   100 _LIT( KSqlPurchasesUpdateEnd, "" );
       
   101 
       
   102 // Select purchase.
       
   103 _LIT( KSqlPurchaseByPurchaseIdStart,
       
   104     "SELECT * FROM purchases WHERE purchase_id = " );
       
   105 _LIT( KSqlPurchaseByPurchaseIdEnd, "" );
       
   106 
       
   107 // Select all purchases.
       
   108 _LIT( KSqlPurchasesAllNone, "SELECT * FROM purchases" );
       
   109 
       
   110 // Delete specified purchase event.
       
   111 _LIT( KSqlPurchasesDeleteStart,
       
   112     "DELETE FROM purchases WHERE purchase_id = " );
       
   113 _LIT( KSqlPurchasesDeleteEnd,   "" );
       
   114 
       
   115 
       
   116 // Select current event count.
       
   117 _LIT( KSqlCurrentEventCount,
       
   118     "SELECT event_counter FROM event_counter_table" );
       
   119 
       
   120 // Delete event count from event count table.
       
   121 _LIT( KSqlEventCountDelete, "DELETE FROM event_counter_table" );
       
   122 
       
   123 // "-2147483648"
       
   124 const TInt KMaxLengthOfInt = 11;
       
   125 
       
   126 // "-9223372036854775808"
       
   127 const TInt KMaxLengthOfTint64 = 20;
       
   128 
       
   129 static void AppendWithQuotesDuplicatedL(
       
   130     CCatalogsBigDes* aOutput,
       
   131     const TDesC& aInput )
       
   132     {
       
   133     _LIT( KQuote, "'" );
       
   134     
       
   135     if ( aOutput == NULL || &aInput == NULL )
       
   136         {
       
   137         return;
       
   138         }
       
   139 
       
   140     TPtrC in = aInput.Mid( 0 );
       
   141     while ( in.Length() > 0 )
       
   142         {
       
   143         TInt i = in.Locate( '\'' );
       
   144         if ( i == KErrNotFound )
       
   145             {
       
   146             // Quote not found, all done
       
   147             aOutput->AppendL( in );
       
   148             return;
       
   149             }
       
   150         aOutput->AppendL( in.Mid( 0, i + 1 ) );
       
   151         // Append extra quote
       
   152         aOutput->AppendL( KQuote );
       
   153         if ( i + 1 < in.Length() )
       
   154             {
       
   155             // Get end part of the input descriptor
       
   156             in.Set( in.Mid( i + 1 ) );
       
   157             }
       
   158         else
       
   159             {
       
   160             // End of the input descriptor reached
       
   161             return;
       
   162             }
       
   163         
       
   164         }
       
   165     }
       
   166 
       
   167 static HBufC* ReadLongTextColumnL( RDbRowSet aView, TDbColNo aCol )
       
   168     {
       
   169     TInt length = aView.ColLength( aCol );
       
   170     if ( length == 0 )
       
   171         {
       
   172         return KNullDesC().Alloc();
       
   173         }
       
   174     RDbColReadStream readStream;
       
   175     readStream.OpenLC( aView, aCol );
       
   176     HBufC* result = HBufC::NewLC( length );
       
   177     TPtr resultPtr = result->Des();
       
   178     readStream.ReadL( resultPtr, length );
       
   179     readStream.Close();
       
   180     CleanupStack::Pop( result );
       
   181     CleanupStack::Pop(); //readStream
       
   182     return result;
       
   183     }
       
   184 
       
   185 static void WriteLongTextColumnL(
       
   186     RDbRowSet aView,
       
   187     TDbColNo aCol,
       
   188     const TDesC& aValue )
       
   189     {
       
   190     RDbColWriteStream writeStream;
       
   191     writeStream.OpenLC( aView, aCol );
       
   192     if ( &aValue )
       
   193         {
       
   194         writeStream.WriteL( aValue );
       
   195         }
       
   196     else
       
   197         {
       
   198         writeStream.WriteL( KNullDesC );
       
   199         }
       
   200     writeStream.Close();
       
   201     CleanupStack::Pop( &writeStream );
       
   202     }
       
   203 
       
   204 static HBufC8* ReadLongTextColumn8L( RDbRowSet aView, TDbColNo aCol )
       
   205     {
       
   206     TInt length = aView.ColLength( aCol );
       
   207     if ( length == 0 )
       
   208         {
       
   209         return KNullDesC8().Alloc();
       
   210         }
       
   211     RDbColReadStream readStream;
       
   212     readStream.OpenLC( aView, aCol );
       
   213     HBufC8* result = HBufC8::NewLC( length );
       
   214     TPtr8 resultPtr = result->Des();
       
   215     readStream.ReadL( resultPtr, length );
       
   216     readStream.Close();
       
   217     CleanupStack::Pop( result );
       
   218     CleanupStack::Pop(); //readStream
       
   219     return result;
       
   220     }
       
   221 
       
   222 static void WriteLongTextColumn8L(
       
   223     RDbRowSet aView,
       
   224     TDbColNo aCol,
       
   225     const TDesC8& aValue )
       
   226     {
       
   227     RDbColWriteStream writeStream;
       
   228     writeStream.OpenLC( aView, aCol );
       
   229     if ( &aValue )
       
   230         {
       
   231         writeStream.WriteL( aValue );
       
   232         }
       
   233     else
       
   234         {
       
   235         writeStream.WriteL( KNullDesC8 );
       
   236         }
       
   237     writeStream.Close();
       
   238     CleanupStack::Pop( &writeStream );
       
   239     }
       
   240 
       
   241 
       
   242 CNcdPurchaseHistoryDb* CNcdPurchaseHistoryDb::NewL(
       
   243     const TDesC& aDbFilename )
       
   244     {
       
   245     CNcdPurchaseHistoryDb* self = NewLC( aDbFilename );
       
   246     CleanupStack::Pop( self );
       
   247     return self;
       
   248     }
       
   249 
       
   250 CNcdPurchaseHistoryDb* CNcdPurchaseHistoryDb::NewLC(
       
   251     const TDesC& aDbFilename )
       
   252     {
       
   253     CNcdPurchaseHistoryDb* self =
       
   254         new ( ELeave ) CNcdPurchaseHistoryDb();
       
   255     CleanupClosePushL( *self );
       
   256     self->ConstructL( aDbFilename );
       
   257     return self;    
       
   258     }
       
   259 
       
   260 CNcdPurchaseHistoryDb::~CNcdPurchaseHistoryDb()
       
   261     {
       
   262     iDatabase.Close();
       
   263     delete iDbFilename;
       
   264     iFs.Close();
       
   265     }
       
   266 
       
   267 void CNcdPurchaseHistoryDb::ReceiveMessage(
       
   268     MCatalogsBaseMessage* aMessage,
       
   269     TInt aFunctionNumber )
       
   270     {
       
   271     DLTRACEIN((""));
       
   272 
       
   273     DASSERT( aMessage );
       
   274     
       
   275     // Now, we can be sure that rest of the time iMessage exists.
       
   276     // This member variable is set for the CounterPartLost function.
       
   277     iMessage = aMessage;
       
   278         
       
   279     TInt trapError( KErrNone );
       
   280         
       
   281     switch( aFunctionNumber )
       
   282         {
       
   283         case NcdNodeFunctionIds::ENcdPurchaseHistorySavePurchase:
       
   284             DLTRACE(("Insert purchase event"));
       
   285             TRAP( trapError, SavePurchaseRequestL( *aMessage ) );
       
   286             break;
       
   287 
       
   288         case NcdNodeFunctionIds::ENcdPurchaseHistorySavePurchaseWithOldIcon:
       
   289             DLTRACE(("Insert purchase event with old icon"));
       
   290             TRAP( trapError, SavePurchaseRequestL( *aMessage, EFalse ) );
       
   291             break;
       
   292             
       
   293         case NcdNodeFunctionIds::ENcdPurchaseHistoryRemovePurchase:
       
   294             DLTRACE(("Remove purchase"));
       
   295             TRAP( trapError, RemovePurchaseRequestL( *aMessage ) );
       
   296             break;
       
   297             
       
   298         case NcdNodeFunctionIds::ENcdPurchaseHistoryGetPurchaseIds:
       
   299             DLTRACE(("Get purchase IDs"));
       
   300             TRAP( trapError, GetPurchaseIdsRequestL( *aMessage ) );
       
   301             break;
       
   302             
       
   303         case NcdNodeFunctionIds::ENcdPurchaseHistoryGetPurchase:
       
   304             DLTRACE(("Get purchase"));
       
   305             TRAP( trapError, GetPurchaseRequestL( *aMessage, ETrue ) );
       
   306             break;
       
   307             
       
   308         case NcdNodeFunctionIds::ENcdPurchaseHistoryGetPurchaseNoIcon:
       
   309             DLTRACE(("Get purchase"));
       
   310             TRAP( trapError, GetPurchaseRequestL( *aMessage, EFalse ) );
       
   311             break;
       
   312             
       
   313         case NcdNodeFunctionIds::ENcdPurchaseHistoryEventCount:
       
   314             DLTRACE(("Get purchase event count"));
       
   315             TRAP( trapError, EventCountRequestL( *aMessage ) );
       
   316             break;
       
   317             
       
   318         case NcdNodeFunctionIds::ENcdRelease:
       
   319             DLTRACE(("Release purchase history"));
       
   320             ReleaseRequest( *aMessage );
       
   321             break;
       
   322             
       
   323         default:
       
   324             break;
       
   325         }
       
   326 
       
   327     if ( trapError != KErrNone )
       
   328         {
       
   329         // Because something went wrong the complete has not been
       
   330         // yet called for the message.
       
   331         // So, inform the client about the error.
       
   332         DLTRACE(("ERROR, Complete and release %d", trapError));
       
   333         
       
   334         aMessage->CompleteAndRelease( trapError );
       
   335         }
       
   336 
       
   337     // Because the message should not be used after this, set it NULL.
       
   338     // So, CounterPartLost function will know that no messages are
       
   339     // waiting the response at the moment.
       
   340     iMessage = NULL;        
       
   341             
       
   342     DLTRACEOUT((""));
       
   343     }
       
   344 
       
   345 void CNcdPurchaseHistoryDb::CounterPartLost(
       
   346     const MCatalogsSession& aSession )
       
   347     {
       
   348     // This function may be called whenever -- when the message is waiting
       
   349     // response or when the message does not exist.
       
   350     // iMessage may be NULL here, because in the end of the
       
   351     // ReceiveMessage it is set to NULL. The life time of the message
       
   352     // ends shortly after CompleteAndRelease is called.
       
   353     if ( iMessage != NULL )
       
   354         {
       
   355         iMessage->CounterPartLost( aSession );
       
   356         }    
       
   357     }
       
   358 
       
   359 void CNcdPurchaseHistoryDb::ConstructL( const TDesC& aDbFilename )
       
   360     {
       
   361     if ( aDbFilename == KNullDesC )
       
   362         {
       
   363         User::Leave( KErrBadName );
       
   364         }
       
   365         
       
   366     User::LeaveIfError( iFs.Connect() );
       
   367 
       
   368     // Set database name.
       
   369     iDbFilename = aDbFilename.AllocL();
       
   370     BaflUtils::EnsurePathExistsL( iFs, *iDbFilename );
       
   371     TInt err = iDatabase.Open( iFs, *iDbFilename );
       
   372 
       
   373     if ( err == KErrNotFound || err == KErrCorrupt )
       
   374         {
       
   375         // Delete existing database file. This should happen only if
       
   376         // database file is corrupted. Ignoring errors as database file
       
   377         // may not be present.
       
   378         BaflUtils::DeleteFile( iFs, *iDbFilename );
       
   379 
       
   380         // See if the database can be found from another drive
       
   381         TFindFile finder( iFs );
       
   382         CDir* dir = NULL;
       
   383 
       
   384         err = finder.FindWildByDir( *iDbFilename, KNullDesC, dir );
       
   385 
       
   386         if ( err == KErrNone )
       
   387             {
       
   388             // Move old database to correct folder and try to open it
       
   389             CleanupStack::PushL( dir );
       
   390             CFileMan* fileman = CFileMan::NewL( iFs );
       
   391             CleanupStack::PushL( fileman );
       
   392             User::LeaveIfError( fileman->Move( finder.File(),
       
   393                                                *iDbFilename,
       
   394                                                CFileMan::EOverWrite ) );
       
   395             CleanupStack::PopAndDestroy( fileman );
       
   396             CleanupStack::PopAndDestroy( dir );
       
   397 
       
   398             // NOTE: Error ignored. If folder contains files,
       
   399             // it will not be deleted.
       
   400             iFs.RmDir( finder.File() );
       
   401 
       
   402             err = iDatabase.Open( iFs, *iDbFilename );
       
   403             if ( err == KErrNotFound || err == KErrCorrupt )
       
   404                 {
       
   405                 BaflUtils::DeleteFile( iFs, *iDbFilename );
       
   406                 // Trying to create the database
       
   407                 User::LeaveIfError( iDatabase.Create( iFs, *iDbFilename ) );
       
   408                 User::LeaveIfError(
       
   409                     iDatabase.Execute( KSqlCreatePurchasesTable ) );
       
   410                 User::LeaveIfError(
       
   411                     iDatabase.Execute( KSqlCreateEventCounterTable ) );
       
   412                 }
       
   413             else if ( err != KErrNone )
       
   414                 {
       
   415                 User::Leave( err );
       
   416                 }
       
   417             }
       
   418         else
       
   419             {
       
   420             // Trying to create the database
       
   421             User::LeaveIfError( iDatabase.Create( iFs, *iDbFilename ) );
       
   422             User::LeaveIfError(
       
   423                 iDatabase.Execute( KSqlCreatePurchasesTable ) );
       
   424             User::LeaveIfError(
       
   425                 iDatabase.Execute( KSqlCreateEventCounterTable ) );
       
   426             }
       
   427         }
       
   428     else if ( err != KErrNone )
       
   429         {
       
   430         User::Leave( err );
       
   431         }
       
   432 
       
   433     if ( iDatabase.IsDamaged() )
       
   434         {
       
   435         // Database has been partly damaged. Try to recover it.
       
   436         iDatabase.Recover();
       
   437         }
       
   438     }
       
   439 
       
   440 CNcdPurchaseHistoryDb::CNcdPurchaseHistoryDb()
       
   441     : CCatalogsCommunicable()
       
   442     {    
       
   443     }
       
   444 
       
   445 void CNcdPurchaseHistoryDb::SavePurchaseL(
       
   446     CNcdPurchaseDetails& aPurchase, 
       
   447     TBool aSaveIcon )
       
   448     {
       
   449     DLTRACEIN((""));
       
   450     // Ensure that purchase history handling bugs in PCD! don't crash the client :)
       
   451     ValidatePurchaseDetailsL( aPurchase );
       
   452     
       
   453     CCatalogsBigDes* sqlStatement = CCatalogsBigDes::NewLC();
       
   454     
       
   455     sqlStatement->AppendL( KSqlPurchaseUpdateStart );
       
   456     TBuf<KMaxLengthOfInt> intBuf;
       
   457     intBuf.Num( aPurchase.ClientUid().iUid );
       
   458     sqlStatement->AppendL( intBuf );
       
   459     sqlStatement->AppendL( KSqlPurchasesUpdateNamespace );
       
   460     AppendWithQuotesDuplicatedL( sqlStatement, aPurchase.Namespace() );
       
   461     sqlStatement->AppendL( KSqlPurchasesUpdateEntityId );
       
   462     AppendWithQuotesDuplicatedL( sqlStatement, aPurchase.EntityId() );
       
   463     sqlStatement->AppendL( KSqlPurchasesUpdatePurchaseTime );
       
   464     TBuf<KMaxLengthOfTint64> bigIntBuf;
       
   465     bigIntBuf.Num( aPurchase.PurchaseTime().Int64() );
       
   466     sqlStatement->AppendL( bigIntBuf );
       
   467     sqlStatement->AppendL( KSqlPurchasesUpdateEnd );
       
   468     
       
   469     TUint newEventCount = EventCountL() + 1;
       
   470 
       
   471     RDbView view;
       
   472     CleanupClosePushL( view );
       
   473 
       
   474     HBufC* sqlStatementBuf = sqlStatement->DesLC();
       
   475     User::LeaveIfError(
       
   476         view.Prepare( iDatabase, TDbQuery( *sqlStatementBuf ) ) );
       
   477     CleanupStack::PopAndDestroy( sqlStatementBuf );
       
   478 
       
   479     User::LeaveIfError( view.EvaluateAll() );
       
   480     view.FirstL();
       
   481 
       
   482     if ( view.AtRow() )
       
   483         {
       
   484         UpdatePurchaseL( view, aPurchase, newEventCount, aSaveIcon );
       
   485         }
       
   486     else
       
   487         {
       
   488         view.Close();
       
   489         NewPurchaseL( aPurchase, newEventCount );
       
   490         }
       
   491         
       
   492     // Set new purchase count
       
   493     SetEventCountL( newEventCount );
       
   494 
       
   495     CleanupStack::PopAndDestroy( &view );
       
   496     CleanupStack::PopAndDestroy( sqlStatement );
       
   497     DLTRACEOUT((""));
       
   498     }
       
   499 
       
   500 void CNcdPurchaseHistoryDb::RemovePurchaseL( TUint aPurchaseId )
       
   501     {
       
   502     if ( ! PurchaseExistsL( aPurchaseId ) )
       
   503         {
       
   504         // Purchase didn't exist in the database.
       
   505         User::Leave( KErrNotFound );
       
   506         }
       
   507 
       
   508     TInt maxLength = KSqlPurchasesDeleteStart().Length() + KMaxLengthOfInt
       
   509         + KSqlPurchasesDeleteEnd().Length();
       
   510 
       
   511     HBufC* sqlStatement = HBufC::NewLC( maxLength );
       
   512     TPtr statementPtr( sqlStatement->Des() );
       
   513 
       
   514     statementPtr.Copy( KSqlPurchasesDeleteStart );
       
   515     statementPtr.AppendNum( aPurchaseId );
       
   516     statementPtr.Append( KSqlPurchasesDeleteEnd );
       
   517 
       
   518     // Remove purchase from the database using event ID.
       
   519     User::LeaveIfError( iDatabase.Execute( *sqlStatement ) );
       
   520     // Remove all unnecessary data from the database.
       
   521     User::LeaveIfError( iDatabase.Compact() );
       
   522 
       
   523     CleanupStack::PopAndDestroy( sqlStatement );
       
   524     }
       
   525 
       
   526 RArray<TUint> CNcdPurchaseHistoryDb::PurchaseIdsL(
       
   527     const CNcdPurchaseHistoryFilter& aFilter,
       
   528     const TSortingOrder aSortingOrder )
       
   529     {
       
   530     CCatalogsBigDes* sqlStatement = CCatalogsBigDes::NewLC();
       
   531 
       
   532     // Construct the SQL query.
       
   533     sqlStatement->AppendL( KSqlPurchasesStart );
       
   534     TBuf<KMaxLengthOfInt> eventId;
       
   535     eventId.Num( aFilter.EventId() );
       
   536     sqlStatement->AppendL( eventId );
       
   537     
       
   538     if ( aFilter.Namespace().Compare( KNullDesC ) != 0 )
       
   539         {
       
   540         sqlStatement->AppendL( KSqlPurchasesNamespace );
       
   541         AppendWithQuotesDuplicatedL( sqlStatement, aFilter.Namespace() );
       
   542         sqlStatement->AppendL( KSqlPurchasesEnd );
       
   543         }
       
   544         
       
   545     if ( aFilter.EntityId().Compare( KNullDesC ) != 0 )
       
   546         {
       
   547         sqlStatement->AppendL( KSqlPurchasesEntityId );
       
   548         AppendWithQuotesDuplicatedL( sqlStatement, aFilter.EntityId() );
       
   549         sqlStatement->AppendL( KSqlPurchasesEnd );
       
   550         }
       
   551     
       
   552     if ( aFilter.ClientUids().Count() > 0 )
       
   553         {
       
   554         TArray< TUid > uids = aFilter.ClientUids();
       
   555         TInt count = uids.Count();
       
   556         sqlStatement->AppendL( KSqlPurchasesClientUid );
       
   557         for ( TInt i = 0; i < count; i++ )
       
   558             {
       
   559             TBuf<KMaxLengthOfInt> clientUid;
       
   560             clientUid.Num( uids[i].iUid );
       
   561             sqlStatement->AppendL( clientUid );
       
   562             if ( i + 1 < count )
       
   563                 {
       
   564                 // More UIDs in the filter.
       
   565                 sqlStatement->AppendL( KSqlPurchasesOrClientUid );
       
   566                 }
       
   567             }
       
   568         sqlStatement->AppendL( KSqlPurchasesEndClientUid );
       
   569         }
       
   570 
       
   571     switch ( aSortingOrder )
       
   572         {
       
   573         case CNcdPurchaseHistoryDb::ENewestFirst:
       
   574             sqlStatement->AppendL( KSqlPurchasesOrderNewestFirst );
       
   575             break;
       
   576         case CNcdPurchaseHistoryDb::EOldestFirst:
       
   577             sqlStatement->AppendL( KSqlPurchasesOrderOldestFirst );
       
   578             break;
       
   579         case CNcdPurchaseHistoryDb::ENone:
       
   580         default:
       
   581             break;
       
   582         }
       
   583 
       
   584     RDbView view;
       
   585     CleanupClosePushL( view );
       
   586 
       
   587     HBufC* sqlStatementBuf = sqlStatement->DesLC();
       
   588     User::LeaveIfError(
       
   589         view.Prepare( iDatabase, TDbQuery( *sqlStatementBuf ) ) );
       
   590     CleanupStack::PopAndDestroy( sqlStatementBuf );
       
   591 
       
   592     User::LeaveIfError( view.EvaluateAll() );
       
   593     view.FirstL();
       
   594 
       
   595     RArray<TUint> purchaseIds;
       
   596     CleanupClosePushL( purchaseIds );
       
   597 
       
   598     while( view.AtRow() )
       
   599         {
       
   600         view.GetL();
       
   601         purchaseIds.Append(
       
   602             view.ColUint32( CNcdPurchaseHistoryDb::EPurchaseId ) );
       
   603         view.NextL();
       
   604         }
       
   605 
       
   606     CleanupStack::Pop( &purchaseIds );
       
   607     CleanupStack::PopAndDestroy( &view );
       
   608     CleanupStack::PopAndDestroy( sqlStatement );
       
   609     
       
   610     return purchaseIds;
       
   611     }
       
   612 
       
   613 CNcdPurchaseDetails* CNcdPurchaseHistoryDb::PurchaseL( 
       
   614     TUint aPurchaseId,
       
   615     TBool aLoadIcon )
       
   616     {
       
   617     TInt maxLength = KSqlPurchaseByPurchaseIdStart().Length()
       
   618         + KMaxLengthOfInt
       
   619         + KSqlPurchaseByPurchaseIdEnd().Length();
       
   620 
       
   621     HBufC* sqlStatement = HBufC::NewLC( maxLength );
       
   622     TPtr statementPtr( sqlStatement->Des() );
       
   623 
       
   624     statementPtr.Copy( KSqlPurchaseByPurchaseIdStart );
       
   625     statementPtr.AppendNum( aPurchaseId );
       
   626     statementPtr.Append( KSqlPurchaseByPurchaseIdEnd );
       
   627 
       
   628     RDbView view;
       
   629     CleanupClosePushL( view );
       
   630 
       
   631     User::LeaveIfError(
       
   632         view.Prepare( iDatabase, TDbQuery( *sqlStatement ) ) );
       
   633 
       
   634     User::LeaveIfError( view.EvaluateAll() );
       
   635     view.FirstL();
       
   636 
       
   637     CNcdPurchaseDetails* details = NULL;
       
   638 
       
   639     if ( view.AtRow() )
       
   640         {
       
   641         view.GetL();
       
   642         
       
   643         details = CNcdPurchaseDetails::NewLC();
       
   644         
       
   645         details->SetClientUid( TUid::Uid( view.ColInt32( EClientUid ) ) );
       
   646         details->SetNamespace( ReadLongTextColumnL( view, ENamespace ) );
       
   647         details->SetEntityId( ReadLongTextColumnL( view, EEntityId ) );
       
   648         details->SetItemName( ReadLongTextColumnL( view, EItemName ) );
       
   649         details->SetItemPurpose( view.ColUint32( EItemPurpose ) );
       
   650         details->SetCatalogSourceName(
       
   651             ReadLongTextColumnL( view, ECatalogName ) );
       
   652 
       
   653         // Get download info buffer from database
       
   654         HBufC8* downloadBuf = ReadLongTextColumn8L( view, EDownloadInfo );
       
   655         CleanupStack::PushL( downloadBuf );
       
   656 
       
   657         if ( downloadBuf->Length() > 0 )
       
   658             {
       
   659             // There is some data.
       
   660             RDesReadStream readStream( *downloadBuf );
       
   661             CleanupClosePushL( readStream );
       
   662 
       
   663             // Get count of download infos.
       
   664             TInt count = readStream.ReadInt32L();
       
   665             for ( TInt i = 0; i < count; i++ )
       
   666                 {
       
   667                 // Internalize download infos from the buffer.
       
   668 
       
   669                 CNcdPurchaseDownloadInfo* info =
       
   670                     CNcdPurchaseDownloadInfo::NewLC();
       
   671 
       
   672                 info->InternalizeL( readStream );
       
   673                 details->AddDownloadInfoL( info );
       
   674 
       
   675                 CleanupStack::Pop( info );
       
   676                 }
       
   677 
       
   678             CleanupStack::PopAndDestroy( &readStream );
       
   679             }
       
   680 
       
   681         CleanupStack::PopAndDestroy( downloadBuf );
       
   682 
       
   683         details->SetPurchaseOptionId(
       
   684             ReadLongTextColumnL( view, EPurchaseOptionId ) );
       
   685         details->SetPurchaseOptionName(
       
   686             ReadLongTextColumnL( view, EPurchaseOptionName ) );
       
   687         details->SetPurchaseOptionPrice(
       
   688             ReadLongTextColumnL( view, EPurchaseOptionPrice ) );
       
   689         details->SetFinalPrice( ReadLongTextColumnL( view, EFinalPrice ) );
       
   690         details->SetPaymentMethodName(
       
   691             ReadLongTextColumnL( view, EPaymentMethodName ) );
       
   692         details->SetPurchaseTime( view.ColInt64( EPurchaseTime ) );
       
   693 
       
   694         HBufC8* filesBuf = ReadLongTextColumn8L( view, EDownloadedFiles );
       
   695         CleanupStack::PushL( filesBuf );
       
   696         CDesCArray* downloadedFiles =
       
   697             new (ELeave) CDesCArrayFlat( KListGranularity );
       
   698         CleanupStack::PushL( downloadedFiles );
       
   699         
       
   700         if ( filesBuf->Length() > 0 )
       
   701             {
       
   702             // There is some data.
       
   703             RDesReadStream readStream( *filesBuf );
       
   704             CleanupClosePushL( readStream );
       
   705 
       
   706             TInt filesCount = readStream.ReadInt32L();
       
   707             for ( TInt i = 0; i < filesCount; i++ )
       
   708                 {
       
   709                 HBufC* buf = NULL;
       
   710                 InternalizeDesL( buf, readStream );
       
   711                 CleanupStack::PushL( buf );
       
   712                 downloadedFiles->AppendL( *buf );
       
   713                 CleanupStack::PopAndDestroy( buf );
       
   714                 }
       
   715 
       
   716             CleanupStack::PopAndDestroy( &readStream );
       
   717             }
       
   718 
       
   719         details->SetDownloadedFiles( downloadedFiles );
       
   720         CleanupStack::Pop( downloadedFiles );
       
   721         CleanupStack::PopAndDestroy( filesBuf );
       
   722         
       
   723         // Get install info buffer from database
       
   724         HBufC8* installBuf = ReadLongTextColumn8L( view, EFileInstallInfos );
       
   725         CleanupStack::PushL( installBuf );
       
   726 
       
   727         if ( installBuf->Length() > 0 )
       
   728             {
       
   729             // There is some data.
       
   730             RDesReadStream readStream( *installBuf );
       
   731             CleanupClosePushL( readStream );
       
   732 
       
   733             // Get count of install infos.
       
   734             TInt count = readStream.ReadInt32L();
       
   735             for ( TInt i = 0; i < count; i++ )
       
   736                 {
       
   737                 // Internalize install infos from the buffer.
       
   738 
       
   739                 CNcdPurchaseInstallInfo* info =
       
   740                     CNcdPurchaseInstallInfo::NewLC();
       
   741 
       
   742                 info->InternalizeL( readStream );
       
   743                 details->AddInstallInfoL( info );
       
   744 
       
   745                 CleanupStack::Pop( info );
       
   746                 }
       
   747 
       
   748             CleanupStack::PopAndDestroy( &readStream );
       
   749             }
       
   750 
       
   751         CleanupStack::PopAndDestroy( installBuf );
       
   752         
       
   753         if ( aLoadIcon ) 
       
   754             {
       
   755             DLTRACE(("Loading icon from the purchase history"));            
       
   756             details->SetIcon( ReadLongTextColumn8L( view, EIcon ) );
       
   757             }
       
   758         details->SetDownloadAccessPoint( ReadLongTextColumnL( view, EDownloadAccessPoint ) );
       
   759         details->SetDescription( ReadLongTextColumnL( view, EDescription ) );
       
   760         details->SetVersion( ReadLongTextColumnL( view, EVersion ) );
       
   761         details->SetServerUri( ReadLongTextColumnL( view, EServerUri ) );
       
   762         details->SetItemType( (MNcdPurchaseDetails::TItemType)view.ColInt32( EItemType ) );
       
   763         details->SetTotalContentSize( view.ColInt32( ETotalContentSize ) );
       
   764         details->SetOriginNodeId( ReadLongTextColumnL( view, EOriginNodeId ) );
       
   765         details->SetLastOperationTime( view.ColInt64( ELastOperationTime ) );
       
   766         details->SetLastOperationErrorCode( view.ColInt32( ELastOperationErrorCode ) );
       
   767         details->SetHasIcon( view.ColInt32( EHasIcon ) );
       
   768         
       
   769         // Get attributes buffer from database
       
   770         HBufC8* attributesBuf = ReadLongTextColumn8L( view, EAttributes );
       
   771         CleanupStack::PushL( attributesBuf );
       
   772 
       
   773         if ( attributesBuf->Length() > 0 )
       
   774             {
       
   775             // There is some data.
       
   776             RDesReadStream readStream( *attributesBuf );
       
   777             CleanupClosePushL( readStream );
       
   778             details->InternalizeAttributesL( readStream );
       
   779             CleanupStack::PopAndDestroy( &readStream );
       
   780             }
       
   781 
       
   782         CleanupStack::PopAndDestroy( attributesBuf );
       
   783         }
       
   784 
       
   785     if ( ! details )
       
   786         {
       
   787         User::Leave( KErrNotFound );
       
   788         }
       
   789 
       
   790     // Ensure that purchase history handling bugs in PCD! don't crash the client :)
       
   791     ValidatePurchaseDetailsL( *details );
       
   792     
       
   793     CleanupStack::Pop( details );
       
   794     CleanupStack::PopAndDestroy( &view );
       
   795     CleanupStack::PopAndDestroy( sqlStatement );
       
   796     
       
   797     return details;
       
   798     }
       
   799 
       
   800 TUint CNcdPurchaseHistoryDb::EventCountL()
       
   801     {
       
   802     TUint eventCount = 0;
       
   803 
       
   804     RDbView view;
       
   805     CleanupClosePushL( view );
       
   806 
       
   807     User::LeaveIfError( view.Prepare(
       
   808         iDatabase,
       
   809         TDbQuery( KSqlCurrentEventCount ),
       
   810         RDbView::EReadOnly ) );
       
   811 
       
   812     view.EvaluateAll();
       
   813     view.FirstL();
       
   814 
       
   815     if ( view.AtRow() )
       
   816         {
       
   817         view.GetL();
       
   818         eventCount = view.ColUint32( KEventCounterColumnNumber );
       
   819         }
       
   820 
       
   821     CleanupStack::PopAndDestroy( &view );
       
   822     
       
   823     return eventCount;
       
   824     }
       
   825 
       
   826 void CNcdPurchaseHistoryDb::SavePurchaseRequestL( MCatalogsBaseMessage& aMessage, 
       
   827                                                   TBool aSaveIcon )
       
   828     {
       
   829     TInt inputLength = aMessage.InputLength();
       
   830     User::LeaveIfError( inputLength );
       
   831     
       
   832     HBufC8* message = HBufC8::NewLC( inputLength );
       
   833     TPtr8 ptr = message->Des();
       
   834     User::LeaveIfError( aMessage.ReadInput( ptr ) );
       
   835     
       
   836     CNcdPurchaseDetails* details = CNcdPurchaseDetails::NewLC();
       
   837     
       
   838     RDesReadStream stream( *message );
       
   839     CleanupClosePushL( stream );
       
   840     
       
   841     details->InternalizeL( stream );
       
   842     
       
   843     CleanupStack::PopAndDestroy( &stream );
       
   844     
       
   845     SavePurchaseL( *details, aSaveIcon );
       
   846     
       
   847     CleanupStack::PopAndDestroy( details );
       
   848     CleanupStack::PopAndDestroy( message );
       
   849     
       
   850     aMessage.CompleteAndRelease( KErrNone );
       
   851     }
       
   852 
       
   853 void CNcdPurchaseHistoryDb::RemovePurchaseRequestL( MCatalogsBaseMessage& aMessage )
       
   854     {
       
   855     TInt inputLength = aMessage.InputLength();
       
   856     User::LeaveIfError( inputLength );
       
   857     
       
   858     HBufC8* message = HBufC8::NewLC( inputLength );
       
   859     TPtr8 ptr = message->Des();
       
   860     User::LeaveIfError( aMessage.ReadInput( ptr ) );
       
   861     
       
   862     TUint purchaseId = Des8ToUint( *message );
       
   863     
       
   864     CleanupStack::PopAndDestroy( message );
       
   865     
       
   866     RemovePurchaseL( purchaseId );
       
   867     
       
   868     aMessage.CompleteAndRelease( KErrNone );
       
   869     }
       
   870 
       
   871 void CNcdPurchaseHistoryDb::GetPurchaseIdsRequestL( MCatalogsBaseMessage& aMessage )
       
   872     {
       
   873     TInt inputLength = aMessage.InputLength();
       
   874     User::LeaveIfError( inputLength );
       
   875     
       
   876     HBufC8* message = HBufC8::NewLC( inputLength );
       
   877     TPtr8 ptr = message->Des();
       
   878     User::LeaveIfError( aMessage.ReadInput( ptr ) );
       
   879     
       
   880     CNcdPurchaseHistoryFilter* filter = CNcdPurchaseHistoryFilter::NewLC();
       
   881     
       
   882     RDesReadStream stream( *message );
       
   883     CleanupClosePushL( stream );
       
   884 
       
   885     filter->InternalizeL( stream );
       
   886     
       
   887     CleanupStack::PopAndDestroy( &stream );
       
   888     
       
   889     RArray<TUint> purchaseIds = PurchaseIdsL( *filter, ENewestFirst );
       
   890     
       
   891     CleanupStack::PopAndDestroy( filter );
       
   892     CleanupStack::PopAndDestroy( message );
       
   893     
       
   894     CleanupClosePushL( purchaseIds );
       
   895 
       
   896     TUint count = purchaseIds.Count();
       
   897 
       
   898     message = HBufC8::NewLC( ( count + 1 ) * sizeof(TUint) );
       
   899     
       
   900     HBufC8* temp = UintToDes8LC( count );
       
   901     message->Des().Copy( *temp );
       
   902     CleanupStack::PopAndDestroy( temp );
       
   903     
       
   904     for ( TInt i = 0; i < count; i++ )
       
   905         {
       
   906         temp = UintToDes8LC( purchaseIds[i] );
       
   907         message->Des().Append( *temp );
       
   908         CleanupStack::PopAndDestroy( temp );
       
   909         }
       
   910 
       
   911     aMessage.CompleteAndReleaseL( *message, KErrNone );
       
   912     
       
   913     CleanupStack::PopAndDestroy( message );
       
   914     
       
   915     CleanupStack::PopAndDestroy( &purchaseIds );
       
   916     }
       
   917 
       
   918 void CNcdPurchaseHistoryDb::GetPurchaseRequestL( 
       
   919     MCatalogsBaseMessage& aMessage,
       
   920     TBool aLoadIcon )
       
   921     {
       
   922     DLTRACEIN(("aLoadIcon: %d", aLoadIcon));
       
   923     TInt inputLength = aMessage.InputLength();
       
   924     User::LeaveIfError( inputLength );
       
   925     
       
   926     HBufC8* message = HBufC8::NewLC( inputLength );
       
   927     TPtr8 ptr = message->Des();
       
   928     User::LeaveIfError( aMessage.ReadInput( ptr ) );
       
   929 
       
   930     TUint purchaseId = Des8ToUint( *message );
       
   931 
       
   932     CleanupStack::PopAndDestroy( message );
       
   933 
       
   934     CNcdPurchaseDetails* details = PurchaseL( purchaseId, aLoadIcon );
       
   935     if ( details )
       
   936         {
       
   937         CleanupStack::PushL( details );
       
   938         
       
   939         CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
       
   940         CleanupStack::PushL( buf );
       
   941         
       
   942         RBufWriteStream stream( *buf );
       
   943         CleanupClosePushL( stream );
       
   944         
       
   945         details->ExternalizeL( stream );
       
   946         
       
   947         CleanupStack::PopAndDestroy( &stream );
       
   948 
       
   949         aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );
       
   950         
       
   951         CleanupStack::PopAndDestroy( buf );
       
   952         CleanupStack::PopAndDestroy( details );
       
   953         }
       
   954     else
       
   955         {
       
   956         aMessage.CompleteAndRelease( KErrNotFound );
       
   957         }
       
   958     }
       
   959 
       
   960 void CNcdPurchaseHistoryDb::EventCountRequestL( MCatalogsBaseMessage& aMessage )
       
   961     {
       
   962     TUint count = EventCountL();
       
   963     
       
   964     HBufC8* message = UintToDes8LC( count );
       
   965     
       
   966     aMessage.CompleteAndReleaseL( *message, KErrNone );
       
   967     
       
   968     CleanupStack::PopAndDestroy( message );
       
   969     }
       
   970 
       
   971 void CNcdPurchaseHistoryDb::ReleaseRequest( MCatalogsBaseMessage& aMessage )
       
   972     {
       
   973     DLTRACEIN((""));
       
   974 
       
   975     // Decrease the reference count for this object.
       
   976     // When the reference count reaches zero, this object will be destroyed
       
   977     // and removed from the session.
       
   978     MCatalogsSession& requestSession( aMessage.Session() );
       
   979     TInt handle( aMessage.Handle() );
       
   980 
       
   981     // Send complete information back to proxy.
       
   982     aMessage.CompleteAndRelease( KErrNone );
       
   983         
       
   984     // Remove this object from the session.
       
   985     requestSession.RemoveObject( handle );
       
   986         
       
   987     DLTRACEOUT((""));
       
   988     }
       
   989 
       
   990 void CNcdPurchaseHistoryDb::NewPurchaseL(
       
   991     CNcdPurchaseDetails& aPurchase,
       
   992     TUint aNewEventCount )
       
   993     {
       
   994     // Construct database view.
       
   995     RDbView view;
       
   996     CleanupClosePushL( view );
       
   997     User::LeaveIfError( view.Prepare(
       
   998         iDatabase,
       
   999         TDbQuery( KSqlPurchasesAllNone ),
       
  1000         RDbView::EInsertOnly ) );
       
  1001     view.InsertL();
       
  1002     
       
  1003     // Set initial value for EHasIcon here. This is needed because in SetPurchaseViewL
       
  1004     // the flag is never unset after being set to true. The reason for this is that
       
  1005     // the flag is unkwnown to PCD! Adapter and when it syncs PH data with the engine
       
  1006     // it cannot set the flag correctly. Therefore the flag is always kept as true 
       
  1007     // regardless of what PCD! Adapter sends in the sync. This is correct because
       
  1008     // once set, the icon data is never removed from the purchase detail entry.
       
  1009     view.SetColL( EHasIcon, EFalse );
       
  1010     
       
  1011     SetPurchaseViewL( view, aPurchase, aNewEventCount, ETrue );
       
  1012     
       
  1013     
       
  1014     // Insert purchase into the database
       
  1015     view.PutL();
       
  1016     view.Close();
       
  1017     CleanupStack::PopAndDestroy( &view );
       
  1018     }
       
  1019 
       
  1020 
       
  1021 void CNcdPurchaseHistoryDb::UpdatePurchaseL(
       
  1022     RDbRowSet& aView,
       
  1023     CNcdPurchaseDetails& aPurchase,
       
  1024     TUint aNewEventCount,
       
  1025     TBool aSaveIcon )
       
  1026     {
       
  1027     aView.UpdateL();
       
  1028     
       
  1029     SetPurchaseViewL( aView, aPurchase, aNewEventCount, aSaveIcon );
       
  1030 
       
  1031     // Update purchase details.
       
  1032     aView.PutL();
       
  1033     }
       
  1034 
       
  1035 
       
  1036 void CNcdPurchaseHistoryDb::SetPurchaseViewL(
       
  1037     RDbRowSet& aView,
       
  1038     CNcdPurchaseDetails& aPurchase,
       
  1039     TUint aNewEventCount,
       
  1040     TBool aSaveIcon )
       
  1041     {
       
  1042     aView.SetColL( EEventId, aNewEventCount );
       
  1043     aView.SetColL( EClientUid, aPurchase.ClientUid().iUid );
       
  1044     WriteLongTextColumnL( aView, ENamespace, aPurchase.Namespace() );
       
  1045     WriteLongTextColumnL( aView, EEntityId, aPurchase.EntityId() );
       
  1046     WriteLongTextColumnL( aView, EItemName, aPurchase.ItemName() );
       
  1047     aView.SetColL( EItemPurpose, aPurchase.ItemPurpose() );
       
  1048     WriteLongTextColumnL(
       
  1049         aView,
       
  1050         ECatalogName,
       
  1051         aPurchase.CatalogSourceName() );
       
  1052 
       
  1053     CBufBase* downloadBuf = CBufFlat::NewL( KBufExpandSize );
       
  1054     CleanupStack::PushL( downloadBuf );
       
  1055 
       
  1056     RBufWriteStream downloadStream( *downloadBuf );
       
  1057     CleanupClosePushL( downloadStream );
       
  1058 
       
  1059     TInt downloadCount = aPurchase.DownloadInfoCount();
       
  1060     downloadStream.WriteInt32L( downloadCount );
       
  1061     for ( TInt i = 0; i < downloadCount; i++ )
       
  1062         {
       
  1063         // Download information present.
       
  1064 
       
  1065         CNcdPurchaseDownloadInfo& info = aPurchase.DownloadInfo( i );
       
  1066         info.ExternalizeL( downloadStream );
       
  1067         }
       
  1068 
       
  1069     CleanupStack::PopAndDestroy( &downloadStream );
       
  1070     TPtr8 downloadPtr = downloadBuf->Ptr( 0 );
       
  1071     WriteLongTextColumn8L( aView, EDownloadInfo, downloadPtr );
       
  1072     CleanupStack::PopAndDestroy( downloadBuf );
       
  1073 
       
  1074     WriteLongTextColumnL( aView, EPurchaseOptionId, aPurchase.PurchaseOptionId() );
       
  1075     WriteLongTextColumnL( aView, EPurchaseOptionName, aPurchase.PurchaseOptionName() );
       
  1076     WriteLongTextColumnL( aView, EPurchaseOptionPrice, aPurchase.PurchaseOptionPrice() );
       
  1077     WriteLongTextColumnL( aView, EFinalPrice, aPurchase.FinalPrice() );
       
  1078     WriteLongTextColumnL( aView, EPaymentMethodName, aPurchase.PaymentMethodName() );
       
  1079     aView.SetColL( EPurchaseTime, aPurchase.PurchaseTime().Int64() );
       
  1080 
       
  1081     const MDesCArray& downloadedFiles = aPurchase.DownloadedFiles();
       
  1082 
       
  1083     CBufBase* filesBuf = CBufFlat::NewL( KBufExpandSize );
       
  1084     CleanupStack::PushL( filesBuf );
       
  1085 
       
  1086     RBufWriteStream filesStream( *filesBuf );
       
  1087     CleanupClosePushL( filesStream );
       
  1088 
       
  1089     TInt filesCount = downloadedFiles.MdcaCount();
       
  1090     filesStream.WriteInt32L( filesCount );
       
  1091     for ( TInt i = 0; i < filesCount; i++ )
       
  1092         {
       
  1093         // Downloaded files present.
       
  1094 
       
  1095         ExternalizeDesL( downloadedFiles.MdcaPoint( i ), filesStream );
       
  1096         }
       
  1097 
       
  1098     CleanupStack::PopAndDestroy( &filesStream );
       
  1099     TPtr8 filesPtr = filesBuf->Ptr( 0 );
       
  1100     WriteLongTextColumn8L( aView, EDownloadedFiles, filesPtr );
       
  1101     CleanupStack::PopAndDestroy( filesBuf );
       
  1102 
       
  1103     CBufBase* installBuf = CBufFlat::NewL( KBufExpandSize );
       
  1104     CleanupStack::PushL( installBuf );
       
  1105 
       
  1106     RBufWriteStream installStream( *installBuf );
       
  1107     CleanupClosePushL( installStream );
       
  1108 
       
  1109     TInt installCount = aPurchase.InstallInfoCount();
       
  1110     installStream.WriteInt32L( installCount );
       
  1111     for ( TInt i = 0; i < installCount; i++ )
       
  1112         {
       
  1113         // Install information present.
       
  1114 
       
  1115         CNcdPurchaseInstallInfo& info = aPurchase.InstallInfo( i );
       
  1116         info.ExternalizeL( installStream );
       
  1117         }
       
  1118 
       
  1119     CleanupStack::PopAndDestroy( &installStream );
       
  1120     TPtr8 installPtr = installBuf->Ptr( 0 );
       
  1121     WriteLongTextColumn8L( aView, EFileInstallInfos, installPtr );
       
  1122     CleanupStack::PopAndDestroy( installBuf );
       
  1123     
       
  1124     if ( aSaveIcon ) 
       
  1125         {
       
  1126         DLTRACE(("Saving the icon to purchase history"));
       
  1127         WriteLongTextColumn8L( aView, EIcon, aPurchase.Icon() );
       
  1128         }
       
  1129     WriteLongTextColumnL(
       
  1130         aView,
       
  1131         EDownloadAccessPoint,
       
  1132         aPurchase.DownloadAccessPoint() );
       
  1133     WriteLongTextColumnL( aView, EDescription, aPurchase.Description() );
       
  1134     WriteLongTextColumnL( aView, EVersion, aPurchase.Version() );
       
  1135     WriteLongTextColumnL( aView, EServerUri, aPurchase.ServerUri() );
       
  1136     aView.SetColL( EItemType, aPurchase.ItemType() );
       
  1137     aView.SetColL( ETotalContentSize, aPurchase.TotalContentSize() );
       
  1138     WriteLongTextColumnL( aView, EOriginNodeId, aPurchase.OriginNodeId() );
       
  1139     aView.SetColL( ELastOperationTime, aPurchase.LastOperationTime().Int64() );
       
  1140     aView.SetColL( ELastOperationErrorCode, aPurchase.LastOperationErrorCode() );
       
  1141     
       
  1142     if( aPurchase.HasIcon() )
       
  1143         {
       
  1144         // HasIcon flag can be set but never unset.
       
  1145         aView.SetColL( EHasIcon, ETrue );
       
  1146         }
       
  1147     
       
  1148     // Externalize attributes
       
  1149     RCatalogsBufferWriter attributeWriter;
       
  1150     attributeWriter.OpenLC();
       
  1151     aPurchase.ExternalizeAttributesL( attributeWriter() );    
       
  1152     WriteLongTextColumn8L( aView, EAttributes, attributeWriter.PtrL() );
       
  1153     CleanupStack::PopAndDestroy( &attributeWriter );
       
  1154     
       
  1155     }
       
  1156 
       
  1157 void CNcdPurchaseHistoryDb::SetEventCountL( TUint aEventCount )
       
  1158     {
       
  1159     // Remove old event count from the database.
       
  1160     User::LeaveIfError( iDatabase.Execute( KSqlEventCountDelete ) );
       
  1161     
       
  1162     // Construct database view.
       
  1163     RDbView view;
       
  1164     User::LeaveIfError( view.Prepare(
       
  1165         iDatabase,
       
  1166         TDbQuery( KSqlCurrentEventCount ),
       
  1167         RDbView::EInsertOnly ) );
       
  1168     view.InsertL();
       
  1169 
       
  1170     view.SetColL( KEventCounterColumnNumber, aEventCount );
       
  1171 
       
  1172     // Insert event count into the database
       
  1173     view.PutL();
       
  1174     view.Close();
       
  1175     
       
  1176     // Remove all unnecessary data from the database.
       
  1177     User::LeaveIfError( iDatabase.Compact() );
       
  1178     }
       
  1179 
       
  1180 TBool CNcdPurchaseHistoryDb::PurchaseExistsL( TUint aPurchaseId )
       
  1181     {
       
  1182     TInt maxLength = KSqlPurchaseByPurchaseIdStart().Length()
       
  1183         + KMaxLengthOfInt
       
  1184         + KSqlPurchaseByPurchaseIdEnd().Length();
       
  1185 
       
  1186     HBufC* sqlStatement = HBufC::NewLC( maxLength );
       
  1187     TPtr statementPtr( sqlStatement->Des() );
       
  1188 
       
  1189     statementPtr.Copy( KSqlPurchaseByPurchaseIdStart );
       
  1190     statementPtr.AppendNum( aPurchaseId );
       
  1191     statementPtr.Append( KSqlPurchaseByPurchaseIdEnd );
       
  1192 
       
  1193     RDbView view;
       
  1194     CleanupClosePushL( view );
       
  1195 
       
  1196     User::LeaveIfError(
       
  1197         view.Prepare( iDatabase, TDbQuery( *sqlStatement ) ) );
       
  1198 
       
  1199     User::LeaveIfError( view.EvaluateAll() );
       
  1200     view.FirstL();
       
  1201 
       
  1202     TBool exists = EFalse;
       
  1203     
       
  1204     if ( view.AtRow() )
       
  1205         {
       
  1206         exists = ETrue;
       
  1207         }
       
  1208 
       
  1209     CleanupStack::PopAndDestroy( &view );
       
  1210     CleanupStack::PopAndDestroy( sqlStatement );
       
  1211     
       
  1212     return exists;
       
  1213     }
       
  1214 
       
  1215 
       
  1216 void CNcdPurchaseHistoryDb::ValidatePurchaseDetailsL( 
       
  1217     CNcdPurchaseDetails& aDetails )
       
  1218     {
       
  1219     DLTRACEIN((""));
       
  1220     
       
  1221     TInt dlInfoCount = aDetails.DownloadInfoCount();
       
  1222     
       
  1223     // Add/remove filepaths so that there's as many filepaths as there are
       
  1224     // download infos. Download infos determine the real count because they
       
  1225     // are received from the protocol
       
  1226     TInt filePathDiff = dlInfoCount - aDetails.DownloadedFiles().MdcaCount();
       
  1227     if ( filePathDiff > 0 ) 
       
  1228         {
       
  1229         DLTRACE(("Adding %d empty filepaths", filePathDiff ));
       
  1230         while ( filePathDiff-- ) 
       
  1231             {
       
  1232             aDetails.AddDownloadedFileL( KNullDesC() );
       
  1233             }        
       
  1234         }
       
  1235     else if ( filePathDiff < 0 ) // This shouldn't really ever happen
       
  1236         {        
       
  1237         DLTRACE(("Removing %d filepaths", -filePathDiff ));
       
  1238         // Start from the end
       
  1239         TInt index = aDetails.DownloadedFiles().MdcaCount() - 1;
       
  1240         
       
  1241         filePathDiff = index + filePathDiff;
       
  1242         for ( ; index > filePathDiff; index-- ) 
       
  1243             {
       
  1244             aDetails.RemoveDownloadedFile( index );            
       
  1245             }
       
  1246         }
       
  1247     
       
  1248     // install info count must be <= download info count
       
  1249     TInt installDiff = dlInfoCount - aDetails.InstallInfoCount();
       
  1250     if ( installDiff < 0 ) // This shouldn't really ever happen
       
  1251         {
       
  1252         DLTRACE(("Removing %d install infos", -installDiff ));
       
  1253         // Start from the end
       
  1254         TInt index = aDetails.InstallInfoCount() - 1;
       
  1255         
       
  1256         installDiff = index + installDiff;
       
  1257         for ( ; index > installDiff; index-- ) 
       
  1258             {
       
  1259             aDetails.RemoveInstallInfo( index );            
       
  1260             }        
       
  1261         }
       
  1262     }
       
  1263