33 #include <config-kleopatra.h>
41 #include <kmime/kmime_header_parsing.h>
43 #include <gpgme++/key.h>
44 #include <gpgme++/importresult.h>
50 #include <QStringList>
52 #include <QCoreApplication>
53 #include <QTextDocument>
55 using namespace GpgME;
57 using namespace KMime::Types;
58 using namespace KMime::HeaderParsing;
67 const QString
name = QString::fromUtf8( name_ );
70 const QString comment = QString::fromUtf8( comment_ );
71 if ( comment.isEmpty() )
73 return QString::fromLatin1(
"%1 (%2)" ).arg( name, comment );
77 const DN subject(
id );
78 const QString cn = subject[QLatin1String(
"CN")].trimmed();
80 return subject.prettyDN();
88 return prettyNameAndEMail( proto, QString::fromUtf8(
id ), QString::fromUtf8( name_ ),
prettyEMail( email_,
id ), QString::fromUtf8( comment_ ) );
94 if ( name.isEmpty() ) {
95 if ( email.isEmpty() )
97 else if ( comment.isEmpty() )
98 return QString::fromLatin1(
"<%1>" ).arg( email );
100 return QString::fromLatin1(
"(%2) <%1>" ).arg( email, comment );
102 if ( email.isEmpty() ) {
103 if ( comment.isEmpty() )
106 return QString::fromLatin1(
"%1 (%2)" ).arg( name, comment );
108 if ( comment.isEmpty() )
109 return QString::fromLatin1(
"%1 <%2>" ).arg( name, email );
111 return QString::fromLatin1(
"%1 (%3) <%2>" ).arg( name, email, comment );
114 if ( proto ==
CMS ) {
115 const DN subject(
id );
116 const QString cn = subject[QLatin1String(
"CN")].trimmed();
118 return subject.prettyDN();
125 if ( uid.parent().protocol() ==
OpenPGP )
127 const QByteArray
id = QByteArray( uid.id() ).trimmed();
128 if (
id.startsWith(
'<' ) )
130 if (
id.startsWith(
'(' ) )
132 return QString::fromUtf8( uid.id() );
134 return DN( uid.id() ).prettyDN();
140 return QLatin1String(
"0x") + QString::fromLatin1(
id ).toUpper();
144 return prettyNameAndEMail( uid.parent().protocol(), uid.id(), uid.name(), uid.email(), uid.comment() );
156 return prettyName( uid.parent().protocol(), uid.id(), uid.name(), uid.comment() );
160 return prettyName(
OpenPGP, sig.signerUserID(), sig.signerName(), sig.signerComment() );
168 for (
unsigned int i = 0, end = key.numUserIDs() ; i < end ; ++i ) {
170 if ( !email.isEmpty() )
181 return prettyEMail( sig.signerEmail(), sig.signerUserID() );
186 if ( email_ && parseMailbox( email_, email_ + strlen( email_ ), mailBox ) )
187 return mailBox.addrSpec().asPrettyString();
189 return DN(
id )[QLatin1String(
"EMAIL")].trimmed();
198 static QString protect_whitespace( QString s ) {
199 static const QLatin1Char SP(
' ' ), NBSP(
'\xA0' );
200 return s.replace( SP, NBSP );
203 template <
typename T_arg>
204 QString format_row(
const QString & field,
const T_arg & arg ) {
205 return i18n(
"<tr><th>%1:</th><td>%2</td></tr>", protect_whitespace( field ), arg );
207 QString format_row(
const QString & field,
const QString & arg ) {
208 return i18n(
"<tr><th>%1:</th><td>%2</td></tr>", protect_whitespace( field ), Qt::escape( arg ) );
210 QString format_row(
const QString & field,
const char * arg ) {
211 return format_row( field, QString::fromUtf8( arg ) );
214 QString format_keytype(
const Key & key ) {
215 const Subkey subkey = key.subkey( 0 );
216 if ( key.hasSecret() )
217 return i18n(
"%1-bit %2 (secret key available)", subkey.length(), QLatin1String(subkey.publicKeyAlgorithmAsString()) );
219 return i18n(
"%1-bit %2", subkey.length(), QLatin1String(subkey.publicKeyAlgorithmAsString()) );
222 QString format_keyusage(
const Key & key ) {
223 QStringList capabilities;
224 if ( key.canReallySign() ) {
225 if ( key.isQualified() )
226 capabilities.push_back( i18n(
"Signing EMails and Files (Qualified)" ) );
228 capabilities.push_back( i18n(
"Signing EMails and Files" ) );
230 if ( key.canEncrypt() )
231 capabilities.push_back( i18n(
"Encrypting EMails and Files" ) );
232 if ( key.canCertify() )
233 capabilities.push_back( i18n(
"Certifying other Certificates" ) );
234 if ( key.canAuthenticate() )
235 capabilities.push_back( i18n(
"Authenticate against Servers" ) );
236 return capabilities.join( QLatin1String(
", ") );
239 static QString time_t2string( time_t t ) {
242 return KGlobal::locale()->formatDateTime( dt, KLocale::ShortDate );
245 static QString make_red(
const QString & txt ) {
246 return QLatin1String(
"<font color=\"red\">" ) + Qt::escape( txt ) + QLatin1String(
"</font>" );
252 if ( flags == 0 || ( key.protocol() !=
CMS && key.protocol() !=
OpenPGP ) )
255 const Subkey subkey = key.subkey( 0 );
259 if ( key.protocol() ==
OpenPGP || ( key.keyListMode() & Validate ) )
260 if ( key.isRevoked() )
261 result += make_red( i18n(
"This certificate has been revoked." ) );
262 else if ( key.isExpired() )
263 result += make_red( i18n(
"This certificate has expired." ) );
264 else if ( key.isDisabled() )
265 result += i18n(
"This certificate has been disabled locally." );
267 result += i18n(
"This certificate is currently valid." );
269 result += i18n(
"The validity of this certificate cannot be checked at the moment." );
270 if ( flags == Validity )
273 result += QLatin1String(
"<table border=\"0\">" );
274 if ( key.protocol() ==
CMS ) {
276 result += format_row( i18n(
"Serial number"), key.issuerSerial() );
278 result += format_row( i18n(
"Issuer"), key.issuerName() );
281 const std::vector<UserID> uids = key.userIDs();
283 result += format_row( key.protocol() ==
CMS
286 if ( uids.size() > 1 )
287 for ( std::vector<UserID>::const_iterator it = uids.begin() + 1, end = uids.end() ; it != end ; ++it )
288 if ( !it->isRevoked() && !it->isInvalid() )
289 result += format_row( i18n(
"a.k.a."),
prettyUserID( *it ) );
292 result += format_row( i18n(
"Validity"),
293 subkey.neverExpires()
294 ? i18n(
"from %1 until forever", time_t2string( subkey.creationTime() ) )
295 : i18n(
"from %1 through %2", time_t2string( subkey.creationTime() ), time_t2string( subkey.expirationTime() ) ) );
297 result += format_row( i18n(
"Certificate type"), format_keytype( key ) );
299 result += format_row( i18n(
"Certificate usage"), format_keyusage( key ) );
301 result += format_row( i18n(
"Key-ID"), QString::fromLatin1( key.shortKeyID() ) ) ;
303 result += format_row( i18n(
"Fingerprint"), key.primaryFingerprint() );
305 if ( key.protocol() ==
OpenPGP )
307 else if ( key.isRoot() )
308 result += format_row( i18n(
"Trusted issuer?"),
309 key.userID(0).validity() == UserID::Ultimate ? i18n(
"Yes") :
312 if (
const char * card = subkey.cardSerialNumber() )
313 result += format_row( i18n(
"Stored"), i18nc(
"stored...",
"on SmartCard with serial no. %1", QString::fromUtf8( card ) ) );
315 result += format_row( i18n(
"Stored"), i18nc(
"stored...",
"on this computer") );
316 result += QLatin1String(
"</table>" );
326 static QDate time_t2date( time_t t ) {
333 static QString date2string(
const QDate & date ) {
334 return KGlobal::locale()->formatDate( date, KLocale::ShortDate );
337 template <
typename T>
338 QString expiration_date_string(
const T & tee ) {
339 return tee.neverExpires() ? QString() : date2string( time_t2date( tee.expirationTime() ) ) ;
341 template <
typename T>
342 QDate creation_date(
const T & tee ) {
343 return time_t2date( tee.creationTime() );
345 template <
typename T>
346 QDate expiration_date(
const T & tee ) {
347 return time_t2date( tee.expirationTime() );
352 return expiration_date_string( key.subkey( 0 ) );
356 return expiration_date_string( subkey );
360 return expiration_date_string( sig );
364 return expiration_date( key.subkey( 0 ) );
368 return expiration_date( subkey );
372 return expiration_date( sig );
377 return date2string( creation_date( key.subkey( 0 ) ) );
381 return date2string( creation_date( subkey ) );
385 return date2string( creation_date( sig ) );
389 return creation_date( key.subkey( 0 ) );
393 return creation_date( subkey );
397 return creation_date( sig );
406 return i18nc(
"X.509/CMS encryption standard",
"X.509");
408 return i18n(
"OpenPGP");
409 return i18nc(
"Unknown encryption protocol",
"Unknown");
417 return QString::fromUtf8( subkey.publicKeyAlgorithmAsString() );
430 case Key::Unknown:
return i18nc(
"unknown trust level",
"unknown");
431 case Key::Never:
return i18n(
"untrusted");
432 case Key::Marginal:
return i18nc(
"marginal trust",
"marginal");
433 case Key::Full:
return i18nc(
"full trust",
"full");
434 case Key::Ultimate:
return i18nc(
"ultimate trust",
"ultimate");
435 case Key::Undefined:
return i18nc(
"undefined trust",
"undefined");
437 assert( !
"unexpected owner trust value" );
444 if ( subkey.isRevoked() )
445 return i18n(
"revoked");
446 if ( subkey.isExpired() )
447 return i18n(
"expired");
448 if ( subkey.isDisabled() )
449 return i18n(
"disabled");
450 if ( subkey.isInvalid() )
451 return i18n(
"invalid");
452 return i18nc(
"as in good/valid signature",
"good");
456 if ( uid.isRevoked() )
457 return i18n(
"revoked");
458 if ( uid.isInvalid() )
459 return i18n(
"invalid");
460 switch ( uid.validity() ) {
462 case UserID::Undefined:
return i18nc(
"undefined trust",
"undefined");
463 case UserID::Never:
return i18n(
"untrusted");
464 case UserID::Marginal:
return i18nc(
"marginal trust",
"marginal");
465 case UserID::Full:
return i18nc(
"full trust",
"full");
466 case UserID::Ultimate:
return i18nc(
"ultimate trust",
"ultimate");
472 switch ( sig.status() ) {
473 case UserID::Signature::NoError:
474 if ( !sig.isInvalid() ) {
475 if ( sig.certClass() > 0 )
476 return i18n(
"class %1", sig.certClass() );
478 return i18nc(
"good/valid signature",
"good");
481 case UserID::Signature::GeneralError:
482 return i18n(
"invalid");
483 case UserID::Signature::SigExpired:
return i18n(
"expired");
484 case UserID::Signature::KeyExpired:
return i18n(
"certificate expired");
485 case UserID::Signature::BadSignature:
return i18nc(
"fake/invalid signature",
"bad");
486 case UserID::Signature::NoPublicKey:
return QString();
494 return QString::fromLatin1(
"<a href=\"key:%1\">%2</a>" ).arg( QLatin1String(key.primaryFingerprint()),
Formatting::prettyName( key ) );
500 if ( !mail.isEmpty() )
501 mail = QLatin1Char(
'<') + mail + QLatin1Char(
'>');
502 return i18nc(
"name, email, key id",
"%1 %2 (%3)", name, mail, QLatin1String(key.shortKeyID()) ).simplified();
507 static QString keyToString(
const Key & key ) {
514 if ( name.isEmpty() )
516 else if ( email.isEmpty() )
519 return QString::fromLatin1(
"%1 <%2>" ).arg( name, email );
526 if ( summary & Signature::Red )
528 if ( summary & Signature::Green )
538 const bool red = (sig.summary() & Signature::Red);
539 const bool valid = (sig.summary() & Signature::Valid);
543 if (
const char * fpr = sig.fingerprint() )
544 return i18n(
"Bad signature by unknown certificate %1: %2", QString::fromLatin1( fpr ), QString::fromLocal8Bit( sig.status().asString() ) );
546 return i18n(
"Bad signature by an unknown certificate: %1", QString::fromLocal8Bit( sig.status().asString() ) );
548 return i18n(
"Bad signature by %1: %2", keyToString( key ), QString::fromLocal8Bit( sig.status().asString() ) );
552 if (
const char * fpr = sig.fingerprint() )
553 return i18n(
"Good signature by unknown certificate %1.", QString::fromLatin1( fpr ) );
555 return i18n(
"Good signature by an unknown certificate.");
557 return i18n(
"Good signature by %1.", keyToString( key ) );
561 if (
const char * fpr = sig.fingerprint() )
562 return i18n(
"Invalid signature by unknown certificate %1: %2", QString::fromLatin1( fpr ), QString::fromLocal8Bit( sig.status().asString() ) );
564 return i18n(
"Invalid signature by an unknown certificate: %1", QString::fromLocal8Bit( sig.status().asString() ) );
566 return i18n(
"Invalid signature by %1: %2", keyToString( key ), QString::fromLocal8Bit( sig.status().asString() ) );
575 if ( result.isEmpty() )
578 return result + QLatin1Char(
'\n') +
579 i18n(
"This certificate was imported from the following sources:") + QLatin1Char(
'\n') +
580 ids.join(QLatin1String(
"\n"));
585 if (
import.isNull() )
588 if (
import.error().isCanceled() )
589 return i18n(
"The import of this certificate was canceled." );
590 if (
import.error() )
591 return i18n(
"An error occurred importing this certificate: %1",
592 QString::fromLocal8Bit(
import.error().asString() ) );
594 const unsigned int status =
import.status();
595 if ( status & Import::NewKey )
596 return ( status & Import::ContainedSecretKey )
597 ? i18n(
"This certificate was new to your keystore. The secret key is available." )
598 : i18n(
"This certificate is new to your keystore." ) ;
601 if ( status & Import::NewUserIDs )
602 results.push_back( i18n(
"New user-ids were added to this certificate by the import." ) );
603 if ( status & Import::NewSignatures )
604 results.push_back( i18n(
"New signatures were added to this certificate by the import." ) );
605 if ( status & Import::NewSubkeys )
606 results.push_back( i18n(
"New subkeys were added to this certificate by the import." ) );
608 return results.empty()
609 ? i18n(
"The import contained no new data for this certificate. It is unchanged.")
610 : results.join( QLatin1String(
"\n") );
static const char * flags[]
static std::string email(const UserID &uid)
VerifyChecksumsDialog::Status status
#define kleo_assert(cond)