~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to third-party/qca/qca/src/qca_keystore.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-04-14 18:57:30 UTC
  • mfrom: (2.1.9 hardy)
  • Revision ID: james.westby@ubuntu.com-20080414185730-528re3zp0m2hdlhi
Tags: 0.11-8
* added CONFIG -= link_prl to .pro files and removed dependencies
  which are made unnecessary by this change
* Fix segfault when closing last chat tab with qt4.4
  (This is from upstream svn, rev. 1101) (Closes: Bug#476122)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2003-2007  Justin Karneges <justin@affinix.com>
 
3
 * Copyright (C) 2004,2005  Brad Hards <bradh@frogmouth.net>
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2.1 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library 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 GNU
 
13
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General Public
 
16
 * License along with this library; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
18
 *
 
19
 */
 
20
 
 
21
#include "qca_keystore.h"
 
22
 
 
23
#include <QCoreApplication>
 
24
#include <QAbstractEventDispatcher>
 
25
#include <QPointer>
 
26
#include <QSet>
 
27
#include <QMutex>
 
28
#include <QWaitCondition>
 
29
 
 
30
#include <stdlib.h> // abort
 
31
#include <stdio.h>  // fprintf
 
32
 
 
33
#include "qcaprovider.h"
 
34
 
 
35
Q_DECLARE_METATYPE(QCA::KeyStoreEntry)
 
36
Q_DECLARE_METATYPE(QList<QCA::KeyStoreEntry>)
 
37
Q_DECLARE_METATYPE(QList<QCA::KeyStoreEntry::Type>)
 
38
Q_DECLARE_METATYPE(QCA::KeyBundle)
 
39
Q_DECLARE_METATYPE(QCA::Certificate)
 
40
Q_DECLARE_METATYPE(QCA::CRL)
 
41
Q_DECLARE_METATYPE(QCA::PGPKey)
 
42
 
 
43
namespace QCA {
 
44
 
 
45
Provider::Context *getContext(const QString &type, Provider *p);
 
46
 
 
47
/*
 
48
  How this stuff works:
 
49
 
 
50
  KeyStoreListContext is queried for a list of store context ids.  A signal
 
51
  is used to indicate when the list may have changed, so polling for changes
 
52
  is not necessary.  Context ids change for every new presence of a store.
 
53
  Even if a user removes and inserts the same smart card device, which has
 
54
  the same storeId, the context id will ALWAYS be different.  If a previously
 
55
  known context id is missing from a later queried list, then it means the
 
56
  associated store is unavailable.  It is recommended that the provider just
 
57
  use a counter for the contextId, incrementing the value anytime a new
 
58
  context is made.
 
59
 
 
60
  KeyStoreTracker manages all of the keystore stuff, and exists in its own
 
61
  thread (called the tracker thread).  All of the KeyStoreListContext
 
62
  objects exist in the tracker thread.
 
63
*/
 
64
 
 
65
/*
 
66
  scenarios to handle:
 
67
  - ksm.start shouldn't block
 
68
  - keystore in available list, but gone by the time it is requested
 
69
  - keystore is unavailable during a call to a keystoreentry method
 
70
  - keystore/keystoreentry methods called simultaneously from different threads
 
71
  - and of course, objects from keystores should work, despite being created
 
72
    in the keystore thread
 
73
*/
 
74
 
 
75
//----------------------------------------------------------------------------
 
76
// KeyStoreTracker
 
77
//----------------------------------------------------------------------------
 
78
static int tracker_id_at = 0;
 
79
 
 
80
class KeyStoreTracker : public QObject
 
81
{
 
82
        Q_OBJECT
 
83
public:
 
84
        static KeyStoreTracker *self;
 
85
 
 
86
        class Item
 
87
        {
 
88
        public:
 
89
                // combine keystore owner and contextid into a single id
 
90
                int trackerId;
 
91
 
 
92
                // number of times the keystore has been updated
 
93
                int updateCount;
 
94
 
 
95
                // keystore context
 
96
                KeyStoreListContext *owner;
 
97
                int storeContextId;
 
98
 
 
99
                // properties
 
100
                QString storeId;
 
101
                QString name;
 
102
                KeyStore::Type type;
 
103
                bool isReadOnly;
 
104
 
 
105
                Item() : trackerId(-1), updateCount(0), owner(0), storeContextId(-1)
 
106
                {
 
107
                }
 
108
        };
 
109
 
 
110
        QMutex m;
 
111
        QSet<KeyStoreListContext*> sources;
 
112
        QSet<KeyStoreListContext*> busySources;
 
113
        QList<Item> items;
 
114
        QString dtext;
 
115
        bool startedAll;
 
116
        bool busy;
 
117
 
 
118
        QMutex updateMutex;
 
119
 
 
120
        KeyStoreTracker()
 
121
        {
 
122
                self = this;
 
123
 
 
124
                qRegisterMetaType<QCA::KeyStoreEntry>("QCA::KeyStoreEntry");
 
125
                qRegisterMetaType< QList<QCA::KeyStoreEntry> >("QList<QCA::KeyStoreEntry>");
 
126
                qRegisterMetaType< QList<QCA::KeyStoreEntry::Type> >("QList<QCA::KeyStoreEntry::Type>");
 
127
 
 
128
                connect(this, SIGNAL(updated_p()), SLOT(updated_locked()), Qt::QueuedConnection);
 
129
 
 
130
                startedAll = false;
 
131
                busy = true; // we start out busy
 
132
        }
 
133
 
 
134
        ~KeyStoreTracker()
 
135
        {
 
136
                qDeleteAll(sources);
 
137
                self = 0;
 
138
        }
 
139
 
 
140
        static KeyStoreTracker *instance()
 
141
        {
 
142
                return self;
 
143
        }
 
144
 
 
145
        // thread-safe
 
146
        bool isBusy()
 
147
        {
 
148
                QMutexLocker locker(&m);
 
149
                return busy;
 
150
        }
 
151
 
 
152
        // thread-safe
 
153
        QList<Item> getItems()
 
154
        {
 
155
                QMutexLocker locker(&m);
 
156
                return items;
 
157
        }
 
158
 
 
159
        // thread-safe
 
160
        QString getDText()
 
161
        {
 
162
                QMutexLocker locker(&m);
 
163
                return dtext;
 
164
        }
 
165
 
 
166
        // thread-safe
 
167
        void clearDText()
 
168
        {
 
169
                QMutexLocker locker(&m);
 
170
                dtext.clear();
 
171
        }
 
172
 
 
173
        // thread-safe
 
174
        void addTarget(QObject *ksm)
 
175
        {
 
176
                QMutexLocker locker(&updateMutex);
 
177
                ksm->connect(this, SIGNAL(updated()), SLOT(tracker_updated()), Qt::DirectConnection);
 
178
        }
 
179
 
 
180
        // thread-safe
 
181
        void removeTarget(QObject *ksm)
 
182
        {
 
183
                QMutexLocker locker(&updateMutex);
 
184
                disconnect(ksm);
 
185
        }
 
186
 
 
187
public slots:
 
188
        void spinEventLoop()
 
189
        {
 
190
                QAbstractEventDispatcher::instance()->processEvents(QEventLoop::AllEvents);
 
191
        }
 
192
 
 
193
        void start()
 
194
        {
 
195
                // grab providers (and default)
 
196
                ProviderList list = providers();
 
197
                list.append(defaultProvider());
 
198
 
 
199
                for(int n = 0; n < list.count(); ++n)
 
200
                {
 
201
                        Provider *p = list[n];
 
202
                        if(p->features().contains("keystorelist") && !haveProviderSource(p))
 
203
                                startProvider(p);
 
204
                }
 
205
 
 
206
                startedAll = true;
 
207
        }
 
208
 
 
209
        void start(const QString &provider)
 
210
        {
 
211
                // grab providers (and default)
 
212
                ProviderList list = providers();
 
213
                list.append(defaultProvider());
 
214
 
 
215
                Provider *p = 0;
 
216
                for(int n = 0; n < list.count(); ++n)
 
217
                {
 
218
                        if(list[n]->name() == provider)
 
219
                        {
 
220
                                p = list[n];
 
221
                                break;
 
222
                        }
 
223
                }
 
224
 
 
225
                if(p && p->features().contains("keystorelist") && !haveProviderSource(p))
 
226
                        startProvider(p);
 
227
        }
 
228
 
 
229
        void scan()
 
230
        {
 
231
                if(startedAll)
 
232
                        start();
 
233
        }
 
234
 
 
235
        QList<QCA::KeyStoreEntry> entryList(int trackerId)
 
236
        {
 
237
                QList<KeyStoreEntry> out;
 
238
                int at = findItem(trackerId);
 
239
                if(at == -1)
 
240
                        return out;
 
241
                Item &i = items[at];
 
242
                QList<KeyStoreEntryContext*> list = i.owner->entryList(i.storeContextId);
 
243
                for(int n = 0; n < list.count(); ++n)
 
244
                {
 
245
                        KeyStoreEntry entry;
 
246
                        entry.change(list[n]);
 
247
                        out.append(entry);
 
248
                }
 
249
                return out;
 
250
        }
 
251
 
 
252
        QList<QCA::KeyStoreEntry::Type> entryTypes(int trackerId)
 
253
        {
 
254
                QList<KeyStoreEntry::Type> out;
 
255
                int at = findItem(trackerId);
 
256
                if(at == -1)
 
257
                        return out;
 
258
                Item &i = items[at];
 
259
                return i.owner->entryTypes(i.storeContextId);
 
260
        }
 
261
 
 
262
        // hack with void *
 
263
        void *entry(const QString &storeId, const QString &entryId)
 
264
        {
 
265
                KeyStoreListContext *c = 0;
 
266
                int contextId = -1;
 
267
                m.lock();
 
268
                foreach(Item i, items)
 
269
                {
 
270
                        if(i.storeId == storeId)
 
271
                        {
 
272
                                c = i.owner;
 
273
                                contextId = i.storeContextId;
 
274
                                break;
 
275
                        }
 
276
                }
 
277
                m.unlock();
 
278
                if(!c)
 
279
                        return 0;
 
280
 
 
281
                return c->entry(contextId, entryId);
 
282
        }
 
283
 
 
284
        // hack with void *
 
285
        void *entryPassive(const QString &serialized)
 
286
        {
 
287
                foreach(KeyStoreListContext *ksl, sources)
 
288
                {
 
289
                        // "is this yours?"
 
290
                        KeyStoreEntryContext *e = ksl->entryPassive(serialized);
 
291
                        if(e)
 
292
                                return e;
 
293
                }
 
294
                return 0;
 
295
        }
 
296
 
 
297
        QString writeEntry(int trackerId, const QVariant &v)
 
298
        {
 
299
                int at = findItem(trackerId);
 
300
                if(at == -1)
 
301
                        return QString();
 
302
                Item &i = items[at];
 
303
                if(qVariantCanConvert<KeyBundle>(v))
 
304
                        return i.owner->writeEntry(i.storeContextId, qVariantValue<KeyBundle>(v));
 
305
                else if(qVariantCanConvert<Certificate>(v))
 
306
                        return i.owner->writeEntry(i.storeContextId, qVariantValue<Certificate>(v));
 
307
                else if(qVariantCanConvert<CRL>(v))
 
308
                        return i.owner->writeEntry(i.storeContextId, qVariantValue<CRL>(v));
 
309
                else if(qVariantCanConvert<PGPKey>(v))
 
310
                        return i.owner->writeEntry(i.storeContextId, qVariantValue<PGPKey>(v));
 
311
                else
 
312
                        return QString();
 
313
        }
 
314
 
 
315
        bool removeEntry(int trackerId, const QString &entryId)
 
316
        {
 
317
                int at = findItem(trackerId);
 
318
                if(at == -1)
 
319
                        return false;
 
320
                Item &i = items[at];
 
321
                return i.owner->removeEntry(i.storeContextId, entryId);
 
322
        }
 
323
 
 
324
signals:
 
325
        // emit this when items or busy state changes
 
326
        void updated();
 
327
        void updated_p();
 
328
 
 
329
private slots:
 
330
        void updated_locked()
 
331
        {
 
332
                QMutexLocker locker(&updateMutex);
 
333
                emit updated();
 
334
        }
 
335
 
 
336
private:
 
337
        bool haveProviderSource(Provider *p) const
 
338
        {
 
339
                foreach(KeyStoreListContext *ksl, sources)
 
340
                {
 
341
                        if(ksl->provider() == p)
 
342
                                return true;
 
343
                }
 
344
                return false;
 
345
        }
 
346
 
 
347
        int findItem(int trackerId)
 
348
        {
 
349
                for(int n = 0; n < items.count(); ++n)
 
350
                {
 
351
                        if(items[n].trackerId == trackerId)
 
352
                                return n;
 
353
                }
 
354
                return -1;
 
355
        }
 
356
 
 
357
        void startProvider(Provider *p)
 
358
        {
 
359
                KeyStoreListContext *c = static_cast<KeyStoreListContext *>(getContext("keystorelist", p));
 
360
                if(!c)
 
361
                        return;
 
362
 
 
363
                sources += c;
 
364
                busySources += c;
 
365
                connect(c, SIGNAL(busyStart()), SLOT(ksl_busyStart()));
 
366
                connect(c, SIGNAL(busyEnd()), SLOT(ksl_busyEnd()));
 
367
                connect(c, SIGNAL(updated()), SLOT(ksl_updated()));
 
368
                connect(c, SIGNAL(diagnosticText(const QString &)), SLOT(ksl_diagnosticText(const QString &)));
 
369
                connect(c, SIGNAL(storeUpdated(int)), SLOT(ksl_storeUpdated(int)));
 
370
                c->start();
 
371
                c->setUpdatesEnabled(true);
 
372
 
 
373
                QCA_logTextMessage(QString("keystore: startProvider %1").arg(p->name()), Logger::Information);
 
374
        }
 
375
 
 
376
        bool updateStores(KeyStoreListContext *c)
 
377
        {
 
378
                bool changed = false;
 
379
 
 
380
                QMutexLocker locker(&m);
 
381
 
 
382
                QList<int> keyStores = c->keyStores();
 
383
 
 
384
                // remove any contexts that are gone
 
385
                for(int n = 0; n < items.count(); ++n)
 
386
                {
 
387
                        if(items[n].owner == c && !keyStores.contains(items[n].storeContextId))
 
388
                        {
 
389
                                QCA_logTextMessage(QString("keystore: updateStores remove %1").arg(items[n].storeContextId), Logger::Information);
 
390
 
 
391
                                items.removeAt(n);
 
392
                                --n; // adjust position
 
393
 
 
394
                                changed = true;
 
395
                        }
 
396
                }
 
397
 
 
398
                // handle add/updates
 
399
                foreach(int id, keyStores)
 
400
                {
 
401
                        // do we have it already?
 
402
                        int at = -1;
 
403
                        for(int n = 0; n < items.count(); ++n)
 
404
                        {
 
405
                                if(items[n].owner == c && items[n].storeContextId == id)
 
406
                                {
 
407
                                        at = n;
 
408
                                        break;
 
409
                                }
 
410
                        }
 
411
 
 
412
                        // if so, update it
 
413
                        if(at != -1)
 
414
                        {
 
415
                                Item &i = items[at];
 
416
 
 
417
                                QString name = c->name(id);
 
418
                                bool isReadOnly = c->isReadOnly(id);
 
419
                                if(i.name != name || i.isReadOnly != isReadOnly)
 
420
                                {
 
421
                                        QCA_logTextMessage(QString("keystore: updateStores update %1").arg(id), Logger::Information);
 
422
                                        i.name = name;
 
423
                                        i.isReadOnly = isReadOnly;
 
424
                                        changed = true;
 
425
                                }
 
426
                        }
 
427
                        // otherwise, add it
 
428
                        else
 
429
                        {
 
430
                                QCA_logTextMessage(QString("keystore: updateStores add %1").arg(id), Logger::Information);
 
431
 
 
432
                                Item i;
 
433
                                i.trackerId = tracker_id_at++;
 
434
                                i.updateCount = 0;
 
435
                                i.owner = c;
 
436
                                i.storeContextId = id;
 
437
                                i.storeId = c->storeId(id);
 
438
                                i.name = c->name(id);
 
439
                                i.type = c->type(id);
 
440
                                i.isReadOnly = c->isReadOnly(id);
 
441
                                items += i;
 
442
 
 
443
                                changed = true;
 
444
                        }
 
445
                }
 
446
 
 
447
                return changed;
 
448
        }
 
449
 
 
450
private slots:
 
451
        void ksl_busyStart()
 
452
        {
 
453
                KeyStoreListContext *c = (KeyStoreListContext *)sender();
 
454
 
 
455
                QCA_logTextMessage(QString("keystore: ksl_busyStart %1").arg(c->provider()->name()), Logger::Information);
 
456
 
 
457
                if(!busySources.contains(c))
 
458
                {
 
459
                        busySources += c;
 
460
 
 
461
                        QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information);
 
462
                        emit updated_p();
 
463
                }
 
464
        }
 
465
 
 
466
        void ksl_busyEnd()
 
467
        {
 
468
                KeyStoreListContext *c = (KeyStoreListContext *)sender();
 
469
 
 
470
                QCA_logTextMessage(QString("keystore: ksl_busyEnd %1").arg(c->provider()->name()), Logger::Information);
 
471
 
 
472
                busySources.remove(c);
 
473
                bool changed = updateStores(c);
 
474
                bool any_busy = !busySources.isEmpty();
 
475
 
 
476
                if(!any_busy)
 
477
                {
 
478
                        m.lock();
 
479
                        busy = false;
 
480
                        m.unlock();
 
481
                }
 
482
 
 
483
                if(!any_busy || changed)
 
484
                {
 
485
                        QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information);
 
486
                        emit updated_p();
 
487
                }
 
488
        }
 
489
 
 
490
        void ksl_updated()
 
491
        {
 
492
                KeyStoreListContext *c = (KeyStoreListContext *)sender();
 
493
 
 
494
                QCA_logTextMessage(QString("keystore: ksl_updated %1").arg(c->provider()->name()), Logger::Information);
 
495
 
 
496
                bool changed = updateStores(c);
 
497
                if(changed)
 
498
                {
 
499
                        QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information);
 
500
                        emit updated_p();
 
501
                }
 
502
        }
 
