utilities/downloadmanager/src/omadownloadbackend.cpp
author hgs
Fri, 15 Oct 2010 17:30:59 -0400
changeset 16 3c88a81ff781
permissions -rw-r--r--
201041

/**
   This file is part of CWRT package **

   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). **

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU (Lesser) General Public License as 
   published by the Free Software Foundation, version 2.1 of the License. 
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
   (Lesser) General Public License for more details. You should have 
   received a copy of the GNU (Lesser) General Public License along 
   with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "omadownloadbackend.h"
#include "omaddparser.h"
#include "downloadmanager.h"
#include "clientdownload.h"
#include "downloadcore.h"
#include "downloadevent.h"
#include <QCoreApplication>
#include <QFileInfo>

#ifdef Q_OS_LINUX
  #include <sys/statvfs.h>
#endif

#ifdef Q_OS_LINUX 
static double freeSpace(const char *path)
#else
static double freeSpace(const char* /*path*/)
#endif
{
#ifdef Q_OS_LINUX   
    struct statvfs fiData;
    if ((statvfs(path,&fiData)) < 0 ) 
        return 0;
    else {
        int blockSize = fiData.f_bsize/1024;
        double freeSize = (fiData.f_bavail)*blockSize;
        freeSize = freeSize/1024;
        return freeSize;
    }
#endif
    return 0;
}

// private implementation
class OMADownloadBackendPrivate {
    DM_DECLARE_PUBLIC(OMADownloadBackend);
public:
    OMADownloadBackendPrivate();
    ~OMADownloadBackendPrivate();

    DownloadCore *m_downloadCore;
    ClientDownload *m_download;
    OMADownloadDescParser *m_parser; // for parsing oma descriptor
    OMADownloadDescriptor *m_downloadDesc;
    bool m_isMediaDownload; // flag to indicate if media download is happening
    ClientDownload *m_mediaDownload; // not owned
    bool m_isUserCancelled;
};

OMADownloadBackendPrivate::OMADownloadBackendPrivate()
{
    m_downloadCore = 0;
    m_download = 0;
    m_parser = 0;
    m_downloadDesc = 0;
    m_isMediaDownload = false;
    m_mediaDownload = 0;
    m_isUserCancelled = false;
}

OMADownloadBackendPrivate::~OMADownloadBackendPrivate()
{
    if (m_parser) {
        delete m_parser;
        m_parser = 0;
        m_downloadDesc = 0;
    }
    if (m_mediaDownload) {
        delete m_mediaDownload;
        m_mediaDownload = NULL;
    }
}

OMADownloadBackend::OMADownloadBackend(DownloadCore *dlCore, ClientDownload *dl)
    :DownloadBackend(dlCore, dl)
{
    DM_INITIALIZE(OMADownloadBackend);
    priv->m_downloadCore = dlCore;
    priv->m_download = dl;
}

OMADownloadBackend::~OMADownloadBackend()
{
     DM_UNINITIALIZE(OMADownloadBackend);
}

int OMADownloadBackend::pause()
{
    DM_PRIVATE(OMADownloadBackend);
    if (priv->m_isMediaDownload) {
        priv->m_mediaDownload->pause();
        setDownloadState(DlPaused);
    }
    return 0;
}

int OMADownloadBackend::resume()
{
    DM_PRIVATE(OMADownloadBackend);
    priv->m_isUserCancelled = false;
    if (priv->m_isMediaDownload)
        return (priv->m_mediaDownload->resume());

    // Ready to download after the descriptor is parsed
    // capability check on the descriptor information
    if (checkDownloadDescriptor()) {
         // create download for media object
        priv->m_mediaDownload = new ClientDownload(priv->m_download->downloadManager(), 
                priv->m_downloadDesc->getAttribute(OMADownloadDescObjectURI).toString(), priv->m_download->id()); 

        if (!priv->m_mediaDownload) {
            deleteInfo(); 
            return -1;               
        }
        priv->m_mediaDownload->setAttribute(DlFileName, priv->m_downloadDesc->getAttribute(OMADownloadDescName));
        priv->m_mediaDownload->registerEventReceiver(this);
        priv->m_mediaDownload->start();
        priv->m_isMediaDownload = true; 
        deleteInfo(); 
        return 0;         
    }
    return -1;
}

