~ubuntu-branches/ubuntu/trusty/virtualbox-lts-xenial/trusty-updates

« back to all changes in this revision

Viewing changes to .pc/16-no-update.patch/src/VBox/Frontends/VirtualBox/src/net/UIUpdateManager.cpp

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-kpprg3lfwn2izud0
Tags: 4.3.36-dfsg-1+deb8u1ubuntu1.14.04.1~14.04.4
Use lts-xenial stack. Build only guest additions (LP: #1424769).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: UIUpdateManager.cpp $ */
 
2
/** @file
 
3
 *
 
4
 * VBox frontends: Qt4 GUI ("VirtualBox"):
 
5
 * UIUpdateManager class implementation
 
6
 */
 
7
 
 
8
/*
 
9
 * Copyright (C) 2006-2012 Oracle Corporation
 
10
 *
 
11
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
12
 * available from http://www.virtualbox.org. This file is free software;
 
13
 * you can redistribute it and/or modify it under the terms of the GNU
 
14
 * General Public License (GPL) as published by the Free Software
 
15
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
16
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
17
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
18
 */
 
19
 
 
20
/* Qt includes: */
 
21
#include <QTimer>
 
22
#include <QDir>
 
23
#include <QPointer>
 
24
#include <VBox/version.h>
 
25
 
 
26
/* GUI includes: */
 
27
#include "UIUpdateDefs.h"
 
28
#include "UIUpdateManager.h"
 
29
#include "UINetworkManager.h"
 
30
#include "UINetworkCustomer.h"
 
31
#include "UINetworkRequest.h"
 
32
#include "VBoxGlobal.h"
 
33
#include "UIMessageCenter.h"
 
34
#include "UIModalWindowManager.h"
 
35
#include "VBoxUtils.h"
 
36
#include "UIDownloaderExtensionPack.h"
 
37
#include "UIGlobalSettingsExtension.h"
 
38
#include "QIProcess.h"
 
39
 
 
40
/* COM includes: */
 
41
#include "CExtPack.h"
 
42
#include "CExtPackManager.h"
 
43
 
 
44
/* Other VBox includes: */
 
45
#include <iprt/path.h>
 
46
#include <iprt/system.h>
 
47
 
 
48
/* Forward declarations: */
 
49
class UIUpdateStep;
 
50
 
 
51
/* Queue for processing update-steps: */
 
52
class UIUpdateQueue : public QObject
 
53
{
 
54
    Q_OBJECT;
 
55
 
 
56
signals:
 
57
 
 
58
    /* Starting-signal of the queue: */
 
59
    void sigStartQueue();
 
60
 
 
61
    /* Completion-signal of the queue: */
 
62
    void sigQueueFinished();
 
63
 
 
64
public:
 
65
 
 
66
    /* Constructor: */
 
67
    UIUpdateQueue(UIUpdateManager *pParent) : QObject(pParent) {}
 
68
 
 
69
    /* Starts a queue: */
 
70
    void start() { emit sigStartQueue(); }
 
71
 
 
72
private:
 
73
 
 
74
    /* Helpers: */
 
75
    bool isEmpty() const { return m_pLastStep.isNull(); }
 
76
    UIUpdateStep* lastStep() const { return m_pLastStep; }
 
77
    void setLastStep(UIUpdateStep *pStep) { m_pLastStep = pStep; }
 
78
 
 
79
    /* Variables: */
 
80
    QPointer<UIUpdateStep> m_pLastStep;
 
81
 
 
82
    /* Friend classes: */
 
83
    friend class UIUpdateStep;
 
84
};
 
85
 
 
86
/* Interface representing update-step: */
 
87
class UIUpdateStep : public UINetworkCustomer
 
88
{
 
89
    Q_OBJECT;
 
90
 
 
91
signals:
 
92
 
 
93
    /* Completion-signal of the step: */
 
94
    void sigStepComplete();
 
95
 
 
96
public:
 
97
 
 
98
    /* Constructor: */
 
99
    UIUpdateStep(UIUpdateQueue *pQueue, bool fForceCall) : UINetworkCustomer(pQueue, fForceCall)
 
100
    {
 
101
        /* If queue has no steps yet: */
 
102
        if (pQueue->isEmpty())
 
103
        {
 
104
            /* Connect starting-signal of the queue to starting-slot of this step: */
 
105
            connect(pQueue, SIGNAL(sigStartQueue()), this, SLOT(sltStartStep()), Qt::QueuedConnection);
 
106
        }
 
107
        /* If queue has at least one step already: */
 
108
        else
 
109
        {
 
110
            /* Reconnect completion-signal of the last-step from completion-signal of the queue to starting-slot of this step: */
 
111
            disconnect(pQueue->lastStep(), SIGNAL(sigStepComplete()), pQueue, SIGNAL(sigQueueFinished()));
 
112
            connect(pQueue->lastStep(), SIGNAL(sigStepComplete()), this, SLOT(sltStartStep()), Qt::QueuedConnection);
 
113
        }
 
114
 
 
115
        /* Connect completion-signal of this step to the completion-signal of the queue: */
 
116
        connect(this, SIGNAL(sigStepComplete()), pQueue, SIGNAL(sigQueueFinished()), Qt::QueuedConnection);
 
117
        /* Connect completion-signal of this step to the destruction-slot of this step: */
 
118
        connect(this, SIGNAL(sigStepComplete()), this, SLOT(deleteLater()), Qt::QueuedConnection);
 
119
 
 
120
        /* Remember this step as the last one: */
 
121
        pQueue->setLastStep(this);
 
122
    }
 
123
 
 
124
protected slots:
 
125
 
 
126
    /* Starting-slot of the step: */
 
127
    virtual void sltStartStep() = 0;
 
128
 
 
129
protected:
 
130
 
 
131
    /* Network pregress handler dummy: */
 
132
    void processNetworkReplyProgress(qint64, qint64) {}
 
133
    /* Network reply canceled handler dummy: */
 
134
    void processNetworkReplyCanceled(UINetworkReply*) {}
 
135
    /* Network reply canceled handler dummy: */
 
136
    void processNetworkReplyFinished(UINetworkReply*) {}
 
137
};
 
138
 
 
139
/* Update-step to check for the new VirtualBox version: */
 
140
class UIUpdateStepVirtualBox : public UIUpdateStep
 
141
{
 
142
    Q_OBJECT;
 
143
 
 
144
public:
 
145
 
 
146
    /* Constructor: */
 
147
    UIUpdateStepVirtualBox(UIUpdateQueue *pQueue, bool fForceCall)
 
148
        : UIUpdateStep(pQueue, fForceCall)
 
149
        , m_url("https://update.virtualbox.org/query.php")
 
150
    {
 
151
    }
 
152
 
 
153
private slots:
 
154
 
 
155
    /* Startup slot: */
 
156
    void sltStartStep() { prepareNetworkRequest(); }
 
157
 
 
158
private:
 
159
 
 
160
    /* Prepare network request: */
 
161
    void prepareNetworkRequest()
 
162
    {
 
163
        /* Calculate the count of checks left: */
 
164
        int cCount = 1;
 
165
        QString strCount = vboxGlobal().virtualBox().GetExtraData(GUI_UpdateCheckCount);
 
166
        if (!strCount.isEmpty())
 
167
        {
 
168
            bool ok = false;
 
169
            int c = strCount.toLongLong(&ok);
 
170
            if (ok) cCount = c;
 
171
        }
 
172
 
 
173
        /* Compose query: */
 
174
        QUrl url(m_url);
 
175
        url.addQueryItem("platform", vboxGlobal().virtualBox().GetPackageType());
 
176
        /* Check if branding is active: */
 
177
        if (vboxGlobal().brandingIsActive())
 
178
        {
 
179
            /* Branding: Check whether we have a local branding file which tells us our version suffix "FOO"
 
180
                         (e.g. 3.06.54321_FOO) to identify this installation: */
 
181
            url.addQueryItem("version", QString("%1_%2_%3").arg(vboxGlobal().virtualBox().GetVersion())
 
182
                                                           .arg(vboxGlobal().virtualBox().GetRevision())
 
183
                                                           .arg(vboxGlobal().brandingGetKey("VerSuffix")));
 
184
        }
 
185
        else
 
186
        {
 
187
            /* Use hard coded version set by VBOX_VERSION_STRING: */
 
188
            url.addQueryItem("version", QString("%1_%2").arg(vboxGlobal().virtualBox().GetVersion())
 
189
                                                        .arg(vboxGlobal().virtualBox().GetRevision()));
 
190
        }
 
191
        url.addQueryItem("count", QString::number(cCount));
 
192
        url.addQueryItem("branch", VBoxUpdateData(vboxGlobal().virtualBox().GetExtraData(GUI_UpdateDate)).branchName());
 
193
        QString strUserAgent(QString("VirtualBox %1 <%2>").arg(vboxGlobal().virtualBox().GetVersion()).arg(platformInfo()));
 
194
 
 
195
        /* Send GET request: */
 
196
        QNetworkRequest request;
 
197
        request.setUrl(url);
 
198
        request.setRawHeader("User-Agent", strUserAgent.toAscii());
 
199
        createNetworkRequest(request, UINetworkRequestType_GET_Our, tr("Checking for a new VirtualBox version..."));
 
200
    }
 
201
 
 
202
    /* Handle network reply canceled: */
 
203
    void processNetworkReplyCanceled(UINetworkReply* /* pReply */)
 
204
    {
 
205
        /* Notify about step completion: */
 
206
        emit sigStepComplete();
 
207
    }
 
208
 
 
209
    /* Handle network reply: */
 
210
    void processNetworkReplyFinished(UINetworkReply *pReply)
 
211
    {
 
212
        /* Deserialize incoming data: */
 
213
        QString strResponseData(pReply->readAll());
 
214
 
 
215
        /* Newer version of necessary package found: */
 
216
        if (strResponseData.indexOf(QRegExp("^\\d+\\.\\d+\\.\\d+(_[0-9A-Z]+)? \\S+$")) == 0)
 
217
        {
 
218
            QStringList response = strResponseData.split(" ", QString::SkipEmptyParts);
 
219
            msgCenter().showUpdateSuccess(response[0], response[1]);
 
220
        }
 
221
        /* No newer version of necessary package found: */
 
222
        else
 
223
        {
 
224
            if (isItForceCall())
 
225
                msgCenter().showUpdateNotFound();
 
226
        }
 
227
 
 
228
        /* Save left count of checks: */
 
229
        int cCount = 1;
 
230
        QString strCount = vboxGlobal().virtualBox().GetExtraData(GUI_UpdateCheckCount);
 
231
        if (!strCount.isEmpty())
 
232
        {
 
233
            bool ok = false;
 
234
            int c = strCount.toLongLong(&ok);
 
235
            if (ok) cCount = c;
 
236
        }
 
237
        vboxGlobal().virtualBox().SetExtraData(GUI_UpdateCheckCount, QString("%1").arg((qulonglong)cCount + 1));
 
238
 
 
239
        /* Notify about step completion: */
 
240
        emit sigStepComplete();
 
241
    }
 
242
 
 
243
    /* Platform information getter: */
 
244
    static QString platformInfo()
 
245
    {
 
246
        /* Prepare platform report: */
 
247
        QString strPlatform;
 
248
 
 
249
#if defined (Q_OS_WIN)
 
250
        strPlatform = "win";
 
251
#elif defined (Q_OS_LINUX)
 
252
        strPlatform = "linux";
 
253
#elif defined (Q_OS_MACX)
 
254
        strPlatform = "macosx";
 
255
#elif defined (Q_OS_OS2)
 
256
        strPlatform = "os2";
 
257
#elif defined (Q_OS_FREEBSD)
 
258
        strPlatform = "freebsd";
 
259
#elif defined (Q_OS_SOLARIS)
 
260
        strPlatform = "solaris";
 
261
#else
 
262
        strPlatform = "unknown";
 
263
#endif
 
264
 
 
265
        /* The format is <system>.<bitness>: */
 
266
        strPlatform += QString(".%1").arg(ARCH_BITS);
 
267
 
 
268
        /* Add more system information: */
 
269
        int vrc;
 
270
#if defined(Q_OS_LINUX)
 
271
        /* On linux we wish to send information about the distribution
 
272
           and such like, so we try invoke a helper script that retrives
 
273
           and formats it for us. */
 
274
 
 
275
        /* Get script path: */
 
276
        char szAppPrivPath[RTPATH_MAX];
 
277
        vrc = RTPathAppPrivateNoArch(szAppPrivPath, sizeof(szAppPrivPath)); AssertRC(vrc);
 
278
        if (RT_SUCCESS(vrc))
 
279
        {
 
280
            /* Run script: */
 
281
            QByteArray result = QIProcess::singleShot(QString(szAppPrivPath) + "/VBoxSysInfo.sh");
 
282
            if (!result.isNull())
 
283
                strPlatform += QString(" [%1]").arg(QString(result).trimmed());
 
284
            else
 
285
                vrc = VERR_TRY_AGAIN; /* (take the fallback path) */
 
286
        }
 
287
        if (RT_FAILURE(vrc))
 
288
#endif
 
289
        {
 
290
            /* Use RTSystemQueryOSInfo: */
 
291
            char szTmp[256];
 
292
            QStringList components;
 
293
 
 
294
            vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
 
295
            if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
 
296
                components << QString("Product: %1").arg(szTmp);
 
297
 
 
298
            vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
 
299
            if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
 
300
                components << QString("Release: %1").arg(szTmp);
 
301
 
 
302
            vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
 
303
            if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
 
304
                components << QString("Version: %1").arg(szTmp);
 
305
 
 
306
            vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szTmp, sizeof(szTmp));
 
307
            if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
 
308
                components << QString("SP: %1").arg(szTmp);
 
309
 
 
310
            if (!components.isEmpty())
 
311
                strPlatform += QString(" [%1]").arg(components.join(" | "));
 
312
        }
 
313
 
 
314
        return strPlatform;
 
315
    }
 
316
 
 
317
private:
 
318
 
 
319
    /* Variables: */
 
320
    QUrl m_url;
 
321
};
 
