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