503
 
 
504
        void ksl_diagnosticText(const QString &str)
 
505
        {
 
506
                QMutexLocker locker(&m);
 
507
                dtext += str;
 
508
        }
 
509
 
 
510
        void ksl_storeUpdated(int id)
 
511
        {
 
512
                KeyStoreListContext *c = (KeyStoreListContext *)sender();
 
513
 
 
514
                QCA_logTextMessage(QString("keystore: ksl_storeUpdated %1 %2").arg(c->provider()->name(), QString::number(id)), Logger::Information);
 
515
 
 
516
                QMutexLocker locker(&m);
 
517
                for(int n = 0; n < items.count(); ++n)
 
518
                {
 
519
                        Item &i = items[n];
 
520
                        if(i.owner == c && i.storeContextId == id)
 
521
                        {
 
522
                                ++i.updateCount;
 
523
 
 
524
                                QCA_logTextMessage(QString("keystore: %1 updateCount = %2").arg(i.name, QString::number(i.updateCount)), Logger::Information);
 
525
 
 
526
                                QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information);
 
527
                                emit updated_p();
 
528
                                return;
 
529
                        }
 
530
                }
 
531
        }
 
532
};
 
533
 
 
534
KeyStoreTracker *KeyStoreTracker::self = 0;
 
