1 /*
2 threadedjobmixin.cpp
3
4 This file is part of qgpgme, the Qt API binding for gpgme
5 Copyright (c) 2008 Klarälvdalens Datakonsult AB
6 Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
7 Software engineering by Intevation GmbH
8
9 QGpgME is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
13
14 QGpgME is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
23 In addition, as a special exception, the copyright holders give
24 permission to link the code of this program with any edition of
25 the Qt library by Trolltech AS, Norway (or with modified versions
26 of Qt that use the same license as Qt), and distribute linked
27 combinations including the two. You must obey the GNU General
28 Public License in all respects for all of the code used other than
29 Qt. If you modify this file, you may extend this exception to
30 your version of the file, but you are not obligated to do so. If
31 you do not wish to do so, delete this exception statement from
32 your version.
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include "threadedjobmixin.h"
40
41 #include "dataprovider.h"
42
43 #include "data.h"
44
45 #include <QString>
46 #include <QStringList>
47 #include <QByteArray>
48
49
50 #include <algorithm>
51 #include <iterator>
52
53 using namespace QGpgME;
54 using namespace GpgME;
55
56 #ifdef Q_OS_WIN
57 #include <windows.h>
58
fromEncoding(unsigned int src_encoding,const char * data)59 static QString fromEncoding (unsigned int src_encoding, const char *data)
60 {
61 int n = MultiByteToWideChar(src_encoding, 0, data, -1, NULL, 0);
62 if (n < 0) {
63 return QString();
64 }
65
66 wchar_t *result = (wchar_t *) malloc ((n+1) * sizeof *result);
67
68 n = MultiByteToWideChar(src_encoding, 0, data, -1, result, n);
69 if (n < 0) {
70 free(result);
71 return QString();
72 }
73 const auto ret = QString::fromWCharArray(result, n);
74 free(result);
75 return ret;
76 }
77 #endif
78
stringFromGpgOutput(const QByteArray & ba)79 static QString stringFromGpgOutput(const QByteArray &ba)
80 {
81 #ifdef Q_OS_WIN
82 /* Qt on Windows uses GetACP while GnuPG prefers
83 * GetConsoleOutputCP.
84 *
85 * As we are not a console application GetConsoleOutputCP
86 * usually returns 0.
87 * From experience the closest thing that let's us guess
88 * what GetConsoleOutputCP returns for a console application
89 * it appears to be the OEMCP.
90 */
91 unsigned int cpno = GetConsoleOutputCP ();
92 if (!cpno) {
93 cpno = GetOEMCP();
94 }
95 if (!cpno) {
96 cpno = GetACP();
97 }
98 if (!cpno) {
99 return QString();
100 }
101
102 return fromEncoding(cpno, ba.constData());
103 #else
104 return QString::fromLocal8Bit(ba);
105 #endif
106 }
107
markupDiagnostics(const QString & data)108 static QString markupDiagnostics(const QString &data)
109 {
110 // First ensure that we don't have html in the diag.
111 QString ret = QStringLiteral("<pre>%1</pre>").arg(data.toHtmlEscaped());
112
113 return ret;
114 }
115
116 static const unsigned int CMSAuditLogFlags = Context::AuditLogWithHelp | Context::HtmlAuditLog;
117 static const unsigned int OpenPGPAuditLogFlags = Context::DiagnosticAuditLog;
118
audit_log_as_html(Context * ctx,GpgME::Error & err)119 QString _detail::audit_log_as_html(Context *ctx, GpgME::Error &err)
120 {
121 assert(ctx);
122 QGpgME::QByteArrayDataProvider dp;
123 Data data(&dp);
124 assert(!data.isNull());
125
126 if (ctx->protocol() == OpenPGP) {
127 if ((err = ctx->getAuditLog(data, OpenPGPAuditLogFlags))) {
128 return QString::fromLocal8Bit(err.asString());
129 }
130 const QByteArray ba = dp.data();
131 return markupDiagnostics(stringFromGpgOutput(ba));
132 }
133
134 if (ctx->protocol() == CMS) {
135 if ((err = ctx->lastError())) {
136 if ((err = ctx->getAuditLog(data, Context::DiagnosticAuditLog))) {
137 return QString::fromLocal8Bit(err.asString());
138 }
139 const QByteArray ba = dp.data();
140 return markupDiagnostics(stringFromGpgOutput(ba));
141 } else if ((err = ctx->getAuditLog(data, CMSAuditLogFlags))) {
142 return QString::fromLocal8Bit(err.asString());
143 }
144 const QByteArray ba = dp.data();
145 return QString::fromUtf8(ba.data(), ba.size());
146 }
147
148 return QStringLiteral("Unsupported protocol for Audit Log");
149 }
150
from_sl(const QStringList & sl)151 static QList<QByteArray> from_sl(const QStringList &sl)
152 {
153 QList<QByteArray> result;
154 Q_FOREACH (const QString &str, sl) {
155 result.append(str.toUtf8());
156 }
157
158 #if 0
159 std::transform(sl.begin(), sl.end(), std::back_inserter(result),
160 mem_fn(static_cast<QByteArray()const>(&QString::toUtf8)));
161 #endif
162 return result;
163 }
164
single(const QByteArray & ba)165 static QList<QByteArray> single(const QByteArray &ba)
166 {
167 QList<QByteArray> result;
168 result.push_back(ba);
169 return result;
170 }
171
PatternConverter(const QByteArray & ba)172 _detail::PatternConverter::PatternConverter(const QByteArray &ba)
173 : m_list(single(ba)), m_patterns(nullptr) {}
PatternConverter(const QString & s)174 _detail::PatternConverter::PatternConverter(const QString &s)
175 : m_list(single(s.toUtf8())), m_patterns(nullptr) {}
PatternConverter(const QList<QByteArray> & lba)176 _detail::PatternConverter::PatternConverter(const QList<QByteArray> &lba)
177 : m_list(lba), m_patterns(nullptr) {}
PatternConverter(const QStringList & sl)178 _detail::PatternConverter::PatternConverter(const QStringList &sl)
179 : m_list(from_sl(sl)), m_patterns(nullptr) {}
180
patterns() const181 const char **_detail::PatternConverter::patterns() const
182 {
183 if (!m_patterns) {
184 m_patterns = new const char *[ m_list.size() + 1 ];
185 const char **end = std::transform(m_list.begin(), m_list.end(), m_patterns,
186 std::mem_fn(&QByteArray::constData));
187 *end = nullptr;
188 }
189 return m_patterns;
190 }
191
~PatternConverter()192 _detail::PatternConverter::~PatternConverter()
193 {
194 delete [] m_patterns;
195 }
196