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;
42const unsigned int ExamineContentHint = 0x8000;
46 {QStringLiteral(
"arl"), Kleo::Class::CMS |
Binary | CertificateRevocationList},
47 {QStringLiteral(
"asc"), Kleo::Class::OpenPGP | Ascii | OpaqueSignature | DetachedSignature | CipherText | AnyCertStoreType | ExamineContentHint},
49 {QStringLiteral(
"crl"), Kleo::Class::CMS |
Binary | CertificateRevocationList},
51 {QStringLiteral(
"der"), Kleo::Class::CMS |
Binary |
Certificate | CertificateRevocationList},
52 {QStringLiteral(
"eml"), Kleo::Class::MimeFile | Ascii},
53 {QStringLiteral(
"gpg"), Kleo::Class::OpenPGP |
Binary | OpaqueSignature | CipherText | AnyCertStoreType | ExamineContentHint},
54 {QStringLiteral(
"mim"), Kleo::Class::MimeFile | Ascii},
55 {QStringLiteral(
"mime"), Kleo::Class::MimeFile | Ascii},
56 {QStringLiteral(
"mbox"), Kleo::Class::MimeFile | Ascii},
57 {QStringLiteral(
"p10"), Kleo::Class::CMS | Ascii | CertificateRequest},
58 {QStringLiteral(
"p12"), Kleo::Class::CMS |
Binary | ExportedPSM},
60 {QStringLiteral(
"p7m"), Kleo::Class::CMS | AnyFormat | CipherText},
61 {QStringLiteral(
"p7s"), Kleo::Class::CMS | AnyFormat | AnySignature},
62 {QStringLiteral(
"pem"), Kleo::Class::CMS | Ascii | AnyType | ExamineContentHint},
64 {QStringLiteral(
"pgp"), Kleo::Class::OpenPGP |
Binary | OpaqueSignature | CipherText | AnyCertStoreType | ExamineContentHint},
65 {QStringLiteral(
"sig"), Kleo::Class::OpenPGP | AnyFormat | DetachedSignature},
70 {GpgME::Data::PGPSigned, Kleo::Class::OpenPGP | OpaqueSignature },
73 {GpgME::Data::PGPOther, Kleo::Class::OpenPGP | CipherText },
74 {GpgME::Data::PGPKey, Kleo::Class::OpenPGP |
Certificate },
75 {GpgME::Data::CMSSigned, Kleo::Class::CMS | AnySignature },
76 {GpgME::Data::CMSEncrypted, Kleo::Class::CMS | CipherText },
78 {GpgME::Data::CMSOther, Kleo::Class::CMS | CipherText },
79 {GpgME::Data::X509Cert, Kleo::Class::CMS |
Certificate },
80 {GpgME::Data::PKCS12, Kleo::Class::CMS |
Binary | ExportedPSM },
81 {GpgME::Data::PGPEncrypted, Kleo::Class::OpenPGP | CipherText },
82 {GpgME::Data::PGPSignature, Kleo::Class::OpenPGP | DetachedSignature},
88 QStringLiteral(
"msg.asc"),
89 QStringLiteral(
"smime.p7m"),
90 QStringLiteral(
"openpgp-encrypted-message.asc"),
94 QStringLiteral(
"GpgOL_MIME_structure.txt"),
95 QStringLiteral(
"GpgOL_MIME_structure.mime"),
97 QStringLiteral(
"OpenPGP encrypted message.asc"),
100static const unsigned int defaultClassification = NoClass;
106 asKeyValueRange(T &data)
113 return m_data.keyValueBegin();
117 return m_data.keyValueEnd();
125unsigned int Kleo::classify(
const QStringList &fileNames)
131 for (
const QString &fileName : fileNames) {
132 result &= classify(fileName);
137static bool mimeTypeInherits(
const QMimeType &mimeType,
const QString &mimeTypeName)
145static bool isMailFile(
const QFileInfo &fi)
147 static const QRegularExpression attachmentNumbering{QStringLiteral(R
"(\([0-9]+\))")};
150 if (mimeFileNames.contains(fileName)) {
155 Kleo::ClassifyConfig classifyConfig;
157 if (classifyConfig.p7mWithoutExtensionAreEmail() && fileName.endsWith(QStringLiteral(
".p7m")) && fi.
completeSuffix() == fi.
suffix()) {
165 return mimeTypeInherits(mimeType, QStringLiteral(
"message/rfc822")) || mimeTypeInherits(mimeType, QStringLiteral(
"application/mbox"));
168static unsigned int classifyExtension(
const QFileInfo &fi)
170 return classifications.value(fi.
suffix(), defaultClassification);
173unsigned int Kleo::classify(
const QString &filename)
181 if (isMailFile(fi)) {
182 return Kleo::Class::MimeFile | Ascii;
185 QFile file(filename);
187 const unsigned int extClass = classifyExtension(fi);
189 qCDebug(LIBKLEO_LOG) <<
"Failed to open file: " << filename <<
" for classification.";
194 const unsigned int contentClass = classifyContent(file.read(4096));
195 if (contentClass != defaultClassification) {
196 qCDebug(LIBKLEO_LOG) <<
"Classified based on content as:" << contentClass;
202 qCDebug(LIBKLEO_LOG) <<
"No classification based on content.";
206unsigned int Kleo::classifyContent(
const QByteArray &data)
208 QGpgME::QByteArrayDataProvider dp(data);
209 GpgME::Data gpgmeData(&dp);
210 GpgME::Data::Type
type = gpgmeData.type();
212 return gpgmeTypeMap.value(type, defaultClassification);
215QString Kleo::printableClassification(
unsigned int classification)
218 if (classification & Kleo::Class::CMS) {
221 if (classification & Kleo::Class::OpenPGP) {
222 parts.
push_back(QStringLiteral(
"OpenPGP"));
224 if (classification & Kleo::Class::Binary) {
225 parts.
push_back(QStringLiteral(
"Binary"));
227 if (classification & Kleo::Class::Ascii) {
228 parts.
push_back(QStringLiteral(
"Ascii"));
230 if (classification & Kleo::Class::DetachedSignature) {
231 parts.
push_back(QStringLiteral(
"DetachedSignature"));
233 if (classification & Kleo::Class::OpaqueSignature) {
234 parts.
push_back(QStringLiteral(
"OpaqueSignature"));
236 if (classification & Kleo::Class::ClearsignedMessage) {
237 parts.
push_back(QStringLiteral(
"ClearsignedMessage"));
239 if (classification & Kleo::Class::CipherText) {
240 parts.
push_back(QStringLiteral(
"CipherText"));
242 if (classification & Kleo::Class::Certificate) {
243 parts.
push_back(QStringLiteral(
"Certificate"));
245 if (classification & Kleo::Class::ExportedPSM) {
246 parts.
push_back(QStringLiteral(
"ExportedPSM"));
248 if (classification & Kleo::Class::CertificateRequest) {
249 parts.
push_back(QStringLiteral(
"CertificateRequest"));
251 if (classification & Kleo::Class::MimeFile) {
252 parts.
push_back(QStringLiteral(
"MimeFile"));
263 if (!mayBeDetachedSignature(signatureFileName)) {
281 for (
const auto &[extension, classification] : asKeyValueRange(classifications)) {
282 if (classification & DetachedSignature) {
295 static const QRegularExpression attachmentNumbering{QStringLiteral(R
"(\s\([0-9]+\)$)")};
309 if (classifications.find(suffix) == std::cend(classifications)) {
313 return stripOutlookAttachmentNumbering(inputFileName.
chopped(suffix.
size() + 1));
324QString Kleo::outputFileExtension(
unsigned int classification,
bool usePGPFileExt)
326 if (usePGPFileExt && (classification & Class::OpenPGP) && (classification & Class::Binary)) {
327 return QStringLiteral(
"pgp");
330 for (
const auto &[extension, classification_] : asKeyValueRange(classifications)) {
331 if ((classification_ & classification) == classification) {
338bool Kleo::isFingerprint(
const QString &fpr)
344bool Kleo::isChecksumFile(
const QString &file)
346 static bool initialized;
353 const auto getChecksumDefinitions = ChecksumDefinition::getChecksumDefinitions();
354 for (
const std::shared_ptr<ChecksumDefinition> &cd : getChecksumDefinitions) {
356 const auto patternsList = cd->patterns();
357 for (
const QString &pattern : patternsList) {
371 if (pattern.match(fileName).hasMatch()) {
Type type(const QSqlDatabase &db)
KCALUTILS_EXPORT QString mimeType()
const QList< QKeySequence > & begin()
const QList< QKeySequence > & end()
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
QRegularExpressionMatch match(QStringView subjectView, qsizetype offset, MatchType matchType, MatchOptions matchOptions) const const
QString anchoredPattern(QStringView expression)
bool hasMatch() const const
QString chopped(qsizetype len) const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
qsizetype size() const const
QString join(QChar separator) const const