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