~ubuntu-branches/ubuntu/wily/psi/wily-proposed

« back to all changes in this revision

Viewing changes to third-party/qca/qca-gnupg/qca-gnupg.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-08-28 18:46:52 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080828184652-iiik12dl91nq7cdi
Tags: 0.12-2
Uploading to unstable (Closes: Bug#494352)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2003-2005  Justin Karneges <justin@affinix.com>
 
2
 * Copyright (C) 2003-2008  Justin Karneges <justin@affinix.com>
3
3
 *
4
4
 * This library is free software; you can redistribute it and/or
5
5
 * modify it under the terms of the GNU Lesser General Public
17
17
 */
18
18
 
19
19
#include <QtCrypto>
 
20
#include <qcaprovider.h>
20
21
#include <QtPlugin>
 
22
#include <QTemporaryFile>
 
23
#include <QDir>
 
24
#include <QLatin1String>
 
25
#include <QMutex>
 
26
#include <stdio.h>
21
27
 
22
28
#ifdef Q_OS_MAC
23
29
#include <QFileInfo>
28
34
#endif
29
35
#include "gpgop.h"
30
36
 
 
37
// for SafeTimer and release function
 
38
#include "gpgproc.h"
 
39
 
 
40
using namespace QCA;
 
41
 
 
42
namespace gpgQCAPlugin {
 
43
 
 
44
static int qVersionInt()
 
45
{
 
46
        static int out = -1;
 
47
 
 
48
        if(out == -1)
 
49
        {
 
50
                QString str = QString::fromLatin1(qVersion());
 
51
                QStringList parts = str.split('.', QString::KeepEmptyParts);
 
52
                if(parts.count() != 3)
 
53
                {
 
54
                        out = 0;
 
55
                        return out;
 
56
                }
 
57
 
 
58
                out = 0;
 
59
                for(int n = 0; n < 3; ++n)
 
60
                {
 
61
                        bool ok;
 
62
                        int x = parts[n].toInt(&ok);
 
63
                        if(ok && x >= 0 && x <= 0xff)
 
64
                        {
 
65
                                out <<= 8;
 
66
                                out += x;
 
67
                        }
 
68
                        else
 
69
                        {
 
70
                                out = 0;
 
71
                                return out;
 
72
                        }
 
73
                }
 
74
        }
 
75
 
 
76
        return out;
 
77
}
 
78
 
 
79
#ifdef Q_OS_LINUX
 
80
static bool qt_buggy_fsw()
 
81
{
 
82
        // fixed in 4.3.5 and 4.4.1
 
83
        int ver = qVersionInt();
 
84
        int majmin = ver >> 8;
 
85
        if(majmin < 0x0403)
 
86
                return true;
 
87
        else if(majmin == 0x0403 && ver < 0x040305)
 
88
                return true;
 
89
        else if(majmin == 0x0404 && ver < 0x040401)
 
90
                return true;
 
91
        return false;
 
92
}
 
93
#else
 
94
static bool qt_buggy_fsw()
 
95
{
 
96
        return false;
 
97
}
 
98
#endif
 
99
 
 
100
// begin ugly hack for qca 2.0.0 with broken dirwatch support
 
101
 
 
102
// hacks:
 
103
//  1) we must construct with a valid file to watch.  passing an empty
 
104
//     string doesn't work.  this means we can't create the objects in
 
105
//     advance.  instead we'll use new/delete as necessary.
 
106
//  2) there's a wrong internal connect() statement in the qca source.
 
107
//     assuming fixed internals for qca 2.0.0, we can fix that connect from
 
108
//     here...
 
109
 
 
110
#include <QFileSystemWatcher>
 
111
 
 
112
// some structures below to give accessible interface to qca 2.0.0 internals
 
113
 
 
114
class DirWatch2 : public QObject
 
115
{
 
116
        Q_OBJECT
 
117
public:
 
118
        explicit DirWatch2(const QString &dir = QString(), QObject *parent = 0)
 
119
        {
 
120
                Q_UNUSED(dir);
 
121
                Q_UNUSED(parent);
 
122
        }
 
123
 
 
124
        ~DirWatch2()
 
125
        {
 
126
        }
 
127
 
 
128
        QString dirName() const
 
129
        {
 
130
                return QString();
 
131
        }
 
132
 
 
133
        void setDirName(const QString &dir)
 
134
        {
 
135
                Q_UNUSED(dir);
 
136
        }
 
137
 
 
138
Q_SIGNALS:
 
139
        void changed();
 
140
 
 
141
public:
 
142
        Q_DISABLE_COPY(DirWatch2)
 
143
 
 
144
        class Private;
 
145
        friend class Private;
 
146
        Private *d;
 
147
};
 
148
 
 
149
/*class FileWatch2 : public QObject
 
150
{
 
151
        Q_OBJECT
 
152
public:
 
153
        explicit FileWatch2(const QString &file = QString(), QObject *parent = 0)
 
154
        {
 
155
                Q_UNUSED(file);
 
156
                Q_UNUSED(parent);
 
157
        }
 
158
 
 
159
        ~FileWatch2()
 
160
        {
 
161
        }
 
162
 
 
163
        QString fileName() const
 
164
        {
 
165
                return QString();
 
166
        }
 
167
 
 
168
        void setFileName(const QString &file)
 
169
        {
 
170
                Q_UNUSED(file);
 
171
        }
 
172
 
 
173
Q_SIGNALS:
 
174
        void changed();
 
175
 
 
176
public:
 
177
        Q_DISABLE_COPY(FileWatch2)
 
178
 
 
179
        class Private;
 
180
        friend class Private;
 
181
        Private *d;
 
182
};*/
 
183
 
 
184
class QFileSystemWatcherRelay2 : public QObject
 
185
{
 
186
        Q_OBJECT
 
187
public:
 
188
};
 
189
 
 
190
class DirWatch2::Private : public QObject
 
191
{
 
192
        Q_OBJECT
 
193
public:
 
194
        DirWatch2 *q;
 
195
        QFileSystemWatcher *watcher;
 
196
        QFileSystemWatcherRelay2 *watcher_relay;
 
197
        QString dirName;
 
198
 
 
199
private slots:
 
200
        void watcher_changed(const QString &path)
 
201
        {
 
202
                Q_UNUSED(path);
 
203
        }
 
204
};
 
205
 
 
206
/*class FileWatch2::Private : public QObject
 
207
{
 
208
        Q_OBJECT
 
209
public:
 
210
        FileWatch2 *q;
 
211
        QFileSystemWatcher *watcher;
 
212
        QFileSystemWatcherRelay2 *watcher_relay;
 
213
        QString fileName;
 
214
 
 
215
private slots:
 
216
        void watcher_changed(const QString &path)
 
217
        {
 
218
                Q_UNUSED(path);
 
219
        }
 
220
};*/
 
221
 
 
222
static void hack_fix(DirWatch *dw)
 
223
{
 
224
        DirWatch2 *dw2 = reinterpret_cast<DirWatch2*>(dw);
 
225
        QObject::connect(dw2->d->watcher_relay, SIGNAL(directoryChanged(const QString &)), dw2->d, SLOT(watcher_changed(const QString &)));
 
226
        fprintf(stderr, "qca-gnupg: patching DirWatch to fix failed connect\n");
 
227
}
 
228
 
 
229
// end ugly hack
 
230
 
31
231
#ifdef Q_OS_WIN
32
232
static QString find_reg_gpgProgram()
33
233
{
109
309
        return out;
110
310
}
111
311
 
112
 
using namespace QCA;
113
 
 
114
 
namespace gpgQCAPlugin {
 
312
static void gpg_waitForFinished(GpgOp *gpg)
 
313
{
 
314
        while(1)
 
315
        {
 
316
                GpgOp::Event e = gpg->waitForEvent(-1);
 
317
                if(e.type == GpgOp::Event::Finished)
 
318
                        break;
 
319
        }
 
320
}
 
321
 
 
322
Q_GLOBAL_STATIC(QMutex, ksl_mutex)
 
323
 
 
324
class MyKeyStoreList;
 
325
static MyKeyStoreList *keyStoreList = 0;
 
326
 
 
327
static void gpg_keyStoreLog(const QString &str);
115
328
 
116
329
class MyPGPKeyContext : public PGPKeyContext
117
330
{
118
331
public:
119
332
        PGPKeyContextProps _props;
120
333
 
 
334
        // keys loaded externally (not from the keyring) need to have these
 
335
        //   values cached, since we can't extract them later
 
336
        QByteArray cacheExportBinary;
 
337
        QString cacheExportAscii;
 
338
 
121
339
        MyPGPKeyContext(Provider *p) : PGPKeyContext(p)
122
340
        {
123
 
                // FIXME
 
341
                // zero out the props
 
342
                _props.isSecret = false;
124
343
                _props.inKeyring = true;
125
 
                _props.isSecret = false;
126
344
                _props.isTrusted = false;
127
345
        }
128
346
 
131
349
                return new MyPGPKeyContext(*this);
132
350
        }
133
351
 
 
352
        void set(const GpgOp::Key &i, bool isSecret, bool inKeyring, bool isTrusted)
 
353
        {
 
354
                const GpgOp::KeyItem &ki = i.keyItems.first();
 
355
 
 
356
                _props.keyId = ki.id;
 
357
                _props.userIds = i.userIds;
 
358
                _props.isSecret = isSecret;
 
359
                _props.creationDate = ki.creationDate;
 
360
                _props.expirationDate = ki.expirationDate;
 
361
                _props.fingerprint = ki.fingerprint.toLower();
 
362
                _props.inKeyring = inKeyring;
 
363
                _props.isTrusted = isTrusted;
 
364
        }
 
365
 
134
366
        virtual const PGPKeyContextProps *props() const
135
367
        {
136
368
                return &_props;
138
370
 
139
371
        virtual QByteArray toBinary() const
140
372
        {
141
 
                // TODO
142
 
                return QByteArray();
 
373
                if(_props.inKeyring)
 
374
                {
 
375
                        GpgOp gpg(find_bin());
 
376
                        gpg.setAsciiFormat(false);
 
377
                        gpg.doExport(_props.keyId);
 
378
                        gpg_waitForFinished(&gpg);
 
379
                        gpg_keyStoreLog(gpg.readDiagnosticText());
 
380
                        if(!gpg.success())
 
381
                                return QByteArray();
 
382
                        return gpg.read();
 
383
                }
 
384
                else
 
385
                        return cacheExportBinary;
143
386
        }
144
387
 
145
388
        virtual QString toAscii() const
146
389
        {
 
390
                if(_props.inKeyring)
 
391
                {
 
392
                        GpgOp gpg(find_bin());
 
393
                        gpg.setAsciiFormat(true);
 
394
                        gpg.doExport(_props.keyId);
 
395
                        gpg_waitForFinished(&gpg);
 
396
                        gpg_keyStoreLog(gpg.readDiagnosticText());
 
397
                        if(!gpg.success())
 
398
                                return QString();
 
399
                        return QString::fromLocal8Bit(gpg.read());
 
400
                }
 
401
                else
 
402
                        return cacheExportAscii;
 
403
        }
 
404
 
 
405
        static void cleanup_temp_keyring(const QString &name)
 
406
        {
 
407
                QFile::remove(name);
 
408
                QFile::remove(name + '~'); // remove possible backup file
 
409
        }
 
410
 
 
411
        virtual ConvertResult fromBinary(const QByteArray &a)
 
412
        {
 
413
                GpgOp::Key key;
 
414
                bool sec = false;
 
415
 
 
416
                // temporary keyrings
 
417
                QString pubname, secname;
 
418
 
 
419
                QTemporaryFile pubtmp(QDir::tempPath() + QLatin1String("/qca_gnupg_tmp.XXXXXX.gpg"));
 
420
                if(!pubtmp.open())
 
421
                        return ErrorDecode;
 
422
 
 
423
                QTemporaryFile sectmp(QDir::tempPath() + QLatin1String("/qca_gnupg_tmp.XXXXXX.gpg"));
 
424
                if(!sectmp.open())
 
425
                        return ErrorDecode;
 
426
 
 
427
                pubname = pubtmp.fileName();
 
428
                secname = sectmp.fileName();
 
429
 
 
430
                // we turn off autoRemove so that we can close the files
 
431
                //   without them getting deleted
 
432
                pubtmp.setAutoRemove(false);
 
433
                sectmp.setAutoRemove(false);
 
434
                pubtmp.close();
 
435
                sectmp.close();
 
436
 
 
437
                // import key into temporary keyring
147
438
                GpgOp gpg(find_bin());
 
439
                gpg.setKeyrings(pubname, secname);
 
440
                gpg.doImport(a);
 
441
                gpg_waitForFinished(&gpg);
 
442
                gpg_keyStoreLog(gpg.readDiagnosticText());
 
443
                // comment this out.  apparently gpg will report failure for
 
444
                //   an import if there are trust issues, even though the
 
445
                //   key actually did get imported
 
446
                /*if(!gpg.success())
 
447
                {
 
448
                        cleanup_temp_keyring(pubname);
 
449
                        cleanup_temp_keyring(secname);
 
450
                        return ErrorDecode;
 
451
                }*/
 
452
 
 
453
                // now extract the key from gpg like normal
 
454
 
 
455
                // is it a public key?
 
456
                gpg.doPublicKeys();
 
457
                gpg_waitForFinished(&gpg);
 
458
                gpg_keyStoreLog(gpg.readDiagnosticText());
 
459
                if(!gpg.success())
 
460
                {
 
461
                        cleanup_temp_keyring(pubname);
 
462
                        cleanup_temp_keyring(secname);
 
463
                        return ErrorDecode;
 
464
                }
 
465
 
 
466
                GpgOp::KeyList pubkeys = gpg.keys();
 
467
                if(!pubkeys.isEmpty())
 
468
                {
 
469
                        key = pubkeys.first();
 
470
                }
 
471
                else
 
472
                {
 
473
                        // is it a secret key?
 
474
                        gpg.doSecretKeys();
 
475
                        gpg_waitForFinished(&gpg);
 
476
                        gpg_keyStoreLog(gpg.readDiagnosticText());
 
477
                        if(!gpg.success())
 
478
                        {
 
479
                                cleanup_temp_keyring(pubname);
 
480
                                cleanup_temp_keyring(secname);
 
481
                                return ErrorDecode;
 
482
                        }
 
483
 
 
484
                        GpgOp::KeyList seckeys = gpg.keys();
 
485
                        if(!seckeys.isEmpty())
 
486
                        {
 
487
                                key = seckeys.first();
 
488
                                sec = true;
 
489
                        }
 
490
                        else
 
491
                        {
 
492
                                // no keys found
 
493
                                cleanup_temp_keyring(pubname);
 
494
                                cleanup_temp_keyring(secname);
 
495
                                return ErrorDecode;
 
496
                        }
 
497
                }
 
498
 
 
499
                // export binary/ascii and cache
 
500
 
 
501
                gpg.setAsciiFormat(false);
 
502
                gpg.doExport(key.keyItems.first().id);
 
503
                gpg_waitForFinished(&gpg);
 
504
                gpg_keyStoreLog(gpg.readDiagnosticText());
 
505
                if(!gpg.success())
 
506
                {
 
507
                        cleanup_temp_keyring(pubname);
 
508
                        cleanup_temp_keyring(secname);
 
509
                        return ErrorDecode;
 
510
                }
 
511
                cacheExportBinary = gpg.read();
 
512
 
148
513
                gpg.setAsciiFormat(true);
149
 
                gpg.doExport(_props.keyId);
150
 
                while(1)
 
514
                gpg.doExport(key.keyItems.first().id);
 
515
                gpg_waitForFinished(&gpg);
 
516
                gpg_keyStoreLog(gpg.readDiagnosticText());
 
517
                if(!gpg.success())
151
518
                {
152
 
                        GpgOp::Event e = gpg.waitForEvent(-1);
153
 
                        if(e.type == GpgOp::Event::Finished)
154
 
                                break;
 
519
                        cleanup_temp_keyring(pubname);
 
520
                        cleanup_temp_keyring(secname);
 
521
                        return ErrorDecode;
155
522
                }
156
 
                if(!gpg.success())
157
 
                        return QString();
158
 
                QString str = QString::fromLocal8Bit(gpg.read());
159
 
                return str;
160
 
        }
161
 
 
162
 
        virtual ConvertResult fromBinary(const QByteArray &a)
163
 
        {
164
 
                // TODO
165
 
                Q_UNUSED(a);
166
 
                return ErrorDecode;
 
523
                cacheExportAscii = QString::fromLocal8Bit(gpg.read());
 
524
 
 
525
                // all done
 
526
 
 
527
                cleanup_temp_keyring(pubname);
 
528
                cleanup_temp_keyring(secname);
 
529
 
 
530
                set(key, sec, false, false);
 
531
                return ConvertGood;
167
532
        }
168
533
 
169
534
        virtual ConvertResult fromAscii(const QString &s)
170
535
        {
171
 
                // TODO
172
 
                Q_UNUSED(s);
173
 
                return ErrorDecode;
 
536
                // GnuPG does ascii/binary detection for imports, so for
 
537
                //   simplicity we consider an ascii import to just be a
 
538
                //   binary import that happens to be comprised of ascii
 
539
                return fromBinary(s.toLocal8Bit());
174
540
        }
175
541
};
176
542
 
241
607
 
242
608
        virtual QString serialize() const
243
609
        {
 
610
                // we only serialize the key id.  this means the keyring
 
611
                //   must be available to restore the data
244
612
                QStringList out;
245
613
                out += escape_string("qca-gnupg-1");
246
614
                out += escape_string(pub.keyId());
248
616
        }
249
617
};
250
618
 
251
 
class MyMessageContext;
252
 
 
253
 
GpgOp *global_gpg;
254
 
 
255
 
/*class MyKeyStore : public KeyStoreContext
 
619
// since keyring files are often modified by creating a new copy and
 
620
//   overwriting the original file, this messes up Qt's file watching
 
621
//   capability since the original file goes away.  to work around this
 
622
//   problem, we'll watch the directories containing the keyring files
 
623
//   instead of watching the actual files themselves.
 
624
//
 
625
// FIXME: consider moving this logic into FileWatch
 
626
class RingWatch : public QObject
256
627
{
257
628
        Q_OBJECT
258
629
public:
259
 
        friend class MyMessageContext;
260
 
 
261
 
        MyKeyStore(Provider *p) : KeyStoreContext(p) {}
262
 
 
263
 
        virtual Provider::Context *clone() const
264
 
        {
265
 
                return 0;
266
 
        }
267
 
 
268
 
        virtual int contextId() const
269
 
        {
270
 
                // TODO
271
 
                return 0; // there is only 1 context, so this can be static
272
 
        }
273
 
 
274
 
        virtual QString deviceId() const
275
 
        {
276
 
                // TODO
277
 
                return "qca-gnupg-(gpg)";
278
 
        }
279
 
 
280
 
        virtual KeyStore::Type type() const
281
 
        {
282
 
                return KeyStore::PGPKeyring;
283
 
        }
284
 
 
285
 
        virtual QString name() const
286
 
        {
287
 
                return "GnuPG Keyring";
288
 
        }
289
 
 
290
 
        virtual QList<KeyStoreEntryContext*> entryList() const
291
 
        {
292
 
                QList<KeyStoreEntryContext*> out;
293
 
 
294
 
                GpgOp::KeyList seckeys;
295
 
                {
296
 
                        GpgOp gpg(find_bin());
297
 
                        gpg.doSecretKeys();
298
 
                        while(1)
299
 
                        {
300
 
                                GpgOp::Event e = gpg.waitForEvent(-1);
301
 
                                if(e.type == GpgOp::Event::Finished)
302
 
                                        break;
303
 
                        }
304
 
                        if(!gpg.success())
305
 
                                return out;
306
 
                        seckeys = gpg.keys();
307
 
                }
308
 
 
309
 
                GpgOp::KeyList pubkeys;
310
 
                {
311
 
                        GpgOp gpg(find_bin());
312
 
                        gpg.doPublicKeys();
313
 
                        while(1)
314
 
                        {
315
 
                                GpgOp::Event e = gpg.waitForEvent(-1);
316
 
                                if(e.type == GpgOp::Event::Finished)
317
 
                                        break;
318
 
                        }
319
 
                        if(!gpg.success())
320
 
                                return out;
321
 
                        pubkeys = gpg.keys();
322
 
                }
323
 
 
324
 
                for(int n = 0; n < pubkeys.count(); ++n)
325
 
                {
326
 
                        QString id = pubkeys[n].keyItems.first().id;
327
 
                        MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
328
 
                        kc->_props.keyId = id;
329
 
                        kc->_props.userIds = QStringList() << pubkeys[n].userIds.first();
330
 
                        PGPKey pub, sec;
331
 
                        pub.change(kc);
332
 
                        for(int i = 0; i < seckeys.count(); ++i)
333
 
                        {
334
 
                                if(seckeys[i].keyItems.first().id == id)
 
630
        class DirItem
 
631
        {
 
632
        public:
 
633
                DirWatch *dirWatch;
 
634
                SafeTimer *changeTimer;
 
635
        };
 
636
 
 
637
        class FileItem
 
638
        {
 
639
        public:
 
640
                DirWatch *dirWatch;
 
641
                QString fileName;
 
642
                bool exists;
 
643
                qint64 size;
 
644
                QDateTime lastModified;
 
645
        };
 
646
 
 
647
        QList<DirItem> dirs;
 
648
        QList<FileItem> files;
 
649
 
 
650
        RingWatch(QObject *parent = 0) :
 
651
                QObject(parent)
 
652
        {
 
653
        }
 
654
 
 
655
        ~RingWatch()
 
656
        {
 
657
                clear();
 
658
        }
 
659
 
 
660
        void add(const QString &filePath)
 
661
        {
 
662
                QFileInfo fi(filePath);
 
663
                QString path = fi.absolutePath();
 
664
 
 
665
                // watching this path already?
 
666
                DirWatch *dirWatch = 0;
 
667
                foreach(const DirItem &di, dirs)
 
668
                {
 
669
                        if(di.dirWatch->dirName() == path)
 
670
                        {
 
671
                                dirWatch = di.dirWatch;
 
672
                                break;
 
673
                        }
 
674
                }
 
675
 
 
676
                // if not, make a watcher
 
677
                if(!dirWatch)
 
678
                {
 
679
                        //printf("creating dirwatch for [%s]\n", qPrintable(path));
 
680
 
 
681
                        DirItem di;
 
682
                        di.dirWatch = new DirWatch(path, this);
 
683
                        connect(di.dirWatch, SIGNAL(changed()), SLOT(dirChanged()));
 
684
 
 
685
                        if(qcaVersion() == 0x020000)
 
686
                                hack_fix(di.dirWatch);
 
687
 
 
688
                        di.changeTimer = new SafeTimer(this);
 
689
                        di.changeTimer->setSingleShot(true);
 
690
                        connect(di.changeTimer, SIGNAL(timeout()), SLOT(handleChanged()));
 
691
 
 
692
                        dirWatch = di.dirWatch;
 
693
                        dirs += di;
 
694
                }
 
695
 
 
696
                FileItem i;
 
697
                i.dirWatch = dirWatch;
 
698
                i.fileName = fi.fileName();
 
699
                i.exists = fi.exists();
 
700
                if(i.exists)
 
701
                {
 
702
                        i.size = fi.size();
 
703
                        i.lastModified = fi.lastModified();
 
704
                }
 
705
                files += i;
 
706
 
 
707
                //printf("watching [%s] in [%s]\n", qPrintable(fi.fileName()), qPrintable(i.dirWatch->dirName()));
 
708
        }
 
709
 
 
710
        void clear()
 
711
        {
 
712
                files.clear();
 
713
 
 
714
                foreach(const DirItem &di, dirs)
 
715
                {
 
716
                        delete di.changeTimer;
 
717
                        delete di.dirWatch;
 
718
                }
 
719
 
 
720
                dirs.clear();
 
721
        }
 
722
 
 
723
signals:
 
724
        void changed(const QString &filePath);
 
725
 
 
726
private slots:
 
727
        void dirChanged()
 
728
        {
 
729
                DirWatch *dirWatch = (DirWatch *)sender();
 
730
 
 
731
                int at = -1;
 
732
                for(int n = 0; n < dirs.count(); ++n)
 
733
                {
 
734
                        if(dirs[n].dirWatch == dirWatch)
 
735
                        {
 
736
                                at = n;
 
737
                                break;
 
738
                        }
 
739
                }
 
740
                if(at == -1)
 
741
                        return;
 
742
 
 
743
                // we get a ton of change notifications for the dir when
 
744
                //   something happens..   let's collect them and only
 
745
                //   report after 100ms
 
746
 
 
747
                if(!dirs[at].changeTimer->isActive())
 
748
                        dirs[at].changeTimer->start(100);
 
749
        }
 
750
 
 
751
        void handleChanged()
 
752
        {
 
753
                SafeTimer *t = (SafeTimer *)sender();
 
754
 
 
755
                int at = -1;
 
756
                for(int n = 0; n < dirs.count(); ++n)
 
757
                {
 
758
                        if(dirs[n].changeTimer == t)
 
759
                        {
 
760
                                at = n;
 
761
                                break;
 
762
                        }
 
763
                }
 
764
                if(at == -1)
 
765
                        return;
 
766
 
 
767
                DirWatch *dirWatch = dirs[at].dirWatch;
 
768
                QString dir = dirWatch->dirName();
 
769
 
 
770
                // see which files changed
 
771
                QStringList changeList;
 
772
                for(int n = 0; n < files.count(); ++n)
 
773
                {
 
774
                        FileItem &i = files[n];
 
775
                        QString filePath = dir + '/' + i.fileName;
 
776
                        QFileInfo fi(filePath);
 
777
 
 
778
                        // if the file didn't exist, and still doesn't, skip
 
779
                        if(!i.exists && !fi.exists())
 
780
                                continue;
 
781
 
 
782
                        // size/lastModified should only get checked here if
 
783
                        //   the file existed and still exists
 
784
                        if(fi.exists() != i.exists || fi.size() != i.size || fi.lastModified() != i.lastModified)
 
785
                        {
 
786
                                changeList += filePath;
 
787
 
 
788
                                i.exists = fi.exists();
 
789
                                if(i.exists)
335
790
                                {
336
 
                                        MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
337
 
                                        kc->_props.keyId = id;
338
 
                                        kc->_props.userIds = QStringList() << pubkeys[n].userIds.first();
339
 
                                        sec.change(kc);
 
791
                                        i.size = fi.size();
 
792
                                        i.lastModified = fi.lastModified();
340
793
                                }
341
794
                        }
342
 
 
343
 
                        MyKeyStoreEntry *c = new MyKeyStoreEntry(pub, sec, provider());
344
 
                        out.append(c);
345
795
                }
346
796
 
347
 
                return out;
348
 
        }
349
 
 
350
 
        virtual QList<KeyStoreEntry::Type> entryTypes() const
351
 
        {
352
 
                QList<KeyStoreEntry::Type> list;
353
 
                list += KeyStoreEntry::TypePGPSecretKey;
354
 
                list += KeyStoreEntry::TypePGPPublicKey;
355
 
                return list;
356
 
        }
357
 
 
358
 
        virtual void submitPassphrase(const SecureArray &a)
359
 
        {
360
 
                global_gpg->submitPassphrase(a.toByteArray());
361
 
        }
362
 
};*/
363
 
 
364
 
class MyKeyStoreList;
365
 
class MyMessageContext;
366
 
 
367
 
static MyKeyStoreList *keyStoreList = 0;
 
797
                foreach(const QString &s, changeList)
 
798
                        emit changed(s);
 
799
        }
 
800
};
368
801
 
