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