int OMADownloadBackend::cancel()
{
    DM_PRIVATE(OMADownloadBackend);
    priv->m_isUserCancelled = true;
    if (priv->m_isMediaDownload)
        priv->m_mediaDownload->cancel();
    else
        DownloadBackend::cancel();
    return 0;
}

QVariant OMADownloadBackend::getAttribute(DownloadAttribute attr)
{
    DM_PRIVATE(OMADownloadBackend);
    switch(attr) {
    case OMADownloadDescriptorName:
        return priv->m_downloadDesc->getAttribute(OMADownloadDescName);
    case OMADownloadDescriptorVersion:
        return priv->m_downloadDesc->getAttribute(OMADownloadDescVersion);
    case OMADownloadDescriptorType:
        return priv->m_downloadDesc->getAttribute(OMADownloadDescType);
    case OMADownloadDescriptorSize:
        return priv->m_downloadDesc->getAttribute(OMADownloadDescSize);
    case OMADownloadDescriptorVendor:
        return priv->m_downloadDesc->getAttribute(OMADownloadDescVendor);
    case OMADownloadDescriptorDescription:
        return priv->m_downloadDesc->getAttribute(OMADownloadDescDescription);

    case DlFileName:
    {
        if (!priv->m_isMediaDownload) {
            QString url = priv->m_downloadCore->url();
            QFileInfo fileUrl(url);
            return QVariant(fileUrl.fileName());
        } else
            return priv->m_downloadDesc->getAttribute(OMADownloadDescName);
    }
    case DlContentType:
    {
        if (!priv->m_isMediaDownload)
            return DownloadBackend::getAttribute(DlContentType);
            
        else
            return priv->m_mediaDownload->getAttribute(DlContentType);
    }
    default:
        return DownloadBackend::getAttribute(attr);
    }    
    return QVariant();
}

int OMADownloadBackend::setAttribute(DownloadAttribute attr, const QVariant& value)
{
    return DownloadBackend::setAttribute(attr, value);
}

// stores the data in storage
void OMADownloadBackend::store(QByteArray /*data*/, bool /*lastChunk=false*/)
{
    return;
}

// deletes the storage
void OMADownloadBackend::deleteStore()
{
    return;
}

// returns the size of stored data
qint64 OMADownloadBackend::storedDataSize()
{
    return 0;
}

void OMADownloadBackend::bytesRecieved(qint64 /*bytesRecieved*/, qint64 /*bytesTotal*/)
{
     //Do nothing. This is here to avoid this signal to reach to base class' slot.
     return;
}

void OMADownloadBackend::bytesUploaded(qint64 bytesUploaded, qint64 bytesTotal)
{
    DM_PRIVATE(OMADownloadBackend); 
    // once data is uploaded, cancel the transaction
    if (bytesUploaded == bytesTotal)
        priv->m_downloadCore->abort() ;
}

void OMADownloadBackend::handleFinished()
{
     DM_PRIVATE(OMADownloadBackend);
     QString contentType = priv->m_downloadCore->contentType();
     if (contentType == OMA_CONTENT_TYPE) {
         bool bSucceeded = parseDownloadDescriptor();
         if (bSucceeded) {
             priv->m_downloadDesc = priv->m_parser->downloadDescriptor();
             
             QString objectURI = priv->m_downloadDesc->getAttribute(OMADownloadDescObjectURI).toString();
             if (objectURI.isEmpty()) {
                 priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("905 Attribute Mismatch"));
                 priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
                 priv->m_downloadCore->setLastErrorString(tr("No ObjectURI"));
                 setDownloadState(DlFailed);
                 postEvent(Error, NULL);
                 return;
             }
             setDownloadState(DlPaused);
             postEvent(OMADownloadDescriptorReady, NULL);
         } else {
             priv->m_downloadDesc = priv->m_parser->downloadDescriptor();
             priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("906 Invalid descriptor"));
             priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
             priv->m_downloadCore->setLastErrorString(tr("Invalid Descriptor"));
             setDownloadState(DlFailed);
             postEvent(Error, NULL);
         }
     }
}
          