535
 
 
536
//----------------------------------------------------------------------------
 
537
// KeyStoreThread
 
538
//----------------------------------------------------------------------------
 
539
class KeyStoreThread : public SyncThread
 
540
{
 
541
        Q_OBJECT
 
542
public:
 
543
        KeyStoreTracker *tracker;
 
544
        QMutex call_mutex;
 
545
 
 
546
        KeyStoreThread(QObject *parent = 0) : SyncThread(parent)
 
547
        {
 
548
        }
 
549
 
 
550
        ~KeyStoreThread()
 
551
        {
 
552
                stop();
 
553
        }
 
554
 
 
555
        void atStart()
 
556
        {
 
557
                tracker = new KeyStoreTracker;
 
558
        }
 
559
 
 
560
        void atEnd()
 
561
        {
 
562
                delete tracker;
 
563
        }
 
564
};
 
565
 
 
566
//----------------------------------------------------------------------------
 
567
// KeyStoreGlobal
 
568
//----------------------------------------------------------------------------
 
569
class KeyStoreManagerGlobal;
 
570
 
 
571
Q_GLOBAL_STATIC(QMutex, ksm_mutex)
 
572
static KeyStoreManagerGlobal *g_ksm = 0;
 
573
 
 
574
class KeyStoreManagerGlobal
 
575
{
 
576
public:
 
577
        KeyStoreThread *thread;
 
578
 
 
579
        KeyStoreManagerGlobal()
 
580
        {
 
581
                thread = new KeyStoreThread;
 
582
                thread->moveToThread(QCoreApplication::instance()->thread());
 
583
                thread->start();
 
584
        }
 
585
 
 
586
        ~KeyStoreManagerGlobal()
 
587
        {
 
588
                delete thread;
 
589
        }
 
590
};
 
591
 
 
592
// this function is thread-safe
 
593
static QVariant trackercall(const char *method, const QVariantList &args = QVariantList())
 
594
{
 
595
        QVariant ret;
 
596
        bool ok;
 
597
 
 
598
        g_ksm->thread->call_mutex.lock();
 
599
        ret = g_ksm->thread->call(KeyStoreTracker::instance(), method, args, &ok);
 
600
        g_ksm->thread->call_mutex.unlock();
 
601
 
 
602
        Q_ASSERT(ok);
 
603
        if(!ok)
 
604
        {
 
605
                fprintf(stderr, "QCA: KeyStoreTracker call [%s] failed.\n", method);
 
606
                abort();
 
607
                return QVariant();
 
608
        }
 
609
        return ret;
 
610
}
 
611
 
 
612
//----------------------------------------------------------------------------
 
613
// KeyStoreEntry
 
614
//----------------------------------------------------------------------------
 
615
class KeyStoreEntry::Private
 
616
{
 
617
public:
 
618
        bool accessible;
 
619
 
 
620
        Private()
 
621
        {
 
622
                accessible = false;
 
623
        }
 
624
};
 
625
 
 
626
KeyStoreEntry::KeyStoreEntry()
 
