10#include <config-libkleo.h>
15#include "classifyconfig.h"
17#include <libkleo/checksumdefinition.h>
19#include <libkleo_debug.h>
21#include <QGpgME/DataProvider>
23#include <QByteArrayMatcher>
27#include <QMimeDatabase>
28#include <QRegularExpression>
31#include <gpgme++/data.h>
36using namespace Kleo::Class;
41const unsigned int ExamineContentHint = 0x8000;
45 {QStringLiteral(
"arl"), Kleo::Class::CMS |
Binary | CertificateRevocationList},
46 {QStringLiteral(
"asc"), Kleo::Class::OpenPGP | Ascii | OpaqueSignature | DetachedSignature | CipherText | AnyCertStoreType | ExamineContentHint},
48 {QStringLiteral(
"crl"), Kleo::Class::CMS |
Binary | CertificateRevocationList},
50 {QStringLiteral(
"der"), Kleo::Class::CMS |
Binary |
Certificate | CertificateRevocationList},
51 {QStringLiteral(
"eml"), Kleo::Class::MimeFile | Ascii},
52 {QStringLiteral(
"gpg"), Kleo::Class::OpenPGP |
Binary | OpaqueSignature | CipherText | AnyCertStoreType | ExamineContentHint},
53 {QStringLiteral(
"mim"), Kleo::Class::MimeFile | Ascii},
54 {QStringLiteral(
"mime"), Kleo::Class::MimeFile | Ascii},
55 {QStringLiteral(
"mbox"), Kleo::Class::MimeFile | Ascii},
56 {QStringLiteral(
"p10"), Kleo::Class::CMS | Ascii | CertificateRequest},
57 {QStringLiteral(
"p12"), Kleo::Class::CMS |
Binary | ExportedPSM},
59 {QStringLiteral(
"p7m"), Kleo::Class::CMS | AnyFormat | CipherText},
60 {QStringLiteral(
"p7s"), Kleo::Class::CMS | AnyFormat | AnySignature},
61 {QStringLiteral(
"pem"), Kleo::Class::CMS | Ascii | AnyType | ExamineContentHint},
63 {QStringLiteral(
"pgp"), Kleo::Class::OpenPGP |
Binary | OpaqueSignature | CipherText | AnyCertStoreType | ExamineContentHint},
64 {QStringLiteral(
"sig"), Kleo::Class::OpenPGP | AnyFormat | DetachedSignature},
69 {GpgME::Data::PGPSigned, Kleo::Class::OpenPGP | OpaqueSignature },
72 {GpgME::Data::PGPOther, Kleo::Class::OpenPGP | CipherText },
73 {GpgME::Data::PGPKey, Kleo::Class::OpenPGP |
Certificate },
74 {GpgME::Data::CMSSigned, Kleo::Class::CMS | AnySignature },
75 {GpgME::Data::CMSEncrypted, Kleo::Class::CMS | CipherText },
77 {GpgME::Data::CMSOther, Kleo::Class::CMS | CipherText },
78 {GpgME::Data::X509Cert, Kleo::Class::CMS |
Certificate },
79 {GpgME::Data::PKCS12, Kleo::Class::CMS |
Binary | ExportedPSM },
80 {GpgME::Data::PGPEncrypted, Kleo::Class::OpenPGP | CipherText },
81 {GpgME::Data::PGPSignature, Kleo::Class::OpenPGP | DetachedSignature},
87 QStringLiteral(
"msg.asc"),
88 QStringLiteral(
"smime.p7m"),
89 QStringLiteral(
"openpgp-encrypted-message.asc"),
93 QStringLiteral(
"GpgOL_MIME_structure.txt"),
94 QStringLiteral(
"GpgOL_MIME_structure.mime"),
96 QStringLiteral(
"OpenPGP encrypted message.asc"),
99static const unsigned int defaultClassification = NoClass;
105 asKeyValueRange(T &data)
112 return m_data.keyValueBegin();
116 return m_data.keyValueEnd();
124unsigned int Kleo::classify(
const QStringList &fileNames)
131 result &= classify(fileName);
136static bool mimeTypeInherits(
const QMimeType &mimeType,
const QString &mimeTypeName)
144static bool isMailFile(
const QFileInfo &fi)
146 static const QRegularExpression attachmentNumbering{QStringLiteral(R
"(\([0-9]+\))")};
149 if (mimeFileNames.contains(fileName)) {
154 Kleo::ClassifyConfig classifyConfig;
156 if (classifyConfig.p7mWithoutExtensionAreEmail() && fileName.endsWith(QStringLiteral(
".p7m")) && fi.
completeSuffix() == fi.
suffix()) {
164 return mimeTypeInherits(mimeType, QStringLiteral(
"message/rfc822")) || mimeTypeInherits(mimeType, QStringLiteral(
"application/mbox"));
167static unsigned int classifyExtension(
const QFileInfo &fi)
169 return classifications.value(fi.
suffix(), defaultClassification);
172unsigned int Kleo::classify(
const QString &filename)
180 if (isMailFile(fi)) {
181 return Kleo::Class::MimeFile | Ascii;
184 QFile file(filename);
186 const unsigned int extClass = classifyExtension(fi);
188 qCDebug(LIBKLEO_LOG) <<
"Failed to open file: " << filename <<
" for classification.";
193 const unsigned int contentClass = classifyContent(file.read(4096));
194 if (contentClass != defaultClassification) {
195 qCDebug(LIBKLEO_LOG) <<
"Classified based on content as:" << contentClass;
201 qCDebug(LIBKLEO_LOG) <<
"No classification based on content.";
205unsigned int Kleo::classifyContent(
const QByteArray &data)
207 QGpgME::QByteArrayDataProvider dp(data);
208 GpgME::Data gpgmeData(&dp);
209 GpgME::Data::Type
type = gpgmeData.type();
211 return gpgmeTypeMap.value(type, defaultClassification);
214QString Kleo::printableClassification(
unsigned int classification)
217 if (classification & Kleo::Class::CMS) {
220 if (classification & Kleo::Class::OpenPGP) {
221 parts.
push_back(QStringLiteral(
"OpenPGP"));
223 if (classification & Kleo::Class::Binary) {
224 parts.
push_back(QStringLiteral(
"Binary"));
226 if (classification & Kleo::Class::Ascii) {
227 parts.
push_back(QStringLiteral(
"Ascii"));
229 if (classification & Kleo::Class::DetachedSignature) {
230 parts.
push_back(QStringLiteral(
"DetachedSignature"));
232 if (classification & Kleo::Class::OpaqueSignature) {
233 parts.
push_back(QStringLiteral(
"OpaqueSignature"));
235 if (classification & Kleo::Class::ClearsignedMessage) {
236 parts.
push_back(QStringLiteral(
"ClearsignedMessage"));
238 if (classification & Kleo::Class::CipherText) {
239 parts.
push_back(QStringLiteral(
"CipherText"));
241 if (classification & Kleo::Class::Certificate) {
242 parts.
push_back(QStringLiteral(
"Certificate"));
244 if (classification & Kleo::Class::ExportedPSM) {
245 parts.
push_back(QStringLiteral(
"ExportedPSM"));
247 if (classification & Kleo::Class::CertificateRequest) {
248 parts.
push_back(QStringLiteral(
"CertificateRequest"));
250 if (classification & Kleo::Class::MimeFile) {
251 parts.
push_back(QStringLiteral(
"MimeFile"));
262 if (!mayBeDetachedSignature(signatureFileName)) {
280 for (
const auto &[extension, classification] : asKeyValueRange(classifications)) {
281 if (classification & DetachedSignature) {
294 static const QRegularExpression attachmentNumbering{QStringLiteral(R
"(\s\([0-9]+\)$)")};
308 if (classifications.find(suffix) == std::cend(classifications)) {
312 return stripOutlookAttachmentNumbering(inputFileName.
chopped(suffix.
size() + 1));
323QString Kleo::outputFileExtension(
unsigned int classification,
bool usePGPFileExt)
325 if (usePGPFileExt && (classification & Class::OpenPGP) && (classification & Class::Binary)) {
326 return QStringLiteral(
"pgp");
329 for (
const auto &[extension, classification_] : asKeyValueRange(classifications)) {
330 if ((classification_ & classification) == classification) {
337bool Kleo::isFingerprint(
const QString &fpr)
340 return fprRegex.match(fpr).hasMatch();
343bool Kleo::isChecksumFile(
const QString &file)
345 static bool initialized;
352 const auto getChecksumDefinitions = ChecksumDefinition::getChecksumDefinitions();
353 for (
const std::shared_ptr<ChecksumDefinition> &cd : getChecksumDefinitions) {
355 const auto patternsList = cd->patterns();
356 for (
const QString &pattern : patternsList) {
370 if (pattern.match(fileName).hasMatch()) {
KCALUTILS_EXPORT QString mimeType()
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
const QList< QKeySequence > & begin()
KEDUVOCDOCUMENT_EXPORT QStringList fileNames(const QString &language=QString())
bool exists() const const
QString completeSuffix() const const
bool exists(const QString &path)
QString fileName() const const
QString suffix() const const
void push_back(parameter_type value)
QMimeType mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const const
QString anchoredPattern(QStringView expression)
QString chopped(qsizetype len) const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
qsizetype size() const const
QString join(QChar separator) const const