Line data Source code
1 : /*
2 : qgpgmekeylistjob.cpp
3 :
4 : This file is part of qgpgme, the Qt API binding for gpgme
5 : Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
6 : Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
7 : Software engineering by Intevation GmbH
8 :
9 : QGpgME is free software; you can redistribute it and/or
10 : modify it under the terms of the GNU General Public License as
11 : published by the Free Software Foundation; either version 2 of the
12 : License, or (at your option) any later version.
13 :
14 : QGpgME is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program; if not, write to the Free Software
21 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 :
23 : In addition, as a special exception, the copyright holders give
24 : permission to link the code of this program with any edition of
25 : the Qt library by Trolltech AS, Norway (or with modified versions
26 : of Qt that use the same license as Qt), and distribute linked
27 : combinations including the two. You must obey the GNU General
28 : Public License in all respects for all of the code used other than
29 : Qt. If you modify this file, you may extend this exception to
30 : your version of the file, but you are not obligated to do so. If
31 : you do not wish to do so, delete this exception statement from
32 : your version.
33 : */
34 :
35 : #ifdef HAVE_CONFIG_H
36 : #include "config.h"
37 : #endif
38 :
39 : #include "qgpgmekeylistjob.h"
40 :
41 : #include "key.h"
42 : #include "context.h"
43 : #include "keylistresult.h"
44 : #include <gpg-error.h>
45 :
46 : #include <QStringList>
47 :
48 : #include <algorithm>
49 :
50 : #include <cstdlib>
51 : #include <cstring>
52 : #include <cassert>
53 :
54 : using namespace QGpgME;
55 : using namespace GpgME;
56 :
57 15 : QGpgMEKeyListJob::QGpgMEKeyListJob(Context *context)
58 : : mixin_type(context),
59 15 : mResult(), mSecretOnly(false)
60 : {
61 15 : lateInitialization();
62 15 : }
63 :
64 30 : QGpgMEKeyListJob::~QGpgMEKeyListJob() {}
65 :
66 17 : static KeyListResult do_list_keys(Context *ctx, const QStringList &pats, std::vector<Key> &keys, bool secretOnly)
67 : {
68 :
69 34 : const _detail::PatternConverter pc(pats);
70 :
71 34 : if (const Error err = ctx->startKeyListing(pc.patterns(), secretOnly)) {
72 0 : return KeyListResult(0, err);
73 : }
74 :
75 34 : Error err;
76 34 : do {
77 34 : keys.push_back(ctx->nextKey(err));
78 34 : } while (!err);
79 :
80 17 : keys.pop_back();
81 :
82 34 : const KeyListResult result = ctx->endKeyListing();
83 17 : ctx->cancelPendingOperation();
84 17 : return result;
85 : }
86 :
87 17 : static QGpgMEKeyListJob::result_type list_keys(Context *ctx, QStringList pats, bool secretOnly)
88 : {
89 17 : if (pats.size() < 2) {
90 34 : std::vector<Key> keys;
91 34 : const KeyListResult r = do_list_keys(ctx, pats, keys, secretOnly);
92 17 : return std::make_tuple(r, keys, QString(), Error());
93 : }
94 :
95 : // The communication channel between gpgme and gpgsm is limited in
96 : // the number of patterns that can be transported, but they won't
97 : // say to how much, so we need to find out ourselves if we get a
98 : // LINE_TOO_LONG error back...
99 :
100 : // We could of course just feed them single patterns, and that would
101 : // probably be easier, but the performance penalty would currently
102 : // be noticeable.
103 :
104 0 : unsigned int chunkSize = pats.size();
105 : retry:
106 0 : std::vector<Key> keys;
107 0 : keys.reserve(pats.size());
108 0 : KeyListResult result;
109 0 : do {
110 0 : const KeyListResult this_result = do_list_keys(ctx, pats.mid(0, chunkSize), keys, secretOnly);
111 0 : if (this_result.error().code() == GPG_ERR_LINE_TOO_LONG) {
112 : // got LINE_TOO_LONG, try a smaller chunksize:
113 0 : chunkSize /= 2;
114 0 : if (chunkSize < 1)
115 : // chunks smaller than one can't be -> return the error.
116 : {
117 0 : return std::make_tuple(this_result, keys, QString(), Error());
118 : } else {
119 0 : goto retry;
120 : }
121 0 : } else if (this_result.error().code() == GPG_ERR_EOF) {
122 : // early end of keylisting (can happen when ~/.gnupg doesn't
123 : // exist). Fakeing an empty result:
124 0 : return std::make_tuple(KeyListResult(), std::vector<Key>(), QString(), Error());
125 : }
126 : // ok, that seemed to work...
127 0 : result.mergeWith(this_result);
128 0 : if (result.error().code()) {
129 0 : break;
130 : }
131 0 : pats = pats.mid(chunkSize);
132 0 : } while (!pats.empty());
133 0 : return std::make_tuple(result, keys, QString(), Error());
134 : }
135 :
136 2 : Error QGpgMEKeyListJob::start(const QStringList &patterns, bool secretOnly)
137 : {
138 2 : mSecretOnly = secretOnly;
139 2 : run(std::bind(&list_keys, std::placeholders::_1, patterns, secretOnly));
140 2 : return Error();
141 : }
142 :
143 15 : KeyListResult QGpgMEKeyListJob::exec(const QStringList &patterns, bool secretOnly, std::vector<Key> &keys)
144 : {
145 15 : mSecretOnly = secretOnly;
146 30 : const result_type r = list_keys(context(), patterns, secretOnly);
147 15 : resultHook(r);
148 15 : keys = std::get<1>(r);
149 30 : return std::get<0>(r);
150 : }
151 :
152 17 : void QGpgMEKeyListJob::resultHook(const result_type &tuple)
153 : {
154 17 : mResult = std::get<0>(tuple);
155 34 : Q_FOREACH (const Key &key, std::get<1>(tuple)) {
156 17 : Q_EMIT nextKey(key);
157 : }
158 17 : }
159 :
160 4 : void QGpgMEKeyListJob::addMode(KeyListMode mode)
161 : {
162 4 : context()->addKeyListMode(mode);
163 4 : }
164 : #if 0
165 : void QGpgMEKeyListJob::showErrorDialog(QWidget *parent, const QString &caption) const
166 : {
167 : if (!mResult.error() || mResult.error().isCanceled()) {
168 : return;
169 : }
170 : const QString msg = i18n("<qt><p>An error occurred while fetching "
171 : "the keys from the backend:</p>"
172 : "<p><b>%1</b></p></qt>",
173 : QString::fromLocal8Bit(mResult.error().asString()));
174 : KMessageBox::error(parent, msg, caption);
175 : }
176 : #endif
177 : #include "qgpgmekeylistjob.moc"
|