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 "klistboxdialog.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 <kmessagebox.h>
00073 #include <klocale.h>
00074 #include <kinputdialog.h>
00075 #include <kdebug.h>
00076 #include <kaction.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 KConfigGroup group( KMKernel::config(), "Composer" );
00097 return group.readBoolEntry( "crypto-warning-unsigned", false );
00098 }
00099 static inline bool warnSendUnencrypted() {
00100 KConfigGroup group( KMKernel::config(), "Composer" );
00101 return group.readBoolEntry( "crypto-warning-unencrypted", false );
00102 }
00103 static inline bool saveMessagesEncrypted() {
00104 KConfigGroup group( KMKernel::config(), "Composer" );
00105 return group.readBoolEntry( "crypto-store-encrypted", true );
00106 }
00107 static inline bool encryptToSelf() {
00108
00109 KConfigGroup group( KMKernel::config(), "Composer" );
00110 return group.readBoolEntry( "crypto-encrypt-to-self", true );
00111 }
00112 static inline bool showKeyApprovalDialog() {
00113 KConfigGroup group( KMKernel::config(), "Composer" );
00114 return group.readBoolEntry( "crypto-show-keys-for-approval", true );
00115 }
00116
00117 static inline int encryptKeyNearExpiryWarningThresholdInDays() {
00118 const KConfigGroup 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 KConfigGroup 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 KConfigGroup 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 KConfigGroup 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 KConfigGroup 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 KConfigGroup 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() == Qt::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 mOldBodyPart.setCharset(mCharset);
01255 addBodyAndAttachments( msg, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
01256 mMessageList.push_back( msg );
01257 if ( it == splitInfos.begin() ) {
01258 if ( doEncrypt && !saveMessagesEncrypted() ) {
01259 mOldBodyPart.setBodyEncodedBinary( bodyData );
01260 KMMessage* msgUnenc = new KMMessage( theMessage );
01261 addBodyAndAttachments( msgUnenc, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
01262 msg->setUnencryptedMsg( msgUnenc );
01263 }
01264 }
01265 }
01266 }
01267
01268
01269 void MessageComposer::composeChiasmusMessage( KMMessage& theMessage, Kleo::CryptoMessageFormat format )
01270 {
01271 assert( !GlobalSettings::chiasmusKey().isEmpty() );
01272 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
01273 assert( cpf );
01274 const Kleo::CryptoBackend::Protocol * chiasmus
01275 = cpf->protocol( "Chiasmus" );
01276 assert( chiasmus );
01277
01278
01279 const TQByteArray bodyData = mText;
01280 if (bodyData.isNull()) {
01281 mRc = false;
01282 return;
01283 }
01284
01285 mNewBodyPart = 0;
01286 mEarlyAddAttachments = false;
01287 mAllAttachmentsAreInBody = false;
01288
01289
01290 theMessage.deleteBodyParts();
01291 TQString oldContentType = theMessage.headerField( "Content-Type" );
01292 theMessage.removeHeaderField("Content-Type");
01293 theMessage.removeHeaderField("Content-Transfer-Encoding");
01294
01295
01296
01297 const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
01298 = mKeyResolver->encryptionItems( format );
01299 assert( splitInfos.size() == 1 );
01300 for ( std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it = splitInfos.begin() ; it != splitInfos.end() ; ++it )
01301 {
01302 const Kleo::KeyResolver::SplitInfo& splitInfo = *it;
01303 KMMessage* msg = new KMMessage( theMessage );
01304 TQByteArray encryptedBody;
01305
01306 if ( !encryptWithChiasmus( chiasmus, bodyData, encryptedBody ) ) {
01307 mRc = false;
01308 return;
01309 }
01310 assert( !encryptedBody.isNull() );
01311
01312
01313
01314 bool doSign = false;
01315 TQValueList<int> allowedCTEs;
01316 mOldBodyPart.setBodyAndGuessCte( encryptedBody, allowedCTEs,
01317 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
01318 doSign );
01319
01320
01321 mOldBodyPart.setContentDisposition( "inline" );
01322
01323 mOldBodyPart.setOriginalContentTypeStr( "application/vnd.de.bund.bsi.chiasmus-text;chiasmus-charset=" + mCharset );
01324
01325 mOldBodyPart.setTypeStr( "application" );
01326 mOldBodyPart.setSubtypeStr( "vnd.de.bund.bsi.chiasmus-text" );
01327 mOldBodyPart.setAdditionalCTypeParamStr( TQCString( "chiasmus-charset=" + mCharset ) );
01328 addBodyAndAttachments( msg, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
01329 mMessageList.push_back( msg );
01330
01331 if ( it == splitInfos.begin() && !saveMessagesEncrypted() ) {
01332 mOldBodyPart.setBodyEncodedBinary( bodyData );
01333 KMMessage* msgUnenc = new KMMessage( theMessage );
01334 addBodyAndAttachments( msgUnenc, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
01335 msg->setUnencryptedMsg( msgUnenc );
01336 }
01337 }
01338 }
01339
01340 void MessageComposer::composeMessage( KMMessage& theMessage,
01341 bool doSign, bool doEncrypt,
01342 Kleo::CryptoMessageFormat format )
01343 {
01344 #ifdef DEBUG
01345 kdDebug(5006) << "entering KMComposeWin::composeMessage" << endl;
01346 #endif
01347 if ( format == Kleo::InlineOpenPGPFormat ) {
01348 composeInlineOpenPGPMessage( theMessage, doSign, doEncrypt );
01349 return;
01350 }
01351
01352 if ( mEncryptWithChiasmus )
01353 {
01354 composeChiasmusMessage( theMessage, format );
01355 return;
01356 }
01357
01358
01359
01360 theMessage.setBody( "This message is in MIME format." );
01361
01362
01363 TQByteArray bodyData = mText;
01364 if (bodyData.isNull()) {
01365 mRc = false;
01366 return;
01367 }
01368
01369
01370 TQString oldContentType = theMessage.headerField( "Content-Type" );
01371 theMessage.deleteBodyParts();
01372 theMessage.removeHeaderField("Content-Type");
01373 theMessage.removeHeaderField("Content-Transfer-Encoding");
01374 theMessage.setAutomaticFields(true);
01375
01376
01377 mNewBodyPart = new KMMessagePart;
01378
01379
01380 mPreviousBoundaryLevel = 0;
01381
01382
01383 const bool doEncryptBody = doEncrypt && mEncryptBody;
01384 const bool doSignBody = doSign && mSignBody;
01385
01386
01387
01388 mEarlyAddAttachments = !mAttachments.empty() && ( doSignBody || doEncryptBody );
01389
01390 mAllAttachmentsAreInBody = mEarlyAddAttachments;
01391
01392
01393 if( mEarlyAddAttachments ) {
01394 bool someOk = false;
01395 for ( TQValueVector<Attachment>::const_iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
01396 if ( it->encrypt == doEncryptBody && it->sign == doSignBody )
01397 someOk = true;
01398 else
01399 mAllAttachmentsAreInBody = false;
01400 }
01401 if( !mAllAttachmentsAreInBody && !someOk )
01402 mEarlyAddAttachments = false;
01403 }
01404
01405 kdDebug(5006) << "mEarlyAddAttachments=" << mEarlyAddAttachments << " mAllAttachmentsAreInBody=" << mAllAttachmentsAreInBody << endl;
01406
01407
01408 mMultipartMixedBoundary = "";
01409 if ( mEarlyAddAttachments ) {
01410 mOldBodyPart.setTypeStr( "multipart" );
01411 mOldBodyPart.setSubtypeStr( "mixed" );
01412
01413 DwMediaType tmpCT;
01414 tmpCT.CreateBoundary( ++mPreviousBoundaryLevel );
01415 mMultipartMixedBoundary = tmpCT.Boundary().c_str();
01416 }
01417 else if ( mIsRichText ) {
01418 mOldBodyPart.setTypeStr( "multipart" );
01419 mOldBodyPart.setSubtypeStr( "alternative" );
01420 }
01421 else
01422 mOldBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
01423
01424 mOldBodyPart.setContentDisposition( "inline" );
01425
01426 if ( mIsRichText ) {
01427
01428 TQCString boundaryCStr;
01429 TQCString newbody;
01430 DwMediaType tmpCT;
01431 tmpCT.CreateBoundary( ++mPreviousBoundaryLevel );
01432 boundaryCStr = KMail::Util::CString( tmpCT.Boundary() );
01433 TQValueList<int> allowedCTEs;
01434
01435 KMMessagePart textBodyPart;
01436 textBodyPart.setTypeStr("text");
01437 textBodyPart.setSubtypeStr("plain");
01438
01439 TQCString textbody = plainTextFromMarkup( mText );
01440
01441
01442 textBodyPart.setBodyAndGuessCte( textbody, allowedCTEs,
01443 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
01444 doSign );
01445 textBodyPart.setCharset( mCharset );
01446 textBodyPart.setBodyEncoded( textbody );
01447 DwBodyPart* textDwPart = theMessage.createDWBodyPart( &textBodyPart );
01448 textDwPart->Assemble();
01449 newbody += "--";
01450 newbody += boundaryCStr;
01451 newbody += "\n";
01452 newbody += textDwPart->AsString().c_str();
01453 delete textDwPart;
01454 textDwPart = 0;
01455
01456 KMMessagePart htmlBodyPart;
01457 htmlBodyPart.setTypeStr("text");
01458 htmlBodyPart.setSubtypeStr("html");
01459 TQByteArray htmlbody = mText;
01460
01461 htmlBodyPart.setBodyAndGuessCte( htmlbody, allowedCTEs,
01462 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
01463 doSign );
01464 htmlBodyPart.setCharset( mCharset );
01465 htmlBodyPart.setBodyEncodedBinary( htmlbody );
01466 DwBodyPart* htmlDwPart = theMessage.createDWBodyPart( &htmlBodyPart );
01467 htmlDwPart->Assemble();
01468 newbody += "\n--";
01469 newbody += boundaryCStr;
01470 newbody += "\n";
01471 newbody += htmlDwPart->AsString().c_str();
01472 delete htmlDwPart;
01473 htmlDwPart = 0;
01474
01475 newbody += "--";
01476 newbody += boundaryCStr;
01477 newbody += "--\n";
01478 bodyData = KMail::Util::byteArrayFromQCStringNoDetach( newbody );
01479 mOldBodyPart.setBodyEncodedBinary( bodyData );
01480
01481 mSaveBoundary = tmpCT.Boundary();
01482 }
01483
01484
01485 for ( TQValueVector<Attachment>::const_iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
01486
01487
01488
01489
01490
01491
01492
01493 if( it->sign || it->encrypt ) {
01494 TQCString cte = it->part->cteStr().lower();
01495 if( ( "8bit" == cte && it->part->type() != DwMime::kTypeMessage )
01496 || ( ( it->part->type() == DwMime::kTypeText )
01497 && ( "7bit" == cte ) ) ) {
01498 const TQByteArray body = it->part->bodyDecodedBinary();
01499 TQValueList<int> dummy;
01500 it->part->setBodyAndGuessCte(body, dummy, false, it->sign);
01501 kdDebug(5006) << "Changed encoding of message part from "
01502 << cte << " to " << it->part->cteStr() << endl;
01503 }
01504 }
01505 }
01506
01507 if( mEarlyAddAttachments ) {
01508
01509 KMMessagePart innerBodyPart;
01510 if ( mIsRichText ) {
01511 innerBodyPart.setTypeStr( "multipart");
01512 innerBodyPart.setSubtypeStr("alternative");
01513 }
01514 else {
01515 innerBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
01516 }
01517 innerBodyPart.setContentDisposition( "inline" );
01518 TQValueList<int> allowedCTEs;
01519
01520 innerBodyPart.setBodyAndGuessCte( bodyData, allowedCTEs,
01521 !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
01522 doSign );
01523 if ( !mIsRichText )
01524 innerBodyPart.setCharset( mCharset );
01525 innerBodyPart.setBodyEncodedBinary( bodyData );
01526 DwBodyPart* innerDwPart = theMessage.createDWBodyPart( &innerBodyPart );
01527 innerDwPart->Assemble();
01528 TQByteArray tmpbody = KMail::Util::ByteArray( innerDwPart->AsString() );
01529 if ( mIsRichText ) {
01530 int boundPos = tmpbody.find( '\n' );
01531 if( -1 < boundPos ) {
01532 TQCString bStr( ";\n boundary=\"" );
01533 bStr += mSaveBoundary.c_str();
01534 bStr += "\"";
01535 bodyData = tmpbody;
01536 KMail::Util::insert( bodyData, boundPos, bStr );
01537 KMail::Util::insert( bodyData, 0, "--" + mMultipartMixedBoundary + "\n" );
01538 }
01539 }
01540 else {
01541 bodyData = tmpbody;
01542 KMail::Util::insert( bodyData, 0, "--" + mMultipartMixedBoundary + "\n" );
01543 }
01544 delete innerDwPart;
01545 innerDwPart = 0;
01546
01547
01548 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
01549 if ( it->encrypt == doEncryptBody && it->sign == doSignBody ) {
01550 innerDwPart = theMessage.createDWBodyPart( it->part );
01551 innerDwPart->Assemble();
01552 KMail::Util::append( bodyData, TQCString( "\n--" + mMultipartMixedBoundary + "\n" ) );
01553 KMail::Util::append( bodyData, innerDwPart->AsString().c_str() );
01554 delete innerDwPart;
01555 innerDwPart = 0;
01556 }
01557 }
01558 KMail::Util::append( bodyData, TQCString( "\n--" + mMultipartMixedBoundary + "--\n" ) );
01559 } else {
01560 TQValueList<int> allowedCTEs;
01561
01562 mOldBodyPart.setBodyAndGuessCte(bodyData, allowedCTEs, !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
01563 doSign);
01564 if ( !mIsRichText )
01565 mOldBodyPart.setCharset(mCharset);
01566 }
01567
01568 mOldBodyPart.setBodyEncodedBinary( bodyData );
01569
01570 if( doSignBody || doEncryptBody ) {
01571
01572
01573 DwBodyPart* dwPart;
01574 if ( mIsRichText && !mEarlyAddAttachments ) {
01575
01576
01577 dwPart = theMessage.createDWBodyPart( &mOldBodyPart );
01578 DwHeaders& headers = dwPart->Headers();
01579 DwMediaType& ct = headers.ContentType();
01580 ct.SetBoundary(mSaveBoundary);
01581 dwPart->Assemble();
01582 }
01583 else {
01584 dwPart = theMessage.createDWBodyPart( &mOldBodyPart );
01585 dwPart->Assemble();
01586 }
01587 mEncodedBody = KMail::Util::ByteArray( dwPart->AsString() );
01588 delete dwPart;
01589 dwPart = 0;
01590
01591
01592 if( !mMultipartMixedBoundary.isEmpty() ) {
01593 int boundPos = mEncodedBody.find( '\n' );
01594 if( -1 < boundPos ) {
01595
01596 TQCString bStr( ";\n boundary=\"" );
01597 bStr += mMultipartMixedBoundary;
01598 bStr += "\"";
01599 KMail::Util::insert( mEncodedBody, boundPos, bStr.data() );
01600 }
01601 }
01602
01603
01604
01605
01606 mEncodedBody = KMail::Util::lf2crlf( mEncodedBody );
01607 }
01608
01609 if ( doSignBody ) {
01610 mPerformingSignOperation = true;
01611 pgpSignedMsg( mEncodedBody, format );
01612 mPerformingSignOperation = false;
01613
01614 if ( mSignature.isEmpty() ) {
01615 kdDebug() << "signature was empty" << endl;
01616 mRc = false;
01617 return;
01618 }
01619 mRc = processStructuringInfo( TQString::null,
01620 mOldBodyPart.contentDescription(),
01621 mOldBodyPart.typeStr(),
01622 mOldBodyPart.subtypeStr(),
01623 mOldBodyPart.contentDisposition(),
01624 mOldBodyPart.contentTransferEncodingStr(),
01625 mEncodedBody, "signature",
01626 mSignature,
01627 *mNewBodyPart, true, format );
01628 if ( mRc ) {
01629 if ( !makeMultiPartSigned( format ) ) {
01630 mNewBodyPart->setCharset( mCharset );
01631 }
01632 } else
01633 KMessageBox::sorry( mComposeWin,
01634 mErrorProcessingStructuringInfo );
01635 }
01636
01637 if ( !mRc )
01638 return;
01639
01640 continueComposeMessage( theMessage, doSign, doEncrypt, format );
01641 }
01642
01643
01644 void MessageComposer::continueComposeMessage( KMMessage& theMessage,
01645 bool doSign, bool doEncrypt,
01646 Kleo::CryptoMessageFormat format )
01647 {
01648
01649 const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
01650 = mKeyResolver->encryptionItems( format );
01651 kdWarning( splitInfos.empty() )
01652 << "MessageComposer::continueComposeMessage(): splitInfos.empty() for "
01653 << Kleo::cryptoMessageFormatToString( format ) << endl;
01654
01655 if ( !splitInfos.empty() && doEncrypt && !saveMessagesEncrypted() ) {
01656 mJobs.push_front( new SetLastMessageAsUnencryptedVersionOfLastButOne( this ) );
01657 mJobs.push_front( new EncryptMessageJob( new KMMessage( theMessage ),
01658 Kleo::KeyResolver::SplitInfo( splitInfos.front().recipients ), doSign,
01659 false, mEncodedBody,
01660 mPreviousBoundaryLevel,
01661 mNewBodyPart,
01662 format, this ) );
01663 }
01664
01665 for ( std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it = splitInfos.begin() ; it != splitInfos.end() ; ++it )
01666 mJobs.push_front( new EncryptMessageJob( new KMMessage( theMessage ), *it, doSign,
01667 doEncrypt, mEncodedBody,
01668 mPreviousBoundaryLevel,
01669 mNewBodyPart,
01670 format, this ) );
01671 }
01672
01673 void MessageComposer::encryptMessage( KMMessage* msg,
01674 const Kleo::KeyResolver::SplitInfo & splitInfo,
01675 bool doSign, bool doEncrypt,
01676 KMMessagePart newBodyPart,
01677 Kleo::CryptoMessageFormat format )
01678 {
01679 if ( doEncrypt && splitInfo.keys.empty() ) {
01680
01681
01682
01683 doEncrypt = false;
01684 }
01685
01686 const bool doEncryptBody = doEncrypt && mEncryptBody;
01687 const bool doSignBody = doSign && mSignBody;
01688
01689 if ( doEncryptBody ) {
01690 TQByteArray innerContent;
01691 if ( doSignBody ) {
01692
01693 DwBodyPart* dwPart = msg->createDWBodyPart( &newBodyPart );
01694 dwPart->Assemble();
01695 innerContent = KMail::Util::ByteArray( dwPart->AsString() );
01696 delete dwPart;
01697 dwPart = 0;
01698 } else {
01699 innerContent = mEncodedBody;
01700 }
01701
01702
01703
01704
01705
01706 innerContent = KMail::Util::lf2crlf( innerContent );
01707
01708
01709 TQByteArray encryptedBody;
01710 Kpgp::Result result = pgpEncryptedMsg( encryptedBody, innerContent,
01711 splitInfo.keys, format );
01712 if ( result != Kpgp::Ok ) {
01713 mRc = false;
01714 return;
01715 }
01716 mRc = processStructuringInfo( "http://www.gnupg.org/aegypten/",
01717 newBodyPart.contentDescription(),
01718 newBodyPart.typeStr(),
01719 newBodyPart.subtypeStr(),
01720 newBodyPart.contentDisposition(),
01721 newBodyPart.contentTransferEncodingStr(),
01722 innerContent,
01723 "encrypted data",
01724 encryptedBody,
01725 newBodyPart, false, format );
01726 if ( !mRc )
01727 KMessageBox::sorry(mComposeWin, mErrorProcessingStructuringInfo);
01728 }
01729
01730
01731 if( mRc ) {
01732 const bool useNewBodyPart = doSignBody || doEncryptBody;
01733 addBodyAndAttachments( msg, splitInfo, doSign, doEncrypt,
01734 useNewBodyPart ? newBodyPart : mOldBodyPart, format );
01735 }
01736 }
01737
01738 void MessageComposer::addBodyAndAttachments( KMMessage* msg,
01739 const Kleo::KeyResolver::SplitInfo & splitInfo,
01740 bool doSign, bool doEncrypt,
01741 const KMMessagePart& ourFineBodyPart,
01742 Kleo::CryptoMessageFormat format )
01743 {
01744 const bool doEncryptBody = doEncrypt && mEncryptBody;
01745 const bool doSignBody = doSign && mSignBody;
01746
01747 if( !mAttachments.empty()
01748 && ( !mEarlyAddAttachments || !mAllAttachmentsAreInBody ) ) {
01749
01750 msg->headers().ContentType().SetType( DwMime::kTypeMultipart );
01751 msg->headers().ContentType().SetSubtype( DwMime::kSubtypeMixed );
01752 msg->headers().ContentType().CreateBoundary( 0 );
01753 kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : set top level Content-Type to Multipart/Mixed" << endl;
01754
01755
01756 DwBodyPart* tmpDwPart = msg->createDWBodyPart( &ourFineBodyPart );
01757 DwHeaders& headers = tmpDwPart->Headers();
01758 DwMediaType& ct = headers.ContentType();
01759 if ( !mSaveBoundary.empty() )
01760 ct.SetBoundary(mSaveBoundary);
01761 tmpDwPart->Assemble();
01762
01763
01764
01765 msg->addDwBodyPart(tmpDwPart);
01766
01767
01768
01769 KMMessagePart newAttachPart;
01770 for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
01771
01772 const bool cryptFlagsDifferent = ( it->encrypt != doEncryptBody || it->sign != doSignBody ) ;
01773
01774 if ( !cryptFlagsDifferent && mEarlyAddAttachments )
01775 continue;
01776
01777 const bool encryptThisNow = doEncrypt && cryptFlagsDifferent && it->encrypt ;
01778 const bool signThisNow = doSign && cryptFlagsDifferent && it->sign ;
01779
01780 if ( !encryptThisNow && !signThisNow ) {
01781 msg->addBodyPart( it->part );
01782
01783 (void)msg->asDwMessage();
01784 continue;
01785 }
01786
01787 KMMessagePart& rEncryptMessagePart( *it->part );
01788
01789 DwBodyPart* innerDwPart = msg->createDWBodyPart( it->part );
01790 innerDwPart->Assemble();
01791 TQByteArray encodedAttachment = KMail::Util::ByteArray( innerDwPart->AsString() );
01792 delete innerDwPart;
01793 innerDwPart = 0;
01794
01795
01796
01797
01798 encodedAttachment = KMail::Util::lf2crlf( encodedAttachment );
01799
01800
01801 if( signThisNow ) {
01802 pgpSignedMsg( encodedAttachment, format );
01803 mRc = !mSignature.isEmpty();
01804 if( mRc ) {
01805 mRc = processStructuringInfo( "http://www.gnupg.org/aegypten/",
01806 it->part->contentDescription(),
01807 it->part->typeStr(),
01808 it->part->subtypeStr(),
01809 it->part->contentDisposition(),
01810 it->part->contentTransferEncodingStr(),
01811 encodedAttachment,
01812 "signature",
01813 mSignature,
01814 newAttachPart, true, format );
01815 if( mRc ) {
01816 if( encryptThisNow ) {
01817 rEncryptMessagePart = newAttachPart;
01818 DwBodyPart* dwPart = msg->createDWBodyPart( &newAttachPart );
01819 dwPart->Assemble();
01820 encodedAttachment = KMail::Util::ByteArray( dwPart->AsString() );
01821 delete dwPart;
01822 dwPart = 0;
01823 }
01824 } else
01825 KMessageBox::sorry( mComposeWin, mErrorProcessingStructuringInfo );
01826 } else {
01827
01828 break;
01829 }
01830 }
01831 if( encryptThisNow ) {
01832 TQByteArray encryptedBody;
01833 Kpgp::Result result = pgpEncryptedMsg( encryptedBody,
01834 encodedAttachment,
01835 splitInfo.keys,
01836 format );
01837
01838 if( Kpgp::Ok == result ) {
01839 mRc = processStructuringInfo( "http://www.gnupg.org/aegypten/",
01840 rEncryptMessagePart.contentDescription(),
01841 rEncryptMessagePart.typeStr(),
01842 rEncryptMessagePart.subtypeStr(),
01843 rEncryptMessagePart.contentDisposition(),
01844 rEncryptMessagePart.contentTransferEncodingStr(),
01845 encodedAttachment,
01846 "encrypted data",
01847 encryptedBody,
01848 newAttachPart, false, format );
01849 if ( !mRc )
01850 KMessageBox::sorry( mComposeWin, mErrorProcessingStructuringInfo );
01851 } else
01852 mRc = false;
01853 }
01854 msg->addBodyPart( &newAttachPart );
01855 (void)msg->asDwMessage();
01856 }
01857 } else {
01858 if( ourFineBodyPart.originalContentTypeStr() ) {
01859 msg->headers().ContentType().FromString( ourFineBodyPart.originalContentTypeStr() );
01860 msg->headers().ContentType().Parse();
01861 kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : set top level Content-Type from originalContentTypeStr()=" << ourFineBodyPart.originalContentTypeStr() << endl;
01862 } else {
01863 TQCString ct = ourFineBodyPart.typeStr() + "/" + ourFineBodyPart.subtypeStr();
01864 if ( ct == "multipart/mixed" )
01865 ct += ";\n\tboundary=\"" + mMultipartMixedBoundary + '"';
01866 else if ( ct == "multipart/alternative" )
01867 ct += ";\n\tboundary=\"" + TQCString(mSaveBoundary.c_str()) + '"';
01868 msg->headers().ContentType().FromString( ct );
01869 msg->headers().ContentType().Parse();
01870 kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : set top level Content-Type to " << ct << endl;
01871 }
01872 if ( !ourFineBodyPart.charset().isEmpty() )
01873 msg->setCharset( ourFineBodyPart.charset() );
01874 msg->setHeaderField( "Content-Transfer-Encoding",
01875 ourFineBodyPart.contentTransferEncodingStr() );
01876 msg->setHeaderField( "Content-Description",
01877 ourFineBodyPart.contentDescription() );
01878 msg->setHeaderField( "Content-Disposition",
01879 ourFineBodyPart.contentDisposition() );
01880
01881 if ( mDebugComposerCrypto )
01882 kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : top level headers and body adjusted" << endl;
01883
01884
01885 msg->setBody( ourFineBodyPart.dwBody() );
01886
01887 }
01888
01889 msg->setHeaderField( "X-KMail-Recipients",
01890 splitInfo.recipients.join(", "), KMMessage::Address );
01891
01892 if ( mDebugComposerCrypto ) {
01893 kdDebug(5006) << "MessageComposer::addBodyAndAttachments():\n Final message:\n|||" << msg->asString() << "|||\n\n" << endl;
01894 msg->headers().Assemble();
01895 kdDebug(5006) << "\n\n\nMessageComposer::addBodyAndAttachments():\n Final headers:\n\n" << msg->headerAsString() << "|||\n\n\n\n\n" << endl;
01896 }
01897 }
01898
01899
01900
01901 bool MessageComposer::processStructuringInfo( const TQString bugURL,
01902 const TQString contentDescClear,
01903 const TQCString contentTypeClear,
01904 const TQCString contentSubtypeClear,
01905 const TQCString contentDispClear,
01906 const TQCString contentTEncClear,
01907 const TQByteArray& clearCStr,
01908 const TQString ,
01909 const TQByteArray& ciphertext,
01910 KMMessagePart& resultingPart,
01911 bool signing, Kleo::CryptoMessageFormat format )
01912 {
01913 assert( clearCStr.isEmpty() || clearCStr[clearCStr.size()-1] != '\0' );
01914 bool bOk = true;
01915
01916 if ( makeMimeObject( format, signing ) ) {
01917 TQCString mainHeader = "Content-Type: ";
01918 const char * toplevelCT = toplevelContentType( format, signing );
01919 if ( toplevelCT )
01920 mainHeader += toplevelCT;
01921 else {
01922 if( makeMultiMime( format, signing ) )
01923 mainHeader += "text/plain";
01924 else
01925 mainHeader += contentTypeClear + '/' + contentSubtypeClear;
01926 }
01927
01928 const TQCString boundaryCStr = KMime::multiPartBoundary();
01929
01930 if ( makeMultiMime( format, signing ) )
01931 mainHeader.replace( "%boundary", boundaryCStr );
01932
01933 if ( toplevelCT ) {
01934 if ( const char * str = toplevelContentDisposition( format, signing ) ) {
01935 mainHeader += "\nContent-Disposition: ";
01936 mainHeader += str;
01937 }
01938 if ( !makeMultiMime( format, signing ) &&
01939 binaryHint( format ) )
01940 mainHeader += "\nContent-Transfer-Encoding: base64";
01941 } else {
01942 if( 0 < contentDispClear.length() ) {
01943 mainHeader += "\nContent-Disposition: ";
01944 mainHeader += contentDispClear;
01945 }
01946 if( 0 < contentTEncClear.length() ) {
01947 mainHeader += "\nContent-Transfer-Encoding: ";
01948 mainHeader += contentTEncClear;
01949 }
01950 }
01951
01952
01953
01954 DwString mainDwStr;
01955 mainDwStr = mainHeader + "\n\n";
01956 DwBodyPart mainDwPa( mainDwStr, 0 );
01957 mainDwPa.Parse();
01958 KMMessage::bodyPart( &mainDwPa, &resultingPart );
01959 if( !makeMultiMime( format, signing ) ) {
01960 if ( signing && includeCleartextWhenSigning( format ) ) {
01961 TQByteArray bodyText( clearCStr );
01962 KMail::Util::append( bodyText, "\n" );
01963 KMail::Util::append( bodyText, ciphertext );
01964 resultingPart.setBodyEncodedBinary( bodyText );
01965 } else {
01966 resultingPart.setBodyEncodedBinary( ciphertext );
01967 }
01968 } else {
01969
01970
01971
01972
01973 TQCString versCStr, codeCStr;
01974 if ( !signing && format == Kleo::OpenPGPMIMEFormat )
01975 versCStr =
01976 "Content-Type: application/pgp-encrypted\n"
01977 "Content-Disposition: attachment\n"
01978 "\n"
01979 "Version: 1";
01980
01981
01982
01983 const char * nestedCT = nestedContentType( format, signing );
01984 assert( nestedCT );
01985 codeCStr = "Content-Type: ";
01986 codeCStr += nestedCT;
01987 codeCStr += '\n';
01988 if ( const char * str = nestedContentDisposition( format, signing ) ) {
01989 codeCStr += "Content-Disposition: ";
01990 codeCStr += str;
01991 codeCStr += '\n';
01992 }
01993 if ( binaryHint( format ) ) {
01994 codeCStr += "Content-Transfer-Encoding: base64\n\n";
01995 codeCStr += KMime::Codec::codecForName( "base64" )->encodeToQCString( ciphertext );
01996 } else
01997 codeCStr += '\n' + TQCString( ciphertext.data(), ciphertext.size() + 1 );
01998
01999
02000 TQByteArray mainStr;
02001 KMail::Util::append( mainStr, "--" );
02002 KMail::Util::append( mainStr, boundaryCStr );
02003 if ( signing && includeCleartextWhenSigning( format ) &&
02004 !clearCStr.isEmpty() ) {
02005 KMail::Util::append( mainStr, "\n" );
02006
02007 KMail::Util::append( mainStr, clearCStr );
02008 KMail::Util::append( mainStr, "\n--" + boundaryCStr );
02009 }
02010 if ( !versCStr.isEmpty() )
02011 KMail::Util::append( mainStr, "\n" + versCStr + "\n--" + boundaryCStr );
02012 if( !codeCStr.isEmpty() )
02013 KMail::Util::append( mainStr, "\n" + codeCStr + "\n--" + boundaryCStr );
02014 KMail::Util::append( mainStr, "--\n" );
02015
02016
02017 resultingPart.setBodyEncodedBinary( mainStr );
02018 }
02019
02020 } else {
02021
02022 resultingPart.setContentDescription( contentDescClear );
02023 resultingPart.setTypeStr( contentTypeClear );
02024 resultingPart.setSubtypeStr( contentSubtypeClear );
02025 resultingPart.setContentDisposition( contentDispClear );
02026 resultingPart.setContentTransferEncodingStr( contentTEncClear );
02027 TQByteArray resultingBody;
02028
02029 if ( signing && includeCleartextWhenSigning( format ) ) {
02030 if( !clearCStr.isEmpty() )
02031 KMail::Util::append( resultingBody, clearCStr );
02032 }
02033 if ( !ciphertext.isEmpty() )
02034 KMail::Util::append( resultingBody, ciphertext );
02035 else {
02036
02037 KMessageBox::sorry( mComposeWin,
02038 i18n( "<qt><p>Error: The backend did not return "
02039 "any encoded data.</p>"
02040 "<p>Please report this bug:<br>%2</p></qt>" )
02041 .arg( bugURL ) );
02042 bOk = false;
02043 }
02044 resultingPart.setBodyEncodedBinary( resultingBody );
02045 }
02046
02047 return bOk;
02048 }
02049
02050
02051 TQCString MessageComposer::plainTextFromMarkup( const TQString& markupText )
02052 {
02053 TQTextEdit *hackConspiratorTextEdit = new TQTextEdit( markupText );
02054 hackConspiratorTextEdit->setTextFormat(Qt::PlainText);
02055 if ( !mDisableBreaking ) {
02056 hackConspiratorTextEdit->setWordWrap( TQTextEdit::FixedColumnWidth );
02057 hackConspiratorTextEdit->setWrapColumnOrWidth( mLineBreakColumn );
02058 }
02059 TQString text = hackConspiratorTextEdit->text();
02060 TQCString textbody;
02061
02062 const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
02063 if( mCharset == "us-ascii" ) {
02064 textbody = KMMsgBase::toUsAscii( text );
02065 } else if( codec == 0 ) {
02066 kdDebug(5006) << "Something is wrong and I can not get a codec." << endl;
02067 textbody = text.local8Bit();
02068 } else {
02069 text = codec->toUnicode( text.latin1(), text.length() );
02070 textbody = codec->fromUnicode( text );
02071 }
02072 if (textbody.isNull()) textbody = "";
02073
02074 delete hackConspiratorTextEdit;
02075 return textbody;
02076 }
02077
02078
02079 TQByteArray MessageComposer::breakLinesAndApplyCodec()
02080 {
02081 TQString text;
02082 TQCString cText;
02083
02084 if( mDisableBreaking || mIsRichText || !GlobalSettings::self()->wordWrap() )
02085 text = mComposeWin->mEditor->text();
02086 else
02087 text = mComposeWin->mEditor->brokenText();
02088 text.truncate( text.length() );
02089
02090 TQString newText;
02091 const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
02092
02093 if( mCharset == "us-ascii" ) {
02094 cText = KMMsgBase::toUsAscii( text );
02095 newText = TQString::fromLatin1( cText );
02096 } else if( codec == 0 ) {
02097 kdDebug(5006) << "Something is wrong and I can not get a codec." << endl;
02098 cText = text.local8Bit();
02099 newText = TQString::fromLocal8Bit( cText );
02100 } else {
02101 cText = codec->fromUnicode( text );
02102 newText = codec->toUnicode( cText );
02103 }
02104 if (cText.isNull()) cText = "";
02105
02106 if( !text.isEmpty() && (newText != text) ) {
02107 TQString oldText = mComposeWin->mEditor->text();
02108 mComposeWin->mEditor->setText( newText );
02109 KCursorSaver idle( KBusyPtr::idle() );
02110 bool anyway = ( KMessageBox::warningYesNo( mComposeWin,
02111 i18n("<qt>Not all characters fit into the chosen"
02112 " encoding.<br><br>Send the message anyway?</qt>"),
02113 i18n("Some Characters Will Be Lost"),
02114 i18n("Lose Characters"), i18n("Change Encoding") ) == KMessageBox::Yes );
02115 if( !anyway ) {
02116 mComposeWin->mEditor->setText(oldText);
02117 return TQByteArray();
02118 }
02119 }
02120
02121
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132 if( cText.isEmpty() || cText[cText.length()-1] != '\n' ) {
02133 kdDebug(5006) << "Added an <LF> on the last line" << endl;
02134 cText += "\n";
02135 }
02136 return KMail::Util::byteArrayFromQCStringNoDetach( cText );
02137 }
02138
02139
02140
02141 void MessageComposer::pgpSignedMsg( const TQByteArray& cText, Kleo::CryptoMessageFormat format ) {
02142
02143 assert( cText.isEmpty() || cText[cText.size()-1] != '\0' );
02144 mSignature = TQByteArray();
02145
02146 const std::vector<GpgME::Key> signingKeys = mKeyResolver->signingKeys( format );
02147 if ( signingKeys.empty() ) {
02148 KMessageBox::sorry( mComposeWin,
02149 i18n("This message could not be signed, "
02150 "since no valid signing keys have been found; "
02151 "this should actually never happen, "
02152 "please report this bug.") );
02153 return;
02154 }
02155
02156
02157 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
02158 assert( cpf );
02159 const Kleo::CryptoBackend::Protocol * proto
02160 = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
02161 assert( proto );
02162
02163 std::auto_ptr<Kleo::SignJob> job( proto->signJob( armor( format ),
02164 textMode( format ) ) );
02165
02166 if ( !job.get() ) {
02167 KMessageBox::sorry( mComposeWin,
02168 i18n("This message could not be signed, "
02169 "since the chosen backend does not seem to support "
02170 "signing; this should actually never happen, "
02171 "please report this bug.") );
02172 return;
02173 }
02174
02175 TQByteArray signature;
02176 const GpgME::SigningResult res =
02177 job->exec( signingKeys, cText, signingMode( format ), signature );
02178 {
02179 std::stringstream ss;
02180 ss << res;
02181 kdDebug(5006) << ss.str().c_str() << endl;
02182 }
02183 if ( res.error().isCanceled() ) {
02184 kdDebug() << "signing was canceled by user" << endl;
02185 return;
02186 }
02187 if ( res.error() ) {
02188 kdDebug() << "signing failed: " << res.error().asString() << endl;
02189 job->showErrorDialog( mComposeWin );
02190 return;
02191 }
02192
02193 if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
02194 if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
02195 Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Signing Operation") );
02196
02197 mSignature = signature;
02198 if ( mSignature.isEmpty() ) {
02199 KMessageBox::sorry( mComposeWin,
02200 i18n( "The signing operation failed. "
02201 "Please make sure that the gpg-agent program "
02202 "is running." ) );
02203 }
02204 }
02205
02206
02207 Kpgp::Result MessageComposer::pgpEncryptedMsg( TQByteArray & encryptedBody,
02208 const TQByteArray& cText,
02209 const std::vector<GpgME::Key> & encryptionKeys,
02210 Kleo::CryptoMessageFormat format )
02211 {
02212
02213 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
02214 assert( cpf );
02215 const Kleo::CryptoBackend::Protocol * proto
02216 = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
02217 assert( proto );
02218
02219 std::auto_ptr<Kleo::EncryptJob> job( proto->encryptJob( armor( format ),
02220 textMode( format ) ) );
02221 if ( !job.get() ) {
02222 KMessageBox::sorry( mComposeWin,
02223 i18n("This message could not be encrypted, "
02224 "since the chosen backend does not seem to support "
02225 "encryption; this should actually never happen, "
02226 "please report this bug.") );
02227 return Kpgp::Failure;
02228 }
02229
02230 const GpgME::EncryptionResult res =
02231 job->exec( encryptionKeys, cText, true , encryptedBody );
02232 {
02233 std::stringstream ss;
02234 ss << res;
02235 kdDebug(5006) << ss.str().c_str() << endl;
02236 }
02237 if ( res.error().isCanceled() ) {
02238 kdDebug() << "encryption was canceled by user" << endl;
02239 return Kpgp::Canceled;
02240 }
02241 if ( res.error() ) {
02242 kdDebug() << "encryption failed: " << res.error().asString() << endl;
02243 job->showErrorDialog( mComposeWin );
02244 return Kpgp::Failure;
02245 }
02246
02247 if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
02248 if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
02249 Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Encryption Operation") );
02250
02251 return Kpgp::Ok;
02252 }
02253
02254 Kpgp::Result MessageComposer::pgpSignedAndEncryptedMsg( TQByteArray & encryptedBody,
02255 const TQByteArray& cText,
02256 const std::vector<GpgME::Key> & signingKeys,
02257 const std::vector<GpgME::Key> & encryptionKeys,
02258 Kleo::CryptoMessageFormat format )
02259 {
02260
02261 const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
02262 assert( cpf );
02263 const Kleo::CryptoBackend::Protocol * proto
02264 = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
02265 assert( proto );
02266
02267 std::auto_ptr<Kleo::SignEncryptJob> job( proto->signEncryptJob( armor( format ),
02268 textMode( format ) ) );
02269 if ( !job.get() ) {
02270 KMessageBox::sorry( mComposeWin,
02271 i18n("This message could not be signed and encrypted, "
02272 "since the chosen backend does not seem to support "
02273 "combined signing and encryption; this should actually never happen, "
02274 "please report this bug.") );
02275 return Kpgp::Failure;
02276 }
02277
02278 const std::pair<GpgME::SigningResult,GpgME::EncryptionResult> res =
02279 job->exec( signingKeys, encryptionKeys, cText, false, encryptedBody );
02280 {
02281 std::stringstream ss;
02282 ss << res.first << '\n' << res.second;
02283 kdDebug(5006) << ss.str().c_str() << endl;
02284 }
02285 if ( res.first.error().isCanceled() || res.second.error().isCanceled() ) {
02286 kdDebug() << "encrypt/sign was canceled by user" << endl;
02287 return Kpgp::Canceled;
02288 }
02289 if ( res.first.error() || res.second.error() ) {
02290 if ( res.first.error() )
02291 kdDebug() << "signing failed: " << res.first.error().asString() << endl;
02292 else
02293 kdDebug() << "encryption failed: " << res.second.error().asString() << endl;
02294 job->showErrorDialog( mComposeWin );
02295 return Kpgp::Failure;
02296 }
02297
02298 if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
02299 if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
02300 Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Encryption Operation") );
02301
02302 return Kpgp::Ok;
02303 }
02304
02305
02306 #include "messagecomposer.moc"