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