322
 
 
323
/* Update-step to check for the new VirtualBox Extension Pack version: */
 
324
class UIUpdateStepVirtualBoxExtensionPack : public UIUpdateStep
 
325
{
 
326
    Q_OBJECT;
 
327
 
 
328
public:
 
329
 
 
330
    /* Constructor: */
 
331
    UIUpdateStepVirtualBoxExtensionPack(UIUpdateQueue *pQueue, bool fForceCall)
 
332
        : UIUpdateStep(pQueue, fForceCall)
 
333
    {
 
334
    }
 
335
 
 
336
private slots:
 
337
 
 
338
    /* Startup slot: */
 
339
    void sltStartStep()
 
340
    {
 
341
        /* Return if already downloading: */
 
342
        if (UIDownloaderExtensionPack::current())
 
343
        {
 
344
            emit sigStepComplete();
 
345
            return;
 
346
        }
 
347
 
 
348
        /* Get extension pack: */
 
349
        CExtPack extPack = vboxGlobal().virtualBox().GetExtensionPackManager().Find(GUI_ExtPackName);
 
350
        /* Return if extension pack is NOT installed: */
 
351
        if (extPack.isNull())
 
352
        {
 
353
            emit sigStepComplete();
 
354
            return;
 
355
        }
 
356
 
 
357
        /* Get VirtualBox version: */
 
358
        QString strVBoxVersion(vboxGlobal().vboxVersionStringNormalized());
 
359
        QByteArray abVBoxVersion = strVBoxVersion.toUtf8();
 
360
        VBoxVersion vboxVersion(strVBoxVersion);
 
361
 
 
362
        /* Get extension pack version: */
 
363
        QString strExtPackVersion(extPack.GetVersion());
 
364
        QByteArray abExtPackVersion = strExtPackVersion.toUtf8();
 
365
 
 
366
        /* Skip the check in unstable VBox version and if the extension pack
 
367
           is equal to or newer than VBox.
 
368
 
 
369
           Note! Use RTStrVersionCompare for the comparison here as it takes
 
370
                 the beta/alpha/preview/whatever tags into consideration when
 
371
                 comparing versions. */
 
372
        if (   vboxVersion.z() % 2 != 0
 
373
            || RTStrVersionCompare(abExtPackVersion.constData(), abVBoxVersion.constData()) >= 0)
 
374
        {
 
375
            emit sigStepComplete();
 
376
            return;
 
377
        }
 
378
 
 
379
        QString strExtPackEdition(extPack.GetEdition());
 
380
        if (strExtPackEdition.contains("ENTERPRISE"))
 
381
        {
 
382
            /* Inform the user that he should update the extension pack: */
 
383
            msgCenter().askUserToDownloadExtensionPack(GUI_ExtPackName, strExtPackVersion, strVBoxVersion);
 
384
            /* Never try to download for ENTERPRISE version: */
 
385
            emit sigStepComplete();
 
386
            return;
 
387
        }
 
388
 
 
389
        /* Ask the user about extension pack downloading: */
 
390
        if (!msgCenter().warAboutOutdatedExtensionPack(GUI_ExtPackName, strExtPackVersion))
 
391
        {
 
392
            emit sigStepComplete();
 
393
            return;
 
394
        }
 
395
 
 
396
        /* Create and configure the Extension Pack downloader: */
 
397
        UIDownloaderExtensionPack *pDl = UIDownloaderExtensionPack::create();
 
398
        /* After downloading finished => propose to install the Extension Pack: */
 
399
        connect(pDl, SIGNAL(sigDownloadFinished(const QString&, const QString&, QString)),
 
400
                this, SLOT(sltHandleDownloadedExtensionPack(const QString&, const QString&, QString)));
 
401
        /* Also, destroyed downloader is a signal to finish the step: */
 
402
        connect(pDl, SIGNAL(destroyed(QObject*)), this, SIGNAL(sigStepComplete()));
 
403
        /* Start downloading: */
 
404
        pDl->start();
 
405
    }
 
406
 
 
407
    /* Finishing slot: */
 
408
    void sltHandleDownloadedExtensionPack(const QString &strSource, const QString &strTarget, QString strDigest)
 
409
    {
 
410
        /* Warn the user about extension pack was downloaded and saved, propose to install it: */
 
411
        if (msgCenter().proposeInstallExtentionPack(GUI_ExtPackName, strSource, QDir::toNativeSeparators(strTarget)))
 
412
            UIGlobalSettingsExtension::doInstallation(strTarget, strDigest, windowManager().networkManagerOrMainWindowShown(), NULL);
 
413
    }
 
414
};
 
