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 : #include "qgpgmekeylistjob.h"
35 :
36 : #include "key.h"
37 : #include "context.h"
38 : #include "keylistresult.h"
39 : #include <gpg-error.h>
40 :
41 : #include <QStringList>
42 :
43 : #include <algorithm>
44 :
45 : #include <cstdlib>
46 : #include <cstring>
47 : #include <cassert>
48 :
49 : using namespace QGpgME;
50 : using namespace GpgME;
51 :
52 11 : QGpgMEKeyListJob::QGpgMEKeyListJob(Context *context)
53 : : mixin_type(context),
54 11 : mResult(), mSecretOnly(false)
55 : {
56 11 : lateInitialization();
57 11 : }
58 :
59 22 : QGpgMEKeyListJob::~QGpgMEKeyListJob() {}
60 :
61 11 : static KeyListResult do_list_keys(Context *ctx, const QStringList &pats, std::vector<Key> &keys, bool secretOnly)
62 : {
63 :
64 11 : const _detail::PatternConverter pc(pats);
65 :
66 11 : if (const Error err = ctx->startKeyListing(pc.patterns(), secretOnly)) {
67 0 : return KeyListResult(0, err);
68 11 : }
69 :
70 22 : Error err;
71 22 : do {
72 22 : keys.push_back(ctx->nextKey(err));
73 22 : } while (!err);
74 :
75 11 : keys.pop_back();
76 :
77 22 : const KeyListResult result = ctx->endKeyListing();
78 11 : ctx->cancelPendingOperation();
79 22 : return result;
80 : }
81 :
82 11 : static QGpgMEKeyListJob::result_type list_keys(Context *ctx, QStringList pats, bool secretOnly)
83 : {
84 11 : if (pats.size() < 2) {
85 11 : std::vector<Key> keys;
86 22 : const KeyListResult r = do_list_keys(ctx, pats, keys, secretOnly);
87 22 : return std::make_tuple(r, keys, QString(), Error());
88 : }
89 :
90 : // The communication channel between gpgme and gpgsm is limited in
91 : // the number of patterns that can be transported, but they won't
92 : // say to how much, so we need to find out ourselves if we get a
93 : // LINE_TOO_LONG error back...
94 :
95 : // We could of course just feed them single patterns, and that would
96 : // probably be easier, but the performance penalty would currently
97 : // be noticeable.
98 :
99 0 : unsigned int chunkSize = pats.size();
100 : retry:
101 0 : std::vector<Key> keys;
102 0 : keys.reserve(pats.size());
103 0 : KeyListResult result;
104 0 : do {
105 0 : const KeyListResult this_result = do_list_keys(ctx, pats.mid(0, chunkSize), keys, secretOnly);
106 0 : if (this_result.error().code() == GPG_ERR_LINE_TOO_LONG) {
107 : // got LINE_TOO_LONG, try a smaller chunksize:
108 0 : chunkSize /= 2;
109 0 : if (chunkSize < 1)
110 : // chunks smaller than one can't be -> return the error.
111 : {
112 0 : return std::make_tuple(this_result, keys, QString(), Error());
113 : } else {
114 0 : goto retry;
115 : }
116 0 : } else if (this_result.error().code() == GPG_ERR_EOF) {
117 : // early end of keylisting (can happen when ~/.gnupg doesn't
118 : // exist). Fakeing an empty result:
119 0 : return std::make_tuple(KeyListResult(), std::vector<Key>(), QString(), Error());
120 : }
121 : // ok, that seemed to work...
122 0 : result.mergeWith(this_result);
123 0 : if (result.error().code()) {
124 0 : break;
125 : }
126 0 : pats = pats.mid(chunkSize);
127 0 : } while (!pats.empty());
128 0 : return std::make_tuple(result, keys, QString(), Error());
129 : }
130 :
131 2 : Error QGpgMEKeyListJob::start(const QStringList &patterns, bool secretOnly)
132 : {
133 2 : mSecretOnly = secretOnly;
134 2 : run(std::bind(&list_keys, std::placeholders::_1, patterns, secretOnly));
135 2 : return Error();
136 : }
137 :
138 9 : KeyListResult QGpgMEKeyListJob::exec(const QStringList &patterns, bool secretOnly, std::vector<Key> &keys)
139 : {
140 9 : mSecretOnly = secretOnly;
141 9 : const result_type r = list_keys(context(), patterns, secretOnly);
142 9 : resultHook(r);
143 9 : keys = std::get<1>(r);
144 9 : return std::get<0>(r);
145 : }
146 :
147 11 : void QGpgMEKeyListJob::resultHook(const result_type &tuple)
148 : {
149 11 : mResult = std::get<0>(tuple);
150 22 : Q_FOREACH (const Key &key, std::get<1>(tuple)) {
151 11 : Q_EMIT nextKey(key);
152 11 : }
153 11 : }
154 :
155 2 : void QGpgMEKeyListJob::addMode(KeyListMode mode)
156 : {
157 2 : context()->addKeyListMode(mode);
158 2 : }
159 : #if 0
160 : void QGpgMEKeyListJob::showErrorDialog(QWidget *parent, const QString &caption) const
161 : {
162 : if (!mResult.error() || mResult.error().isCanceled()) {
163 : return;
164 : }
165 : const QString msg = i18n("<qt><p>An error occurred while fetching "
166 : "the keys from the backend:</p>"
167 : "<p><b>%1</b></p></qt>",
168 : QString::fromLocal8Bit(mResult.error().asString()));
169 : KMessageBox::error(parent, msg, caption);
170 : }
171 : #endif
172 : #include "qgpgmekeylistjob.moc"
|