fotaapplication/fotaserver/src/FotaDB.cpp
branchRCL_3
changeset 61 b183ec05bd8c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fotaapplication/fotaserver/src/FotaDB.cpp	Tue Aug 31 16:04:06 2010 +0300
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies). 
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of "Eclipse Public License v1.0"
+ * which accompanies this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ *
+ * Initial Contributors:
+ * Nokia Corporation - initial contribution.
+ *
+ * Contributors:
+ *
+ * Description:   Fota package state preservation 
+ *
+ */
+
+#include <centralrepository.h>
+#include "FotaDB.h"
+#include "FotaSrvDebug.h"
+#include "fotaserverPrivateCRKeys.h"
+
+#define __LEAVE_IF_ERROR(x) if(KErrNone!=x) {FLOG(_L("LEAVE in %s: %d"), __FILE__, __LINE__); User::Leave(x); }
+
+// ====================== MEMBER FUNCTIONS ===================================
+
+// ---------------------------------------------------------------------------
+// CFotaDB::CFotaDB()
+// ---------------------------------------------------------------------------
+CFotaDB::CFotaDB() :
+    iIsOpen(EFalse)
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::~CFotaDB()
+// ---------------------------------------------------------------------------
+CFotaDB::~CFotaDB()
+    {
+    //Delete columns set
+    if (iColSet)
+        {
+        delete iColSet;
+        iColSet = NULL;
+        }
+    //Close table
+    iTable.Close();
+
+    //Close database
+    iStateDB.Close();
+
+    //Close file server session
+    if (iFSSession.Handle())
+        iFSSession.Close();
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::NewL()
+// ---------------------------------------------------------------------------
+CFotaDB* CFotaDB::NewL()
+    {
+    CFotaDB* self = new (ELeave) CFotaDB();
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::ConstructL()
+// ---------------------------------------------------------------------------
+void CFotaDB::ConstructL()
+    {
+    TInt err;
+    TBuf<KMaxPath> tmp;
+    User::LeaveIfError(iFSSession.Connect());
+    err = iFSSession.CreatePrivatePath(EDriveC);
+    if (err != KErrNone && err != KErrAlreadyExists)
+        User::Leave(err);
+    User::LeaveIfError(iFSSession.SetSessionToPrivate(EDriveC));
+    User::LeaveIfError(iFSSession.SessionPath(tmp));
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::CreateDatabaseL()
+// Creates db in private dir of fotaserver
+// ---------------------------------------------------------------------------
+void CFotaDB::CreateDatabaseL()
+    {
+    FLOG(_L("CFotaDB::CreateDatabaseL()  >>"));
+    TInt err;
+    User::LeaveIfError(iStateDB.Create(iFSSession, KDatabaseName));
+    User::LeaveIfError(iStateDB.Begin());
+    User::LeaveIfError(iStateDB.Execute(KCreateTable));
+    err = iStateDB.Commit();
+    if (err)
+        {
+        FLOG(_L("      cdb err %d"), err);
+        iStateDB.Rollback();
+        User::Leave(err);
+        }
+    User::LeaveIfError(iStateDB.Compact());
+    FLOG(_L("CFotaDB::CreateDatabaseL()  <<"));
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::AddPackageStateL
+// Adds state to db
+// ---------------------------------------------------------------------------
+void CFotaDB::AddPackageStateL(const TPackageState& aState,
+        const TDesC8& aPkgURL)
+    {
+    FLOG(_L("  CFotaDB::AddPackageStateL   >>"));
+    TInt err;
+    RDbView view;
+    CleanupClosePushL(view);
+    TPackageState pkgstate(aState);
+    pkgstate.iResult = -1; // result should be -1 if no Execs have been done
+    err = view.Prepare(iStateDB, TDbQuery(KSelectAll), RDbView::EInsertOnly);
+    __LEAVE_IF_ERROR(err);
+    FLOG(_L("  CFotaDB::AddPackageStateL   inserting. pkgid:%d result:%d  state:%d"),
+            pkgstate.iPkgId, pkgstate.iResult, pkgstate.iState);
+    view.InsertL();
+    StateToRowL(pkgstate, aPkgURL, view);
+    view.PutL();
+    CleanupStack::PopAndDestroy(); //view
+    FLOG(_L("  CFotaDB::AddPackageStateL   <<"));
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::GetAllL
+// Get all states
+// ---------------------------------------------------------------------------
+void CFotaDB::GetAllL(RArray<TInt>& aStates)
+    {
+    RDbView view;
+    CleanupClosePushL(view);
+
+    TInt err = view.Prepare(iStateDB, TDbQuery(KSelectAll));
+    __LEAVE_IF_ERROR(err);
+    view.EvaluateAll();
+
+    view.FirstL();
+    FLOG(_L("[fota DB] --- rows ------------------------------------------------------------------- v"));
+    while (view.AtRow())
+        {
+        view.GetL();
+        HBufC8* url;
+        TPackageState s = RowToStateL(url, view);
+        aStates.Append(s.iPkgId);
+        CleanupStack::PushL(url);
+        FLOG(_L("[fotaDB] pkgid: %d profid:%d state:%d  result:%d \
+                url: %d chars sessiontype:%d IapId:%d Pkgsize:%d UpdateLtr:%d"),
+                s.iPkgId, s.iProfileId, s.iState, s.iResult,
+                url->Des().Length(), s.iSessionType, s.iIapId, s.iPkgSize,
+                s.iUpdateLtr);
+        CleanupStack::PopAndDestroy(); // url
+        view.NextL();
+        }
+    FLOG(_L("[fota DB] --- rows ------------------------------------------------------------------- ^"));
+    view.Close();
+    CleanupStack::PopAndDestroy(); //view
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::OpenDBL()
+// Opens database
+// ---------------------------------------------------------------------------
+void CFotaDB::OpenDBL()
+    {
+    FLOG(_L("CFotaDB::OpenDBL()"));
+    if (!iIsOpen) //Prevents accidental opening of database twice
+        {
+        TInt err;
+        err = iStateDB.Open(iFSSession, KDatabaseName);
+
+        if (err == KErrNotFound)
+            {
+            CreateDatabaseL();
+            }
+        else if (err != KErrNone)
+            {
+            FLOG(_L("[fota DB openDB]\t db open error: %d"), err);
+            FLOG(_L("deleting fota DB and creating it again..."));
+            err = iFSSession.Delete(KDatabaseName);
+            CreateDatabaseL();
+            User::LeaveIfError(err);
+            }
+        User::LeaveIfError(iTable.Open(iStateDB, KTblState));
+        iColSet = iTable.ColSetL();
+
+        iIsOpen = ETrue;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::CloseAndCommitDB
+// Closes and commits DB
+// ---------------------------------------------------------------------------
+void CFotaDB::CloseAndCommitDB()
+    {
+    if (iColSet)
+        {
+        delete iColSet;
+        iColSet = NULL;
+        }
+    iTable.Close();
+    iStateDB.Close();
+    iIsOpen = EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::IsOpen()
+// Chekcs if db is open
+// ---------------------------------------------------------------------------
+TBool CFotaDB::IsOpen()
+    {
+    return iIsOpen;
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::GetStateL
+// Gets pkg state from db
+// ---------------------------------------------------------------------------
+TPackageState CFotaDB::GetStateL(const TInt aPkgId, TDes8& aPkgURL)
+    {
+    RDbView view;
+    TPackageState s;
+    CleanupClosePushL(view);
+
+    s.iState = RFotaEngineSession::EIdle; // default state is idle
+
+    HBufC* select = HBufC::NewLC(KSelect_where_packageid().Length() + 10);
+    select->Des().Format(KSelect_where_packageid, aPkgId);
+
+    TInt err = view.Prepare(iStateDB, TDbQuery(*select));
+    __LEAVE_IF_ERROR(err);
+    view.EvaluateAll();
+    view.FirstL();
+
+    while (view.AtRow())
+        {
+        view.GetL();
+        HBufC8* url;
+        s = RowToStateL(url, view);
+        CleanupStack::PushL(url);
+        aPkgURL.Copy(url->Des());
+        CleanupStack::PopAndDestroy(); // url
+        view.NextL();
+        }
+    CleanupStack::PopAndDestroy(); //select
+    CleanupStack::PopAndDestroy(); //view
+    return s;
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::SetStateL
+// Writes package state to DB. 
+// ---------------------------------------------------------------------------
+void CFotaDB::SetStateL(TPackageState& aState, const TDesC8& aPkgURL,
+        TUint aChangedFields)
+    {
+    FLOG(_L("  CFotaDB::SetStateL  >>  id %d result %d  state %d sessiontype %d iapid %d pkgsize %d updateltr %d"), aState.iPkgId, aState.iResult, aState.iState);
+    __ASSERT_ALWAYS( aChangedFields!=0, User::Leave(KErrArgument) );
+    TBuf8<KMaxFileName> temp;
+    TPackageState found = GetStateL(aState.iPkgId, temp);
+    if (found.iPkgId == KErrNotFound)
+        {
+        AddPackageStateL(aState, aPkgURL);
+        }
+    else
+        {
+        // sml try count must be reset, if state is set
+        if (aChangedFields & EFDBState)
+            {
+            aChangedFields = aChangedFields | EFDBSmlTryCount;
+            SetRetryCount(aState);
+            }
+
+        // Construct a SQL string for update. 
+        // Example: UPDATE State SET Result=40,State=4 WHERE pkgID=5
+        // 
+        TInt sqlsize = 0;
+        _LIT8( KSqlbegin, "UPDATE State SET " );
+        TBuf<21> sqlEnd;
+        HBufC8* sql(NULL);
+        // determine characters needed 
+        sqlsize = DetermineCharNeeded(aChangedFields, aState, aPkgURL);
+        sqlEnd.AppendFormat(_L(" WHERE pkgID=%d"), aState.iPkgId);
+
+        sql = HBufC8::NewLC(((TDesC8) KSqlbegin).Length() + sqlsize
+                + sqlEnd.Length());
+
+        sql->Des().Append(KSqlbegin);
+
+        if (aChangedFields & EFDBResult)
+            {
+            // check FUMO compability
+            __ASSERT_ALWAYS( aState.iResult>=KErrNotFound
+                    && aState.iResult<=602, User::Leave(KErrArgument) );
+            sql->Des().AppendFormat(_L8("Result=%d,"), aState.iResult);
+            }
+        if (aChangedFields & EFDBState)
+            {
+            // check FUMO compability
+            __ASSERT_ALWAYS( aState.iState>=0 && aState.iState<=100
+                    , User::Leave(KErrArgument) );
+            sql->Des().AppendFormat(_L8("State=%d,"), aState.iState);
+            }
+        if (aChangedFields & EFDBProfileId)
+            {
+            sql->Des().AppendFormat(_L8("profileid=%d,"), aState.iProfileId);
+            }
+        if (aChangedFields & EFDBPkgUrl)
+            {
+            sql->Des().AppendFormat(_L8("pkgurl='%S',"), &aPkgURL);
+            }
+        if (aChangedFields & EFDBPkgName)
+            {
+            sql->Des().AppendFormat(_L8("pkgname='%S',"), &(aState.iPkgName));
+            }
+        if (aChangedFields & EFDBVersion)
+            {
+            sql->Des().AppendFormat(_L8("Version='%S',"),
+                    &(aState.iPkgVersion));
+            }
+        if (aChangedFields & EFDBSmlTryCount)
+            {
+            __ASSERT_ALWAYS( aState.iSmlTryCount>=0
+                    , User::Leave(KErrArgument) );
+            sql->Des().AppendFormat(_L8("SmlTryCount=%d,"),
+                    aState.iSmlTryCount);
+
+            }
+        if (aChangedFields & EFDBSessionType)
+            {
+            sql->Des().AppendFormat(_L8("SessionType=%d,"),
+                    aState.iSessionType);
+            }
+        if (aChangedFields & EFDBIapId)
+            {
+            // validate IAP ID
+            __ASSERT_ALWAYS( aState.iIapId>=-1 ,User::Leave(KErrArgument) );
+            sql->Des().AppendFormat(_L8("IapId=%d,"), aState.iIapId);
+            }
+        if (aChangedFields & EFDBPkgSize)
+            {
+            sql->Des().AppendFormat(_L8("PkgSize=%d,"), aState.iPkgSize);
+            }
+        if (aChangedFields & EFDBUpdateLtr)
+            {
+            // validate bit
+            sql->Des().AppendFormat(_L8("UpdateLtr=%d,"), aState.iUpdateLtr);
+            }
+        // remove trailing ,
+        if (aChangedFields)
+            {
+            sql->Des().SetLength(sql->Des().Length() - 1);
+            }
+        sql->Des().Append(sqlEnd);
+        HBufC* sql2 = HBufC::NewLC(sql->Length()); // to cleanupstack
+        sql2->Des().Copy(sql->Des());
+        FLOG(_L("  sql:%S"), sql2);
+
+        User::LeaveIfError(iStateDB.Begin());
+        User::LeaveIfError(iStateDB.Execute(*sql2));
+        User::LeaveIfError(iStateDB.Commit());
+        User::LeaveIfError(iStateDB.Compact());
+
+        CleanupStack::PopAndDestroy(sql2); //sql2
+        CleanupStack::PopAndDestroy(sql); //sql
+        }
+    FLOG(_L("  CFotaDB::SetStateL  <<"));
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::DetermineCharNeeded 
+// Returns the char needed fro the query 
+// ---------------------------------------------------------------------------
+
+TInt CFotaDB::DetermineCharNeeded(TInt aChangedFields, TPackageState& aState,
+        const TDesC8& aPkgURL)
+
+    {
+
+    TInt sqlsize = 0;
+    if (aChangedFields & EFDBResult)
+        sqlsize += 4 + 7 + 4;
+    if (aChangedFields & EFDBState)
+        sqlsize += 4 + 5 + 4;
+    if (aChangedFields & EFDBProfileId)
+        sqlsize += 4 + 9 + 4;
+    if (aChangedFields & EFDBPkgUrl)
+        sqlsize += aPkgURL.Length() + 6 + 4;
+    if (aChangedFields & EFDBPkgName)
+        sqlsize += aState.iPkgName.Length() + 7 + 4;
+    if (aChangedFields & EFDBVersion)
+        sqlsize += aState.iPkgVersion.Length() + 7 + 4;
+    if (aChangedFields & EFDBSmlTryCount)
+        sqlsize += 4 + 11 + 4;
+
+    if (aChangedFields & EFDBSessionType)
+        sqlsize += 4 + 11 + 4;
+    if (aChangedFields & EFDBIapId)
+        sqlsize += 4 + 5 + 4;
+    if (aChangedFields & EFDBPkgSize)
+        sqlsize += 4 + 7 + 10;
+    if (aChangedFields & EFDBUpdateLtr)
+        sqlsize += 4 + 11 + 4;
+
+    return sqlsize;
+
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::SetRetryCount
+// Sets the retry count
+// ---------------------------------------------------------------------------
+void CFotaDB::SetRetryCount(TPackageState& aState)
+    {
+    CRepository* centrep(NULL);
+    TInt err = KErrNone;
+    TInt retry = 0;
+
+    TRAP(err, centrep = CRepository::NewL( KCRUidFotaServer ) );
+    if (centrep)
+        {
+        err = centrep->Get(KGenericAlertRetries, retry);
+        delete centrep;
+        centrep = NULL;
+        }
+    if (err == KErrNone)
+        {
+        if (retry < 0)
+            {
+            aState.iSmlTryCount = KDefaultSmlTryCount;
+            }
+        else if (retry == 0)
+            {
+            aState.iSmlTryCount = 2;
+            }
+        else if (retry > KMaximumSmlTryCount)
+            {
+            aState.iSmlTryCount = KMaximumSmlTryCount + 1;
+            }
+        else
+            {
+            aState.iSmlTryCount = retry + 1;
+            }
+        }
+    else
+        {
+        aState.iSmlTryCount = KDefaultSmlTryCount;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::RowToStateL
+// Extracts db row contents to package state object and aPkgUrl
+// Returns url in aPkgURL parameter
+// ---------------------------------------------------------------------------
+TPackageState CFotaDB::RowToStateL(HBufC8*& aPkgUrl, const RDbView& aView)
+    {
+    TPackageState s;
+    TInt pkgid = aView.ColInt(iColSet->ColNo(KColPkgId));
+    TInt state = aView.ColInt(iColSet->ColNo(KColState));
+    TInt result = aView.ColInt(iColSet->ColNo(KColResult));
+    TSmlProfileId profileid(aView.ColInt(iColSet->ColNo(KColProfileId)));
+    TPtrC pkgname = aView.ColDes(iColSet->ColNo(KColPkgName));
+    TPtrC version = aView.ColDes(iColSet->ColNo(KColVersion));
+    TInt smltrycount = aView.ColInt(iColSet->ColNo(KColSmlTryCount));
+    TInt sessiontype = aView.ColInt(iColSet->ColNo(KColSessionType));
+    TInt iapid = aView.ColInt(iColSet->ColNo(KColIapId));
+    TUint pkgsize = aView.ColUint(iColSet->ColNo(KColPkgSize));
+    TBool updateltr = aView.ColUint8(iColSet->ColNo(KColUpdateLtr));
+
+    s.iPkgId = pkgid;
+    s.iPkgName.Copy(pkgname);
+    s.iPkgVersion.Copy(version);
+    s.iProfileId = profileid;
+    s.iResult = result;
+    s.iState = RFotaEngineSession::TState(state);
+    s.iSmlTryCount = smltrycount;
+    s.iSessionType = sessiontype;
+    s.iIapId = iapid;
+    s.iPkgSize = pkgsize;
+    s.iUpdateLtr = updateltr;
+
+    RDbColReadStream rstream;
+    TInt len = aView.ColLength(iColSet->ColNo(KColPkgUrl));
+    rstream.OpenLC(aView, iColSet->ColNo(KColPkgUrl));
+    HBufC* pkgurl = HBufC::NewLC(len);
+    TPtr ptr = pkgurl->Des();
+    rstream.ReadL(ptr, len);
+
+    HBufC8* tmp = HBufC8::NewL(pkgurl->Des().Length());
+    tmp->Des().Copy(pkgurl->Des());
+    aPkgUrl = tmp;
+
+    CleanupStack::PopAndDestroy(pkgurl);
+    CleanupStack::PopAndDestroy(&rstream);
+    return s;
+    }
+
+// ---------------------------------------------------------------------------
+// CFotaDB::StateToRowL
+// Converts state object to database row (into view object)
+// ---------------------------------------------------------------------------
+void CFotaDB::StateToRowL(const TPackageState& aPkg, const TDesC8& aPkgURL,
+        RDbView& aView)
+    {
+    HBufC* pkgname = HBufC::NewLC(aPkg.iPkgName.Length());
+    HBufC* version = HBufC::NewLC(aPkg.iPkgVersion.Length());
+
+    pkgname->Des().Copy(aPkg.iPkgName);
+    version->Des().Copy(aPkg.iPkgVersion);
+
+    aView.SetColL(iColSet->ColNo(KColPkgId), aPkg.iPkgId);
+    aView.SetColL(iColSet->ColNo(KColResult), aPkg.iResult);
+    aView.SetColL(iColSet->ColNo(KColState), aPkg.iState);
+    aView.SetColL(iColSet->ColNo(KColProfileId), aPkg.iProfileId);
+    aView.SetColL(iColSet->ColNo(KColPkgName), *pkgname);
+    aView.SetColL(iColSet->ColNo(KColVersion), *version);
+    aView.SetColL(iColSet->ColNo(KColSmlTryCount), aPkg.iSmlTryCount);
+    aView.SetColL(iColSet->ColNo(KColSessionType), aPkg.iSessionType);
+    aView.SetColL(iColSet->ColNo(KColIapId), aPkg.iIapId);
+    aView.SetColL(iColSet->ColNo(KColPkgSize), aPkg.iPkgSize);
+    aView.SetColL(iColSet->ColNo(KColUpdateLtr), aPkg.iUpdateLtr);
+
+    RDbColWriteStream wstream;
+    CleanupClosePushL(wstream);
+    wstream.OpenL(aView, iColSet->ColNo(KColPkgUrl));
+    // Cannot write 8 bit descriptors to databae
+    HBufC* buf = HBufC::NewLC(aPkgURL.Length());
+    buf->Des().Copy(aPkgURL);
+    wstream.WriteL(buf->Des());
+
+    FLOG(_L("CFotaDB::StateToRowL  id:%d result:%d state:%d profileid:%d \
+    		name:%d chars version: %d chars url: %d chars sessiontype:%d iapid:%d pkgsize:%d updateltr = %d"),
+            aPkg.iPkgId, aPkg.iResult, aPkg.iState, aPkg.iProfileId,
+            pkgname->Des().Length(), version->Des().Length(),
+            buf->Des().Length(), aPkg.iSessionType, aPkg.iIapId,
+            aPkg.iPkgSize, aPkg.iUpdateLtr);
+
+    CleanupStack::PopAndDestroy(buf);
+    CleanupStack::PopAndDestroy(&wstream);
+    CleanupStack::PopAndDestroy(version);
+    CleanupStack::PopAndDestroy(pkgname);
+    }