~ubuntu-branches/ubuntu/precise/kde-runtime/precise-updates

« back to all changes in this revision

Viewing changes to nepomuk/services/storage/resourcewatchermanager.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-11-20 15:46:42 UTC
  • mfrom: (18.1.5 precise-proposed)
  • Revision ID: package-import@ubuntu.com-20141120154642-hyesdbuvsk78ihtz
Tags: 4:4.8.5-0ubuntu0.3
* SECURITY UPDATE: Insufficient Input Validation By IO Slaves and
  Webkit Part
 - Add upstream_CVE-2014-8600.diff to escape protocol twice: once
   for i18n, and once for HTML
 - https://www.kde.org/info/security/advisory-20141113-1.txt
 - CVE-2014-8600
 - LP: #1393479

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
    This file is part of the Nepomuk KDE project.
3
3
    Copyright (C) 2011  Vishesh Handa <handa.vish@gmail.com>
4
 
    Copyright (C) 2011 Sebastian Trueg <trueg@kde.org>
 
4
    Copyright (C) 2011-2012 Sebastian Trueg <trueg@kde.org>
5
5
 
6
6
    This program is free software; you can redistribute it and/or modify
7
7
    it under the terms of the GNU General Public License as published by
21
21
 
22
22
#include "resourcewatchermanager.h"
23
23
#include "resourcewatcherconnection.h"
 
24
#include "datamanagementmodel.h"
24
25
 
25
26
#include <Soprano/Statement>
 
27
#include <Soprano/StatementIterator>
 
28
#include <Soprano/NodeIterator>
26
29
#include <Soprano/Vocabulary/RDF>
27
30
 
28
31
#include <QtDBus/QDBusConnection>
47
50
    }
48
51
}
49
52
 
50
 
QStringList convertUris(const QList<QUrl>& uris) {
 
53
template<typename T> QVariantList nodeListToVariantList(const T &nodes) {
 
54
    QVariantList list;
 
55
    list.reserve(nodes.size());
 
56
    foreach( const Soprano::Node &n, nodes ) {
 
57
        list << nodeToVariant(n).variant();
 
58
    }
 
59
 
 
60
    return list;
 
61
}
 
62
 
 
63
QString convertUri(const QUrl& uri) {
 
64
    return KUrl(uri).url();
 
65
}
 
66
 
 
67
template<typename T> QStringList convertUris(const T& uris) {
51
68
    QStringList sl;
52
69
    foreach(const QUrl& uri, uris)
53
 
        sl << KUrl(uri).url();
 
70
        sl << convertUri(uri);
54
71
    return sl;
55
72
}
56
73
 
 
74
QUrl convertUri(const QString& s) {
 
75
    return KUrl(s);
 
76
}
 
77
 
57
78
QList<QUrl> convertUris(const QStringList& uris) {
58
79
    QList<QUrl> sl;
59
80
    foreach(const QString& uri, uris)
60
 
        sl << KUrl(uri);
 
81
        sl << convertUri(uri);
61
82
    return sl;
62
83
}
63
 
}
64
 
 
65
 
Nepomuk::ResourceWatcherManager::ResourceWatcherManager(QObject* parent)
 
84
 
 
85
/**
 
86
 * Returns true if the given hash contains at least one of the possible combinations of con and "c in candidates".
 
87
 */
 
88
bool hashContainsAtLeastOneOf(Nepomuk::ResourceWatcherConnection* con, const QSet<QUrl>& candidates, const QMultiHash<QUrl, Nepomuk::ResourceWatcherConnection*>& hash) {
 
89
    for(QSet<QUrl>::const_iterator it = candidates.constBegin();
 
90
        it != candidates.constEnd(); ++it) {
 
91
        if(hash.contains(*it, con)) {
 
92
            return true;
 
93
        }
 
94
    }
 
95
    return false;
 
96
}
 
97
}
 
98
 
 
99
 
 
100
Nepomuk::ResourceWatcherManager::ResourceWatcherManager(DataManagementModel* parent)
66
101
    : QObject(parent),
 
102
      m_model(parent),
67
103
      m_connectionCount(0)
