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
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"
51 #include <boost/shared_ptr.hpp>
52 #include <boost/range.hpp>
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
]);
83 class EngineCheck
: public SelfTestImplementation
86 explicit EngineCheck(GpgME::Engine eng
)
87 : SelfTestImplementation(test_name(eng
))
92 void runTest(GpgME::Engine eng
)
94 const Error err
= GpgME::checkEngine(eng
);
95 assert(!err
.code() || err
.code() == GPG_ERR_INV_ENGINE
);
103 m_explaination
= xi18nc("@info",
104 "<para>A problem was detected with the <application>%1</application> backend.</para>",
107 const EngineInfo ei
= engineInfo(eng
);
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>",
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()));
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>",
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
;
174 int actual_version
[3];
175 for (int i
= 0; i
< 3; ++i
) {
177 actual_version
[i
] = rx
.cap(i
+ 1).toUInt(&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
));
192 qCDebug(KLEOPATRA_LOG
) << QStringLiteral("%1.%2.%3").arg(major
).arg(minor
).arg(patch
) << "<=" << actual
;
194 qCDebug(KLEOPATRA_LOG
) << QStringLiteral("%1.%2.%3").arg(major
).arg(minor
).arg(patch
) << ">" << actual
;
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
);
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
));
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
));