FwupdBackend.cpp 25.8 KB
Newer Older
Abhijeet  sharma's avatar
Abhijeet sharma committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/***************************************************************************
 *   Copyright © 2013 Aleix Pol Gonzalez <aleixpol@blue-systems.com>       *
 *   Copyright © 2018 Abhijeet Sharma <sharma.abhijeet2096@gmail.com>      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU General Public License as        *
 *   published by the Free Software Foundation; either version 2 of        *
 *   the License or (at your option) version 3 or any later version        *
 *   accepted by the membership of KDE e.V. (or its successor approved     *
 *   by the membership of KDE e.V.), which shall act as a proxy            *
 *   defined in Section 14 of version 3 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 ***************************************************************************/

#include "FwupdBackend.h"
#include "FwupdResource.h"
#include "FwupdTransaction.h"
#include "FwupdSourcesBackend.h"
#include <resources/StandardBackendUpdater.h>
#include <resources/SourcesModel.h>
#include <Transaction/Transaction.h>

#include <KAboutData>
#include <KLocalizedString>
#include <KPluginFactory>
#include <KConfigGroup>
#include <KSharedConfig>

DISCOVER_BACKEND_PLUGIN(FwupdBackend)
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
37

Abhijeet  sharma's avatar
Abhijeet sharma committed
38
39
40
41
42
43
44
45
46
FwupdBackend::FwupdBackend(QObject* parent)
    : AbstractResourcesBackend(parent)
    , m_updater(new StandardBackendUpdater(this))
    , m_fetching(true)
{

    QTimer::singleShot(500, this, &FwupdBackend::toggleFetching);
    connect(m_updater, &StandardBackendUpdater::updatesCountChanged, this, &FwupdBackend::updatesCountChanged);

Abhijeet  sharma's avatar
Abhijeet sharma committed
47
    client = fwupd_client_new();
Abhijeet  sharma's avatar
Abhijeet sharma committed
48
49
50
51
52
53
54
55

    populate(QStringLiteral("Releases"));
    SourcesModel::global()->addSourcesBackend(new FwupdSourcesBackend(this));
}

QMap<GChecksumType, QCryptographicHash::Algorithm> FwupdBackend::initHashMap()
{
    QMap<GChecksumType,QCryptographicHash::Algorithm> map;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
56

Abhijeet  sharma's avatar
Abhijeet sharma committed
57
58
59
60
    map.insert(G_CHECKSUM_SHA1,QCryptographicHash::Sha1);
    map.insert(G_CHECKSUM_SHA256,QCryptographicHash::Sha256);
    map.insert(G_CHECKSUM_SHA512,QCryptographicHash::Sha512);
    map.insert(G_CHECKSUM_MD5,QCryptographicHash::Md5);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
61

Abhijeet  sharma's avatar
Abhijeet sharma committed
62
63
64
65
66
    return map;
}

FwupdBackend::~FwupdBackend()
{
Abhijeet  sharma's avatar
Abhijeet sharma committed
67
    g_object_unref(client);
Abhijeet  sharma's avatar
Abhijeet sharma committed
68
69
70
71
}

QString FwupdBackend::buildDeviceID(FwupdDevice* device)
{
Abhijeet  sharma's avatar
Abhijeet sharma committed
72
    QString DeviceID = QString::fromUtf8(fwupd_device_get_id(device));
Abhijeet  sharma's avatar
Abhijeet sharma committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    DeviceID.replace(QLatin1Char('/'),QLatin1Char('_'));
    return QStringLiteral("org.fwupd.%1.device").arg(DeviceID);
}

void FwupdBackend::addResourceToList(FwupdResource* res)
{
    res->setState(FwupdResource::Upgradeable);
    m_resources.insert(res->packageName().toLower(), res);
}

FwupdResource * FwupdBackend::createDevice(FwupdDevice *device)
{
    const QString name = QString::fromUtf8(fwupd_device_get_name(device));
    FwupdResource* res = new FwupdResource(name, true, this);
    res->setId(buildDeviceID(device));
    res->addCategories(QStringLiteral("Releases"));
89
90
    if(fwupd_device_get_icons(device)->len >= 1)
        res->setIconName(QString::fromUtf8((const gchar *)g_ptr_array_index(fwupd_device_get_icons(device),0)));// Check wether given icon exists or not!
Abhijeet  sharma's avatar
Abhijeet sharma committed
91
92
93
94
95
96
97

    setDeviceDetails(res,device);
    return res;
}