369
802
class MyKeyStoreList : public KeyStoreListContext
370
803
{
371
804
        Q_OBJECT
372
805
public:
373
 
        friend class MyMessageContext;
374
 
        //MyKeyStore *ks;
 
806
        int init_step;
 
807
        bool initialized;
 
808
        GpgOp gpg;
 
809
        GpgOp::KeyList pubkeys, seckeys;
 
810
        QString pubring, secring;
 
811
        bool pubdirty, secdirty;
 
812
        RingWatch ringWatch;
 
813
        QMutex ringMutex;
375
814
 
376
 
        MyKeyStoreList(Provider *p) : KeyStoreListContext(p)
 
815
        MyKeyStoreList(Provider *p) :
 
816
                KeyStoreListContext(p),
 
817
                initialized(false),
 
818
                gpg(find_bin(), this),
 
819
                pubdirty(false),
 
820
                secdirty(false),
 
821
                ringWatch(this)
377
822
        {
 
823
                QMutexLocker locker(ksl_mutex());
378
824
                keyStoreList = this;
379
825
 
380
 
                //ks = 0;
381
 
 
382
 
                //ks = new MyKeyStore(provider());
 
826
                connect(&gpg, SIGNAL(finished()), SLOT(gpg_finished()));
 
827
                connect(&ringWatch, SIGNAL(changed(const QString &)), SLOT(ring_changed(const QString &)));
383
828
        }
384
829
 
385
830
        ~MyKeyStoreList()
386
831
        {
387
 
                //delete ks;
388
 
 
 
832
                QMutexLocker locker(ksl_mutex());
389
833
                keyStoreList = 0;
390
834
        }
391
835
 
394
838
                return 0;
395
839
        }