68
104
{
69
105
    QDBusConnection::sessionBus().registerObject("/resourcewatcher", this, QDBusConnection::ExportScriptableSlots);
83
119
 
84
120
void Nepomuk::ResourceWatcherManager::addStatement(const Soprano::Statement& st)
85
121
{
86
 
    addProperty( st.subject(), st.predicate().uri(), st.object() );
 
122
    // FIXME!
 
123
    //addProperty( st.subject(), st.predicate().uri(), QList<Soprano::Node>() << st.object() );
87
124
}
88
125
 
89
 
void Nepomuk::ResourceWatcherManager::addProperty(const Soprano::Node res, const QUrl& property, const Soprano::Node& value)
 
126
 
 
127
void Nepomuk::ResourceWatcherManager::changeProperty(const QUrl &res, const QUrl &property, const QList<Soprano::Node> &addedValues, const QList<Soprano::Node> &removedValues)
90
128
{
91
 
    typedef ResourceWatcherConnection RWC;
92
 
 
93
 
    // FIXME: take care of duplicate signals!
 
129
    kDebug() << res << property << addedValues << removedValues;
 
130
 
 
131
    //
 
132
    // We only need the resource types if any connections are watching types.
 
133
    //
 
134
    QSet<QUrl> types;
 
135
    if(!m_typeHash.isEmpty()) {
 
136
        types = getTypes(res);
 
137
    }
 
138
 
 
139
 
 
140
    //
 
141
    // special case: rdf:type
 
142
    //
 
143
    if(property == RDF::type()) {
 
144
        QSet<QUrl> addedTypes, removedTypes;
 
145
        for(QList<Soprano::Node>::const_iterator it = addedValues.constBegin();
 
146
            it != addedValues.constEnd(); ++it) {
 
147
            addedTypes << it->uri();
 
148
        }
 
149
        for(QList<Soprano::Node>::const_iterator it = removedValues.constBegin();
 
150
            it != removedValues.constEnd(); ++it) {
 
151
            removedTypes << it->uri();
 
152
        }
 
153
        changeTypes(res, types, addedTypes, removedTypes);
 
154
    }
 
155
 
 
156
 
 
157
    // first collect all the connections we need to emit the signals for
 
158
    QSet<ResourceWatcherConnection*> connections;
94
159
 
95
160
    //
96
161
    // Emit signals for all the connections that are only watching specific resources
97
162
    //
98
 
    QSet<RWC*> resConnections;
99
 
    QList<RWC*> connections = m_resHash.values( res.uri() );
100
 
    foreach( RWC* con, connections ) {
101
 
        if( !con->hasProperties() ) {
102
 
            emit con->propertyAdded( KUrl(res.uri()).url(),
103
 
                                     property.toString(),
104
 
                                     nodeToVariant(value) );
105
 
        }
106
 
        else {
107
 
            resConnections << con;
 
163
    foreach( ResourceWatcherConnection* con, m_resHash.values( res ) ) {
 
164
        if( m_propHash.contains(property, con) ||
 
165
            !m_propHash.values().contains(con) ) {
 
166
            connections << con;
108
167
        }
109
168
    }
110
169
 
 
170
 
111
171
    //
112
172
    // Emit signals for the connections that are watching specific resources and properties
113
173
    //
114
 
    QList<RWC*> propConnections = m_propHash.values( property );
115
 
    foreach( RWC* con, propConnections ) {
116
 
        QSet<RWC*>::const_iterator it = resConnections.constFind( con );
117
 
        if( it != resConnections.constEnd() ) {
118
 
            emit con->propertyAdded( KUrl(res.uri()).url(),
119
 
                                     property.toString(),
120
 
                                     nodeToVariant(value) );
121
 
        }
122
 
    }
123
 
 
124
 
    //
125
 
    // Emit type + property signals
126
 
    //
127
 
    //TODO: Implement me! ( How? )
 
174
    foreach( ResourceWatcherConnection* con, m_propHash.values( property ) ) {
 
175
        //
 
176
        // Emit for those connections which watch the property and either no
 
177
        // type or once of the types of the resource.
 
178
        // Only query the types if we have any type watching connections.
 
179
        //
 
180
        bool conIsWatchingResType = !m_typeHash.values().contains(con);
 
181
        foreach(const QUrl& type, types) {
 
182
            if(m_typeHash.contains(type, con)) {
 
183
                conIsWatchingResType = true;
 
184
                break;
 
185
            }
 
186
        }
 
187
 
 
188
        if( !m_resHash.values().contains(con) && conIsWatchingResType ) {
 
189
            connections << con;
 
190
        }
 
191
    }
 
192
 
 
193
 
 
194
 
 
195
    //
 
196
    // Emit signals for all connections which watch one of the types of the resource
 
197
    // but no properties (that is handled above).
 
198
    //
 
199
    foreach(const QUrl& type, types) {
 
200
        foreach(ResourceWatcherConnection* con, m_typeHash.values(type)) {
 
201
            if(!m_propHash.values(property).contains(con)) {
 
202
                connections << con;
 
203
            }
 
204
        }
 
205
    }
 
206
 
 
207
 
 
208
    //
 
209
    // Finally emit the signals for all connections
 
210
    //
 
211
    foreach(ResourceWatcherConnection* con, connections) {
 
212
        emit con->propertyChanged( convertUri(res),
 
213
                                   convertUri(property),
 
214
                                   nodeListToVariantList(addedValues),
 
215
                                   nodeListToVariantList(removedValues) );
 
216
        if(!addedValues.isEmpty()) {
 
217
            emit con->propertyAdded(convertUri(res),
 
218
                                    convertUri(property),
 
219
                                    nodeListToVariantList(addedValues));
 
220
        }
 
221
        if(!removedValues.isEmpty()) {
 
222
            emit con->propertyRemoved(convertUri(res),
 
223
                                      convertUri(property),
 
224
                                      nodeListToVariantList(removedValues));
 
225
        }
 
226
    }
128
227
}
129
228
 
130
 
void Nepomuk::ResourceWatcherManager::removeProperty(const Soprano::Node res, const QUrl& property, const Soprano::Node& value)
 
229
void Nepomuk::ResourceWatcherManager::changeProperty(const QMultiHash< QUrl, Soprano::Node >& oldValues,
 
230
                                                     const QUrl& property,
 
231
                                                     const QList<Soprano::Node>& nodes)
131
232
{
132
 
    typedef ResourceWatcherConnection RWC;
133
 
 
134
 
    //
135
 
    // Emit signals for all the connections that are only watching specific resources
136
 
    //
137
 
    QSet<RWC*> resConnections;
138
 
    QList<RWC*> connections = m_resHash.values( res.uri() );
139
 
    foreach( RWC* con, connections ) {
140
 
        if( !con->hasProperties() ) {
141
 
            emit con->propertyRemoved( KUrl(res.uri()).url(),
142
 
                                       property.toString(),
143
 
                                       nodeToVariant(value) );
144
 
        }
145
 
        else {
146
 
            resConnections << con;
147
 
        }
148
 
    }
149
 
 
150
 
    //
151
 
    // Emit signals for the conn2ections that are watching specific resources and properties
152
 
    //
153
 
    QList<RWC*> propConnections = m_propHash.values( property );
154
 
    foreach( RWC* con, propConnections ) {
155
 
        QSet<RWC*>::const_iterator it = resConnections.constFind( con );
156
 
        if( it != resConnections.constEnd() ) {
157
 
            emit con->propertyRemoved( KUrl(res.uri()).url(),
158
 
                                       property.toString(),
159
 
                                       nodeToVariant(value) );
160
 
        }
 
233
    QList<QUrl> uniqueKeys = oldValues.keys();
 
234
    foreach( const QUrl resUri, uniqueKeys ) {
 
235
        const QList<Soprano::Node> old = oldValues.values( resUri );
 
236
        changeProperty(resUri, property, old, nodes);
161
237
    }
162
238
}
163
239
 
171
247
    }
172
248
 
173
249
    foreach(ResourceWatcherConnection* con, connections) {
174
 
        emit con->resourceCreated(KUrl(uri).url(), convertUris(types));
 
250
        emit con->resourceCreated(convertUri(uri), convertUris(types));
175
251
    }
176
252
}
177
253
 
188
264
    }
189
265
 
190
266
    foreach(ResourceWatcherConnection* con, connections) {
191
 
        emit con->resourceRemoved(KUrl(res).url(), convertUris(types));
 
267
        emit con->resourceRemoved(convertUri(res), convertUris(types));
192
268
    }
193
269
}
194
270
 
