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