~rpadovani/webbrowser-app/settings-page

« back to all changes in this revision

Viewing changes to click-hooks/hook-utils.cpp

  • Committer: Alexandre Abreu
  • Date: 2014-11-12 17:00:12 UTC
  • mto: (806.3.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 827.
  • Revision ID: alexandre.abreu@canonical.com-20141112170012-6ov4k5pbqa8ta7sq
draft

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2014 Canonical Ltd.
 
3
 *
 
4
 * This file is part of webbrowser-app.
 
5
 *
 
6
 * webbrowser-app is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; version 3.
 
9
 *
 
10
 * webbrowser-app is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include "hook-utils.h"
 
20
 
 
21
#include <QDateTime>
 
22
#include <QDebug>
 
23
#include <QFileInfo>
 
24
#include <QJsonArray>
 
25
#include <QJsonDocument>
 
26
#include <QJsonObject>
 
27
#include <QStandardPaths>
 
28
 
 
29
 
 
30
namespace HookUtils {
 
31
 
 
32
 
 
33
WebappHookParser::OptionalData
 
34
WebappHookParser::parseContent(const QString& filename)
 
35
{
 
36
    QFileInfo info(filename);
 
37
    if (!info.exists() || !info.isFile() || !info.isReadable())
 
38
    {
 
39
        return OptionalData(Data(), false);
 
40
    }
 
41
 
 
42
    QFile file(filename);
 
43
    if (!file.open(QIODevice::ReadOnly))
 
44
    {
 
45
        qWarning() << "Cannot open webapp hook: " << filename;
 
46
        return OptionalData(Data(), false);
 
47
    }
 
48
 
 
49
    QJsonDocument document(QJsonDocument::fromJson(file.readAll()));
 
50
    if (document.isNull() || document.isEmpty() || !document.isArray()) {
 
51
        return OptionalData(Data(), false);
 
52
    }
 
53
 
 
54
    return parseDocument(document.array());
 
55
}
 
56
 
 
57
WebappHookParser::OptionalData
 
58
WebappHookParser::parseDocument(const QJsonArray &array)
 
59
{
 
60
    Data result;
 
61
    if (array.count() == 0
 
62
            || !array.at(0).isObject())
 
63
    {
 
64
        return OptionalData(result);
 
65
    }
 
66
 
 
67
    QJsonObject rootObject = array.at(0).toObject();
 
68
 
 
69
#define JSON_OBJECT_VALIDATE(o,key,predicate) \
 
70
    o.contains(key) && o.value(key).predicate()
 
71
 
 
72
    const QString UNINSTALL_KEY = "uninstall";
 
73
    if (JSON_OBJECT_VALIDATE(rootObject,UNINSTALL_KEY,isObject))
 
74
    {
 
75
        const QString UNINSTALL_DELETE_COOKIES = "delete-cookies";
 
76
        const QString UNINSTALL_DELETE_CACHE = "    ";
 
77
 
 
78
        QJsonObject uninstallObject =
 
79
                rootObject.value(UNINSTALL_KEY).toObject();
 
80
        if (JSON_OBJECT_VALIDATE(uninstallObject,UNINSTALL_DELETE_COOKIES,isBool))
 
81
        {
 
82
            result.shouldDeleteCookiesOnUninstall =
 
83
                    uninstallObject.value(UNINSTALL_DELETE_COOKIES).toBool();
 
84
        }
 
85
 
 
86
        if (JSON_OBJECT_VALIDATE(uninstallObject,UNINSTALL_DELETE_CACHE,isBool))
 
87
        {
 
88
            result.shouldDeleteCacheOnUninstall =
 
89
                    uninstallObject.value(UNINSTALL_DELETE_CACHE).toBool();
 
90
        }
 
91
    }
 
92
#undef JSON_OBJECT_VALIDATE
 
93
 
 
94
    return OptionalData(result);
 
95
}
 
96
 
 
97
WebappClickHookInstallDescription
 
98
listWebappClickHookFilesIn(const QDir& dir)
 
99
{
 
100
    WebappClickHookInstallDescription
 
101
            description(dir.absolutePath(), QHash<QString, QString>());
 
102
 
 
103
    const QString WEBAPP_CLICK_HOOK_FILE_EXT = "webapp";
 
104
    Q_FOREACH(const QFileInfo &fileInfo, dir.entryInfoList())
 
105
    {
 
106
        if (fileInfo.suffix() == WEBAPP_CLICK_HOOK_FILE_EXT)
 
107
        {
 
108
            QString suffix = fileInfo.suffix();
 
109
            description.hookFiles[removeVersionFrom(fileInfo.completeBaseName()) + "." + suffix] =
 
110
                    fileInfo.fileName();
 
111
        }
 
112
    }
 
113
    return description;
 
114
}
 
115
 
 
116
QString
 
117
getProcessedClickHooksFolder()
 
118
{
 
119
    QString result = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation)
 
120
            + "/webapp-container";
 
121
    if (!qgetenv("WEBAPPCONTAINER_PROCESSED_HOOKS_FOLDER").isNull())
 
122
    {
 
123
        result = QString(qgetenv("WEBAPPCONTAINER_PROCESSED_HOOKS_FOLDER"));
 
124
    }
 
125
    return result;
 
126
}
 
127
 
 
128
QString
 
129
getClickHooksInstallFolder()
 
130
{
 
131
    QString result = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
 
132
            + "/webapp-container";
 
133
    if (!qgetenv("WEBAPPCONTAINER_INSTALLED_HOOKS_FOLDER").isNull())
 
134
    {
 
135
        result = QString(qgetenv("WEBAPPCONTAINER_INSTALLED_HOOKS_FOLDER"));
 
136
    }
 
137
    return result;
 
138
}
 
139
 
 
140
QString removeVersionFrom(const QString &appId)
 
141
{
 
142
    QStringList components = appId.split('_');
 
143
    if (components.count() != 3)
 
144
    {
 
145
        return appId;
 
146
    }
 
147
    components.removeLast();
 
148
    return components.join('_');
 
149
}
 
150
 
 
151
void handleInstalls(const WebappClickHookInstallDescription& alreadyProcessedClickHooks
 
152
                   , const WebappClickHookInstallDescription& installedClickHooks)
 
153
{
 
154
    QStringList newlyInstalledClickPackages =
 
155
            installedClickHooks.hookFiles.keys().toSet().subtract(
 
156
                alreadyProcessedClickHooks.hookFiles.keys().toSet()).toList();
 
157
 
 
158
    if (newlyInstalledClickPackages.count() == 0)
 
159
    {
 
160
        qDebug() << "Nothing to install.";
 
161
        return;
 
162
    }
 
163
 
 
164
    Q_FOREACH(const QString &webappClickHook, newlyInstalledClickPackages)
 
165
    {
 
166
        QString hookFilename =
 
167
                installedClickHooks.parentFolder + "/"
 
168
                + installedClickHooks.hookFiles[webappClickHook];
 
169
 
 
170
        QFileInfo hookFileInfo(hookFilename);
 
171
        QString suffix = hookFileInfo.suffix();
 
172
        QString appIdNoVersion = removeVersionFrom(hookFileInfo.completeBaseName());
 
173
 
 
174
        QString destination = QString("%1/%2").
 
175
            arg(alreadyProcessedClickHooks.parentFolder).arg(appIdNoVersion + "." + suffix);
 
176
 
 
177
        qDebug() << "Installing: " << destination;
 
178
 
 
179
        QFile::copy(hookFilename, destination);
 
180
    }
 
181
 
 
182
}
 
183
 
 
184
void handleUninstall(const WebappClickHookInstallDescription& alreadyProcessedClickHooks
 
185
                     , const WebappClickHookInstallDescription& currentClickHooks)
 
186
{
 
187
    WebappHookParser webappHookParser;
 
188
    QStringList deletedClickPackages =
 
189
            alreadyProcessedClickHooks.hookFiles.keys().toSet().subtract(
 
190
                currentClickHooks.hookFiles.keys().toSet()).toList();
 
191
 
 
192
    if (deletedClickPackages.count() == 0)
 
193
    {
 
194
        qDebug() << "Nothing to delete.";
 
195
        return;
 
196
    }
 
197
 
 
198
    Q_FOREACH(const QString &webappClickHook, deletedClickPackages)
 
199
    {
 
200
        QString hookFilename =
 
201
                alreadyProcessedClickHooks.parentFolder + "/" + webappClickHook;
 
202
 
 
203
        WebappHookParser::OptionalData optional_data =
 
204
                webappHookParser.parseContent(hookFilename);
 
205
        if (!optional_data.is_valid())
 
206
        {
 
207
            continue;
 
208
        }
 
209
 
 
210
        QFileInfo fileInfo(hookFilename);
 
211
        QString appIdNoVersion = fileInfo.fileName();
 
212
 
 
213
        WebappHookParser::Data data = optional_data.value();
 
214
        if (data.shouldDeleteCacheOnUninstall)
 
215
        {
 
216
            QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation)
 
217
                     + "/" + appIdNoVersion);
 
218
            dir.removeRecursively();
 
219
        }
 
220
        if (data.shouldDeleteCookiesOnUninstall)
 
221
        {
 
222
            QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
 
223
                     + "/" + appIdNoVersion);
 
224
            dir.removeRecursively();
 
225
        }
 