FwupdResource * FwupdBackend::createRelease(FwupdDevice *device)
{
Abhijeet  sharma's avatar
Abhijeet sharma committed
98
99
    FwupdRelease *release = fwupd_device_get_release_default(device);
    const QString name = QString::fromUtf8(fwupd_release_get_name(release));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
100
101
102
103
104
105
    auto appstreamId = fwupd_release_get_appstream_id(release);
    if (!appstreamId) {
        qWarning() << "no appstream id for" << name;
        return nullptr;
    }

Abhijeet  sharma's avatar
Abhijeet sharma committed
106
107
    FwupdResource* res = new FwupdResource(name, true, this);

Abhijeet  sharma's avatar
Abhijeet sharma committed
108
109
    res->setDeviceID(QString::fromUtf8(fwupd_device_get_id(device)));
    setReleaseDetails(res,release);
Abhijeet  sharma's avatar
Abhijeet sharma committed
110
    setDeviceDetails(res,device);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
111
    res->setId(QString::fromUtf8(appstreamId));
Abhijeet  sharma's avatar
Abhijeet sharma committed
112
113

    /* the same as we have already */
114
    if(qstrcmp(fwupd_device_get_version(device), fwupd_release_get_version(release)) == 0)
Abhijeet  sharma's avatar
Abhijeet sharma committed
115
116
117
118
119
120
121
    {
        qWarning() << "Fwupd Error: same firmware version as installed";
    }

    return res;

}
Abhijeet  sharma's avatar
Abhijeet sharma committed
122
void FwupdBackend::setReleaseDetails(FwupdResource *res, FwupdRelease *release)
Abhijeet  sharma's avatar
Abhijeet sharma committed
123
124
{
    res->addCategories(QLatin1String("Releases"));
Abhijeet  sharma's avatar
Abhijeet sharma committed
125
126
127
128
    if(fwupd_release_get_summary(release))
        res->setSummary(QString::fromUtf8(fwupd_release_get_summary(release)));
    if(fwupd_release_get_vendor(release))
        res->setVendor(QString::fromUtf8(fwupd_release_get_vendor(release)));
Abhijeet  sharma's avatar
Abhijeet sharma committed
129
130
    if(fwupd_release_get_size(release))
        res->setSize(fwupd_release_get_size(release));
Abhijeet  sharma's avatar
Abhijeet sharma committed
131
132
133
134
135
136
137
138
139
140
    if(fwupd_release_get_version(release))
        res->setVersion(QString::fromUtf8(fwupd_release_get_version(release)));
    if(fwupd_release_get_description(release))
        res->setDescription(QString::fromUtf8((fwupd_release_get_description(release))));
    if(fwupd_release_get_homepage(release))
        res->setHomePage(QUrl(QString::fromUtf8(fwupd_release_get_homepage(release))));
    if(fwupd_release_get_license(release))
        res->setLicense(QString::fromUtf8(fwupd_release_get_license(release)));
    if(fwupd_release_get_uri(release))
        res->m_updateURI = QString::fromUtf8(fwupd_release_get_uri(release));
Abhijeet  sharma's avatar
Abhijeet sharma committed
141
142
143
}
void FwupdBackend::setDeviceDetails(FwupdResource *res, FwupdDevice *dev)
{
Abhijeet  sharma's avatar
Abhijeet sharma committed
144
145
146
147
    res->isLiveUpdatable = fwupd_device_has_flag(dev, FWUPD_DEVICE_FLAG_UPDATABLE);
    res->isOnlyOffline = fwupd_device_has_flag(dev, FWUPD_DEVICE_FLAG_ONLY_OFFLINE);
    res->needsReboot = fwupd_device_has_flag(dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT);
    res->isDeviceRemoval = !fwupd_device_has_flag(dev, FWUPD_DEVICE_FLAG_INTERNAL);
Abhijeet  sharma's avatar
Abhijeet sharma committed
148
    res->needsBootLoader = fwupd_device_has_flag(dev, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
149

Abhijeet  sharma's avatar
Abhijeet sharma committed
150
    GPtrArray *guids = fwupd_device_get_guids(dev);
Abhijeet  sharma's avatar
Abhijeet sharma committed
151
152
    if(guids->len > 0)
    {
Abhijeet  sharma's avatar
Abhijeet sharma committed
153
154
        QString guidStr = QString::fromUtf8((char *)g_ptr_array_index(guids, 0));
        for(uint i = 1; i < guids->len; i++)
Abhijeet  sharma's avatar
Abhijeet sharma committed
155
        {
Abhijeet  sharma's avatar
Abhijeet sharma committed
156
            guidStr += QLatin1Char(',') + QString::fromUtf8((char *)g_ptr_array_index(guids, i));
Abhijeet  sharma's avatar
Abhijeet sharma committed
157
158
159
        }
        res->guidString = guidStr;
    }
Abhijeet  sharma's avatar
Abhijeet sharma committed
160
    if(fwupd_device_get_name(dev))
Abhijeet  sharma's avatar
Abhijeet sharma committed
161
162
    {
        QString vendorName;
Abhijeet  sharma's avatar
Abhijeet sharma committed
163
        vendorName.sprintf("%s",fwupd_device_get_name(dev));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
164

Abhijeet  sharma's avatar
Abhijeet sharma committed
165
166
        if(vendorName.indexOf(QString::fromUtf8(fwupd_device_get_vendor(dev))) == 0)
            vendorName.sprintf("%s %s",fwupd_device_get_vendor(dev), fwupd_device_get_name(dev));
Abhijeet  sharma's avatar
Abhijeet sharma committed
167
168
        res->setName(vendorName);
     }
Abhijeet  sharma's avatar
Abhijeet sharma committed
169
    if(fwupd_device_get_summary(dev))
Abhijeet  sharma's avatar
Abhijeet sharma committed
170
171
172
        res->setSummary(QString::fromUtf8(fwupd_device_get_summary(dev)));
    if(fwupd_device_get_vendor(dev))
        res->setVendor(QString::fromUtf8(fwupd_device_get_vendor(dev)));
Abhijeet  sharma's avatar
Abhijeet sharma committed
173
174
    if(fwupd_device_get_created(dev))
        res->setReleaseDate((QDateTime::fromSecsSinceEpoch(fwupd_device_get_created(dev))).date());
Abhijeet  sharma's avatar
Abhijeet sharma committed
175
176
177
178
    if(fwupd_device_get_version(dev))
        res->setVersion(QString::fromUtf8(fwupd_device_get_version(dev)));
    if(fwupd_device_get_description(dev))
        res->setDescription(QString::fromUtf8((fwupd_device_get_description(dev))));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
179
    res->setIconName(QString::fromUtf8("device-notifier"));
Abhijeet  sharma's avatar
Abhijeet sharma committed
180
181
182
183
184
}

void FwupdBackend::populate(const QString& n)
{
    /* get devices */
Abhijeet  sharma's avatar
Abhijeet sharma committed
185
    g_autoptr(GPtrArray) devices = fwupd_client_get_devices(client, nullptr, nullptr);
Abhijeet  sharma's avatar
Abhijeet sharma committed
186

Abhijeet  sharma's avatar
Abhijeet sharma committed
187
    if(devices)
Abhijeet  sharma's avatar
Abhijeet sharma committed
188
    {
Abhijeet  sharma's avatar
Abhijeet sharma committed
189
        for(uint i = 0; i < devices->len; i++)
Abhijeet  sharma's avatar
Abhijeet sharma committed
190
         {
Abhijeet  sharma's avatar
Abhijeet sharma committed
191
            FwupdDevice *device = (FwupdDevice *)g_ptr_array_index(devices, i);
Abhijeet  sharma's avatar
Abhijeet sharma committed
192
193

            /* Devices Which are not updatable */
Abhijeet  sharma's avatar
Abhijeet sharma committed
194
            if(!fwupd_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE))
Abhijeet  sharma's avatar
Abhijeet sharma committed
195
196
197
198
199
200
201
                continue;

            /* add releases */
            FwupdResource * res = createDevice(device);
            res->addCategories(n);


Abhijeet  sharma's avatar
Abhijeet sharma committed
202
            g_autoptr(GPtrArray) releases = fwupd_client_get_releases(client, res->m_deviceID.toUtf8().constData(), nullptr, nullptr);
Abhijeet  sharma's avatar
Abhijeet sharma committed
203

Abhijeet  sharma's avatar
Abhijeet sharma committed
204
            if(releases)
Abhijeet  sharma's avatar
Abhijeet sharma committed
205
            {
Abhijeet  sharma's avatar
Abhijeet sharma committed
206
                for(uint j = 0; j < releases->len; j++)
Abhijeet  sharma's avatar
Abhijeet sharma committed
207
                {
Abhijeet  sharma's avatar
Abhijeet sharma committed
208
209
                    FwupdRelease *release = (FwupdRelease *)g_ptr_array_index(releases, j);
                    const QString name = QString::fromUtf8(fwupd_release_get_name(release));
Abhijeet  sharma's avatar
Abhijeet sharma committed
210
                    FwupdResource* res_ = new FwupdResource(name, true, this);
Abhijeet  sharma's avatar
Abhijeet sharma committed
211
                    setReleaseDetails(res_, release);
Abhijeet  sharma's avatar
Abhijeet sharma committed
212
213
214
215
216
217
218
219
220
221
222
223
224
225
                    res->m_releases.append(res_);
                }
            }
            /* add all Valid Resources */
            m_resources.insert(res->packageName().toLower(), res);
          }
    }
}


