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