627
:d(new Private)
 
628
{
 
629
}
 
630
 
 
631
KeyStoreEntry::KeyStoreEntry(const QString &serialized)
 
632
:d(new Private)
 
633
{
 
634
        *this = fromString(serialized);
 
635
}
 
636
 
 
637
KeyStoreEntry::KeyStoreEntry(const KeyStoreEntry &from)
 
638
:Algorithm(from), d(new Private(*from.d))
 
639
{
 
640
}
 
641
 
 
642
KeyStoreEntry::~KeyStoreEntry()
 
643
{
 
644
        delete d;
 
645
}
 
646
 
 
647
KeyStoreEntry & KeyStoreEntry::operator=(const KeyStoreEntry &from)
 
648
{
 
649
        Algorithm::operator=(from);
 
650
        *d = *from.d;
 
651
        return *this;
 
652
}
 
653
 
 
654
bool KeyStoreEntry::isNull() const
 
655
{
 
656
        return (!context() ? true : false);
 
657
}
 
658
 
 
659
bool KeyStoreEntry::isAvailable() const
 
660
{
 
661
        return static_cast<const KeyStoreEntryContext *>(context())->isAvailable();
 
662
}
 
663
 
 
664
bool KeyStoreEntry::isAccessible() const
 
665
{
 
666
        return d->accessible;
 
667
}
 
668
 
 
669
KeyStoreEntry::Type KeyStoreEntry::type() const
 
670
{
 
671
        return static_cast<const KeyStoreEntryContext *>(context())->type();
 
672
}
 
673
 
 
674
QString KeyStoreEntry::name() const
 
675
{
 
676
        return static_cast<const KeyStoreEntryContext *>(context())->name();
 
677
}
 
678
 
 
679
QString KeyStoreEntry::id() const
 
680
{
 
681
        return static_cast<const KeyStoreEntryContext *>(context())->id();
 
682
}
 
683
 
 
684
QString KeyStoreEntry::storeName() const
 
685
{
 
686
        return static_cast<const KeyStoreEntryContext *>(context())->storeName();
 
687
}
 
688
 
 
689
QString KeyStoreEntry::storeId() const
 
690
{
 
691
        return static_cast<const KeyStoreEntryContext *>(context())->storeId();
 
692
}
 
693
 
 
694
QString KeyStoreEntry::toString() const
 
695
{
 
696
        return static_cast<const KeyStoreEntryContext *>(context())->serialize();
 
697
}
 
698
 
 
699
KeyStoreEntry KeyStoreEntry::fromString(const QString &serialized)
 
700
{
 
701
        KeyStoreEntry e;
 
702
        KeyStoreEntryContext *c = (KeyStoreEntryContext *)KeyStoreTracker::instance()->entryPassive(serialized);
 
703
        if(c)
 
704
                e.change(c);
 
705
        return e;
 
706
}
 
707
 
 
708
KeyBundle KeyStoreEntry::keyBundle() const
 
709
{
 
710
        return static_cast<const KeyStoreEntryContext *>(context())->keyBundle();
 
711
}
 
712
 
 
713
Certificate KeyStoreEntry::certificate() const
 
714
{
 
715
        return static_cast<const KeyStoreEntryContext *>(context())->certificate();
 
716
}
 
717
 
 
718
CRL KeyStoreEntry::crl() const
 
719
{
 
720
        return static_cast<const KeyStoreEntryContext *>(context())->crl();
 
721
}
 
722
 
 
723
PGPKey KeyStoreEntry::pgpSecretKey() const
 
724
{
 
725
        return static_cast<const KeyStoreEntryContext *>(context())->pgpSecretKey();
 
726
}
 
727
 
 
728
PGPKey KeyStoreEntry::pgpPublicKey() const
 
729
{
 
730
        return static_cast<const KeyStoreEntryContext *>(context())->pgpPublicKey();
 
731
}
 
732
 
 
733
bool KeyStoreEntry::ensureAvailable()
 
734
{
 
735
        QString storeId = this->storeId();
 
736
        QString entryId = id();
 
737
        KeyStoreEntryContext *c = (KeyStoreEntryContext *)qVariantValue<void*>(trackercall("entry", QVariantList() << storeId << entryId));
 
738
        if(c)
 
739
                change(c);
 
740
        return isAvailable();
 
741
}
 
742
 
 
743
bool KeyStoreEntry::ensureAccess()
 
744
{
 
745
        if(!ensureAvailable())
 
746
        {
 
747
                d->accessible = false;
 
748
                return false;
 
749
        }
 
750
        bool ok = static_cast<KeyStoreEntryContext *>(context())->ensureAccess();
 
751
        d->accessible = ok;
 
752
        return d->accessible;
 
753
}
 
754
 
 
755
//----------------------------------------------------------------------------
 
756
// KeyStoreEntryWatcher
 
757
//----------------------------------------------------------------------------
 
758
class KeyStoreEntryWatcher::Private : public QObject
 
759
{
 
760
        Q_OBJECT
 
761
public:
 
762
        KeyStoreEntryWatcher *q;
 
763
        KeyStoreManager ksm;
 
764
        KeyStoreEntry entry;
 
765
        QString storeId, entryId;
 
766
        KeyStore *ks;
 
767
        bool avail;
 
768
 
 
769
        Private(KeyStoreEntryWatcher *_q) : QObject(_q), q(_q), ksm(this)
 
770
        {
 
771
                ks = 0;
 
772
                avail = false;
 
773
                connect(&ksm, SIGNAL(keyStoreAvailable(const QString &)), SLOT(ksm_available(const QString &)));
 
774
        }
 
775
 
 
776
        ~Private()
 
777
        {
 
778
                delete ks;
 
779
        }
 
780
 
 
781
        void start()
 
782
        {
 
783
                QStringList list = ksm.keyStores();
 
784
                foreach(const QString &storeId, list)
 
785
                        ksm_available(storeId);
 
786
        }
 
787
 
 
788
private slots:
 
789
        void ksm_available(const QString &_storeId)
 
790
        {
 
791
                // we only care about one store
 
792
                if(_storeId == storeId)
 
793
                {
 
794
                        ks = new KeyStore(storeId, &ksm);
 
795
                        connect(ks, SIGNAL(updated()), SLOT(ks_updated()));
 
796
                        ks->startAsynchronousMode();
 
797
                }
 
798
        }
 
799
 
 
800
        void ks_updated()
 
801
        {
 
802
                bool found = false;
 
803
                QList<KeyStoreEntry> list = ks->entryList();
 
804
                foreach(const KeyStoreEntry &e, list)
 
805
                {
 
806
                        if(e.id() == entryId && e.isAvailable())
 
807
                        {
 
808
                                found = true;
 
809
                                if(!avail)
 
810
                                        entry = e;
 
811
                                break;
 
812
                        }
 
813
                }
 
814
 
 
815
                if(found && !avail)
 
816
                {
 
817
                        avail = true;
 
818
                        emit q->available();
 
819
                }
 
820
                else if(!found && avail)
 
821
                {
 
822
                        avail = false;
 
823
                        emit q->unavailable();
 
824
                }
 
825
        }
 
826
 
 
827
        void ks_unavailable()
 
828
        {
 
829
                delete ks;
 
830
                ks = 0;
 
831
 
 
832
                if(avail)
 
833
                {
 
834
                        avail = false;
 
835
                        emit q->unavailable();
 
836
                }
 
837
        }
 
838
};
 
839
 
 
840
KeyStoreEntryWatcher::KeyStoreEntryWatcher(const KeyStoreEntry &e, QObject *parent)
 
841
:QObject(parent)
 