void FwupdBackend::addUpdates()
{
    g_autoptr(GError) error = nullptr;
    g_autoptr(GError) error2 = nullptr;
Abhijeet  sharma's avatar
Abhijeet sharma committed
226
    g_autoptr(GPtrArray) devices = fwupd_client_get_devices(client, nullptr, &error);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
227

Abhijeet  sharma's avatar
Abhijeet sharma committed
228
229
    if(!devices)
    {
Abhijeet  sharma's avatar
Abhijeet sharma committed
230
        if(g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO))
Abhijeet  sharma's avatar
Abhijeet sharma committed
231
232
233
234
        {
            qDebug() << "Fwupd Info: No Devices Found";
            handleError(&error);
        }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
235
        return;
Abhijeet  sharma's avatar
Abhijeet sharma committed
236
    }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
237
238
239
240
241
242
243
244
245
246

    for(uint i = 0; i < devices->len; i++)
    {
        FwupdDevice *device = (FwupdDevice *)g_ptr_array_index(devices, i);

        if(!fwupd_device_has_flag(device, FWUPD_DEVICE_FLAG_SUPPORTED))
            continue;

        /*Device is Locked Needs Unlocking*/
        if(fwupd_device_has_flag(device, FWUPD_DEVICE_FLAG_LOCKED))
Abhijeet  sharma's avatar
Abhijeet sharma committed
247
        {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
248
249
250
251
252
253
            auto res = createDevice(device);
            res->setIsDeviceLocked(true);
            addResourceToList(res);
            connect(res, &FwupdResource::stateChanged, this, &FwupdBackend::updatesCountChanged);
            continue;
        }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
254

Abhijeet  sharma's avatar
Abhijeet sharma committed
255

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
256
257
258
259
260
        g_autoptr(GPtrArray) rels = fwupd_client_get_upgrades(client, fwupd_device_get_id(device), nullptr, &error2);

        if(!rels)
        {
            if(g_error_matches(error2, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO))
Abhijeet  sharma's avatar
Abhijeet sharma committed
261
            {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
262
263
                qWarning() << "Fwupd Error: No Packages Found for "<< fwupd_device_get_id(device);
                handleError(&error2);
Abhijeet  sharma's avatar
Abhijeet sharma committed
264
265
                continue;
            }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
266
267
268
269
270
271
        }
        else
        {
            fwupd_device_add_release(device,(FwupdRelease *)g_ptr_array_index(rels, 0));
            auto res = createApp(device);
            if(res == nullptr)
Abhijeet  sharma's avatar
Abhijeet sharma committed
272
            {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
273
                qWarning() << "Fwupd Error: Cannot Create App From Device";
Abhijeet  sharma's avatar
Abhijeet sharma committed
274
275
276
            }
            else
            {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
277
                if(rels->len > 1)
Abhijeet  sharma's avatar
Abhijeet sharma committed
278
                {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
279
280
                    QString longdescription;
                    for(uint j = 0; j < rels->len; j++)
Abhijeet  sharma's avatar
Abhijeet sharma committed
281
                    {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
282
283
284
285
286
                        FwupdRelease *release = (FwupdRelease *)g_ptr_array_index(rels, j);
                        if(fwupd_release_get_description(release) == nullptr)
                            continue;
                        longdescription += QStringLiteral("Version %1\n").arg(QString::fromUtf8(fwupd_release_get_version(release)));
                        longdescription += QString::fromUtf8(fwupd_release_get_description(release)) + QLatin1Char('\n');
Abhijeet  sharma's avatar
Abhijeet sharma committed
287
                    }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
288
                    res->setDescription(longdescription);
Abhijeet  sharma's avatar
Abhijeet sharma committed
289
                }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
290
                addResourceToList(res);
Abhijeet  sharma's avatar
Abhijeet sharma committed
291
292
293
294
295
296
297
298
            }
        }
    }
}

