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