33 #include <config-kleopatra.h>
40 #include <QStringList>
43 #include <QtAlgorithms>
44 #include <QByteArrayMatcher>
46 #include <boost/range.hpp>
49 # include <ext/algorithm>
54 using namespace boost;
55 using namespace Kleo::Class;
59 const unsigned int ExamineContentHint = 0x8000;
61 static const struct _classification {
63 unsigned int classification;
64 } classifications[] = {
82 static const unsigned int defaultClassification =
NoClass;
84 template <
template <
typename U>
class Op>
86 typedef bool result_type;
89 bool operator()(
const T & lhs,
const T & rhs )
const {
90 return Op<int>()( qstricmp( lhs.extension, rhs.extension ), 0 );
93 bool operator()(
const T & lhs,
const char * rhs )
const {
94 return Op<int>()( qstricmp( lhs.extension, rhs ), 0 );
97 bool operator()(
const char * lhs,
const T & rhs )
const {
98 return Op<int>()( qstricmp( lhs, rhs.extension ), 0 );
100 bool operator()(
const char * lhs,
const char * rhs )
const {
101 return Op<int>()( qstricmp( lhs, rhs ), 0 );
105 static const struct _content_classification {
107 unsigned int classification;
108 } content_classifications[] = {
119 template <
template <
typename U>
class Op>
121 typedef bool result_type;
123 const unsigned int N;
124 explicit ByContent(
unsigned int n ) : N( n ) {}
126 template <
typename T>
127 bool operator()(
const T & lhs,
const T & rhs )
const {
128 return Op<int>()( qstrncmp( lhs.content, rhs.content, N ), 0 );
130 template <
typename T>
131 bool operator()(
const T & lhs,
const char * rhs )
const {
132 return Op<int>()( qstrncmp( lhs.content, rhs, N ), 0 );
134 template <
typename T>
135 bool operator()(
const char * lhs,
const T & rhs )
const {
136 return Op<int>()( qstrncmp( lhs, rhs.content, N ), 0 );
138 bool operator()(
const char * lhs,
const char * rhs )
const {
139 return Op<int>()( qstrncmp( lhs, rhs, N ), 0 );
146 if ( fileNames.empty() )
148 unsigned int result =
classify( fileNames.front() );
149 Q_FOREACH(
const QString & fileName, fileNames )
156 assert( __gnu_cxx::is_sorted( begin( classifications ), end( classifications ), ByExtension<std::less>() ) );
159 const QFileInfo fi( filename );
161 const _classification *
const it = qBinaryFind( begin( classifications ), end( classifications ),
162 fi.suffix().toLatin1().constData(),
163 ByExtension<std::less>() );
164 if ( it != end( classifications ) )
165 if ( !( it->classification & ExamineContentHint ) )
166 return it->classification;
168 const unsigned int bestGuess =
169 it == end( classifications ) ? defaultClassification
170 : it->classification ;
172 QFile file( filename );
173 if ( !file.open( QIODevice::ReadOnly|QIODevice::Text ) )
176 const unsigned int contentClassification =
classifyContent( file.read( 4096 ) );
177 if ( contentClassification != defaultClassification )
178 return contentClassification;
185 assert( __gnu_cxx::is_sorted( begin( content_classifications ), end( content_classifications ), ByContent<std::less>(100) ) );
188 static const char beginString[] =
"-----BEGIN ";
189 static const QByteArrayMatcher beginMatcher( beginString );
190 int pos = beginMatcher.indexIn( data );
192 return defaultClassification;
193 pos +=
sizeof beginString - 1;
195 const bool pgp = qstrncmp( data.data() + pos,
"PGP ", 4 ) == 0;
199 const int epos = data.indexOf(
"-----\n", pos );
201 return defaultClassification;
203 const _content_classification *
const cit
204 = qBinaryFind( begin( content_classifications ), end( content_classifications ),
205 data.data() + pos, ByContent<std::less>( epos - pos ) );
207 if ( cit == end( content_classifications ) )
208 return defaultClassification;
210 return cit->classification | ( pgp ?
OpenPGP :
CMS );
215 if ( classification &
CMS )
216 parts.push_back( QLatin1String(
"CMS") );
217 if ( classification &
OpenPGP )
218 parts.push_back( QLatin1String(
"OpenPGP") );
219 if ( classification &
Binary )
220 parts.push_back( QLatin1String(
"Binary") );
221 if ( classification &
Ascii )
222 parts.push_back( QLatin1String(
"Ascii") );
224 parts.push_back( QLatin1String(
"DetachedSignature") );
226 parts.push_back( QLatin1String(
"OpaqueSignature") );
228 parts.push_back( QLatin1String(
"ClearsignedMessage") );
230 parts.push_back( QLatin1String(
"CipherText") );
232 parts.push_back( QLatin1String(
"Certificate" ));
234 parts.push_back( QLatin1String(
"ExportedPSM") );
236 parts.push_back( QLatin1String(
"CertificateRequest") );
237 return parts.join( QLatin1String(
", ") );
240 static QString
chopped( QString s,
unsigned int n ) {
250 if ( !mayBeDetachedSignature( signatureFileName ) )
252 const QString baseName =
chopped( signatureFileName, 4 );
253 return QFile::exists( baseName ) ? baseName : QString() ;
264 for (
unsigned int i = 0, end = size( classifications ) ; i < end ; ++i )
266 const QString candiate = signedDataFileName + QLatin1Char(
'.') + QLatin1String(classifications[i].
extension);
267 if ( QFile::exists( candiate ) )
268 result.push_back( candiate );
278 const QFileInfo fi( inputFileName );
280 if ( qBinaryFind( begin( classifications ), end( classifications ),
281 fi.suffix().toLatin1().constData(),
282 ByExtension<std::less>() ) == end( classifications ) )
283 return inputFileName + QLatin1String(
".out");
285 return chopped( inputFileName, 4 );
294 if ( classification &
OpenPGP ) {
301 for (
unsigned int i = 0 ; i <
sizeof classifications /
sizeof *classifications ; ++i )
302 if ( ( classifications[i].classification & classification ) == classification )
const char * outputFileExtension(unsigned int classification)
QString findSignedData(const QString &signatureFileName)
QString printableClassification(unsigned int classification)
QString outputFileName(const QString &input)
QStringList findSignatures(const QString &signedDataFileName)
unsigned int classify(const QString &filename)
bool usePGPFileExt() const
Get Use pgp as the default extension for generated OpenPGP files.
static QString chopped(QString s, unsigned int n)
unsigned int classifyContent(const QByteArray &data)
static const char * extension(bool pgp, bool sign, bool encrypt, bool ascii, bool detached)