226
 
 
227
        qDebug() << "Uninstalling: " << hookFilename;
 
228
 
 
229
        QFile::remove(hookFilename);
 
230
    }
 
231
}
 
232
 
 
233
void handleUpdates(const WebappClickHookInstallDescription& alreadyProcessedClickHooks
 
234
                   , const WebappClickHookInstallDescription& installedClickHooks)
 
235
{
 
236
    QStringList foundClickHooks =
 
237
            alreadyProcessedClickHooks.hookFiles.keys().toSet().intersect(
 
238
                installedClickHooks.hookFiles.keys().toSet()).toList();
 
239
 
 
240
    if (foundClickHooks.count() == 0)
 
241
    {
 
242
        qDebug() << "Nothing to update.";
 
243
        return;
 
244
    }
 
245
 
 
246
    Q_FOREACH(const QString &webappClickHook, foundClickHooks)
 
247
    {
 
248
        QString hookFilename =
 
249
                installedClickHooks.parentFolder + "/"
 
250
                + installedClickHooks.hookFiles[webappClickHook];
 
251
 
 
252
        QFileInfo hookFileInfo(hookFilename);
 
253
        QString suffix = hookFileInfo.suffix();
 
254
        QString appIdNoVersion = removeVersionFrom(hookFileInfo.completeBaseName());
 
255
 
 
256
        QString destination = QString("%1/%2").
 
257
            arg(alreadyProcessedClickHooks.parentFolder).arg(appIdNoVersion + "." + suffix);
 
258
 
 
259
        QFileInfo destinationInfo(destination);
 
260
        if (destinationInfo.exists() &&
 
261
            destinationInfo.lastModified() >= hookFileInfo.lastModified()) {
 
262
            continue;
 
263
        }
 
264
 
 
265
        qDebug() << "Updating " << destination;
 
266
 
 
267
        if (QFile::exists(destination))
 
268
        {
 
269
            QFile::remove(destination);
 
270
        }
 
271
 
 
272
        QFile::copy(hookFilename, destination);
 
273
    }
 
274
}
 
275
 
 
276
 
 
277
}