415
 
 
416
/* UIUpdateManager stuff: */
 
417
UIUpdateManager* UIUpdateManager::m_pInstance = 0;
 
418
 
 
419
/* static */
 
420
void UIUpdateManager::schedule()
 
421
{
 
422
    /* Ensure instance is NOT created: */
 
423
    if (m_pInstance)
 
424
        return;
 
425
 
 
426
    /* Create instance: */
 
427
    new UIUpdateManager;
 
428
}
 
429
 
 
430
/* static */
 
431
void UIUpdateManager::shutdown()
 
432
{
 
433
    /* Ensure instance is created: */
 
434
    if (!m_pInstance)
 
435
        return;
 
436
 
 
437
    /* Delete instance: */
 
438
    delete m_pInstance;
 
439
}
 
440
 
 
441
void UIUpdateManager::sltForceCheck()
 
442
{
 
443
    /* Force call for new version check: */
 
444
    sltCheckIfUpdateIsNecessary(true /* force call */);
 
445
}
 
446
 
 
447
UIUpdateManager::UIUpdateManager()
 
448
    : m_pQueue(new UIUpdateQueue(this))
 
449
    , m_fIsRunning(false)
 
450
    , m_uTime(1 /* day */ * 24 /* hours */ * 60 /* minutes */ * 60 /* seconds */ * 1000 /* ms */)
 