void FwupdBackend::addHistoricalUpdates()
{
    g_autoptr(GError) error = nullptr;
Abhijeet  sharma's avatar
Abhijeet sharma committed
299
    g_autoptr(FwupdDevice) device = fwupd_client_get_results(client, FWUPD_DEVICE_ID_ANY, nullptr, &error);
Abhijeet  sharma's avatar
Abhijeet sharma committed
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
    if(!device)
    {
        handleError(&error);
    }
    else
    {
        FwupdResource* res = createRelease(device);
        if(!res)
            qWarning() << "Fwupd Error: Cannot Make App for" << fwupd_device_get_id(device);
        else
        {
            addResourceToList(res);
        }
    }
}


QByteArray FwupdBackend::getChecksum(const QUrl filename, QCryptographicHash::Algorithm hashAlgorithm)
{
    QFile f(filename.toString());
Abhijeet  sharma's avatar
Abhijeet sharma committed
320
    if(f.open(QFile::ReadOnly))
Abhijeet  sharma's avatar
Abhijeet sharma committed
321
322
    {
        QCryptographicHash hash(hashAlgorithm);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
323
        if(hash.addData(&f))
Abhijeet  sharma's avatar
Abhijeet sharma committed
324
325
326
327
328
329
330
331
332
        {
            return hash.result().toHex();
        }
    }
    return QByteArray();
}