202
278
        return 0;
203
279
    }
204
280
 
205
 
    ResourceWatcherConnection* con = new ResourceWatcherConnection( this, !properties.isEmpty() );
 
281
    ResourceWatcherConnection* con = new ResourceWatcherConnection( this );
206
282
    foreach( const QUrl& res, resources ) {
207
283
        m_resHash.insert(res, con);
208
284
    }
251
327
    removeConnectionFromHash( m_typeHash, con );
252
328
}
253
329
 
 
330
void Nepomuk::ResourceWatcherManager::setResources(Nepomuk::ResourceWatcherConnection *conn, const QStringList &resources)
 
331
{
 
332
    const QSet<QUrl> newRes = convertUris(resources).toSet();
 
333
    const QSet<QUrl> oldRes = m_resHash.keys(conn).toSet();
 
334
 
 
335
    foreach(const QUrl& res, newRes - oldRes) {
 
336
        m_resHash.insert(res, conn);
 
337
    }
 
338
    foreach(const QUrl& res, oldRes - newRes) {
 
339
        m_resHash.remove(res, conn);
 
340
    }
 
341
}
 
342
 
 
343
void Nepomuk::ResourceWatcherManager::addResource(Nepomuk::ResourceWatcherConnection *conn, const QString &resource)
 