bool OMADownloadBackend::parseDownloadDescriptor()
{
    DM_PRIVATE(OMADownloadBackend);
    priv->m_parser = new OMADownloadDescParser();
    QXmlInputSource source(priv->m_downloadCore->reply());
    QXmlSimpleReader reader;
    reader.setContentHandler(priv->m_parser);
    reader.setErrorHandler(priv->m_parser);
    return reader.parse(source);
}

// capability check on the descriptor
bool OMADownloadBackend::checkDownloadDescriptor()
{
    DM_PRIVATE(OMADownloadBackend);

    QString version = priv->m_downloadDesc->getAttribute(OMADownloadDescVersion).toString();
    if (! version.isEmpty() && (version != OMA_VERSION_1)) {
        priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("951 Invalid DDVersion"));
        priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
        priv->m_downloadCore->setLastErrorString(tr("951 Invalid DDVersion"));
        setDownloadState(DlFailed); 
        postEvent(Error, NULL);
        return false; 
    } 

#ifdef Q_OS_LINUX
    // "Size" check needs to be done
    double fileSize =  priv->m_downloadDesc->getAttribute(OMADownloadDescSize).toDouble();
    double mbFactor = 1024*1024;
    fileSize = fileSize/mbFactor; //fileSize in MB
    double spaceLeft = freeSpace(ROOT_PATH); //spaze left in MB
    
    if (fileSize > spaceLeft) {
        priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("901 Insufficient memory"));
        priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
        priv->m_downloadCore->setLastErrorString(tr("901 Insufficient Memory"));
        setDownloadState(DlFailed);
        postEvent(Error, NULL);
        return false;       
    } 
#endif
    return true;
}

bool OMADownloadBackend::event(QEvent *event)
{
    DM_PRIVATE(OMADownloadBackend);
    DEventType type = (DEventType)event->type();
    switch(type) {
    case Started:
        break;
    case HeaderReceived:
    {
        // handling the events from media object downloads
        // Check the mismatch in total size returned by server with the size given in the descriptor.
        //This piece of code is commented as-of-now. when needed in future , will be uncommented
        /*int totalSize = dl->getAttribute(DlTotalSize).toInt();
        if (priv->m_downloadDesc->getAttribute(OMADownloadDescSize).toInt() != totalSize)
        {
            priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("905 Attribute Mismatch"));
             
            if (dl)
            {
                dl->setError("905 Attribute Mismatch");
                dl->cancel();
                dl->setDownloadState(DlFailed);
                dl->postEvent(Error, NULL);
            } 
            return true;
        }*/
        // Check the mismatch in content type returned by server with the content type given in the descriptor.
        QString contentType = priv->m_mediaDownload->getAttribute(DlContentType).toString();
        if (priv->m_downloadDesc->getAttribute(OMADownloadDescType).toString() != contentType) {
            // media object download cannot be proceeded
            if (priv->m_mediaDownload) {
                priv->m_mediaDownload->setError("905 Attribute Mismatch");
                priv->m_mediaDownload->cancel();
                priv->m_mediaDownload->setDownloadState(DlFailed);
                priv->m_mediaDownload->postEvent(Error, NULL);
            } 
            break;
        } 
    }
    case Progress:
    {
        QVariant tSize = priv->m_mediaDownload->getAttribute(DlTotalSize);
        setTotalSize(tSize.toInt());
        QVariant curDlsize = priv->m_mediaDownload->getAttribute(DlDownloadedSize);
        setDownloadedDataSize(curDlsize.toInt());
        setDownloadState(DlInprogress);
        postEvent(Progress, NULL);
        break;
    }
    case NetworkLoss:
    {
        postEvent(NetworkLoss, NULL);
        break;
    }
    case Cancelled:
    {
        if (priv->m_isUserCancelled)
            priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("902 User Cancelled"));
        setDownloadState(DlCancelled);
        postEvent(Cancelled, NULL);
        break;
    }
    case Completed:
    {
        priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("900 Success "));
        setDownloadState(DlCompleted);
        postEvent(Completed, NULL); 
        break;
    }
    case Error:
    {
        priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("905 Attribute Mismatch"));
        priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
        priv->m_downloadCore->setLastErrorString(tr("905 Attribute Mismatch"));
        setDownloadState(DlFailed);
        postEvent(Error, NULL);
        break;
    } 
    default:
        break;
    }
    return true;
}