FwupdResource* FwupdBackend::createApp(FwupdDevice *device)
{
Abhijeet  sharma's avatar
Abhijeet sharma committed
333
    FwupdRelease *release = fwupd_device_get_release_default(device);
Abhijeet  sharma's avatar
Abhijeet sharma committed
334
335
336
337
    GPtrArray *checksums;
    FwupdResource* app = createRelease(device);

    /* update unsupported */
Abhijeet  sharma's avatar
Abhijeet sharma committed
338
    if(!app->isLiveUpdatable)
Abhijeet  sharma's avatar
Abhijeet sharma committed
339
340
341
342
343
344
    {
        qWarning() << "Fwupd Error: " << app->m_name << "[" << app->m_id << "]" << "cannot be updated ";
        return nullptr;
    }

    /* Important Attributes missing */
Abhijeet  sharma's avatar
Abhijeet sharma committed
345
    if(app->m_id.isNull())
Abhijeet  sharma's avatar
Abhijeet sharma committed
346
347
348
349
    {
        qWarning() << "Fwupd Error: No id for firmware";
        return nullptr;
    }
Abhijeet  sharma's avatar
Abhijeet sharma committed
350
    if(app->m_version.isNull())
Abhijeet  sharma's avatar
Abhijeet sharma committed
351
352
353
354
    {
        qWarning() << "Fwupd Error: No version! for " << app->m_id;
        return nullptr;
    }
Abhijeet  sharma's avatar
Abhijeet sharma committed
355
    if(app->m_updateVersion.isNull())
Abhijeet  sharma's avatar
Abhijeet sharma committed
356
357
358
359
    {
        qWarning() << "Fwupd Error: No update-version! for " << app->m_id;
        return nullptr;
    }
Abhijeet  sharma's avatar
Abhijeet sharma committed
360
361
    checksums = fwupd_release_get_checksums(release);
    if(checksums->len == 0)
Abhijeet  sharma's avatar
Abhijeet sharma committed
362
363
364
365
    {
        qWarning() << "Fwupd Error: " << app->m_name << "[" << app->m_id << "]" << "(" << app->m_updateVersion << ")" "has no checksums, ignoring as unsafe";
        return nullptr;
    }
Abhijeet  sharma's avatar
Abhijeet sharma committed
366
    const QUrl update_uri(QString::fromUtf8(fwupd_release_get_uri(release)));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
367

Abhijeet  sharma's avatar
Abhijeet sharma committed
368
    if(!update_uri.isValid())
Abhijeet  sharma's avatar
Abhijeet sharma committed
369
370
371
372
373
374
375
376
    {
        qWarning() << "Fwupd Error: No Update URI available for" << app->m_name <<  "[" << app->m_id << "]";
        return nullptr;
    }

    /* Checking for firmware in the cache? */
    QFileInfo basename = QFileInfo(update_uri.path());
    const QUrl filename_cache = cacheFile(QStringLiteral("fwupd"), basename);
Abhijeet  sharma's avatar
Abhijeet sharma committed
377
    if(filename_cache.isEmpty())
Abhijeet  sharma's avatar
Abhijeet sharma committed
378
379
        return nullptr;

Abhijeet  sharma's avatar
Abhijeet sharma committed
380
    if(filename_cache.isLocalFile())
Abhijeet  sharma's avatar
Abhijeet sharma committed
381
    {
Abhijeet  sharma's avatar
Abhijeet sharma committed
382
        QByteArray checksum_tmp = QByteArray(fwupd_checksum_get_by_kind(checksums, G_CHECKSUM_SHA1));
Abhijeet  sharma's avatar
Abhijeet sharma committed
383
384

        /* Currently LVFS supports SHA1 only*/
Abhijeet  sharma's avatar
Abhijeet sharma committed
385
        if(checksum_tmp.isNull())
Abhijeet  sharma's avatar
Abhijeet sharma committed
386
387
388
389
        {
            qWarning() << "Fwupd Error: No valid checksum for" << filename_cache;
        }
        QByteArray checksum =  getChecksum(filename_cache, QCryptographicHash::Sha1);
Abhijeet  sharma's avatar
Abhijeet sharma committed
390
        if(checksum.isNull() || checksum_tmp.isNull())
Abhijeet  sharma's avatar
Abhijeet sharma committed
391
            return nullptr;
Abhijeet  sharma's avatar
Abhijeet sharma committed
392
        if(checksum_tmp != checksum)
Abhijeet  sharma's avatar
Abhijeet sharma committed
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
        {
            qWarning() << "Fwupd Error: " << filename_cache << " does not match checksum, expected" << checksum_tmp << "got" << checksum;
            QFile::remove((filename_cache.toString()));
            return nullptr;
        }
    }

    /* link file to application and return its reference */
    app->m_file = filename_cache.toString();
    return app;
}

void FwupdBackend::saveFile(QNetworkReply *reply)
{
    QString filename = this->m_downloadFile[reply->url()];
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
408
    if(reply->error() == QNetworkReply::NoError)
Abhijeet  sharma's avatar
Abhijeet sharma committed
409
410
411
    {
        QByteArray Data = reply->readAll();
        QFile file(filename);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
412
        if(file.open(QIODevice::WriteOnly))
Abhijeet  sharma's avatar
Abhijeet sharma committed
413
414
415
416
417
418
419
420
421
422
423
424
425
426
        {
            file.write(Data);
        }
        else
        {
            qWarning() << "Fwupd Error: Cannot Open File to write Data";
        }
        file.close();
        delete reply;
    }
}

