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