842
{
 
843
        d = new Private(this);
 
844
        if(!e.isNull())
 
845
        {
 
846
                d->entry = e;
 
847
                d->storeId = e.storeId();
 
848
                d->entryId = e.id();
 
849
                d->start();
 
850
        }
 
851
}
 
852
 
 
853
KeyStoreEntryWatcher::~KeyStoreEntryWatcher()
 
854
{
 
855
        delete d;
 
856
}
 
857
 
 
858
KeyStoreEntry KeyStoreEntryWatcher::entry() const
 
859
{
 
860
        return d->entry;
 
861
}
 
862
 
 
863
//----------------------------------------------------------------------------
 
864
// KeyStore
 
865
//----------------------------------------------------------------------------
 
866
// union thingy
 
867
class KeyStoreWriteEntry
 
868
{
 
869
public:
 
870
        enum Type { TypeKeyBundle, TypeCertificate, TypeCRL, TypePGPKey };
 
871
 
 
872
        Type type;
 
873
        KeyBundle keyBundle;
 
874
        Certificate cert;
 
875
        CRL crl;
 
876
        PGPKey pgpKey;
 
877
 
 
878
        KeyStoreWriteEntry()
 
879
        {
 
880
        }
 
881
 
 
882
        KeyStoreWriteEntry(const KeyBundle &_keyBundle)
 
883
        :type(TypeKeyBundle), keyBundle(_keyBundle)
 
884
        {
 
885
        }
 
886
 
 
887
        KeyStoreWriteEntry(const Certificate &_cert)
 
888
        :type(TypeCertificate), cert(_cert)
 
889
        {
 
890
        }
 
891
 
 
892
        KeyStoreWriteEntry(const CRL &_crl)
 
893
        :type(TypeCRL), crl(_crl)
 
894
        {
 
895
        }
 
896
 
 
897
        KeyStoreWriteEntry(const PGPKey &_pgpKey)
 
898
        :type(TypePGPKey), pgpKey(_pgpKey)
 
899
        {
 
900
        }
 
901
};
 
902
 
 
903
class KeyStoreOperation : public QThread
 
904
{
 
905
        Q_OBJECT
 
906
public:
 
907
        enum Type { EntryList, WriteEntry, RemoveEntry };
 
908
 
 
909
        Type type;
 
910
        int trackerId;
 
911
 
 
912
        KeyStoreWriteEntry wentry; // in: WriteEntry
 
913
        QList<KeyStoreEntry> entryList; // out: EntryList
 
914
        QString entryId; // in: RemoveEntry, out: WriteEntry
 
915
        bool success; // out: RemoveEntry
 
916
 
 
917
        KeyStoreOperation(QObject *parent = 0)
 
918
        :QThread(parent)
 
919
        {
 
920
        }
 
921
 
 
922
        ~KeyStoreOperation()
 
923
        {
 
924
                wait();
 
925
        }
 
926
 
 
927
protected:
 
928
        virtual void run()
 
929
        {
 
930
                if(type == EntryList)
 
931
                        entryList = qVariantValue< QList<KeyStoreEntry> >(trackercall("entryList", QVariantList() << trackerId));
 
932
                else if(type == WriteEntry)
 
933
                {
 
934
                        QVariant arg;
 
935
                        if(wentry.type == KeyStoreWriteEntry::TypeKeyBundle)
 
936
                                qVariantSetValue<KeyBundle>(arg, wentry.keyBundle);
 
937
                        else if(wentry.type == KeyStoreWriteEntry::TypeCertificate)
 
938
                                qVariantSetValue<Certificate>(arg, wentry.cert);
 
939
                        else if(wentry.type == KeyStoreWriteEntry::TypeCRL)
 
940
                                qVariantSetValue<CRL>(arg, wentry.crl);
 
941
                        else if(wentry.type == KeyStoreWriteEntry::TypePGPKey)
 
942
                                qVariantSetValue<PGPKey>(arg, wentry.pgpKey);
 
943
                        entryId = trackercall("writeEntry", QVariantList() << trackerId << arg).toString();
 
944
                }
 
945
                else // RemoveEntry
 
946
                {
 
947
                        success = trackercall("removeEntry", QVariantList() << trackerId << entryId).toBool();
 
948
                }
 
949
        }
 
950
};
 
951
 
 
952
class KeyStorePrivate : public QObject
 
953
{
 
954
        Q_OBJECT
 
955
public:
 
956
        KeyStore *q;
 
957
        KeyStoreManager *ksm;
 
958
        int trackerId;
 
959
        KeyStoreTracker::Item item;
 
960
        bool async;
 
961
        bool need_update;
 
962
        QList<KeyStoreEntry> latestEntryList;
 
963
        QList<KeyStoreOperation*> ops;
 
964
 
 
965
        KeyStorePrivate(KeyStore *_q) : QObject(_q), q(_q), async(false)
 
966
        {
 
967
        }
 
968
 
 
969
        ~KeyStorePrivate()
 
970
        {
 
971
                qDeleteAll(ops);
 
972
        }
 
973
 
 
974
        // implemented below, after KeyStorePrivate is declared
 
975
        void reg();
 
976
        void unreg();
 
977
        KeyStoreTracker::Item *getItem(const QString &storeId);
 
978
        KeyStoreTracker::Item *getItem(int trackerId);
 
979
 
 
980
        void invalidate()
 
981
        {
 
982
                trackerId = -1;
 
983
                unreg();
 
984
        }
 
985
 
 
986
        bool have_entryList_op() const
 
987
        {
 
988
                foreach(KeyStoreOperation *op, ops)
 
989
                {
 
990
                        if(op->type == KeyStoreOperation::EntryList)
 
991
                                return true;
 
992
                }
 
993
                return false;
 
994
        }
 
995
 
 
996
        void handle_updated()
 
997
        {
 
998
                if(async)
 
999
                {
 
1000
                        if(!have_entryList_op())
 
1001
                                async_entryList();
 
1002
                        else
 
1003
                                need_update = true;
 
1004
                }
 
1005
                else
 
1006
                        emit q->updated();
 
1007
        }
 
1008
 
 
1009
        void async_entryList()
 
1010
        {
 
1011
                KeyStoreOperation *op = new KeyStoreOperation(this);
 
1012
                // use queued for signal-safety
 
1013
                connect(op, SIGNAL(finished()), SLOT(op_finished()), Qt::QueuedConnection);
 
1014
                op->type = KeyStoreOperation::EntryList;
 
1015
                op->trackerId = trackerId;
 
1016
                ops += op;
 
1017
                op->start();
 
1018
        }
 
1019
 
 
1020
        void async_writeEntry(const KeyStoreWriteEntry &wentry)
 
1021
        {
 
1022
                KeyStoreOperation *op = new KeyStoreOperation(this);
 
1023
                // use queued for signal-safety
 
1024
                connect(op, SIGNAL(finished()), SLOT(op_finished()), Qt::QueuedConnection);
 
1025
                op->type = KeyStoreOperation::WriteEntry;
 
1026
                op->trackerId = trackerId;
 
1027
                op->wentry = wentry;
 
1028
                ops += op;
 
1029
                op->start();
 
1030
        }
 
1031
 
 
1032
        void async_removeEntry(const QString &entryId)
 
1033
        {
 
1034
                KeyStoreOperation *op = new KeyStoreOperation(this);
 
1035
                // use queued for signal-safety
 
1036
                connect(op, SIGNAL(finished()), SLOT(op_finished()), Qt::QueuedConnection);
 
1037
                op->type = KeyStoreOperation::RemoveEntry;
 
1038
                op->trackerId = trackerId;
 
1039
                op->entryId = entryId;
 
1040
                ops += op;
 
1041
                op->start();
 
1042
        }
 
1043
 
 
1044
private slots:
 
1045
        void op_finished()
 
1046
        {
 
1047
                KeyStoreOperation *op = (KeyStoreOperation *)sender();
 
1048
 
 
1049
                if(op->type == KeyStoreOperation::EntryList)
 
1050
                {
 
1051
                        latestEntryList = op->entryList;
 
1052
                        ops.removeAll(op);
 
1053
                        delete op;
 
1054
 
 
1055
                        if(need_update)
 
1056
                        {
 
1057
                                need_update = false;
 
1058
                                async_entryList();
 
1059
                        }
 
1060
 
 
1061
                        emit q->updated();
 
1062
                }
 
1063
                else if(op->type == KeyStoreOperation::WriteEntry)
 
1064
                {
 
1065
                        QString entryId = op->entryId;
 
1066
                        ops.removeAll(op);
 
1067
                        delete op;
 
1068
 
 
1069
                        emit q->entryWritten(entryId);
 
1070
                }
 
1071
                else // RemoveEntry
 
1072
                {
 
1073
                        bool success = op->success;
 
1074
                        ops.removeAll(op);
 
1075
                        delete op;
 
1076
 
 
1077
                        emit q->entryRemoved(success);
 
1078
                }
 
1079
        }
 
1080
};
 
