35 #include "messagecomposer.h" 36 #include "kmmsgpart.h" 37 #define REALLY_WANT_KMCOMPOSEWIN_H 38 #include "kmcomposewin.h" 39 #undef REALLY_WANT_KMCOMPOSEWIN_H 40 #include "tdelistboxdialog.h" 41 #include "kcursorsaver.h" 42 #include "messagesender.h" 44 #include "kmfoldercombobox.h" 45 #include "keyresolver.h" 46 #include "kleo_util.h" 47 #include "globalsettings.h" 48 #include "custommimeheader.h" 52 #include <libkpimidentities/identity.h> 53 #include <libkpimidentities/identitymanager.h> 54 #include <libemailfunctions/email.h> 56 #include <ui/keyselectiondialog.h> 57 #include <ui/keyapprovaldialog.h> 58 #include <ui/messagebox.h> 59 #include <kleo/cryptobackendfactory.h> 60 #include <kleo/keylistjob.h> 61 #include <kleo/encryptjob.h> 62 #include <kleo/signencryptjob.h> 63 #include <kleo/signjob.h> 64 #include <kleo/specialjob.h> 66 #include <kmime_util.h> 67 #include <kmime_codecs.h> 68 #include <kpgpblock.h> 70 #include <mimelib/mimepp.h> 72 #include <tdemessagebox.h> 73 #include <tdelocale.h> 74 #include <kinputdialog.h> 76 #include <tdeaction.h> 78 #include <tqtextcodec.h> 79 #include <tqtextedit.h> 82 #include <gpgmepp/key.h> 83 #include <gpgmepp/keylistresult.h> 84 #include <gpgmepp/encryptionresult.h> 85 #include <gpgmepp/signingresult.h> 86 #include <gpgmepp/context.h> 95 static inline bool warnSendUnsigned() {
96 TDEConfigGroup group( KMKernel::config(),
"Composer" );
97 return group.readBoolEntry(
"crypto-warning-unsigned",
false );
99 static inline bool warnSendUnencrypted() {
100 TDEConfigGroup group( KMKernel::config(),
"Composer" );
101 return group.readBoolEntry(
"crypto-warning-unencrypted",
false );
103 static inline bool saveMessagesEncrypted() {
104 TDEConfigGroup group( KMKernel::config(),
"Composer" );
105 return group.readBoolEntry(
"crypto-store-encrypted",
true );
107 static inline bool encryptToSelf() {
109 TDEConfigGroup group( KMKernel::config(),
"Composer" );
110 return group.readBoolEntry(
"crypto-encrypt-to-self",
true );
112 static inline bool showKeyApprovalDialog() {
113 TDEConfigGroup group( KMKernel::config(),
"Composer" );
114 return group.readBoolEntry(
"crypto-show-keys-for-approval",
true );
117 static inline int encryptKeyNearExpiryWarningThresholdInDays() {
118 const TDEConfigGroup composer( KMKernel::config(),
"Composer" );
119 if ( ! composer.readBoolEntry(
"crypto-warn-when-near-expire",
true ) )
121 const int num = composer.readNumEntry(
"crypto-warn-encr-key-near-expire-int", 14 );
122 return kMax( 1, num );
125 static inline int signingKeyNearExpiryWarningThresholdInDays() {
126 const TDEConfigGroup composer( KMKernel::config(),
"Composer" );
127 if ( ! composer.readBoolEntry(
"crypto-warn-when-near-expire",
true ) )
129 const int num = composer.readNumEntry(
"crypto-warn-sign-key-near-expire-int", 14 );
130 return kMax( 1, num );
133 static inline int encryptRootCertNearExpiryWarningThresholdInDays() {
134 const TDEConfigGroup composer( KMKernel::config(),
"Composer" );
135 if ( ! composer.readBoolEntry(
"crypto-warn-when-near-expire",
true ) )
137 const int num = composer.readNumEntry(
"crypto-warn-encr-root-near-expire-int", 14 );
138 return kMax( 1, num );
141 static inline int signingRootCertNearExpiryWarningThresholdInDays() {
142 const TDEConfigGroup composer( KMKernel::config(),
"Composer" );
143 if ( ! composer.readBoolEntry(
"crypto-warn-when-near-expire",
true ) )
145 const int num = composer.readNumEntry(
"crypto-warn-sign-root-near-expire-int", 14 );
146 return kMax( 1, num );
149 static inline int encryptChainCertNearExpiryWarningThresholdInDays() {
150 const TDEConfigGroup composer( KMKernel::config(),
"Composer" );
151 if ( ! composer.readBoolEntry(
"crypto-warn-when-near-expire",
true ) )
153 const int num = composer.readNumEntry(
"crypto-warn-encr-chaincert-near-expire-int", 14 );
154 return kMax( 1, num );
157 static inline int signingChainCertNearExpiryWarningThresholdInDays() {
158 const TDEConfigGroup composer( KMKernel::config(),
"Composer" );
159 if ( ! composer.readBoolEntry(
"crypto-warn-when-near-expire",
true ) )
161 const int num = composer.readNumEntry(
"crypto-warn-sign-chaincert-near-expire-int", 14 );
162 return kMax( 1, num );
222 static TQString mErrorProcessingStructuringInfo =
223 i18n(
"<qt><p>Structuring information returned by the Crypto plug-in " 224 "could not be processed correctly; the plug-in might be damaged.</p>" 225 "<p>Please contact your system administrator.</p></qt>");
226 static TQString mErrorNoCryptPlugAndNoBuildIn =
227 i18n(
"<p>No active Crypto Plug-In was found and the built-in OpenPGP code " 228 "did not run successfully.</p>" 229 "<p>You can do two things to change this:</p>" 230 "<ul><li><em>either</em> activate a Plug-In using the " 231 "Settings->Configure KMail->Plug-In dialog.</li>" 232 "<li><em>or</em> specify traditional OpenPGP settings on the same dialog's " 233 "Identity->Advanced tab.</li></ul>");
236 class MessageComposerJob {
238 MessageComposerJob( MessageComposer* composer ) : mComposer( composer ) {}
239 virtual ~MessageComposerJob() {}
241 virtual void execute() = 0;
246 void adjustCryptFlags() { mComposer->adjustCryptFlags(); }
247 void composeMessage() { mComposer->composeMessage(); }
248 void continueComposeMessage(
KMMessage& msg,
bool doSign,
bool doEncrypt,
249 Kleo::CryptoMessageFormat format )
251 mComposer->continueComposeMessage( msg, doSign, doEncrypt, format );
253 void chiasmusEncryptAllAttachments() {
254 mComposer->chiasmusEncryptAllAttachments();
257 MessageComposer* mComposer;
260 class ChiasmusBodyPartEncryptJob :
public MessageComposerJob {
262 ChiasmusBodyPartEncryptJob( MessageComposer * composer )
263 : MessageComposerJob( composer ) {}
266 chiasmusEncryptAllAttachments();
270 class AdjustCryptFlagsJob :
public MessageComposerJob {
272 AdjustCryptFlagsJob( MessageComposer* composer )
273 : MessageComposerJob( composer ) {}
280 class ComposeMessageJob :
public MessageComposerJob {
282 ComposeMessageJob( MessageComposer* composer )
283 : MessageComposerJob( composer ) {}
290 MessageComposer::MessageComposer( KMComposeWin* win,
const char* name )
291 : TQObject( win, name ), mComposeWin( win ), mCurrentJob( 0 ),
292 mReferenceMessage( 0 ), mKeyResolver( 0 ),
293 mUseOpportunisticEncryption( false ),
294 mSignBody( false ), mEncryptBody( false ),
295 mSigningRequested( false ), mEncryptionRequested( false ),
296 mDoSign( false ), mDoEncrypt( false ),
297 mAllowedCryptoMessageFormats( 0 ),
298 mDisableCrypto( false ),
299 mDisableBreaking( false ),
300 mDebugComposerCrypto( false ),
301 mAutoCharset( true ),
302 mIsRichText( false ),
303 mIdentityUid( 0 ), mRc( true ),
306 mEarlyAddAttachments( false ), mAllAttachmentsAreInBody( false ),
307 mPreviousBoundaryLevel( 0 ),
308 mEncryptWithChiasmus( false ),
309 mPerformingSignOperation( false )
313 MessageComposer::~MessageComposer()
315 delete mKeyResolver; mKeyResolver = 0;
316 delete mNewBodyPart; mNewBodyPart = 0;
319 void MessageComposer::applyChanges(
bool disableCrypto )
322 if( getenv(
"KMAIL_DEBUG_COMPOSER_CRYPTO") != 0 ) {
323 TQCString cE = getenv(
"KMAIL_DEBUG_COMPOSER_CRYPTO");
324 mDebugComposerCrypto = cE ==
"1" || cE.upper() ==
"ON" || cE.upper() ==
"TRUE";
325 kdDebug(5006) <<
"KMAIL_DEBUG_COMPOSER_CRYPTO = TRUE" << endl;
327 mDebugComposerCrypto =
false;
328 kdDebug(5006) <<
"KMAIL_DEBUG_COMPOSER_CRYPTO = FALSE" << endl;
334 mDisableCrypto = disableCrypto;
338 readFromComposeWin();
343 mJobs.push_back(
new ChiasmusBodyPartEncryptJob(
this ) );
346 mJobs.push_back(
new AdjustCryptFlagsJob(
this ) );
349 mJobs.push_back(
new ComposeMessageJob(
this ) );
355 void MessageComposer::doNextJob()
357 delete mCurrentJob; mCurrentJob = 0;
359 if( mJobs.isEmpty() ) {
367 while( !mJobs.isEmpty() ) {
368 delete mJobs.front();
376 TQTimer::singleShot( 0,
this, TQT_SLOT( slotDoNextJob() ) );
379 void MessageComposer::emitDone(
bool b )
382 mEncodedBody = TQByteArray();
383 delete mNewBodyPart; mNewBodyPart = 0;
384 mOldBodyPart.clear();
388 void MessageComposer::slotDoNextJob()
390 assert( !mCurrentJob );
396 assert( !mJobs.empty() );
398 mCurrentJob = mJobs.front();
399 assert( mCurrentJob );
403 mCurrentJob->execute();
411 void MessageComposer::readFromComposeWin()
414 mDisableBreaking =
false;
416 mSignBody = mComposeWin->mSignAction->isChecked();
417 mSigningRequested = mSignBody;
418 mEncryptBody = mComposeWin->mEncryptAction->isChecked();
419 mEncryptionRequested = mEncryptBody;
421 mAutoCharset = mComposeWin->mAutoCharset;
422 mCharset = mComposeWin->mCharset;
423 mReferenceMessage = mComposeWin->mMsg;
435 if ( mReferenceMessage->type() == DwMime::kTypeMultipart )
436 mReferenceMessage->setHeaderField(
"Content-Type",
"text/plain" );
437 mUseOpportunisticEncryption = GlobalSettings::self()->pgpAutoEncrypt();
438 mAllowedCryptoMessageFormats = mComposeWin->cryptoMessageFormat();
442 if( charset.isEmpty() )
444 KMessageBox::sorry( mComposeWin,
445 i18n(
"No suitable encoding could be found for " 446 "your message.\nPlease set an encoding " 447 "using the 'Options' menu." ) );
453 mComposeWin->mCharset = charset;
455 mReferenceMessage->setCharset(mCharset);
457 mReferenceMessage->setTo(mComposeWin->to());
458 mReferenceMessage->setFrom(mComposeWin->from());
459 mReferenceMessage->setCc(mComposeWin->cc());
460 mReferenceMessage->setSubject(mComposeWin->subject());
461 mReferenceMessage->setReplyTo(mComposeWin->replyTo());
462 mReferenceMessage->setBcc(mComposeWin->bcc());
464 const KPIM::Identity &
id = mComposeWin->identity();
466 KMFolder *f = mComposeWin->mFcc->getFolder();
469 mReferenceMessage->removeHeaderField(
"X-KMail-Fcc");
471 mReferenceMessage->setFcc( f->
idString() );
474 mReferenceMessage->setDrafts(
id.drafts() );
477 mReferenceMessage->removeHeaderField(
"X-KMail-Identity");
478 else mReferenceMessage->setHeaderField(
"X-KMail-Identity", TQString::number(
id.uoid() ));
481 if (!mComposeWin->replyTo().isEmpty()) replyAddr = mComposeWin->replyTo();
482 else replyAddr = mComposeWin->from();
484 if (mComposeWin->mRequestMDNAction->isChecked())
485 mReferenceMessage->setHeaderField(
"Disposition-Notification-To", replyAddr);
487 mReferenceMessage->removeHeaderField(
"Disposition-Notification-To");
489 if (mComposeWin->mUrgentAction->isChecked()) {
490 mReferenceMessage->setHeaderField(
"X-PRIORITY",
"2 (High)");
491 mReferenceMessage->setHeaderField(
"Priority",
"urgent");
493 mReferenceMessage->removeHeaderField(
"X-PRIORITY");
494 mReferenceMessage->removeHeaderField(
"Priority");
497 int num = GlobalSettings::self()->custHeaderCount();
498 for(
int ix=0; ix<num; ix++) {
499 CustomMimeHeader customMimeHeader( TQString::number(ix) );
500 customMimeHeader.readConfig();
501 mReferenceMessage->setHeaderField(
502 KMMsgBase::toUsAscii( customMimeHeader.custHeaderName() ),
503 customMimeHeader.custHeaderValue() );
512 mBcc = mComposeWin->bcc();
513 mTo = KPIM::splitEmailAddrList( mComposeWin->to().stripWhiteSpace() );
514 mCc = KPIM::splitEmailAddrList( mComposeWin->cc().stripWhiteSpace() );
515 mBccList = KPIM::splitEmailAddrList( mBcc.stripWhiteSpace() );
517 for (
unsigned int i = 0 ; i < mComposeWin->mAtmList.count() ; ++i )
518 mAttachments.push_back( Attachment( mComposeWin->mAtmList.at(i),
519 mComposeWin->signFlagOfAttachment( i ),
520 mComposeWin->encryptFlagOfAttachment( i ) ) );
522 mEncryptWithChiasmus = mComposeWin->mEncryptWithChiasmus;
524 mIsRichText = mComposeWin->mEditor->textFormat() == TQt::RichText;
525 mIdentityUid = mComposeWin->identityUid();
526 mText = breakLinesAndApplyCodec();
527 assert( mText.isEmpty() || mText[mText.size()-1] ==
'\n' );
531 mLineBreakColumn = mComposeWin->mEditor->lineBreakColumn();
534 static TQCString escape_quoted_string(
const TQCString & str ) {
536 const unsigned int str_len = str.length();
537 result.resize( 2*str_len + 1 );
538 char * d = result.data();
539 for (
unsigned int i = 0 ; i < str_len ; ++i )
540 switch (
const char ch = str[i] ) {
547 result.truncate( d - result.begin() );
551 bool MessageComposer::encryptWithChiasmus(
const Kleo::CryptoBackend::Protocol * chiasmus,
552 const TQByteArray& body,
553 TQByteArray& resultData )
555 std::auto_ptr<Kleo::SpecialJob> job( chiasmus->specialJob(
"x-encrypt", TQMap<TQString,TQVariant>() ) );
557 const TQString msg = i18n(
"Chiasmus backend does not offer the " 558 "\"x-encrypt\" function. Please report this bug." );
559 KMessageBox::error( mComposeWin, msg, i18n(
"Chiasmus Backend Error" ) );
562 if ( !job->setProperty(
"key", GlobalSettings::chiasmusKey() ) ||
563 !job->setProperty(
"options", GlobalSettings::chiasmusOptions() ) ||
564 !job->setProperty(
"input", body ) ) {
565 const TQString msg = i18n(
"The \"x-encrypt\" function does not accept " 566 "the expected parameters. Please report this bug." );
567 KMessageBox::error( mComposeWin, msg, i18n(
"Chiasmus Backend Error" ) );
570 const GpgME::Error err = job->exec();
571 if ( err.isCanceled() || err ) {
573 job->showErrorDialog( mComposeWin, i18n(
"Chiasmus Encryption Error" ) );
576 const TQVariant result = job->property(
"result" );
577 if ( result.type() != TQVariant::ByteArray ) {
578 const TQString msg = i18n(
"Unexpected return value from Chiasmus backend: " 579 "The \"x-encrypt\" function did not return a " 580 "byte array. Please report this bug." );
581 KMessageBox::error( mComposeWin, msg, i18n(
"Chiasmus Backend Error" ) );
584 resultData = result.toByteArray();
588 void MessageComposer::chiasmusEncryptAllAttachments() {
589 if ( !mEncryptWithChiasmus )
591 assert( !GlobalSettings::chiasmusKey().isEmpty() );
592 if ( mAttachments.empty() )
594 const Kleo::CryptoBackend::Protocol * chiasmus
595 = Kleo::CryptoBackendFactory::instance()->protocol(
"Chiasmus" );
599 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin(), end = mAttachments.end() ; it != end ; ++it ) {
600 KMMessagePart * part = it->part;
601 const TQString filename = part->fileName();
602 if ( filename.endsWith(
".xia",
false ) )
604 const TQByteArray body = part->bodyDecodedBinary();
605 TQByteArray resultData;
606 if ( !encryptWithChiasmus( chiasmus, body, resultData ) ) {
611 TQValueList<int> dummy;
612 part->setBodyAndGuessCte( resultData, dummy );
613 part->setTypeStr(
"application" );
614 part->setSubtypeStr(
"vnd.de.bund.bsi.chiasmus" );
615 part->setName( filename +
".xia" );
616 const TQCString enc_name = KMMsgBase::encodeRFC2231StringAutoDetectCharset(
617 filename +
".xia", part->charset() );
618 const TQCString cDisp =
"attachment;\n\tfilename" 619 + ( TQString( enc_name ) != filename +
".xia" 621 :
"=\"" + escape_quoted_string( enc_name ) +
'\"' );
622 part->setContentDisposition( cDisp );
626 void MessageComposer::adjustCryptFlags()
628 if ( !mDisableCrypto &&
629 mAllowedCryptoMessageFormats & Kleo::InlineOpenPGPFormat &&
630 !mAttachments.empty() &&
631 ( mSigningRequested || mEncryptionRequested ) )
634 if ( mAllowedCryptoMessageFormats == Kleo::InlineOpenPGPFormat ) {
635 ret = KMessageBox::warningYesNoCancel( mComposeWin,
636 i18n(
"The inline OpenPGP crypto message format " 637 "does not support encryption or signing " 639 "Really use deprecated inline OpenPGP?"),
640 i18n(
"Insecure Message Format"),
641 i18n(
"Use Inline OpenPGP"),
642 i18n(
"Use OpenPGP/MIME") );
647 ret = KMessageBox::No;
650 if ( ret == KMessageBox::Cancel ) {
653 }
else if ( ret == KMessageBox::No ) {
654 mAllowedCryptoMessageFormats &= ~
Kleo::InlineOpenPGPFormat;
655 mAllowedCryptoMessageFormats |= Kleo::OpenPGPMIMEFormat;
656 if ( mSigningRequested ) {
658 for (
unsigned int idx = 0 ; idx < mAttachments.size() ; ++idx )
659 mAttachments[idx].sign =
true;
661 if ( mEncryptionRequested ) {
664 for (
unsigned int idx = 0 ; idx < mAttachments.size() ; ++idx )
665 mAttachments[idx].encrypt =
true;
672 mUseOpportunisticEncryption, mAllowedCryptoMessageFormats,
673 encryptKeyNearExpiryWarningThresholdInDays(),
674 signingKeyNearExpiryWarningThresholdInDays(),
675 encryptRootCertNearExpiryWarningThresholdInDays(),
676 signingRootCertNearExpiryWarningThresholdInDays(),
677 encryptChainCertNearExpiryWarningThresholdInDays(),
678 signingChainCertNearExpiryWarningThresholdInDays() );
680 if ( !mDisableCrypto ) {
681 const KPIM::Identity &
id =
682 kmkernel->identityManager()->identityForUoidOrDefault( mIdentityUid );
684 TQStringList encryptToSelfKeys;
685 if ( !
id.pgpEncryptionKey().isEmpty() )
686 encryptToSelfKeys.push_back(
id.pgpEncryptionKey() );
687 if ( !
id.smimeEncryptionKey().isEmpty() )
688 encryptToSelfKeys.push_back(
id.smimeEncryptionKey() );
689 if ( mKeyResolver->setEncryptToSelfKeys( encryptToSelfKeys ) != Kpgp::Ok ) {
694 TQStringList signKeys;
695 if ( !
id.pgpSigningKey().isEmpty() )
696 signKeys.push_back( mPGPSigningKey =
id.pgpSigningKey() );
697 if ( !
id.smimeSigningKey().isEmpty() )
698 signKeys.push_back( mSMIMESigningKey =
id.smimeSigningKey() );
699 if ( mKeyResolver->setSigningKeys( signKeys ) != Kpgp::Ok ) {
705 mKeyResolver->setPrimaryRecipients( mTo + mCc );
706 mKeyResolver->setSecondaryRecipients( mBccList );
709 bool doSignCompletely = mSigningRequested;
710 bool doEncryptCompletely = mEncryptionRequested;
711 for (
unsigned int idx = 0 ; idx < mAttachments.size() ; ++idx ) {
712 if ( mAttachments[idx].encrypt )
713 mEncryptionRequested =
true;
715 doEncryptCompletely =
false;
716 if ( mAttachments[idx].sign )
717 mSigningRequested =
true;
719 doSignCompletely =
false;
722 mDoSign = !mDisableCrypto && determineWhetherToSign( doSignCompletely );
727 mDoEncrypt = !mDisableCrypto && determineWhetherToEncrypt( doEncryptCompletely );
735 if ( mKeyResolver->resolveAllKeys( mDoSign, mDoEncrypt ) != Kpgp::Ok )
739 bool MessageComposer::determineWhetherToSign(
bool doSignCompletely ) {
741 switch ( mKeyResolver->checkSigningPreferences( mSigningRequested ) ) {
743 if ( !mSigningRequested ) {
744 markAllAttachmentsForSigning(
true );
752 case Kleo::AskOpportunistic:
758 const TQString msg = i18n(
"Examination of the recipient's signing preferences " 759 "yielded that you be asked whether or not to sign " 761 "Sign this message?");
762 switch ( KMessageBox::questionYesNoCancel( mComposeWin, msg,
763 i18n(
"Sign Message?"),
764 i18n(
"to sign",
"&Sign"),
765 i18n(
"Do &Not Sign") ) ) {
766 case KMessageBox::Cancel:
769 case KMessageBox::Yes:
770 markAllAttachmentsForSigning(
true );
772 case KMessageBox::No:
773 markAllAttachmentsForSigning(
false );
782 const TQString msg = i18n(
"There are conflicting signing preferences " 783 "for these recipients.\n" 784 "Sign this message?");
785 switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
786 i18n(
"Sign Message?"),
787 i18n(
"to sign",
"&Sign"),
788 i18n(
"Do &Not Sign") ) ) {
789 case KMessageBox::Cancel:
792 case KMessageBox::Yes:
793 markAllAttachmentsForSigning(
true );
795 case KMessageBox::No:
796 markAllAttachmentsForSigning(
false );
801 case Kleo::Impossible:
804 const TQString msg = i18n(
"You have requested to sign this message, " 805 "but no valid signing keys have been configured " 806 "for this identity.");
807 if ( KMessageBox::warningContinueCancel( mComposeWin, msg,
808 i18n(
"Send Unsigned?"),
809 i18n(
"Send &Unsigned") )
810 == KMessageBox::Cancel ) {
814 markAllAttachmentsForSigning(
false );
820 if ( !sign || !doSignCompletely ) {
821 if ( warnSendUnsigned() ) {
823 const TQString msg = sign && !doSignCompletely
824 ? i18n(
"Some parts of this message will not be signed.\n" 825 "Sending only partially signed messages might violate site policy.\n" 826 "Sign all parts instead?")
827 : i18n(
"This message will not be signed.\n" 828 "Sending unsigned message might violate site policy.\n" 829 "Sign message instead?") ;
830 const TQString buttonText = sign && !doSignCompletely
831 ? i18n(
"&Sign All Parts") : i18n(
"&Sign") ;
832 switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
833 i18n(
"Unsigned-Message Warning"),
835 i18n(
"Send &As Is") ) ) {
836 case KMessageBox::Cancel:
839 case KMessageBox::Yes:
840 markAllAttachmentsForSigning(
true );
842 case KMessageBox::No:
843 return sign || doSignCompletely;
848 return sign || doSignCompletely ;
851 bool MessageComposer::determineWhetherToEncrypt(
bool doEncryptCompletely ) {
852 bool encrypt =
false;
853 bool opportunistic =
false;
854 switch ( mKeyResolver->checkEncryptionPreferences( mEncryptionRequested ) ) {
856 if ( !mEncryptionRequested ) {
857 markAllAttachmentsForEncryption(
true );
865 case Kleo::AskOpportunistic:
866 opportunistic =
true;
872 const TQString msg = opportunistic
873 ? i18n(
"Valid trusted encryption keys were found for all recipients.\n" 874 "Encrypt this message?")
875 : i18n(
"Examination of the recipient's encryption preferences " 876 "yielded that you be asked whether or not to encrypt " 878 "Encrypt this message?");
879 switch ( KMessageBox::questionYesNoCancel( mComposeWin, msg,
880 i18n(
"Encrypt Message?"),
882 ? i18n(
"Sign && &Encrypt")
886 : i18n(
"&Send As-Is") ) ) {
887 case KMessageBox::Cancel:
890 case KMessageBox::Yes:
891 markAllAttachmentsForEncryption(
true );
893 case KMessageBox::No:
894 markAllAttachmentsForEncryption(
false );
903 const TQString msg = i18n(
"There are conflicting encryption preferences " 904 "for these recipients.\n" 905 "Encrypt this message?");
906 switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
907 i18n(
"Encrypt Message?"),
909 i18n(
"Do &Not Encrypt") ) ) {
910 case KMessageBox::Cancel:
913 case KMessageBox::Yes:
914 markAllAttachmentsForEncryption(
true );
916 case KMessageBox::No:
917 markAllAttachmentsForEncryption(
false );
922 case Kleo::Impossible:
925 const TQString msg = i18n(
"You have requested to encrypt this message, " 926 "and to encrypt a copy to yourself, " 927 "but no valid trusted encryption keys have been " 928 "configured for this identity.");
929 if ( KMessageBox::warningContinueCancel( mComposeWin, msg,
930 i18n(
"Send Unencrypted?"),
931 i18n(
"Send &Unencrypted") )
932 == KMessageBox::Cancel ) {
936 markAllAttachmentsForEncryption(
false );
942 if ( !encrypt || !doEncryptCompletely ) {
943 if ( warnSendUnencrypted() ) {
945 const TQString msg = !doEncryptCompletely
946 ? i18n(
"Some parts of this message will not be encrypted.\n" 947 "Sending only partially encrypted messages might violate site policy " 948 "and/or leak sensitive information.\n" 949 "Encrypt all parts instead?")
950 : i18n(
"This message will not be encrypted.\n" 951 "Sending unencrypted messages might violate site policy and/or " 952 "leak sensitive information.\n" 953 "Encrypt messages instead?") ;
954 const TQString buttonText = !doEncryptCompletely
955 ? i18n(
"&Encrypt All Parts") : i18n(
"&Encrypt") ;
956 switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
957 i18n(
"Unencrypted Message Warning"),
961 : i18n(
"&Send As-Is") ) ) {
962 case KMessageBox::Cancel:
965 case KMessageBox::Yes:
966 markAllAttachmentsForEncryption(
true );
968 case KMessageBox::No:
969 return encrypt || doEncryptCompletely;
974 return encrypt || doEncryptCompletely ;
977 void MessageComposer::markAllAttachmentsForSigning(
bool sign ) {
979 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it )
983 void MessageComposer::markAllAttachmentsForEncryption(
bool enc ) {
985 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it )
990 void MessageComposer::composeMessage()
992 for (
unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
993 if ( mKeyResolver->encryptionItems( concreteCryptoMessageFormats[i] ).empty() )
996 composeMessage( *msg, mDoSign, mDoEncrypt, concreteCryptoMessageFormats[i] );
1007 static inline bool makeMultiMime( Kleo::CryptoMessageFormat f,
bool sign ) {
1010 case Kleo::InlineOpenPGPFormat:
1011 case Kleo::SMIMEOpaqueFormat:
return false;
1012 case Kleo::OpenPGPMIMEFormat:
return true;
1013 case Kleo::SMIMEFormat:
return sign;
1016 static inline bool makeMultiPartSigned( Kleo::CryptoMessageFormat f ) {
1017 return makeMultiMime( f,
true );
1019 static inline bool makeMultiPartEncrypted( Kleo::CryptoMessageFormat f ) {
1020 return makeMultiMime( f,
false );
1023 static inline bool makeMimeObject( Kleo::CryptoMessageFormat f,
bool ) {
1024 return f != Kleo::InlineOpenPGPFormat;
1027 static inline const char * toplevelContentType( Kleo::CryptoMessageFormat f,
bool signing ) {
1030 case Kleo::InlineOpenPGPFormat:
return 0;
1031 case Kleo::OpenPGPMIMEFormat:
1033 "multipart/signed;\n\t" 1034 "boundary=\"%boundary\";\n\t" 1035 "protocol=\"application/pgp-signature\";\n\t" 1038 "multipart/encrypted;\n\t" 1039 "boundary=\"%boundary\";\n\t" 1040 "protocol=\"application/pgp-encrypted\"" 1042 case Kleo::SMIMEFormat:
1045 "multipart/signed;\n\t" 1046 "boundary=\"%boundary\";\n\t" 1047 "protocol=\"application/pkcs7-signature\";\n\t" 1052 case Kleo::SMIMEOpaqueFormat:
1054 "application/pkcs7-mime;\n\t" 1055 "smime-type=signed-data;\n\t" 1056 "name=\"smime.p7m\";\n\t" 1058 "application/pkcs7-mime;\n\t" 1059 "smime-type=enveloped-data;\n\t" 1060 "name=\"smime.p7m\";\n\t" 1065 static inline const char * toplevelContentDisposition( Kleo::CryptoMessageFormat f,
bool signing ) {
1068 case Kleo::InlineOpenPGPFormat:
1069 case Kleo::OpenPGPMIMEFormat:
1071 case Kleo::SMIMEFormat:
1074 case Kleo::SMIMEOpaqueFormat:
1075 return "attachment; filename=\"smime.p7m\"";
1079 static inline bool includeCleartextWhenSigning( Kleo::CryptoMessageFormat f ) {
1080 return makeMultiPartSigned( f );
1083 static inline const char * nestedContentType( Kleo::CryptoMessageFormat f,
bool signing ) {
1085 case Kleo::OpenPGPMIMEFormat:
1086 return signing ?
"application/pgp-signature; name=signature.asc \nContent-Description: This is a digitally signed message part." :
"application/octet-stream" ;
1087 case Kleo::SMIMEFormat:
1089 return "application/pkcs7-signature; name=\"smime.p7s\"";
1092 case Kleo::InlineOpenPGPFormat:
1093 case Kleo::SMIMEOpaqueFormat:
1098 static inline const char * nestedContentDisposition( Kleo::CryptoMessageFormat f,
bool signing ) {
1099 if ( !signing && f == Kleo::OpenPGPMIMEFormat )
1100 return "inline; filename=\"msg.asc\"";
1101 if ( signing && f == Kleo::SMIMEFormat )
1102 return "attachment; filename=\"smime.p7s\"";
1106 static inline bool binaryHint( Kleo::CryptoMessageFormat f ) {
1108 case Kleo::SMIMEFormat:
1109 case Kleo::SMIMEOpaqueFormat:
1112 case Kleo::OpenPGPMIMEFormat:
1113 case Kleo::InlineOpenPGPFormat:
1118 static inline bool armor( Kleo::CryptoMessageFormat f ) {
1119 return !binaryHint( f );
1122 static inline bool textMode( Kleo::CryptoMessageFormat f ) {
1123 return f == Kleo::InlineOpenPGPFormat;
1126 static inline GpgME::Context::SignatureMode signingMode( Kleo::CryptoMessageFormat f ) {
1128 case Kleo::SMIMEOpaqueFormat:
1129 return GpgME::Context::Normal;
1130 case Kleo::InlineOpenPGPFormat:
1131 return GpgME::Context::Clearsigned;
1133 case Kleo::SMIMEFormat:
1134 case Kleo::OpenPGPMIMEFormat:
1135 return GpgME::Context::Detached;
1143 class EncryptMessageJob :
public MessageComposerJob {
1145 EncryptMessageJob(
KMMessage* msg,
const Kleo::KeyResolver::SplitInfo & si,
1146 bool doSign,
bool doEncrypt,
const TQByteArray& encodedBody,
1148 KMMessagePart* newBodyPart, Kleo::CryptoMessageFormat format,
1149 MessageComposer* composer )
1150 : MessageComposerJob( composer ), mMsg( msg ), mSplitInfo( si ),
1151 mDoSign( doSign ), mDoEncrypt( doEncrypt ), mEncodedBody( encodedBody ),
1152 mBoundaryLevel( boundaryLevel ),
1153 mNewBodyPart( newBodyPart ), mFormat( format ) {}
1156 KMMessagePart tmpNewBodyPart;
1157 tmpNewBodyPart.duplicate( *mNewBodyPart );
1161 mComposer->encryptMessage( mMsg, mSplitInfo, mDoSign, mDoEncrypt,
1162 tmpNewBodyPart, mFormat );
1163 if ( !mComposer->mRc ) {
1164 delete mMsg; mMsg = 0;
1167 mComposer->mMessageList.push_back( mMsg );
1172 Kleo::KeyResolver::SplitInfo mSplitInfo;
1173 bool mDoSign, mDoEncrypt;
1174 TQByteArray mEncodedBody;
1177 KMMessagePart* mNewBodyPart;
1178 Kleo::CryptoMessageFormat mFormat;
1181 class SetLastMessageAsUnencryptedVersionOfLastButOne :
public MessageComposerJob {
1183 SetLastMessageAsUnencryptedVersionOfLastButOne( MessageComposer * composer )
1184 : MessageComposerJob( composer ) {}
1187 KMMessage * last = mComposer->mMessageList.back();
1188 mComposer->mMessageList.pop_back();
1193 void MessageComposer::composeInlineOpenPGPMessage(
KMMessage& theMessage,
1194 bool doSign,
bool doEncrypt )
1197 const TQByteArray bodyData = mText;
1198 if (bodyData.isNull()) {
1204 mEarlyAddAttachments =
false;
1205 mAllAttachmentsAreInBody =
false;
1209 TQString oldContentType = theMessage.
headerField(
"Content-Type" );
1213 const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
1214 = mKeyResolver->encryptionItems( Kleo::InlineOpenPGPFormat );
1215 kdWarning( splitInfos.empty() )
1216 <<
"MessageComposer::continueComposeMessage(): splitInfos.empty() for InlineOpenPGPFormat" 1218 std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it;
1219 for ( it = splitInfos.begin() ; it != splitInfos.end() ; ++it ) {
1220 const Kleo::KeyResolver::SplitInfo& splitInfo = *it;
1223 Kpgp::Result result;
1224 TQByteArray encryptedBody;
1226 const std::vector<GpgME::Key> signingKeys = mKeyResolver->signingKeys( Kleo::InlineOpenPGPFormat );
1227 result = pgpSignedAndEncryptedMsg( encryptedBody, bodyData, signingKeys,
1228 splitInfo.keys, Kleo::InlineOpenPGPFormat );
1230 result = pgpEncryptedMsg( encryptedBody, bodyData,
1231 splitInfo.keys, Kleo::InlineOpenPGPFormat );
1233 if ( result != Kpgp::Ok ) {
1237 assert( !encryptedBody.isNull() );
1238 mOldBodyPart.setBodyEncodedBinary( encryptedBody );
1241 pgpSignedMsg( bodyData, Kleo::InlineOpenPGPFormat );
1242 if ( mSignature.isNull() ) {
1246 mOldBodyPart.setBodyEncodedBinary( mSignature );
1248 assert( !bodyData.isNull() );
1249 mOldBodyPart.setBodyEncodedBinary( bodyData );
1252 mOldBodyPart.setContentDisposition(
"inline" );
1253 mOldBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
1254 mOldBodyPart.setCharset(mCharset);
1255 addBodyAndAttachments( msg, splitInfo,
false,
false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
1256 mMessageList.push_back( msg );
1257 if ( it == splitInfos.begin() ) {
1258 if ( doEncrypt && !saveMessagesEncrypted() ) {
1259 mOldBodyPart.setBodyEncodedBinary( bodyData );
1261 addBodyAndAttachments( msgUnenc, splitInfo,
false,
false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
1269 void MessageComposer::composeChiasmusMessage(
KMMessage& theMessage, Kleo::CryptoMessageFormat format )
1271 assert( !GlobalSettings::chiasmusKey().isEmpty() );
1272 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
1274 const Kleo::CryptoBackend::Protocol * chiasmus
1275 = cpf->protocol(
"Chiasmus" );
1279 const TQByteArray bodyData = mText;
1280 if (bodyData.isNull()) {
1286 mEarlyAddAttachments =
false;
1287 mAllAttachmentsAreInBody =
false;
1291 TQString oldContentType = theMessage.
headerField(
"Content-Type" );
1297 const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
1298 = mKeyResolver->encryptionItems( format );
1299 assert( splitInfos.size() == 1 );
1300 for ( std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it = splitInfos.begin() ; it != splitInfos.end() ; ++it )
1302 const Kleo::KeyResolver::SplitInfo& splitInfo = *it;
1304 TQByteArray encryptedBody;
1306 if ( !encryptWithChiasmus( chiasmus, bodyData, encryptedBody ) ) {
1310 assert( !encryptedBody.isNull() );
1314 bool doSign =
false;
1315 TQValueList<int> allowedCTEs;
1316 mOldBodyPart.setBodyAndGuessCte( encryptedBody, allowedCTEs,
1317 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
1321 mOldBodyPart.setContentDisposition(
"inline" );
1323 mOldBodyPart.setOriginalContentTypeStr(
"application/vnd.de.bund.bsi.chiasmus-text;chiasmus-charset=" + mCharset );
1325 mOldBodyPart.setTypeStr(
"application" );
1326 mOldBodyPart.setSubtypeStr(
"vnd.de.bund.bsi.chiasmus-text" );
1327 mOldBodyPart.setAdditionalCTypeParamStr( TQCString(
"chiasmus-charset=" + mCharset ) );
1328 addBodyAndAttachments( msg, splitInfo,
false,
false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
1329 mMessageList.push_back( msg );
1331 if ( it == splitInfos.begin() && !saveMessagesEncrypted() ) {
1332 mOldBodyPart.setBodyEncodedBinary( bodyData );
1334 addBodyAndAttachments( msgUnenc, splitInfo,
false,
false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
1340 void MessageComposer::composeMessage(
KMMessage& theMessage,
1341 bool doSign,
bool doEncrypt,
1342 Kleo::CryptoMessageFormat format )
1345 kdDebug(5006) <<
"entering KMComposeWin::composeMessage" << endl;
1347 if ( format == Kleo::InlineOpenPGPFormat ) {
1348 composeInlineOpenPGPMessage( theMessage, doSign, doEncrypt );
1352 if ( mEncryptWithChiasmus )
1354 composeChiasmusMessage( theMessage, format );
1360 theMessage.
setBody(
"This message is in MIME format." );
1363 TQByteArray bodyData = mText;
1364 if (bodyData.isNull()) {
1370 TQString oldContentType = theMessage.
headerField(
"Content-Type" );
1377 mNewBodyPart =
new KMMessagePart;
1380 mPreviousBoundaryLevel = 0;
1383 const bool doEncryptBody = doEncrypt && mEncryptBody;
1384 const bool doSignBody = doSign && mSignBody;
1388 mEarlyAddAttachments = !mAttachments.empty() && ( doSignBody || doEncryptBody );
1390 mAllAttachmentsAreInBody = mEarlyAddAttachments;
1393 if( mEarlyAddAttachments ) {
1394 bool someOk =
false;
1395 for ( TQValueVector<Attachment>::const_iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
1396 if ( it->encrypt == doEncryptBody && it->sign == doSignBody )
1399 mAllAttachmentsAreInBody =
false;
1401 if( !mAllAttachmentsAreInBody && !someOk )
1402 mEarlyAddAttachments =
false;
1405 kdDebug(5006) <<
"mEarlyAddAttachments=" << mEarlyAddAttachments <<
" mAllAttachmentsAreInBody=" << mAllAttachmentsAreInBody << endl;
1408 mMultipartMixedBoundary =
"";
1409 if ( mEarlyAddAttachments ) {
1410 mOldBodyPart.setTypeStr(
"multipart" );
1411 mOldBodyPart.setSubtypeStr(
"mixed" );
1414 tmpCT.CreateBoundary( ++mPreviousBoundaryLevel );
1415 mMultipartMixedBoundary = tmpCT.Boundary().c_str();
1417 else if ( mIsRichText ) {
1418 mOldBodyPart.setTypeStr(
"multipart" );
1419 mOldBodyPart.setSubtypeStr(
"alternative" );
1422 mOldBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
1424 mOldBodyPart.setContentDisposition(
"inline" );
1426 if ( mIsRichText ) {
1428 TQCString boundaryCStr;
1431 tmpCT.CreateBoundary( ++mPreviousBoundaryLevel );
1433 TQValueList<int> allowedCTEs;
1435 KMMessagePart textBodyPart;
1436 textBodyPart.setTypeStr(
"text");
1437 textBodyPart.setSubtypeStr(
"plain");
1439 TQCString textbody = plainTextFromMarkup( mText );
1442 textBodyPart.setBodyAndGuessCte( textbody, allowedCTEs,
1443 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
1445 textBodyPart.setCharset( mCharset );
1446 textBodyPart.setBodyEncoded( textbody );
1448 textDwPart->Assemble();
1450 newbody += boundaryCStr;
1452 newbody += textDwPart->AsString().c_str();
1456 KMMessagePart htmlBodyPart;
1457 htmlBodyPart.setTypeStr(
"text");
1458 htmlBodyPart.setSubtypeStr(
"html");
1459 TQByteArray htmlbody = mText;
1461 htmlBodyPart.setBodyAndGuessCte( htmlbody, allowedCTEs,
1462 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
1464 htmlBodyPart.setCharset( mCharset );
1465 htmlBodyPart.setBodyEncodedBinary( htmlbody );
1467 htmlDwPart->Assemble();
1469 newbody += boundaryCStr;
1471 newbody += htmlDwPart->AsString().c_str();
1476 newbody += boundaryCStr;
1479 mOldBodyPart.setBodyEncodedBinary( bodyData );
1481 mSaveBoundary = tmpCT.Boundary();
1485 for ( TQValueVector<Attachment>::const_iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
1493 if( it->sign || it->encrypt ) {
1494 TQCString cte = it->part->cteStr().lower();
1495 if( (
"8bit" == cte && it->part->type() != DwMime::kTypeMessage )
1496 || ( ( it->part->type() == DwMime::kTypeText )
1497 && (
"7bit" == cte ) ) ) {
1498 const TQByteArray body = it->part->bodyDecodedBinary();
1499 TQValueList<int> dummy;
1500 it->part->setBodyAndGuessCte(body, dummy,
false, it->sign);
1501 kdDebug(5006) <<
"Changed encoding of message part from " 1502 << cte <<
" to " << it->part->cteStr() << endl;
1507 if( mEarlyAddAttachments ) {
1509 KMMessagePart innerBodyPart;
1510 if ( mIsRichText ) {
1511 innerBodyPart.setTypeStr(
"multipart");
1512 innerBodyPart.setSubtypeStr(
"alternative");
1515 innerBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
1517 innerBodyPart.setContentDisposition(
"inline" );
1518 TQValueList<int> allowedCTEs;
1520 innerBodyPart.setBodyAndGuessCte( bodyData, allowedCTEs,
1521 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
1524 innerBodyPart.setCharset( mCharset );
1525 innerBodyPart.setBodyEncodedBinary( bodyData );
1527 innerDwPart->Assemble();
1529 if ( mIsRichText ) {
1530 int boundPos = tmpbody.find(
'\n' );
1531 if( -1 < boundPos ) {
1532 TQCString bStr(
";\n boundary=\"" );
1533 bStr += mSaveBoundary.c_str();
1536 KMail::Util::insert( bodyData, boundPos, bStr );
1537 KMail::Util::insert( bodyData, 0,
"--" + mMultipartMixedBoundary +
"\n" );
1542 KMail::Util::insert( bodyData, 0,
"--" + mMultipartMixedBoundary +
"\n" );
1548 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
1549 if ( it->encrypt == doEncryptBody && it->sign == doSignBody ) {
1551 innerDwPart->Assemble();
1560 TQValueList<int> allowedCTEs;
1562 mOldBodyPart.setBodyAndGuessCte(bodyData, allowedCTEs, !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
1565 mOldBodyPart.setCharset(mCharset);
1568 mOldBodyPart.setBodyEncodedBinary( bodyData );
1570 if( doSignBody || doEncryptBody ) {
1574 if ( mIsRichText && !mEarlyAddAttachments ) {
1578 DwHeaders& headers = dwPart->Headers();
1579 DwMediaType& ct = headers.ContentType();
1580 ct.SetBoundary(mSaveBoundary);
1592 if( !mMultipartMixedBoundary.isEmpty() ) {
1593 int boundPos = mEncodedBody.find(
'\n' );
1594 if( -1 < boundPos ) {
1596 TQCString bStr(
";\n boundary=\"" );
1597 bStr += mMultipartMixedBoundary;
1599 KMail::Util::insert( mEncodedBody, boundPos, bStr.data() );
1610 mPerformingSignOperation =
true;
1611 pgpSignedMsg( mEncodedBody, format );
1612 mPerformingSignOperation =
false;
1614 if ( mSignature.isEmpty() ) {
1615 kdDebug() <<
"signature was empty" << endl;
1619 mRc = processStructuringInfo( TQString(),
1620 mOldBodyPart.contentDescription(),
1621 mOldBodyPart.typeStr(),
1622 mOldBodyPart.subtypeStr(),
1623 mOldBodyPart.contentDisposition(),
1624 mOldBodyPart.contentTransferEncodingStr(),
1625 mEncodedBody,
"signature",
1627 *mNewBodyPart,
true, format );
1629 if ( !makeMultiPartSigned( format ) ) {
1630 mNewBodyPart->setCharset( mCharset );
1633 KMessageBox::sorry( mComposeWin,
1634 mErrorProcessingStructuringInfo );
1640 continueComposeMessage( theMessage, doSign, doEncrypt, format );
1644 void MessageComposer::continueComposeMessage(
KMMessage& theMessage,
1645 bool doSign,
bool doEncrypt,
1646 Kleo::CryptoMessageFormat format )
1649 const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
1650 = mKeyResolver->encryptionItems( format );
1651 kdWarning( splitInfos.empty() )
1652 <<
"MessageComposer::continueComposeMessage(): splitInfos.empty() for " 1653 << Kleo::cryptoMessageFormatToString( format ) << endl;
1655 if ( !splitInfos.empty() && doEncrypt && !saveMessagesEncrypted() ) {
1656 mJobs.push_front(
new SetLastMessageAsUnencryptedVersionOfLastButOne(
this ) );
1657 mJobs.push_front(
new EncryptMessageJob(
new KMMessage( theMessage ),
1658 Kleo::KeyResolver::SplitInfo( splitInfos.front().recipients ), doSign,
1659 false, mEncodedBody,
1660 mPreviousBoundaryLevel,
1665 for ( std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it = splitInfos.begin() ; it != splitInfos.end() ; ++it )
1666 mJobs.push_front(
new EncryptMessageJob(
new KMMessage( theMessage ), *it, doSign,
1667 doEncrypt, mEncodedBody,
1668 mPreviousBoundaryLevel,
1673 void MessageComposer::encryptMessage(
KMMessage* msg,
1674 const Kleo::KeyResolver::SplitInfo & splitInfo,
1675 bool doSign,
bool doEncrypt,
1676 KMMessagePart newBodyPart,
1677 Kleo::CryptoMessageFormat format )
1679 if ( doEncrypt && splitInfo.keys.empty() ) {
1686 const bool doEncryptBody = doEncrypt && mEncryptBody;
1687 const bool doSignBody = doSign && mSignBody;
1689 if ( doEncryptBody ) {
1690 TQByteArray innerContent;
1699 innerContent = mEncodedBody;
1709 TQByteArray encryptedBody;
1710 Kpgp::Result result = pgpEncryptedMsg( encryptedBody, innerContent,
1711 splitInfo.keys, format );
1712 if ( result != Kpgp::Ok ) {
1716 mRc = processStructuringInfo(
"http://www.gnupg.org/aegypten/",
1717 newBodyPart.contentDescription(),
1718 newBodyPart.typeStr(),
1719 newBodyPart.subtypeStr(),
1720 newBodyPart.contentDisposition(),
1721 newBodyPart.contentTransferEncodingStr(),
1725 newBodyPart,
false, format );
1727 KMessageBox::sorry(mComposeWin, mErrorProcessingStructuringInfo);
1732 const bool useNewBodyPart = doSignBody || doEncryptBody;
1733 addBodyAndAttachments( msg, splitInfo, doSign, doEncrypt,
1734 useNewBodyPart ? newBodyPart : mOldBodyPart, format );
1738 void MessageComposer::addBodyAndAttachments(
KMMessage* msg,
1739 const Kleo::KeyResolver::SplitInfo & splitInfo,
1740 bool doSign,
bool doEncrypt,
1741 const KMMessagePart& ourFineBodyPart,
1742 Kleo::CryptoMessageFormat format )
1744 const bool doEncryptBody = doEncrypt && mEncryptBody;
1745 const bool doSignBody = doSign && mSignBody;
1747 if( !mAttachments.empty()
1748 && ( !mEarlyAddAttachments || !mAllAttachmentsAreInBody ) ) {
1750 msg->
headers().ContentType().SetType( DwMime::kTypeMultipart );
1751 msg->
headers().ContentType().SetSubtype( DwMime::kSubtypeMixed );
1752 msg->
headers().ContentType().CreateBoundary( 0 );
1753 kdDebug(5006) <<
"MessageComposer::addBodyAndAttachments() : set top level Content-Type to Multipart/Mixed" << endl;
1757 DwHeaders& headers = tmpDwPart->Headers();
1758 DwMediaType& ct = headers.ContentType();
1759 if ( !mSaveBoundary.empty() )
1760 ct.SetBoundary(mSaveBoundary);
1761 tmpDwPart->Assemble();
1769 KMMessagePart newAttachPart;
1770 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
1772 const bool cryptFlagsDifferent = ( it->encrypt != doEncryptBody || it->sign != doSignBody ) ;
1774 if ( !cryptFlagsDifferent && mEarlyAddAttachments )
1777 const bool encryptThisNow = doEncrypt && cryptFlagsDifferent && it->encrypt ;
1778 const bool signThisNow = doSign && cryptFlagsDifferent && it->sign ;
1780 if ( !encryptThisNow && !signThisNow ) {
1783 (void)msg->asDwMessage();
1787 KMMessagePart& rEncryptMessagePart( *it->part );
1790 innerDwPart->Assemble();
1802 pgpSignedMsg( encodedAttachment, format );
1803 mRc = !mSignature.isEmpty();
1805 mRc = processStructuringInfo(
"http://www.gnupg.org/aegypten/",
1806 it->part->contentDescription(),
1807 it->part->typeStr(),
1808 it->part->subtypeStr(),
1809 it->part->contentDisposition(),
1810 it->part->contentTransferEncodingStr(),
1814 newAttachPart,
true, format );
1816 if( encryptThisNow ) {
1817 rEncryptMessagePart = newAttachPart;
1825 KMessageBox::sorry( mComposeWin, mErrorProcessingStructuringInfo );
1831 if( encryptThisNow ) {
1832 TQByteArray encryptedBody;
1833 Kpgp::Result result = pgpEncryptedMsg( encryptedBody,
1838 if( Kpgp::Ok == result ) {
1839 mRc = processStructuringInfo(
"http://www.gnupg.org/aegypten/",
1840 rEncryptMessagePart.contentDescription(),
1841 rEncryptMessagePart.typeStr(),
1842 rEncryptMessagePart.subtypeStr(),
1843 rEncryptMessagePart.contentDisposition(),
1844 rEncryptMessagePart.contentTransferEncodingStr(),
1848 newAttachPart,
false, format );
1850 KMessageBox::sorry( mComposeWin, mErrorProcessingStructuringInfo );
1855 (void)msg->asDwMessage();
1858 if( !ourFineBodyPart.originalContentTypeStr().isNull() ) {
1859 msg->
headers().ContentType().FromString( ourFineBodyPart.originalContentTypeStr() );
1860 msg->
headers().ContentType().Parse();
1861 kdDebug(5006) <<
"MessageComposer::addBodyAndAttachments() : set top level Content-Type from originalContentTypeStr()=" << ourFineBodyPart.originalContentTypeStr() << endl;
1863 TQCString ct = ourFineBodyPart.typeStr() +
"/" + ourFineBodyPart.subtypeStr();
1864 if ( ct ==
"multipart/mixed" )
1865 ct +=
";\n\tboundary=\"" + mMultipartMixedBoundary +
'"';
1866 else if ( ct ==
"multipart/alternative" )
1867 ct +=
";\n\tboundary=\"" + TQCString(mSaveBoundary.c_str()) +
'"';
1868 msg->
headers().ContentType().FromString( ct );
1869 msg->
headers().ContentType().Parse();
1870 kdDebug(5006) <<
"MessageComposer::addBodyAndAttachments() : set top level Content-Type to " << ct << endl;
1872 if ( !ourFineBodyPart.charset().isEmpty() )
1873 msg->
setCharset( ourFineBodyPart.charset() );
1875 ourFineBodyPart.contentTransferEncodingStr() );
1877 ourFineBodyPart.contentDescription() );
1879 ourFineBodyPart.contentDisposition() );
1881 if ( mDebugComposerCrypto )
1882 kdDebug(5006) <<
"MessageComposer::addBodyAndAttachments() : top level headers and body adjusted" << endl;
1885 msg->
setBody( ourFineBodyPart.dwBody() );
1890 splitInfo.recipients.join(
", "), KMMessage::Address );
1892 if ( mDebugComposerCrypto ) {
1893 kdDebug(5006) <<
"MessageComposer::addBodyAndAttachments():\n Final message:\n|||" << msg->
asString() <<
"|||\n\n" << endl;
1895 kdDebug(5006) <<
"\n\n\nMessageComposer::addBodyAndAttachments():\n Final headers:\n\n" << msg->
headerAsString() <<
"|||\n\n\n\n\n" << endl;
1901 bool MessageComposer::processStructuringInfo(
const TQString bugURL,
1902 const TQString contentDescClear,
1903 const TQCString contentTypeClear,
1904 const TQCString contentSubtypeClear,
1905 const TQCString contentDispClear,
1906 const TQCString contentTEncClear,
1907 const TQByteArray& clearCStr,
1909 const TQByteArray& ciphertext,
1910 KMMessagePart& resultingPart,
1911 bool signing, Kleo::CryptoMessageFormat format )
1913 assert( clearCStr.isEmpty() || clearCStr[clearCStr.size()-1] !=
'\0' );
1916 if ( makeMimeObject( format, signing ) ) {
1917 TQCString mainHeader =
"Content-Type: ";
1918 const char * toplevelCT = toplevelContentType( format, signing );
1920 mainHeader += toplevelCT;
1922 if( makeMultiMime( format, signing ) )
1923 mainHeader +=
"text/plain";
1925 mainHeader += contentTypeClear +
'/' + contentSubtypeClear;
1928 const TQCString boundaryCStr = KMime::multiPartBoundary();
1930 if ( makeMultiMime( format, signing ) )
1931 mainHeader.replace(
"%boundary", boundaryCStr );
1934 if (
const char * str = toplevelContentDisposition( format, signing ) ) {
1935 mainHeader +=
"\nContent-Disposition: ";
1938 if ( !makeMultiMime( format, signing ) &&
1939 binaryHint( format ) )
1940 mainHeader +=
"\nContent-Transfer-Encoding: base64";
1942 if( 0 < contentDispClear.length() ) {
1943 mainHeader +=
"\nContent-Disposition: ";
1944 mainHeader += contentDispClear;
1946 if( 0 < contentTEncClear.length() ) {
1947 mainHeader +=
"\nContent-Transfer-Encoding: ";
1948 mainHeader += contentTEncClear;
1955 mainDwStr = TQCString(mainHeader +
"\n\n").data();
1956 DwBodyPart mainDwPa( mainDwStr, 0 );
1959 if( !makeMultiMime( format, signing ) ) {
1960 if ( signing && includeCleartextWhenSigning( format ) ) {
1961 TQByteArray bodyText( clearCStr );
1964 resultingPart.setBodyEncodedBinary( bodyText );
1966 resultingPart.setBodyEncodedBinary( ciphertext );
1973 TQCString versCStr, codeCStr;
1974 if ( !signing && format == Kleo::OpenPGPMIMEFormat )
1976 "Content-Type: application/pgp-encrypted\n" 1977 "Content-Disposition: attachment\n" 1983 const char * nestedCT = nestedContentType( format, signing );
1985 codeCStr =
"Content-Type: ";
1986 codeCStr += nestedCT;
1988 if (
const char * str = nestedContentDisposition( format, signing ) ) {
1989 codeCStr +=
"Content-Disposition: ";
1993 if ( binaryHint( format ) ) {
1994 codeCStr +=
"Content-Transfer-Encoding: base64\n\n";
1995 codeCStr += KMime::Codec::codecForName(
"base64" )->encodeToTQCString( ciphertext );
1997 codeCStr +=
'\n' + TQCString( ciphertext.data(), ciphertext.size() + 1 );
2000 TQByteArray mainStr;
2003 if ( signing && includeCleartextWhenSigning( format ) &&
2004 !clearCStr.isEmpty() ) {
2010 if ( !versCStr.isEmpty() )
2012 if( !codeCStr.isEmpty() )
2017 resultingPart.setBodyEncodedBinary( mainStr );
2022 resultingPart.setContentDescription( contentDescClear );
2023 resultingPart.setTypeStr( contentTypeClear );
2024 resultingPart.setSubtypeStr( contentSubtypeClear );
2025 resultingPart.setContentDisposition( contentDispClear );
2026 resultingPart.setContentTransferEncodingStr( contentTEncClear );
2027 TQByteArray resultingBody;
2029 if ( signing && includeCleartextWhenSigning( format ) ) {
2030 if( !clearCStr.isEmpty() )
2033 if ( !ciphertext.isEmpty() )
2037 KMessageBox::sorry( mComposeWin,
2038 i18n(
"<qt><p>Error: The backend did not return " 2039 "any encoded data.</p>" 2040 "<p>Please report this bug:<br>%2</p></qt>" )
2044 resultingPart.setBodyEncodedBinary( resultingBody );
2051 TQCString MessageComposer::plainTextFromMarkup(
const TQString& markupText )
2053 TQTextEdit *hackConspiratorTextEdit =
new TQTextEdit( markupText );
2054 hackConspiratorTextEdit->setTextFormat(TQt::PlainText);
2055 if ( !mDisableBreaking ) {
2056 hackConspiratorTextEdit->setWordWrap( TQTextEdit::FixedColumnWidth );
2057 hackConspiratorTextEdit->setWrapColumnOrWidth( mLineBreakColumn );
2059 TQString text = hackConspiratorTextEdit->text();
2062 const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
2063 if( mCharset ==
"us-ascii" ) {
2064 textbody = KMMsgBase::toUsAscii( text );
2065 }
else if( codec == 0 ) {
2066 kdDebug(5006) <<
"Something is wrong and I can not get a codec." << endl;
2067 textbody = text.local8Bit();
2069 text = codec->toUnicode( text.latin1(), text.length() );
2070 textbody = codec->fromUnicode( text );
2072 if (textbody.isNull()) textbody =
"";
2074 delete hackConspiratorTextEdit;
2079 TQByteArray MessageComposer::breakLinesAndApplyCodec()
2084 if( mDisableBreaking || mIsRichText || !GlobalSettings::self()->wordWrap() )
2085 text = mComposeWin->mEditor->text();
2087 text = mComposeWin->mEditor->brokenText();
2088 text.truncate( text.length() );
2091 const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
2093 if( mCharset ==
"us-ascii" ) {
2094 cText = KMMsgBase::toUsAscii( text );
2095 newText = TQString::fromLatin1( cText );
2096 }
else if( codec == 0 ) {
2097 kdDebug(5006) <<
"Something is wrong and I can not get a codec." << endl;
2098 cText = text.local8Bit();
2099 newText = TQString::fromLocal8Bit( cText );
2101 cText = codec->fromUnicode( text );
2102 newText = codec->toUnicode( cText );
2104 if (cText.isNull()) cText =
"";
2106 if( !text.isEmpty() && (newText != text) ) {
2107 TQString oldText = mComposeWin->mEditor->text();
2108 mComposeWin->mEditor->setText( newText );
2110 bool anyway = ( KMessageBox::warningYesNo( mComposeWin,
2111 i18n(
"<qt>Not all characters fit into the chosen" 2112 " encoding.<br><br>Send the message anyway?</qt>"),
2113 i18n(
"Some Characters Will Be Lost"),
2114 i18n(
"Lose Characters"), i18n(
"Change Encoding") ) == KMessageBox::Yes );
2116 mComposeWin->mEditor->setText(oldText);
2117 return TQByteArray();
2132 if( cText.isEmpty() || cText[cText.length()-1] !=
'\n' ) {
2133 kdDebug(5006) <<
"Added an <LF> on the last line" << endl;
2141 void MessageComposer::pgpSignedMsg(
const TQByteArray& cText, Kleo::CryptoMessageFormat format ) {
2143 assert( cText.isEmpty() || cText[cText.size()-1] !=
'\0' );
2144 mSignature = TQByteArray();
2146 const std::vector<GpgME::Key> signingKeys = mKeyResolver->signingKeys( format );
2147 if ( signingKeys.empty() ) {
2148 KMessageBox::sorry( mComposeWin,
2149 i18n(
"This message could not be signed, " 2150 "since no valid signing keys have been found; " 2151 "this should actually never happen, " 2152 "please report this bug.") );
2157 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
2159 const Kleo::CryptoBackend::Protocol * proto
2160 = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
2163 std::auto_ptr<Kleo::SignJob> job( proto->signJob( armor( format ),
2164 textMode( format ) ) );
2167 KMessageBox::sorry( mComposeWin,
2168 i18n(
"This message could not be signed, " 2169 "since the chosen backend does not seem to support " 2170 "signing; this should actually never happen, " 2171 "please report this bug.") );
2175 TQByteArray signature;
2176 const GpgME::SigningResult res =
2177 job->exec( signingKeys, cText, signingMode( format ), signature );
2179 std::stringstream ss;
2181 kdDebug(5006) << ss.str().c_str() << endl;
2183 if ( res.error().isCanceled() ) {
2184 kdDebug() <<
"signing was canceled by user" << endl;
2187 if ( res.error() ) {
2188 kdDebug() <<
"signing failed: " << res.error().asString() << endl;
2189 job->showErrorDialog( mComposeWin );
2193 if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
2194 if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
2195 Kleo::MessageBox::auditLog( 0, job.get(), i18n(
"GnuPG Audit Log for Signing Operation") );
2197 mSignature = signature;
2198 if ( mSignature.isEmpty() ) {
2199 KMessageBox::sorry( mComposeWin,
2200 i18n(
"The signing operation failed. " 2201 "Please make sure that the gpg-agent program " 2207 Kpgp::Result MessageComposer::pgpEncryptedMsg( TQByteArray & encryptedBody,
2208 const TQByteArray& cText,
2209 const std::vector<GpgME::Key> & encryptionKeys,
2210 Kleo::CryptoMessageFormat format )
2213 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
2215 const Kleo::CryptoBackend::Protocol * proto
2216 = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
2219 std::auto_ptr<Kleo::EncryptJob> job( proto->encryptJob( armor( format ),
2220 textMode( format ) ) );
2222 KMessageBox::sorry( mComposeWin,
2223 i18n(
"This message could not be encrypted, " 2224 "since the chosen backend does not seem to support " 2225 "encryption; this should actually never happen, " 2226 "please report this bug.") );
2227 return Kpgp::Failure;
2230 const GpgME::EncryptionResult res =
2231 job->exec( encryptionKeys, cText,
true , encryptedBody );
2233 std::stringstream ss;
2235 kdDebug(5006) << ss.str().c_str() << endl;
2237 if ( res.error().isCanceled() ) {
2238 kdDebug() <<
"encryption was canceled by user" << endl;
2239 return Kpgp::Canceled;
2241 if ( res.error() ) {
2242 kdDebug() <<
"encryption failed: " << res.error().asString() << endl;
2243 job->showErrorDialog( mComposeWin );
2244 return Kpgp::Failure;
2247 if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
2248 if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
2249 Kleo::MessageBox::auditLog( 0, job.get(), i18n(
"GnuPG Audit Log for Encryption Operation") );
2254 Kpgp::Result MessageComposer::pgpSignedAndEncryptedMsg( TQByteArray & encryptedBody,
2255 const TQByteArray& cText,
2256 const std::vector<GpgME::Key> & signingKeys,
2257 const std::vector<GpgME::Key> & encryptionKeys,
2258 Kleo::CryptoMessageFormat format )
2261 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
2263 const Kleo::CryptoBackend::Protocol * proto
2264 = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
2267 std::auto_ptr<Kleo::SignEncryptJob> job( proto->signEncryptJob( armor( format ),
2268 textMode( format ) ) );
2270 KMessageBox::sorry( mComposeWin,
2271 i18n(
"This message could not be signed and encrypted, " 2272 "since the chosen backend does not seem to support " 2273 "combined signing and encryption; this should actually never happen, " 2274 "please report this bug.") );
2275 return Kpgp::Failure;
2278 const std::pair<GpgME::SigningResult,GpgME::EncryptionResult> res =
2279 job->exec( signingKeys, encryptionKeys, cText,
false, encryptedBody );
2281 std::stringstream ss;
2282 ss << res.first <<
'\n' << res.second;
2283 kdDebug(5006) << ss.str().c_str() << endl;
2285 if ( res.first.error().isCanceled() || res.second.error().isCanceled() ) {
2286 kdDebug() <<
"encrypt/sign was canceled by user" << endl;
2287 return Kpgp::Canceled;
2289 if ( res.first.error() || res.second.error() ) {
2290 if ( res.first.error() )
2291 kdDebug() <<
"signing failed: " << res.first.error().asString() << endl;
2293 kdDebug() <<
"encryption failed: " << res.second.error().asString() << endl;
2294 job->showErrorDialog( mComposeWin );
2295 return Kpgp::Failure;
2298 if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
2299 if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
2300 Kleo::MessageBox::auditLog( 0, job.get(), i18n(
"GnuPG Audit Log for Encryption Operation") );
2306 #include "messagecomposer.moc" void addDwBodyPart(DwBodyPart *aDwPart)
Append a DwBodyPart to the message.
TQCString lf2crlf(const TQCString &src)
Convert "\n" line endings to "\r\n".
void setBody(const TQCString &aStr)
Set the message body.
void setCharset(const TQCString &charset, DwEntity *entity=0)
Sets the charset of the message or a subpart of the message.
static void bodyPart(DwBodyPart *aDwBodyPart, KMMessagePart *aPart, bool withBody=true)
Fill the KMMessagePart structure for a given DwBodyPart.
void setHeaderField(const TQCString &name, const TQString &value, HeaderFieldType type=Unstructured, bool prepend=false)
Set the header field with the given name to the given value.
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
DwBodyPart * createDWBodyPart(const KMMessagePart *aPart)
Compose a DwBodyPart (needed for adding a part to the message).
DwHeaders & headers() const
get the DwHeaders (make sure to call setNeedsAssembly() function after directly modyfying internal da...
void append(TQByteArray &that, const TQByteArray &str)
Append a bytearray to a bytearray.
TQString idString() const
Returns a string that can be used to identify this folder.
TQString headerAsString() const
Return header as string.
TQByteArray byteArrayFromTQCStringNoDetach(TQCString &cstr)
Creates a TQByteArray from a TQCString without detaching (duplicating the data).
void deleteBodyParts()
Delete all body parts.
void setUnencryptedMsg(KMMessage *unencrypted)
Specifies an unencrypted copy of this message to be stored in a separate member variable to allow sav...
TQCString asString() const
Return the entire message contents as a string.
void addBodyPart(const KMMessagePart *aPart)
Append a body part to the message.
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
TQByteArray ByteArray(const DwString &str)
Construct a TQByteArray from a DwString.
static const TQStringList & preferredCharsets()
Get a list of preferred message charsets.
TQCString CString(const DwString &str)
Construct a TQCString from a DwString.
void removeHeaderField(const TQCString &name)
Remove header field with given name.
void setAutomaticFields(bool isMultipart=false)
Set fields that are either automatically set (Message-id) or that do not change from one message to a...
A class to resolve signing/encryption keys w.r.t.