TDE personal information management applications
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2309 lines
85 KiB

  1. /**
  2. * messagecomposer.cpp
  3. *
  4. * Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; version 2 of the License
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. *
  19. * In addition, as a special exception, the copyright holders give
  20. * permission to link the code of this program with any edition of
  21. * the TQt library by Trolltech AS, Norway (or with modified versions
  22. * of TQt that use the same license as TQt), and distribute linked
  23. * combinations including the two. You must obey the GNU General
  24. * Public License in all respects for all of the code used other than
  25. * TQt. If you modify this file, you may extend this exception to
  26. * your version of the file, but you are not obligated to do so. If
  27. * you do not wish to do so, delete this exception statement from
  28. * your version.
  29. */
  30. #ifdef HAVE_CONFIG_H
  31. #include <config.h>
  32. #endif
  33. #include "messagecomposer.h"
  34. #include "kmmsgpart.h"
  35. #define REALLY_WANT_KMCOMPOSEWIN_H
  36. #include "kmcomposewin.h"
  37. #undef REALLY_WANT_KMCOMPOSEWIN_H
  38. #include "tdelistboxdialog.h"
  39. #include "kcursorsaver.h"
  40. #include "messagesender.h"
  41. #include "kmfolder.h"
  42. #include "kmfoldercombobox.h"
  43. #include "keyresolver.h"
  44. #include "kleo_util.h"
  45. #include "globalsettings.h"
  46. #include "custommimeheader.h"
  47. #include "kmedit.h"
  48. #include "util.h"
  49. #include <libkpimidentities/identity.h>
  50. #include <libkpimidentities/identitymanager.h>
  51. #include <libemailfunctions/email.h>
  52. #include <ui/keyselectiondialog.h>
  53. #include <ui/keyapprovaldialog.h>
  54. #include <ui/messagebox.h>
  55. #include <kleo/cryptobackendfactory.h>
  56. #include <kleo/keylistjob.h>
  57. #include <kleo/encryptjob.h>
  58. #include <kleo/signencryptjob.h>
  59. #include <kleo/signjob.h>
  60. #include <kleo/specialjob.h>
  61. #include <kmime_util.h>
  62. #include <kmime_codecs.h>
  63. #include <kpgpblock.h>
  64. #include <mimelib/mimepp.h>
  65. #include <tdemessagebox.h>
  66. #include <tdelocale.h>
  67. #include <kinputdialog.h>
  68. #include <kdebug.h>
  69. #include <tdeaction.h>
  70. #include <tqfile.h>
  71. #include <tqtextcodec.h>
  72. #include <tqtextedit.h>
  73. #include <tqtimer.h>
  74. #include <gpgmepp/key.h>
  75. #include <gpgmepp/keylistresult.h>
  76. #include <gpgmepp/encryptionresult.h>
  77. #include <gpgmepp/signingresult.h>
  78. #include <gpgmepp/context.h>
  79. #include <algorithm>
  80. #include <sstream>
  81. #include <memory>
  82. // ## keep default values in sync with configuredialog.cpp, Security::CryptoTab::setup()
  83. // This should be ported to a .kcfg one day I suppose (dfaure).
  84. static inline bool warnSendUnsigned() {
  85. TDEConfigGroup group( KMKernel::config(), "Composer" );
  86. return group.readBoolEntry( "crypto-warning-unsigned", false );
  87. }
  88. static inline bool warnSendUnencrypted() {
  89. TDEConfigGroup group( KMKernel::config(), "Composer" );
  90. return group.readBoolEntry( "crypto-warning-unencrypted", false );
  91. }
  92. static inline bool saveMessagesEncrypted() {
  93. TDEConfigGroup group( KMKernel::config(), "Composer" );
  94. return group.readBoolEntry( "crypto-store-encrypted", true );
  95. }
  96. static inline bool encryptToSelf() {
  97. // return !Kpgp::Module::getKpgp() || Kpgp::Module::getKpgp()->encryptToSelf();
  98. TDEConfigGroup group( KMKernel::config(), "Composer" );
  99. return group.readBoolEntry( "crypto-encrypt-to-self", true );
  100. }
  101. static inline bool showKeyApprovalDialog() {
  102. TDEConfigGroup group( KMKernel::config(), "Composer" );
  103. return group.readBoolEntry( "crypto-show-keys-for-approval", true );
  104. }
  105. static inline int encryptKeyNearExpiryWarningThresholdInDays() {
  106. const TDEConfigGroup composer( KMKernel::config(), "Composer" );
  107. if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
  108. return -1;
  109. const int num = composer.readNumEntry( "crypto-warn-encr-key-near-expire-int", 14 );
  110. return kMax( 1, num );
  111. }
  112. static inline int signingKeyNearExpiryWarningThresholdInDays() {
  113. const TDEConfigGroup composer( KMKernel::config(), "Composer" );
  114. if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
  115. return -1;
  116. const int num = composer.readNumEntry( "crypto-warn-sign-key-near-expire-int", 14 );
  117. return kMax( 1, num );
  118. }
  119. static inline int encryptRootCertNearExpiryWarningThresholdInDays() {
  120. const TDEConfigGroup composer( KMKernel::config(), "Composer" );
  121. if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
  122. return -1;
  123. const int num = composer.readNumEntry( "crypto-warn-encr-root-near-expire-int", 14 );
  124. return kMax( 1, num );
  125. }
  126. static inline int signingRootCertNearExpiryWarningThresholdInDays() {
  127. const TDEConfigGroup composer( KMKernel::config(), "Composer" );
  128. if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
  129. return -1;
  130. const int num = composer.readNumEntry( "crypto-warn-sign-root-near-expire-int", 14 );
  131. return kMax( 1, num );
  132. }
  133. static inline int encryptChainCertNearExpiryWarningThresholdInDays() {
  134. const TDEConfigGroup composer( KMKernel::config(), "Composer" );
  135. if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
  136. return -1;
  137. const int num = composer.readNumEntry( "crypto-warn-encr-chaincert-near-expire-int", 14 );
  138. return kMax( 1, num );
  139. }
  140. static inline int signingChainCertNearExpiryWarningThresholdInDays() {
  141. const TDEConfigGroup composer( KMKernel::config(), "Composer" );
  142. if ( ! composer.readBoolEntry( "crypto-warn-when-near-expire", true ) )
  143. return -1;
  144. const int num = composer.readNumEntry( "crypto-warn-sign-chaincert-near-expire-int", 14 );
  145. return kMax( 1, num );
  146. }
  147. /*
  148. Design of this:
  149. The idea is that the main run of applyChanges here makes two jobs:
  150. the first sets the flags for encryption/signing or not, and the other
  151. starts the encryption process.
  152. When a job is run, it has already been removed from the job queue. This
  153. means if one of the current jobs needs to add new jobs, it can add them
  154. to the front and that way control when new jobs are added.
  155. For example, the compose message job will add jobs that will do the
  156. actual encryption and signing.
  157. There are two types of jobs: synchronous and asynchronous:
  158. A synchronous job simply implments the execute() method and performs
  159. it's operation there and sets mComposer->mRc to false if the compose
  160. queue should be canceled.
  161. An asynchronous job only sets up and starts it's operation. Before
  162. returning, it connects to the result signals of the operation
  163. (e.g. Kleo::Job's result(...) signal) and sets mComposer->mHoldJobs
  164. to true. This makes the scheduler return to the event loop. The job
  165. is now responsible for giving control back to the scheduler by
  166. calling mComposer->doNextJob().
  167. */
  168. /*
  169. Test plan:
  170. For each message format (e.g. openPGP/MIME)
  171. 1. Body signed
  172. 2. Body encrypted
  173. 3. Body signed and encrypted
  174. 4. Body encrypted, attachments encrypted (they must be encrypted together, mEarlyAddAttachments)
  175. 5. Body encrypted, attachments not encrypted
  176. 6. Body encrypted, attachment encrypted and signed (separately)
  177. 7. Body not encrypted, one attachment encrypted+signed, one attachment encrypted only, one attachment signed only
  178. (https://intevation.de/roundup/aegypten/issue295)
  179. (this is the reason attachments can't be encrypted together)
  180. 8. Body and attachments encrypted+signed (they must be encrypted+signed together, mEarlyAddAttachments)
  181. 9. Body encrypted+signed, attachments encrypted
  182. 10. Body encrypted+signed, one attachment signed, one attachment not encrypted nor signed
  183. ...
  184. I recorded a KDExecutor script sending all of the above (David)
  185. Further tests (which test opportunistic encryption):
  186. 1. Send a message to a person with valid key but without encryption preference
  187. and answer the question whether the message should be encrypted with Yes.
  188. 2. Send a message to a person with valid key but without encryption preference
  189. and answer the question whether the message should be encrypted with No.
  190. 3. Send a message to a person with valid key and with encryption preference
  191. "Encrypt whenever possible" (aka opportunistic encryption).
  192. */
  193. static TQString mErrorProcessingStructuringInfo =
  194. i18n("<qt><p>Structuring information returned by the Crypto plug-in "
  195. "could not be processed correctly; the plug-in might be damaged.</p>"
  196. "<p>Please contact your system administrator.</p></qt>");
  197. static TQString mErrorNoCryptPlugAndNoBuildIn =
  198. i18n("<p>No active Crypto Plug-In was found and the built-in OpenPGP code "
  199. "did not run successfully.</p>"
  200. "<p>You can do two things to change this:</p>"
  201. "<ul><li><em>either</em> activate a Plug-In using the "
  202. "Settings->Configure KMail->Plug-In dialog.</li>"
  203. "<li><em>or</em> specify traditional OpenPGP settings on the same dialog's "
  204. "Identity->Advanced tab.</li></ul>");
  205. class MessageComposerJob {
  206. public:
  207. MessageComposerJob( MessageComposer* composer ) : mComposer( composer ) {}
  208. virtual ~MessageComposerJob() {}
  209. virtual void execute() = 0;
  210. protected:
  211. // These are the methods that call the private MessageComposer methods
  212. // Workaround for friend not being inherited
  213. void adjustCryptFlags() { mComposer->adjustCryptFlags(); }
  214. void composeMessage() { mComposer->composeMessage(); }
  215. void continueComposeMessage( KMMessage& msg, bool doSign, bool doEncrypt,
  216. Kleo::CryptoMessageFormat format )
  217. {
  218. mComposer->continueComposeMessage( msg, doSign, doEncrypt, format );
  219. }
  220. void chiasmusEncryptAllAttachments() {
  221. mComposer->chiasmusEncryptAllAttachments();
  222. }
  223. MessageComposer* mComposer;
  224. };
  225. class ChiasmusBodyPartEncryptJob : public MessageComposerJob {
  226. public:
  227. ChiasmusBodyPartEncryptJob( MessageComposer * composer )
  228. : MessageComposerJob( composer ) {}
  229. void execute() {
  230. chiasmusEncryptAllAttachments();
  231. }
  232. };
  233. class AdjustCryptFlagsJob : public MessageComposerJob {
  234. public:
  235. AdjustCryptFlagsJob( MessageComposer* composer )
  236. : MessageComposerJob( composer ) {}
  237. void execute() {
  238. adjustCryptFlags();
  239. }
  240. };
  241. class ComposeMessageJob : public MessageComposerJob {
  242. public:
  243. ComposeMessageJob( MessageComposer* composer )
  244. : MessageComposerJob( composer ) {}
  245. void execute() {
  246. composeMessage();
  247. }
  248. };
  249. MessageComposer::MessageComposer( KMComposeWin* win, const char* name )
  250. : TQObject( win, name ), mComposeWin( win ), mCurrentJob( 0 ),
  251. mReferenceMessage( 0 ), mKeyResolver( 0 ),
  252. mUseOpportunisticEncryption( false ),
  253. mSignBody( false ), mEncryptBody( false ),
  254. mSigningRequested( false ), mEncryptionRequested( false ),
  255. mDoSign( false ), mDoEncrypt( false ),
  256. mAllowedCryptoMessageFormats( 0 ),
  257. mDisableCrypto( false ),
  258. mDisableBreaking( false ),
  259. mDebugComposerCrypto( false ),
  260. mAutoCharset( true ),
  261. mIsRichText( false ),
  262. mIdentityUid( 0 ), mRc( true ),
  263. mHoldJobs( false ),
  264. mNewBodyPart( 0 ),
  265. mEarlyAddAttachments( false ), mAllAttachmentsAreInBody( false ),
  266. mPreviousBoundaryLevel( 0 ),
  267. mEncryptWithChiasmus( false ),
  268. mPerformingSignOperation( false )
  269. {
  270. }
  271. MessageComposer::~MessageComposer()
  272. {
  273. delete mKeyResolver; mKeyResolver = 0;
  274. delete mNewBodyPart; mNewBodyPart = 0;
  275. }
  276. void MessageComposer::applyChanges( bool disableCrypto )
  277. {
  278. // Do the initial setup
  279. if( getenv("KMAIL_DEBUG_COMPOSER_CRYPTO") != 0 ) {
  280. TQCString cE = getenv("KMAIL_DEBUG_COMPOSER_CRYPTO");
  281. mDebugComposerCrypto = cE == "1" || cE.upper() == "ON" || cE.upper() == "TRUE";
  282. kdDebug(5006) << "KMAIL_DEBUG_COMPOSER_CRYPTO = TRUE" << endl;
  283. } else {
  284. mDebugComposerCrypto = false;
  285. kdDebug(5006) << "KMAIL_DEBUG_COMPOSER_CRYPTO = FALSE" << endl;
  286. }
  287. mHoldJobs = false;
  288. mRc = true;
  289. mDisableCrypto = disableCrypto;
  290. // 1: Read everything from KMComposeWin and set all
  291. // trivial parts of the message
  292. readFromComposeWin();
  293. // From now on, we're not supposed to read from the composer win
  294. // TODO: Make it so ;-)
  295. // 1.5: Replace all body parts with their chiasmus-encrypted equivalent
  296. mJobs.push_back( new ChiasmusBodyPartEncryptJob( this ) );
  297. // 2: Set encryption/signing options and resolve keys
  298. mJobs.push_back( new AdjustCryptFlagsJob( this ) );
  299. // 3: Build the message (makes the crypto jobs also)
  300. mJobs.push_back( new ComposeMessageJob( this ) );
  301. // Finally: Run the jobs
  302. doNextJob();
  303. }
  304. void MessageComposer::doNextJob()
  305. {
  306. delete mCurrentJob; mCurrentJob = 0;
  307. if( mJobs.isEmpty() ) {
  308. // No more jobs. Signal that we're done
  309. emitDone( mRc );
  310. return;
  311. }
  312. if( !mRc ) {
  313. // Something has gone wrong - stop the process and bail out
  314. while( !mJobs.isEmpty() ) {
  315. delete mJobs.front();
  316. mJobs.pop_front();
  317. }
  318. emitDone( false );
  319. return;
  320. }
  321. // We have more jobs to do, but allow others to come first
  322. TQTimer::singleShot( 0, this, TQT_SLOT( slotDoNextJob() ) );
  323. }
  324. void MessageComposer::emitDone( bool b )
  325. {
  326. // Save memory - before sending the mail
  327. mEncodedBody = TQByteArray();
  328. delete mNewBodyPart; mNewBodyPart = 0;
  329. mOldBodyPart.clear();
  330. emit done( b );
  331. }
  332. void MessageComposer::slotDoNextJob()
  333. {
  334. assert( !mCurrentJob );
  335. if( mHoldJobs )
  336. // Always make it run from now. If more than one job should be held,
  337. // The individual jobs must do this.
  338. mHoldJobs = false;
  339. else {
  340. assert( !mJobs.empty() );
  341. // Get the next job
  342. mCurrentJob = mJobs.front();
  343. assert( mCurrentJob );
  344. mJobs.pop_front();
  345. // Execute it
  346. mCurrentJob->execute();
  347. }
  348. // Finally run the next job if necessary
  349. if( !mHoldJobs )
  350. doNextJob();
  351. }
  352. void MessageComposer::readFromComposeWin()
  353. {
  354. // Copy necessary attributes over
  355. mDisableBreaking = false;
  356. mSignBody = mComposeWin->mSignAction->isChecked();
  357. mSigningRequested = mSignBody; // for now; will be adjusted depending on attachments
  358. mEncryptBody = mComposeWin->mEncryptAction->isChecked();
  359. mEncryptionRequested = mEncryptBody; // for now; will be adjusted depending on attachments
  360. mAutoCharset = mComposeWin->mAutoCharset;
  361. mCharset = mComposeWin->mCharset;
  362. mReferenceMessage = mComposeWin->mMsg;
  363. // if the user made any modifications to the message then the Content-Type
  364. // of the message is no longer reliable (e. g. if he editted a draft/resent a
  365. // message and then removed all attachments or changed from PGP/MIME signed
  366. // to clearsigned);
  367. // even if the user didn't make any modifications to the message the
  368. // Content-Type of the message might be wrong, e.g. when inline-forwarding
  369. // an mp/alt message then the Content-Type is set to mp/alt although it should
  370. // be text/plain (cf. bug 127526);
  371. // OTOH we must not reset the Content-Type of inline invitations;
  372. // therefore we reset the Content-Type to text/plain whenever the current
  373. // Content-Type is multipart/*.
  374. if ( mReferenceMessage->type() == DwMime::kTypeMultipart )
  375. mReferenceMessage->setHeaderField( "Content-Type", "text/plain" );
  376. mUseOpportunisticEncryption = GlobalSettings::self()->pgpAutoEncrypt();
  377. mAllowedCryptoMessageFormats = mComposeWin->cryptoMessageFormat();
  378. if( mAutoCharset ) {
  379. TQCString charset = KMMsgBase::autoDetectCharset( mCharset, KMMessage::preferredCharsets(), mComposeWin->mEditor->text() );
  380. if( charset.isEmpty() )
  381. {
  382. KMessageBox::sorry( mComposeWin,
  383. i18n( "No suitable encoding could be found for "
  384. "your message.\nPlease set an encoding "
  385. "using the 'Options' menu." ) );
  386. mRc = false;
  387. return;
  388. }
  389. mCharset = charset;
  390. // Also apply this to the composer window
  391. mComposeWin->mCharset = charset;
  392. }
  393. mReferenceMessage->setCharset(mCharset);
  394. mReferenceMessage->setTo(mComposeWin->to());
  395. mReferenceMessage->setFrom(mComposeWin->from());
  396. mReferenceMessage->setCc(mComposeWin->cc());
  397. mReferenceMessage->setSubject(mComposeWin->subject());
  398. mReferenceMessage->setReplyTo(mComposeWin->replyTo());
  399. mReferenceMessage->setBcc(mComposeWin->bcc());
  400. const KPIM::Identity & id = mComposeWin->identity();
  401. KMFolder *f = mComposeWin->mFcc->getFolder();
  402. assert( f != 0 );
  403. if ( f->idString() == id.fcc() )
  404. mReferenceMessage->removeHeaderField("X-KMail-Fcc");
  405. else
  406. mReferenceMessage->setFcc( f->idString() );
  407. // set the correct drafts folder
  408. mReferenceMessage->setDrafts( id.drafts() );
  409. if (id.isDefault())
  410. mReferenceMessage->removeHeaderField("X-KMail-Identity");
  411. else mReferenceMessage->setHeaderField("X-KMail-Identity", TQString::number( id.uoid() ));
  412. TQString replyAddr;
  413. if (!mComposeWin->replyTo().isEmpty()) replyAddr = mComposeWin->replyTo();
  414. else replyAddr = mComposeWin->from();
  415. if (mComposeWin->mRequestMDNAction->isChecked())
  416. mReferenceMessage->setHeaderField("Disposition-Notification-To", replyAddr);
  417. else
  418. mReferenceMessage->removeHeaderField("Disposition-Notification-To");
  419. if (mComposeWin->mUrgentAction->isChecked()) {
  420. mReferenceMessage->setHeaderField("X-PRIORITY", "2 (High)");
  421. mReferenceMessage->setHeaderField("Priority", "urgent");
  422. } else {
  423. mReferenceMessage->removeHeaderField("X-PRIORITY");
  424. mReferenceMessage->removeHeaderField("Priority");
  425. }
  426. int num = GlobalSettings::self()->custHeaderCount();
  427. for(int ix=0; ix<num; ix++) {
  428. CustomMimeHeader customMimeHeader( TQString::number(ix) );
  429. customMimeHeader.readConfig();
  430. mReferenceMessage->setHeaderField(
  431. KMMsgBase::toUsAscii( customMimeHeader.custHeaderName() ),
  432. customMimeHeader.custHeaderValue() );
  433. }
  434. // we have to remember the Bcc because it might have been overwritten
  435. // by a custom header (therefore we can't use bcc() later) and because
  436. // mimelib removes addresses without domain part (therefore we can't use
  437. // mReferenceMessage->bcc() later and also not now. So get the Bcc from
  438. // the composer window.)
  439. mBcc = mComposeWin->bcc();
  440. mTo = KPIM::splitEmailAddrList( mComposeWin->to().stripWhiteSpace() );
  441. mCc = KPIM::splitEmailAddrList( mComposeWin->cc().stripWhiteSpace() );
  442. mBccList = KPIM::splitEmailAddrList( mBcc.stripWhiteSpace() );
  443. for ( unsigned int i = 0 ; i < mComposeWin->mAtmList.count() ; ++i )
  444. mAttachments.push_back( Attachment( mComposeWin->mAtmList.at(i),
  445. mComposeWin->signFlagOfAttachment( i ),
  446. mComposeWin->encryptFlagOfAttachment( i ) ) );
  447. mEncryptWithChiasmus = mComposeWin->mEncryptWithChiasmus;
  448. mIsRichText = mComposeWin->mEditor->textFormat() == TQt::RichText;
  449. mIdentityUid = mComposeWin->identityUid();
  450. mText = breakLinesAndApplyCodec();
  451. assert( mText.isEmpty() || mText[mText.size()-1] == '\n' );
  452. // Hopefully we can get rid of this eventually, it's needed to be able
  453. // to break the plain/text version of a multipart/alternative (html) mail
  454. // according to the line breaks of the richtext version.
  455. mLineBreakColumn = mComposeWin->mEditor->lineBreakColumn();
  456. }
  457. static TQCString escape_quoted_string( const TQCString & str ) {
  458. TQCString result;
  459. const unsigned int str_len = str.length();
  460. result.resize( 2*str_len + 1 );
  461. char * d = result.data();
  462. for ( unsigned int i = 0 ; i < str_len ; ++i )
  463. switch ( const char ch = str[i] ) {
  464. case '\\':
  465. case '"':
  466. *d++ = '\\';
  467. default: // fall through:
  468. *d++ = ch;
  469. }
  470. result.truncate( d - result.begin() );
  471. return result;
  472. }
  473. bool MessageComposer::encryptWithChiasmus( const Kleo::CryptoBackend::Protocol * chiasmus,
  474. const TQByteArray& body,
  475. TQByteArray& resultData )
  476. {
  477. std::auto_ptr<Kleo::SpecialJob> job( chiasmus->specialJob( "x-encrypt", TQStringVariantMap() ) );
  478. if ( !job.get() ) {
  479. const TQString msg = i18n( "Chiasmus backend does not offer the "
  480. "\"x-encrypt\" function. Please report this bug." );
  481. KMessageBox::error( mComposeWin, msg, i18n( "Chiasmus Backend Error" ) );
  482. return false;
  483. }
  484. if ( !job->setProperty( "key", GlobalSettings::chiasmusKey() ) ||
  485. !job->setProperty( "options", GlobalSettings::chiasmusOptions() ) ||
  486. !job->setProperty( "input", body ) ) {
  487. const TQString msg = i18n( "The \"x-encrypt\" function does not accept "
  488. "the expected parameters. Please report this bug." );
  489. KMessageBox::error( mComposeWin, msg, i18n( "Chiasmus Backend Error" ) );
  490. return false;
  491. }
  492. const GpgME::Error err = job->exec();
  493. if ( err.isCanceled() || err ) {
  494. if ( err )
  495. job->showErrorDialog( mComposeWin, i18n( "Chiasmus Encryption Error" ) );
  496. return false;
  497. }
  498. const TQVariant result = job->property( "result" );
  499. if ( result.type() != TQVariant::ByteArray ) {
  500. const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
  501. "The \"x-encrypt\" function did not return a "
  502. "byte array. Please report this bug." );
  503. KMessageBox::error( mComposeWin, msg, i18n( "Chiasmus Backend Error" ) );
  504. return false;
  505. }
  506. resultData = result.toByteArray();
  507. return true;
  508. }
  509. void MessageComposer::chiasmusEncryptAllAttachments() {
  510. if ( !mEncryptWithChiasmus )
  511. return;
  512. assert( !GlobalSettings::chiasmusKey().isEmpty() ); // kmcomposewin code should have made sure
  513. if ( mAttachments.empty() )
  514. return;
  515. const Kleo::CryptoBackend::Protocol * chiasmus
  516. = Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
  517. assert( chiasmus ); // kmcomposewin code should have made sure
  518. for ( TQValueVector<Attachment>::iterator it = mAttachments.begin(), end = mAttachments.end() ; it != end ; ++it ) {
  519. KMMessagePart * part = it->part;
  520. const TQString filename = part->fileName();
  521. if ( filename.endsWith( ".xia", false ) )
  522. continue; // already encrypted
  523. const TQByteArray body = part->bodyDecodedBinary();
  524. TQByteArray resultData;
  525. if ( !encryptWithChiasmus( chiasmus, body, resultData ) ) {
  526. mRc = false;
  527. return;
  528. }
  529. // everything ok, so let's fill in the part again:
  530. TQValueList<int> dummy;
  531. part->setBodyAndGuessCte( resultData, dummy );
  532. part->setTypeStr( "application" );
  533. part->setSubtypeStr( "vnd.de.bund.bsi.chiasmus" );
  534. part->setName( filename + ".xia" );
  535. const TQCString enc_name = KMMsgBase::encodeRFC2231StringAutoDetectCharset(
  536. filename + ".xia", part->charset() );
  537. const TQCString cDisp = "attachment;\n\tfilename"
  538. + ( TQString( enc_name ) != filename + ".xia"
  539. ? "*=" + enc_name
  540. : "=\"" + escape_quoted_string( enc_name ) + '\"' );
  541. part->setContentDisposition( cDisp );
  542. }
  543. }
  544. void MessageComposer::adjustCryptFlags()
  545. {
  546. if ( !mDisableCrypto &&
  547. mAllowedCryptoMessageFormats & Kleo::InlineOpenPGPFormat &&
  548. !mAttachments.empty() &&
  549. ( mSigningRequested || mEncryptionRequested ) )
  550. {
  551. int ret;
  552. if ( mAllowedCryptoMessageFormats == Kleo::InlineOpenPGPFormat ) {
  553. ret = KMessageBox::warningYesNoCancel( mComposeWin,
  554. i18n("The inline OpenPGP crypto message format "
  555. "does not support encryption or signing "
  556. "of attachments.\n"
  557. "Really use deprecated inline OpenPGP?"),
  558. i18n("Insecure Message Format"),
  559. i18n("Use Inline OpenPGP"),
  560. i18n("Use OpenPGP/MIME") );
  561. }
  562. else {
  563. // if other crypto message formats are allowed then simply don't use
  564. // inline OpenPGP
  565. ret = KMessageBox::No;
  566. }
  567. if ( ret == KMessageBox::Cancel ) {
  568. mRc = false;
  569. return;
  570. } else if ( ret == KMessageBox::No ) {
  571. mAllowedCryptoMessageFormats &= ~Kleo::InlineOpenPGPFormat;
  572. mAllowedCryptoMessageFormats |= Kleo::OpenPGPMIMEFormat;
  573. if ( mSigningRequested ) {
  574. // The composer window disabled signing on the attachments, re-enable it
  575. for ( unsigned int idx = 0 ; idx < mAttachments.size() ; ++idx )
  576. mAttachments[idx].sign = true;
  577. }
  578. if ( mEncryptionRequested ) {
  579. // The composer window disabled encrypting on the attachments, re-enable it
  580. // We assume this is what the user wants - after all he chose OpenPGP/MIME for this.
  581. for ( unsigned int idx = 0 ; idx < mAttachments.size() ; ++idx )
  582. mAttachments[idx].encrypt = true;
  583. }
  584. }
  585. }
  586. mKeyResolver =
  587. new Kleo::KeyResolver( encryptToSelf(), showKeyApprovalDialog(),
  588. mUseOpportunisticEncryption, mAllowedCryptoMessageFormats,
  589. encryptKeyNearExpiryWarningThresholdInDays(),
  590. signingKeyNearExpiryWarningThresholdInDays(),
  591. encryptRootCertNearExpiryWarningThresholdInDays(),
  592. signingRootCertNearExpiryWarningThresholdInDays(),
  593. encryptChainCertNearExpiryWarningThresholdInDays(),
  594. signingChainCertNearExpiryWarningThresholdInDays() );
  595. if ( !mDisableCrypto ) {
  596. const KPIM::Identity & id =
  597. kmkernel->identityManager()->identityForUoidOrDefault( mIdentityUid );
  598. TQStringList encryptToSelfKeys;
  599. if ( !id.pgpEncryptionKey().isEmpty() )
  600. encryptToSelfKeys.push_back( id.pgpEncryptionKey() );
  601. if ( !id.smimeEncryptionKey().isEmpty() )
  602. encryptToSelfKeys.push_back( id.smimeEncryptionKey() );
  603. if ( mKeyResolver->setEncryptToSelfKeys( encryptToSelfKeys ) != Kpgp::Ok ) {
  604. mRc = false;
  605. return;
  606. }
  607. TQStringList signKeys;
  608. if ( !id.pgpSigningKey().isEmpty() )
  609. signKeys.push_back( mPGPSigningKey = id.pgpSigningKey() );
  610. if ( !id.smimeSigningKey().isEmpty() )
  611. signKeys.push_back( mSMIMESigningKey = id.smimeSigningKey() );
  612. if ( mKeyResolver->setSigningKeys( signKeys ) != Kpgp::Ok ) {
  613. mRc = false;
  614. return;
  615. }
  616. }
  617. mKeyResolver->setPrimaryRecipients( mTo + mCc );
  618. mKeyResolver->setSecondaryRecipients( mBccList );
  619. // check settings of composer buttons *and* attachment check boxes
  620. bool doSignCompletely = mSigningRequested;
  621. bool doEncryptCompletely = mEncryptionRequested;
  622. for ( unsigned int idx = 0 ; idx < mAttachments.size() ; ++idx ) {
  623. if ( mAttachments[idx].encrypt )
  624. mEncryptionRequested = true;
  625. else
  626. doEncryptCompletely = false;
  627. if ( mAttachments[idx].sign )
  628. mSigningRequested = true;
  629. else
  630. doSignCompletely = false;
  631. }
  632. mDoSign = !mDisableCrypto && determineWhetherToSign( doSignCompletely );
  633. if ( !mRc )
  634. return;
  635. mDoEncrypt = !mDisableCrypto && determineWhetherToEncrypt( doEncryptCompletely );
  636. if ( !mRc )
  637. return;
  638. // resolveAllKeys needs to run even if mDisableCrypto == true, since
  639. // we depend on it collecting all recipients into one dummy
  640. // SplitInfo to avoid special-casing all over the place:
  641. if ( mKeyResolver->resolveAllKeys( mDoSign, mDoEncrypt ) != Kpgp::Ok )
  642. mRc = false;
  643. }
  644. bool MessageComposer::determineWhetherToSign( bool doSignCompletely ) {
  645. bool sign = false;
  646. switch ( mKeyResolver->checkSigningPreferences( mSigningRequested ) ) {
  647. case Kleo::DoIt:
  648. if ( !mSigningRequested ) {
  649. markAllAttachmentsForSigning( true );
  650. return true;
  651. }
  652. sign = true;
  653. break;
  654. case Kleo::DontDoIt:
  655. sign = false;
  656. break;
  657. case Kleo::AskOpportunistic:
  658. assert( 0 );
  659. case Kleo::Ask:
  660. {
  661. // the user wants to be asked or has to be asked
  662. const KCursorSaver idle( KBusyPtr::idle() );
  663. const TQString msg = i18n("Examination of the recipient's signing preferences "
  664. "yielded that you be asked whether or not to sign "
  665. "this message.\n"
  666. "Sign this message?");
  667. switch ( KMessageBox::questionYesNoCancel( mComposeWin, msg,
  668. i18n("Sign Message?"),
  669. i18n("to sign","&Sign"),
  670. i18n("Do &Not Sign") ) ) {
  671. case KMessageBox::Cancel:
  672. mRc = false;
  673. return false;
  674. case KMessageBox::Yes:
  675. markAllAttachmentsForSigning( true );
  676. return true;
  677. case KMessageBox::No:
  678. markAllAttachmentsForSigning( false );
  679. return false;
  680. }
  681. }
  682. break;
  683. case Kleo::Conflict:
  684. {
  685. // warn the user that there are conflicting signing preferences
  686. const KCursorSaver idle( KBusyPtr::idle() );
  687. const TQString msg = i18n("There are conflicting signing preferences "
  688. "for these recipients.\n"
  689. "Sign this message?");
  690. switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
  691. i18n("Sign Message?"),
  692. i18n("to sign","&Sign"),
  693. i18n("Do &Not Sign") ) ) {
  694. case KMessageBox::Cancel:
  695. mRc = false;
  696. return false;
  697. case KMessageBox::Yes:
  698. markAllAttachmentsForSigning( true );
  699. return true;
  700. case KMessageBox::No:
  701. markAllAttachmentsForSigning( false );
  702. return false;
  703. }
  704. }
  705. break;
  706. case Kleo::Impossible:
  707. {
  708. const KCursorSaver idle( KBusyPtr::idle() );
  709. const TQString msg = i18n("You have requested to sign this message, "
  710. "but no valid signing keys have been configured "
  711. "for this identity.");
  712. if ( KMessageBox::warningContinueCancel( mComposeWin, msg,
  713. i18n("Send Unsigned?"),
  714. i18n("Send &Unsigned") )
  715. == KMessageBox::Cancel ) {
  716. mRc = false;
  717. return false;
  718. } else {
  719. markAllAttachmentsForSigning( false );
  720. return false;
  721. }
  722. }
  723. }
  724. if ( !sign || !doSignCompletely ) {
  725. if ( warnSendUnsigned() ) {
  726. const KCursorSaver idle( KBusyPtr::idle() );
  727. const TQString msg = sign && !doSignCompletely
  728. ? i18n("Some parts of this message will not be signed.\n"
  729. "Sending only partially signed messages might violate site policy.\n"
  730. "Sign all parts instead?") // oh, I hate this...
  731. : i18n("This message will not be signed.\n"
  732. "Sending unsigned message might violate site policy.\n"
  733. "Sign message instead?") ; // oh, I hate this...
  734. const TQString buttonText = sign && !doSignCompletely
  735. ? i18n("&Sign All Parts") : i18n("&Sign") ;
  736. switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
  737. i18n("Unsigned-Message Warning"),
  738. buttonText,
  739. i18n("Send &As Is") ) ) {
  740. case KMessageBox::Cancel:
  741. mRc = false;
  742. return false;
  743. case KMessageBox::Yes:
  744. markAllAttachmentsForSigning( true );
  745. return true;
  746. case KMessageBox::No:
  747. return sign || doSignCompletely;
  748. }
  749. }
  750. }
  751. return sign || doSignCompletely ;
  752. }
  753. bool MessageComposer::determineWhetherToEncrypt( bool doEncryptCompletely ) {
  754. bool encrypt = false;
  755. bool opportunistic = false;
  756. switch ( mKeyResolver->checkEncryptionPreferences( mEncryptionRequested ) ) {
  757. case Kleo::DoIt:
  758. if ( !mEncryptionRequested ) {
  759. markAllAttachmentsForEncryption( true );
  760. return true;
  761. }
  762. encrypt = true;
  763. break;
  764. case Kleo::DontDoIt:
  765. encrypt = false;
  766. break;
  767. case Kleo::AskOpportunistic:
  768. opportunistic = true;
  769. // fall through...
  770. case Kleo::Ask:
  771. {
  772. // the user wants to be asked or has to be asked
  773. const KCursorSaver idle( KBusyPtr::idle() );
  774. const TQString msg = opportunistic
  775. ? i18n("Valid trusted encryption keys were found for all recipients.\n"
  776. "Encrypt this message?")
  777. : i18n("Examination of the recipient's encryption preferences "
  778. "yielded that you be asked whether or not to encrypt "
  779. "this message.\n"
  780. "Encrypt this message?");
  781. switch ( KMessageBox::questionYesNoCancel( mComposeWin, msg,
  782. i18n("Encrypt Message?"),
  783. mDoSign
  784. ? i18n("Sign && &Encrypt")
  785. : i18n("&Encrypt"),
  786. mDoSign
  787. ? i18n("&Sign Only")
  788. : i18n("&Send As-Is") ) ) {
  789. case KMessageBox::Cancel:
  790. mRc = false;
  791. return false;
  792. case KMessageBox::Yes:
  793. markAllAttachmentsForEncryption( true );
  794. return true;
  795. case KMessageBox::No:
  796. markAllAttachmentsForEncryption( false );
  797. return false;
  798. }
  799. }
  800. break;
  801. case Kleo::Conflict:
  802. {
  803. // warn the user that there are conflicting encryption preferences
  804. const KCursorSaver idle( KBusyPtr::idle() );
  805. const TQString msg = i18n("There are conflicting encryption preferences "
  806. "for these recipients.\n"
  807. "Encrypt this message?");
  808. switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
  809. i18n("Encrypt Message?"),
  810. i18n("&Encrypt"),
  811. i18n("Do &Not Encrypt") ) ) {
  812. case KMessageBox::Cancel:
  813. mRc = false;
  814. return false;
  815. case KMessageBox::Yes:
  816. markAllAttachmentsForEncryption( true );
  817. return true;
  818. case KMessageBox::No:
  819. markAllAttachmentsForEncryption( false );
  820. return false;
  821. }
  822. }
  823. break;
  824. case Kleo::Impossible:
  825. {
  826. const KCursorSaver idle( KBusyPtr::idle() );
  827. const TQString msg = i18n("You have requested to encrypt this message, "
  828. "and to encrypt a copy to yourself, "
  829. "but no valid trusted encryption keys have been "
  830. "configured for this identity.");
  831. if ( KMessageBox::warningContinueCancel( mComposeWin, msg,
  832. i18n("Send Unencrypted?"),
  833. i18n("Send &Unencrypted") )
  834. == KMessageBox::Cancel ) {
  835. mRc = false;
  836. return false;
  837. } else {
  838. markAllAttachmentsForEncryption( false );
  839. return false;
  840. }
  841. }
  842. }
  843. if ( !encrypt || !doEncryptCompletely ) {
  844. if ( warnSendUnencrypted() ) {
  845. const KCursorSaver idle( KBusyPtr::idle() );
  846. const TQString msg = !doEncryptCompletely
  847. ? i18n("Some parts of this message will not be encrypted.\n"
  848. "Sending only partially encrypted messages might violate site policy "
  849. "and/or leak sensitive information.\n"
  850. "Encrypt all parts instead?") // oh, I hate this...
  851. : i18n("This message will not be encrypted.\n"
  852. "Sending unencrypted messages might violate site policy and/or "
  853. "leak sensitive information.\n"
  854. "Encrypt messages instead?") ; // oh, I hate this...
  855. const TQString buttonText = !doEncryptCompletely
  856. ? i18n("&Encrypt All Parts") : i18n("&Encrypt") ;
  857. switch ( KMessageBox::warningYesNoCancel( mComposeWin, msg,
  858. i18n("Unencrypted Message Warning"),
  859. buttonText,
  860. mDoSign
  861. ? i18n("&Sign Only")
  862. : i18n("&Send As-Is") ) ) {
  863. case KMessageBox::Cancel:
  864. mRc = false;
  865. return false;
  866. case KMessageBox::Yes:
  867. markAllAttachmentsForEncryption( true );
  868. return true;
  869. case KMessageBox::No:
  870. return encrypt || doEncryptCompletely;
  871. }
  872. }
  873. }
  874. return encrypt || doEncryptCompletely ;
  875. }
  876. void MessageComposer::markAllAttachmentsForSigning( bool sign ) {
  877. mSignBody = sign;
  878. for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it )
  879. it->sign = sign;
  880. }
  881. void MessageComposer::markAllAttachmentsForEncryption( bool enc ) {
  882. mEncryptBody = enc;
  883. for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it )
  884. it->encrypt = enc;
  885. }
  886. void MessageComposer::composeMessage()
  887. {
  888. for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
  889. if ( mKeyResolver->encryptionItems( concreteCryptoMessageFormats[i] ).empty() )
  890. continue;
  891. KMMessage * msg = new KMMessage( *mReferenceMessage );
  892. composeMessage( *msg, mDoSign, mDoEncrypt, concreteCryptoMessageFormats[i] );
  893. if ( !mRc )
  894. return;
  895. }
  896. }
  897. //
  898. // These are replacements for StructuringInfo(Wrapper):
  899. //
  900. // check whether to use multipart/{signed,encrypted}
  901. static inline bool makeMultiMime( Kleo::CryptoMessageFormat f, bool sign ) {
  902. switch ( f ) {
  903. default:
  904. case Kleo::InlineOpenPGPFormat:
  905. case Kleo::SMIMEOpaqueFormat: return false;
  906. case Kleo::OpenPGPMIMEFormat: return true;
  907. case Kleo::SMIMEFormat: return sign; // only on sign - there's no mp/encrypted for S/MIME
  908. }
  909. }
  910. static inline bool makeMultiPartSigned( Kleo::CryptoMessageFormat f ) {
  911. return makeMultiMime( f, true );
  912. }
  913. static inline bool makeMultiPartEncrypted( Kleo::CryptoMessageFormat f ) {
  914. return makeMultiMime( f, false );
  915. }
  916. static inline bool makeMimeObject( Kleo::CryptoMessageFormat f, bool /*signing*/ ) {
  917. return f != Kleo::InlineOpenPGPFormat;
  918. }
  919. static inline const char * toplevelContentType( Kleo::CryptoMessageFormat f, bool signing ) {
  920. switch ( f ) {
  921. default:
  922. case Kleo::InlineOpenPGPFormat: return 0;
  923. case Kleo::OpenPGPMIMEFormat:
  924. return signing ?
  925. "multipart/signed;\n\t"
  926. "boundary=\"%boundary\";\n\t"
  927. "protocol=\"application/pgp-signature\";\n\t"
  928. "micalg=pgp-sha1" // FIXME: obtain this parameter from gpgme!
  929. :
  930. "multipart/encrypted;\n\t"
  931. "boundary=\"%boundary\";\n\t"
  932. "protocol=\"application/pgp-encrypted\""
  933. ;
  934. case Kleo::SMIMEFormat:
  935. if ( signing )
  936. return
  937. "multipart/signed;\n\t"
  938. "boundary=\"%boundary\";\n\t"
  939. "protocol=\"application/pkcs7-signature\";\n\t"
  940. "micalg=sha1"; // FIXME: obtain this parameter from gpgme!
  941. // fall through (for encryption, there's no difference between
  942. // SMIME and SMIMEOpaque, since there is no mp/encrypted for
  943. // S/MIME):
  944. case Kleo::SMIMEOpaqueFormat:
  945. return signing ?
  946. "application/pkcs7-mime;\n\t"
  947. "smime-type=signed-data;\n\t"
  948. "name=\"smime.p7m\";\n\t"
  949. :
  950. "application/pkcs7-mime;\n\t"
  951. "smime-type=enveloped-data;\n\t"
  952. "name=\"smime.p7m\";\n\t"
  953. ;
  954. }
  955. }
  956. static inline const char * toplevelContentDisposition( Kleo::CryptoMessageFormat f, bool signing ) {
  957. switch ( f ) {
  958. default:
  959. case Kleo::InlineOpenPGPFormat:
  960. case Kleo::OpenPGPMIMEFormat:
  961. return 0;
  962. case Kleo::SMIMEFormat:
  963. if ( signing )
  964. return 0;
  965. case Kleo::SMIMEOpaqueFormat:
  966. return "attachment; filename=\"smime.p7m\"";
  967. }
  968. }
  969. static inline bool includeCleartextWhenSigning( Kleo::CryptoMessageFormat f ) {
  970. return makeMultiPartSigned( f );
  971. }
  972. static inline const char * nestedContentType( Kleo::CryptoMessageFormat f, bool signing ) {
  973. switch ( f ) {
  974. case Kleo::OpenPGPMIMEFormat:
  975. return signing ? "application/pgp-signature; name=signature.asc \nContent-Description: This is a digitally signed message part." : "application/octet-stream" ;
  976. case Kleo::SMIMEFormat:
  977. if ( signing )
  978. return "application/pkcs7-signature; name=\"smime.p7s\"";
  979. // fall through:
  980. default:
  981. case Kleo::InlineOpenPGPFormat:
  982. case Kleo::SMIMEOpaqueFormat:
  983. return 0;
  984. }
  985. }
  986. static inline const char * nestedContentDisposition( Kleo::CryptoMessageFormat f, bool signing ) {
  987. if ( !signing && f == Kleo::OpenPGPMIMEFormat )
  988. return "inline; filename=\"msg.asc\"";
  989. if ( signing && f == Kleo::SMIMEFormat )
  990. return "attachment; filename=\"smime.p7s\"";
  991. return 0;
  992. }
  993. static inline bool binaryHint( Kleo::CryptoMessageFormat f ) {
  994. switch ( f ) {
  995. case Kleo::SMIMEFormat:
  996. case Kleo::SMIMEOpaqueFormat:
  997. return true;
  998. default:
  999. case Kleo::OpenPGPMIMEFormat:
  1000. case Kleo::InlineOpenPGPFormat:
  1001. return false;
  1002. }
  1003. }
  1004. static inline bool armor( Kleo::CryptoMessageFormat f ) {
  1005. return !binaryHint( f );
  1006. }
  1007. static inline bool textMode( Kleo::CryptoMessageFormat f ) {
  1008. return f == Kleo::InlineOpenPGPFormat;
  1009. }
  1010. static inline GpgME::Context::SignatureMode signingMode( Kleo::CryptoMessageFormat f ) {
  1011. switch ( f ) {
  1012. case Kleo::SMIMEOpaqueFormat:
  1013. return GpgME::Context::Normal;
  1014. case Kleo::InlineOpenPGPFormat:
  1015. return GpgME::Context::Clearsigned;
  1016. default:
  1017. case Kleo::SMIMEFormat:
  1018. case Kleo::OpenPGPMIMEFormat:
  1019. return GpgME::Context::Detached;
  1020. }
  1021. }
  1022. //
  1023. // END replacements for StructuringInfo(Wrapper)
  1024. //
  1025. class EncryptMessageJob : public MessageComposerJob {
  1026. public:
  1027. EncryptMessageJob( KMMessage* msg, const Kleo::KeyResolver::SplitInfo & si,
  1028. bool doSign, bool doEncrypt, const TQByteArray& encodedBody,
  1029. int boundaryLevel, /*const KMMessagePart& oldBodyPart,*/
  1030. KMMessagePart* newBodyPart, Kleo::CryptoMessageFormat format,
  1031. MessageComposer* composer )
  1032. : MessageComposerJob( composer ), mMsg( msg ), mSplitInfo( si ),
  1033. mDoSign( doSign ), mDoEncrypt( doEncrypt ), mEncodedBody( encodedBody ),
  1034. mBoundaryLevel( boundaryLevel ), /*mOldBodyPart( oldBodyPart ),*/
  1035. mNewBodyPart( newBodyPart ), mFormat( format ) {}
  1036. void execute() {
  1037. KMMessagePart tmpNewBodyPart;
  1038. tmpNewBodyPart.duplicate( *mNewBodyPart ); // slow - we duplicate everything again
  1039. // TODO: Async call
  1040. mComposer->encryptMessage( mMsg, mSplitInfo, mDoSign, mDoEncrypt,
  1041. tmpNewBodyPart, mFormat );
  1042. if ( !mComposer->mRc ) {
  1043. delete mMsg; mMsg = 0;
  1044. return;
  1045. }
  1046. mComposer->mMessageList.push_back( mMsg );
  1047. }
  1048. private:
  1049. KMMessage* mMsg;
  1050. Kleo::KeyResolver::SplitInfo mSplitInfo;
  1051. bool mDoSign, mDoEncrypt;
  1052. TQByteArray mEncodedBody;
  1053. int mBoundaryLevel;
  1054. //KMMessagePart mOldBodyPart;
  1055. KMMessagePart* mNewBodyPart;
  1056. Kleo::CryptoMessageFormat mFormat;
  1057. };
  1058. class SetLastMessageAsUnencryptedVersionOfLastButOne : public MessageComposerJob {
  1059. public:
  1060. SetLastMessageAsUnencryptedVersionOfLastButOne( MessageComposer * composer )
  1061. : MessageComposerJob( composer ) {}
  1062. void execute() {
  1063. KMMessage * last = mComposer->mMessageList.back();
  1064. mComposer->mMessageList.pop_back();
  1065. mComposer->mMessageList.back()->setUnencryptedMsg( last );
  1066. }
  1067. };
  1068. void MessageComposer::composeInlineOpenPGPMessage( KMMessage& theMessage,
  1069. bool doSign, bool doEncrypt )
  1070. {
  1071. // preprocess the body text
  1072. const TQByteArray bodyData = mText;
  1073. if (bodyData.isNull()) {
  1074. mRc = false;
  1075. return;
  1076. }
  1077. mNewBodyPart = 0; // unused
  1078. mEarlyAddAttachments = false;
  1079. mAllAttachmentsAreInBody = false;
  1080. // set the main headers
  1081. theMessage.deleteBodyParts();
  1082. TQString oldContentType = theMessage.headerField( "Content-Type" );
  1083. theMessage.removeHeaderField("Content-Type");
  1084. theMessage.removeHeaderField("Content-Transfer-Encoding");
  1085. const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
  1086. = mKeyResolver->encryptionItems( Kleo::InlineOpenPGPFormat );
  1087. kdWarning( splitInfos.empty() )
  1088. << "MessageComposer::continueComposeMessage(): splitInfos.empty() for InlineOpenPGPFormat"
  1089. << endl;
  1090. std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it;
  1091. for ( it = splitInfos.begin() ; it != splitInfos.end() ; ++it ) {
  1092. const Kleo::KeyResolver::SplitInfo& splitInfo = *it;
  1093. KMMessage* msg = new KMMessage( theMessage );
  1094. if ( doEncrypt ) {
  1095. Kpgp::Result result;
  1096. TQByteArray encryptedBody;
  1097. if ( doSign ) { // Sign and encrypt
  1098. const std::vector<GpgME::Key> signingKeys = mKeyResolver->signingKeys( Kleo::InlineOpenPGPFormat );
  1099. result = pgpSignedAndEncryptedMsg( encryptedBody, bodyData, signingKeys,
  1100. splitInfo.keys, Kleo::InlineOpenPGPFormat );
  1101. } else { // Encrypt but don't sign
  1102. result = pgpEncryptedMsg( encryptedBody, bodyData,
  1103. splitInfo.keys, Kleo::InlineOpenPGPFormat );
  1104. }
  1105. if ( result != Kpgp::Ok ) {
  1106. mRc = false;
  1107. return;
  1108. }
  1109. assert( !encryptedBody.isNull() ); // if you hit this, check gpg-agent is running, then blame gpgme.
  1110. mOldBodyPart.setBodyEncodedBinary( encryptedBody );
  1111. } else {
  1112. if ( doSign ) { // Sign but don't encrypt
  1113. pgpSignedMsg( bodyData, Kleo::InlineOpenPGPFormat );
  1114. if ( mSignature.isNull() ) {
  1115. mRc = false;
  1116. return;
  1117. }
  1118. mOldBodyPart.setBodyEncodedBinary( mSignature );
  1119. } else { // don't sign nor encrypt -> nothing to do
  1120. assert( !bodyData.isNull() );
  1121. mOldBodyPart.setBodyEncodedBinary( bodyData );
  1122. }
  1123. }
  1124. mOldBodyPart.setContentDisposition( "inline" );
  1125. mOldBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
  1126. if (mOldBodyPart.type() == DwMime::kTypeText) {
  1127. mOldBodyPart.setCharset(mCharset);
  1128. }
  1129. addBodyAndAttachments( msg, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
  1130. mMessageList.push_back( msg );
  1131. if ( it == splitInfos.begin() ) {
  1132. if ( doEncrypt && !saveMessagesEncrypted() ) {
  1133. mOldBodyPart.setBodyEncodedBinary( bodyData );
  1134. KMMessage* msgUnenc = new KMMessage( theMessage );
  1135. addBodyAndAttachments( msgUnenc, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
  1136. msg->setUnencryptedMsg( msgUnenc );
  1137. }
  1138. }
  1139. } // end for
  1140. }
  1141. // very much inspired by composeInlineOpenPGPMessage
  1142. void MessageComposer::composeChiasmusMessage( KMMessage& theMessage, Kleo::CryptoMessageFormat format )
  1143. {
  1144. assert( !GlobalSettings::chiasmusKey().isEmpty() ); // kmcomposewin code should have made sure
  1145. const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
  1146. assert( cpf );
  1147. const Kleo::CryptoBackend::Protocol * chiasmus
  1148. = cpf->protocol( "Chiasmus" );
  1149. assert( chiasmus ); // kmcomposewin code should have made sure
  1150. // preprocess the body text
  1151. const TQByteArray bodyData = mText;
  1152. if (bodyData.isNull()) {
  1153. mRc = false;
  1154. return;
  1155. }
  1156. mNewBodyPart = 0; // unused
  1157. mEarlyAddAttachments = false;
  1158. mAllAttachmentsAreInBody = false;
  1159. // set the main headers
  1160. theMessage.deleteBodyParts();
  1161. TQString oldContentType = theMessage.headerField( "Content-Type" );
  1162. theMessage.removeHeaderField("Content-Type");
  1163. theMessage.removeHeaderField("Content-Transfer-Encoding");
  1164. // This reads strange, but we know that AdjustCryptFlagsJob created a single splitinfo,
  1165. // under the given "format" (usually openpgp/mime; doesn't matter)
  1166. const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
  1167. = mKeyResolver->encryptionItems( format );
  1168. assert( splitInfos.size() == 1 );
  1169. for ( std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it = splitInfos.begin() ; it != splitInfos.end() ; ++it )
  1170. {
  1171. const Kleo::KeyResolver::SplitInfo& splitInfo = *it;
  1172. KMMessage* msg = new KMMessage( theMessage );
  1173. TQByteArray encryptedBody;
  1174. if ( !encryptWithChiasmus( chiasmus, bodyData, encryptedBody ) ) {
  1175. mRc = false;
  1176. return;
  1177. }
  1178. assert( !encryptedBody.isNull() );
  1179. // This leaves CTE==7-bit, no good
  1180. //mOldBodyPart.setBodyEncodedBinary( encryptedBody );
  1181. bool doSign = false;
  1182. TQValueList<int> allowedCTEs;
  1183. mOldBodyPart.setBodyAndGuessCte( encryptedBody, allowedCTEs,
  1184. !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
  1185. doSign );
  1186. mOldBodyPart.setContentDisposition( "inline" );
  1187. // Used in case of no attachments
  1188. mOldBodyPart.setOriginalContentTypeStr( "application/vnd.de.bund.bsi.chiasmus-text;chiasmus-charset=" + mCharset );
  1189. // Used in case of attachments
  1190. mOldBodyPart.setTypeStr( "application" );
  1191. mOldBodyPart.setSubtypeStr( "vnd.de.bund.bsi.chiasmus-text" );
  1192. mOldBodyPart.setAdditionalCTypeParamStr( TQCString( "chiasmus-charset=" + mCharset ) );
  1193. addBodyAndAttachments( msg, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
  1194. mMessageList.push_back( msg );
  1195. if ( it == splitInfos.begin() && !saveMessagesEncrypted() ) {
  1196. mOldBodyPart.setBodyEncodedBinary( bodyData );
  1197. KMMessage* msgUnenc = new KMMessage( theMessage );
  1198. addBodyAndAttachments( msgUnenc, splitInfo, false, false, mOldBodyPart, Kleo::InlineOpenPGPFormat );
  1199. msg->setUnencryptedMsg( msgUnenc );
  1200. }
  1201. }
  1202. }
  1203. void MessageComposer::composeMessage( KMMessage& theMessage,
  1204. bool doSign, bool doEncrypt,
  1205. Kleo::CryptoMessageFormat format )
  1206. {
  1207. #ifdef DEBUG
  1208. kdDebug(5006) << "entering KMComposeWin::composeMessage" << endl;
  1209. #endif
  1210. if ( format == Kleo::InlineOpenPGPFormat ) {
  1211. composeInlineOpenPGPMessage( theMessage, doSign, doEncrypt );
  1212. return;
  1213. }
  1214. if ( mEncryptWithChiasmus )
  1215. {
  1216. composeChiasmusMessage( theMessage, format );
  1217. return;
  1218. }
  1219. // create informative header for those that have no mime-capable
  1220. // email client
  1221. theMessage.setBody( "This message is in MIME format." );
  1222. // preprocess the body text
  1223. TQByteArray bodyData = mText;
  1224. if (bodyData.isNull()) {
  1225. mRc = false;
  1226. return;
  1227. }
  1228. // set the main headers
  1229. TQString oldContentType = theMessage.headerField( "Content-Type" );
  1230. theMessage.deleteBodyParts();
  1231. theMessage.removeHeaderField("Content-Type");
  1232. theMessage.removeHeaderField("Content-Transfer-Encoding");
  1233. theMessage.setAutomaticFields(true); // == multipart/mixed
  1234. // this is our *final* body part
  1235. mNewBodyPart = new KMMessagePart;
  1236. // this is the boundary depth of the surrounding MIME part
  1237. mPreviousBoundaryLevel = 0;
  1238. // whether the body must be signed/encrypted
  1239. const bool doEncryptBody = doEncrypt && mEncryptBody;
  1240. const bool doSignBody = doSign && mSignBody;
  1241. // create temporary bodyPart for editor text
  1242. // (and for all attachments, if mail is to be signed and/or encrypted)
  1243. mEarlyAddAttachments = !mAttachments.empty() && ( doSignBody || doEncryptBody );
  1244. mAllAttachmentsAreInBody = mEarlyAddAttachments;
  1245. // test whether there ARE attachments that can be included into the body
  1246. if( mEarlyAddAttachments ) {
  1247. bool someOk = false;
  1248. for ( TQValueVector<Attachment>::const_iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
  1249. if ( it->encrypt == doEncryptBody && it->sign == doSignBody )
  1250. someOk = true;
  1251. else
  1252. mAllAttachmentsAreInBody = false;
  1253. }
  1254. if( !mAllAttachmentsAreInBody && !someOk )
  1255. mEarlyAddAttachments = false;
  1256. }
  1257. kdDebug(5006) << "mEarlyAddAttachments=" << mEarlyAddAttachments << " mAllAttachmentsAreInBody=" << mAllAttachmentsAreInBody << endl;
  1258. // if an html message is to be generated, make a text/plain and text/html part
  1259. mMultipartMixedBoundary = "";
  1260. if ( mEarlyAddAttachments ) {
  1261. mOldBodyPart.setTypeStr( "multipart" );
  1262. mOldBodyPart.setSubtypeStr( "mixed" );
  1263. // calculate a boundary string
  1264. DwMediaType tmpCT;
  1265. tmpCT.CreateBoundary( ++mPreviousBoundaryLevel );
  1266. mMultipartMixedBoundary = tmpCT.Boundary().c_str();
  1267. }
  1268. else if ( mIsRichText ) {
  1269. mOldBodyPart.setTypeStr( "multipart" );
  1270. mOldBodyPart.setSubtypeStr( "alternative" );
  1271. }
  1272. else
  1273. mOldBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
  1274. mOldBodyPart.setContentDisposition( "inline" );
  1275. if ( mIsRichText ) { // create a multipart body
  1276. // calculate a boundary string
  1277. TQCString boundaryCStr; // storing boundary string data
  1278. TQCString newbody;
  1279. DwMediaType tmpCT;
  1280. tmpCT.CreateBoundary( ++mPreviousBoundaryLevel );
  1281. boundaryCStr = KMail::Util::CString( tmpCT.Boundary() );
  1282. TQValueList<int> allowedCTEs;
  1283. KMMessagePart textBodyPart;
  1284. textBodyPart.setTypeStr("text");
  1285. textBodyPart.setSubtypeStr("plain");
  1286. TQCString textbody = plainTextFromMarkup( mText /* converted to TQString */ );
  1287. // the signed body must not be 8bit encoded
  1288. textBodyPart.setBodyAndGuessCte( textbody, allowedCTEs,
  1289. !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
  1290. doSign );
  1291. textBodyPart.setCharset( mCharset );
  1292. textBodyPart.setBodyEncoded( textbody );
  1293. DwBodyPart* textDwPart = theMessage.createDWBodyPart( &textBodyPart );
  1294. textDwPart->Assemble();
  1295. newbody += "--";
  1296. newbody += boundaryCStr;
  1297. newbody += "\n";
  1298. newbody += textDwPart->AsString().c_str();
  1299. delete textDwPart;
  1300. textDwPart = 0;
  1301. KMMessagePart htmlBodyPart;
  1302. htmlBodyPart.setTypeStr("text");
  1303. htmlBodyPart.setSubtypeStr("html");
  1304. TQByteArray htmlbody = mText;
  1305. // the signed body must not be 8bit encoded
  1306. htmlBodyPart.setBodyAndGuessCte( htmlbody, allowedCTEs,
  1307. !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
  1308. doSign );
  1309. htmlBodyPart.setCharset( mCharset );
  1310. htmlBodyPart.setBodyEncodedBinary( htmlbody );
  1311. DwBodyPart* htmlDwPart = theMessage.createDWBodyPart( &htmlBodyPart );
  1312. htmlDwPart->Assemble();
  1313. newbody += "\n--";
  1314. newbody += boundaryCStr;
  1315. newbody += "\n";
  1316. newbody += htmlDwPart->AsString().c_str();
  1317. delete htmlDwPart;
  1318. htmlDwPart = 0;
  1319. newbody += "--";
  1320. newbody += boundaryCStr;
  1321. newbody += "--\n";
  1322. bodyData = KMail::Util::byteArrayFromTQCStringNoDetach( newbody );
  1323. mOldBodyPart.setBodyEncodedBinary( bodyData );
  1324. mSaveBoundary = tmpCT.Boundary();
  1325. }
  1326. // Prepare attachments that will be signed/encrypted
  1327. for ( TQValueVector<Attachment>::const_iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
  1328. // signed/encrypted body parts must be either QP or base64 encoded
  1329. // Why not 7 bit? Because the LF->CRLF canonicalization would render
  1330. // e.g. 7 bit encoded shell scripts unusable because of the CRs.
  1331. //
  1332. // (marc) this is a workaround for the KMail bug that doesn't
  1333. // respect the CRLF->LF de-canonicalisation. We should
  1334. // eventually get rid of this:
  1335. if( it->sign || it->encrypt ) {
  1336. TQCString cte = it->part->cteStr().lower();
  1337. if( ( "8bit" == cte && it->part->type() != DwMime::kTypeMessage )
  1338. || ( ( it->part->type() == DwMime::kTypeText )
  1339. && ( "7bit" == cte ) ) ) {
  1340. const TQByteArray body = it->part->bodyDecodedBinary();
  1341. TQValueList<int> dummy;
  1342. it->part->setBodyAndGuessCte(body, dummy, false, it->sign);
  1343. kdDebug(5006) << "Changed encoding of message part from "
  1344. << cte << " to " << it->part->cteStr() << endl;
  1345. }
  1346. }
  1347. }
  1348. if( mEarlyAddAttachments ) {
  1349. // add the normal body text
  1350. KMMessagePart innerBodyPart;
  1351. if ( mIsRichText ) {
  1352. innerBodyPart.setTypeStr( "multipart");//text" );
  1353. innerBodyPart.setSubtypeStr("alternative");//html");
  1354. }
  1355. else {
  1356. innerBodyPart.setOriginalContentTypeStr( oldContentType.utf8() );
  1357. }
  1358. innerBodyPart.setContentDisposition( "inline" );
  1359. TQValueList<int> allowedCTEs;
  1360. // the signed body must not be 8bit encoded
  1361. innerBodyPart.setBodyAndGuessCte( bodyData, allowedCTEs,
  1362. !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
  1363. doSign );
  1364. if ( !mIsRichText )
  1365. innerBodyPart.setCharset( mCharset );
  1366. innerBodyPart.setBodyEncodedBinary( bodyData ); // do we need this, since setBodyAndGuessCte does this already?
  1367. DwBodyPart* innerDwPart = theMessage.createDWBodyPart( &innerBodyPart );
  1368. innerDwPart->Assemble();
  1369. TQByteArray tmpbody = KMail::Util::ByteArray( innerDwPart->AsString() );
  1370. if ( mIsRichText ) { // and add our mp/a boundary
  1371. int boundPos = tmpbody.find( '\n' );
  1372. if( -1 < boundPos ) {
  1373. TQCString bStr( ";\n boundary=\"" );
  1374. bStr += mSaveBoundary.c_str();
  1375. bStr += "\"";
  1376. bodyData = tmpbody;
  1377. KMail::Util::insert( bodyData, boundPos, bStr );
  1378. KMail::Util::insert( bodyData, 0, "--" + mMultipartMixedBoundary + "\n" ); // prepend
  1379. }
  1380. }
  1381. else {
  1382. bodyData = tmpbody;
  1383. KMail::Util::insert( bodyData, 0, "--" + mMultipartMixedBoundary + "\n" ); // prepend
  1384. }
  1385. delete innerDwPart;
  1386. innerDwPart = 0;
  1387. // add all matching Attachments
  1388. // NOTE: This code will be changed when KMime is complete.
  1389. for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
  1390. if ( it->encrypt == doEncryptBody && it->sign == doSignBody ) {
  1391. innerDwPart = theMessage.createDWBodyPart( it->part );
  1392. innerDwPart->Assemble();
  1393. KMail::Util::append( bodyData, TQCString( "\n--" + mMultipartMixedBoundary + "\n" ) );
  1394. KMail::Util::append( bodyData, innerDwPart->AsString().c_str() );
  1395. delete innerDwPart;
  1396. innerDwPart = 0;
  1397. }
  1398. }
  1399. KMail::Util::append( bodyData, TQCString( "\n--" + mMultipartMixedBoundary + "--\n" ) );
  1400. } else { // !earlyAddAttachments
  1401. TQValueList<int> allowedCTEs;
  1402. // the signed body must not be 8bit encoded
  1403. mOldBodyPart.setBodyAndGuessCte(bodyData, allowedCTEs, !kmkernel->msgSender()->sendQuotedPrintable() && !doSign,
  1404. doSign);
  1405. if ( !mIsRichText )
  1406. mOldBodyPart.setCharset(mCharset);
  1407. }
  1408. // create S/MIME body part for signing and/or encrypting
  1409. mOldBodyPart.setBodyEncodedBinary( bodyData );
  1410. if( doSignBody || doEncryptBody ) {
  1411. // get string representation of body part (including the attachments)
  1412. DwBodyPart* dwPart;
  1413. if ( mIsRichText && !mEarlyAddAttachments ) {
  1414. // if we are using richtext and not already have a mp/a body
  1415. // make the body a mp/a body
  1416. dwPart = theMessage.createDWBodyPart( &mOldBodyPart );
  1417. DwHeaders& headers = dwPart->Headers();
  1418. DwMediaType& ct = headers.ContentType();
  1419. ct.SetBoundary(mSaveBoundary);
  1420. dwPart->Assemble();
  1421. }
  1422. else {
  1423. dwPart = theMessage.createDWBodyPart( &mOldBodyPart );
  1424. dwPart->Assemble();
  1425. }
  1426. mEncodedBody = KMail::Util::ByteArray( dwPart->AsString() );
  1427. delete dwPart;
  1428. dwPart = 0;
  1429. // manually add a boundary definition to the Content-Type header
  1430. if( !mMultipartMixedBoundary.isEmpty() ) {
  1431. int boundPos = mEncodedBody.find( '\n' );
  1432. if( -1 < boundPos ) {
  1433. // insert new "boundary" parameter
  1434. TQCString bStr( ";\n boundary=\"" );
  1435. bStr += mMultipartMixedBoundary;
  1436. bStr += "\"";
  1437. KMail::Util::insert( mEncodedBody, boundPos, bStr.data() );
  1438. }
  1439. }
  1440. // replace simple LFs by CRLFs for all MIME supporting CryptPlugs
  1441. // according to RfC 2633, 3.1.1 Canonicalization
  1442. //kdDebug(5006) << "Converting LF to CRLF (see RfC 2633, 3.1.1 Canonicalization)" << endl;
  1443. mEncodedBody = KMail::Util::lf2crlf( mEncodedBody );
  1444. }
  1445. if ( doSignBody ) {
  1446. mPerformingSignOperation = true; // this lets the KMComposeWin know if it is safe to close the window.
  1447. pgpSignedMsg( mEncodedBody, format );
  1448. mPerformingSignOperation = false;
  1449. if ( mSignature.isEmpty() ) {
  1450. kdDebug() << "signature was empty" << endl;
  1451. mRc = false;
  1452. return;
  1453. }
  1454. mRc = processStructuringInfo( TQString(),
  1455. mOldBodyPart.contentDescription(),
  1456. mOldBodyPart.typeStr(),
  1457. mOldBodyPart.subtypeStr(),
  1458. mOldBodyPart.contentDisposition(),
  1459. mOldBodyPart.contentTransferEncodingStr(),
  1460. mEncodedBody, "signature",
  1461. mSignature,
  1462. *mNewBodyPart, true, format );
  1463. if ( mRc ) {
  1464. if ( !makeMultiPartSigned( format ) ) {
  1465. mNewBodyPart->setCharset( mCharset );
  1466. }
  1467. } else
  1468. KMessageBox::sorry( mComposeWin,
  1469. mErrorProcessingStructuringInfo );
  1470. }
  1471. if ( !mRc )
  1472. return;
  1473. continueComposeMessage( theMessage, doSign, doEncrypt, format );
  1474. }
  1475. // Do the encryption stuff
  1476. void MessageComposer::continueComposeMessage( KMMessage& theMessage,
  1477. bool doSign, bool doEncrypt,
  1478. Kleo::CryptoMessageFormat format )
  1479. {
  1480. const std::vector<Kleo::KeyResolver::SplitInfo> splitInfos
  1481. = mKeyResolver->encryptionItems( format );
  1482. kdWarning( splitInfos.empty() )
  1483. << "MessageComposer::continueComposeMessage(): splitInfos.empty() for "
  1484. << Kleo::cryptoMessageFormatToString( format ) << endl;
  1485. if ( !splitInfos.empty() && doEncrypt && !saveMessagesEncrypted() ) {
  1486. mJobs.push_front( new SetLastMessageAsUnencryptedVersionOfLastButOne( this ) );
  1487. mJobs.push_front( new EncryptMessageJob( new KMMessage( theMessage ),
  1488. Kleo::KeyResolver::SplitInfo( splitInfos.front().recipients ), doSign,
  1489. false, mEncodedBody,
  1490. mPreviousBoundaryLevel,
  1491. /*mOldBodyPart,*/ mNewBodyPart,
  1492. format, this ) );
  1493. }
  1494. for ( std::vector<Kleo::KeyResolver::SplitInfo>::const_iterator it = splitInfos.begin() ; it != splitInfos.end() ; ++it )
  1495. mJobs.push_front( new EncryptMessageJob( new KMMessage( theMessage ), *it, doSign,
  1496. doEncrypt, mEncodedBody,
  1497. mPreviousBoundaryLevel,
  1498. /*mOldBodyPart,*/ mNewBodyPart,
  1499. format, this ) );
  1500. }
  1501. void MessageComposer::encryptMessage( KMMessage* msg,
  1502. const Kleo::KeyResolver::SplitInfo & splitInfo,
  1503. bool doSign, bool doEncrypt,
  1504. KMMessagePart newBodyPart,
  1505. Kleo::CryptoMessageFormat format )
  1506. {
  1507. if ( doEncrypt && splitInfo.keys.empty() ) {
  1508. // the user wants to send the message unencrypted
  1509. //mComposeWin->setEncryption( false, false );
  1510. //FIXME why is this talkback needed? Till
  1511. doEncrypt = false;
  1512. }
  1513. const bool doEncryptBody = doEncrypt && mEncryptBody;
  1514. const bool doSignBody = doSign && mSignBody;
  1515. if ( doEncryptBody ) {
  1516. TQByteArray innerContent;
  1517. if ( doSignBody ) {
  1518. // extract signed body from newBodyPart
  1519. DwBodyPart* dwPart = msg->createDWBodyPart( &newBodyPart );
  1520. dwPart->Assemble();
  1521. innerContent = KMail::Util::ByteArray( dwPart->AsString() );
  1522. delete dwPart;
  1523. dwPart = 0;
  1524. } else {
  1525. innerContent = mEncodedBody;
  1526. }
  1527. // now do the encrypting:
  1528. // replace simple LFs by CRLFs for all MIME supporting CryptPlugs
  1529. // according to RfC 2633, 3.1.1 Canonicalization
  1530. //kdDebug(5006) << "Converting LF to CRLF (see RfC 2633, 3.1.1 Canonicalization)" << endl;
  1531. innerContent = KMail::Util::lf2crlf( innerContent );
  1532. //kdDebug(5006) << " done." << endl;
  1533. TQByteArray encryptedBody;
  1534. Kpgp::Result result = pgpEncryptedMsg( encryptedBody, innerContent,
  1535. splitInfo.keys, format );
  1536. if ( result != Kpgp::Ok ) {
  1537. mRc = false;
  1538. return;
  1539. }
  1540. mRc = processStructuringInfo( "http://www.gnupg.org/aegypten/",
  1541. newBodyPart.contentDescription(),
  1542. newBodyPart.typeStr(),
  1543. newBodyPart.subtypeStr(),
  1544. newBodyPart.contentDisposition(),
  1545. newBodyPart.contentTransferEncodingStr(),
  1546. innerContent,
  1547. "encrypted data",
  1548. encryptedBody,
  1549. newBodyPart, false, format );
  1550. if ( !mRc )
  1551. KMessageBox::sorry(mComposeWin, mErrorProcessingStructuringInfo);
  1552. }
  1553. // process the attachments that are not included into the body
  1554. if( mRc ) {
  1555. const bool useNewBodyPart = doSignBody || doEncryptBody;
  1556. addBodyAndAttachments( msg, splitInfo, doSign, doEncrypt,
  1557. useNewBodyPart ? newBodyPart : mOldBodyPart, format );
  1558. }
  1559. }
  1560. void MessageComposer::addBodyAndAttachments( KMMessage* msg,
  1561. const Kleo::KeyResolver::SplitInfo & splitInfo,
  1562. bool doSign, bool doEncrypt,
  1563. const KMMessagePart& ourFineBodyPart,
  1564. Kleo::CryptoMessageFormat format )
  1565. {
  1566. const bool doEncryptBody = doEncrypt && mEncryptBody;
  1567. const bool doSignBody = doSign && mSignBody;
  1568. if( !mAttachments.empty()
  1569. && ( !mEarlyAddAttachments || !mAllAttachmentsAreInBody ) ) {
  1570. // set the content type header
  1571. msg->headers().ContentType().SetType( DwMime::kTypeMultipart );
  1572. msg->headers().ContentType().SetSubtype( DwMime::kSubtypeMixed );
  1573. msg->headers().ContentType().CreateBoundary( 0 );
  1574. kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : set top level Content-Type to Multipart/Mixed" << endl;
  1575. // add our Body Part
  1576. DwBodyPart* tmpDwPart = msg->createDWBodyPart( &ourFineBodyPart );
  1577. DwHeaders& headers = tmpDwPart->Headers();
  1578. DwMediaType& ct = headers.ContentType();
  1579. if ( !mSaveBoundary.empty() )
  1580. ct.SetBoundary(mSaveBoundary);
  1581. tmpDwPart->Assemble();
  1582. //KMMessagePart newPart;
  1583. //newPart.setBody(tmpDwPart->AsString().c_str());
  1584. msg->addDwBodyPart(tmpDwPart); // only this method doesn't add it as text/plain
  1585. // add Attachments
  1586. // create additional bodyparts for the attachments (if any)
  1587. KMMessagePart newAttachPart;
  1588. for ( TQValueVector<Attachment>::iterator it = mAttachments.begin() ; it != mAttachments.end() ; ++it ) {
  1589. const bool cryptFlagsDifferent = ( it->encrypt != doEncryptBody || it->sign != doSignBody ) ;
  1590. if ( !cryptFlagsDifferent && mEarlyAddAttachments )
  1591. continue;
  1592. const bool encryptThisNow = doEncrypt && cryptFlagsDifferent && it->encrypt ;
  1593. const bool signThisNow = doSign && cryptFlagsDifferent && it->sign ;
  1594. if ( !encryptThisNow && !signThisNow ) {
  1595. msg->addBodyPart( it->part );
  1596. // Assemble the message. Not sure why, but this fixes the vanishing boundary parameter
  1597. (void)msg->asDwMessage();
  1598. continue;
  1599. }
  1600. KMMessagePart& rEncryptMessagePart( *it->part );
  1601. DwBodyPart* innerDwPart = msg->createDWBodyPart( it->part );
  1602. innerDwPart->Assemble();
  1603. TQByteArray encodedAttachment = KMail::Util::ByteArray( innerDwPart->AsString() );
  1604. delete innerDwPart;
  1605. innerDwPart = 0;
  1606. // replace simple LFs by CRLFs for all MIME supporting CryptPlugs
  1607. // according to RfC 2633, 3.1.1 Canonicalization
  1608. //kdDebug(5006) << "Converting LF to CRLF (see RfC 2633, 3.1.1 Canonicalization)" << endl;
  1609. encodedAttachment = KMail::Util::lf2crlf( encodedAttachment );
  1610. // sign this attachment
  1611. if( signThisNow ) {
  1612. pgpSignedMsg( encodedAttachment, format );
  1613. mRc = !mSignature.isEmpty();
  1614. if( mRc ) {
  1615. mRc = processStructuringInfo( "http://www.gnupg.org/aegypten/",
  1616. it->part->contentDescription(),
  1617. it->part->typeStr(),
  1618. it->part->subtypeStr(),
  1619. it->part->contentDisposition(),
  1620. it->part->contentTransferEncodingStr(),
  1621. encodedAttachment,
  1622. "signature",
  1623. mSignature,
  1624. newAttachPart, true, format );
  1625. if( mRc ) {
  1626. if( encryptThisNow ) {
  1627. rEncryptMessagePart = newAttachPart;
  1628. DwBodyPart* dwPart = msg->createDWBodyPart( &newAttachPart );
  1629. dwPart->Assemble();
  1630. encodedAttachment = KMail::Util::ByteArray( dwPart->AsString() );
  1631. delete dwPart;
  1632. dwPart = 0;
  1633. }
  1634. } else
  1635. KMessageBox::sorry( mComposeWin, mErrorProcessingStructuringInfo );
  1636. } else {
  1637. // quit the attachments' loop
  1638. break;
  1639. }
  1640. }
  1641. if( encryptThisNow ) {
  1642. TQByteArray encryptedBody;
  1643. Kpgp::Result result = pgpEncryptedMsg( encryptedBody,
  1644. encodedAttachment,
  1645. splitInfo.keys,
  1646. format );
  1647. if( Kpgp::Ok == result ) {
  1648. mRc = processStructuringInfo( "http://www.gnupg.org/aegypten/",
  1649. rEncryptMessagePart.contentDescription(),
  1650. rEncryptMessagePart.typeStr(),
  1651. rEncryptMessagePart.subtypeStr(),
  1652. rEncryptMessagePart.contentDisposition(),
  1653. rEncryptMessagePart.contentTransferEncodingStr(),
  1654. encodedAttachment,
  1655. "encrypted data",
  1656. encryptedBody,
  1657. newAttachPart, false, format );
  1658. if ( !mRc )
  1659. KMessageBox::sorry( mComposeWin, mErrorProcessingStructuringInfo );
  1660. } else
  1661. mRc = false;
  1662. }
  1663. msg->addBodyPart( &newAttachPart );
  1664. (void)msg->asDwMessage(); // Assemble the message. One gets a completely empty message otherwise :/
  1665. }
  1666. } else { // no attachments in the final message
  1667. if( !ourFineBodyPart.originalContentTypeStr().isNull() ) {
  1668. msg->headers().ContentType().FromString( ourFineBodyPart.originalContentTypeStr() );
  1669. msg->headers().ContentType().Parse();
  1670. kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : set top level Content-Type from originalContentTypeStr()=" << ourFineBodyPart.originalContentTypeStr() << endl;
  1671. } else {
  1672. TQCString ct = ourFineBodyPart.typeStr() + "/" + ourFineBodyPart.subtypeStr();
  1673. if ( ct == "multipart/mixed" )
  1674. ct += ";\n\tboundary=\"" + mMultipartMixedBoundary + '"';
  1675. else if ( ct == "multipart/alternative" )
  1676. ct += ";\n\tboundary=\"" + TQCString(mSaveBoundary.c_str()) + '"';
  1677. msg->headers().ContentType().FromString( ct );
  1678. msg->headers().ContentType().Parse();
  1679. kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : set top level Content-Type to " << ct << endl;
  1680. }
  1681. if ( !ourFineBodyPart.charset().isEmpty() )
  1682. msg->setCharset( ourFineBodyPart.charset() );
  1683. msg->setHeaderField( "Content-Transfer-Encoding",
  1684. ourFineBodyPart.contentTransferEncodingStr() );
  1685. msg->setHeaderField( "Content-Description",
  1686. ourFineBodyPart.contentDescription() );
  1687. msg->setHeaderField( "Content-Disposition",
  1688. ourFineBodyPart.contentDisposition() );
  1689. if ( mDebugComposerCrypto )
  1690. kdDebug(5006) << "MessageComposer::addBodyAndAttachments() : top level headers and body adjusted" << endl;
  1691. // set body content
  1692. msg->setBody( ourFineBodyPart.dwBody() );
  1693. }
  1694. msg->setHeaderField( "X-KMail-Recipients",
  1695. splitInfo.recipients.join(", "), KMMessage::Address );
  1696. if ( mDebugComposerCrypto ) {
  1697. kdDebug(5006) << "MessageComposer::addBodyAndAttachments():\n Final message:\n|||" << msg->asString() << "|||\n\n" << endl;
  1698. msg->headers().Assemble();
  1699. kdDebug(5006) << "\n\n\nMessageComposer::addBodyAndAttachments():\n Final headers:\n\n" << msg->headerAsString() << "|||\n\n\n\n\n" << endl;
  1700. }
  1701. }
  1702. //-----------------------------------------------------------------------------
  1703. // This method does not call any crypto ops, so it does not need to be async
  1704. bool MessageComposer::processStructuringInfo( const TQString bugURL,
  1705. const TQString contentDescClear,
  1706. const TQCString contentTypeClear,
  1707. const TQCString contentSubtypeClear,
  1708. const TQCString contentDispClear,
  1709. const TQCString contentTEncClear,
  1710. const TQByteArray& clearCStr,
  1711. const TQString /*contentDescCiph*/,
  1712. const TQByteArray& ciphertext,
  1713. KMMessagePart& resultingPart,
  1714. bool signing, Kleo::CryptoMessageFormat format )
  1715. {
  1716. assert( clearCStr.isEmpty() || clearCStr[clearCStr.size()-1] != '\0' ); // I was called with a TQCString !?
  1717. bool bOk = true;
  1718. if ( makeMimeObject( format, signing ) ) {
  1719. TQCString mainHeader = "Content-Type: ";
  1720. const char * toplevelCT = toplevelContentType( format, signing );
  1721. if ( toplevelCT )
  1722. mainHeader += toplevelCT;
  1723. else {
  1724. if( makeMultiMime( format, signing ) )
  1725. mainHeader += "text/plain";
  1726. else
  1727. mainHeader += contentTypeClear + '/' + contentSubtypeClear;
  1728. }
  1729. const TQCString boundaryCStr = KMime::multiPartBoundary();
  1730. // add "boundary" parameter
  1731. if ( makeMultiMime( format, signing ) )
  1732. mainHeader.replace( "%boundary", boundaryCStr );
  1733. if ( toplevelCT ) {
  1734. if ( const char * str = toplevelContentDisposition( format, signing ) ) {
  1735. mainHeader += "\nContent-Disposition: ";
  1736. mainHeader += str;
  1737. }
  1738. if ( !makeMultiMime( format, signing ) &&
  1739. binaryHint( format ) )
  1740. mainHeader += "\nContent-Transfer-Encoding: base64";
  1741. } else {
  1742. if( 0 < contentDispClear.length() ) {
  1743. mainHeader += "\nContent-Disposition: ";
  1744. mainHeader += contentDispClear;
  1745. }
  1746. if( 0 < contentTEncClear.length() ) {
  1747. mainHeader += "\nContent-Transfer-Encoding: ";
  1748. mainHeader += contentTEncClear;
  1749. }
  1750. }
  1751. //kdDebug(5006) << "processStructuringInfo: mainHeader=" << mainHeader << endl;
  1752. DwString mainDwStr;
  1753. mainDwStr = TQCString(mainHeader + "\n\n").data();
  1754. DwBodyPart mainDwPa( mainDwStr, 0 );
  1755. mainDwPa.Parse();
  1756. KMMessage::bodyPart( &mainDwPa, &resultingPart );
  1757. if( !makeMultiMime( format, signing ) ) {
  1758. if ( signing && includeCleartextWhenSigning( format ) ) {
  1759. TQByteArray bodyText( clearCStr );
  1760. KMail::Util::append( bodyText, "\n" );
  1761. KMail::Util::append( bodyText, ciphertext );
  1762. resultingPart.setBodyEncodedBinary( bodyText );
  1763. } else {
  1764. resultingPart.setBodyEncodedBinary( ciphertext );
  1765. }
  1766. } else {
  1767. // Build the encapsulated MIME parts.
  1768. // Build a MIME part holding the version information
  1769. // taking the body contents returned in
  1770. // structuring.data.bodyTextVersion.
  1771. TQCString versCStr, codeCStr;
  1772. if ( !signing && format == Kleo::OpenPGPMIMEFormat )
  1773. versCStr =
  1774. "Content-Type: application/pgp-encrypted\n"
  1775. "Content-Disposition: attachment\n"
  1776. "\n"
  1777. "Version: 1";
  1778. // Build a MIME part holding the code information
  1779. // taking the body contents returned in ciphertext.
  1780. const char * nestedCT = nestedContentType( format, signing );
  1781. assert( nestedCT );
  1782. codeCStr = "Content-Type: ";
  1783. codeCStr += nestedCT;
  1784. codeCStr += '\n';
  1785. if ( const char * str = nestedContentDisposition( format, signing ) ) {
  1786. codeCStr += "Content-Disposition: ";
  1787. codeCStr += str;
  1788. codeCStr += '\n';
  1789. }
  1790. if ( binaryHint( format ) ) {
  1791. codeCStr += "Content-Transfer-Encoding: base64\n\n";
  1792. codeCStr += KMime::Codec::codecForName( "base64" )->encodeToTQCString( ciphertext );
  1793. } else
  1794. codeCStr += '\n' + TQCString( ciphertext.data(), ciphertext.size() + 1 );
  1795. TQByteArray mainStr;
  1796. KMail::Util::append( mainStr, "--" );
  1797. KMail::Util::append( mainStr, boundaryCStr );
  1798. if ( signing && includeCleartextWhenSigning( format ) &&
  1799. !clearCStr.isEmpty() ) {
  1800. KMail::Util::append( mainStr, "\n" );
  1801. // clearCStr is the one that can be very big for large attachments, don't merge with the other lines
  1802. KMail::Util::append( mainStr, clearCStr );
  1803. KMail::Util::append( mainStr, "\n--" + boundaryCStr );
  1804. }
  1805. if ( !versCStr.isEmpty() )
  1806. KMail::Util::append( mainStr, "\n" + versCStr + "\n--" + boundaryCStr );
  1807. if( !codeCStr.isEmpty() )
  1808. KMail::Util::append( mainStr, "\n" + codeCStr + "\n--" + boundaryCStr );
  1809. KMail::Util::append( mainStr, "--\n" );
  1810. //kdDebug(5006) << "processStructuringInfo: mainStr=" << mainStr << endl;
  1811. resultingPart.setBodyEncodedBinary( mainStr );
  1812. }
  1813. } else { // not making a mime object, build a plain message body.
  1814. resultingPart.setContentDescription( contentDescClear );
  1815. resultingPart.setTypeStr( contentTypeClear );
  1816. resultingPart.setSubtypeStr( contentSubtypeClear );
  1817. resultingPart.setContentDisposition( contentDispClear );
  1818. resultingPart.setContentTransferEncodingStr( contentTEncClear );
  1819. TQByteArray resultingBody;
  1820. if ( signing && includeCleartextWhenSigning( format ) ) {
  1821. if( !clearCStr.isEmpty() )
  1822. KMail::Util::append( resultingBody, clearCStr );
  1823. }
  1824. if ( !ciphertext.isEmpty() )
  1825. KMail::Util::append( resultingBody, ciphertext );
  1826. else {
  1827. // Plugin error!
  1828. KMessageBox::sorry( mComposeWin,
  1829. i18n( "<qt><p>Error: The backend did not return "
  1830. "any encoded data.</p>"
  1831. "<p>Please report this bug:<br>%2</p></qt>" )
  1832. .arg( bugURL ) );
  1833. bOk = false;
  1834. }
  1835. resultingPart.setBodyEncodedBinary( resultingBody );
  1836. }
  1837. return bOk;
  1838. }
  1839. //-----------------------------------------------------------------------------
  1840. TQCString MessageComposer::plainTextFromMarkup( const TQString& markupText )
  1841. {
  1842. TQTextEdit *hackConspiratorTextEdit = new TQTextEdit( markupText );
  1843. hackConspiratorTextEdit->setTextFormat(TQt::PlainText);
  1844. if ( !mDisableBreaking ) {
  1845. hackConspiratorTextEdit->setWordWrap( TQTextEdit::FixedColumnWidth );
  1846. hackConspiratorTextEdit->setWrapColumnOrWidth( mLineBreakColumn );
  1847. }
  1848. TQString text = hackConspiratorTextEdit->text();
  1849. TQCString textbody;
  1850. const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
  1851. if( mCharset == "us-ascii" ) {
  1852. textbody = KMMsgBase::toUsAscii( text );
  1853. } else if( codec == 0 ) {
  1854. kdDebug(5006) << "Something is wrong and I can not get a codec." << endl;
  1855. textbody = text.local8Bit();
  1856. } else {
  1857. text = codec->toUnicode( text.latin1(), text.length() );
  1858. textbody = codec->fromUnicode( text );
  1859. }
  1860. if (textbody.isNull()) textbody = "";
  1861. delete hackConspiratorTextEdit;
  1862. return textbody;
  1863. }
  1864. //-----------------------------------------------------------------------------
  1865. TQByteArray MessageComposer::breakLinesAndApplyCodec()
  1866. {
  1867. TQString text;
  1868. TQCString cText;
  1869. if( mDisableBreaking || mIsRichText || !GlobalSettings::self()->wordWrap() )
  1870. text = mComposeWin->mEditor->text();
  1871. else
  1872. text = mComposeWin->mEditor->brokenText();
  1873. text.truncate( text.length() ); // to ensure text.size()==text.length()+1
  1874. TQString newText;
  1875. const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
  1876. if( mCharset == "us-ascii" ) {
  1877. cText = KMMsgBase::toUsAscii( text );
  1878. newText = TQString::fromLatin1( cText );
  1879. } else if( codec == 0 ) {
  1880. kdDebug(5006) << "Something is wrong and I can not get a codec." << endl;
  1881. cText = text.local8Bit();
  1882. newText = TQString::fromLocal8Bit( cText );
  1883. } else {
  1884. cText = codec->fromUnicode( text );
  1885. newText = codec->toUnicode( cText );
  1886. }
  1887. if (cText.isNull()) cText = "";
  1888. if( !text.isEmpty() && (newText != text) ) {
  1889. TQString oldText = mComposeWin->mEditor->text();
  1890. mComposeWin->mEditor->setText( newText );
  1891. KCursorSaver idle( KBusyPtr::idle() );
  1892. bool anyway = ( KMessageBox::warningYesNo( mComposeWin,
  1893. i18n("<qt>Not all characters fit into the chosen"
  1894. " encoding.<br><br>Send the message anyway?</qt>"),
  1895. i18n("Some Characters Will Be Lost"),
  1896. i18n("Lose Characters"), i18n("Change Encoding") ) == KMessageBox::Yes );
  1897. if( !anyway ) {
  1898. mComposeWin->mEditor->setText(oldText);
  1899. return TQByteArray();
  1900. }
  1901. }
  1902. // From RFC 3156:
  1903. // Note: The accepted OpenPGP convention is for signed data to end
  1904. // with a <CR><LF> sequence. Note that the <CR><LF> sequence
  1905. // immediately preceding a MIME boundary delimiter line is considered
  1906. // to be part of the delimiter in [3], 5.1. Thus, it is not part of
  1907. // the signed data preceding the delimiter line. An implementation
  1908. // which elects to adhere to the OpenPGP convention has to make sure
  1909. // it inserts a <CR><LF> pair on the last line of the data to be
  1910. // signed and transmitted (signed message and transmitted message
  1911. // MUST be identical).
  1912. // So make sure that the body ends with a <LF>.
  1913. if( cText.isEmpty() || cText[cText.length()-1] != '\n' ) {
  1914. kdDebug(5006) << "Added an <LF> on the last line" << endl;
  1915. cText += "\n";
  1916. }
  1917. return KMail::Util::byteArrayFromTQCStringNoDetach( cText );
  1918. }
  1919. //-----------------------------------------------------------------------------
  1920. void MessageComposer::pgpSignedMsg( const TQByteArray& cText, Kleo::CryptoMessageFormat format ) {
  1921. assert( cText.isEmpty() || cText[cText.size()-1] != '\0' ); // I was called with a TQCString !?
  1922. mSignature = TQByteArray();
  1923. const std::vector<GpgME::Key> signingKeys = mKeyResolver->signingKeys( format );
  1924. if ( signingKeys.empty() ) {
  1925. KMessageBox::sorry( mComposeWin,
  1926. i18n("This message could not be signed, "
  1927. "since no valid signing keys have been found; "
  1928. "this should actually never happen, "
  1929. "please report this bug.") );
  1930. return;
  1931. }
  1932. // TODO: ASync call? Likely, yes :-)
  1933. const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
  1934. assert( cpf );
  1935. const Kleo::CryptoBackend::Protocol * proto
  1936. = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
  1937. assert( proto ); /// hmmm.....?
  1938. std::auto_ptr<Kleo::SignJob> job( proto->signJob( armor( format ),
  1939. textMode( format ) ) );
  1940. if ( !job.get() ) {
  1941. KMessageBox::sorry( mComposeWin,
  1942. i18n("This message could not be signed, "
  1943. "since the chosen backend does not seem to support "
  1944. "signing; this should actually never happen, "
  1945. "please report this bug.") );
  1946. return;
  1947. }
  1948. TQByteArray signature;
  1949. const GpgME::SigningResult res =
  1950. job->exec( signingKeys, cText, signingMode( format ), signature );
  1951. {
  1952. std::stringstream ss;
  1953. ss << res;
  1954. kdDebug(5006) << ss.str().c_str() << endl;
  1955. }
  1956. if ( res.error().isCanceled() ) {
  1957. kdDebug() << "signing was canceled by user" << endl;
  1958. return;
  1959. }
  1960. if ( res.error() ) {
  1961. kdDebug() << "signing failed: " << res.error().asString() << endl;
  1962. job->showErrorDialog( mComposeWin );
  1963. return;
  1964. }
  1965. if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
  1966. if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
  1967. Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Signing Operation") );
  1968. mSignature = signature;
  1969. if ( mSignature.isEmpty() ) {
  1970. KMessageBox::sorry( mComposeWin,
  1971. i18n( "The signing operation failed. "
  1972. "Please make sure that the gpg-agent program "
  1973. "is running." ) );
  1974. }
  1975. }
  1976. //-----------------------------------------------------------------------------
  1977. Kpgp::Result MessageComposer::pgpEncryptedMsg( TQByteArray & encryptedBody,
  1978. const TQByteArray& cText,
  1979. const std::vector<GpgME::Key> & encryptionKeys,
  1980. Kleo::CryptoMessageFormat format )
  1981. {
  1982. // TODO: ASync call? Likely, yes :-)
  1983. const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
  1984. assert( cpf );
  1985. const Kleo::CryptoBackend::Protocol * proto
  1986. = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
  1987. assert( proto ); // hmmmm....?
  1988. std::auto_ptr<Kleo::EncryptJob> job( proto->encryptJob( armor( format ),
  1989. textMode( format ) ) );
  1990. if ( !job.get() ) {
  1991. KMessageBox::sorry( mComposeWin,
  1992. i18n("This message could not be encrypted, "
  1993. "since the chosen backend does not seem to support "
  1994. "encryption; this should actually never happen, "
  1995. "please report this bug.") );
  1996. return Kpgp::Failure;
  1997. }
  1998. const GpgME::EncryptionResult res =
  1999. job->exec( encryptionKeys, cText, true /* we do ownertrust ourselves */, encryptedBody );
  2000. {
  2001. std::stringstream ss;
  2002. ss << res;
  2003. kdDebug(5006) << ss.str().c_str() << endl;
  2004. }
  2005. if ( res.error().isCanceled() ) {
  2006. kdDebug() << "encryption was canceled by user" << endl;
  2007. return Kpgp::Canceled;
  2008. }
  2009. if ( res.error() ) {
  2010. kdDebug() << "encryption failed: " << res.error().asString() << endl;
  2011. job->showErrorDialog( mComposeWin );
  2012. return Kpgp::Failure;
  2013. }
  2014. if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
  2015. if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
  2016. Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Encryption Operation") );
  2017. return Kpgp::Ok;
  2018. }
  2019. Kpgp::Result MessageComposer::pgpSignedAndEncryptedMsg( TQByteArray & encryptedBody,
  2020. const TQByteArray& cText,
  2021. const std::vector<GpgME::Key> & signingKeys,
  2022. const std::vector<GpgME::Key> & encryptionKeys,
  2023. Kleo::CryptoMessageFormat format )
  2024. {
  2025. // TODO: ASync call? Likely, yes :-)
  2026. const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
  2027. assert( cpf );
  2028. const Kleo::CryptoBackend::Protocol * proto
  2029. = isSMIME( format ) ? cpf->smime() : cpf->openpgp() ;
  2030. assert( proto ); // hmmmm....?
  2031. std::auto_ptr<Kleo::SignEncryptJob> job( proto->signEncryptJob( armor( format ),
  2032. textMode( format ) ) );
  2033. if ( !job.get() ) {
  2034. KMessageBox::sorry( mComposeWin,
  2035. i18n("This message could not be signed and encrypted, "
  2036. "since the chosen backend does not seem to support "
  2037. "combined signing and encryption; this should actually never happen, "
  2038. "please report this bug.") );
  2039. return Kpgp::Failure;
  2040. }
  2041. const std::pair<GpgME::SigningResult,GpgME::EncryptionResult> res =
  2042. job->exec( signingKeys, encryptionKeys, cText, false, encryptedBody );
  2043. {
  2044. std::stringstream ss;
  2045. ss << res.first << '\n' << res.second;
  2046. kdDebug(5006) << ss.str().c_str() << endl;
  2047. }
  2048. if ( res.first.error().isCanceled() || res.second.error().isCanceled() ) {
  2049. kdDebug() << "encrypt/sign was canceled by user" << endl;
  2050. return Kpgp::Canceled;
  2051. }
  2052. if ( res.first.error() || res.second.error() ) {
  2053. if ( res.first.error() )
  2054. kdDebug() << "signing failed: " << res.first.error().asString() << endl;
  2055. else
  2056. kdDebug() << "encryption failed: " << res.second.error().asString() << endl;
  2057. job->showErrorDialog( mComposeWin );
  2058. return Kpgp::Failure;
  2059. }
  2060. if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
  2061. if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
  2062. Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Encryption Operation") );
  2063. return Kpgp::Ok;
  2064. }
  2065. #include "messagecomposer.moc"