Fix layout
[kdepim.git] / kleopatra / selftest / enginecheck.cpp
blob9a6d8b72b435ba142defecc20bebb604b4cc8bb7
1 /* -*- mode: c++; c-basic-offset:4 -*-
2 selftest/enginecheck.cpp
4 This file is part of Kleopatra, the KDE keymanager
5 Copyright (c) 2008 Klarälvdalens Datakonsult AB
7 Kleopatra is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 Kleopatra is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 In addition, as a special exception, the copyright holders give
22 permission to link the code of this program with any edition of
23 the Qt library by Trolltech AS, Norway (or with modified versions
24 of Qt that use the same license as Qt), and distribute linked
25 combinations including the two. You must obey the GNU General
26 Public License in all respects for all of the code used other than
27 Qt. If you modify this file, you may extend this exception to
28 your version of the file, but you are not obligated to do so. If
29 you do not wish to do so, delete this exception statement from
30 your version.
33 #include <config-kleopatra.h>
35 #include "enginecheck.h"
37 #include "implementation_p.h"
39 #include <gpgme++/global.h>
40 #include <gpgme++/engineinfo.h>
41 #include <gpgme++/error.h>
43 #include <gpg-error.h>
45 #include <KLocalizedString>
46 #include "kleopatra_debug.h"
48 #include <QFile>
49 #include <QRegExp>
51 #include <boost/shared_ptr.hpp>
52 #include <boost/range.hpp>
54 #include <algorithm>
55 #include <cassert>
57 using namespace Kleo;
58 using namespace Kleo::_detail;
59 using namespace GpgME;
60 using namespace boost;
62 static QString engine_name(GpgME::Engine eng)
64 static const char *engines[] = {
65 "gpg", "gpgsm", "gpgconf"
67 return QString::fromLatin1(engines[eng]);
70 static QString test_name(GpgME::Engine eng)
72 static const char *names[] = {
73 I18N_NOOP2("@title", "GPG (OpenPGP Backend) installation"),
74 I18N_NOOP2("@title", "GpgSM (S/MIME Backend) installation"),
75 I18N_NOOP2("@title", "GpgConf (Configuration) installation"),
77 return i18nc("@title", names[eng]);
80 namespace
83 class EngineCheck : public SelfTestImplementation
85 public:
86 explicit EngineCheck(GpgME::Engine eng)
87 : SelfTestImplementation(test_name(eng))
89 runTest(eng);
92 void runTest(GpgME::Engine eng)
94 const Error err = GpgME::checkEngine(eng);
95 assert(!err.code() || err.code() == GPG_ERR_INV_ENGINE);
97 m_passed = !err;
99 if (m_passed) {
100 return;
103 m_explaination = xi18nc("@info",
104 "<para>A problem was detected with the <application>%1</application> backend.</para>",
105 engine_name(eng));
107 const EngineInfo ei = engineInfo(eng);
108 if (ei.isNull()) {
109 m_error = i18n("not supported");
110 m_explaination += xi18nc("@info",
111 "<para>It seems that the <icode>gpgme</icode> library was compiled without "
112 "support for this backend.</para>");
113 m_proposedFix += xi18nc("@info",
114 "<para>Replace the <icode>gpgme</icode> library with a version compiled "
115 "with <application>%1</application> support.</para>",
116 engine_name(eng));
117 } else if (ei.fileName() && !ei.version()) {
118 m_error = i18n("not properly installed");
119 m_explaination += xi18nc("@info",
120 "<para>Backend <command>%1</command> is not installed properly.</para>", QFile::decodeName(ei.fileName()));
121 m_proposedFix += xi18nc("@info",
122 "<para>Please check the output of <command>%1 --version</command> manually.</para>",
123 QFile::decodeName(ei.fileName()));
124 } else if (ei.fileName() && ei.version() && ei.requiredVersion()) {
125 m_error = i18n("too old");
126 m_explaination += xi18nc("@info",
127 "<para>Backend <command>%1</command> is installed in version %2, "
128 "but at least version %3 is required.</para>",
129 QFile::decodeName(ei.fileName()),
130 QString::fromUtf8(ei.version()),
131 QString::fromUtf8(ei.requiredVersion()));
132 m_proposedFix += xi18nc("@info",
133 "<para>Install <application>%1</application> version %2 or higher.</para>",
134 engine_name(eng), QString::fromUtf8(ei.requiredVersion()));
135 } else {
136 m_error = m_explaination = i18n("unknown problem");
137 m_proposedFix += xi18nc("@info",
138 "<para>Make sure <application>%1</application> is installed and "
139 "in <envar>PATH</envar>.</para>",
140 engine_name(eng));
147 shared_ptr<SelfTest> Kleo::makeGpgEngineCheckSelfTest()
149 return shared_ptr<SelfTest>(new EngineCheck(GpgME::GpgEngine));
152 shared_ptr<SelfTest> Kleo::makeGpgSmEngineCheckSelfTest()
154 return shared_ptr<SelfTest>(new EngineCheck(GpgME::GpgSMEngine));
157 shared_ptr<SelfTest> Kleo::makeGpgConfEngineCheckSelfTest()
159 return shared_ptr<SelfTest>(new EngineCheck(GpgME::GpgConfEngine));
163 // SelfTestImplementation (parts)
166 static bool is_version(const char *actual, int major, int minor, int patch)
168 QRegExp rx(QStringLiteral("(\\d+)\\.(\\d+)\\.(\\d+)(?:-svn\\d+)?.*"));
169 if (!rx.exactMatch(QString::fromUtf8(actual))) {
170 qCDebug(KLEOPATRA_LOG) << "Can't parse version " << actual;
171 return false;
173 bool ok;
174 int actual_version[3];
175 for (int i = 0; i < 3; ++i) {
176 ok = false;
177 actual_version[i] = rx.cap(i + 1).toUInt(&ok);
178 assert(ok);
181 qCDebug(KLEOPATRA_LOG) << "Parsed" << actual << "as: "
182 << actual_version[0] << '.'
183 << actual_version[1] << '.'
184 << actual_version[2] << '.';
186 const int required_version[] = { major, minor, patch };
188 // return ! ( actual_version < required_version )
189 ok = !std::lexicographical_compare(begin(actual_version), end(actual_version),
190 begin(required_version), end(required_version));
191 if (ok) {
192 qCDebug(KLEOPATRA_LOG) << QStringLiteral("%1.%2.%3").arg(major).arg(minor).arg(patch) << "<=" << actual;
193 } else {
194 qCDebug(KLEOPATRA_LOG) << QStringLiteral("%1.%2.%3").arg(major).arg(minor).arg(patch) << ">" << actual;
196 return ok;
199 bool SelfTestImplementation::ensureEngineVersion(GpgME::Engine engine, int major, int minor, int patch)
201 const Error err = GpgME::checkEngine(engine);
202 assert(!err || err.code() == GPG_ERR_INV_ENGINE);
204 const EngineInfo ei = GpgME::engineInfo(engine);
206 m_skipped = err || !is_version(ei.version(), major, minor, patch);
208 if (!m_skipped) {
209 return true;
212 if (!err && ei.version()) {
213 // properly installed, but too old
214 m_explaination = xi18nc("@info",
215 "<para><application>%1</application> v%2.%3.%4 is required for this test, but only %5 is installed.</para>",
216 engine_name(engine), major, minor, patch, QString::fromUtf8(ei.version()));
217 m_proposedFix += xi18nc("@info",
218 "<para>Install <application>%1</application> version %2 or higher.</para>",
219 engine_name(engine), QStringLiteral("%1.%2.%3").arg(major).arg(minor).arg(patch));
220 } else {
221 // not properly installed
222 m_explaination = xi18nc("@info",
223 "<para><application>%1</application> is required for this test, but does not seem available.</para>"
224 "<para>See tests further up for more information.</para>",
225 engine_name(engine));
226 m_proposedFix = xi18nc("@info %1: test name",
227 "<para>See \"%1\" above.</para>", test_name(engine));
230 return false;