bool FwupdBackend::downloadFile(const QUrl &uri,const QString &filename)
{
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
427
    QScopedPointer<QNetworkAccessManager> manager(new QNetworkAccessManager(this));
Abhijeet  sharma's avatar
Abhijeet sharma committed
428
429
    this->m_downloadFile.insert(uri,filename);
    QEventLoop loop;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
430
    QTimer getTimer;
Abhijeet  sharma's avatar
Abhijeet sharma committed
431
    connect(&getTimer, &QTimer::timeout, &loop, &QEventLoop::quit);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
432
    connect(manager.data(), &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
Abhijeet  sharma's avatar
Abhijeet sharma committed
433
434
435
436
437
438
439
    QNetworkReply *reply = manager->get(QNetworkRequest(uri));
    getTimer.start(600000); // 60 Seconds TimeOout Period
    loop.exec();
    if(!reply)
    {
        return false;
    }
Abhijeet  sharma's avatar
Abhijeet sharma committed
440
    else if(QNetworkReply::NoError != reply->error() )
Abhijeet  sharma's avatar
Abhijeet sharma committed
441
442
443
444
445
446
447
448
449
450
451
452
453
    {
        return false;
    }
    else
    {
        saveFile(reply);
    }
    return true;
}

bool FwupdBackend::refreshRemotes(uint cacheAge)
{
    g_autoptr(GError) error = nullptr;
Abhijeet  sharma's avatar
Abhijeet sharma committed
454
455
    g_autoptr(GPtrArray) remotes = fwupd_client_get_remotes(client, nullptr, &error);
    if(!remotes)
Abhijeet  sharma's avatar
Abhijeet sharma committed
456
        return false;
Abhijeet  sharma's avatar
Abhijeet sharma committed
457
    for(uint i = 0; i < remotes->len; i++)
Abhijeet  sharma's avatar
Abhijeet sharma committed
458
459
460
    {
        FwupdRemote *remote = (FwupdRemote *)g_ptr_array_index(remotes, i);
        /*Remotes disabled by user so ignore*/
Abhijeet  sharma's avatar
Abhijeet sharma committed
461
        if(!fwupd_remote_get_enabled(remote))
Abhijeet  sharma's avatar
Abhijeet sharma committed
462
463
            continue;
        /*Local Remotes Ignore*/
Abhijeet  sharma's avatar
Abhijeet sharma committed
464
        if(fwupd_remote_get_kind(remote) == FWUPD_REMOTE_KIND_LOCAL)
Abhijeet  sharma's avatar
Abhijeet sharma committed
465
466
            continue;
        /*Refresh the left ones*/
Abhijeet  sharma's avatar
Abhijeet sharma committed
467
        if(!refreshRemote(remote, cacheAge))
Abhijeet  sharma's avatar
Abhijeet sharma committed
468
469
470
471
472
473
474
475
            return false;
    }
    return true;
}

bool FwupdBackend::refreshRemote(FwupdRemote* remote, uint cacheAge)
{
    g_autoptr(GError) error = nullptr;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
476
477

    if(fwupd_remote_get_filename_cache_sig(remote) == nullptr)
Abhijeet  sharma's avatar
Abhijeet sharma committed
478
    {
Abhijeet  sharma's avatar
Abhijeet sharma committed
479
        qWarning() << "Fwupd Error: " << "Remote " << fwupd_remote_get_id(remote) << "has no cache signature!";
Abhijeet  sharma's avatar
Abhijeet sharma committed
480
481
        return false;
    }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
482

Abhijeet  sharma's avatar
Abhijeet sharma committed
483
    /* check cache age */
Abhijeet  sharma's avatar
Abhijeet sharma committed
484
    if(cacheAge > 0)
Abhijeet  sharma's avatar
Abhijeet sharma committed
485
486
487
    {
        quint64 age = fwupd_remote_get_age(remote);
        uint tmp = age < std::numeric_limits<uint>::max() ? (uint) age : std::numeric_limits<uint>::max();
Abhijeet  sharma's avatar
Abhijeet sharma committed
488
        if(tmp < cacheAge)
Abhijeet  sharma's avatar
Abhijeet sharma committed
489
        {
Abhijeet  sharma's avatar
Abhijeet sharma committed
490
            qDebug() << "Fwupd Info:" << fwupd_remote_get_id(remote) << "is only" << tmp << "seconds old, so ignoring refresh! ";
Abhijeet  sharma's avatar
Abhijeet sharma committed
491
492
493
            return true;
        }
    }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
494
495

    QString cacheId = QStringLiteral("fwupd/remotes.d/%1").arg(QString::fromUtf8(fwupd_remote_get_id(remote)));
Abhijeet  sharma's avatar
Abhijeet sharma committed
496
    QFileInfo basenameSig = QFileInfo(QString::fromUtf8(g_path_get_basename(fwupd_remote_get_filename_cache_sig(remote))));
Abhijeet  sharma's avatar
Abhijeet sharma committed
497
    const QUrl filenameSig = cacheFile(cacheId, basenameSig);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
498

Abhijeet  sharma's avatar
Abhijeet sharma committed
499
    if(filenameSig.isEmpty())
Abhijeet  sharma's avatar
Abhijeet sharma committed
500
        return false;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
501

Abhijeet  sharma's avatar
Abhijeet sharma committed
502
503
504
505
    /* download the signature first*/
    const QUrl urlSig(QString::fromUtf8(fwupd_remote_get_metadata_uri_sig(remote)));
    qDebug() << "Fwupd Info: downloading remotes signatures ...";

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
506

Abhijeet  sharma's avatar
Abhijeet sharma committed
507
508
509
510
511
512
513
    const QUrl filenameSig_(filenameSig.toString() + QStringLiteral(".tmp"));

    if(!downloadFile(urlSig,filenameSig_.toString()))
    {
        qDebug() << "Fwupd Info: remote signature download failed ...";
        return false;
    }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
514

Abhijeet  sharma's avatar
Abhijeet sharma committed
515
516
517
    QMap<GChecksumType,QCryptographicHash::Algorithm> map = initHashMap();
    QCryptographicHash::Algorithm hashAlgorithm = map[(fwupd_checksum_guess_kind(fwupd_remote_get_checksum(remote)))];
    QByteArray hash = getChecksum(filenameSig_,hashAlgorithm);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
518

Abhijeet  sharma's avatar
Abhijeet sharma committed
519
    if((fwupd_remote_get_checksum(remote) == hash) && filenameSig.isLocalFile())
Abhijeet  sharma's avatar
Abhijeet sharma committed
520
521
522
523
524
525
    {
        qDebug() << "Fwupd Info: signature of" <<  urlSig.toString() << "is unchanged";
        return true;
    }
    else
        QFile::remove(filenameSig.toString());
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
526

Abhijeet  sharma's avatar
Abhijeet sharma committed
527
528
    /* save to a file */
    qDebug() << "Fwupd Info: saving new remote signature to:" << filenameSig.toString();
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
529

Abhijeet  sharma's avatar
Abhijeet sharma committed
530
    if(!(QFile::copy(filenameSig_.toString(), filenameSig.toString())))
Abhijeet  sharma's avatar
Abhijeet sharma committed
531
532
533
534
535
536
537
538
539
    {
        QFile::remove(filenameSig_.toString());
        qWarning() << "Fwupd Error: cannot save remote signature";
        return false;
    }
    QFile::remove(filenameSig_.toString());

    QFileInfo basename = QFileInfo(QString::fromUtf8(g_path_get_basename(fwupd_remote_get_filename_cache(remote))));
    const QUrl filename = cacheFile(cacheId, basename);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
540

Abhijeet  sharma's avatar
Abhijeet sharma committed
541
    if(filename.isEmpty())
Abhijeet  sharma's avatar
Abhijeet sharma committed
542
        return false;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
543

Abhijeet  sharma's avatar
Abhijeet sharma committed
544
545
546
    qDebug() << "Fwupd Info: saving new firmware metadata to:" <<  filename.toString();

    const QUrl url(QString::fromUtf8(fwupd_remote_get_metadata_uri(remote)));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
547
    if(!downloadFile(url, filename.toString()))
Abhijeet  sharma's avatar
Abhijeet sharma committed
548
549
550
551
552
    {
        qWarning() << "Fwupd Error: cannot download file : " << filename.toString() ;
        return false;
    }
    /* Sending Metadata to fwupd Daemon*/
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
553
    if(!fwupd_client_update_metadata(client, fwupd_remote_get_id(remote), filename.toString().toUtf8().constData(), filenameSig.toString().toUtf8().constData(), nullptr, &error))
Abhijeet  sharma's avatar
Abhijeet sharma committed
554
555
556
557
558
559
560
561
562
563
564
565
566
    {
        handleError(&error);
        return false;
    }
    return true;
}

void FwupdBackend::handleError(GError **perror)
{
    GError *error = perror != nullptr ? *perror : nullptr;

    if(!error)
        return;
Abhijeet  sharma's avatar
Abhijeet sharma committed
567
    switch(error->code)
Abhijeet  sharma's avatar
Abhijeet sharma committed
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
    {
        case FWUPD_ERROR_ALREADY_PENDING:
            qWarning() << "Fwupd Error: FWUPD_ERROR_ALREADY_PENDING";
            Q_EMIT passiveMessage(i18n("FWUPD ERROR ALREADY PENDING!"));
            break;
        case FWUPD_ERROR_INVALID_FILE:
            qWarning() << "Fwupd Error: FWUPD_ERROR_INVALID_FILE";
            Q_EMIT passiveMessage(i18n("FWUPD ERROR INVALID FILE"));
            break;
        case FWUPD_ERROR_NOT_SUPPORTED:
            qWarning() << "Fwupd Error: FWUPD_ERROR_NOT_SUPPORTED";
            Q_EMIT passiveMessage(i18n("FWUPD ERROR NOT SUPPORTED"));
            break;
        case FWUPD_ERROR_AUTH_FAILED:
            qWarning() << "Fwupd Error: FWUPD_ERROR_AUTH_FAILED";
            Q_EMIT passiveMessage(i18n("FWUPD ERROR AUTH FAILED"));
            break;
        case FWUPD_ERROR_SIGNATURE_INVALID:
            qWarning() << "Fwupd Error: FWUPD_ERROR_SIGNATURE_INVALID";
            Q_EMIT passiveMessage(i18n("FWUPD ERROR SIGNATURE INVALID"));
            break;
        case FWUPD_ERROR_AC_POWER_REQUIRED:
            qWarning() << "Fwupd Error: FWUPD_ERROR_AC_POWER_REQUIRED";
            Q_EMIT passiveMessage(i18n("FWUPD ERROR AC POWER REQUIRED"));
           break;
        default:
            qWarning() << "Fwupd Error: Unknown Error " << error->code;
            break;
    }
}

const QUrl FwupdBackend::cacheFile(const QString &kind,const QFileInfo &resource)
{
    QString basename = resource.fileName();
    const QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
    const QUrl cacheDirFile = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1Char('/') + kind);
    const QUrl fileUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1Char('/') + kind + QLatin1Char('/') + basename);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