451
{
 
452
    /* Prepare instance: */
 
453
    if (m_pInstance != this)
 
454
        m_pInstance = this;
 
455
 
 
456
    /* Configure queue: */
 
457
    connect(m_pQueue, SIGNAL(sigQueueFinished()), this, SLOT(sltHandleUpdateFinishing()));
 
458
 
 
459
#ifdef VBOX_WITH_UPDATE_REQUEST
 
460
    /* Ask updater to check for the first time: */
 
461
    CVirtualBox vbox = vboxGlobal().virtualBox();
 
462
    if (VBoxGlobal::shouldWeAllowApplicationUpdate(vbox) &&
 
463
        !vboxGlobal().isVMConsoleProcess())
 
464
        QTimer::singleShot(0, this, SLOT(sltCheckIfUpdateIsNecessary()));
 
465
#endif /* VBOX_WITH_UPDATE_REQUEST */
 
466
}
 
467
 
 
468
UIUpdateManager::~UIUpdateManager()
 
469
{
 
470
    /* Cleanup instance: */
 
471
    if (m_pInstance == this)
 
472
        m_pInstance = 0;
 
473
}
 
474
 
 
475
void UIUpdateManager::sltCheckIfUpdateIsNecessary(bool fForceCall /* = false */)
 
476
{
 
477
    /* If already running: */
 
478
    if (m_fIsRunning)
 
479
    {
 
480
        /* And we have a force-call: */
 
481
        if (fForceCall)
 
482
        {
 
483
            /* Just show Network Access Manager: */
 
484
            gNetworkManager->show();
 
485
        }
 
486
        return;
 
487
    }
 
488
 
 
489
    /* Set as running: */
 
490
    m_fIsRunning = true;
 
491
 
 
492
    /* Load/decode curent update data: */
 
493
    VBoxUpdateData currentData(vboxGlobal().virtualBox().GetExtraData(GUI_UpdateDate));
 
494
 
 
495
    /* If update is really necessary: */
 
496
    if (fForceCall || currentData.isNeedToCheck())
 
497
    {
 
498
        /* Prepare update queue: */
 
499
        new UIUpdateStepVirtualBox(m_pQueue, fForceCall);
 
500
        new UIUpdateStepVirtualBoxExtensionPack(m_pQueue, fForceCall);
 
501
        /* Start update queue: */
 
502
        m_pQueue->start();
 
503
    }
 
504
    else
 
505
        sltHandleUpdateFinishing();
 
506
}
 
507
 
 
508
void UIUpdateManager::sltHandleUpdateFinishing()
 
509
{
 
510
    /* Load/decode curent update data: */
 
511
    VBoxUpdateData currentData(vboxGlobal().virtualBox().GetExtraData(GUI_UpdateDate));
 
512
    /* Encode/save new update data: */
 
513
    VBoxUpdateData newData(currentData.periodIndex(), currentData.branchIndex());
 
514
    vboxGlobal().virtualBox().SetExtraData(GUI_UpdateDate, newData.data());
 
515
 
 
516
#ifdef VBOX_WITH_UPDATE_REQUEST
 
517
    /* Ask updater to check for the next time: */
 
518
    QTimer::singleShot(m_uTime, this, SLOT(sltCheckIfUpdateIsNecessary()));
 
519
#endif /* VBOX_WITH_UPDATE_REQUEST */
 
520
 
 
521
    /* Set as not running: */
 
522
    m_fIsRunning = false;
 
523
}
 
524
 
 
525
#include "UIUpdateManager.moc"
 
526