61 #include <messagecore/utils/stringutil.h>
62 #include <kleo/specialjob.h>
63 #include <kleo/cryptobackendfactory.h>
64 #include <kleo/decryptverifyjob.h>
65 #include <kleo/verifydetachedjob.h>
66 #include <kleo/verifyopaquejob.h>
67 #include <kleo/keylistjob.h>
68 #include <kleo/importjob.h>
70 #include <libkpgp/kpgpblock.h>
71 #include <libkpgp/kpgp.h>
74 #include <kpimutils/email.h>
75 #include <kpimutils/linklocator.h>
76 #include <gpgme++/importresult.h>
77 #include <gpgme++/decryptionresult.h>
78 #include <gpgme++/key.h>
79 #include <gpgme++/keylistresult.h>
81 #include <kmime/kmime_message.h>
82 #include <kmime/kmime_util.h>
87 #include <kmimetype.h>
89 #include <ktemporaryfile.h>
90 #include <kstandarddirs.h>
91 #include <kiconloader.h>
93 #include <kconfiggroup.h>
97 #include <QApplication>
98 #include <QTextDocument>
101 #include <QTextCodec>
102 #include <QByteArray>
107 #ifdef KDEPIM_NO_WEBKIT
108 # include <QTextBrowser>
110 # include <QtWebKit/QWebPage>
111 # include <QtWebKit/QWebFrame>
116 #include <sys/stat.h>
117 #include <sys/types.h>
120 #include <messagecore/helpers/nodehelper.h>
121 #include <qtextdocument.h>
123 using KPIMUtils::LinkLocator;
124 using namespace MessageViewer;
125 using namespace MessageCore;
128 class ObjectTreeParser::CryptoProtocolSaver {
130 const Kleo::CryptoBackend::Protocol * protocol;
132 CryptoProtocolSaver(
ObjectTreeParser * _otp,
const Kleo::CryptoBackend::Protocol* _w )
133 : otp( _otp ), protocol( _otp ? _otp->cryptoProtocol() : 0 )
136 otp->setCryptoProtocol( _w );
139 ~CryptoProtocolSaver() {
141 otp->setCryptoProtocol( protocol );
146 bool showOnlyOneMimePart,
bool keepEncryptions,
147 bool includeSignatures,
149 : mSource( topLevelParser->mSource ),
150 mNodeHelper( topLevelParser->mNodeHelper ),
151 mTopLevelContent( topLevelParser->mTopLevelContent ),
152 mCryptoProtocol( topLevelParser->mCryptoProtocol ),
153 mShowOnlyOneMimePart( showOnlyOneMimePart ),
154 mKeepEncryptions( keepEncryptions ),
155 mIncludeSignatures( includeSignatures ),
156 mHasPendingAsyncJobs( false ),
157 mAllowAsync( topLevelParser->mAllowAsync ),
158 mShowRawToltecMail( false ),
159 mAttachmentStrategy( strategy )
166 const Kleo::CryptoBackend::Protocol * protocol,
167 bool showOnlyOneMimePart,
bool keepEncryptions,
168 bool includeSignatures,
171 mNodeHelper( nodeHelper ),
172 mTopLevelContent( 0 ),
173 mCryptoProtocol( protocol ),
174 mShowOnlyOneMimePart( showOnlyOneMimePart ),
175 mKeepEncryptions( keepEncryptions ),
176 mIncludeSignatures( includeSignatures ),
177 mHasPendingAsyncJobs( false ),
178 mAllowAsync( false ),
179 mShowRawToltecMail( false ),
180 mAttachmentStrategy( strategy )
185 void ObjectTreeParser::init()
191 if ( !mNodeHelper ) {
193 mDeleteNodeHelper =
true;
195 mDeleteNodeHelper =
false;
200 : mSource( other.mSource ),
201 mNodeHelper( other.nodeHelper() ),
202 mTopLevelContent( other.mTopLevelContent ),
203 mCryptoProtocol( other.cryptoProtocol() ),
204 mShowOnlyOneMimePart( other.showOnlyOneMimePart() ),
205 mKeepEncryptions( other.keepEncryptions() ),
206 mIncludeSignatures( other.includeSignatures() ),
207 mHasPendingAsyncJobs( other.hasPendingAsyncJobs() ),
208 mAllowAsync( other.allowAsync() ),
209 mAttachmentStrategy( other.attachmentStrategy() ),
210 mDeleteNodeHelper( false )
217 if ( mDeleteNodeHelper ) {
236 void ObjectTreeParser::createAndParseTempNode( KMime::Content* parentNode,
const char* content,
const char* cntDesc )
240 KMime::Content *newNode =
new KMime::Content();
241 newNode->setContent( KMime::CRLFtoLF( content ) );
250 if ( !newNode->head().isEmpty() ) {
251 newNode->contentDescription()->from7BitString( cntDesc );
256 otp.parseObjectTreeInternal( newNode );
257 copyContentFrom( &otp );
265 mTopLevelContent = node;
266 parseObjectTreeInternal( node );
269 void ObjectTreeParser::parseObjectTreeInternal( KMime::Content * node )
275 mHasPendingAsyncJobs =
false;
281 if ( MessageCore::NodeHelper::firstChild( node ) ) {
284 }
else if ( !node->parent() ) {
292 bool isRoot = node->isTopLevel();
294 htmlWriter()->
queue( QLatin1String(
"<div style=\"position: relative; word-wrap: break-word\">\n") );
296 for( ; node ; node = MessageCore::NodeHelper::nextSibling( node ) )
304 KMime::ContentIndex contentIndex = node->index();
306 htmlWriter()->
queue( QString::fromLatin1(
"<a name=\"att%1\"></a>").arg( contentIndex.toString() ) );
308 QByteArray mediaType(
"text" );
309 QByteArray subType(
"plain" );
310 if ( node->contentType(
false ) && !node->contentType()->mediaType().isEmpty() &&
311 !node->contentType()->subType().isEmpty() ) {
312 mediaType = node->contentType()->mediaType();
313 subType = node->contentType()->subType();
319 PartNodeBodyPart part( mTopLevelContent, node, mNodeHelper, codecFor( node ) );
331 processResult.setNeverDisplayInline(
true );
335 defaultHandling( node, processResult );
350 kFatal() <<
"THIS SHOULD NO LONGER HAPPEN:" << mediaType <<
'/' << subType;
353 if ( bpf && !bpf->
process(
this, node, processResult ) ) {
354 defaultHandling( node, processResult );
361 processResult.adjustCryptoStatesOfNode( node );
371 void ObjectTreeParser::defaultHandling( KMime::Content * node,
ProcessResult & result ) {
375 kWarning() <<
"no htmlWriter()";
380 if ( result.
isImage() && node->parent() &&
383 QString href = QLatin1String(
"file:///") + fileName;
384 QByteArray cid = node->contentID()->identifier();
390 if ( node->contentType()->mimeType() == QByteArray(
"application/octet-stream" ) &&
391 ( node->contentType()->name().endsWith( QString::fromLatin1(
"p7m" ) ) ||
392 node->contentType()->name().endsWith( QString::fromLatin1(
"p7s" ) ) ||
393 node->contentType()->name().endsWith( QString::fromLatin1(
"p7c" ) )
419 && !node->contentType()->isText() )
436 }
else if ( result.
isImage() ) {
444 codecFor( node ), result, false );
463 switch ( sig.status().code() ) {
464 case GPG_ERR_NO_ERROR:
465 return GPGME_SIG_STAT_GOOD;
466 case GPG_ERR_BAD_SIGNATURE:
467 return GPGME_SIG_STAT_BAD;
468 case GPG_ERR_NO_PUBKEY:
469 return GPGME_SIG_STAT_NOKEY;
470 case GPG_ERR_NO_DATA:
471 return GPGME_SIG_STAT_NOSIG;
472 case GPG_ERR_SIG_EXPIRED:
473 return GPGME_SIG_STAT_GOOD_EXP;
474 case GPG_ERR_KEY_EXPIRED:
475 return GPGME_SIG_STAT_GOOD_EXPKEY;
477 return GPGME_SIG_STAT_ERROR;
481 bool ObjectTreeParser::writeOpaqueOrMultipartSignedData( KMime::Content* data,
482 KMime::Content& sign,
483 const QString& fromAddress,
485 QByteArray* cleartextData,
486 const std::vector<GpgME::Signature> & paramSignatures,
490 bool bIsOpaqueSigned =
false;
491 enum { NO_PLUGIN, NOT_INITIALIZED, CANT_VERIFY_SIGNATURES }
492 cryptPlugError = NO_PLUGIN;
494 const Kleo::CryptoBackend::Protocol* cryptProto =
cryptoProtocol();
496 QString cryptPlugLibName;
497 QString cryptPlugDisplayName;
499 cryptPlugLibName = cryptProto->name();
500 cryptPlugDisplayName = cryptProto->displayName();
503 #ifdef DEBUG_SIGNATURE
506 kDebug() <<
"showing OpenPGP (Encrypted+Signed) data";
509 kDebug() <<
"processing Multipart Signed data";
511 kDebug() <<
"processing Opaque Signed data";
514 if ( doCheck && cryptProto ) {
519 QByteArray cleartext;
520 QByteArray signaturetext;
522 if ( doCheck && cryptProto ) {
524 cleartext = data->encodedContent();
525 #ifdef DEBUG_SIGNATURE
526 kDebug() <<
"ClearText : " << cleartext;
528 dumpToFile(
"dat_01_reader_signedtext_before_canonicalization",
529 cleartext.data(), cleartext.length() );
533 kDebug() <<
"Converting LF to CRLF (see RfC 2633, 3.1.1 Canonicalization)";
535 cleartext = KMime::LFtoCRLF( cleartext );
536 #ifdef DEBUG_SIGNATURE
537 kDebug() <<
" done.";
541 dumpToFile(
"dat_02_reader_signedtext_after_canonicalization",
542 cleartext.data(), cleartext.length() );
544 signaturetext = sign.decodedContent();
545 dumpToFile(
"dat_03_reader.sig", signaturetext.data(),
546 signaturetext.size() );
549 std::vector<GpgME::Signature> signatures;
551 signatures = paramSignatures;
559 messagePart.
keyTrust = Kpgp::KPGP_VALIDITY_UNKNOWN;
560 messagePart.
status = i18n(
"Wrong Crypto Plug-In.");
565 if ( doCheck && cryptProto ) {
566 #ifdef DEBUG_SIGNATURE
567 kDebug() <<
"tokoe: doCheck and cryptProto";
569 GpgME::VerificationResult result;
571 #ifdef DEBUG_SIGNATURE
572 kDebug() <<
"tokoe: is detached signature";
577 #ifdef DEBUG_SIGNATURE
578 kDebug() <<
"tokoe: no memento available";
580 Kleo::VerifyDetachedJob * job = cryptProto->verifyDetachedJob();
582 cryptPlugError = CANT_VERIFY_SIGNATURES;
585 QByteArray plainData = cleartext;
589 #ifdef DEBUG_SIGNATURE
590 kDebug() <<
"tokoe: allowAsync";
594 if ( newM->
start() ) {
595 #ifdef DEBUG_SIGNATURE
596 kDebug() <<
"tokoe: new memento started";
599 mHasPendingAsyncJobs =
true;
610 #ifdef DEBUG_SIGNATURE
611 kDebug() <<
"tokoe: memento is running";
614 mHasPendingAsyncJobs =
true;
619 #ifdef DEBUG_SIGNATURE
620 kDebug() <<
"tokoe: memento finished, assign result";
628 #ifdef DEBUG_SIGNATURE
629 kDebug() <<
"tokoe: is opaque signature";
634 #ifdef DEBUG_SIGNATURE
635 kDebug() <<
"tokoe: no memento available";
637 Kleo::VerifyOpaqueJob * job = cryptProto->verifyOpaqueJob();
639 cryptPlugError = CANT_VERIFY_SIGNATURES;
645 #ifdef DEBUG_SIGNATURE
646 kDebug() <<
"tokoe: allowAsync";
650 if ( newM->
start() ) {
651 #ifdef DEBUG_SIGNATURE
652 kDebug() <<
"tokoe: new memento started";
655 mHasPendingAsyncJobs =
true;
666 #ifdef DEBUG_SIGNATURE
667 kDebug() <<
"tokoe: memento is running";
670 mHasPendingAsyncJobs =
true;
675 #ifdef DEBUG_SIGNATURE
676 kDebug() <<
"tokoe: memento finished, assign result";
685 std::stringstream ss;
687 #ifdef DEBUG_SIGNATURE
688 kDebug() << ss.str().c_str();
690 signatures = result.signatures();
693 messagePart.
auditLogError = GpgME::Error( GPG_ERR_NOT_IMPLEMENTED );
695 #ifdef DEBUG_SIGNATURE
697 kDebug() <<
"returned from CRYPTPLUG";
701 if ( !signatures.empty() ) {
702 #ifdef DEBUG_SIGNATURE
703 kDebug() <<
"\nFound signature";
705 GpgME::Signature signature = signatures.front();
708 messagePart.
status = QString::fromLocal8Bit( signature.status().asString() );
709 for ( uint i = 1; i < signatures.size(); ++i ) {
712 messagePart.
status = i18n(
"Different results for signatures");
715 if ( messagePart.
status_code & GPGME_SIG_STAT_GOOD ) {
721 Q_ASSERT( !key.keyID() );
725 Kleo::KeyListJob * job = cryptProto->keyListJob(
false );
727 kDebug() <<
"The Crypto backend does not support listing keys. ";
729 std::vector<GpgME::Key> found_keys;
731 GpgME::KeyListResult res = job->exec( QStringList( QLatin1String(signature.fingerprint()) ),
false, found_keys );
733 kDebug() <<
"Error while searching key for Fingerprint: " << signature.fingerprint();
735 if ( found_keys.size() > 1 ) {
737 kDebug() <<
"Oops: Found more then one Key for Fingerprint: " << signature.fingerprint();
739 if ( found_keys.size() != 1 ) {
741 kDebug() <<
"Oops: Found no Key for Fingerprint: " << signature.fingerprint();
753 messagePart.
keyId = key.keyID();
754 if ( messagePart.
keyId.isEmpty() )
755 messagePart.
keyId = signature.fingerprint();
757 messagePart.
keyTrust = (Kpgp::Validity)signature.validity();
758 if ( key.numUserIDs() > 0 && key.userID( 0 ).id() )
759 messagePart.
signer = Kleo::DN( key.userID( 0 ).id() ).prettyDN();
760 for ( uint iMail = 0; iMail < key.numUserIDs(); ++iMail ) {
763 if ( key.userID( iMail ).email() ) {
764 QString email = QString::fromUtf8( key.userID( iMail ).email() );
767 if ( email.startsWith( QLatin1Char(
'<') ) && email.endsWith( QLatin1Char(
'>') ) )
768 email = email.mid( 1, email.length() - 2 );
769 if ( !email.isEmpty() )
774 if ( signature.creationTime() )
775 messagePart.
creationTime.setTime_t( signature.creationTime() );
778 if ( messagePart.
signer.isEmpty() ) {
779 if ( key.numUserIDs() > 0 && key.userID( 0 ).name() )
780 messagePart.
signer = Kleo::DN( key.userID( 0 ).name() ).prettyDN();
782 if ( messagePart.
signer.isEmpty() )
788 #ifdef DEBUG_SIGNATURE
789 kDebug() <<
"\n key id:" << messagePart.
keyId
790 <<
"\n key trust:" << messagePart.
keyTrust
791 <<
"\n signer:" << messagePart.
signer;
797 if ( !doCheck || !data ){
798 if ( cleartextData || !cleartext.isEmpty() ) {
803 bIsOpaqueSigned =
true;
805 CryptoProtocolSaver cpws(
this, cryptProto );
806 createAndParseTempNode( &sign, doCheck ? cleartext.data() : cleartextData->data(),
807 "opaque signed data" );
813 else if ( !hideErrors ) {
815 txt = QLatin1String(
"<hr><b><h2>");
816 txt.append( i18n(
"The crypto engine returned no cleartext data." ) );
817 txt.append( QLatin1String(
"</h2></b>" ));
818 txt.append( QLatin1String(
"<br/> <br/>") );
819 txt.append( i18n(
"Status: " ) );
820 if ( !messagePart.
status.isEmpty() ) {
821 txt.append( QLatin1String(
"<i>") );
822 txt.append( messagePart.
status );
823 txt.append( QLatin1String(
"</i>") );
826 txt.append( i18nc(
"Status of message unknown.",
"(unknown)") );
835 switch ( cryptPlugError ) {
836 case NOT_INITIALIZED:
837 errorMsg = i18n(
"Crypto plug-in \"%1\" is not initialized.",
840 case CANT_VERIFY_SIGNATURES:
841 errorMsg = i18n(
"Crypto plug-in \"%1\" cannot verify signatures.",
845 if ( cryptPlugDisplayName.isEmpty() )
846 errorMsg = i18n(
"No appropriate crypto plug-in was found." );
848 errorMsg = i18nc(
"%1 is either 'OpenPGP' or 'S/MIME'",
849 "No %1 plug-in was found.",
850 cryptPlugDisplayName );
853 messagePart.
errorText = i18n(
"The message is signed, but the "
854 "validity of the signature cannot be "
867 otp.parseObjectTreeInternal( data );
868 copyContentFrom( &otp );
873 #ifdef DEBUG_SIGNATURE
874 kDebug() <<
"done, returning" << ( bIsOpaqueSigned ?
"TRUE" :
"FALSE" );
877 return bIsOpaqueSigned;
880 void ObjectTreeParser::writeDeferredDecryptionBlock()
882 const QString iconName = QLatin1String(
"file:///") + KIconLoader::global()->iconPath( QLatin1String(
"document-decrypt"),
883 KIconLoader::Small );
884 const QString decryptedData = QLatin1String(
"<div style=\"font-size:large; text-align:center;"
885 "padding-top:20pt;\">")
886 + i18n(
"This message is encrypted.")
887 + QLatin1String(
"</div>"
888 "<div style=\"text-align:center; padding-bottom:20pt;\">"
889 "<a href=\"kmail:decryptMessage\">"
890 "<img src=\"") + iconName + QLatin1String(
"\"/>")
891 + i18n(
"Decrypt Message")
892 + QLatin1String(
"</a></div>");
897 mRawDecryptedBody += decryptedData.toUtf8();
909 void ObjectTreeParser::writeDecryptionInProgressBlock()
915 const QString decryptedData = i18n(
"Encrypted data not shown");
928 void ObjectTreeParser::writeCertificateImportResult(
const GpgME::ImportResult & res )
931 htmlWriter()->
queue( i18n(
"Sorry, certificate could not be imported.<br />"
932 "Reason: %1", QString::fromLocal8Bit( res.error().asString() ) ) );
936 const int nImp = res.numImported();
937 const int nUnc = res.numUnchanged();
938 const int nSKImp = res.numSecretKeysImported();
939 const int nSKUnc = res.numSecretKeysUnchanged();
940 if ( !nImp && !nSKImp && !nUnc && !nSKUnc ) {
941 htmlWriter()->
queue( i18n(
"Sorry, no certificates were found in this message." ) );
944 QString comment = QLatin1String(
"<b>") + i18n(
"Certificate import status:" ) + QLatin1String(
"</b><br/> <br/>");
946 comment += i18np(
"1 new certificate was imported.",
947 "%1 new certificates were imported.", nImp ) + QLatin1String(
"<br/>");
949 comment += i18np(
"1 certificate was unchanged.",
950 "%1 certificates were unchanged.", nUnc ) + QLatin1String(
"<br/>");
952 comment += i18np(
"1 new secret key was imported.",
953 "%1 new secret keys were imported.", nSKImp ) + QLatin1String(
"<br/>");
955 comment += i18np(
"1 secret key was unchanged.",
956 "%1 secret keys were unchanged.", nSKUnc ) + QLatin1String(
"<br/>");
957 comment += QLatin1String(
" <br/>");
959 if ( !nImp && !nSKImp ) {
963 const std::vector<GpgME::Import> imports = res.imports();
964 if ( imports.empty() ) {
965 htmlWriter()->
queue( i18n(
"Sorry, no details on certificate import available." ) + QLatin1String(
"<hr>") );
968 htmlWriter()->
queue( QLatin1String(
"<b>") + i18n(
"Certificate import details:" ) + QLatin1String(
"</b><br/>") );
969 std::vector<GpgME::Import>::const_iterator end( imports.end() );
970 for ( std::vector<GpgME::Import>::const_iterator it = imports.begin() ; it != end ; ++it ) {
971 if ( (*it).error() ) {
972 htmlWriter()->
queue( i18nc(
"Certificate import failed.",
"Failed: %1 (%2)", QLatin1String((*it).fingerprint()),
973 QString::fromLocal8Bit( (*it).error().asString() ) ) );
974 }
else if ( (*it).status() & ~GpgME::Import::ContainedSecretKey ) {
975 if ( (*it).status() & GpgME::Import::ContainedSecretKey ) {
976 htmlWriter()->
queue( i18n(
"New or changed: %1 (secret key available)", QLatin1String((*it).fingerprint() )) );
978 htmlWriter()->
queue( i18n(
"New or changed: %1", QLatin1String((*it).fingerprint() )) );
988 bool ObjectTreeParser::okDecryptMIME( KMime::Content& data,
989 QByteArray& decryptedData,
990 bool& signatureFound,
991 std::vector<GpgME::Signature> &signatures,
993 bool& passphraseError,
994 bool& actuallyEncrypted,
995 bool& decryptionStarted,
998 passphraseError =
false;
999 decryptionStarted =
false;
1003 bool bDecryptionOk =
false;
1004 enum { NO_PLUGIN, NOT_INITIALIZED, CANT_DECRYPT }
1005 cryptPlugError = NO_PLUGIN;
1007 const Kleo::CryptoBackend::Protocol* cryptProto =
cryptoProtocol();
1009 QString cryptPlugLibName;
1011 cryptPlugLibName = cryptProto->name();
1015 const QString errorMsg = i18n(
"Could not decrypt the data." );
1018 QByteArray ciphertext = data.decodedContent();
1020 QString cipherStr = QString::fromLatin1( ciphertext );
1021 bool cipherIsBinary = ( !cipherStr.contains(
"BEGIN ENCRYPTED MESSAGE", Qt::CaseInsensitive ) ) &&
1022 ( !cipherStr.contains(
"BEGIN PGP ENCRYPTED MESSAGE", Qt::CaseInsensitive ) ) &&
1023 ( !cipherStr.contains(
"BEGIN PGP MESSAGE", Qt::CaseInsensitive ) );
1025 dumpToFile(
"dat_04_reader.encrypted", ciphertext.data(), ciphertext.size() );
1028 deb =
"\n\nE N C R Y P T E D D A T A = ";
1029 if ( cipherIsBinary )
1030 deb +=
"[binary data]";
1047 Kleo::DecryptVerifyJob * job = cryptProto->decryptVerifyJob();
1049 cryptPlugError = CANT_DECRYPT;
1057 if ( newM->
start() ) {
1058 decryptionStarted =
true;
1059 mHasPendingAsyncJobs =
true;
1070 decryptionStarted =
true;
1071 mHasPendingAsyncJobs =
true;
1076 const QByteArray & plainText = m->
plainText();
1077 const GpgME::DecryptionResult & decryptResult = m->
decryptResult();
1078 const GpgME::VerificationResult & verifyResult = m->
verifyResult();
1079 std::stringstream ss;
1080 ss << decryptResult <<
'\n' << verifyResult;
1082 signatureFound = verifyResult.signatures().size() > 0;
1083 signatures = verifyResult.signatures();
1084 bDecryptionOk = !decryptResult.error();
1085 passphraseError = decryptResult.error().isCanceled()
1086 || decryptResult.error().code() == GPG_ERR_NO_SECKEY;
1087 actuallyEncrypted = decryptResult.error().code() != GPG_ERR_NO_DATA;
1088 partMetaData.
errorText = QString::fromLocal8Bit( decryptResult.error().asString() );
1092 if ( actuallyEncrypted && decryptResult.numRecipients() > 0 )
1093 partMetaData.
keyId = decryptResult.recipient( 0 ).keyID();
1096 if ( bDecryptionOk )
1097 decryptedData = plainText;
1099 decryptedData =
"<div style=\"font-size:x-large; text-align:center;"
1103 if ( !passphraseError )
1104 partMetaData.
errorText = i18n(
"Crypto plug-in \"%1\" could not decrypt the data.", cryptPlugLibName )
1105 + QLatin1String(
"<br />")
1106 + i18n(
"Error: %1", partMetaData.
errorText );
1111 if ( !cryptProto ) {
1112 decryptedData =
"<div style=\"text-align:center; padding:20pt;\">"
1115 switch ( cryptPlugError ) {
1116 case NOT_INITIALIZED:
1117 partMetaData.
errorText = i18n(
"Crypto plug-in \"%1\" is not initialized.",
1121 partMetaData.
errorText = i18n(
"Crypto plug-in \"%1\" cannot decrypt messages.",
1125 partMetaData.
errorText = i18n(
"No appropriate crypto plug-in was found." );
1132 QByteArray ciphertext( data.decodedContent() );
1133 QString cipherStr = QString::fromLatin1( ciphertext );
1134 bool cipherIsBinary = ( !cipherStr.contains(QLatin1String(
"BEGIN ENCRYPTED MESSAGE"), Qt::CaseInsensitive ) ) &&
1135 ( !cipherStr.contains(QLatin1String(
"BEGIN PGP ENCRYPTED MESSAGE"), Qt::CaseInsensitive ) ) &&
1136 ( !cipherStr.contains(QLatin1String(
"BEGIN PGP MESSAGE"), Qt::CaseInsensitive ) );
1137 if ( !cipherIsBinary ) {
1138 decryptedData = ciphertext;
1141 decryptedData =
"<div style=\"font-size:x-large; text-align:center;"
1148 dumpToFile(
"dat_05_reader.decrypted", decryptedData.data(), decryptedData.size() );
1150 return bDecryptionOk;
1154 bool ObjectTreeParser::containsExternalReferences(
const QString & str,
const QString&extraHead )
1156 const bool hasBaseInHeader = extraHead.contains(QLatin1String(
"<base href=\""),Qt::CaseInsensitive);
1157 if(hasBaseInHeader && (str.contains(QLatin1String(
"href=\"/"),Qt::CaseInsensitive) ||
1158 str.contains(QLatin1String(
"<img src=\"/"),Qt::CaseInsensitive)) ) {
1167 int httpPos = str.indexOf( QLatin1String(
"\"http:"), Qt::CaseInsensitive );
1168 int httpsPos = str.indexOf( QLatin1String(
"\"https:"), Qt::CaseInsensitive );
1170 while ( httpPos >= 0 || httpsPos >= 0 ) {
1172 int pos = ( httpPos < httpsPos )
1173 ? ( ( httpPos >= 0 ) ? httpPos : httpsPos )
1174 : ( ( httpsPos >= 0 ) ? httpsPos : httpPos );
1177 int hrefPos = str.lastIndexOf( QLatin1String(
"href"), pos - 5, Qt::CaseInsensitive );
1181 if ( ( hrefPos == -1 ) || ( pos - hrefPos > 7 ) ) {
1186 int dtdPos = str.indexOf( QLatin1String(
"http://www.w3.org/TR/html4/loose.dtd"), pos + 1 );
1187 if ( dtdPos != ( pos + 1 ) )
1192 if ( pos == httpPos ) {
1193 httpPos = str.indexOf( QLatin1String(
"\"http:"), httpPos + 6, Qt::CaseInsensitive );
1196 httpsPos = str.indexOf( QLatin1String(
"\"https:"), httpsPos + 7, Qt::CaseInsensitive );
1203 const QByteArray partBody( curNode->decodedContent() );
1205 const QString bodyHTML = codecFor( curNode )->toUnicode( partBody );
1206 mHtmlContent += bodyHTML;
1208 mRawDecryptedBody = partBody;
1215 bodyText = bodyHTML;
1217 bodyText = QLatin1String(StringUtil::convertAngleBracketsToHtml( partBody ));
1227 for (
int i = 0; i < 3; ++i )
1229 bodyText = colorer.
process( bodyText, extraHead );
1240 containsExternalReferences( bodyText,extraHead ) ) {
1242 htmlWriter()->
queue( i18n(
"<b>Note:</b> This HTML message may contain external "
1243 "references to images etc. For security/privacy reasons "
1244 "external references are not loaded. If you trust the "
1245 "sender of this message then you can load the external "
1246 "references for this message "
1247 "<a href=\"kmail:loadExternal\">by clicking here</a>.") );
1252 htmlWriter()->
queue( i18n(
"<b>Note:</b> This is an HTML message. For "
1253 "security reasons, only the raw HTML code "
1254 "is shown. If you trust the sender of this "
1255 "message then you can activate formatted "
1256 "HTML display for this message "
1257 "<a href=\"kmail:showHTML\">by clicking here</a>.") );
1262 htmlWriter()->
queue( QLatin1String(
"<div style=\"position: relative\">\n") );
1273 if ( !curNode || curNode->head().isEmpty() )
1275 if ( curNode->hasHeader(
"X-Mailman-Version") )
1277 if ( curNode->hasHeader(
"X-Mailer") ) {
1278 KMime::Headers::Base *header = curNode->headerByType(
"X-Mailer");
1279 if ( header->asUnicodeString().contains(QLatin1String(
"MAILMAN"), Qt::CaseInsensitive ) )
1285 bool ObjectTreeParser::processMailmanMessage( KMime::Content* curNode ) {
1286 const QString str = QString::fromLatin1( curNode->decodedContent() );
1289 const QLatin1String delim1(
"--__--__--\n\nMessage:" );
1290 const QLatin1String delim2(
"--__--__--\r\n\r\nMessage:" );
1291 const QLatin1String delimZ2(
"--__--__--\n\n_____________" );
1292 const QLatin1String delimZ1(
"--__--__--\r\n\r\n_____________" );
1293 QString partStr, digestHeaderStr;
1294 int thisDelim = str.indexOf( delim1, Qt::CaseInsensitive );
1295 if ( thisDelim == -1 ) {
1296 thisDelim = str.indexOf( delim2, Qt::CaseInsensitive );
1298 if ( thisDelim == -1 ) {
1302 int nextDelim = str.indexOf( delim1, thisDelim+1, Qt::CaseInsensitive );
1303 if ( -1 == nextDelim ) {
1304 nextDelim = str.indexOf( delim2, thisDelim+1, Qt::CaseInsensitive );
1306 if ( -1 == nextDelim ) {
1307 nextDelim = str.indexOf( delimZ1, thisDelim+1, Qt::CaseInsensitive );
1309 if ( -1 == nextDelim ) {
1310 nextDelim = str.indexOf( delimZ2, thisDelim+1, Qt::CaseInsensitive );
1312 if ( nextDelim < 0) {
1320 digestHeaderStr = QLatin1String(
"Content-Type: text/plain\nContent-Description: digest header\n\n");
1321 digestHeaderStr += str.mid( 0, thisDelim );
1322 createAndParseTempNode( mTopLevelContent, digestHeaderStr.toLatin1(),
"Digest Header" );
1326 curNode->contentType()->setMimeType(
"multipart/digest" );
1327 while( -1 < nextDelim ){
1328 int thisEoL = str.indexOf(QLatin1String(
"\nMessage:"), thisDelim, Qt::CaseInsensitive );
1330 thisDelim = thisEoL+1;
1332 thisEoL = str.indexOf(QLatin1String(
"\n_____________"), thisDelim, Qt::CaseInsensitive );
1334 thisDelim = thisEoL+1;
1336 thisEoL = str.indexOf( QLatin1Char(
'\n'), thisDelim );
1338 thisDelim = thisEoL+1;
1340 thisDelim = thisDelim+1;
1344 partStr = QLatin1String(
"Content-Type: message/rfc822\nContent-Description: embedded message\n\n");
1345 partStr += QLatin1String(
"Content-Type: text/plain\n");
1346 partStr += str.mid( thisDelim, nextDelim-thisDelim );
1347 QString subject = QString::fromLatin1(
"embedded message");
1348 QString subSearch = QString::fromLatin1(
"\nSubject:");
1349 int subPos = partStr.indexOf(subSearch, 0, Qt::CaseInsensitive );
1351 subject = partStr.mid(subPos+subSearch.length());
1352 thisEoL = subject.indexOf(QLatin1Char(
'\n'));
1354 subject.truncate( thisEoL );
1356 kDebug() <<
" embedded message found: \"" << subject;
1357 createAndParseTempNode( mTopLevelContent, partStr.toLatin1(), subject.toLatin1() );
1359 thisDelim = nextDelim+1;
1360 nextDelim = str.indexOf(delim1, thisDelim, Qt::CaseInsensitive );
1361 if ( -1 == nextDelim )
1362 nextDelim = str.indexOf(delim2, thisDelim, Qt::CaseInsensitive);
1363 if ( -1 == nextDelim )
1364 nextDelim = str.indexOf(delimZ1, thisDelim, Qt::CaseInsensitive);
1365 if ( -1 == nextDelim )
1366 nextDelim = str.indexOf(delimZ2, thisDelim, Qt::CaseInsensitive);
1369 curNode->contentType()->setMimeType(
"text/plain" );
1370 int thisEoL = str.indexOf( QLatin1String(
"_____________"), thisDelim );
1371 if ( -1 < thisEoL ){
1372 thisDelim = thisEoL;
1373 thisEoL = str.indexOf( QLatin1Char(
'\n'), thisDelim );
1375 thisDelim = thisEoL+1;
1378 thisDelim = thisDelim+1;
1379 partStr = QLatin1String(
"Content-Type: text/plain\nContent-Description: digest footer\n\n");
1380 partStr += str.mid( thisDelim );
1381 createAndParseTempNode( mTopLevelContent, partStr.toLatin1(),
"Digest Footer" );
1385 void ObjectTreeParser::extractNodeInfos( KMime::Content *curNode,
bool isFirstTextPart )
1387 mRawDecryptedBody = curNode->decodedContent();
1388 if ( isFirstTextPart ) {
1389 mPlainTextContent += curNode->decodedText();
1397 const bool isFirstTextPart = ( curNode->topLevel()->textContent() == curNode );
1403 extractNodeInfos( curNode, isFirstTextPart );
1407 const bool bDrawFrame = !isFirstTextPart
1409 && !label.isEmpty();
1411 label = StringUtil::quoteHtmlChars( label,
true );
1413 const QString comment =
1414 StringUtil::quoteHtmlChars( curNode->contentDescription()->asUnicodeString(), true );
1416 const QString fileName;
1418 const QString dir = QApplication::isRightToLeft() ? QLatin1String(
"rtl") : QLatin1String(
"ltr") ;
1420 QString htmlStr = QLatin1String(
"<table cellspacing=\"1\" class=\"textAtm\">"
1421 "<tr class=\"textAtmH\"><td dir=\"") + dir + QLatin1String(
"\">");
1422 if ( !fileName.isEmpty() )
1423 htmlStr += QLatin1String(
"<a href=\"") + mNodeHelper->
asHREF( curNode, QLatin1String(
"body") ) + QLatin1String(
"\">")
1424 + label + QLatin1String(
"</a>");
1427 if ( !comment.isEmpty() )
1428 htmlStr += QLatin1String(
"<br/>") + comment;
1429 htmlStr += QLatin1String(
"</td></tr><tr class=\"textAtmB\"><td>");
1436 !processMailmanMessage( curNode ) ) {
1437 const QString oldPlainText = mPlainTextContent;
1439 codecFor( curNode ), result, !bDrawFrame );
1444 if ( !isFirstTextPart ) {
1445 mPlainTextContent = oldPlainText;
1456 void ObjectTreeParser::stdChildHandling( KMime::Content * child ) {
1461 otp.setShowOnlyOneMimePart(
false );
1462 otp.parseObjectTreeInternal( child );
1463 copyContentFrom( &otp );
1468 return i18n(
"This message is a <i>Toltec</i> Groupware object, it can only be viewed with "
1469 "Microsoft Outlook in combination with the Toltec connector." );
1472 bool ObjectTreeParser::processToltecMail( KMime::Content *node )
1479 htmlWriter()->
queue( QLatin1String(
"<br/><br/><a href=\"kmail:showRawToltecMail\">") +
1480 i18n(
"Show Raw Message" ) + QLatin1String(
"</a>") );
1486 if ( processToltecMail( node ) ) {
1490 KMime::Content * child = MessageCore::NodeHelper::firstChild( node );
1495 stdChildHandling( child );
1501 KMime::Content * child = MessageCore::NodeHelper::firstChild( node );
1505 KMime::Content* dataHtml =
findType( child,
"text/html",
false,
true );
1506 KMime::Content* dataPlain =
findType( child,
"text/plain",
false,
true );
1513 dataHtml =
findType( child,
"multipart/related",
false,
true );
1520 if ( !dataHtml && mSource->
htmlMail() ) {
1521 dataHtml =
findType( child,
"multipart/mixed",
false,
true );
1529 stdChildHandling( dataPlain );
1532 stdChildHandling( dataHtml );
1537 if ( ( mSource->
htmlMail() && dataHtml) ||
1538 (dataHtml && dataPlain && dataPlain->body().isEmpty()) ) {
1541 stdChildHandling( dataHtml );
1548 stdChildHandling( dataPlain );
1553 stdChildHandling( child );
1567 KMime::Content * child = MessageCore::NodeHelper::firstChild( node );
1568 if ( node->contents().size() != 2 ) {
1569 kDebug() <<
"mulitpart/signed must have exactly two child parts!" << endl
1570 <<
"processing as multipart/mixed";
1572 stdChildHandling( child );
1576 KMime::Content * signedData = child;
1577 assert( signedData );
1579 KMime::Content * signature = node->contents().at(1);
1580 assert( signature );
1585 stdChildHandling( signedData );
1589 QString protocolContentType = node->contentType()->parameter( QLatin1String(
"protocol") ).toLower();
1590 const QString signatureContentType = QLatin1String(signature->contentType()->mimeType().toLower());
1591 if ( protocolContentType.isEmpty() ) {
1592 kWarning() <<
"Message doesn't set the protocol for the multipart/signed content-type, "
1593 "using content-type of the signature:" << signatureContentType;
1594 protocolContentType = signatureContentType;
1597 const Kleo::CryptoBackend::Protocol *protocol = 0;
1598 if ( protocolContentType == QLatin1String(
"application/pkcs7-signature" ) ||
1599 protocolContentType == QLatin1String(
"application/x-pkcs7-signature" ) )
1600 protocol = Kleo::CryptoBackendFactory::instance()->smime();
1601 else if ( protocolContentType == QLatin1String(
"application/pgp-signature" ) ||
1602 protocolContentType == QLatin1String(
"application/x-pgp-signature" ) )
1603 protocol = Kleo::CryptoBackendFactory::instance()->openpgp();
1607 stdChildHandling( signedData );
1611 CryptoProtocolSaver saver(
this, protocol );
1614 writeOpaqueOrMultipartSignedData( signedData, *signature,
1621 KMime::Content * child = MessageCore::NodeHelper::firstChild( node );
1627 const QByteArray cstr = node->decodedContent();
1630 codecFor( node ), result,
false );
1632 mRawDecryptedBody += cstr;
1636 const Kleo::CryptoBackend::Protocol * useThisCryptProto = 0;
1641 KMime::Content* data =
findType( child,
"application/octet-stream",
false,
true );
1643 useThisCryptProto = Kleo::CryptoBackendFactory::instance()->openpgp();
1646 data =
findType( child,
"application/pkcs7-mime",
false,
true );
1648 useThisCryptProto = Kleo::CryptoBackendFactory::instance()->smime();
1656 stdChildHandling( child );
1660 CryptoProtocolSaver cpws(
this, useThisCryptProto );
1662 KMime::Content * dataChild = MessageCore::NodeHelper::firstChild( data );
1664 stdChildHandling( dataChild );
1671 writeDeferredDecryptionBlock();
1682 otp.parseObjectTreeInternal( newNode );
1683 copyContentFrom( &otp );
1686 QByteArray decryptedData;
1687 bool signatureFound;
1688 std::vector<GpgME::Signature> signatures;
1689 bool passphraseError;
1690 bool actuallyEncrypted =
true;
1691 bool decryptionStarted;
1693 bool bOkDecrypt = okDecryptMIME( *data,
1704 if ( decryptionStarted ) {
1705 writeDecryptionInProgressBlock();
1733 if ( signatureFound ) {
1734 writeOpaqueOrMultipartSignedData( 0,
1744 decryptedData = KMime::CRLFtoLF( decryptedData );
1746 createAndParseTempNode( node, decryptedData.constData(),
"encrypted data" );
1749 mRawDecryptedBody += decryptedData;
1777 KMime::Message::Ptr message = node->bodyAsMessage();
1779 kWarning() <<
"Node is of type message/rfc822 but doesn't have a message!";
1791 message->from()->asUnicodeString(),
1799 otp.parseObjectTreeInternal( message.get() );
1821 otp.parseObjectTreeInternal( child );
1822 copyContentFrom( &otp );
1826 const Kleo::CryptoBackend::Protocol* oldUseThisCryptPlug =
cryptoProtocol();
1828 && node->parent()->contentType()->mimeType() ==
"multipart/encrypted" ) {
1831 const QByteArray cstr = node->decodedContent();
1834 codecFor( node ), result,
false );
1836 mRawDecryptedBody += cstr;
1838 writeDeferredDecryptionBlock();
1845 QByteArray decryptedData;
1846 bool signatureFound;
1847 std::vector<GpgME::Signature> signatures;
1848 bool passphraseError;
1849 bool actuallyEncrypted =
true;
1850 bool decryptionStarted;
1852 bool bOkDecrypt = okDecryptMIME( *node,
1862 if ( decryptionStarted ) {
1863 writeDecryptionInProgressBlock();
1879 createAndParseTempNode( node, decryptedData.constData(),
"encrypted data" );
1881 mRawDecryptedBody += decryptedData;
1903 otp.parseObjectTreeInternal( child );
1904 copyContentFrom( &otp );
1908 if ( node->head().isEmpty() )
1911 const Kleo::CryptoBackend::Protocol * smimeCrypto = Kleo::CryptoBackendFactory::instance()->smime();
1915 const QString smimeType = node->contentType()->parameter(QLatin1String(
"smime-type")).toLower();
1917 if ( smimeType == QLatin1String(
"certs-only" ) ) {
1925 const QByteArray certData = node->decodedContent();
1927 Kleo::ImportJob *
import = smimeCrypto->importJob();
1929 const GpgME::ImportResult res = executor.
exec(
import, certData );
1930 writeCertificateImportResult( res );
1934 CryptoProtocolSaver cpws(
this, smimeCrypto );
1936 bool isSigned = ( smimeType == QLatin1String(
"signed-data" ) );
1937 bool isEncrypted = ( smimeType == QLatin1String(
"enveloped-data" ) );
1942 KMime::Content* signTestNode = isEncrypted ? 0 : node;
1949 if ( isEncrypted ) {
1954 QByteArray decryptedData;
1958 bool signatureFound;
1959 std::vector<GpgME::Signature> signatures;
1960 bool passphraseError;
1961 bool actuallyEncrypted =
true;
1962 bool decryptionStarted;
1965 writeDeferredDecryptionBlock();
1969 const bool bOkDecrypt = okDecryptMIME( *node, decryptedData, signatureFound, signatures,
1970 false, passphraseError, actuallyEncrypted,
1971 decryptionStarted, messagePart );
1973 if ( decryptionStarted ) {
1974 writeDecryptionInProgressBlock();
1982 if( signatureFound )
1991 createAndParseTempNode( node, decryptedData.constData(),
"encrypted data" );
1999 if ( passphraseError || ( smimeType.isEmpty() && actuallyEncrypted ) ) {
2004 if ( isEncrypted ) {
2027 if ( signTestNode ) {
2034 bool sigFound = writeOpaqueOrMultipartSignedData( 0,
2039 std::vector<GpgME::Signature>(),
2048 if ( signTestNode != node )
2055 return isSigned || isEncrypted;
2060 const Kleo::CryptoBackend::Protocol * chiasmus =
2061 Kleo::CryptoBackendFactory::instance()->protocol(
"Chiasmus" );
2065 const std::auto_ptr<Kleo::SpecialJob> listjob( chiasmus->specialJob(
"x-obtain-keys", QMap<QString,QVariant>() ) );
2066 if ( !listjob.get() ) {
2067 errorText = i18n(
"Chiasmus backend does not offer the "
2068 "\"x-obtain-keys\" function. Please report this bug." );
2072 if ( listjob->exec() ) {
2073 errorText = i18n(
"Chiasmus Backend Error" );
2077 const QVariant result = listjob->property(
"result" );
2078 if ( result.type() != QVariant::StringList ) {
2079 errorText = i18n(
"Unexpected return value from Chiasmus backend: "
2080 "The \"x-obtain-keys\" function did not return a "
2081 "string list. Please report this bug." );
2085 const QStringList keys = result.toStringList();
2086 if ( keys.empty() ) {
2087 errorText = i18n(
"No keys have been found. Please check that a "
2088 "valid key path has been set in the Chiasmus "
2094 keys, GlobalSettings::chiasmusDecryptionKey(),
2095 GlobalSettings::chiasmusDecryptionOptions() ) );
2097 if ( selectorDlg->exec() != KDialog::Accepted || !selectorDlg ) {
2100 GlobalSettings::setChiasmusDecryptionOptions( selectorDlg->
options() );
2101 GlobalSettings::setChiasmusDecryptionKey( selectorDlg->
key() );
2102 assert( !GlobalSettings::chiasmusDecryptionKey().isEmpty() );
2104 Kleo::SpecialJob * job = chiasmus->specialJob(
"x-decrypt", QMap<QString,QVariant>() );
2106 errorText = i18n(
"Chiasmus backend does not offer the "
2107 "\"x-decrypt\" function. Please report this bug." );
2111 if ( !job->setProperty(
"key", GlobalSettings::chiasmusDecryptionKey() ) ||
2112 !job->setProperty(
"options", GlobalSettings::chiasmusDecryptionOptions() ) ||
2113 !job->setProperty(
"input", data ) ) {
2114 errorText = i18n(
"The \"x-decrypt\" function does not accept "
2115 "the expected parameters. Please report this bug." );
2119 if ( job->exec() ) {
2120 errorText = i18n(
"Chiasmus Decryption Error" );
2124 const QVariant resultData = job->property(
"result" );
2125 if ( resultData.type() != QVariant::ByteArray ) {
2126 errorText = i18n(
"Unexpected return value from Chiasmus backend: "
2127 "The \"x-decrypt\" function did not return a "
2128 "byte array. Please report this bug." );
2131 bodyDecoded = resultData.toByteArray();
2138 mRawDecryptedBody = curNode->decodedContent();
2143 mPlainTextContent += curNode->decodedText();
2148 QByteArray decryptedBody;
2150 const QByteArray data = curNode->decodedContent();
2161 const QByteArray body = bOkDecrypt ? decryptedBody : data;
2162 const QString chiasmusCharset = curNode->contentType()->parameter(QLatin1String(
"chiasmus-charset"));
2163 const QTextCodec* aCodec = chiasmusCharset.isEmpty() ? codecFor( curNode )
2165 htmlWriter()->
queue( quotedHTML( aCodec->toUnicode( body ),
false ) );
2174 const QString & fromAddress,
2175 const QTextCodec * codec,
2183 inlineSignatureState, inlineEncryptionState, decorate );
2193 const QString name = msgPart->contentType()->name();
2195 if ( label.isEmpty() )
2196 label = i18nc(
"display name for an unnamed attachment",
"Unnamed" );
2197 label = StringUtil::quoteHtmlChars( label,
true );
2199 QString comment = msgPart->contentDescription()->asUnicodeString();
2200 comment = StringUtil::quoteHtmlChars( comment,
true );
2201 if ( label == comment )
2204 QString href = mNodeHelper->
asHREF( msgPart, QLatin1String(
"body") );
2206 if ( inlineImage ) {
2209 htmlWriter()->
queue( QLatin1String(
"<div><a href=\"") + href + QLatin1String(
"\">"
2210 "<img src=\"file:///") + fileName + QLatin1String(
"\" border=\"0\" style=\"max-width: 100%\"/></a>"
2212 "<div><a href=\"") + href + QLatin1String(
"\">") + label + QLatin1String(
"</a>"
2214 "<div>") + comment + QLatin1String(
"</div><br/>") );
2217 const QString iconName = mNodeHelper->
iconName( msgPart );
2218 if( iconName.right( 14 ) == QLatin1String(
"mime_empty.png" ) ) {
2222 htmlWriter()->
queue( QLatin1String(
"<div><a href=\"") + href + QLatin1String(
"\"><img src=\"file:///") +
2223 iconName + QLatin1String(
"\" border=\"0\" style=\"max-width: 100%\" alt=\"\"/>") + label +
2224 QLatin1String(
"</a></div>"
2225 "<div>") + comment +QLatin1String(
"</div><br/>") );
2230 #define SIG_FRAME_COL_RED -1
2231 #define SIG_FRAME_COL_YELLOW 0
2232 #define SIG_FRAME_COL_GREEN 1
2235 GpgME::Signature::Summary summary,
2237 bool& showKeyInfos )
2242 showKeyInfos =
true;
2245 if( cryptProto == Kleo::CryptoBackendFactory::instance()->openpgp() ) {
2248 switch( status_code ) {
2250 result = i18n(
"Error: Signature not verified");
2253 result = i18n(
"Good signature");
2256 result = i18n(
"<b>Bad</b> signature");
2259 result = i18n(
"No public key to verify the signature");
2262 result = i18n(
"No signature found");
2265 result = i18n(
"Error verifying the signature");
2268 result = i18n(
"Different results for signatures");
2283 else if ( cryptProto == Kleo::CryptoBackendFactory::instance()->smime() ) {
2287 if( summary == GpgME::Signature::None ) {
2288 result = i18n(
"No status information available.");
2290 showKeyInfos =
false;
2294 if( summary & GpgME::Signature::Valid ) {
2295 result = i18n(
"Good signature.");
2305 showKeyInfos =
false;
2314 if( summary & GpgME::Signature::KeyExpired ){
2316 result2 += i18n(
"One key has expired.");
2318 if( summary & GpgME::Signature::SigExpired ){
2320 result2 += i18n(
"The signature has expired.");
2324 if( summary & GpgME::Signature::KeyMissing ) {
2325 result2 += i18n(
"Unable to verify: key missing.");
2328 showKeyInfos =
false;
2331 if( summary & GpgME::Signature::CrlMissing ){
2332 result2 += i18n(
"CRL not available.");
2335 if( summary & GpgME::Signature::CrlTooOld ){
2336 result2 += i18n(
"Available CRL is too old.");
2339 if( summary & GpgME::Signature::BadPolicy ){
2340 result2 += i18n(
"A policy was not met.");
2343 if( summary & GpgME::Signature::SysError ){
2344 result2 += i18n(
"A system error occurred.");
2348 showKeyInfos =
false;
2353 if( summary & GpgME::Signature::KeyRevoked ){
2355 result2 += i18n(
"One key has been revoked.");
2358 if( summary & GpgME::Signature::Red ) {
2359 if( result2.isEmpty() )
2372 showKeyInfos =
false;
2379 result = i18n(
"Good signature.");
2381 result = i18n(
"<b>Bad</b> signature.");
2385 if( !result2.isEmpty() ) {
2386 if( !result.isEmpty() )
2387 result.append(QLatin1String(
"<br />"));
2388 result.append( result2 );
2405 html += QLatin1String(
"<table cellspacing=\"0\" cellpadding=\"0\" width=\"100%\"><tr><td>");
2407 if ( block.
signClass == QLatin1String(
"signErr" ) ) {
2408 html += i18n(
"Invalid signature." );
2409 }
else if ( block.
signClass == QLatin1String(
"signOkKeyBad" )
2410 || block.
signClass == QLatin1String(
"signWarn" ) ) {
2411 html += i18n(
"Not enough information to check signature validity." );
2412 }
else if ( block.
signClass == QLatin1String(
"signOkKeyOk" ) ) {
2418 QString name = addr;
2419 if ( name.isEmpty() )
2422 if ( addr.isEmpty() ) {
2423 html += i18n(
"Signature is valid." );
2425 html += i18n(
"Signed by <a href=\"mailto:%1\">%2</a>.", addr, name );
2430 html += i18n(
"Unknown signature state" );
2432 html += QLatin1String(
"</td><td align=\"right\">");
2433 html += QLatin1String(
"<a href=\"kmail:showSignatureDetails\">");
2434 html += i18n(
"Show Details" );
2435 html += QLatin1String(
"</a></td></tr></table>");
2441 return QLatin1String(
"<table cellspacing=\"0\" cellpadding=\"0\" width=\"100%\"><tr><td rowspan=\"2\">");
2448 if (
const unsigned int code = err.code() ) {
2449 if ( code == GPG_ERR_NOT_IMPLEMENTED ) {
2450 kDebug() <<
"not showing link (not implemented)";
2452 }
else if ( code == GPG_ERR_NO_DATA ) {
2453 kDebug() <<
"not showing link (not available)";
2454 return i18n(
"No Audit Log available");
2456 return i18n(
"Error Retrieving Audit Log: %1", QString::fromLocal8Bit( err.asString() ) );
2460 if ( !auditLog.isEmpty() ) {
2462 url.setScheme( QLatin1String(
"kmail") );
2463 url.setPath( QLatin1String(
"showAuditLog") );
2464 url.addQueryItem( QLatin1String(
"log"), auditLog );
2466 return QLatin1String(
"<a href=\"") + url.url() + QLatin1String(
"\">") + i18nc(
"The Audit Log is a detailed error log from the gnupg backend",
"Show Audit Log") + QLatin1String(
"</a>");
2475 html += QLatin1String(
"</td><td align=\"right\" valign=\"top\" nowrap=\"nowrap\">");
2476 html += QLatin1String(
"<a href=\"kmail:hideSignatureDetails\">");
2477 html += i18n(
"Hide Details" );
2478 html += QLatin1String(
"</a></td></tr>");
2479 html += QLatin1String(
"<tr><td align=\"right\" valign=\"bottom\" nowrap=\"nowrap\">");
2481 html += QLatin1String(
"</td></tr></table>");
2486 const Kleo::CryptoBackend::Protocol * cryptProto,
2487 const QString & fromAddress,
2488 KMime::Content *node )
2490 const bool isSMIME = cryptProto && ( cryptProto == Kleo::CryptoBackendFactory::instance()->smime() );
2491 QString signer = block.
signer;
2493 QString htmlStr, simpleHtmlStr;
2494 const QString dir = QApplication::isRightToLeft() ? QLatin1String(
"rtl") : QLatin1String(
"ltr");
2495 QString cellPadding(QLatin1String(
"cellpadding=\"1\""));
2499 htmlStr += QLatin1String(
"<table cellspacing=\"1\" ")+cellPadding+QLatin1String(
" class=\"rfc822\">"
2500 "<tr class=\"rfc822H\"><td dir=\"") + dir + QLatin1String(
"\">");
2502 htmlStr += QLatin1String(
"<a href=\"") + mNodeHelper->
asHREF( node, QLatin1String(
"body") ) + QLatin1String(
"\">")
2503 + i18n(
"Encapsulated message") + QLatin1String(
"</a>");
2505 htmlStr += i18n(
"Encapsulated message");
2507 htmlStr += QLatin1String(
"</td></tr><tr class=\"rfc822B\"><td>");
2511 htmlStr += QLatin1String(
"<table cellspacing=\"1\" ")+cellPadding+QLatin1String(
" class=\"encr\">"
2512 "<tr class=\"encrH\"><td dir=\"") + dir + QLatin1String(
"\">");
2514 htmlStr += i18n(
"Please wait while the message is being decrypted...");
2516 htmlStr += i18n(
"Encrypted message");
2518 htmlStr += i18n(
"Encrypted message (decryption not possible)");
2520 htmlStr += QLatin1String(
"<br />") + i18n(
"Reason: %1", block.
errorText );
2523 htmlStr += QLatin1String(
"</td></tr><tr class=\"encrB\"><td>");
2527 block.
signClass =QLatin1String(
"signInProgress");
2528 htmlStr += QLatin1String(
"<table cellspacing=\"1\" ")+cellPadding+QLatin1String(
" class=\"signInProgress\">"
2529 "<tr class=\"signInProgressH\"><td dir=\"") + dir + QLatin1String(
"\">");
2530 htmlStr += i18n(
"Please wait while the signature is being verified...");
2531 htmlStr += QLatin1String(
"</td></tr><tr class=\"signInProgressB\"><td>");
2534 simpleHtmlStr = htmlStr;
2543 bool onlyShowKeyURL =
false;
2544 bool cannotCheckSignature =
true;
2552 if( statusStr.isEmpty() )
2553 statusStr = block.
status;
2557 switch( frameColor ){
2559 cannotCheckSignature =
false;
2562 cannotCheckSignature =
true;
2565 cannotCheckSignature =
false;
2574 QString startKeyHREF;
2575 QString keyWithWithoutURL;
2578 QString::fromLatin1(
"<a href=\"kmail:showCertificate#%1 ### %2 ### %3\">")
2579 .arg( cryptProto->displayName(),
2581 QString::fromLatin1( block.
keyId ) );
2584 QString::fromLatin1(
"%1%2</a>").arg( startKeyHREF, QString::fromLatin1(
"0x" + block.
keyId) );
2586 keyWithWithoutURL = QLatin1String(
"0x") + QString::fromUtf8( block.
keyId );
2592 showKeyInfos =
true;
2601 if( !statusStr.isEmpty() ) {
2602 statusStr.prepend(QLatin1String(
"<i>"));
2603 statusStr.append( QLatin1String(
"</i>"));
2607 switch( frameColor ) {
2609 block.
signClass = QLatin1String(
"signErr");
2610 onlyShowKeyURL =
true;
2614 block.
signClass = QLatin1String(
"signWarn");
2616 block.
signClass = QLatin1String(
"signOkKeyBad");
2619 block.
signClass = QLatin1String(
"signOkKeyOk");
2622 QString greenCaseWarning;
2623 QString msgFrom( KPIMUtils::extractEmailAddress(fromAddress) );
2624 QString certificate;
2625 if( block.
keyId.isEmpty() )
2626 certificate = i18n(
"certificate");
2628 certificate = startKeyHREF + i18n(
"certificate") + QLatin1String(
"</a>");
2629 if( !blockAddrs.empty() ){
2630 if( !blockAddrs.contains( msgFrom, Qt::CaseInsensitive ) ) {
2632 QLatin1String(
"<u>") +
2633 i18nc(
"Start of warning message."
2635 QLatin1String(
"</u> ") +
2636 i18n(
"Sender's mail address is not stored "
2637 "in the %1 used for signing.", certificate) +
2638 QLatin1String(
"<br />") +
2641 QLatin1String(
"<br />") +
2648 for(QStringList::ConstIterator it = blockAddrs.constBegin();
2649 it != blockAddrs.constEnd(); ++it ){
2651 greenCaseWarning.append(QLatin1String(
", <br /> "));
2653 greenCaseWarning.append( KPIMUtils::extractEmailAddress(*it) );
2658 QLatin1String(
"<u>") +
2659 i18nc(
"Start of warning message.",
"Warning:") +
2660 QLatin1String(
"</u> ") +
2661 i18n(
"No mail address is stored in the %1 used for signing, "
2662 "so we cannot compare it to the sender's address %2.",
2666 if( !greenCaseWarning.isEmpty() ) {
2667 if( !statusStr.isEmpty() )
2668 statusStr.append(QLatin1String(
"<br /> <br />"));
2669 statusStr.append( greenCaseWarning );
2674 QString frame = QLatin1String(
"<table cellspacing=\"1\" ")+cellPadding+QLatin1String(
" "
2675 "class=\"") + block.
signClass + QLatin1String(
"\">"
2676 "<tr class=\"") + block.
signClass + QLatin1String(
"H\"><td dir=\"") + dir + QLatin1String(
"\">");
2678 simpleHtmlStr += frame;
2683 else if( showKeyInfos ) {
2684 if( cannotCheckSignature ) {
2685 htmlStr += i18n(
"Not enough information to check "
2687 keyWithWithoutURL );
2691 if (block.
signer.isEmpty())
2694 if( !blockAddrs.empty() ){
2695 const KUrl address = KPIMUtils::encodeMailtoUrl( blockAddrs.first() );
2696 signer = QLatin1String(
"<a href=\"mailto:") + QLatin1String(KUrl::toPercentEncoding( address.path() )) +
2697 QLatin1String(
"\">") + signer + QLatin1String(
"</a>");
2701 if( block.
keyId.isEmpty() ) {
2702 if( signer.isEmpty() || onlyShowKeyURL )
2703 htmlStr += i18n(
"Message was signed with unknown key." );
2705 htmlStr += i18n(
"Message was signed by %1.",
2709 if( created.isValid() ) {
2710 if( signer.isEmpty() ) {
2711 if( onlyShowKeyURL )
2712 htmlStr += i18n(
"Message was signed with key %1.",
2713 keyWithWithoutURL );
2715 htmlStr += i18n(
"Message was signed on %1 with key %2.",
2716 KGlobal::locale()->formatDateTime( created ),
2717 keyWithWithoutURL );
2720 if( onlyShowKeyURL )
2721 htmlStr += i18n(
"Message was signed with key %1.",
2722 keyWithWithoutURL );
2724 htmlStr += i18n(
"Message was signed by %3 on %1 with key %2",
2725 KGlobal::locale()->formatDateTime( created ),
2731 if( signer.isEmpty() || onlyShowKeyURL )
2732 htmlStr += i18n(
"Message was signed with key %1.",
2733 keyWithWithoutURL );
2735 htmlStr += i18n(
"Message was signed by %2 with key %1.",
2741 htmlStr += QLatin1String(
"<br />");
2742 if( !statusStr.isEmpty() ) {
2743 htmlStr += QLatin1String(
" <br />");
2744 htmlStr += i18n(
"Status: " );
2745 htmlStr += statusStr;
2748 htmlStr += statusStr;
2750 frame = QLatin1String(
"</td></tr><tr class=\"") + block.
signClass + QLatin1String(
"B\"><td>");
2752 simpleHtmlStr += frame;
2759 block.
signClass = QLatin1String(
"signWarn");
2760 QString frame = QLatin1String(
"<table cellspacing=\"1\" ")+cellPadding+QLatin1String(
" "
2761 "class=\"") + block.
signClass + QLatin1String(
"\">"
2762 "<tr class=\"") + block.
signClass + QLatin1String(
"H\"><td dir=\"" )+ dir + QLatin1String(
"\">");
2764 simpleHtmlStr += frame;
2770 if( !block.
keyId.isEmpty() ) {
2772 if ( created.isValid() )
2773 htmlStr += i18n(
"Message was signed on %1 with unknown key %2.",
2774 KGlobal::locale()->formatDateTime( created ),
2775 keyWithWithoutURL );
2777 htmlStr += i18n(
"Message was signed with unknown key %1.",
2778 keyWithWithoutURL );
2781 htmlStr += i18n(
"Message was signed with unknown key." );
2782 htmlStr += QLatin1String(
"<br />");
2783 htmlStr += i18n(
"The validity of the signature cannot be "
2785 if( !statusStr.isEmpty() ) {
2786 htmlStr += QLatin1String(
"<br />");
2787 htmlStr += i18n(
"Status: " );
2788 htmlStr += QLatin1String(
"<i>");
2789 htmlStr += statusStr;
2790 htmlStr += QLatin1String(
"</i>");
2793 frame = QLatin1String(
"</td></tr><tr class=\"") + block.
signClass + QLatin1String(
"B\"><td>");
2795 simpleHtmlStr += frame;
2800 signer = StringUtil::quoteHtmlChars( signer,
true );
2801 signer = QLatin1String(
"<a href=\"mailto:") + signer + QLatin1String(
"\">") + signer + QLatin1String(
"</a>");
2804 if( block.
keyTrust < Kpgp::KPGP_VALIDITY_MARGINAL )
2805 block.
signClass = QLatin1String(
"signOkKeyBad");
2807 block.
signClass = QLatin1String(
"signOkKeyOk");
2808 QString frame = QLatin1String(
"<table cellspacing=\"1\" ")+cellPadding+QLatin1String(
" "
2809 "class=\"") + block.
signClass + QLatin1String(
"\">"
2810 "<tr class=\"") + block.
signClass + QLatin1String(
"H\"><td dir=\"") + dir + QLatin1String(
"\">");
2812 simpleHtmlStr += frame;
2814 if( !block.
keyId.isEmpty() )
2815 htmlStr += i18n(
"Message was signed by %2 (Key ID: %1).",
2819 htmlStr += i18n(
"Message was signed by %1.", signer );
2820 htmlStr += QLatin1String(
"<br />");
2824 case Kpgp::KPGP_VALIDITY_UNKNOWN:
2825 htmlStr += i18n(
"The signature is valid, but the key's "
2826 "validity is unknown." );
2828 case Kpgp::KPGP_VALIDITY_MARGINAL:
2829 htmlStr += i18n(
"The signature is valid and the key is "
2830 "marginally trusted." );
2832 case Kpgp::KPGP_VALIDITY_FULL:
2833 htmlStr += i18n(
"The signature is valid and the key is "
2836 case Kpgp::KPGP_VALIDITY_ULTIMATE:
2837 htmlStr += i18n(
"The signature is valid and the key is "
2838 "ultimately trusted." );
2841 htmlStr += i18n(
"The signature is valid, but the key is "
2844 frame = QLatin1String(
"</td></tr>"
2845 "<tr class=\"") + block.
signClass + QLatin1String(
"B\"><td>");
2847 simpleHtmlStr += frame;
2851 block.
signClass = QLatin1String(
"signErr");
2852 QString frame = QLatin1String(
"<table cellspacing=\"1\" ")+cellPadding+QLatin1String(
" "
2853 "class=\"") + block.
signClass + QLatin1String(
"\">"
2854 "<tr class=\"") + block.
signClass + QLatin1String(
"H\"><td dir=\"") + dir + QLatin1String(
"\">");
2856 simpleHtmlStr += frame;
2858 if( !block.
keyId.isEmpty() )
2859 htmlStr += i18n(
"Message was signed by %2 (Key ID: %1).",
2863 htmlStr += i18n(
"Message was signed by %1.", signer );
2864 htmlStr += QLatin1String(
"<br />");
2865 htmlStr += i18n(
"Warning: The signature is bad.");
2866 frame = QLatin1String(
"</td></tr>"
2867 "<tr class=\"") + block.
signClass + QLatin1String(
"B\"><td>");
2869 simpleHtmlStr += frame;
2877 return simpleHtmlStr;
2882 const QString dir = ( QApplication::isRightToLeft() ? QLatin1String(
"rtl") : QLatin1String(
"ltr") );
2887 htmlStr += QLatin1String(
"</td></tr><tr class=\"") + block.
signClass + QLatin1String(
"H\">");
2888 htmlStr += QLatin1String(
"<td dir=\"") + dir + QLatin1String(
"\">") +
2889 i18n(
"End of signed message" ) +
2890 QLatin1String(
"</td></tr></table>");
2894 htmlStr += QLatin1String(
"</td></tr><tr class=\"encrH\"><td dir=\"") + dir + QLatin1String(
"\">") +
2895 i18n(
"End of encrypted message" ) +
2896 QLatin1String(
"</td></tr></table>");
2901 htmlStr += QLatin1String(
"</td></tr><tr class=\"rfc822H\"><td dir=\"") + dir + QLatin1String(
"\">") +
2902 i18n(
"End of encapsulated message" ) +
2903 QLatin1String(
"</td></tr></table>");
2917 htmlWriter()->
queue( QString::fromLatin1(
"<div id=\"attachmentDiv%1\">\n" ).arg( node->index().toString() ) );
2934 const QString& fromAddress )
2938 writeBodyStr( aStr, aCodec, fromAddress, dummy1, dummy2,
false );
2943 const QString& fromAddress,
2948 const QString dir = ( QApplication::isRightToLeft() ? QLatin1String(
"rtl") : QLatin1String(
"ltr") );
2953 QList<Kpgp::Block> pgpBlocks;
2954 QList<QByteArray> nonPgpBlocks;
2955 if( Kpgp::Module::prepareMessageForDecryption( aStr, pgpBlocks, nonPgpBlocks ) ) {
2957 const Kleo::CryptoBackend::Protocol* cryptProto = Kleo::CryptoBackendFactory::instance()->openpgp();
2961 QString plainTextStr;
2962 bool fullySignedOrEncrypted =
true;
2964 QList<Kpgp::Block>::iterator pbit = pgpBlocks.begin();
2965 QListIterator<QByteArray> npbit( nonPgpBlocks );
2967 for( ; pbit != pgpBlocks.end(); ++pbit )
2970 QByteArray str( npbit.next() );
2971 if( !str.trimmed().isEmpty() ) {
2972 const QString text = aCodec->toUnicode( str );
2973 plainTextStr += text;
2975 htmlStr += quotedHTML( text, decorate );
2977 kDebug() <<
"Non-empty Non-OpenPGP block found: '" << str <<
"'";
2978 fullySignedOrEncrypted =
false;
2981 Kpgp::Block &block = *pbit;
2982 KMime::Content* content =
new KMime::Content;
2983 content->setBody( block.text() );
2986 std::vector<GpgME::Signature> signatures;
2987 bool passphraseError;
2994 if ( block.type() == Kpgp::PgpMessageBlock ) {
2995 QByteArray decryptedData;
2996 bool signatureFound;
2997 bool actuallyEncrypted =
true;
2998 bool decryptionStarted;
2999 bool bOkDecrypt = okDecryptMIME( *content,
3009 if ( decryptionStarted ) {
3010 writeDecryptionInProgressBlock();
3016 messagePart.
isSigned = signatureFound;
3018 text = aCodec->toUnicode( decryptedData );
3020 }
else if ( block.type() == Kpgp::ClearsignedBlock ) {
3026 messagePart.
keyTrust = Kpgp::KPGP_VALIDITY_UNKNOWN;
3027 messagePart.
status = i18n(
"Wrong Crypto Plug-In.");
3030 Kleo::VerifyOpaqueJob * job = cryptProto->verifyOpaqueJob();
3035 text = aCodec->toUnicode( m->
plainText() );
3039 messagePart.
isSigned = signatures.size() > 0;
3044 text = aCodec->toUnicode( block.text() );
3054 GpgME::Signature signature = signatures.front();
3059 messagePart.
sigSummary = signature.summary();
3063 Kleo::KeyListJob * job = cryptProto->keyListJob(
false );
3065 kDebug() <<
"The Crypto backend does not support listing keys. ";
3067 std::vector<GpgME::Key> found_keys;
3069 GpgME::KeyListResult res = job->exec( QStringList( QLatin1String(signature.fingerprint()) ),
false, found_keys );
3070 if ( res.error() ) {
3071 kDebug() <<
"Error while searching key for Fingerprint: " << signature.fingerprint();
3073 if ( found_keys.size() > 1 ) {
3075 kDebug() <<
"Oops: Found more then one Key for Fingerprint: " << signature.fingerprint();
3077 if ( found_keys.size() != 1 ) {
3079 kDebug() <<
"Oops: Found no Key for Fingerprint: " << signature.fingerprint();
3081 key = found_keys[0];
3086 if ( key.keyID() ) {
3087 messagePart.
keyId = key.keyID();
3089 if ( messagePart.
keyId.isEmpty() )
3090 messagePart.
keyId = signature.fingerprint();
3092 messagePart.
keyTrust = (Kpgp::Validity)signature.validity();
3093 if ( key.numUserIDs() > 0 && key.userID( 0 ).id() )
3094 messagePart.
signer = Kleo::DN( key.userID( 0 ).id() ).prettyDN();
3095 for ( uint iMail = 0; iMail < key.numUserIDs(); ++iMail ) {
3098 if ( key.userID( iMail ).email() ) {
3099 QString email = QString::fromUtf8( key.userID( iMail ).email() );
3102 if ( email.startsWith( QLatin1Char(
'<') ) && email.endsWith( QLatin1Char(
'>') ) )
3103 email = email.mid( 1, email.length() - 2 );
3104 if ( !email.isEmpty() )
3109 if ( signature.creationTime() )
3110 messagePart.
creationTime.setTime_t( signature.creationTime() );
3113 if ( messagePart.
signer.isEmpty() ) {
3114 if ( key.numUserIDs() > 0 && key.userID( 0 ).name() )
3115 messagePart.
signer = Kleo::DN( key.userID( 0 ).name() ).prettyDN();
3117 if ( messagePart.
signer.isEmpty() )
3125 plainTextStr += text;
3134 htmlStr += quotedHTML( text, decorate );
3145 QByteArray str( nonPgpBlocks.last() );
3146 if( !str.trimmed().isEmpty() ) {
3147 const QString text = aCodec->toUnicode( str );
3148 plainTextStr += text;
3150 htmlStr += quotedHTML( text, decorate );
3155 if( fullySignedOrEncrypted ) {
3166 mPlainTextContent = plainTextStr;
3167 mPlainTextContentCharset = aCodec->name();
3171 const QString plainText = aCodec->toUnicode( aStr );
3173 if ( mPlainTextContent.isEmpty() ) {
3174 mPlainTextContent = plainText;
3175 mPlainTextContentCharset = aCodec->name();
3185 QString ObjectTreeParser::quotedHTML(
const QString& s,
bool decorate )
3189 int convertFlags = LinkLocator::PreserveSpaces | LinkLocator::HighlightText;
3191 convertFlags |= LinkLocator::ReplaceSmileys;
3195 QString quoteFontTag[3];
3196 QString deepQuoteFontTag[3];
3197 for (
int i = 0 ; i < 3 ; ++i ) {
3201 const QString normalEndTag = QLatin1String(
"</div>");
3202 const QString quoteEnd = QLatin1String(
"</div>");
3204 const unsigned int length = s.length();
3205 bool paraIsRTL =
false;
3206 bool startNewPara =
true;
3207 unsigned int pos, beg;
3210 for ( pos = 0; pos < length && s[pos] <= QLatin1Char(
' '); pos++ )
3212 while (pos > 0 && (s[pos-1] == QLatin1Char(
' ') || s[pos-1] == QLatin1Char(
'\t'))) pos--;
3215 int currQuoteLevel = -2;
3216 bool curHidden =
false;
3221 if ( mCollapseIcon.isEmpty() ) {
3222 mCollapseIcon= LinkLocator::pngToDataUrl(
3225 if ( mExpandIcon.isEmpty() )
3226 mExpandIcon= LinkLocator::pngToDataUrl(
3233 pos = s.indexOf(QLatin1Char(
'\n'), beg, Qt::CaseInsensitive);
3234 if (pos == (
unsigned int)(-1))
3237 QString line( s.mid(beg,pos-beg) );
3241 int actQuoteLevel = -1;
3242 const int numberOfCaracters( line.length() );
3243 for (
int p=0; p<numberOfCaracters; ++p) {
3244 switch (line[p].toLatin1()) {
3254 p = numberOfCaracters;
3259 bool actHidden =
false;
3263 && mSource->
levelQuote() <= ( actQuoteLevel ) )
3266 if ( actQuoteLevel != currQuoteLevel ) {
3268 if (currQuoteLevel == -1) {
3269 htmlStr.append( normalEndTag );
3270 }
else if ( currQuoteLevel >= 0 && !curHidden ) {
3271 htmlStr.append( quoteEnd );
3275 if (actQuoteLevel == -1) {
3276 htmlStr += normalStartTag;
3283 htmlStr += QLatin1String(
"<div class=\"quotelevelmark\" >") ;
3284 htmlStr += QString::fromLatin1(
"<a href=\"kmail:levelquote?%1 \">"
3285 "<img src=\"%2\" alt=\"\" title=\"\"/></a>" )
3287 .arg( mExpandIcon );
3288 htmlStr += QLatin1String(
"</div><br/>");
3289 htmlStr += quoteEnd;
3292 htmlStr += QLatin1String(
"<div class=\"quotelevelmark\" >" );
3293 htmlStr += QString::fromLatin1(
"<a href=\"kmail:levelquote?%1 \">"
3294 "<img src=\"%2\" alt=\"\" title=\"\"/></a>" )
3296 .arg( mCollapseIcon);
3297 htmlStr += QLatin1String(
"</div>");
3298 if ( actQuoteLevel < 3 ) {
3299 htmlStr += quoteFontTag[actQuoteLevel];
3301 htmlStr += deepQuoteFontTag[actQuoteLevel%3];
3305 if ( actQuoteLevel < 3 ) {
3306 htmlStr += quoteFontTag[actQuoteLevel];
3308 htmlStr += deepQuoteFontTag[actQuoteLevel%3];
3312 currQuoteLevel = actQuoteLevel;
3314 curHidden = actHidden;
3321 if( !line.remove( QLatin1Char(
'\015') ).isEmpty() )
3324 paraIsRTL = line.isRightToLeft();
3325 htmlStr += QString::fromLatin1(
"<div dir=\"%1\">" ).arg( paraIsRTL ? QLatin1String(
"rtl") : QLatin1String(
"ltr") );
3326 htmlStr += LinkLocator::convertToHtml( line, convertFlags );
3327 htmlStr += QLatin1String(
"</div>" );
3328 startNewPara = looksLikeParaBreak( s, pos );
3332 htmlStr += QLatin1String(
"<br/>");
3334 startNewPara =
true;
3340 if (currQuoteLevel == -1) {
3341 htmlStr.append( normalEndTag );
3343 htmlStr.append( quoteEnd );
3354 const QTextCodec * ObjectTreeParser::codecFor( KMime::Content * node )
const
3359 return mNodeHelper->
codec( node );
3371 bool ObjectTreeParser::looksLikeParaBreak(
const QString& s,
unsigned int newLinePos )
const
3373 const unsigned int WRAP_COL = 78;
3375 unsigned int length = s.length();
3377 if ( newLinePos >= length-1 || newLinePos == 0 ) {
3384 unsigned prevStart = s.lastIndexOf( QLatin1Char(
'\n'), newLinePos - 1 ) + 1;
3385 unsigned prevLineLength = newLinePos - prevStart;
3386 if ( prevLineLength > WRAP_COL ) {
3391 unsigned int nextStart = newLinePos + 1;
3392 int nextEnd = s.indexOf( QLatin1Char(
'\n'), nextStart );
3393 if ( nextEnd == -1 ) {
3396 QString nextLine = s.mid( nextStart, nextEnd - nextStart );
3397 length = nextLine.length();
3399 unsigned int wordStart;
3401 for ( wordStart = 0; !found && wordStart < length; wordStart++ ) {
3402 switch ( nextLine[wordStart].toLatin1() ) {
3424 int wordEnd = nextLine.indexOf( QLatin1Char(
' '), wordStart );
3425 if ( wordEnd == (-1) ) {
3428 int wordLength = wordEnd - wordStart;
3433 return prevLineLength + wordLength + 1 < WRAP_COL;
3437 void ObjectTreeParser::dumpToFile(
const char * filename,
const char * start,
3441 QFile f( filename );
3442 if ( f.open( QIODevice::WriteOnly ) ) {
3444 QDataStream ds( &f );
3445 ds.writeRawData( start, len );
3455 if( ( !content->contentType()->isEmpty() )
3456 && ( mimeType.isEmpty() || ( mimeType == content->contentType()->mimeType() ) ) )
3458 KMime::Content *child = MessageCore::NodeHelper::firstChild( content );
3459 if ( child && deep )
3460 return findType( child, mimeType, deep, wide );
3462 KMime::Content *next = MessageCore::NodeHelper::nextSibling( content );
3464 return findType( next, mimeType, deep, wide );
3469 KMime::Content*
ObjectTreeParser::findType( KMime::Content* content,
const QByteArray& mediaType,
const QByteArray& subType,
bool deep,
bool wide )
3471 if ( !content->contentType()->isEmpty() ) {
3472 if ( ( mediaType.isEmpty() || mediaType == content->contentType()->mediaType() )
3473 && ( subType.isEmpty() || subType == content->contentType()->subType() ) )
3476 KMime::Content *child = MessageCore::NodeHelper::firstChild( content );
3477 if ( child && deep )
3478 return findType( child, mediaType, subType, deep, wide );
3480 KMime::Content *next = MessageCore::NodeHelper::nextSibling( content );
3482 return findType( next, mediaType, subType, deep, wide );
3489 if( ( !content->contentType()->isEmpty() )
3490 && ( mediaType.isEmpty() || content->contentType()->mediaType() != mediaType )
3491 && ( subType.isEmpty() || content->contentType()->subType() != subType )
3494 KMime::Content *child = MessageCore::NodeHelper::firstChild( content );
3495 if ( child && deep )
3496 return findTypeNot( child, mediaType, subType, deep, wide );
3498 KMime::Content *next = MessageCore::NodeHelper::nextSibling( content );
3500 return findTypeNot( next, mediaType, subType, deep, wide );
3507 if( plainTextContent.isEmpty() ) {
3508 #ifdef KDEPIM_NO_WEBKIT
3510 doc.setHtml( mHtmlContent );
3511 plainTextContent = doc.toPlainText();
3514 doc.mainFrame()->setHtml( mHtmlContent );
3515 plainTextContent = doc.mainFrame()->toPlainText();
3518 return plainTextContent.append(QLatin1Char(
'\n'));
3524 if( htmlContent.isEmpty() ) {
3525 QString convertedHtml = Qt::escape( mPlainTextContent );
3526 convertedHtml.append(QLatin1String(
"</body></html>"));
3527 convertedHtml.prepend(QLatin1String(
"<html><head></head><body>"));
3528 htmlContent = convertedHtml.replace( QRegExp( QLatin1String(
"\n" )), QLatin1String(
"<br />") );
3530 return htmlContent.append(QLatin1Char(
'\n'));
bool processMessageRfc822Subtype(KMime::Content *node, ProcessResult &result)
const GpgME::VerificationResult & verifyResult() const
const GpgME::VerificationResult & verifyResult() const
bool decryptChiasmus(const QByteArray &data, QByteArray &bodyDecoded, QString &errorText)
virtual bool htmlLoadExternal()=0
Return true if external sources should be loaded in a html mail.
bool showOnlyOneMimePart() const
QString nonQuotedFontTag() const
void attachExtraContent(KMime::Content *topLevelNode, KMime::Content *content)
Attach an extra node to an existing node.
void writePartIcon(KMime::Content *msgPart, bool inlineImage=false)
void writeBodyString(const QByteArray &bodyString, const QString &fromAddress, const QTextCodec *codec, ProcessResult &result, bool decorate)
an implementation of the BodyPart interface using KMime::Content's
static const BodyPartFormatter * createFor(const char *type, const char *subtype)
A multipart/alternative message, the plain text part is currently displayed.
KMime::Content * decryptedNodeForContent(KMime::Content *content) const
bool processTextPlainSubtype(KMime::Content *node, ProcessResult &result)
PartMetaData partMetaData(KMime::Content *node)
const GpgME::Key & signingKey() const
virtual QObject * sourceObject()=0
The source object behind the interface.
bool neverDisplayInline() const
bool processMultiPartEncryptedSubtype(KMime::Content *node, ProcessResult &result)
bool processMultiPartAlternativeSubtype(KMime::Content *node, ProcessResult &result)
KMMsgSignatureState
Flags for the signature state.
const GpgME::VerificationResult & verifyResult() const
QByteArray plainTextContentCharset() const
The original charset of MIME part the plain text was extracted from.
virtual Display defaultDisplay(KMime::Content *node) const =0
static const int SIG_FRAME_COL_UNDEF
QString sigStatusToString(const Kleo::CryptoBackend::Protocol *cryptProto, int status_code, GpgME::Signature::Summary summary, int &frameColor, bool &showKeyInfos)
UpdateMode
The display update mode: Force updates the display immediately, Delayed updates after some time (150m...
void setNeverDisplayInline(bool display)
void setCryptoProtocol(const Kleo::CryptoBackend::Protocol *protocol)
bool includeSignatures() const
void writeAttachmentMarkFooter()
void writeAttachmentMarkHeader(KMime::Content *node)
#define SIG_FRAME_COL_GREEN
static QString defaultToltecReplacementText()
Default text for processToltecMail(), which is used in messageviewer.kcfg, therefore it needs to be s...
static KMime::Content * findTypeNot(KMime::Content *content, const QByteArray &mediaType, const QByteArray &subType, bool deep=true, bool wide=true)
bool processApplicationOctetStreamSubtype(KMime::Content *node, ProcessResult &result)
bool keepEncryptions() const
GpgME::VerificationResult exec(Kleo::VerifyDetachedJob *job, const QByteArray &signature, const QByteArray &signedData)
QString process(const QString &htmlSource, QString &extraHead)
Do the work and add nice colors to the HTML.
bool processApplicationPkcs7MimeSubtype(KMime::Content *node, ProcessResult &result)
static IconNameCache * instance()
A QPointer which when destructed, deletes the object it points to.
void setInlineEncryptionState(KMMsgEncryptionState state)
void adjustCryptoStatesOfNode(KMime::Content *node) const
virtual bool showSignatureDetails()=0
Return true to include the signature details in the generated html.
virtual const QTextCodec * overrideCodec()=0
The override codec that should be used for the mail.
bool processApplicationChiasmusTextSubtype(KMime::Content *node, ProcessResult &result)
static GlobalSettings * self()
void writeBodyStr(const QByteArray &bodyString, const QTextCodec *aCodec, const QString &fromAddress, KMMsgSignatureState &inlineSignatureState, KMMsgEncryptionState &inlineEncryptionState, bool decorate)
QByteArray htmlContentCharset() const
QString writeSigstatFooter(PartMetaData &part)
NodeHelper * nodeHelper() const
Interface for object tree sources.
Little helper class that takes a HTML source as input and finds all lines that are quoted with '>' or...
static const BodyPartFormatterFactory * instance()
void parseObjectTree(KMime::Content *node)
Parse beginning at a given node and recursively parsing the children of that node and it's next sibli...
virtual void queue(const QString &str)=0
bool nodeProcessed(KMime::Content *node) const
bool processMultiPartMixedSubtype(KMime::Content *node, ProcessResult &result)
const QByteArray & plainText() const
const GpgME::Key & signingKey() const
KDE_DEPRECATED QByteArray rawDecryptedBody() const
The origin and purpose of this function is unknown, the ancient wisdom about it got lost during the c...
virtual void extraHead(const QString &str)=0
static const QTextCodec * codecForName(const QByteArray &_str)
Return a QTextCodec for the specified charset.
KMMsgSignatureState inlineSignatureState() const
A HTML message, non-multipart.
const AttachmentStrategy * attachmentStrategy() const
QString iconPath(const QString &name, int size) const
void setQuoteColor(unsigned int level, const QColor &color)
Sets the quote color of the specific leve.
QString asHREF(const KMime::Content *node, const QString &place)
virtual int levelQuote()=0
virtual bool process(ObjectTreeParser *, KMime::Content *, ProcessResult &) const =0
void setBodyPartMemento(KMime::Content *node, const QByteArray &which, Interface::BodyPartMemento *memento)
QString quoteFontTag(int level) const
static QString beginVerboseSigstatHeader()
QString htmlContent() const
Similar to plainTextContent(), but returns the HTML source of the first text/html MIME part...
virtual void embedPart(const QByteArray &contentId, const QString &url)=0
Embed a part with Content-ID contentId, using url url.
void setSignatureState(KMime::Content *node, const KMMsgSignatureState state)
QString writeNodeToTempFile(KMime::Content *node)
Writes the given message part to a temporary file and returns the name of this file or QString() if w...
Interface::BodyPartMemento * bodyPartMemento(KMime::Content *node, const QByteArray &which) const
QString writeSigstatHeader(PartMetaData &part, const Kleo::CryptoBackend::Protocol *cryptProto, const QString &fromAddress, KMime::Content *node=0)
static QByteArray charset(KMime::Content *node)
Returns the charset for the given node.
virtual ~ObjectTreeParser()
void setPartMetaData(KMime::Content *node, const PartMetaData &metaData)
static QString makeShowAuditLogLink(const GpgME::Error &err, const QString &auditLog)
static QString fromAsString(KMime::Content *node)
static bool isToltecMessage(KMime::Content *node)
static QString writeSimpleSigstatHeader(const PartMetaData &block)
const QByteArray & plainText() const
void setNodeDisplayedHidden(KMime::Content *node, bool displayedHidden)
void setNodeDisplayedEmbedded(KMime::Content *node, bool displayedEmbedded)
static int signatureToStatus(const GpgME::Signature &sig)
KMMsgEncryptionState inlineEncryptionState() const
HtmlWriter * htmlWriter() const
CSSHelper * cssHelper() const
const Kleo::CryptoBackend::Protocol * cryptoProtocol() const
static QString endVerboseSigstatHeader(const PartMetaData &pmd)
KMMsgEncryptionState
Flags for the encryption state.
static KMime::Content * findType(KMime::Content *content, const QByteArray &mimeType, bool deep, bool wide)
virtual const AttachmentStrategy * attachmentStrategy()=0
Return the wanted attachment startegy.
virtual bool htmlMail()=0
Return true if the mail should be parsed as a html mail.
const GpgME::DecryptionResult & decryptResult() const
bool processMultiPartDigestSubtype(KMime::Content *node, ProcessResult &result)
static QString iconName(KMime::Content *node, int size=KIconLoader::Desktop)
QString convertedTextContent() const
Returns a plain text version of the content, which is either plainTextContent() if that exists...
void setNodeUnprocessed(KMime::Content *node, bool recurse)
void setNodeProcessed(KMime::Content *node, bool recurse)
virtual QString createMessageHeader(KMime::Message *message)=0
Parses messages and generates HTML display code out of them.
const QTextCodec * codec(KMime::Content *node)
Get a QTextCodec suitable for this message part.
Helper class for synchronous execution of Kleo crypto jobs.
bool processTextHtmlSubtype(KMime::Content *node, ProcessResult &result)
void setInlineSignatureState(KMMsgSignatureState state)
bool isMailmanMessage(KMime::Content *curNode)
virtual bool decryptMessage()=0
Return true if an encrypted mail should be decrypted.
bool processMultiPartSignedSubtype(KMime::Content *node, ProcessResult &result)
QString convertedHtmlContent() const
Returns a HTML version of the plain text mail.
virtual void setHtmlMode(MessageViewer::Util::HtmlMode mode)=0
Sets the type of mail that is currently displayed.
#define SIG_FRAME_COL_RED
const QString & auditLogAsHtml() const
void setEncryptionState(KMime::Content *node, const KMMsgEncryptionState state)
static QString fileName(const KMime::Content *node)
Returns a usable filename for a node, that can be the filename from the content disposition header...
void magicSetType(KMime::Content *node, bool autoDecode=true)
Set the 'Content-Type' by mime-magic from the contents of the body.
A multipart/altervative message, the HTML part is currently displayed.
QString plainTextContent() const
The text of the message, ie.
#define SIG_FRAME_COL_YELLOW
bool processMultiPartParallelSubtype(KMime::Content *node, ProcessResult &result)
GpgME::Error auditLogError() const