344
{
 
345
    m_resHash.insert(convertUri(resource), conn);
 
346
}
 
347
 
 
348
void Nepomuk::ResourceWatcherManager::removeResource(Nepomuk::ResourceWatcherConnection *conn, const QString &resource)
 
349
{
 
350
    m_resHash.remove(convertUri(resource), conn);
 
351
}
 
352
 
 
353
void Nepomuk::ResourceWatcherManager::setProperties(Nepomuk::ResourceWatcherConnection *conn, const QStringList &properties)
 
354
{
 
355
    const QSet<QUrl> newprop = convertUris(properties).toSet();
 
356
    const QSet<QUrl> oldprop = m_propHash.keys(conn).toSet();
 
357
 
 
358
    foreach(const QUrl& prop, newprop - oldprop) {
 
359
        m_propHash.insert(prop, conn);
 
360
    }
 
361
    foreach(const QUrl& prop, oldprop - newprop) {
 
362
        m_propHash.remove(prop, conn);
 
363
    }
 
364
}
 
365
 
 
366
void Nepomuk::ResourceWatcherManager::addProperty(Nepomuk::ResourceWatcherConnection *conn, const QString &property)
 
367
{
 
368
    m_propHash.insert(convertUri(property), conn);
 
369
}
 
370
 
 
371
void Nepomuk::ResourceWatcherManager::removeProperty(Nepomuk::ResourceWatcherConnection *conn, const QString &property)
 
372
{
 
373
    m_propHash.remove(convertUri(property), conn);
 
374
}
 
375
 
 
376
void Nepomuk::ResourceWatcherManager::setTypes(Nepomuk::ResourceWatcherConnection *conn, const QStringList &types)
 
377
{
 
378
    const QSet<QUrl> newtype = convertUris(types).toSet();
 
379
    const QSet<QUrl> oldtype = m_typeHash.keys(conn).toSet();
 
380
 
 
381
    foreach(const QUrl& type, newtype - oldtype) {
 
382
        m_typeHash.insert(type, conn);
 
383
    }
 
384
    foreach(const QUrl& type, oldtype - newtype) {
 
385
        m_typeHash.remove(type, conn);
 
386
    }
 
387
}
 
388
 
 
389
void Nepomuk::ResourceWatcherManager::addType(Nepomuk::ResourceWatcherConnection *conn, const QString &type)
 
390
{
 
391
    m_typeHash.insert(convertUri(type), conn);
 
392
}
 
393
 
 
394
void Nepomuk::ResourceWatcherManager::removeType(Nepomuk::ResourceWatcherConnection *conn, const QString &type)
 
395
{
 
396
    m_typeHash.remove(convertUri(type), conn);
 
397
}
 
