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