396
840
 
397
 
        /*virtual void start()
398
 
        {
399
 
                QTimer::singleShot(0, this, SLOT(do_ready()));
400
 
        }*/
 
841
        static MyKeyStoreList *instance()
 
842
        {
 
843
                QMutexLocker locker(ksl_mutex());
 
844
                return keyStoreList;
 
845
        }
 
846
 
 
847
        void ext_keyStoreLog(const QString &str)
 
848
        {
 
849
                if(str.isEmpty())
 
850
                        return;
 
851
 
 
852
                // FIXME: collect and emit in one pass
 
853
                QMetaObject::invokeMethod(this, "diagnosticText", Qt::QueuedConnection, Q_ARG(QString, str));
 
854
        }
 
855
 
 
856
        virtual void start()
 
857
        {
 
858
                // kick start our init procedure:
 
859
                //   ensure gpg is installed
 
860
                //   obtain keyring file names for monitoring
 
861
                //   cache initial keyrings
 
862
 
 
863
                init_step = 0;
 
864
                gpg.doCheck();
 
865
        }
401
866
 
402
867
        virtual QList<int> keyStores()
403
868
        {
 
869
                // we just support one fixed keyring, if any
404
870
                QList<int> list;
405
 
                list += 0; // TODO
 
871
                if(initialized)
 
872
                        list += 0;
406
873
                return list;
407
874
        }