1081
 
 
1082
KeyStore::KeyStore(const QString &id, KeyStoreManager *keyStoreManager)
 
1083
:QObject(keyStoreManager)
 
1084
{
 
1085
        d = new KeyStorePrivate(this);
 
1086
        d->ksm = keyStoreManager;
 
1087
 
 
1088
        KeyStoreTracker::Item *i = d->getItem(id);
 
1089
        if(i)
 
1090
        {
 
1091
                d->trackerId = i->trackerId;
 
1092
                d->item = *i;
 
1093
                d->reg();
 
1094
        }
 
1095
        else
 
1096
                d->trackerId = -1;
 
1097
}
 
1098
 
 
1099
KeyStore::~KeyStore()
 
1100
{
 
1101
        if(d->trackerId != -1)
 
1102
                d->unreg();
 
1103
        delete d;
 
1104
}
 
1105
 
 
1106
bool KeyStore::isValid() const
 
1107
{
 
1108
        return (d->getItem(d->trackerId) ? true : false);
 
1109
}
 
1110
 
 
1111
KeyStore::Type KeyStore::type() const
 
1112
{
 
1113
        return d->item.type;
 
1114
}
 
1115
 
 
1116
QString KeyStore::name() const
 
1117
{
 
1118
        return d->item.name;
 
1119
}
 
1120
 
 
1121
QString KeyStore::id() const
 
1122
{
 
1123
        return d->item.storeId;
 
1124
}
 
1125
 
 
1126
bool KeyStore::isReadOnly() const
 
1127
{
 
1128
        return d->item.isReadOnly;
 
1129
}
 
1130
 
 
1131
void KeyStore::startAsynchronousMode()
 
1132
{
 
1133
        if(d->async)
 
1134
                return;
 
1135
 
 
1136
        d->async = true;
 
1137
 
 
1138
        // initial entrylist
 
1139
        d->need_update = false;
 
1140
        d->async_entryList();
 
1141
}
 
1142
 
 
1143
QList<KeyStoreEntry> KeyStore::entryList() const
 
1144
{
 
1145
        if(d->async)
 
1146
                return d->latestEntryList;
 
1147
 
 
1148
        if(d->trackerId == -1)
 
1149
                return QList<KeyStoreEntry>();
 
1150
        return qVariantValue< QList<KeyStoreEntry> >(trackercall("entryList", QVariantList() << d->trackerId));
 
1151
}
 
1152
 
 
1153
bool KeyStore::holdsTrustedCertificates() const
 
1154
{
 
1155
        QList<KeyStoreEntry::Type> list;
 
1156
        if(d->trackerId == -1)
 
1157
                return false;
 
1158
        list = qVariantValue< QList<KeyStoreEntry::Type> >(trackercall("entryTypes", QVariantList() << d->trackerId));
 
1159
        if(list.contains(KeyStoreEntry::TypeCertificate) || list.contains(KeyStoreEntry::TypeCRL))
 
1160
                return true;
 
1161
        return false;
 
1162
}
 
1163
 
 
1164
bool KeyStore::holdsIdentities() const
 
1165
{
 
1166
        QList<KeyStoreEntry::Type> list;
 
1167
        if(d->trackerId == -1)
 
1168
                return false;
 
1169
        list = qVariantValue< QList<KeyStoreEntry::Type> >(trackercall("entryTypes", QVariantList() << d->trackerId));
 
1170
        if(list.contains(KeyStoreEntry::TypeKeyBundle) || list.contains(KeyStoreEntry::TypePGPSecretKey))
 
1171
                return true;
 
1172
        return false;
 
1173
}
 
1174
 
 
1175
bool KeyStore::holdsPGPPublicKeys() const
 
1176
{
 
1177
        QList<KeyStoreEntry::Type> list;
 
1178
        if(d->trackerId == -1)
 
1179
                return false;
 
1180
        list = qVariantValue< QList<KeyStoreEntry::Type> >(trackercall("entryTypes", QVariantList() << d->trackerId));
 
1181
        if(list.contains(KeyStoreEntry::TypePGPPublicKey))
 
1182
                return true;
 
1183
        return false;
 
1184
}
 
1185
 
 
1186
QString KeyStore::writeEntry(const KeyBundle &kb)
 
1187
{
 
1188
        if(d->async)
 
1189
        {
 
1190
                d->async_writeEntry(KeyStoreWriteEntry(kb));
 
1191
                return QString();
 
1192
        }
 
1193
        else
 
1194
        {
 
1195
                QVariant arg;
 
1196
                qVariantSetValue<KeyBundle>(arg, kb);
 
1197
                return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString();
 
1198
        }
 
1199
}
 
1200
 
 
1201
QString KeyStore::writeEntry(const Certificate &cert)
 
1202
{
 
1203
        if(d->async)
 
1204
        {
 
1205
                d->async_writeEntry(KeyStoreWriteEntry(cert));
 
1206
                return QString();
 
1207
        }
 
1208
        else
 
1209
        {
 
1210
                QVariant arg;
 
1211
                qVariantSetValue<Certificate>(arg, cert);
 
1212
                return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString();
 
1213
        }
 
1214
}
 
1215
 
 
1216
QString KeyStore::writeEntry(const CRL &crl)
 
1217
{
 
1218
        if(d->async)
 
1219
        {
 
1220
                d->async_writeEntry(KeyStoreWriteEntry(crl));
 
1221
                return QString();
 
1222
        }
 
1223
        else
 
1224
        {
 
1225
                QVariant arg;
 
1226
                qVariantSetValue<CRL>(arg, crl);
 
1227
                return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString();
 
1228
        }
 
1229
}
 
1230
 
 
1231
QString KeyStore::writeEntry(const PGPKey &key)
 
1232
{
 
1233
        if(d->async)
 
1234
        {
 
1235
                d->async_writeEntry(KeyStoreWriteEntry(key));
 
1236
                return QString();
 
1237
        }
 
1238
        else
 
1239
        {
 
1240
                QVariant arg;
 
1241
                qVariantSetValue<PGPKey>(arg, key);
 
1242
                return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString();
 
1243
        }
 
1244
}
 
1245
 
 
1246
bool KeyStore::removeEntry(const QString &id)
 