398
 
 
399
QSet<QUrl> Nepomuk::ResourceWatcherManager::getTypes(const Soprano::Node &res) const
 
400
{
 
401
    QSet<QUrl> types;
 
402
    Soprano::StatementIterator it = m_model->listStatements(res, RDF::type(), Soprano::Node());
 
403
    while(it.next()) {
 
404
        types.insert(it.current().object().uri());
 
405
    }
 
406
    return types;
 
407
}
 
408
 
 
409
// FIXME: also take super-classes into account
 
410
void Nepomuk::ResourceWatcherManager::changeTypes(const QUrl &res, const QSet<QUrl>& resTypes, const QSet<QUrl> &addedTypes, const QSet<QUrl> &removedTypes)
 
411
{
 
412
    // first collect all the connections we need to emit the signals for
 
413
    QSet<ResourceWatcherConnection*> addConnections, removeConnections;
 
414
 
 
415
    // all connections watching the resource and not a special property
 
416
    // and no special type or one of the changed types
 
417
    foreach( ResourceWatcherConnection* con, m_resHash.values( res ) ) {
 
418
        if( m_propHash.contains(RDF::type(), con) ||
 
419
            !m_propHash.values().contains(con) ) {
 
420
            if(!addedTypes.isEmpty() &&
 
421
               connectionWatchesOneType(con, addedTypes)) {
 
422
                addConnections << con;
 
423
            }
 
424
            if(!removedTypes.isEmpty() &&
 
425
               connectionWatchesOneType(con, removedTypes)) {
 
426
                removeConnections << con;
 
427
            }
 
428
        }
 
429
    }
 
430
 
 
431
    // all connections watching one of the types and no special resource or property
 
432
    if(!addedTypes.isEmpty()) {
 
433
        foreach(const QUrl& type, addedTypes + resTypes) {
 
434
            foreach(ResourceWatcherConnection* con, m_typeHash.values(type)) {
 
435
                if(!m_resHash.values().contains(con) &&
 
436
                   !m_propHash.values().contains(con)) {
 
437
                    addConnections << con;
 
438
                }
 
439
            }
 
440
        }
 
441
    }
 
442
    if(!removedTypes.isEmpty()) {
 
443
        foreach(const QUrl& type, removedTypes + resTypes) {
 
444
            foreach(ResourceWatcherConnection* con, m_typeHash.values(type)) {
 
445
                if(!m_resHash.values().contains(con) &&
 
446
                   !m_propHash.values().contains(con)) {
 
447
                    removeConnections << con;
 
448
                }
 
449
            }
 
450
        }
 
451
    }
 
452
 
 
453
    // all connections watching rdf:type
 
454
    foreach(ResourceWatcherConnection* con, m_propHash.values(RDF::type())) {
 
455
        if(!m_resHash.values().contains(con) ) {
 
456
            if(connectionWatchesOneType(con, addedTypes + resTypes)) {
 
457
                addConnections << con;
 
458
            }
 
459
            if(connectionWatchesOneType(con, removedTypes + resTypes)) {
 
460
                removeConnections << con;
 
461
            }
 
462
        }
 
463
    }
 
464
 
 
465
    // finally emit the actual signals
 
466
    if(!addedTypes.isEmpty()) {
 
467
        foreach(ResourceWatcherConnection* con, addConnections) {
 
468
            emit con->resourceTypesAdded(convertUri(res),
 
469
                                         convertUris(addedTypes));
 
470
        }
 
471
    }
 
472
    if(!removedTypes.isEmpty()) {
 
473
        foreach(ResourceWatcherConnection* con, removeConnections) {
 
474
            emit con->resourceTypesRemoved(convertUri(res),
 
475
                                           convertUris(removedTypes));
 
476
        }
 
477
    }
 
478
}
 
479
 
 
480
bool Nepomuk::ResourceWatcherManager::connectionWatchesOneType(Nepomuk::ResourceWatcherConnection *con, const QSet<QUrl> &types) const
 
481
{
 
482
    return !m_typeHash.values().contains(con) || hashContainsAtLeastOneOf(con, types, m_typeHash);
 
483
}
 
484
 
254
485
#include "resourcewatchermanager.moc"