408
875
 
413
880
 
414
881
        virtual QString storeId(int) const
415
882
        {
416
 
                // TODO
417
883
                return "qca-gnupg";
418
884
        }
419
885
 
432
898
 
433
899
        virtual QList<KeyStoreEntryContext*> entryList(int)
434
900
        {
 
901
                QMutexLocker locker(&ringMutex);
 
902
 
435
903
                QList<KeyStoreEntryContext*> out;
436
904
 
437
 
                GpgOp::KeyList seckeys;
438
 
                {
439
 
                        GpgOp gpg(find_bin());
440
 
                        gpg.doSecretKeys();
441
 
                        while(1)
442
 
                        {
443
 
                                GpgOp::Event e = gpg.waitForEvent(-1);
444
 
                                if(e.type == GpgOp::Event::Finished)
445
 
                                        break;
446
 
                        }
447
 
                        if(!gpg.success())
448
 
                                return out;
449
 
                        seckeys = gpg.keys();
450
 
                }
451
 
 
452
 
                GpgOp::KeyList pubkeys;
453
 
                {
454
 
                        GpgOp gpg(find_bin());
455
 
                        gpg.doPublicKeys();
456
 
                        while(1)
457
 
                        {
458
 
                                GpgOp::Event e = gpg.waitForEvent(-1);
459
 
                                if(e.type == GpgOp::Event::Finished)
460
 
                                        break;
461
 
                        }
462
 
                        if(!gpg.success())
463
 
                                return out;
464
 
                        pubkeys = gpg.keys();
465
 
                }
466
 
 
467
 
                for(int n = 0; n < pubkeys.count(); ++n)
468
 
                {
469
 
                        QString id = pubkeys[n].keyItems.first().id;
 
905
                foreach(const GpgOp::Key &pkey, pubkeys)
 
906
                {
 
907
                        PGPKey pub, sec;
 
908
 
 
909
                        QString id = pkey.keyItems.first().id;
 
910
 
470
911
                        MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
471
 
                        kc->_props.keyId = id;
472
 
                        kc->_props.userIds = QStringList() << pubkeys[n].userIds.first();
473
 
                        PGPKey pub, sec;
 
912
                        // not secret, in keyring
 
913
                        kc->set(pkey, false, true, pkey.isTrusted);
474
914
                        pub.change(kc);
475
 
                        for(int i = 0; i < seckeys.count(); ++i)
476
 
                        {
477
 
                                if(seckeys[i].keyItems.first().id == id)
478
 
                                {
479
 
                                        MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
480
 
                                        kc->_props.keyId = id;
481
 
                                        kc->_props.userIds = QStringList() << pubkeys[n].userIds.first();
482
 
                                        kc->_props.isSecret = true;
483
 
                                        sec.change(kc);
484
 
                                }
485
 
                        }
 
915
 
 
916
                        // optional
 
917
                        sec = getSecKey(id, pkey.userIds);
486
918
 
487
919
                        MyKeyStoreEntry *c = new MyKeyStoreEntry(pub, sec, provider());
488
920
                        c->_storeId = storeId(0);
493
925
                return out;
494
926
        }
495
927
 
 
928
        virtual KeyStoreEntryContext *entry(int, const QString &entryId)
 
929
        {
 
930
                QMutexLocker locker(&ringMutex);
 
931
 
 
932
                PGPKey pub = getPubKey(entryId);
 
933
                if(pub.isNull())
 
934
                        return 0;
 
935
 
 
936
                // optional
 
937
                PGPKey sec = getSecKey(entryId, static_cast<MyPGPKeyContext *>(pub.context())->_props.userIds);
 
938
 
 
939
                MyKeyStoreEntry *c = new MyKeyStoreEntry(pub, sec, provider());
 
940
                c->_storeId = storeId(0);
 
941
                c->_storeName = name(0);
 
942
                return c;
 
943
        }
 
944
 
496
945
        virtual KeyStoreEntryContext *entryPassive(const QString &serialized)
497
946
        {
 
947
                QMutexLocker locker(&ringMutex);
 
948
 
498
949
                QStringList parts = serialized.split(':');
499
950
                if(parts.count() < 2)
500
951
                        return 0;
501
952
                if(unescape_string(parts[0]) != "qca-gnupg-1")
502
953
                        return 0;
503
954
 
504
 
                QString keyId = unescape_string(parts[1]);
505
 
 
506
 
                GpgOp::KeyList seckeys;
507
 
                {
508
 
                        GpgOp gpg(find_bin());
509
 
                        gpg.doSecretKeys();
510
 
                        while(1)
511
 
                        {
512
 
                                GpgOp::Event e = gpg.waitForEvent(-1);
513
 
                                if(e.type == GpgOp::Event::Finished)
514
 
                                        break;
515
 
                        }
516
 
                        if(!gpg.success())
517
 
                                return 0;
518
 
                        seckeys = gpg.keys();
519
 
                }
520
 
 
521
 
                GpgOp::KeyList pubkeys;
522
 
                {
523
 
                        GpgOp gpg(find_bin());
524
 
                        gpg.doPublicKeys();
525
 
                        while(1)
526
 
                        {
527
 
                                GpgOp::Event e = gpg.waitForEvent(-1);
528
 
                                if(e.type == GpgOp::Event::Finished)
529
 
                                        break;
530
 
                        }
531
 
                        if(!gpg.success())
532
 
                                return 0;
533
 
                        pubkeys = gpg.keys();
534
 
                }
535
 
 
536
 
                int at = -1;
537
 
                for(int n = 0; n < pubkeys.count(); ++n)
538
 
                {
539
 
                        QString id = pubkeys[n].keyItems.first().id;
540
 
                        if(id == keyId)
541
 
                        {
542
 
                                at = n;
543
 
                                break;
544
 
                        }
545
 
                }
546
 
                if(at == -1)
547
 
                        return 0;
548
 
 
549
 
                MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
550
 
                kc->_props.keyId = keyId;
551
 
                kc->_props.userIds = QStringList() << pubkeys[at].userIds.first();
552
 
                PGPKey pub, sec;
553
 
                pub.change(kc);
554
 
                for(int i = 0; i < seckeys.count(); ++i)
555
 
                {
556
 
                        if(seckeys[i].keyItems.first().id == keyId)
557
 
                        {
558
 
                                MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
559
 
                                kc->_props.keyId = keyId;
560
 
                                kc->_props.userIds = QStringList() << pubkeys[at].userIds.first();
561
 
                                kc->_props.isSecret = true;
562
 
                                sec.change(kc);
563
 
                        }
564
 
                }
 
955
                QString entryId = unescape_string(parts[1]);
 
956
                if(entryId.isEmpty())
 
957
                        return 0;
 
958
 
 
959
                PGPKey pub = getPubKey(entryId);
 
960
                if(pub.isNull())
 
961
                        return 0;
 
962
 
 
963
                // optional
 
964
                PGPKey sec = getSecKey(entryId, static_cast<MyPGPKeyContext *>(pub.context())->_props.userIds);
565
965
 
566
966
                MyKeyStoreEntry *c = new MyKeyStoreEntry(pub, sec, provider());
567
967
                c->_storeId = storeId(0);
569
969
                return c;
570
970
        }
571
971
 
572
 
        virtual void submitPassphrase(int, int, const SecureArray &a)
573
 
        {
574
 
                global_gpg->submitPassphrase(a.toByteArray());
575
 
        }
576
 
 
577
 
/*private slots:
578
 
        void do_ready()
579
 
        {
580
 
                emit busyEnd();
581
 
        }*/
 
972
        // TODO: cache should reflect this change immediately
 
973
        virtual QString writeEntry(int, const PGPKey &key)
 
974
        {
 
975
                const MyPGPKeyContext *kc = static_cast<const MyPGPKeyContext *>(key.context());
 
976
                QByteArray buf = kc->toBinary();
 
977
 
 
978
                GpgOp gpg(find_bin());
 
979
                gpg.doImport(buf);
 
980
                gpg_waitForFinished(&gpg);
 
981
                gpg_keyStoreLog(gpg.readDiagnosticText());
 
982
                if(!gpg.success())
 
983
                        return QString();
 
984
 
 
985
                return kc->_props.keyId;
 
986
        }
 
987
 
 
988
        // TODO: cache should reflect this change immediately
 
989
        virtual bool removeEntry(int, const QString &entryId)
 
990
        {
 
991
                ringMutex.lock();
 
992
                PGPKey pub = getPubKey(entryId);
 
993
                ringMutex.unlock();
 
994
 
 
995
                const MyPGPKeyContext *kc = static_cast<const MyPGPKeyContext *>(pub.context());
 
996
                QString fingerprint = kc->_props.fingerprint;
 
997
 
 
998
                GpgOp gpg(find_bin());
 
999
                gpg.doDeleteKey(fingerprint);
 
1000
                gpg_waitForFinished(&gpg);
 
1001
                gpg_keyStoreLog(gpg.readDiagnosticText());
 
1002
                return gpg.success();
 
1003
        }
 
1004
 
 
1005
        // internal
 
1006
        PGPKey getPubKey(const QString &keyId) const
 
1007
        {
 
1008
                int at = -1;
 
1009
                for(int n = 0; n < pubkeys.count(); ++n)
 
1010
                {
 
1011
                        if(pubkeys[n].keyItems.first().id == keyId)
 
1012
                        {
 
1013
                                at = n;
 
1014
                                break;
 
1015
                        }
 
1016
                }
 
1017
                if(at == -1)
 
1018
                        return PGPKey();
 
1019
 
 
1020
                const GpgOp::Key &pkey = pubkeys[at];
 
1021
 
 
1022
                PGPKey pub;
 
1023
                MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
 
1024
                // not secret, in keyring
 
1025
                kc->set(pkey, false, true, pkey.isTrusted);
 
1026
                pub.change(kc);
 
1027
 
 
1028
                return pub;
 
1029
        }
 
1030
 
 
1031
        // internal
 
1032
        PGPKey getSecKey(const QString &keyId, const QStringList &userIdsOverride) const
 
1033
        {
 
1034
                Q_UNUSED(userIdsOverride);
 
1035
 
 
1036
                int at = -1;
 
1037
                for(int n = 0; n < seckeys.count(); ++n)
 
1038
                {
 
1039
                        if(seckeys[n].keyItems.first().id == keyId)
 
1040
                        {
 
1041
                                at = n;
 
1042
                                break;
 
1043
                        }
 
1044
                }
 
1045
                if(at == -1)
 
1046
                        return PGPKey();
 
1047
 
 
1048
                const GpgOp::Key &skey = seckeys[at];
 
1049
 
 
1050
                PGPKey sec;
 
1051
                MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
 
1052
                // secret, in keyring, trusted
 
1053
                kc->set(skey, true, true, true);
 
1054
                //kc->_props.userIds = userIdsOverride;
 
1055
                sec.change(kc);
 
1056
 
 
1057
                return sec;
 
1058
        }
 
1059
 
 
1060
        PGPKey publicKeyFromId(const QString &keyId)
 
1061
        {
 
1062
                QMutexLocker locker(&ringMutex);
 
1063
 
 
1064
                int at = -1;
 
1065
                for(int n = 0; n < pubkeys.count(); ++n)
 
1066
                {
 
1067
                        const GpgOp::Key &pkey = pubkeys[n];
 
1068
                        for(int k = 0; k < pkey.keyItems.count(); ++k)
 
1069
                        {
 
1070
                                const GpgOp::KeyItem &ki = pkey.keyItems[k];
 
1071
                                if(ki.id == keyId)
 
1072
                                {
 
1073
                                        at = n;
 
1074
                                        break;
 
1075
                                }
 
1076
                        }
 
1077
                        if(at != -1)
 
1078
                                break;
 
1079
                }
 
1080
                if(at == -1)
 
1081
                        return PGPKey();
 
1082
 
 
1083
                const GpgOp::Key &pkey = pubkeys[at];
 
1084
 
 
1085
                PGPKey pub;
 
1086
                MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
 
1087
                // not secret, in keyring
 
1088
                kc->set(pkey, false, true, pkey.isTrusted);
 
1089
                pub.change(kc);
 
1090
 
 
1091
                return pub;
 
1092
        }
 
1093
 
 
1094
        PGPKey secretKeyFromId(const QString &keyId)
 
1095
        {
 
1096
                QMutexLocker locker(&ringMutex);
 
1097
 
 
1098
                int at = -1;
 
1099
                for(int n = 0; n < seckeys.count(); ++n)
 
1100
                {
 
1101
                        const GpgOp::Key &skey = seckeys[n];
 
1102
                        for(int k = 0; k < skey.keyItems.count(); ++k)
 
1103
                        {
 
1104
                                const GpgOp::KeyItem &ki = skey.keyItems[k];
 
1105
                                if(ki.id == keyId)
 
1106
                                {
 
1107
                                        at = n;
 
1108
                                        break;
 
1109
                                }
 
1110
                        }
 
1111
                        if(at != -1)
 
1112
                                break;
 
1113
                }
 
1114
                if(at == -1)
 
1115
                        return PGPKey();
 
1116
 
 
1117
                const GpgOp::Key &skey = seckeys[at];
 
1118
 
 
1119
                PGPKey sec;
 
1120
                MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
 
1121
                // secret, in keyring, trusted
 
1122
                kc->set(skey, true, true, true);
 
1123
                sec.change(kc);
 
1124
 
 
1125
                return sec;
 
1126
        }
 
1127
 
 
1128
private slots:
 
1129
        void gpg_finished()
 
1130
        {
 
1131
                gpg_keyStoreLog(gpg.readDiagnosticText());
 
1132
 
 
1133
                if(!initialized)
 
1134
                {
 
1135
                        // any steps that fail during init, just give up completely
 
1136
                        if(!gpg.success())
 
1137
                        {
 
1138
                                ringWatch.clear();
 
1139
                                emit busyEnd();
 
1140
                                return;
 
1141
                        }
 
1142
 
 
1143
                        // check
 
1144
                        if(init_step == 0)
 
1145
                        {
 
1146
                                // obtain keyring file names for monitoring
 
1147
                                init_step = 1;
 
1148
                                gpg.doSecretKeyringFile();
 
1149
                        }
 
1150
                        // secret keyring filename
 
1151
                        else if(init_step == 1)
 
1152
                        {
 
1153
                                secring = gpg.keyringFile();
 
1154
 
 
1155
                                if(qt_buggy_fsw())
 
1156
                                        fprintf(stderr, "qca-gnupg: disabling keyring monitoring in Qt version < 4.3.5 or 4.4.1\n");
 
1157
 
 
1158
                                if(!secring.isEmpty())
 
1159
                                {
 
1160
                                        if(!qt_buggy_fsw())
 
1161
                                                ringWatch.add(secring);
 
1162
                                }
 
1163
 
 
1164
                                // obtain keyring file names for monitoring
 
1165
                                init_step = 2;
 
1166
                                gpg.doPublicKeyringFile();
 
1167
                        }
 
1168
                        // public keyring filename
 
1169
                        else if(init_step == 2)
 
1170
                        {
 
1171
                                pubring = gpg.keyringFile();
 
1172
                                if(!pubring.isEmpty())
 
1173
                                {
 
1174
                                        if(!qt_buggy_fsw())
 
1175
                                                ringWatch.add(pubring);
 
1176
                                }
 
1177
 
 
1178
                                // cache initial keyrings
 
1179
                                init_step = 3;
 
1180
                                gpg.doSecretKeys();
 
1181
                        }
 
1182
                        else if(init_step == 3)
 
1183
                        {
 
1184
                                ringMutex.lock();
 
1185
                                seckeys = gpg.keys();
 
1186
                                ringMutex.unlock();
 
1187
 
 
1188
                                // cache initial keyrings
 
1189
                                init_step = 4;
 
1190
                                gpg.doPublicKeys();
 
1191
                        }
 
1192
                        else if(init_step == 4)
 
1193
                        {
 
1194
                                ringMutex.lock();
 
1195
                                pubkeys = gpg.keys();
 
1196
                                ringMutex.unlock();
 
1197
 
 
1198
                                initialized = true;
 
1199
                                handleDirtyRings();
 
1200
                                emit busyEnd();
 
1201
                        }
 
1202
                }
 
1203
                else
 
1204
                {
 
1205
                        if(!gpg.success())
 
1206
                                return;
 
1207
 
 
1208
                        GpgOp::Type op = gpg.op();
 
1209
                        if(op == GpgOp::SecretKeys)
 
1210
                        {
 
1211
                                ringMutex.lock();
 
1212
                                seckeys = gpg.keys();
 
1213
                                ringMutex.unlock();
 
1214
 
 
1215
                                secdirty = false;
 
1216
                        }
 
1217
                        else if(op == GpgOp::PublicKeys)
 
1218
                        {
 
1219
                                ringMutex.lock();
 
1220
                                pubkeys = gpg.keys();
 
1221
                                ringMutex.unlock();
 
1222
 
 
1223
                                pubdirty = false;
 
1224
                        }
 
1225
 
 
1226
                        if(!secdirty && !pubdirty)
 
1227
                        {
 
1228
                                emit storeUpdated(0);
 
1229
                                return;
 
1230
                        }
 
1231
 
 
1232
                        handleDirtyRings();
 
1233
                }
 
1234
        }
 
1235
 
 
1236
        void ring_changed(const QString &filePath)
 
1237
        {
 
1238
                ext_keyStoreLog(QString("ring_changed: [%1]\n").arg(filePath));
 
1239
 
 
1240
                if(filePath == secring)
 
1241
                        sec_changed();
 
1242
                else if(filePath == pubring)
 
1243
                        pub_changed();
 
1244
        }
 
1245
 
 
1246
private:
 
1247
        void pub_changed()
 
1248
        {
 
1249
                pubdirty = true;
 
1250
                handleDirtyRings();
 
1251
        }
 
1252
 
 
1253
        void sec_changed()
 
1254
        {
 
1255
                secdirty = true;
 
1256
                handleDirtyRings();
 
1257
        }
 
1258
 
 
1259
        void handleDirtyRings()
 
1260
        {
 
1261
                if(!initialized || gpg.isActive())
 
1262
                        return;
 
1263
 
 
1264
                if(secdirty)
 
1265
                        gpg.doSecretKeys();
 
1266
                else if(pubdirty)
 
1267
                        gpg.doPublicKeys();
 
1268
        }
582
1269
};
583
1270
 
584
 
// FIXME: sloooooow
585
 
static PGPKey publicKeyFromId(const QString &id, Provider *p)
586
 
{
587
 
        GpgOp::KeyList pubkeys;
588
 
        {
589
 
                GpgOp gpg(find_bin());
590
 
                gpg.doPublicKeys();
591
 
                while(1)
592
 
                {
593
 
                        GpgOp::Event e = gpg.waitForEvent(-1);
594
 
                        if(e.type == GpgOp::Event::Finished)
595
 
                                break;
596
 
                }
597
 
                if(!gpg.success())
598
 
                        return PGPKey(); // FIXME
599
 
                pubkeys = gpg.keys();
600
 
        }
601
 
 
602
 
        int at = -1;
603
 
        for(int n = 0; n < pubkeys.count(); ++n)
604
 
        {
605
 
                if(pubkeys[n].keyItems.first().id == id)
606
 
                {
607
 
                        at = n;
608
 
                        break;
609
 
                }
610
 
        }
611
 
        if(at == -1)
612
 
                return PGPKey(); // FIXME
613
 
 
614
 
        MyPGPKeyContext *kc = new MyPGPKeyContext(p);
615
 
        kc->_props.keyId = pubkeys[at].keyItems.first().id;
616
 
        kc->_props.userIds = QStringList() << pubkeys[at].userIds.first();
617
 
 
618
 
        PGPKey pub;
619
 
        pub.change(kc);
620
 
        return pub;
621
 
}
622
 
 
623
 
static PGPKey secretKeyFromId(const QString &id, Provider *p)
624
 
{
625
 
        GpgOp::KeyList seckeys;
626
 
        {
627
 
                GpgOp gpg(find_bin());
628
 
                gpg.doSecretKeys();
629
 
                while(1)
630
 
                {
631
 
                        GpgOp::Event e = gpg.waitForEvent(-1);
632
 
                        if(e.type == GpgOp::Event::Finished)
633
 
                                break;
634
 
                }
635
 
                if(!gpg.success())
636
 
                        return PGPKey(); // FIXME
637
 
                seckeys = gpg.keys();
638
 
        }
639
 
 
640
 
        int at = -1;
641
 
        for(int n = 0; n < seckeys.count(); ++n)
642
 
        {
643
 
                const GpgOp::Key &key = seckeys[n];
644
 
                for(int k = 0; k < key.keyItems.count(); ++k)
645
 
                {
646
 
                        const GpgOp::KeyItem &ki = key.keyItems[k];
647
 
                        if(ki.id == id)
648
 
                        {
649
 
                                at = n;
650
 
                                break;
651
 
                        }
652
 
                }
653
 
                if(at != -1)
654
 
                        break;
655
 
        }
656
 
        if(at == -1)
657
 
                return PGPKey(); // FIXME
658
 
 
659
 
        MyPGPKeyContext *kc = new MyPGPKeyContext(p);
660
 
        kc->_props.keyId = seckeys[at].keyItems.first().id;
661
 
        kc->_props.userIds = QStringList() << seckeys[at].userIds.first();
662
 
 
663
 
        PGPKey sec;
664
 
        sec.change(kc);
665
 
        return sec;
 
1271
static void gpg_keyStoreLog(const QString &str)
 
1272
{
 
1273
        MyKeyStoreList *ksl = MyKeyStoreList::instance();
 
1274
        if(ksl)
 
1275
                ksl->ext_keyStoreLog(str);
 
1276
}
 
1277
 
 
1278
static PGPKey publicKeyFromId(const QString &id)
 
1279
{
 
1280
        MyKeyStoreList *ksl = MyKeyStoreList::instance();
 
1281
        if(!ksl)
 
1282
                return PGPKey();
 
1283
 
 
1284
        return ksl->publicKeyFromId(id);
 
1285
}
 
1286
 
 
1287
static PGPKey secretKeyFromId(const QString &id)
 
1288
{
 
1289
        MyKeyStoreList *ksl = MyKeyStoreList::instance();
 
1290
        if(!ksl)
 
1291
                return PGPKey();
 
1292
 
 
1293
        return ksl->secretKeyFromId(id);
666
1294
}
667
1295
 
668
1296
class MyOpenPGPContext : public SMSContext
887
1515
                                }
888
1516
 
889
1517
                                SecureMessageKey key;
890
 
                                PGPKey pub = publicKeyFromId(signerId, provider());
 
1518
                                PGPKey pub = publicKeyFromId(signerId);
891
1519
                                if(pub.isNull())
892
1520
                                {
893
1521
                                        MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
902
1530
                }
903
1531
                else
904
1532
                        op_err = gpg.errorCode();
905
 
 
906
 
                global_gpg = 0;
907
1533
        }
908
1534
 
909
1535
        virtual bool finished() const
926
1552
                                // TODO
927
1553
 
928
1554
                                QString keyId;
929
 
                                PGPKey sec = secretKeyFromId(e.keyId, provider());
 
1555
                                PGPKey sec = secretKeyFromId(e.keyId);
930
1556
                                if(!sec.isNull())
931
1557
                                        keyId = sec.keyId();
932
1558
                                else
933
1559
                                        keyId = e.keyId;
934
 
                                //emit keyStoreList->storeNeedPassphrase(0, 0, keyId);
935
1560
                                QStringList out;
936
1561
                                out += escape_string("qca-gnupg-1");
937
1562
                                out += escape_string(keyId);
1048
1673
                // FIXME: copied from above, clean up later
1049
1674
 
1050
1675
                QString keyId;
1051
 
                PGPKey sec = secretKeyFromId(in_keyId, provider());
 
1676
                PGPKey sec = secretKeyFromId(in_keyId);
1052
1677
                if(!sec.isNull())
1053
1678
                        keyId = sec.keyId();
1054
1679
                else