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