1247
{
 
1248
        if(d->async)
 
1249
        {
 
1250
                d->async_removeEntry(id);
 
1251
                return false;
 
1252
        }
 
1253
        else
 
1254
        {
 
1255
                return trackercall("removeEntry", QVariantList() << d->trackerId << id).toBool();
 
1256
        }
 
1257
}
 
1258
 
 
1259
//----------------------------------------------------------------------------
 
1260
// KeyStoreManager
 
1261
//----------------------------------------------------------------------------
 
1262
static void ensure_init()
 
1263
{
 
1264
        QMutexLocker locker(ksm_mutex());
 
1265
        if(!g_ksm)
 
1266
                g_ksm = new KeyStoreManagerGlobal;
 
1267
}
 
1268
 
 
1269
// static functions
 
1270
void KeyStoreManager::start()
 
1271
{
 
1272
        ensure_init();
 
1273
        QMetaObject::invokeMethod(KeyStoreTracker::instance(), "start", Qt::QueuedConnection);
 
1274
        trackercall("spinEventLoop");
 
1275
}
 
1276
 
 
1277
void KeyStoreManager::start(const QString &provider)
 
1278
{
 
1279
        ensure_init();
 
1280
        QMetaObject::invokeMethod(KeyStoreTracker::instance(), "start", Qt::QueuedConnection, Q_ARG(QString, provider));
 
1281
        trackercall("spinEventLoop");
 
1282
}
 
1283
 
 
1284
QString KeyStoreManager::diagnosticText()
 
1285
{
 
1286
        ensure_init();
 
1287
 
 
1288
        // spin one event cycle in the tracker, to receive any pending text.
 
1289
        //   note that since trackercall also goes through the eventloop,
 
1290
        //   this may end up doing two rounds.  probably no big deal.
 
1291
        trackercall("spinEventLoop");
 
1292
 
 
1293
        return KeyStoreTracker::instance()->getDText();
 
1294
}
 
1295
 
 
1296
void KeyStoreManager::clearDiagnosticText()
 
1297
{
 
1298
        ensure_init();
 
1299
        KeyStoreTracker::instance()->clearDText();
 
1300
}
 
1301
 
 
1302
void KeyStoreManager::scan()
 
1303
{
 
1304
        ensure_init();
 
1305
        QMetaObject::invokeMethod(KeyStoreTracker::instance(), "scan", Qt::QueuedConnection);
 
1306
}
 
1307
 
 
1308
void KeyStoreManager::shutdown()
 
1309
{
 
1310
        QMutexLocker locker(ksm_mutex());
 
1311
        delete g_ksm;
 
1312
        g_ksm = 0;
 
1313
}
 
1314
 
 
1315
// object
 
1316
class KeyStoreManagerPrivate : public QObject
 
1317
{
 
1318
        Q_OBJECT
 
1319
public:
 
1320
        KeyStoreManager *q;
 
1321
 
 
1322
        QMutex m;
 
1323
        QWaitCondition w;
 
1324
        bool busy;
 
1325
        QList<KeyStoreTracker::Item> items;
 
1326
        bool pending, waiting;
 
1327
 
 
1328
        QMultiHash<int,KeyStore*> keyStoreForTrackerId;
 
1329
        QHash<KeyStore*,int> trackerIdForKeyStore;
 
1330
 
 
1331
        KeyStoreManagerPrivate(KeyStoreManager *_q) : QObject(_q), q(_q)
 
1332
        {
 
1333
                pending = false;
 
1334
                waiting = false;
 
1335
        }
 
1336
 
 
1337
        ~KeyStoreManagerPrivate()
 
1338
        {
 
1339
                // invalidate registered keystores
 
1340
                QList<KeyStore*> list;
 
1341
                QHashIterator<KeyStore*,int> it(trackerIdForKeyStore);
 
1342
                while(it.hasNext())
 
1343
                {
 
1344
                        it.next();
 
1345
                        list += it.key();
 
1346
                }
 
1347
                foreach(KeyStore *ks, list)
 
1348
                        ks->d->invalidate();
 
1349
        }
 
1350
 
 
1351
        // for keystore
 
1352
        void reg(KeyStore *ks, int trackerId)
 
1353
        {
 
1354
                keyStoreForTrackerId.insert(trackerId, ks);
 
1355
                trackerIdForKeyStore.insert(ks, trackerId);
 
1356
        }
 
1357
 
 
1358
        void unreg(KeyStore *ks)
 
1359
        {
 
1360
                int trackerId = trackerIdForKeyStore.take(ks);
 
1361
 
 
1362
                // this is the only way I know to remove one item from a multihash
 
1363
                QList<KeyStore*> vals = keyStoreForTrackerId.values(trackerId);
 
1364
                keyStoreForTrackerId.remove(trackerId);
 
1365
                vals.removeAll(ks);
 
1366
                foreach(KeyStore *i, vals)
 
1367
                        keyStoreForTrackerId.insert(trackerId, i);
 
1368
        }
 
1369
 
 
1370
        KeyStoreTracker::Item *getItem(const QString &storeId)
 
1371
        {
 
1372
                for(int n = 0; n < items.count(); ++n)
 
1373
                {
 
1374
                        KeyStoreTracker::Item *i = &items[n];
 
1375
                        if(i->storeId == storeId)
 
1376
                                return i;
 
1377
                }
 
1378
                return 0;
 
1379
        }
 
1380
 
 
1381
        KeyStoreTracker::Item *getItem(int trackerId)
 
1382
        {
 
1383
                for(int n = 0; n < items.count(); ++n)
 
1384
                {
 
1385
                        KeyStoreTracker::Item *i = &items[n];
 
1386
                        if(i->trackerId == trackerId)
 
1387
                                return i;
 
1388
                }
 
1389
                return 0;
 
1390
        }
 
1391
 
 
1392
        void do_update()
 
1393
        {
 
1394
                // ksm doesn't have reset or state changes so we can
 
1395
                //   use QPointer here for full SS.
 
1396
                QPointer<QObject> self(this);
 
1397
 
 
1398
                bool newbusy = KeyStoreTracker::instance()->isBusy();
 
1399
                QList<KeyStoreTracker::Item> newitems = KeyStoreTracker::instance()->getItems();
 
1400
 
 
1401
                if(!busy && newbusy)
 
1402
                {
 
1403
                        emit q->busyStarted();
 
1404
                        if(!self)
 
1405
                                return;
 
1406
                }
 
1407
                if(busy && !newbusy)
 
1408
                {
 
1409
                        emit q->busyFinished();
 
1410
                        if(!self)
 
1411
                                return;
 
1412
                }
 
1413
 
 
1414
                QStringList here;
 
1415
                QList<int> changed;
 
1416
                QList<int> gone;
 
1417
 
 
1418
                // removed
 
1419
                for(int n = 0; n < items.count(); ++n)
 
1420
                {
 
1421
                        KeyStoreTracker::Item &i = items[n];
 
1422
                        bool found = false;
 
1423
                        for(int k = 0; k < newitems.count(); ++k)
 
1424
                        {
 
1425
                                if(i.trackerId == newitems[k].trackerId)
 
1426
                                {
 
1427
                                        found = true;
 
1428
                                        break;
 
1429
                                }
 
1430
                        }
 
1431
                        if(!found)
 
1432
                                gone += i.trackerId;
 
1433
                }
 
1434
 
 
1435
                // changed
 
1436
                for(int n = 0; n < items.count(); ++n)
 
1437
                {
 
1438
                        KeyStoreTracker::Item &i = items[n];
 
1439
                        for(int k = 0; k < newitems.count(); ++k)
 
1440
                        {
 
1441
                                if(i.trackerId == newitems[k].trackerId)
 
1442
                                {
 
1443
                                        if(i.updateCount < newitems[k].updateCount)
 
1444
                                                changed += i.trackerId;
 
1445
                                        break;
 
1446
                                }
 
1447
                        }
 
1448
                }
 
1449
 
 
1450
                // added
 
1451
                for(int n = 0; n < newitems.count(); ++n)
 
1452
                {
 
1453
                        KeyStoreTracker::Item &i = newitems[n];
 
1454
                        bool found = false;
 
1455
                        for(int k = 0; k < items.count(); ++k)
 
1456
                        {
 
1457
                                if(i.trackerId == items[k].trackerId)
 
1458
                                {
 
1459
                                        found = true;
 
1460
                                        break;
 
1461
                                }
 
1462
                        }
 
1463
                        if(!found)
 
1464
                                here += i.storeId;
 
1465
                }
 
1466
 
 
1467
                busy = newbusy;
 
1468
                items = newitems;
 
1469
 
 
1470
                // signals
 
1471
                foreach(int trackerId, gone)
 
1472
                {
 
1473
                        KeyStore *ks = keyStoreForTrackerId.value(trackerId);
 
1474
                        if(ks)
 
1475
                        {
 
1476
                                ks->d->invalidate();
 
1477
                                emit ks->unavailable();
 
1478
                                if(!self)
 
1479
                                        return;
 
1480
                        }
 
1481
                }
 
1482
 
 
1483
                foreach(int trackerId, changed)
 
1484
                {
 
1485
                        KeyStore *ks = keyStoreForTrackerId.value(trackerId);
 
1486
                        if(ks)
 
1487
                        {
 
1488
                                ks->d->handle_updated();
 
1489
                                if(!self)
 
1490
                                        return;
 
1491
                        }
 
1492
                }
 
1493
 
 
1494
                foreach(QString storeId, here)
 
1495
                {
 
1496
                        emit q->keyStoreAvailable(storeId);
 
1497
                        if(!self)
 
1498
                                return;
 
1499
                }
 
1500
        }
 
1501
 
 
1502
public slots:
 
1503
        void tracker_updated()
 
1504
        {
 
1505
                QCA_logTextMessage(QString().sprintf("keystore: %p: tracker_updated start", q), Logger::Information);
 
1506
 
 
1507
                QMutexLocker locker(&m);
 
1508
                if(!pending)
 
1509
                {
 
1510
                        QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
 
1511
                        pending = true;
 
1512
                }
 
1513
                if(waiting && !KeyStoreTracker::instance()->isBusy())
 
1514
                {
 
1515
                        busy = false;
 
1516
                        items = KeyStoreTracker::instance()->getItems();
 
1517
                        w.wakeOne();
 
1518
                }
 
1519
 
 
1520
                QCA_logTextMessage(QString().sprintf("keystore: %p: tracker_updated end", q), Logger::Information);
 
1521
        }
 
1522
 
 
1523
        void update()
 
1524
        {
 
1525
                m.lock();
 
1526
                pending = false;
 
1527
                m.unlock();
 
1528
 
 
1529
                do_update();
 
1530
        }
 
1531
};
 