605
606

    if(!QFileInfo::exists(cacheDirFile.toLocalFile()) && !cacheDir.mkpath(kind))
Abhijeet  sharma's avatar
Abhijeet sharma committed
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
    {
        qWarning() << "Fwupd Error: cannot make  cache directory!";
        return QUrl();
    }
    return QUrl(fileUrl.toString().remove(QStringLiteral("file://")));
}

void FwupdBackend::toggleFetching()
{
    m_fetching = !m_fetching;
    refreshRemotes(30*24*60*60); //  Nicer Way to put time? currently 30 days in seconds
    addUpdates();
    addHistoricalUpdates();
    emit fetchingChanged();
}

int FwupdBackend::updatesCount() const
{
    return m_updater->updatesCount();
}

ResultsStream* FwupdBackend::search(const AbstractResourcesBackend::Filters& filter)
{
630
    if(filter.resourceUrl.scheme() == QLatin1String("fwupd")) {
Abhijeet  sharma's avatar
Abhijeet sharma committed
631
        return findResourceByPackageName(filter.resourceUrl);
632
    } else if (!filter.resourceUrl.isEmpty()) {
633
634
635
636
637
638
639
        return new ResultsStream(QStringLiteral("FwupdStream-void"), {});
    }

    QVector<AbstractResource*> ret;
    foreach(AbstractResource* r, m_resources) {
        if(r->name().contains(filter.search, Qt::CaseInsensitive) || r->comment().contains(filter.search, Qt::CaseInsensitive))
            ret += r;
Abhijeet  sharma's avatar
Abhijeet sharma committed
640
641
642
643
644
645
646
    }
    return new ResultsStream(QStringLiteral("FwupdStream"), ret);
}

