00001
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif
00034
00035 #include "messagecomposer.h"
00036 #include "kmmsgpart.h"
00037 #define REALLY_WANT_KMCOMPOSEWIN_H
00038 #include "kmcomposewin.h"
00039 #undef REALLY_WANT_KMCOMPOSEWIN_H
00040 #include "tdelistboxdialog.h"
00041 #include "kcursorsaver.h"
00042 #include "messagesender.h"
00043 #include "kmfolder.h"
00044 #include "kmfoldercombobox.h"
00045 #include "keyresolver.h"
00046 #include "kleo_util.h"
00047 #include "globalsettings.h"
00048 #include "custommimeheader.h"
00049 #include "kmedit.h"
00050 #include "util.h"
00051
00052 #include <libkpimidentities/identity.h>
00053 #include <libkpimidentities/identitymanager.h>
00054 #include <libemailfunctions/email.h>
00055
00056 #include <ui/keyselectiondialog.h>
00057 #include <ui/keyapprovaldialog.h>
00058 #include <ui/messagebox.h>
00059 #include <kleo/cryptobackendfactory.h>
00060 #include <kleo/keylistjob.h>
00061 #include <kleo/encryptjob.h>
00062 #include <kleo/signencryptjob.h>
00063 #include <kleo/signjob.h>
00064 #include <kleo/specialjob.h>
00065
00066 #include <kmime_util.h>
00067 #include <kmime_codecs.h>
00068 #include <kpgpblock.h>
00069
00070 #include <mimelib/mimepp.h>
00071
00072 #include <tdemessagebox.h>
00073 #include <tdelocale.h>
00074 #include <kinputdialog.h>
00075 #include <kdebug.h>
00076 #include <tdeaction.h>
00077 #include <tqfile.h>
00078 #include <tqtextcodec.h>
00079 #include <tqtextedit.h>
00080 #include <tqtimer.h>
00081
00082 #include <gpgmepp/key.h>
00083 #include <gpgmepp/keylistresult.h>
00084 #include <gpgmepp/encryptionresult.h>
00085 #include <gpgmepp/signingresult.h>
00086 #include <gpgmepp/context.h>
00087
00088 #include <algorithm>
00089 #include <sstream>
00090 #include <memory>
00091
00092
00093
00094
00095 static inline bool warnSendUnsigned() {
00096 TDEConfigGroup group( KMKernel::config(), "Composer" );
00097 return group.readBoolEntry( "crypto-warning-unsigned", false );
00098 }
00099 static inline bool warnSendUnencrypted() {
00100 TDEConfigGroup group( KMKernel::config(), "Composer" );
00101 return group.readBoolEntry( "crypto-warning-unencrypted", false );
00102 }
00103 static inline bool saveMessagesEncrypted() {
00104 TDEConfigGroup group( KMKernel::config(), "Composer" );
00105 return group.readBoolEntry( "crypto-store-encrypted", true );
00106 }
00107 static inline bool encryptToSelf() {
00108
00109 TDEConfigGroup group( KMKernel::config(), "Composer" );
00110 return group.readBoolEntry( "crypto-encrypt-to-self", true );
00111 }
00112 static inline bool showKeyApprovalDialog() {
00113 TDEConfigGroup group( KMKernel::config(), "Composer" );
00114 return group.readBoolEntry( "crypto-show-keys-for-approval", true );
00115 }
00116
00117 static inline int encryptKeyNearExpiryWarningThresholdInDays() {
00118 const TDEConfigGroup composer( KMKernel::config(), "Composer" );
00119 if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
00120 return -1;
00121 const int num = composer.readNumEntry( "crypto-warn-encr-key-near-expire-int", 14 );
00122 return kMax( 1, num );
00123 }
00124
00125 static inline int signingKeyNearExpiryWarningThresholdInDays() {
00126 const TDEConfigGroup composer( KMKernel::config(), "Composer" );
00127 if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
00128 return -1;
00129 const int num = composer.readNumEntry( "crypto-warn-sign-key-near-expire-int", 14 );
00130 return kMax( 1, num );
00131 }
00132
00133 static inline int encryptRootCertNearExpiryWarningThresholdInDays() {
00134 const TDEConfigGroup composer( KMKernel::config(), "Composer" );
00135 if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
00136 return -1;
00137 const int num = composer.readNumEntry( "crypto-warn-encr-root-near-expire-int", 14 );
00138 return kMax( 1, num );
00139 }
00140
00141 static inline int signingRootCertNearExpiryWarningThresholdInDays() {
00142 const TDEConfigGroup composer( KMKernel::config(), "Composer" );
00143 if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
00144 return -1;
00145 const int num = composer.readNumEntry( "crypto-warn-sign-root-near-expire-int", 14 );
00146 return kMax( 1, num );
00147 }
00148
00149 static inline int encryptChainCertNearExpiryWarningThresholdInDays() {
00150 const TDEConfigGroup composer( KMKernel::config(), "Composer" );
00151 if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
00152 return -1;
00153 const int num = composer.readNumEntry( "crypto-warn-encr-chaincert-near-expire-int", 14 );
00154 return kMax( 1, num );
00155 }
00156
00157 static inline int signingChainCertNearExpiryWarningThresholdInDays() {
00158 const TDEConfigGroup composer( KMKernel::config(), "Composer" );
00159 if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
00160 return -1;
00161 const int num = composer.readNumEntry( "crypto-warn-sign-chaincert-near-expire-int", 14 );
00162 return kMax( 1, num );
00163 }
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 static TQString mErrorProcessingStructuringInfo =
00223 i18n("<qt><p>Structuring information returned by the Crypto plug-in "
00224 "could not be processed correctly; the plug-in might be damaged.</p>"
00225 "<p>Please contact your system administrator.</p></qt>");
00226 static TQString mErrorNoCryptPlugAndNoBuildIn =
00227 i18n("<p>No active Crypto Plug-In was found and the built-in OpenPGP code "
00228 "did not run successfully.</p>"
00229 "<p>You can do two things to change this:</p>"
00230 "<ul><li><em>either</em> activate a Plug-In using the "
00231 "Settings->Configure KMail->Plug-In dialog.</li>"
00232 "<li><em>or</em> specify traditional OpenPGP settings on the same dialog's "
00233 "Identity->Advanced tab.</li></ul>");
00234
00235
00236 class MessageComposerJob {
00237 public:
00238 MessageComposerJob( MessageComposer* composer ) : mComposer( composer ) {}
00239 virtual ~MessageComposerJob() {}
00240
00241 virtual void execute() = 0;
00242
00243 protected:
00244
00245
00246 void adjustCryptFlags() { mComposer->adjustCryptFlags(); }
00247 void composeMessage() { mComposer->composeMessage(); }
00248 void continueComposeMessage( KMMessage& msg, bool doSign, bool doEncrypt,
00249 Kleo::CryptoMessageFormat format )
00250 {
00251 mComposer->continueComposeMessage( msg, doSign, doEncrypt, format );
00252 }
00253 void chiasmusEncryptAllAttachments() {
00254 mComposer->chiasmusEncryptAllAttachments();
00255 }
00256
00257 MessageComposer* mComposer;
00258 };
00259
00260 class ChiasmusBodyPartEncryptJob : public MessageComposerJob {
00261 public:
00262 ChiasmusBodyPartEncryptJob( MessageComposer * composer )
00263 : MessageComposerJob( composer ) {}
00264
00265 void execute() {
00266 chiasmusEncryptAllAttachments();
00267 }
00268 };
00269
00270 class AdjustCryptFlagsJob : public MessageComposerJob {
00271 public:
00272 AdjustCryptFlagsJob( MessageComposer* composer )
00273 : MessageComposerJob( composer ) {}
00274
00275 void execute() {
00276 adjustCryptFlags();
00277 }
00278 };
00279
00280 class ComposeMessageJob : public MessageComposerJob {
00281 public:
00282 ComposeMessageJob( MessageComposer* composer )
00283 : MessageComposerJob( composer ) {}
00284
00285 void execute() {
00286 composeMessage();
00287 }
00288 };
00289
00290 MessageComposer::MessageComposer( KMComposeWin* win, const char* name )
00291 : TQObject( win, name ), mComposeWin( win ), mCurrentJob( 0 ),
00292 mReferenceMessage( 0 ), mKeyResolver( 0 ),
00293 mUseOpportunisticEncryption( false ),
00294 mSignBody( false ), mEncryptBody( false ),
00295 mSigningRequested( false ), mEncryptionRequested( false ),
00296 mDoSign( false ), mDoEncrypt( false ),
00297 mAllowedCryptoMessageFormats( 0 ),
00298 mDisableCrypto( false ),
00299 mDisableBreaking( false ),
00300 mDebugComposerCrypto( false ),
00301 mAutoCharset( true ),
00302 mIsRichText( false ),
00303 mIdentityUid( 0 ), mRc( true ),
00304 mHoldJobs( false ),
00305 mNewBodyPart( 0 ),
00306 mEarlyAddAttachments( false ), mAllAttachmentsAreInBody( false ),
00307 mPreviousBoundaryLevel( 0 ),
00308 mEncryptWithChiasmus( false ),
00309 mPerformingSignOperation( false )
00310 {
00311 }
00312
00313 MessageComposer::~MessageComposer()
00314 {
00315 delete mKeyResolver; mKeyResolver = 0;
00316 delete mNewBodyPart; mNewBodyPart = 0;
00317 }
00318
00319 void MessageComposer::applyChanges( bool disableCrypto )
00320 {
00321
00322 if( getenv("KMAIL_DEBUG_COMPOSER_CRYPTO") != 0 ) {
00323 TQCString cE = getenv("KMAIL_DEBUG_COMPOSER_CRYPTO");
00324 mDebugComposerCrypto = cE == "1" || cE.upper() == "ON" || cE.upper() == "TRUE";
00325 kdDebug(5006) << "KMAIL_DEBUG_COMPOSER_CRYPTO = TRUE" << endl;
00326 } else {
00327 mDebugComposerCrypto = false;
00328 kdDebug(5006) << "KMAIL_DEBUG_COMPOSER_CRYPTO = FALSE" << endl;
00329 }
00330
00331 mHoldJobs = false;
00332 mRc = true;
00333
00334 mDisableCrypto = disableCrypto;
00335
00336
00337
00338 readFromComposeWin();
00339
00340
00341
00342
00343 mJobs.push_back( new ChiasmusBodyPartEncryptJob( this ) );
00344
00345
00346 mJobs.push_back( new AdjustCryptFlagsJob( this ) );
00347
00348
00349 mJobs.push_back( new ComposeMessageJob( this ) );
00350
00351
00352 doNextJob();
00353 }
00354
00355 void MessageComposer::doNextJob()
00356 {
00357 delete mCurrentJob; mCurrentJob = 0;
00358
00359 if( mJobs.isEmpty() ) {
00360
00361 emitDone( mRc );
00362 return;
00363 }
00364
00365 if( !mRc ) {
00366
00367 while( !mJobs.isEmpty() ) {
00368 delete mJobs.front();
00369 mJobs.pop_front();
00370 }
00371 emitDone( false );
00372 return;
00373 }
00374
00375
00376 TQTimer::singleShot( 0, this, TQT_SLOT( slotDoNextJob() ) );
00377 }
00378
00379 void MessageComposer::emitDone( bool b )
00380 {
00381
00382 mEncodedBody = TQByteArray();
00383 delete mNewBodyPart; mNewBodyPart = 0;
00384 mOldBodyPart.clear();
00385 emit done( b );
00386 }
00387
00388 void MessageComposer::slotDoNextJob()
00389 {
00390 assert( !mCurrentJob );
00391 if( mHoldJobs )
00392
00393
00394 mHoldJobs = false;
00395 else {
00396 assert( !mJobs.empty() );
00397
00398 mCurrentJob = mJobs.front();
00399 assert( mCurrentJob );
00400 mJobs.pop_front();
00401
00402
00403 mCurrentJob->execute();
00404 }
00405
00406
00407 if( !mHoldJobs )
00408 doNextJob();
00409 }
00410
00411 void MessageComposer::readFromComposeWin()
00412 {
00413
00414 mDisableBreaking = false;
00415
00416 mSignBody = mComposeWin->mSignAction->isChecked();
00417 mSigningRequested = mSignBody;
00418 mEncryptBody = mComposeWin->mEncryptAction->isChecked();
00419 mEncryptionRequested = mEncryptBody;
00420
00421 mAutoCharset = mComposeWin->mAutoCharset;
00422 mCharset = mComposeWin->mCharset;
00423 mReferenceMessage = mComposeWin->mMsg;
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 if ( mReferenceMessage->type() == DwMime::kTypeMultipart )
00436 mReferenceMessage->setHeaderField( "Content-Type", "text/plain" );
00437 mUseOpportunisticEncryption = GlobalSettings::self()->pgpAutoEncrypt();
00438 mAllowedCryptoMessageFormats = mComposeWin->cryptoMessageFormat();
00439
00440 if( mAutoCharset ) {
00441 TQCString charset = KMMsgBase::autoDetectCharset( mCharset, KMMessage::preferredCharsets(), mComposeWin->mEditor->text() );
00442 if( charset.isEmpty() )
00443 {
00444 KMessageBox::sorry( mComposeWin,
00445 i18n( "No suitable encoding could be found for "
00446 "your message.\nPlease set an encoding "
00447 "using the 'Options' menu." ) );
00448 mRc = false;
00449 return;
00450 }
00451 mCharset = charset;
00452
00453 mComposeWin->mCharset = charset;
00454 }
00455 mReferenceMessage->setCharset(mCharset);
00456
00457 mReferenceMessage->setTo(mComposeWin->to());
00458 mReferenceMessage->setFrom(mComposeWin->from());
00459 mReferenceMessage->setCc(mComposeWin->cc());
00460 mReferenceMessage->setSubject(mComposeWin->subject());
00461 mReferenceMessage->setReplyTo(mComposeWin->replyTo());
00462 mReferenceMessage->setBcc(mComposeWin->bcc());
00463
00464 const KPIM::Identity & id = mComposeWin->identity();
00465
00466 KMFolder *f = mComposeWin->mFcc->getFolder();
00467 assert( f != 0 );
00468 if ( f->idString() == id.fcc() )
00469 mReferenceMessage->removeHeaderField("X-KMail-Fcc");
00470 else
00471 mReferenceMessage->setFcc( f->idString() );
00472
00473
00474 mReferenceMessage->setDrafts( id.drafts() );
00475
00476 if (id.isDefault())
00477 mReferenceMessage->removeHeaderField("X-KMail-Identity");
00478 else mReferenceMessage->setHeaderField("X-KMail-Identity", TQString::number( id.uoid() ));
00479
00480 TQString replyAddr;
00481 if (!mComposeWin->replyTo().isEmpty()) replyAddr = mComposeWin->replyTo();
00482 else replyAddr = mComposeWin->from();
00483
00484 if (mComposeWin->mRequestMDNAction->isChecked())
00485 mReferenceMessage->setHeaderField("Disposition-Notification-To", replyAddr);
00486 else
00487 mReferenceMessage->removeHeaderField("Disposition-Notification-To");
00488
00489 if (mComposeWin->mUrgentAction->isChecked()) {
00490 mReferenceMessage->setHeaderField("X-PRIORITY", "2 (High)");
00491 mReferenceMessage->setHeaderField("Priority", "urgent");
00492 } else {
00493 mReferenceMessage->removeHeaderField("X-PRIORITY");
00494 mReferenceMessage->removeHeaderField("Priority");
00495 }
00496
00497 int num = GlobalSettings::self()->custHeaderCount();
00498 for(int ix=0; ix<num; ix++) {
00499 CustomMimeHeader customMimeHeader( TQString::number(ix) );
00500 customMimeHeader.readConfig();
00501 mReferenceMessage->setHeaderField(
00502 KMMsgBase::toUsAscii( customMimeHeader.custHeaderName() ),
00503 customMimeHeader.custHeaderValue() );
00504 }
00505
00506
00507
00508
00509
00510
00511
00512 mBcc = mComposeWin->bcc();
00513 mTo = KPIM::splitEmailAddrList( mComposeWin->to().stripWhiteSpace() );
00514 mCc = KPIM::splitEmailAddrList( mComposeWin->cc().stripWhiteSpace() );
00515 mBccList = KPIM::splitEmailAddrList( mBcc.stripWhiteSpace() );
00516
00517 for ( unsigned int i = 0 ; i < mComposeWin->mAtmList.count() ; ++i )
00518 mAttachments.push_back( Attachment( mComposeWin->mAtmList.at(i),
00519 mComposeWin->signFlagOfAttachment( i ),
00520 mComposeWin->encryptFlagOfAttachment( i ) ) );
00521
00522 mEncryptWithChiasmus = mComposeWin->mEncryptWithChiasmus;
00523
00524 mIsRichText = mComposeWin->mEditor->textFormat() == TQt::RichText;
00525 mIdentityUid = mComposeWin->identityUid();
00526 mText = breakLinesAndApplyCodec();
00527 assert( mText.isEmpty() || mText[mText.size()-1] == '\n' );
00528
00529
00530
00531 mLineBreakColumn = mComposeWin->mEditor->lineBreakColumn();
00532 }
00533
00534 static TQCString escape_quoted_string( const TQCString & str ) {
00535 TQCString result;
00536 const unsigned int str_len = str.length();
00537 result.resize( 2*str_len + 1 );
00538 char * d = result.data();
00539 for ( unsigned int i = 0 ; i < str_len ; ++i )
00540 switch ( const char ch = str[i] ) {
00541 case '\\':
00542 case '"':
00543 *d++ = '\\';
00544 default:
00545 *d++ = ch;
00546 }
00547 result.truncate( d - result.begin() );
00548 return result;
00549 }
00550
00551 bool MessageComposer::encryptWithChiasmus( const Kleo::CryptoBackend::Protocol * chiasmus,
00552 const TQByteArray& body,
00553 TQByteArray& resultData )
00554 {
00555 std::auto_ptr<Kleo::SpecialJob> job( chiasmus->specialJob( "x-encrypt", TQMap<TQString,TQVariant>() ) );
00556 if ( !job.get() ) {
00557 const TQString msg = i18n( "Chiasmus backend does not offer the "
00558 "\"x-encrypt\" function. Please report this bug." );
00559 KMessageBox::error( mComposeWin, msg, i18n( "Chiasmus Backend Error" ) );
00560 return false;
00561 }
00562 if ( !job->setProperty( "key", GlobalSettings::chiasmusKey() ) ||
00563 !job->setProperty( "options", GlobalSettings::chiasmusOptions() ) ||
00564 !job->setProperty( "input", body ) ) {
00565 const TQString msg = i18n( "The \"x-encrypt\" function does not accept "
00566 "the expected parameters. Please report this bug." );
00567 KMessageBox::error( mComposeWin, msg, i18n( "Chiasmus Backend Error" ) );
00568 return false;
00569 }
00570 const GpgME::Error err = job->exec();
00571 if ( err.isCanceled() || err ) {
00572 if ( err )
00573 job->showErrorDialog( mComposeWin, i18n( "Chiasmus Encryption Error" ) );
00574 return false;
00575 }
00576 const TQVariant result = job->property( "result" );
00577 if ( result.type() != TQVariant::ByteArray ) {
00578 const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
00579 "The \"x-encrypt\" function did not return a "
00580 "byte array. Please report this bug." );
00581 KMessageBox::error( mComposeWin, msg, i18n( "Chiasmus Backend Error" ) );
00582 return false;
00583 }
00584 resultData = result.toByteArray();
00585 return true;
00586 }
00587
00588 void MessageComposer::chiasmusEncryptAllAttachments() {
00589 if ( !mEncryptWithChiasmus )
00590 return;
00591 assert( !GlobalSettings::chiasmusKey().isEmpty() );
00592 if ( mAttachments.empty() )
00593 return;
00594 const Kleo::CryptoBackend::Protocol * chiasmus
00595 = Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
00596 assert( chiasmus );
00597
00598
00599 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin(), end = mAttachments.end() ; it != end ; ++it ) {
00600 KMMessagePart * part = it->part;
00601 const TQString filename = part->fileName();
00602 if ( filename.endsWith( ".xia", false ) )
00603 continue;
00604 const TQByteArray body = part->bodyDecodedBinary();
00605 TQByteArray resultData;
00606 if ( !encryptWithChiasmus( chiasmus, body, resultData ) ) {
00607 mRc = false;
00608 return;
00609 }
00610
00611 TQValueList<int> dummy;
00612 part->setBodyAndGuessCte( resultData, dummy );
00613 part->setTypeStr( "application" );
00614 part->setSubtypeStr( "vnd.de.bund.bsi.chiasmus" );
00615 part->setName( filename + ".xia" );
00616 const TQCString enc_name = KMMsgBase::encodeRFC2231StringAutoDetectCharset(
00617 filename + ".xia", part->charset() );
00618 const TQCString cDisp = "attachment;\n\tfilename"
00619 + ( TQString( enc_name ) != filename + ".xia"
00620 ? "*=" + enc_name
00621 : "=\"" + escape_quoted_string( enc_name ) + '\"' );
00622 part->setContentDisposition( cDisp );
00623 }
00624 }
00625
00626 void MessageComposer::adjustCryptFlags()
00627 {
00628 if ( !mDisableCrypto &&
00629 mAllowedCryptoMessageFormats & Kleo::InlineOpenPGPFormat &&
00630 !mAttachments.empty() &&
00631 ( mSigningRequested || mEncryptionRequested ) )
00632 {
00633 int ret;
00634 if ( mAllowedCryptoMessageFormats == Kleo::InlineOpenPGPFormat ) {
00635 ret = KMessageBox::warningYesNoCancel( mComposeWin,
00636 i18n("The inline OpenPGP crypto message format "
00637 "does not support encryption or signing "
00638 "of attachments.\n"
00639 "Really use deprecated inline OpenPGP?"),
00640 i18n("Insecure Message Format"),
00641 i18n("Use Inline OpenPGP"),
00642 i18n("Use OpenPGP/MIME") );
00643 }
00644 else {
00645
00646
00647 ret = KMessageBox::No;
00648 }
00649
00650 if ( ret == KMessageBox::Cancel ) {
00651 mRc = false;
00652 return;
00653 } else if ( ret == KMessageBox::No ) {
00654 mAllowedCryptoMessageFormats &= ~Kleo::InlineOpenPGPFormat;
00655 mAllowedCryptoMessageFormats |= Kleo::OpenPGPMIMEFormat;
00656 if ( mSigningRequested ) {
00657
00658 for ( unsigned int idx = 0 ; idx < mAttachments.size() ; ++idx )
00659 mAttachments[idx].sign = true;
00660 }
00661 if ( mEncryptionRequested ) {
00662
00663
00664 for ( unsigned int idx = 0 ; idx < mAttachments.size() ; ++idx )
00665 mAttachments[idx].encrypt = true;
00666 }
00667 }
00668 }
00669
00670 mKeyResolver =
00671 new Kleo::KeyResolver( encryptToSelf(), showKeyApprovalDialog(),
00672 mUseOpportunisticEncryption, mAllowedCryptoMessageFormats,
00673 encryptKeyNearExpiryWarningThresholdInDays(),
00674 signingKeyNearExpiryWarningThresholdInDays(),
00675 encryptRootCertNearExpiryWarningThresholdInDays(),
00676 signingRootCertNearExpiryWarningThresholdInDays(),
00677 encryptChainCertNearExpiryWarningThresholdInDays(),
00678 signingChainCertNearExpiryWarningThresholdInDays() );
00679
00680 if ( !mDisableCrypto ) {
00681 const KPIM::Identity & id =
00682 kmkernel->identityManager()->identityForUoidOrDefault( mIdentityUid );
00683
00684 TQStringList encryptToSelfKeys;
00685 if ( !id.pgpEncryptionKey().isEmpty() )
00686 encryptToSelfKeys.push_back( id.pgpEncryptionKey() );
00687 if ( !id.smimeEncryptionKey().isEmpty() )
00688 encryptToSelfKeys.push_back( id.smimeEncryptionKey() );
00689 if ( mKeyResolver->setEncryptToSelfKeys( encryptToSelfKeys ) != Kpgp::Ok ) {
00690 mRc = false;
00691 return;
00692 }
00693
00694 TQStringList signKeys;
00695 if ( !id.pgpSigningKey().isEmpty() )
00696 signKeys.push_back( mPGPSigningKey = id.pgpSigningKey() );
00697 if ( !id.smimeSigningKey().isEmpty() )
00698 signKeys.push_back( mSMIMESigningKey = id.smimeSigningKey() );
00699 if ( mKeyResolver->setSigningKeys( signKeys ) != Kpgp::Ok ) {
00700 mRc = false;
00701 return;
00702 }
00703 }
00704
00705 mKeyResolver->setPrimaryRecipients( mTo + mCc );
00706 mKeyResolver->setSecondaryRecipients( mBccList );
00707
00708
00709 bool doSignCompletely = mSigningRequested;
00710 bool doEncryptCompletely = mEncryptionRequested;
00711 for ( unsigned int idx = 0 ; idx < mAttachments.size() ; ++idx ) {
00712 if ( mAttachments[idx].encrypt )
00713 mEncryptionRequested = true;
00714 else
00715 doEncryptCompletely = false;
00716 if ( mAttachments[idx].sign )
00717 mSigningRequested = true;
00718 else
00719 doSignCompletely = false;
00720 }
00721
00722 mDoSign = !mDisableCrypto && determineWhetherToSign( doSignCompletely );
00723
00724 if ( !mRc )
00725 return;
00726
00727 mDoEncrypt = !mDisableCrypto && determineWhetherToEncrypt( doEncryptCompletely );
00728
00729 if ( !mRc )
00730 return;
00731
00732
00733
00734
00735 if ( mKeyResolver->resolveAllKeys( mDoSign, mDoEncrypt ) != Kpgp::Ok )
00736 mRc = false;
00737 }
00738
00739 bool MessageComposer::determineWhetherToSign( bool doSignCompletely ) {
00740 bool sign = false;
00741 switch ( mKeyResolver->checkSigningPreferences( mSigningRequested ) ) {
00742 case Kleo::DoIt:
00743 if ( !mSigningRequested ) {
00744 markAllAttachmentsForSigning( true );
00745 return true;
00746 }
00747 sign = true;
00748 break;
00749 case Kleo::DontDoIt:
00750 sign = false;
00751 break;
00752 case Kleo::AskOpportunistic:
00753 assert( 0 );
00754 case Kleo::Ask:
00755 {
00756
00757 const KCursorSaver idle( KBusyPtr::idle() );
00758 const TQString msg = i18n("Examination of the recipient's signing preferences "
00759 "yielded that you be asked whether or not to sign "
00760 "this message.\n"
00761 "Sign this message?");
00762 switch ( KMessageBox::questionYesNoCancel( mComposeWin, msg,
00763 i18n("Sign Message?"),
00764 i18n("to sign","&Sign"),
00765 i18n("Do &Not Sign") ) ) {
00766 case KMessageBox::Cancel:
00767 mRc = false;
00768 return false;
00769 case KMessageBox::Yes:
00770 markAllAttachmentsForSigning( true );
00771 return true;
00772 case KMessageBox::No:
00773 markAllAttachmentsForSigning( false );
00774 return false;
00775 }
00776 }
00777 break;
00778 case Kleo::Conflict:
00779 {
00780
00781 const KCursorSaver idle( KBusyPtr::idle() );
00782 const TQString msg = i18n("There are conflicting signing preferences "
00783 "for these recipients.\n"
00784 "Sign this message?");
00785 switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
00786 i18n("Sign Message?"),
00787 i18n("to sign","&Sign"),
00788 i18n("Do &Not Sign") ) ) {
00789 case KMessageBox::Cancel:
00790 mRc = false;
00791 return false;
00792 case KMessageBox::Yes:
00793 markAllAttachmentsForSigning( true );
00794 return true;
00795 case KMessageBox::No:
00796 markAllAttachmentsForSigning( false );
00797 return false;
00798 }
00799 }
00800 break;
00801 case Kleo::Impossible:
00802 {
00803 const KCursorSaver idle( KBusyPtr::idle() );
00804 const TQString msg = i18n("You have requested to sign this message, "
00805 "but no valid signing keys have been configured "
00806 "for this identity.");
00807 if ( KMessageBox::warningContinueCancel( mComposeWin, msg,
00808 i18n("Send Unsigned?"),
00809 i18n("Send &Unsigned") )
00810 == KMessageBox::Cancel ) {
00811 mRc = false;
00812 return false;
00813 } else {
00814 markAllAttachmentsForSigning( false );
00815 return false;
00816 }
00817 }
00818 }
00819
00820 if ( !sign || !doSignCompletely ) {
00821 if ( warnSendUnsigned() ) {
00822 const KCursorSaver idle( KBusyPtr::idle() );
00823 const TQString msg = sign && !doSignCompletely
00824 ? i18n("Some parts of this message will not be signed.\n"
00825 "Sending only partially signed messages might violate site policy.\n"
00826 "Sign all parts instead?")
00827 : i18n("This message will not be signed.\n"
00828 "Sending unsigned message might violate site policy.\n"
00829 "Sign message instead?") ;
00830 const TQString buttonText = sign && !doSignCompletely
00831 ? i18n("&Sign All Parts") : i18n("&Sign") ;
00832 switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
00833 i18n("Unsigned-Message Warning"),
00834 buttonText,
00835 i18n("Send &As Is") ) ) {
00836 case KMessageBox::Cancel:
00837 mRc = false;
00838 return false;
00839 case KMessageBox::Yes:
00840 markAllAttachmentsForSigning( true );
00841 return true;
00842 case KMessageBox::No:
00843 return sign || doSignCompletely;
00844 }
00845 }
00846 }
00847
00848 return sign || doSignCompletely ;
00849 }
00850
00851 bool MessageComposer::determineWhetherToEncrypt( bool doEncryptCompletely ) {
00852 bool encrypt = false;
00853 bool opportunistic = false;
00854 switch ( mKeyResolver->checkEncryptionPreferences( mEncryptionRequested ) ) {
00855 case Kleo::DoIt:
00856 if ( !mEncryptionRequested ) {
00857 markAllAttachmentsForEncryption( true );
00858 return true;
00859 }
00860 encrypt = true;
00861 break;
00862 case Kleo::DontDoIt:
00863 encrypt = false;
00864 break;
00865 case Kleo::AskOpportunistic:
00866 opportunistic = true;
00867
00868 case Kleo::Ask:
00869 {
00870
00871 const KCursorSaver idle( KBusyPtr::idle() );
00872 const TQString msg = opportunistic
00873 ? i18n("Valid trusted encryption keys were found for all recipients.\n"
00874 "Encrypt this message?")
00875 : i18n("Examination of the recipient's encryption preferences "
00876 "yielded that you be asked whether or not to encrypt "
00877 "this message.\n"
00878 "Encrypt this message?");
00879 switch ( KMessageBox::questionYesNoCancel( mComposeWin, msg,
00880 i18n("Encrypt Message?"),
00881 mDoSign
00882 ? i18n("Sign && &Encrypt")
00883 : i18n("&Encrypt"),
00884 mDoSign
00885 ? i18n("&Sign Only")
00886 : i18n("&Send As-Is") ) ) {
00887 case KMessageBox::Cancel:
00888 mRc = false;
00889 return false;
00890 case KMessageBox::Yes:
00891 markAllAttachmentsForEncryption( true );
00892 return true;
00893 case KMessageBox::No:
00894 markAllAttachmentsForEncryption( false );
00895 return false;
00896 }
00897 }
00898 break;
00899 case Kleo::Conflict:
00900 {
00901
00902 const KCursorSaver idle( KBusyPtr::idle() );
00903 const TQString msg = i18n("There are conflicting encryption preferences "
00904 "for these recipients.\n"
00905 "Encrypt this message?");
00906 switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
00907 i18n("Encrypt Message?"),
00908 i18n("&Encrypt"),
00909 i18n("Do &Not Encrypt") ) ) {
00910 case KMessageBox::Cancel:
00911 mRc = false;
00912 return false;
00913 case KMessageBox::Yes:
00914 markAllAttachmentsForEncryption( true );
00915 return true;
00916 case KMessageBox::No:
00917 markAllAttachmentsForEncryption( false );
00918 return false;
00919 }
00920 }
00921 break;
00922 case Kleo::Impossible:
00923 {
00924 const KCursorSaver idle( KBusyPtr::idle() );
00925 const TQString msg = i18n("You have requested to encrypt this message, "
00926 "and to encrypt a copy to yourself, "
00927 "but no valid trusted encryption keys have been "
00928 "configured for this identity.");
00929 if ( KMessageBox::warningContinueCancel( mComposeWin, msg,
00930 i18n("Send Unencrypted?"),
00931 i18n("Send &Unencrypted") )
00932 == KMessageBox::Cancel ) {
00933 mRc = false;
00934 return false;
00935 } else {
00936 markAllAttachmentsForEncryption( false );
00937 return false;
00938 }
00939 }
00940 }
00941
00942 if ( !encrypt || !doEncryptCompletely ) {
00943 if ( warnSendUnencrypted() ) {
00944 const KCursorSaver idle( KBusyPtr::idle() );
00945 const TQString msg = !doEncryptCompletely
00946 ? i18n("Some parts of this message will not be encrypted.\n"
00947 "Sending only partially encrypted messages might violate site policy "
00948 "and/or leak sensitive information.\n"
00949 "Encrypt all parts instead?")
00950 : i18n("This message will not be encrypted.\n"
00951 "Sending unencrypted messages might violate site policy and/or "
00952 "leak sensitive information.\n"
00953 "Encrypt messages instead?") ;
00954 const TQString buttonText = !doEncryptCompletely
00955 ? i18n("&Encrypt All Parts") : i18n("&Encrypt") ;
00956 switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
00957 i18n("Unencrypted Message Warning"),
00958 buttonText,
00959 mDoSign
00960 ? i18n("&Sign Only")
00961 : i18n("&Send As-Is") ) ) {
00962 case KMessageBox::Cancel:
00963 mRc = false;
00964 return false;
00965 case KMessageBox::Yes:
00966 markAllAttachmentsForEncryption( true );
00967 return true;
00968 case KMessageBox::No:
00969 return encrypt || doEncryptCompletely;
00970 }
00971 }
00972 }
00973
00974 return encrypt || doEncryptCompletely ;
00975 }
00976
00977 void MessageComposer::markAllAttachmentsForSigning( bool sign ) {
00978 mSignBody = sign;
00979 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it )
00980 it->sign = sign;
00981 }
00982
00983 void MessageComposer::markAllAttachmentsForEncryption( bool enc ) {
00984 mEncryptBody = enc;
00985 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it )
00986 it->encrypt = enc;
00987 }
00988
00989
00990 void MessageComposer::composeMessage()
00991 {
00992 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
00993 if ( mKeyResolver->encryptionItems( concreteCryptoMessageFormats[i] ).empty() )
00994 continue;
00995 KMMessage * msg = new KMMessage( *mReferenceMessage );
00996 composeMessage( *msg, mDoSign, mDoEncrypt, concreteCryptoMessageFormats[i] );
00997 if ( !mRc )
00998 return;
00999 }
01000 }
01001
01002
01003
01004
01005
01006
01007 static inline bool makeMultiMime( Kleo::CryptoMessageFormat f, bool sign ) {
01008 switch ( f ) {
01009 default:
01010 case Kleo::InlineOpenPGPFormat:
01011 case Kleo::SMIMEOpaqueFormat: return false;
01012 case Kleo::OpenPGPMIMEFormat: return true;
01013 case Kleo::SMIMEFormat: return sign;
01014 }
01015 }
01016 static inline bool makeMultiPartSigned( Kleo::CryptoMessageFormat f ) {
01017 return makeMultiMime( f, true );
01018 }
01019 static inline bool makeMultiPartEncrypted( Kleo::CryptoMessageFormat f ) {
01020 return makeMultiMime( f, false );
01021 }
01022
01023 static inline bool makeMimeObject( Kleo::CryptoMessageFormat f, bool ) {
01024 return f != Kleo::InlineOpenPGPFormat;
01025 }
01026
01027 static inline const char * toplevelContentType( Kleo::CryptoMessageFormat f, bool signing ) {
01028 switch ( f ) {
01029 default:
01030 case Kleo::InlineOpenPGPFormat: return 0;
01031 case Kleo::OpenPGPMIMEFormat:
01032 return signing ?
01033 "multipart/signed;\n\t"
01034 "boundary=\"%boundary\";\n\t"
01035 "protocol=\"application/pgp-signature\";\n\t"
01036 "micalg=pgp-sha1"
01037 :
01038 "multipart/encrypted;\n\t"
01039 "boundary=\"%boundary\";\n\t"
01040 "protocol=\"application/pgp-encrypted\""
01041 ;
01042 case Kleo::SMIMEFormat:
01043 if ( signing )
01044 return
01045 "multipart/signed;\n\t"
01046 "boundary=\"%boundary\";\n\t"
01047 "protocol=\"application/pkcs7-signature\";\n\t"
01048 "micalg=sha1";
01049
01050
01051
01052 case Kleo::SMIMEOpaqueFormat:
01053 return signing ?
01054 "application/pkcs7-mime;\n\t"
01055 "smime-type=signed-data;\n\t"
01056 "name=\"smime.p7m\";\n\t"
01057 :
01058 "application/pkcs7-mime;\n\t"
01059 "smime-type=enveloped-data;\n\t"
01060 "name=\"smime.p7m\";\n\t"
01061 ;
01062 }
01063 }
01064
01065 static inline const char * toplevelContentDisposition( Kleo::CryptoMessageFormat f, bool signing ) {
01066 switch ( f ) {
01067 default:
01068 case Kleo::InlineOpenPGPFormat:
01069 case Kleo::OpenPGPMIMEFormat:
01070 return 0;
01071 case Kleo::SMIMEFormat:
01072 if ( signing )
01073 return 0;
01074 case Kleo::SMIMEOpaqueFormat:
01075 return "attachment; filename=\"smime.p7m\"";
01076 }
01077 }
01078
01079 static inline bool includeCleartextWhenSigning( Kleo::CryptoMessageFormat f ) {
01080 return makeMultiPartSigned( f );
01081 }
01082
01083 static inline const char * nestedContentType( Kleo::CryptoMessageFormat f, bool signing ) {
01084 switch ( f ) {
01085 case Kleo::OpenPGPMIMEFormat:
01086 return signing ? "application/pgp-signature; name=signature.asc \nContent-Description: This is a digitally signed message part." : "application/octet-stream" ;
01087 case Kleo::SMIMEFormat:
01088 if ( signing )
01089 return "application/pkcs7-signature; name=\"smime.p7s\"";
01090
01091 default:
01092 case Kleo::InlineOpenPGPFormat:
01093 case Kleo::SMIMEOpaqueFormat:
01094 return 0;
01095 }
01096 }
01097
01098 static inline const char * nestedContentDisposition( Kleo::CryptoMessageFormat f, bool signing ) {
01099 if ( !signing && f == Kleo::OpenPGPMIMEFormat )
01100 return "inline; filename=\"msg.asc\"";
01101 if ( signing && f == Kleo::SMIMEFormat )
01102 return "attachment; filename=\"smime.p7s\"";
01103 return 0;
01104 }
01105
01106 static inline bool binaryHint( Kleo::CryptoMessageFormat f ) {
01107 switch ( f ) {
01108 case Kleo::SMIMEFormat:
01109 case Kleo::SMIMEOpaqueFormat:
01110 return true;
01111 default:
01112 case Kleo::OpenPGPMIMEFormat:
01113 case Kleo::InlineOpenPGPFormat:
01114 return false;
01115 }
01116 }
01117
01118 static inline bool armor( Kleo::CryptoMessageFormat f ) {
01119 return !binaryHint( f );
01120 }
01121
01122 static inline bool textMode( Kleo::CryptoMessageFormat f ) {
01123 return f == Kleo::InlineOpenPGPFormat;
01124 }
01125
01126 static inline GpgME::Context::SignatureMode signingMode( Kleo::CryptoMessageFormat f ) {
01127 switch ( f ) {
01128 case Kleo::SMIMEOpaqueFormat:
01129 return GpgME::Context::Normal;
01130 case Kleo::InlineOpenPGPFormat:
01131 return GpgME::Context::Clearsigned;
01132 default:
01133 case Kleo::SMIMEFormat:
01134 case Kleo::OpenPGPMIMEFormat:
01135 return GpgME::Context::Detached;
01136 }
01137 }
01138
01139
01140
01141
01142
01143 class EncryptMessageJob : public MessageComposerJob {
01144 public:
01145 EncryptMessageJob( KMMessage* msg, const Kleo::KeyResolver::SplitInfo & si,
01146 bool doSign, bool doEncrypt, const TQByteArray& encodedBody,
01147 int boundaryLevel,
01148 KMMessagePart* newBodyPart, Kleo::CryptoMessageFormat format,
01149 MessageComposer* composer )
01150 : MessageComposerJob( composer ), mMsg( msg ), mSplitInfo( si ),
01151 mDoSign( doSign ), mDoEncrypt( doEncrypt ), mEncodedBody( encodedBody ),
01152 mBoundaryLevel( boundaryLevel ),
01153 mNewBodyPart( newBodyPart ), mFormat( format ) {}
01154
01155 void execute() {
01156 KMMessagePart tmpNewBodyPart;
01157 tmpNewBodyPart.duplicate( *mNewBodyPart );
01158
01159
01160
01161 mComposer->encryptMessage( mMsg, mSplitInfo, mDoSign, mDoEncrypt,
01162 tmpNewBodyPart, mFormat );
01163 if ( !mComposer->mRc ) {
01164 delete mMsg; mMsg = 0;
01165 return;
01166 }
01167 mComposer->mMessageList.push_back( mMsg );
01168 }
01169
01170 private:
01171 KMMessage* mMsg;
01172 Kleo::KeyResolver::SplitInfo mSplitInfo;
01173 bool mDoSign, mDoEncrypt;
01174 TQByteArray mEncodedBody;
01175 int mBoundaryLevel;
01176
01177 KMMessagePart* mNewBodyPart;
01178 Kleo::CryptoMessageFormat mFormat;
01179 };
01180
01181 class SetLastMessageAsUnencryptedVersionOfLastButOne : public MessageComposerJob {
01182 public:
01183 SetLastMessageAsUnencryptedVersionOfLastButOne( MessageComposer * composer )
01184 : MessageComposerJob( composer ) {}
01185
01186 void execute() {
01187 KMMessage * last = mComposer->mMessageList.back();
01188 mComposer->mMessageList.pop_back();
01189 mComposer->mMessageList.back()->setUnencryptedMsg( last );
01190 }
01191 };
01192
01193 void MessageComposer::composeInlineOpenPGPMessage( KMMessage& theMessage,
01194 bool doSign, bool doEncrypt )
01195 {
01196
01197 const TQByteArray bodyData = mText;
01198 if (bodyData.isNull()) {
01199 mRc = false;
01200 return;
01201 }
01202
01203 mNewBodyPart = 0;
01204 mEarlyAddAttachments = false;
01205 mAllAttachmentsAreInBody = false;
01206
01207
01208 theMessage.deleteBodyParts();
01209 TQString oldContentType = theMessage.headerField( "Content-Type" );
01210 theMessage.removeHeaderField("Content-Type");
01211 theMessage.removeHeaderField("Content-Transfer-Encoding");
01212
01213 const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
01214 = mKeyResolver->encryptionItems( Kleo::InlineOpenPGPFormat );
01215 kdWarning( splitInfos.empty() )
01216 << "MessageComposer::continueComposeMessage(): splitInfos.empty() for InlineOpenPGPFormat"
01217 << endl;
01218 std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it;
01219 for ( it = splitInfos.begin() ; it != splitInfos.end() ; ++it ) {
01220 const Kleo::KeyResolver::SplitInfo& splitInfo = *it;
01221 KMMessage* msg = new KMMessage( theMessage );
01222 if ( doEncrypt ) {
01223 Kpgp::Result result;
01224 TQByteArray encryptedBody;
01225 if ( doSign ) {
01226 const std::vector<GpgME::Key> signingKeys = mKeyResolver->signingKeys( Kleo::InlineOpenPGPFormat );
01227 result = pgpSignedAndEncryptedMsg( encryptedBody, bodyData, signingKeys,
01228 splitInfo.keys, Kleo::InlineOpenPGPFormat );
01229 } else {
01230 result = pgpEncryptedMsg( encryptedBody, bodyData,
01231 splitInfo.keys, Kleo::InlineOpenPGPFormat );
01232 }
01233 if ( result != Kpgp::Ok ) {
01234 mRc = false;
01235 return;
01236 }
01237 assert( !encryptedBody.isNull() );
01238 mOldBodyPart.setBodyEncodedBinary( encryptedBody );
01239 } else {
01240 if ( doSign ) {
01241 pgpSignedMsg( bodyData, Kleo::InlineOpenPGPFormat );
01242 if ( mSignature.isNull() ) {
01243 mRc = false;
01244 return;
01245 }
01246 mOldBodyPart.setBodyEncodedBinary( mSignature );
01247 } else {
01248 assert( !bodyData.isNull() );
01249 mOldBodyPart.setBodyEncodedBinary( bodyData );
01250 }
01251 }
01252 mOldBodyPart.setContentDisposition( "inline" );
01253 mOldBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
01254 if (mOldBodyPart.type() == DwMime::kTypeText) {
01255 mOldBodyPart.setCharset(mCharset);
01256 }
01257 addBodyAndAttachments( msg, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
01258 mMessageList.push_back( msg );
01259 if ( it == splitInfos.begin() ) {
01260 if ( doEncrypt && !saveMessagesEncrypted() ) {
01261 mOldBodyPart.setBodyEncodedBinary( bodyData );
01262 KMMessage* msgUnenc = new KMMessage( theMessage );
01263 addBodyAndAttachments( msgUnenc, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
01264 msg->setUnencryptedMsg( msgUnenc );
01265 }
01266 }
01267 }
01268 }
01269
01270
01271 void MessageComposer::composeChiasmusMessage( KMMessage& theMessage, Kleo::CryptoMessageFormat format )
01272 {
01273 assert( !GlobalSettings::chiasmusKey().isEmpty() );
01274 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
01275 assert( cpf );
01276 const Kleo::CryptoBackend::Protocol * chiasmus
01277 = cpf->protocol( "Chiasmus" );
01278 assert( chiasmus );
01279
01280
01281 const TQByteArray bodyData = mText;
01282 if (bodyData.isNull()) {
01283 mRc = false;
01284 return;
01285 }
01286
01287 mNewBodyPart = 0;
01288 mEarlyAddAttachments = false;
01289 mAllAttachmentsAreInBody = false;
01290
01291
01292 theMessage.deleteBodyParts();
01293 TQString oldContentType = theMessage.headerField( "Content-Type" );
01294 theMessage.removeHeaderField("Content-Type");
01295 theMessage.removeHeaderField("Content-Transfer-Encoding");
01296
01297
01298
01299 const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
01300 = mKeyResolver->encryptionItems( format );
01301 assert( splitInfos.size() == 1 );
01302 for ( std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it = splitInfos.begin() ; it != splitInfos.end() ; ++it )
01303 {
01304 const Kleo::KeyResolver::SplitInfo& splitInfo = *it;
01305 KMMessage* msg = new KMMessage( theMessage );
01306 TQByteArray encryptedBody;
01307
01308 if ( !encryptWithChiasmus( chiasmus, bodyData, encryptedBody ) ) {
01309 mRc = false;
01310 return;
01311 }
01312 assert( !encryptedBody.isNull() );
01313
01314
01315
01316 bool doSign = false;
01317 TQValueList<int> allowedCTEs;
01318 mOldBodyPart.setBodyAndGuessCte( encryptedBody, allowedCTEs,
01319 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
01320 doSign );
01321
01322
01323 mOldBodyPart.setContentDisposition( "inline" );
01324
01325 mOldBodyPart.setOriginalContentTypeStr( "application/vnd.de.bund.bsi.chiasmus-text;chiasmus-charset=" + mCharset );
01326
01327 mOldBodyPart.setTypeStr( "application" );
01328 mOldBodyPart.setSubtypeStr( "vnd.de.bund.bsi.chiasmus-text" );
01329 mOldBodyPart.setAdditionalCTypeParamStr( TQCString( "chiasmus-charset=" + mCharset ) );
01330 addBodyAndAttachments( msg, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
01331 mMessageList.push_back( msg );
01332
01333 if ( it == splitInfos.begin() && !saveMessagesEncrypted() ) {
01334 mOldBodyPart.setBodyEncodedBinary( bodyData );
01335 KMMessage* msgUnenc = new KMMessage( theMessage );
01336 addBodyAndAttachments( msgUnenc, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
01337 msg->setUnencryptedMsg( msgUnenc );
01338 }
01339 }
01340 }
01341
01342 void MessageComposer::composeMessage( KMMessage& theMessage,
01343 bool doSign, bool doEncrypt,
01344 Kleo::CryptoMessageFormat format )
01345 {
01346 #ifdef DEBUG
01347 kdDebug(5006) << "entering KMComposeWin::composeMessage" << endl;
01348 #endif
01349 if ( format == Kleo::InlineOpenPGPFormat ) {
01350 composeInlineOpenPGPMessage( theMessage, doSign, doEncrypt );
01351 return;
01352 }
01353
01354 if ( mEncryptWithChiasmus )
01355 {
01356 composeChiasmusMessage( theMessage, format );
01357 return;
01358 }
01359
01360
01361
01362 theMessage.setBody( "This message is in MIME format." );
01363
01364
01365 TQByteArray bodyData = mText;
01366 if (bodyData.isNull()) {
01367 mRc = false;
01368 return;
01369 }
01370
01371
01372 TQString oldContentType = theMessage.headerField( "Content-Type" );
01373 theMessage.deleteBodyParts();
01374 theMessage.removeHeaderField("Content-Type");
01375 theMessage.removeHeaderField("Content-Transfer-Encoding");
01376 theMessage.setAutomaticFields(true);
01377
01378
01379 mNewBodyPart = new KMMessagePart;
01380
01381
01382 mPreviousBoundaryLevel = 0;
01383
01384
01385 const bool doEncryptBody = doEncrypt && mEncryptBody;
01386 const bool doSignBody = doSign && mSignBody;
01387
01388
01389
01390 mEarlyAddAttachments = !mAttachments.empty() && ( doSignBody || doEncryptBody );
01391
01392 mAllAttachmentsAreInBody = mEarlyAddAttachments;
01393
01394
01395 if( mEarlyAddAttachments ) {
01396 bool someOk = false;
01397 for ( TQValueVector<Attachment>::const_iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
01398 if ( it->encrypt == doEncryptBody && it->sign == doSignBody )
01399 someOk = true;
01400 else
01401 mAllAttachmentsAreInBody = false;
01402 }
01403 if( !mAllAttachmentsAreInBody && !someOk )
01404 mEarlyAddAttachments = false;
01405 }
01406
01407 kdDebug(5006) << "mEarlyAddAttachments=" << mEarlyAddAttachments << " mAllAttachmentsAreInBody=" << mAllAttachmentsAreInBody << endl;
01408
01409
01410 mMultipartMixedBoundary = "";
01411 if ( mEarlyAddAttachments ) {
01412 mOldBodyPart.setTypeStr( "multipart" );
01413 mOldBodyPart.setSubtypeStr( "mixed" );
01414
01415 DwMediaType tmpCT;
01416 tmpCT.CreateBoundary( ++mPreviousBoundaryLevel );
01417 mMultipartMixedBoundary = tmpCT.Boundary().c_str();
01418 }
01419 else if ( mIsRichText ) {
01420 mOldBodyPart.setTypeStr( "multipart" );
01421 mOldBodyPart.setSubtypeStr( "alternative" );
01422 }
01423 else
01424 mOldBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
01425
01426 mOldBodyPart.setContentDisposition( "inline" );
01427
01428 if ( mIsRichText ) {
01429
01430 TQCString boundaryCStr;
01431 TQCString newbody;
01432 DwMediaType tmpCT;
01433 tmpCT.CreateBoundary( ++mPreviousBoundaryLevel );
01434 boundaryCStr = KMail::Util::CString( tmpCT.Boundary() );
01435 TQValueList<int> allowedCTEs;
01436
01437 KMMessagePart textBodyPart;
01438 textBodyPart.setTypeStr("text");
01439 textBodyPart.setSubtypeStr("plain");
01440
01441 TQCString textbody = plainTextFromMarkup( mText );
01442
01443
01444 textBodyPart.setBodyAndGuessCte( textbody, allowedCTEs,
01445 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
01446 doSign );
01447 textBodyPart.setCharset( mCharset );
01448 textBodyPart.setBodyEncoded( textbody );
01449 DwBodyPart* textDwPart = theMessage.createDWBodyPart( &textBodyPart );
01450 textDwPart->Assemble();
01451 newbody += "--";
01452 newbody += boundaryCStr;
01453 newbody += "\n";
01454 newbody += textDwPart->AsString().c_str();
01455 delete textDwPart;
01456 textDwPart = 0;
01457
01458 KMMessagePart htmlBodyPart;
01459 htmlBodyPart.setTypeStr("text");
01460 htmlBodyPart.setSubtypeStr("html");
01461 TQByteArray htmlbody = mText;
01462
01463 htmlBodyPart.setBodyAndGuessCte( htmlbody, allowedCTEs,
01464 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
01465 doSign );
01466 htmlBodyPart.setCharset( mCharset );
01467 htmlBodyPart.setBodyEncodedBinary( htmlbody );
01468 DwBodyPart* htmlDwPart = theMessage.createDWBodyPart( &htmlBodyPart );
01469 htmlDwPart->Assemble();
01470 newbody += "\n--";
01471 newbody += boundaryCStr;
01472 newbody += "\n";
01473 newbody += htmlDwPart->AsString().c_str();
01474 delete htmlDwPart;
01475 htmlDwPart = 0;
01476
01477 newbody += "--";
01478 newbody += boundaryCStr;
01479 newbody += "--\n";
01480 bodyData = KMail::Util::byteArrayFromTQCStringNoDetach( newbody );
01481 mOldBodyPart.setBodyEncodedBinary( bodyData );
01482
01483 mSaveBoundary = tmpCT.Boundary();
01484 }
01485
01486
01487 for ( TQValueVector<Attachment>::const_iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
01488
01489
01490
01491
01492
01493
01494
01495 if( it->sign || it->encrypt ) {
01496 TQCString cte = it->part->cteStr().lower();
01497 if( ( "8bit" == cte && it->part->type() != DwMime::kTypeMessage )
01498 || ( ( it->part->type() == DwMime::kTypeText )
01499 && ( "7bit" == cte ) ) ) {
01500 const TQByteArray body = it->part->bodyDecodedBinary();
01501 TQValueList<int> dummy;
01502 it->part->setBodyAndGuessCte(body, dummy, false, it->sign);
01503 kdDebug(5006) << "Changed encoding of message part from "
01504 << cte << " to " << it->part->cteStr() << endl;
01505 }
01506 }
01507 }
01508
01509 if( mEarlyAddAttachments ) {
01510
01511 KMMessagePart innerBodyPart;
01512 if ( mIsRichText ) {
01513 innerBodyPart.setTypeStr( "multipart");
01514 innerBodyPart.setSubtypeStr("alternative");
01515 }
01516 else {
01517 innerBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
01518 }
01519 innerBodyPart.setContentDisposition( "inline" );
01520 TQValueList<int> allowedCTEs;
01521
01522 innerBodyPart.setBodyAndGuessCte( bodyData, allowedCTEs,
01523 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
01524 doSign );
01525 if ( !mIsRichText )
01526 innerBodyPart.setCharset( mCharset );
01527 innerBodyPart.setBodyEncodedBinary( bodyData );
01528 DwBodyPart* innerDwPart = theMessage.createDWBodyPart( &innerBodyPart );
01529 innerDwPart->Assemble();
01530 TQByteArray tmpbody = KMail::Util::ByteArray( innerDwPart->AsString() );
01531 if ( mIsRichText ) {
01532 int boundPos = tmpbody.find( '\n' );
01533 if( -1 < boundPos ) {
01534 TQCString bStr( ";\n boundary=\"" );
01535 bStr += mSaveBoundary.c_str();
01536 bStr += "\"";
01537 bodyData = tmpbody;
01538 KMail::Util::insert( bodyData, boundPos, bStr );
01539 KMail::Util::insert( bodyData, 0, "--" + mMultipartMixedBoundary + "\n" );
01540 }
01541 }
01542 else {
01543 bodyData = tmpbody;
01544 KMail::Util::insert( bodyData, 0, "--" + mMultipartMixedBoundary + "\n" );
01545 }
01546 delete innerDwPart;
01547 innerDwPart = 0;
01548
01549
01550 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
01551 if ( it->encrypt == doEncryptBody && it->sign == doSignBody ) {
01552 innerDwPart = theMessage.createDWBodyPart( it->part );
01553 innerDwPart->Assemble();
01554 KMail::Util::append( bodyData, TQCString( "\n--" + mMultipartMixedBoundary + "\n" ) );
01555 KMail::Util::append( bodyData, innerDwPart->AsString().c_str() );
01556 delete innerDwPart;
01557 innerDwPart = 0;
01558 }
01559 }
01560 KMail::Util::append( bodyData, TQCString( "\n--" + mMultipartMixedBoundary + "--\n" ) );
01561 } else {
01562 TQValueList<int> allowedCTEs;
01563
01564 mOldBodyPart.setBodyAndGuessCte(bodyData, allowedCTEs, !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
01565 doSign);
01566 if ( !mIsRichText )
01567 mOldBodyPart.setCharset(mCharset);
01568 }
01569
01570 mOldBodyPart.setBodyEncodedBinary( bodyData );
01571
01572 if( doSignBody || doEncryptBody ) {
01573
01574
01575 DwBodyPart* dwPart;
01576 if ( mIsRichText && !mEarlyAddAttachments ) {
01577
01578
01579 dwPart = theMessage.createDWBodyPart( &mOldBodyPart );
01580 DwHeaders& headers = dwPart->Headers();
01581 DwMediaType& ct = headers.ContentType();
01582 ct.SetBoundary(mSaveBoundary);
01583 dwPart->Assemble();
01584 }
01585 else {
01586 dwPart = theMessage.createDWBodyPart( &mOldBodyPart );
01587 dwPart->Assemble();
01588 }
01589 mEncodedBody = KMail::Util::ByteArray( dwPart->AsString() );
01590 delete dwPart;
01591 dwPart = 0;
01592
01593
01594 if( !mMultipartMixedBoundary.isEmpty() ) {
01595 int boundPos = mEncodedBody.find( '\n' );
01596 if( -1 < boundPos ) {
01597
01598 TQCString bStr( ";\n boundary=\"" );
01599 bStr += mMultipartMixedBoundary;
01600 bStr += "\"";
01601 KMail::Util::insert( mEncodedBody, boundPos, bStr.data() );
01602 }
01603 }
01604
01605
01606
01607
01608 mEncodedBody = KMail::Util::lf2crlf( mEncodedBody );
01609 }
01610
01611 if ( doSignBody ) {
01612 mPerformingSignOperation = true;
01613 pgpSignedMsg( mEncodedBody, format );
01614 mPerformingSignOperation = false;
01615
01616 if ( mSignature.isEmpty() ) {
01617 kdDebug() << "signature was empty" << endl;
01618 mRc = false;
01619 return;
01620 }
01621 mRc = processStructuringInfo( TQString(),
01622 mOldBodyPart.contentDescription(),
01623 mOldBodyPart.typeStr(),
01624 mOldBodyPart.subtypeStr(),
01625 mOldBodyPart.contentDisposition(),
01626 mOldBodyPart.contentTransferEncodingStr(),
01627 mEncodedBody, "signature",
01628 mSignature,
01629 *mNewBodyPart, true, format );
01630 if ( mRc ) {
01631 if ( !makeMultiPartSigned( format ) ) {
01632 mNewBodyPart->setCharset( mCharset );
01633 }
01634 } else
01635 KMessageBox::sorry( mComposeWin,
01636 mErrorProcessingStructuringInfo );
01637 }
01638
01639 if ( !mRc )
01640 return;
01641
01642 continueComposeMessage( theMessage, doSign, doEncrypt, format );
01643 }
01644
01645
01646 void MessageComposer::continueComposeMessage( KMMessage& theMessage,
01647 bool doSign, bool doEncrypt,
01648 Kleo::CryptoMessageFormat format )
01649 {
01650
01651 const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
01652 = mKeyResolver->encryptionItems( format );
01653 kdWarning( splitInfos.empty() )
01654 << "MessageComposer::continueComposeMessage(): splitInfos.empty() for "
01655 << Kleo::cryptoMessageFormatToString( format ) << endl;
01656
01657 if ( !splitInfos.empty() && doEncrypt && !saveMessagesEncrypted() ) {
01658 mJobs.push_front( new SetLastMessageAsUnencryptedVersionOfLastButOne( this ) );
01659 mJobs.push_front( new EncryptMessageJob( new KMMessage( theMessage ),
01660 Kleo::KeyResolver::SplitInfo( splitInfos.front().recipients ), doSign,
01661 false, mEncodedBody,
01662 mPreviousBoundaryLevel,
01663 mNewBodyPart,
01664 format, this ) );
01665 }
01666
01667 for ( std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it = splitInfos.begin() ; it != splitInfos.end() ; ++it )
01668 mJobs.push_front( new EncryptMessageJob( new KMMessage( theMessage ), *it, doSign,
01669 doEncrypt, mEncodedBody,
01670 mPreviousBoundaryLevel,
01671 mNewBodyPart,
01672 format, this ) );
01673 }
01674
01675 void MessageComposer::encryptMessage( KMMessage* msg,
01676 const Kleo::KeyResolver::SplitInfo & splitInfo,
01677 bool doSign, bool doEncrypt,
01678 KMMessagePart newBodyPart,
01679 Kleo::CryptoMessageFormat format )
01680 {
01681 if ( doEncrypt && splitInfo.keys.empty() ) {
01682
01683
01684
01685 doEncrypt = false;
01686 }
01687
01688 const bool doEncryptBody = doEncrypt && mEncryptBody;
01689 const bool doSignBody = doSign && mSignBody;
01690
01691 if ( doEncryptBody ) {
01692 TQByteArray innerContent;
01693 if ( doSignBody ) {
01694
01695 DwBodyPart* dwPart = msg->createDWBodyPart( &newBodyPart );
01696 dwPart->Assemble();
01697 innerContent = KMail::Util::ByteArray( dwPart->AsString() );
01698 delete dwPart;
01699 dwPart = 0;
01700 } else {
01701 innerContent = mEncodedBody;
01702 }
01703
01704
01705
01706
01707
01708 innerContent = KMail::Util::lf2crlf( innerContent );
01709
01710
01711 TQByteArray encryptedBody;
01712 Kpgp::Result result = pgpEncryptedMsg( encryptedBody, innerContent,
01713 splitInfo.keys, format );
01714 if ( result != Kpgp::Ok ) {
01715 mRc = false;
01716 return;
01717 }
01718 mRc = processStructuringInfo( "http://www.gnupg.org/aegypten/",
01719 newBodyPart.contentDescription(),
01720 newBodyPart.typeStr(),
01721 newBodyPart.subtypeStr(),
01722 newBodyPart.contentDisposition(),
01723 newBodyPart.contentTransferEncodingStr(),
01724 innerContent,
01725 "encrypted data",
01726 encryptedBody,
01727 newBodyPart, false, format );
01728 if ( !mRc )
01729 KMessageBox::sorry(mComposeWin, mErrorProcessingStructuringInfo);
01730 }
01731
01732
01733 if( mRc ) {
01734 const bool useNewBodyPart = doSignBody || doEncryptBody;
01735 addBodyAndAttachments( msg, splitInfo, doSign, doEncrypt,
01736 useNewBodyPart ? newBodyPart : mOldBodyPart, format );
01737 }
01738 }
01739
01740 void MessageComposer::addBodyAndAttachments( KMMessage* msg,
01741 const Kleo::KeyResolver::SplitInfo & splitInfo,
01742 bool doSign, bool doEncrypt,
01743 const KMMessagePart& ourFineBodyPart,
01744 Kleo::CryptoMessageFormat format )
01745 {
01746 const bool doEncryptBody = doEncrypt && mEncryptBody;
01747 const bool doSignBody = doSign && mSignBody;
01748
01749 if( !mAttachments.empty()
01750 && ( !mEarlyAddAttachments || !mAllAttachmentsAreInBody ) ) {
01751
01752 msg->headers().ContentType().SetType( DwMime::kTypeMultipart );
01753 msg->headers().ContentType().SetSubtype( DwMime::kSubtypeMixed );
01754 msg->headers().ContentType().CreateBoundary( 0 );
01755 kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : set top level Content-Type to Multipart/Mixed" << endl;
01756
01757
01758 DwBodyPart* tmpDwPart = msg->createDWBodyPart( &ourFineBodyPart );
01759 DwHeaders& headers = tmpDwPart->Headers();
01760 DwMediaType& ct = headers.ContentType();
01761 if ( !mSaveBoundary.empty() )
01762 ct.SetBoundary(mSaveBoundary);
01763 tmpDwPart->Assemble();
01764
01765
01766
01767 msg->addDwBodyPart(tmpDwPart);
01768
01769
01770
01771 KMMessagePart newAttachPart;
01772 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
01773
01774 const bool cryptFlagsDifferent = ( it->encrypt != doEncryptBody || it->sign != doSignBody ) ;
01775
01776 if ( !cryptFlagsDifferent && mEarlyAddAttachments )
01777 continue;
01778
01779 const bool encryptThisNow = doEncrypt && cryptFlagsDifferent && it->encrypt ;
01780 const bool signThisNow = doSign && cryptFlagsDifferent && it->sign ;
01781
01782 if ( !encryptThisNow && !signThisNow ) {
01783 msg->addBodyPart( it->part );
01784
01785 (void)msg->asDwMessage();
01786 continue;
01787 }
01788
01789 KMMessagePart& rEncryptMessagePart( *it->part );
01790
01791 DwBodyPart* innerDwPart = msg->createDWBodyPart( it->part );
01792 innerDwPart->Assemble();
01793 TQByteArray encodedAttachment = KMail::Util::ByteArray( innerDwPart->AsString() );
01794 delete innerDwPart;
01795 innerDwPart = 0;
01796
01797
01798
01799
01800 encodedAttachment = KMail::Util::lf2crlf( encodedAttachment );
01801
01802
01803 if( signThisNow ) {
01804 pgpSignedMsg( encodedAttachment, format );
01805 mRc = !mSignature.isEmpty();
01806 if( mRc ) {
01807 mRc = processStructuringInfo( "http://www.gnupg.org/aegypten/",
01808 it->part->contentDescription(),
01809 it->part->typeStr(),
01810 it->part->subtypeStr(),
01811 it->part->contentDisposition(),
01812 it->part->contentTransferEncodingStr(),
01813 encodedAttachment,
01814 "signature",
01815 mSignature,
01816 newAttachPart, true, format );
01817 if( mRc ) {
01818 if( encryptThisNow ) {
01819 rEncryptMessagePart = newAttachPart;
01820 DwBodyPart* dwPart = msg->createDWBodyPart( &newAttachPart );
01821 dwPart->Assemble();
01822 encodedAttachment = KMail::Util::ByteArray( dwPart->AsString() );
01823 delete dwPart;
01824 dwPart = 0;
01825 }
01826 } else
01827 KMessageBox::sorry( mComposeWin, mErrorProcessingStructuringInfo );
01828 } else {
01829
01830 break;
01831 }
01832 }
01833 if( encryptThisNow ) {
01834 TQByteArray encryptedBody;
01835 Kpgp::Result result = pgpEncryptedMsg( encryptedBody,
01836 encodedAttachment,
01837 splitInfo.keys,
01838 format );
01839
01840 if( Kpgp::Ok == result ) {
01841 mRc = processStructuringInfo( "http://www.gnupg.org/aegypten/",
01842 rEncryptMessagePart.contentDescription(),
01843 rEncryptMessagePart.typeStr(),
01844 rEncryptMessagePart.subtypeStr(),
01845 rEncryptMessagePart.contentDisposition(),
01846 rEncryptMessagePart.contentTransferEncodingStr(),
01847 encodedAttachment,
01848 "encrypted data",
01849 encryptedBody,
01850 newAttachPart, false, format );
01851 if ( !mRc )
01852 KMessageBox::sorry( mComposeWin, mErrorProcessingStructuringInfo );
01853 } else
01854 mRc = false;
01855 }
01856 msg->addBodyPart( &newAttachPart );
01857 (void)msg->asDwMessage();
01858 }
01859 } else {
01860 if( !ourFineBodyPart.originalContentTypeStr().isNull() ) {
01861 msg->headers().ContentType().FromString( ourFineBodyPart.originalContentTypeStr() );
01862 msg->headers().ContentType().Parse();
01863 kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : set top level Content-Type from originalContentTypeStr()=" << ourFineBodyPart.originalContentTypeStr() << endl;
01864 } else {
01865 TQCString ct = ourFineBodyPart.typeStr() + "/" + ourFineBodyPart.subtypeStr();
01866 if ( ct == "multipart/mixed" )
01867 ct += ";\n\tboundary=\"" + mMultipartMixedBoundary + '"';
01868 else if ( ct == "multipart/alternative" )
01869 ct += ";\n\tboundary=\"" + TQCString(mSaveBoundary.c_str()) + '"';
01870 msg->headers().ContentType().FromString( ct );
01871 msg->headers().ContentType().Parse();
01872 kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : set top level Content-Type to " << ct << endl;
01873 }
01874 if ( !ourFineBodyPart.charset().isEmpty() )
01875 msg->setCharset( ourFineBodyPart.charset() );
01876 msg->setHeaderField( "Content-Transfer-Encoding",
01877 ourFineBodyPart.contentTransferEncodingStr() );
01878 msg->setHeaderField( "Content-Description",
01879 ourFineBodyPart.contentDescription() );
01880 msg->setHeaderField( "Content-Disposition",
01881 ourFineBodyPart.contentDisposition() );
01882
01883 if ( mDebugComposerCrypto )
01884 kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : top level headers and body adjusted" << endl;
01885
01886
01887 msg->setBody( ourFineBodyPart.dwBody() );
01888
01889 }
01890
01891 msg->setHeaderField( "X-KMail-Recipients",
01892 splitInfo.recipients.join(", "), KMMessage::Address );
01893
01894 if ( mDebugComposerCrypto ) {
01895 kdDebug(5006) << "MessageComposer::addBodyAndAttachments():\n Final message:\n|||" << msg->asString() << "|||\n\n" << endl;
01896 msg->headers().Assemble();
01897 kdDebug(5006) << "\n\n\nMessageComposer::addBodyAndAttachments():\n Final headers:\n\n" << msg->headerAsString() << "|||\n\n\n\n\n" << endl;
01898 }
01899 }
01900
01901
01902
01903 bool MessageComposer::processStructuringInfo( const TQString bugURL,
01904 const TQString contentDescClear,
01905 const TQCString contentTypeClear,
01906 const TQCString contentSubtypeClear,
01907 const TQCString contentDispClear,
01908 const TQCString contentTEncClear,
01909 const TQByteArray& clearCStr,
01910 const TQString ,
01911 const TQByteArray& ciphertext,
01912 KMMessagePart& resultingPart,
01913 bool signing, Kleo::CryptoMessageFormat format )
01914 {
01915 assert( clearCStr.isEmpty() || clearCStr[clearCStr.size()-1] != '\0' );
01916 bool bOk = true;
01917
01918 if ( makeMimeObject( format, signing ) ) {
01919 TQCString mainHeader = "Content-Type: ";
01920 const char * toplevelCT = toplevelContentType( format, signing );
01921 if ( toplevelCT )
01922 mainHeader += toplevelCT;
01923 else {
01924 if( makeMultiMime( format, signing ) )
01925 mainHeader += "text/plain";
01926 else
01927 mainHeader += contentTypeClear + '/' + contentSubtypeClear;
01928 }
01929
01930 const TQCString boundaryCStr = KMime::multiPartBoundary();
01931
01932 if ( makeMultiMime( format, signing ) )
01933 mainHeader.replace( "%boundary", boundaryCStr );
01934
01935 if ( toplevelCT ) {
01936 if ( const char * str = toplevelContentDisposition( format, signing ) ) {
01937 mainHeader += "\nContent-Disposition: ";
01938 mainHeader += str;
01939 }
01940 if ( !makeMultiMime( format, signing ) &&
01941 binaryHint( format ) )
01942 mainHeader += "\nContent-Transfer-Encoding: base64";
01943 } else {
01944 if( 0 < contentDispClear.length() ) {
01945 mainHeader += "\nContent-Disposition: ";
01946 mainHeader += contentDispClear;
01947 }
01948 if( 0 < contentTEncClear.length() ) {
01949 mainHeader += "\nContent-Transfer-Encoding: ";
01950 mainHeader += contentTEncClear;
01951 }
01952 }
01953
01954
01955
01956 DwString mainDwStr;
01957 mainDwStr = TQCString(mainHeader + "\n\n").data();
01958 DwBodyPart mainDwPa( mainDwStr, 0 );
01959 mainDwPa.Parse();
01960 KMMessage::bodyPart( &mainDwPa, &resultingPart );
01961 if( !makeMultiMime( format, signing ) ) {
01962 if ( signing && includeCleartextWhenSigning( format ) ) {
01963 TQByteArray bodyText( clearCStr );
01964 KMail::Util::append( bodyText, "\n" );
01965 KMail::Util::append( bodyText, ciphertext );
01966 resultingPart.setBodyEncodedBinary( bodyText );
01967 } else {
01968 resultingPart.setBodyEncodedBinary( ciphertext );
01969 }
01970 } else {
01971
01972
01973
01974
01975 TQCString versCStr, codeCStr;
01976 if ( !signing && format == Kleo::OpenPGPMIMEFormat )
01977 versCStr =
01978 "Content-Type: application/pgp-encrypted\n"
01979 "Content-Disposition: attachment\n"
01980 "\n"
01981 "Version: 1";
01982
01983
01984
01985 const char * nestedCT = nestedContentType( format, signing );
01986 assert( nestedCT );
01987 codeCStr = "Content-Type: ";
01988 codeCStr += nestedCT;
01989 codeCStr += '\n';
01990 if ( const char * str = nestedContentDisposition( format, signing ) ) {
01991 codeCStr += "Content-Disposition: ";
01992 codeCStr += str;
01993 codeCStr += '\n';
01994 }
01995 if ( binaryHint( format ) ) {
01996 codeCStr += "Content-Transfer-Encoding: base64\n\n";
01997 codeCStr += KMime::Codec::codecForName( "base64" )->encodeToTQCString( ciphertext );
01998 } else
01999 codeCStr += '\n' + TQCString( ciphertext.data(), ciphertext.size() + 1 );
02000
02001
02002 TQByteArray mainStr;
02003 KMail::Util::append( mainStr, "--" );
02004 KMail::Util::append( mainStr, boundaryCStr );
02005 if ( signing && includeCleartextWhenSigning( format ) &&
02006 !clearCStr.isEmpty() ) {
02007 KMail::Util::append( mainStr, "\n" );
02008
02009 KMail::Util::append( mainStr, clearCStr );
02010 KMail::Util::append( mainStr, "\n--" + boundaryCStr );
02011 }
02012 if ( !versCStr.isEmpty() )
02013 KMail::Util::append( mainStr, "\n" + versCStr + "\n--" + boundaryCStr );
02014 if( !codeCStr.isEmpty() )
02015 KMail::Util::append( mainStr, "\n" + codeCStr + "\n--" + boundaryCStr );
02016 KMail::Util::append( mainStr, "--\n" );
02017
02018
02019 resultingPart.setBodyEncodedBinary( mainStr );
02020 }
02021
02022 } else {
02023
02024 resultingPart.setContentDescription( contentDescClear );
02025 resultingPart.setTypeStr( contentTypeClear );
02026 resultingPart.setSubtypeStr( contentSubtypeClear );
02027 resultingPart.setContentDisposition( contentDispClear );
02028 resultingPart.setContentTransferEncodingStr( contentTEncClear );
02029 TQByteArray resultingBody;
02030
02031 if ( signing && includeCleartextWhenSigning( format ) ) {
02032 if( !clearCStr.isEmpty() )
02033 KMail::Util::append( resultingBody, clearCStr );
02034 }
02035 if ( !ciphertext.isEmpty() )
02036 KMail::Util::append( resultingBody, ciphertext );
02037 else {
02038
02039 KMessageBox::sorry( mComposeWin,
02040 i18n( "<qt><p>Error: The backend did not return "
02041 "any encoded data.</p>"
02042 "<p>Please report this bug:<br>%2</p></qt>" )
02043 .arg( bugURL ) );
02044 bOk = false;
02045 }
02046 resultingPart.setBodyEncodedBinary( resultingBody );
02047 }
02048
02049 return bOk;
02050 }
02051
02052
02053 TQCString MessageComposer::plainTextFromMarkup( const TQString& markupText )
02054 {
02055 TQTextEdit *hackConspiratorTextEdit = new TQTextEdit( markupText );
02056 hackConspiratorTextEdit->setTextFormat(TQt::PlainText);
02057 if ( !mDisableBreaking ) {
02058 hackConspiratorTextEdit->setWordWrap( TQTextEdit::FixedColumnWidth );
02059 hackConspiratorTextEdit->setWrapColumnOrWidth( mLineBreakColumn );
02060 }
02061 TQString text = hackConspiratorTextEdit->text();
02062 TQCString textbody;
02063
02064 const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
02065 if( mCharset == "us-ascii" ) {
02066 textbody = KMMsgBase::toUsAscii( text );
02067 } else if( codec == 0 ) {
02068 kdDebug(5006) << "Something is wrong and I can not get a codec." << endl;
02069 textbody = text.local8Bit();
02070 } else {
02071 text = codec->toUnicode( text.latin1(), text.length() );
02072 textbody = codec->fromUnicode( text );
02073 }
02074 if (textbody.isNull()) textbody = "";
02075
02076 delete hackConspiratorTextEdit;
02077 return textbody;
02078 }
02079
02080
02081 TQByteArray MessageComposer::breakLinesAndApplyCodec()
02082 {
02083 TQString text;
02084 TQCString cText;
02085
02086 if( mDisableBreaking || mIsRichText || !GlobalSettings::self()->wordWrap() )
02087 text = mComposeWin->mEditor->text();
02088 else
02089 text = mComposeWin->mEditor->brokenText();
02090 text.truncate( text.length() );
02091
02092 TQString newText;
02093 const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
02094
02095 if( mCharset == "us-ascii" ) {
02096 cText = KMMsgBase::toUsAscii( text );
02097 newText = TQString::fromLatin1( cText );
02098 } else if( codec == 0 ) {
02099 kdDebug(5006) << "Something is wrong and I can not get a codec." << endl;
02100 cText = text.local8Bit();
02101 newText = TQString::fromLocal8Bit( cText );
02102 } else {
02103 cText = codec->fromUnicode( text );
02104 newText = codec->toUnicode( cText );
02105 }
02106 if (cText.isNull()) cText = "";
02107
02108 if( !text.isEmpty() && (newText != text) ) {
02109 TQString oldText = mComposeWin->mEditor->text();
02110 mComposeWin->mEditor->setText( newText );
02111 KCursorSaver idle( KBusyPtr::idle() );
02112 bool anyway = ( KMessageBox::warningYesNo( mComposeWin,
02113 i18n("<qt>Not all characters fit into the chosen"
02114 " encoding.<br><br>Send the message anyway?</qt>"),
02115 i18n("Some Characters Will Be Lost"),
02116 i18n("Lose Characters"), i18n("Change Encoding") ) == KMessageBox::Yes );
02117 if( !anyway ) {
02118 mComposeWin->mEditor->setText(oldText);
02119 return TQByteArray();
02120 }
02121 }
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134 if( cText.isEmpty() || cText[cText.length()-1] != '\n' ) {
02135 kdDebug(5006) << "Added an <LF> on the last line" << endl;
02136 cText += "\n";
02137 }
02138 return KMail::Util::byteArrayFromTQCStringNoDetach( cText );
02139 }
02140
02141
02142
02143 void MessageComposer::pgpSignedMsg( const TQByteArray& cText, Kleo::CryptoMessageFormat format ) {
02144
02145 assert( cText.isEmpty() || cText[cText.size()-1] != '\0' );
02146 mSignature = TQByteArray();
02147
02148 const std::vector<GpgME::Key> signingKeys = mKeyResolver->signingKeys( format );
02149 if ( signingKeys.empty() ) {
02150 KMessageBox::sorry( mComposeWin,
02151 i18n("This message could not be signed, "
02152 "since no valid signing keys have been found; "
02153 "this should actually never happen, "
02154 "please report this bug.") );
02155 return;
02156 }
02157
02158
02159 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
02160 assert( cpf );
02161 const Kleo::CryptoBackend::Protocol * proto
02162 = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
02163 assert( proto );
02164
02165 std::auto_ptr<Kleo::SignJob> job( proto->signJob( armor( format ),
02166 textMode( format ) ) );
02167
02168 if ( !job.get() ) {
02169 KMessageBox::sorry( mComposeWin,
02170 i18n("This message could not be signed, "
02171 "since the chosen backend does not seem to support "
02172 "signing; this should actually never happen, "
02173 "please report this bug.") );
02174 return;
02175 }
02176
02177 TQByteArray signature;
02178 const GpgME::SigningResult res =
02179 job->exec( signingKeys, cText, signingMode( format ), signature );
02180 {
02181 std::stringstream ss;
02182 ss << res;
02183 kdDebug(5006) << ss.str().c_str() << endl;
02184 }
02185 if ( res.error().isCanceled() ) {
02186 kdDebug() << "signing was canceled by user" << endl;
02187 return;
02188 }
02189 if ( res.error() ) {
02190 kdDebug() << "signing failed: " << res.error().asString() << endl;
02191 job->showErrorDialog( mComposeWin );
02192 return;
02193 }
02194
02195 if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
02196 if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
02197 Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Signing Operation") );
02198
02199 mSignature = signature;
02200 if ( mSignature.isEmpty() ) {
02201 KMessageBox::sorry( mComposeWin,
02202 i18n( "The signing operation failed. "
02203 "Please make sure that the gpg-agent program "
02204 "is running." ) );
02205 }
02206 }
02207
02208
02209 Kpgp::Result MessageComposer::pgpEncryptedMsg( TQByteArray & encryptedBody,
02210 const TQByteArray& cText,
02211 const std::vector<GpgME::Key> & encryptionKeys,
02212 Kleo::CryptoMessageFormat format )
02213 {
02214
02215 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
02216 assert( cpf );
02217 const Kleo::CryptoBackend::Protocol * proto
02218 = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
02219 assert( proto );
02220
02221 std::auto_ptr<Kleo::EncryptJob> job( proto->encryptJob( armor( format ),
02222 textMode( format ) ) );
02223 if ( !job.get() ) {
02224 KMessageBox::sorry( mComposeWin,
02225 i18n("This message could not be encrypted, "
02226 "since the chosen backend does not seem to support "
02227 "encryption; this should actually never happen, "
02228 "please report this bug.") );
02229 return Kpgp::Failure;
02230 }
02231
02232 const GpgME::EncryptionResult res =
02233 job->exec( encryptionKeys, cText, true , encryptedBody );
02234 {
02235 std::stringstream ss;
02236 ss << res;
02237 kdDebug(5006) << ss.str().c_str() << endl;
02238 }
02239 if ( res.error().isCanceled() ) {
02240 kdDebug() << "encryption was canceled by user" << endl;
02241 return Kpgp::Canceled;
02242 }
02243 if ( res.error() ) {
02244 kdDebug() << "encryption failed: " << res.error().asString() << endl;
02245 job->showErrorDialog( mComposeWin );
02246 return Kpgp::Failure;
02247 }
02248
02249 if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
02250 if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
02251 Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Encryption Operation") );
02252
02253 return Kpgp::Ok;
02254 }
02255
02256 Kpgp::Result MessageComposer::pgpSignedAndEncryptedMsg( TQByteArray & encryptedBody,
02257 const TQByteArray& cText,
02258 const std::vector<GpgME::Key> & signingKeys,
02259 const std::vector<GpgME::Key> & encryptionKeys,
02260 Kleo::CryptoMessageFormat format )
02261 {
02262
02263 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
02264 assert( cpf );
02265 const Kleo::CryptoBackend::Protocol * proto
02266 = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
02267 assert( proto );
02268
02269 std::auto_ptr<Kleo::SignEncryptJob> job( proto->signEncryptJob( armor( format ),
02270 textMode( format ) ) );
02271 if ( !job.get() ) {
02272 KMessageBox::sorry( mComposeWin,
02273 i18n("This message could not be signed and encrypted, "
02274 "since the chosen backend does not seem to support "
02275 "combined signing and encryption; this should actually never happen, "
02276 "please report this bug.") );
02277 return Kpgp::Failure;
02278 }
02279
02280 const std::pair<GpgME::SigningResult,GpgME::EncryptionResult> res =
02281 job->exec( signingKeys, encryptionKeys, cText, false, encryptedBody );
02282 {
02283 std::stringstream ss;
02284 ss << res.first << '\n' << res.second;
02285 kdDebug(5006) << ss.str().c_str() << endl;
02286 }
02287 if ( res.first.error().isCanceled() || res.second.error().isCanceled() ) {
02288 kdDebug() << "encrypt/sign was canceled by user" << endl;
02289 return Kpgp::Canceled;
02290 }
02291 if ( res.first.error() || res.second.error() ) {
02292 if ( res.first.error() )
02293 kdDebug() << "signing failed: " << res.first.error().asString() << endl;
02294 else
02295 kdDebug() << "encryption failed: " << res.second.error().asString() << endl;
02296 job->showErrorDialog( mComposeWin );
02297 return Kpgp::Failure;
02298 }
02299
02300 if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
02301 if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
02302 Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Encryption Operation") );
02303
02304 return Kpgp::Ok;
02305 }
02306
02307
02308 #include "messagecomposer.moc"