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