ResultsStream * FwupdBackend::findResourceByPackageName(const QUrl& search)
{
    auto res = search.scheme() == QLatin1String("fwupd") ? m_resources.value(search.host().replace(QLatin1Char('.'), QLatin1Char(' '))) : nullptr;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
647
    if(!res)
Abhijeet  sharma's avatar
Abhijeet sharma committed
648
    {
Abhijeet  sharma's avatar
Abhijeet sharma committed
649
        return new ResultsStream(QStringLiteral("FwupdStream"), {});
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
650
    }
Abhijeet  sharma's avatar
Abhijeet sharma committed
651
    else
Abhijeet  sharma's avatar
Abhijeet sharma committed
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
        return new ResultsStream(QStringLiteral("FwupdStream"), { res });
}

AbstractBackendUpdater* FwupdBackend::backendUpdater() const
{
    return m_updater;
}

AbstractReviewsBackend* FwupdBackend::reviewsBackend() const
{
    return nullptr;
}

Transaction* FwupdBackend::installApplication(AbstractResource* app, const AddonList& addons)
{
    return new FwupdTransaction(qobject_cast<FwupdResource*>(app), this, addons, Transaction::InstallRole);
}

Transaction* FwupdBackend::installApplication(AbstractResource* app)
{
	return new FwupdTransaction(qobject_cast<FwupdResource*>(app), this, Transaction::InstallRole);
}

Transaction* FwupdBackend::removeApplication(AbstractResource* app)
{
	return new FwupdTransaction(qobject_cast<FwupdResource*>(app), this, Transaction::RemoveRole);
}

void FwupdBackend::checkForUpdates()
{
    if(m_fetching)
        return;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
684

Abhijeet  sharma's avatar
Abhijeet sharma committed
685
686
687
688
689
690
691
692
693
694
695
696
    populate(QStringLiteral("Releases"));
    toggleFetching();
    QTimer::singleShot(500, this, &FwupdBackend::toggleFetching);
}

AbstractResource * FwupdBackend::resourceForFile(const QUrl& path)
{
    g_autoptr(GError) error = nullptr;

    QMimeDatabase db;
    QMimeType type = db.mimeTypeForFile(path.fileName());
    FwupdResource* app = nullptr;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
697

Abhijeet  sharma's avatar
Abhijeet sharma committed
698
699
700
701
702
    if(type.isValid() && type.inherits(QStringLiteral("application/vnd.ms-cab-compressed")))
    {
        g_autofree gchar *filename = path.fileName().toUtf8().data();
        g_autoptr(GPtrArray) devices = fwupd_client_get_details(client, filename, nullptr, &error);

Abhijeet  sharma's avatar
Abhijeet sharma committed
703
        if(devices)
Abhijeet  sharma's avatar
Abhijeet sharma committed
704
        {
Abhijeet  sharma's avatar
Abhijeet sharma committed
705
706
            FwupdDevice *device = (FwupdDevice *)g_ptr_array_index(devices, 0);
            app = createRelease(device);
Abhijeet  sharma's avatar
Abhijeet sharma committed
707
            app->setState(AbstractResource::None);
Abhijeet  sharma's avatar
Abhijeet sharma committed
708
            for(uint i = 1; i < devices->len; i++)
Abhijeet  sharma's avatar
Abhijeet sharma committed
709
            {
Abhijeet  sharma's avatar
Abhijeet sharma committed
710
711
                FwupdDevice *device = (FwupdDevice *)g_ptr_array_index(devices, i);
                FwupdResource* app_ = createRelease(device);
Abhijeet  sharma's avatar
Abhijeet sharma committed
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
                app_->setState(AbstractResource::None);
                if(!app->m_releases.contains(app_))
                    app->m_releases.append(app_);
            }
            m_resources.insert(app->packageName(), app);
            addResourceToList(app);
            connect(app, &FwupdResource::stateChanged, this, &FwupdBackend::updatesCountChanged);
        }
        else
        {
            handleError(&error);
        }
    }
    return app;
}

QString FwupdBackend::displayName() const
{
    return QStringLiteral("Firmware Updates");
}

bool FwupdBackend::hasApplications() const
{
735
    return false;
Abhijeet  sharma's avatar
Abhijeet sharma committed
736
737
738
}

#include "FwupdBackend.moc"