1532
 
 
1533
// from KeyStorePrivate
 
1534
void KeyStorePrivate::reg()
 
1535
{
 
1536
        ksm->d->reg(q, trackerId);
 
1537
}
 
1538
 
 
1539
void KeyStorePrivate::unreg()
 
1540
{
 
1541
        ksm->d->unreg(q);
 
1542
}
 
1543
 
 
1544
KeyStoreTracker::Item *KeyStorePrivate::getItem(const QString &storeId)
 
1545
{
 
1546
        return ksm->d->getItem(storeId);
 
1547
}
 
1548
 
 
1549
KeyStoreTracker::Item *KeyStorePrivate::getItem(int trackerId)
 
1550
{
 
1551
        return ksm->d->getItem(trackerId);
 
1552
}
 
1553
 
 
1554
KeyStoreManager::KeyStoreManager(QObject *parent)
 
1555
:QObject(parent)
 
1556
{
 
1557
        ensure_init();
 
1558
        d = new KeyStoreManagerPrivate(this);
 
1559
        KeyStoreTracker::instance()->addTarget(d);
 
1560
        sync();
 
1561
}
 
1562
 
 
1563
KeyStoreManager::~KeyStoreManager()
 
1564
{
 
1565
        Q_ASSERT(KeyStoreTracker::instance());
 
1566
        KeyStoreTracker::instance()->removeTarget(d);
 
1567
        delete d;
 
1568
}
 
1569
 
 
1570
bool KeyStoreManager::isBusy() const
 
1571
{
 
1572
        return d->busy;
 
1573
}
 
1574
 
 
1575
void KeyStoreManager::waitForBusyFinished()
 
1576
{
 
1577
        d->m.lock();
 
1578
        d->busy = KeyStoreTracker::instance()->isBusy();
 
1579
        if(d->busy)
 
1580
        {
 
1581
                d->waiting = true;
 
1582
                d->w.wait(&d->m);
 
1583
                d->waiting = false;
 
1584
        }
 
1585
        d->m.unlock();
 
1586
}
 
1587
 
 
1588
QStringList KeyStoreManager::keyStores() const
 
1589
{
 
1590
        QStringList out;
 
1591
        for(int n = 0; n < d->items.count(); ++n)
 
1592
                out += d->items[n].storeId;
 
1593
        return out;
 
1594
}
 
1595
 
 
1596
void KeyStoreManager::sync()
 
1597
{
 
1598
        d->busy = KeyStoreTracker::instance()->isBusy();
 
1599
        d->items = KeyStoreTracker::instance()->getItems();
 
1600
}
 
1601
 
 
1602
//----------------------------------------------------------------------------
 
1603
// KeyStoreInfo
 
1604
//----------------------------------------------------------------------------
 
1605
class KeyStoreInfo::Private : public QSharedData
 
1606
{
 
1607
public:
 
1608
        KeyStore::Type type;
 
1609
        QString id, name;
 
1610
};
 
1611
 
 
1612
KeyStoreInfo::KeyStoreInfo()
 
1613
{
 
1614
}
 
1615
 
 
1616
KeyStoreInfo::KeyStoreInfo(KeyStore::Type type, const QString &id, const QString &name)
 
1617
:d(new Private)
 
1618
{
 
1619
        d->type = type;
 
1620
        d->id = id;
 
1621
        d->name = name;
 
1622
}
 
1623
 
 
1624
KeyStoreInfo::KeyStoreInfo(const KeyStoreInfo &from)
 
1625
:d(from.d)
 
1626
{
 
1627
}
 
1628
 
 
1629
KeyStoreInfo::~KeyStoreInfo()
 
1630
{
 
1631
}
 
1632
 
 
1633
KeyStoreInfo & KeyStoreInfo::operator=(const KeyStoreInfo &from)
 
1634
{
 
1635
        d = from.d;
 
1636
        return *this;
 
1637
}
 
1638
 
 
1639
bool KeyStoreInfo::isNull() const
 
1640
{
 
1641
        return (d ? false: true);
 
1642
}
 
1643
 
 
1644
KeyStore::Type KeyStoreInfo::type() const
 
1645
{
 
1646
        return d->type;
 
1647
}
 
1648
 
 
1649
QString KeyStoreInfo::id() const
 
1650
{
 
1651
        return d->id;
 
1652
}
 
1653
 
 
1654
QString KeyStoreInfo::name() const
 
1655
{
 
1656
        return d->name;
 
1657
}
 
1658
 
 
1659
}
 
1660
 
 
1661
#include "qca_keystore.moc"