2
* Copyright (C) 2014 Canonical Ltd
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Diego Sarmentero <diego.sarmentero@canonical.com>
22
#include <QDBusInterface>
23
#include <QJsonDocument>
24
#include <QJsonObject>
27
#include <QProcessEnvironment>
29
#include <QStringList>
30
#include <ssoservice.h>
32
#include "update_manager.h"
35
using namespace UbuntuOne;
37
#define CLICK_COMMAND "click"
39
#define CHECK_CREDENTIALS "IGNORE_CREDENTIALS"
41
#define CHECK_CREDENTIALS "CHECK_CREDENTIALS"
44
const QString TEST_APP = "com.ubuntu.developer.testclick";
46
namespace UpdatePlugin {
48
UpdateManager *UpdateManager::m_instance = 0;
50
UpdateManager *UpdateManager::instance()
53
m_instance = new UpdateManager;
58
UpdateManager::UpdateManager(QObject *parent):
60
m_systemCheckingUpdate(false),
61
m_clickCheckingUpdate(false),
66
QObject::connect(&m_service, SIGNAL(credentialsFound(const Token&)),
67
this, SLOT(handleCredentialsFound(Token)));
68
QObject::connect(&m_service, SIGNAL(credentialsNotFound()),
69
this, SIGNAL(credentialsNotFound()));
70
QObject::connect(&m_service, SIGNAL(credentialsNotFound()),
71
this, SLOT(clickUpdateNotAvailable()));
72
QObject::connect(&m_service, SIGNAL(credentialsDeleted()),
73
this, SIGNAL(credentialsDeleted()));
74
QObject::connect(&m_service, SIGNAL(credentialsDeleted()),
75
this, SLOT(clickUpdateNotAvailable()));
77
QObject::connect(&m_process, SIGNAL(finished(int)),
78
this, SLOT(processOutput()));
80
QObject::connect(&m_network, SIGNAL(updatesFound()),
81
this, SLOT(processUpdates()));
82
QObject::connect(&m_network, SIGNAL(updatesNotFound()),
83
this, SLOT(clickUpdateNotAvailable()));
84
QObject::connect(&m_network, SIGNAL(errorOccurred()),
85
this, SIGNAL(errorFound()));
86
QObject::connect(&m_network, SIGNAL(networkError()),
87
this, SIGNAL(networkError()));
88
QObject::connect(&m_network, SIGNAL(serverError()),
89
this, SIGNAL(serverError()));
90
QObject::connect(&m_network, SIGNAL(credentialError()),
91
this, SLOT(handleCredentialsFailed()));
92
QObject::connect(&m_network,
93
SIGNAL(clickTokenObtained(Update*, const QString&)),
94
this, SLOT(clickTokenReceived(Update*, const QString&)));
96
QObject::connect(&m_systemUpdate, SIGNAL(updateAvailable(const QString&, Update*)),
97
this, SLOT(registerSystemUpdate(const QString&, Update*)));
98
QObject::connect(&m_systemUpdate, SIGNAL(updateNotFound()),
99
this, SLOT(systemUpdateNotAvailable()));
100
QObject::connect(&m_systemUpdate, SIGNAL(downloadModeChanged()),
101
SIGNAL(downloadModeChanged()));
102
QObject::connect(&m_systemUpdate, SIGNAL(updateDownloaded()),
103
SLOT(updateDownloaded()));
104
QObject::connect(&m_systemUpdate, SIGNAL(updateProcessFailed(const QString&)),
105
SIGNAL(updateProcessFailed(QString)));
106
QObject::connect(&m_systemUpdate, SIGNAL(updateFailed(int, QString)),
107
SLOT(updateFailed(int, QString)));
108
QObject::connect(&m_systemUpdate, SIGNAL(updatePaused(int)),
109
SLOT(systemUpdatePaused(int)));
110
QObject::connect(&m_systemUpdate, SIGNAL(downloadStarted()),
111
SLOT(systemUpdateDownloadStarted()));
112
QObject::connect(&m_systemUpdate, SIGNAL(updateProgress(int, double)),
113
SLOT(systemUpdateProgress(int, double)));
114
QObject::connect(&m_systemUpdate, SIGNAL(rebooting(bool)),
115
SIGNAL(rebooting(bool)));
118
UpdateManager::~UpdateManager()
122
void UpdateManager::clickUpdateNotAvailable()
124
m_clickCheckingUpdate = false;
126
updateNotAvailable();
129
void UpdateManager::systemUpdateNotAvailable()
131
m_systemCheckingUpdate = false;
133
updateNotAvailable();
136
void UpdateManager::updateNotAvailable()
139
if (m_checkingUpdates == 0 && m_model.count() == 0) {
140
Q_EMIT updatesNotFound();
144
void UpdateManager::reportCheckState()
146
if (!m_clickCheckingUpdate && !m_systemCheckingUpdate) {
147
Q_EMIT checkFinished();
151
void UpdateManager::checkUpdates()
153
m_systemCheckingUpdate = true;
154
m_clickCheckingUpdate = true;
155
m_checkingUpdates = 2;
158
Q_EMIT modelChanged();
159
bool enabled = enableAutopilotMode();
161
// If we're in testing mode, always consider updates for TEST_APP
163
Update *app = new Update();
164
app->initializeApplication(TEST_APP, QString("Test App"), QString("1.0"));
165
m_apps.insert(app->getPackageName(), app);
168
if (getCheckForCredentials()) {
169
m_systemUpdate.checkForUpdate();
170
m_service.getCredentials();
171
} else if (enabled) {
172
systemUpdateNotAvailable();
173
Token token("", "", "", "");
174
handleCredentialsFound(token);
176
systemUpdateNotAvailable();
177
clickUpdateNotAvailable();
181
void UpdateManager::handleCredentialsFound(Token token)
183
m_network.setUbuntuOneToken(token);
184
QStringList args("list");
185
args << "--manifest";
186
QString command = getClickCommand();
187
m_process.start(command, args);
190
void UpdateManager::handleCredentialsFailed()
192
m_service.invalidateCredentials();
195
QString UpdateManager::getClickCommand()
197
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
198
QString command = environment.value("CLICK_COMMAND", QString(CLICK_COMMAND));
202
bool UpdateManager::getCheckForCredentials()
204
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
205
QString value = environment.value("IGNORE_CREDENTIALS", QString(CHECK_CREDENTIALS));
206
return value == "CHECK_CREDENTIALS";
209
bool UpdateManager::enableAutopilotMode()
211
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
212
QString value = environment.value("AUTOPILOT_ENABLED", QString("AUTOPILOT_DISABLED"));
213
return value == "AUTOPILOT_ENABLED";
216
void UpdateManager::processOutput()
218
QString output(m_process.readAllStandardOutput());
220
QJsonDocument document = QJsonDocument::fromJson(output.toUtf8());
222
QJsonArray array = document.array();
225
for (i = 0; i < array.size(); i++) {
226
QJsonObject object = array.at(i).toObject();
227
QString name = object.value("name").toString();
228
QString title = object.value("title").toString();
229
QString version = object.value("version").toString();
230
Update *app = new Update();
231
app->initializeApplication(name, title, version);
232
m_apps[app->getPackageName()] = app;
235
m_network.checkForNewVersions(m_apps);
238
void UpdateManager::processUpdates()
240
m_clickCheckingUpdate = false;
241
bool updateAvailable = false;
242
foreach (QString id, m_apps.keys()) {
243
if (m_model.contains(id))
245
Update *app = m_apps.value(id);
246
QString packagename(UBUNTU_PACKAGE_NAME);
247
if(app->getPackageName() != packagename && app->updateRequired()) {
248
updateAvailable = true;
249
m_model.append(QVariant::fromValue(app));
253
if (updateAvailable) {
254
Q_EMIT modelChanged();
255
Q_EMIT updateAvailableFound(false);
260
void UpdateManager::registerSystemUpdate(const QString& packageName, Update *update)
262
QString packagename(UBUNTU_PACKAGE_NAME);
263
if (!m_apps.contains(packagename)) {
264
m_apps[packageName] = update;
265
m_model.insert(0, QVariant::fromValue(update));
266
Q_EMIT modelChanged();
267
Q_EMIT updateAvailableFound(update->updateState());
268
if (update->getRemoteVersion() == m_latestDownload)
271
m_systemCheckingUpdate = false;
276
void UpdateManager::updateDownloaded()
278
QString packagename(UBUNTU_PACKAGE_NAME);
279
if (m_apps.contains(packagename)) {
280
Update *update = m_apps[packagename];
281
update->setSelected(false);
282
update->setUpdateState(false);
283
update->setUpdateReady(true);
284
m_latestDownload = update->getRemoteVersion();
285
Q_EMIT systemUpdateDownloaded();
288
void UpdateManager::updateFailed(int consecutiveFailureCount, QString lastReason)
290
QString packagename(UBUNTU_PACKAGE_NAME);
291
if (m_apps.contains(packagename)) {
292
Update *update = m_apps[packagename];
293
update->setSelected(false);
294
update->setUpdateState(false);
295
update->setDownloadProgress(0);
296
Q_EMIT systemUpdateFailed(consecutiveFailureCount, lastReason);
300
void UpdateManager::systemUpdatePaused(int value)
302
QString packagename(UBUNTU_PACKAGE_NAME);
303
if (m_apps.contains(packagename)) {
304
Update *update = m_apps[packagename];
305
update->setSelected(true);
306
update->setUpdateState(false);
307
update->setDownloadProgress(value);
308
update->setStatus(Update::Paused);
312
void UpdateManager::systemUpdateDownloadStarted()
314
QString packagename(UBUNTU_PACKAGE_NAME);
315
if (m_apps.contains(packagename)) {
316
Update *update = m_apps[packagename];
317
update->setSelected(true);
318
update->setUpdateState(true);
319
update->setStatus(Update::Downloading);
323
void UpdateManager::systemUpdateProgress(int value, double eta)
326
QString packagename(UBUNTU_PACKAGE_NAME);
327
if (m_apps.contains(packagename)) {
328
Update *update = m_apps[packagename];
329
update->setDownloadProgress(value);
333
void UpdateManager::startDownload(const QString &packagename)
335
m_apps[packagename]->setUpdateState(true);
336
if (m_apps[packagename]->systemUpdate()) {
337
m_systemUpdate.downloadUpdate();
339
downloadApp(m_apps[packagename]);
343
void UpdateManager::forceAllowGSMDownload(const QString &packagename)
345
if (!m_apps[packagename]->systemUpdate())
348
m_apps[packagename]->setUpdateState(true);
349
m_systemUpdate.forceAllowGSMDownload();
352
void UpdateManager::retryDownload(const QString &packagename)
354
if (m_apps[packagename]->systemUpdate()) {
355
Update *update = m_apps.take(packagename);
356
m_systemUpdate.cancelUpdate();
358
update->deleteLater();
359
Q_EMIT modelChanged();
360
m_systemUpdate.checkForUpdate();
362
startDownload(packagename);
366
void UpdateManager::pauseDownload(const QString &packagename)
368
m_apps[packagename]->setUpdateState(false);
369
m_systemUpdate.pauseDownload();
372
void UpdateManager::downloadApp(Update *app)
374
m_network.getClickToken(app, app->downloadUrl());
377
void UpdateManager::clickTokenReceived(Update *app, const QString &clickToken)
380
app->setClickToken(clickToken);
381
app->setDownloadUrl(app->getClickUrl());
384
void UpdateManager::updateClickScope()
386
// Refresh click scope
387
QDBusMessage signal = QDBusMessage::createSignal(
388
"/com/canonical/unity/scopes",
389
"com.canonical.unity.scopes",
390
"InvalidateResults");
391
signal << "clickscope";
392
QDBusConnection::sessionBus().send(signal);
394
// When a click update is complete, emit modelChanged
395
Q_EMIT modelChanged();