TDE personal information management applications
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

5423 lignes
189KB

  1. // -*- mode: C++; c-file-style: "gnu" -*-
  2. // kmcomposewin.cpp
  3. // Author: Markus Wuebben <markus.wuebben@kde.org>
  4. // This code is published under the GPL.
  5. #undef GrayScale
  6. #undef Color
  7. #include <config.h>
  8. #define REALLY_WANT_KMCOMPOSEWIN_H
  9. #include "kmcomposewin.h"
  10. #undef REALLY_WANT_KMCOMPOSEWIN_H
  11. #include "kmedit.h"
  12. #include "kmlineeditspell.h"
  13. #include "kmatmlistview.h"
  14. #include "kmmainwin.h"
  15. #include "kmreadermainwin.h"
  16. #include "messagesender.h"
  17. #include "kmmsgpartdlg.h"
  18. #include <kpgpblock.h>
  19. #include <kaddrbook.h>
  20. #include "kmaddrbook.h"
  21. #include "kmmsgdict.h"
  22. #include "kmfolderimap.h"
  23. #include "kmfoldermgr.h"
  24. #include "kmfoldercombobox.h"
  25. #include "kmtransport.h"
  26. #include "kmcommands.h"
  27. #include "kcursorsaver.h"
  28. #include "partNode.h"
  29. #include "encodingdetector.h"
  30. #include "attachmentlistview.h"
  31. #include "transportmanager.h"
  32. using KMail::AttachmentListView;
  33. #include "dictionarycombobox.h"
  34. using KMail::DictionaryComboBox;
  35. #include "addressesdialog.h"
  36. using KPIM::AddressesDialog;
  37. #include "addresseeemailselection.h"
  38. using KPIM::AddresseeEmailSelection;
  39. using KPIM::AddresseeSelectorDialog;
  40. #include <maillistdrag.h>
  41. using KPIM::MailListDrag;
  42. #include "recentaddresses.h"
  43. using TDERecentAddress::RecentAddresses;
  44. #include "kleo_util.h"
  45. #include "stl_util.h"
  46. #include "recipientseditor.h"
  47. #include "editorwatcher.h"
  48. #include "attachmentcollector.h"
  49. #include "objecttreeparser.h"
  50. #include "kmfoldermaildir.h"
  51. #include <libkpimidentities/identitymanager.h>
  52. #include <libkpimidentities/identitycombo.h>
  53. #include <libkpimidentities/identity.h>
  54. #include <libtdepim/tdefileio.h>
  55. #include <libemailfunctions/email.h>
  56. #include <kleo/cryptobackendfactory.h>
  57. #include <kleo/exportjob.h>
  58. #include <kleo/specialjob.h>
  59. #include <ui/progressdialog.h>
  60. #include <ui/keyselectiondialog.h>
  61. #include <gpgmepp/context.h>
  62. #include <gpgmepp/key.h>
  63. #include <tdeio/netaccess.h>
  64. #include "tdelistboxdialog.h"
  65. #include "messagecomposer.h"
  66. #include "chiasmuskeyselector.h"
  67. #include <kcharsets.h>
  68. #include <tdecompletionbox.h>
  69. #include <kcursor.h>
  70. #include <kcombobox.h>
  71. #include <tdestdaccel.h>
  72. #include <tdepopupmenu.h>
  73. #include <kedittoolbar.h>
  74. #include <kkeydialog.h>
  75. #include <kdebug.h>
  76. #include <tdefiledialog.h>
  77. #include <twin.h>
  78. #include <kinputdialog.h>
  79. #include <tdemessagebox.h>
  80. #include <kurldrag.h>
  81. #include <tdeio/scheduler.h>
  82. #include <tdetempfile.h>
  83. #include <tdelocale.h>
  84. #include <tdeapplication.h>
  85. #include <kstatusbar.h>
  86. #include <tdeaction.h>
  87. #include <kstdaction.h>
  88. #include <kdirwatch.h>
  89. #include <kstdguiitem.h>
  90. #include <kiconloader.h>
  91. #include <kpushbutton.h>
  92. #include <kuserprofile.h>
  93. #include <krun.h>
  94. #include <ktempdir.h>
  95. #include <kstandarddirs.h>
  96. //#include <keditlistbox.h>
  97. #include "globalsettings.h"
  98. #include "replyphrases.h"
  99. #include <tdespell.h>
  100. #include <tdespelldlg.h>
  101. #include <spellingfilter.h>
  102. #include <ksyntaxhighlighter.h>
  103. #include <kcolordialog.h>
  104. #include <kzip.h>
  105. #include <ksavefile.h>
  106. #include <tqtabdialog.h>
  107. #include <tqregexp.h>
  108. #include <tqbuffer.h>
  109. #include <tqtooltip.h>
  110. #include <tqtextcodec.h>
  111. #include <tqheader.h>
  112. #include <tqwhatsthis.h>
  113. #include <tqfontdatabase.h>
  114. #include <mimelib/mimepp.h>
  115. #include <algorithm>
  116. #include <memory>
  117. #include <sys/stat.h>
  118. #include <sys/types.h>
  119. #include <stdlib.h>
  120. #include <unistd.h>
  121. #include <errno.h>
  122. #include <fcntl.h>
  123. #include <assert.h>
  124. #include "kmcomposewin.moc"
  125. #include "snippetwidget.h"
  126. KMail::Composer * KMail::makeComposer( KMMessage * msg, uint identitiy ) {
  127. return KMComposeWin::create( msg, identitiy );
  128. }
  129. KMail::Composer * KMComposeWin::create( KMMessage * msg, uint identitiy ) {
  130. return new KMComposeWin( msg, identitiy );
  131. }
  132. //-----------------------------------------------------------------------------
  133. KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
  134. : MailComposerIface(), KMail::Composer( "kmail-composer#" ),
  135. mSpellCheckInProgress( false ),
  136. mDone( false ),
  137. mAtmModified( false ),
  138. mAtmSelectNew( 0 ),
  139. mMsg( 0 ),
  140. mAttachMenu( 0 ),
  141. mSigningAndEncryptionExplicitlyDisabled( false ),
  142. mFolder( 0 ),
  143. mUseHTMLEditor( false ),
  144. mId( id ),
  145. mAttachPK( 0 ), mAttachMPK( 0 ),
  146. mAttachRemoveAction( 0 ), mAttachSaveAction( 0 ), mAttachPropertiesAction( 0 ),
  147. mAppendSignatureAction( 0 ), mPrependSignatureAction( 0 ), mInsertSignatureAction( 0 ),
  148. mSignAction( 0 ), mEncryptAction( 0 ), mRequestMDNAction( 0 ),
  149. mUrgentAction( 0 ), mAllFieldsAction( 0 ), mFromAction( 0 ),
  150. mReplyToAction( 0 ), mToAction( 0 ), mCcAction( 0 ), mBccAction( 0 ),
  151. mSubjectAction( 0 ),
  152. mIdentityAction( 0 ), mTransportAction( 0 ), mFccAction( 0 ),
  153. mWordWrapAction( 0 ), mFixedFontAction( 0 ), mAutoSpellCheckingAction( 0 ),
  154. mDictionaryAction( 0 ), mSnippetAction( 0 ),
  155. mEncodingAction( 0 ),
  156. mCryptoModuleAction( 0 ),
  157. mEncryptChiasmusAction( 0 ),
  158. mEncryptWithChiasmus( false ),
  159. mComposer( 0 ),
  160. mLabelWidth( 0 ),
  161. mAutoSaveTimer( 0 ), mLastAutoSaveErrno( 0 ),
  162. mSignatureStateIndicator( 0 ), mEncryptionStateIndicator( 0 ),
  163. mPreserveUserCursorPosition( false ),
  164. mPreventFccOverwrite( false ),
  165. mCheckForRecipients( true ),
  166. mCheckForForgottenAttachments( true ),
  167. mIgnoreStickyFields( false )
  168. {
  169. mClassicalRecipients = GlobalSettings::self()->recipientsEditorType() ==
  170. GlobalSettings::EnumRecipientsEditorType::Classic;
  171. mSubjectTextWasSpellChecked = false;
  172. if (kmkernel->xmlGuiInstance())
  173. setInstance( kmkernel->xmlGuiInstance() );
  174. mMainWidget = new TQWidget(this);
  175. // splitter between the headers area and the actual editor
  176. mHeadersToEditorSplitter = new TQSplitter( Qt::Vertical, mMainWidget, "mHeadersToEditorSplitter" );
  177. mHeadersToEditorSplitter->setChildrenCollapsible( false );
  178. mHeadersArea = new TQWidget( mHeadersToEditorSplitter );
  179. mHeadersArea->setSizePolicy( mHeadersToEditorSplitter->sizePolicy().horData(), TQSizePolicy::Maximum );
  180. TQVBoxLayout *v = new TQVBoxLayout( mMainWidget );
  181. v->addWidget( mHeadersToEditorSplitter );
  182. mIdentity = new KPIM::IdentityCombo(kmkernel->identityManager(), mHeadersArea);
  183. TQToolTip::add( mIdentity,
  184. i18n( "Select an identity for this message" ) );
  185. mDictionaryCombo = new DictionaryComboBox( mHeadersArea );
  186. TQToolTip::add( mDictionaryCombo,
  187. i18n( "Select the dictionary to use when spell-checking this message" ) );
  188. mFcc = new KMFolderComboBox(mHeadersArea);
  189. mFcc->showOutboxFolder( false );
  190. TQToolTip::add( mFcc,
  191. i18n( "Select the sent-mail folder where a copy of this message will be saved" ) );
  192. mTransport = new TQComboBox(true, mHeadersArea);
  193. TQToolTip::add( mTransport,
  194. i18n( "Select the outgoing account to use for sending this message" ) );
  195. mEdtFrom = new KMLineEdit(false,mHeadersArea, "fromLine");
  196. TQToolTip::add( mEdtFrom,
  197. i18n( "Set the \"From:\" email address for this message" ) );
  198. mEdtReplyTo = new KMLineEdit(true,mHeadersArea, "replyToLine");
  199. TQToolTip::add( mEdtReplyTo,
  200. i18n( "Set the \"Reply-To:\" email address for this message" ) );
  201. connect(mEdtReplyTo,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
  202. TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
  203. if ( mClassicalRecipients ) {
  204. mRecipientsEditor = 0;
  205. mEdtTo = new KMLineEdit(true,mHeadersArea, "toLine");
  206. mEdtCc = new KMLineEdit(true,mHeadersArea, "ccLine");
  207. mEdtBcc = new KMLineEdit(true,mHeadersArea, "bccLine");
  208. mLblTo = new TQLabel(mHeadersArea);
  209. mLblCc = new TQLabel(mHeadersArea);
  210. mLblBcc = new TQLabel(mHeadersArea);
  211. mBtnTo = new TQPushButton("...",mHeadersArea);
  212. mBtnCc = new TQPushButton("...",mHeadersArea);
  213. mBtnBcc = new TQPushButton("...",mHeadersArea);
  214. //mBtnFrom = new TQPushButton("...",mHeadersArea);
  215. TQString tip = i18n("Select email address(es)");
  216. TQToolTip::add( mBtnTo, tip );
  217. TQToolTip::add( mBtnCc, tip );
  218. TQToolTip::add( mBtnBcc, tip );
  219. mBtnTo->setFocusPolicy(TQ_NoFocus);
  220. mBtnCc->setFocusPolicy(TQ_NoFocus);
  221. mBtnBcc->setFocusPolicy(TQ_NoFocus);
  222. //mBtnFrom->setFocusPolicy(TQ_NoFocus);
  223. connect(mBtnTo,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookTo()));
  224. connect(mBtnCc,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookTo()));
  225. connect(mBtnBcc,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookTo()));
  226. //connect(mBtnFrom,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookFrom()));
  227. connect(mEdtTo,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
  228. TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
  229. connect(mEdtCc,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
  230. TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
  231. connect(mEdtBcc,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
  232. TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
  233. mEdtTo->setFocus();
  234. } else {
  235. mEdtTo = 0;
  236. mEdtCc = 0;
  237. mEdtBcc = 0;
  238. mLblTo = 0;
  239. mLblCc = 0;
  240. mLblBcc = 0;
  241. mBtnTo = 0;
  242. mBtnCc = 0;
  243. mBtnBcc = 0;
  244. //mBtnFrom = 0;
  245. mRecipientsEditor = new RecipientsEditor( mHeadersArea );
  246. connect( mRecipientsEditor,
  247. TQT_SIGNAL( completionModeChanged( TDEGlobalSettings::Completion ) ),
  248. TQT_SLOT( slotCompletionModeChanged( TDEGlobalSettings::Completion ) ) );
  249. connect( mRecipientsEditor, TQT_SIGNAL(sizeHintChanged()), TQT_SLOT(recipientEditorSizeHintChanged()) );
  250. mRecipientsEditor->setFocus();
  251. }
  252. mEdtSubject = new KMLineEditSpell(false,mHeadersArea, "subjectLine");
  253. TQToolTip::add( mEdtSubject,
  254. i18n( "Set a subject for this message" ) );
  255. mLblIdentity = new TQLabel( i18n("&Identity:"), mHeadersArea );
  256. mDictionaryLabel = new TQLabel( i18n("&Dictionary:"), mHeadersArea );
  257. mLblFcc = new TQLabel( i18n("&Sent-Mail folder:"), mHeadersArea );
  258. mLblTransport = new TQLabel( i18n("&Mail transport:"), mHeadersArea );
  259. mLblFrom = new TQLabel( i18n("sender address field", "&From:"), mHeadersArea );
  260. mLblReplyTo = new TQLabel( i18n("&Reply to:"), mHeadersArea );
  261. mLblSubject = new TQLabel( i18n("S&ubject:"), mHeadersArea );
  262. TQString sticky = i18n("Sticky");
  263. mBtnIdentity = new TQCheckBox(sticky,mHeadersArea);
  264. TQToolTip::add( mBtnIdentity,
  265. i18n( "Use the selected value as your identity for future messages" ) );
  266. mBtnFcc = new TQCheckBox(sticky,mHeadersArea);
  267. TQToolTip::add( mBtnFcc,
  268. i18n( "Use the selected value as your sent-mail folder for future messages" ) );
  269. mBtnTransport = new TQCheckBox(sticky,mHeadersArea);
  270. TQToolTip::add( mBtnTransport,
  271. i18n( "Use the selected value as your outgoing account for future messages" ) );
  272. mBtnDictionary = new TQCheckBox( sticky, mHeadersArea );
  273. TQToolTip::add( mBtnDictionary,
  274. i18n( "Use the selected value as your dictionary for future messages" ) );
  275. //setWFlags( WType_TopLevel | WStyle_Dialog );
  276. mHtmlMarkup = GlobalSettings::self()->useHtmlMarkup();
  277. mShowHeaders = GlobalSettings::self()->headers();
  278. mDone = false;
  279. mGrid = 0;
  280. mAtmListView = 0;
  281. mAtmList.setAutoDelete(true);
  282. mAtmTempList.setAutoDelete(true);
  283. mAtmModified = false;
  284. mAutoDeleteMsg = false;
  285. mFolder = 0;
  286. mAutoCharset = true;
  287. mFixedFontAction = 0;
  288. mTempDir = 0;
  289. // the attachment view is separated from the editor by a splitter
  290. mSplitter = new TQSplitter( Qt::Vertical, mHeadersToEditorSplitter, "mSplitter" );
  291. mSplitter->setChildrenCollapsible( false );
  292. mSnippetSplitter = new TQSplitter( Qt::Horizontal, mSplitter, "mSnippetSplitter");
  293. mSnippetSplitter->setChildrenCollapsible( false );
  294. TQWidget *editorAndCryptoStateIndicators = new TQWidget( mSnippetSplitter );
  295. TQVBoxLayout *vbox = new TQVBoxLayout( editorAndCryptoStateIndicators );
  296. TQHBoxLayout *hbox = new TQHBoxLayout( vbox );
  297. {
  298. mSignatureStateIndicator = new TQLabel( editorAndCryptoStateIndicators );
  299. mSignatureStateIndicator->setAlignment( TQt::AlignHCenter );
  300. hbox->addWidget( mSignatureStateIndicator );
  301. TDEConfigGroup reader( KMKernel::config(), "Reader" );
  302. TQPalette p( mSignatureStateIndicator->palette() );
  303. TQColor defaultSignedColor( 0x40, 0xFF, 0x40 ); // light green // pgp ok, trusted key
  304. TQColor defaultEncryptedColor( 0x00, 0x80, 0xFF ); // light blue // pgp encrypted
  305. p.setColor( TQColorGroup::Background, reader.readColorEntry( "PGPMessageOkKeyOk", &defaultSignedColor ) );
  306. mSignatureStateIndicator->setPalette( p );
  307. mEncryptionStateIndicator = new TQLabel( editorAndCryptoStateIndicators );
  308. mEncryptionStateIndicator->setAlignment( TQt::AlignHCenter );
  309. hbox->addWidget( mEncryptionStateIndicator );
  310. p.setColor( TQColorGroup::Background, reader.readColorEntry( "PGPMessageEncr" , &defaultEncryptedColor ) );
  311. mEncryptionStateIndicator->setPalette( p );
  312. }
  313. mEditor = new KMEdit( editorAndCryptoStateIndicators, this, mDictionaryCombo->spellConfig() );
  314. vbox->addWidget( mEditor );
  315. mSnippetWidget = new SnippetWidget( mEditor, actionCollection(), mSnippetSplitter );
  316. mSnippetWidget->setShown( GlobalSettings::self()->showSnippetManager() );
  317. // mSplitter->moveToFirst( editorAndCryptoStateIndicators );
  318. mSplitter->setOpaqueResize( true );
  319. mEditor->initializeAutoSpellChecking();
  320. mEditor->setTextFormat(TQt::PlainText);
  321. mEditor->setAcceptDrops( true );
  322. TQWhatsThis::add( mBtnIdentity,
  323. GlobalSettings::self()->stickyIdentityItem()->whatsThis() );
  324. TQWhatsThis::add( mBtnFcc,
  325. GlobalSettings::self()->stickyFccItem()->whatsThis() );
  326. TQWhatsThis::add( mBtnTransport,
  327. GlobalSettings::self()->stickyTransportItem()->whatsThis() );
  328. TQWhatsThis::add( mBtnTransport,
  329. GlobalSettings::self()->stickyDictionaryItem()->whatsThis() );
  330. mSpellCheckInProgress=false;
  331. setCaption( i18n("Composer") );
  332. setMinimumSize(200,200);
  333. mBtnIdentity->setFocusPolicy(TQ_NoFocus);
  334. mBtnFcc->setFocusPolicy(TQ_NoFocus);
  335. mBtnTransport->setFocusPolicy(TQ_NoFocus);
  336. mBtnDictionary->setFocusPolicy( TQ_NoFocus );
  337. mAtmListView = new AttachmentListView( this, mSplitter,
  338. "attachment list view" );
  339. mAtmListView->setSelectionMode( TQListView::Extended );
  340. mAtmListView->addColumn( i18n("Name"), 200 );
  341. mAtmListView->addColumn( i18n("Size"), 80 );
  342. mAtmListView->addColumn( i18n("Encoding"), 120 );
  343. int atmColType = mAtmListView->addColumn( i18n("Type"), 120 );
  344. // Stretch "Type".
  345. mAtmListView->header()->setStretchEnabled( true, atmColType );
  346. mAtmEncryptColWidth = 80;
  347. mAtmSignColWidth = 80;
  348. mAtmCompressColWidth = 100;
  349. mAtmColCompress = mAtmListView->addColumn( i18n("Compress"),
  350. mAtmCompressColWidth );
  351. mAtmColEncrypt = mAtmListView->addColumn( i18n("Encrypt"),
  352. mAtmEncryptColWidth );
  353. mAtmColSign = mAtmListView->addColumn( i18n("Sign"),
  354. mAtmSignColWidth );
  355. mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
  356. mAtmListView->setColumnWidth( mAtmColSign, 0 );
  357. mAtmListView->setAllColumnsShowFocus( true );
  358. connect( mAtmListView,
  359. TQT_SIGNAL( doubleClicked( TQListViewItem* ) ),
  360. TQT_SLOT( slotAttachEdit() ) );
  361. connect( mAtmListView,
  362. TQT_SIGNAL( rightButtonPressed( TQListViewItem*, const TQPoint&, int ) ),
  363. TQT_SLOT( slotAttachPopupMenu( TQListViewItem*, const TQPoint&, int ) ) );
  364. connect( mAtmListView,
  365. TQT_SIGNAL( selectionChanged() ),
  366. TQT_SLOT( slotUpdateAttachActions() ) );
  367. connect( mAtmListView,
  368. TQT_SIGNAL( attachmentDeleted() ),
  369. TQT_SLOT( slotAttachRemove() ) );
  370. connect( mAtmListView,
  371. TQT_SIGNAL( dragStarted() ),
  372. TQT_SLOT( slotAttachmentDragStarted() ) );
  373. mAttachMenu = 0;
  374. readConfig();
  375. setupStatusBar();
  376. setupActions();
  377. setupEditor();
  378. slotUpdateSignatureAndEncrypionStateIndicators();
  379. applyMainWindowSettings(KMKernel::config(), "Composer");
  380. connect( mEdtSubject, TQT_SIGNAL( subjectTextSpellChecked() ),
  381. TQT_SLOT( slotSubjectTextSpellChecked() ) );
  382. connect(mEdtSubject,TQT_SIGNAL(textChanged(const TQString&)),
  383. TQT_SLOT(slotUpdWinTitle(const TQString&)));
  384. connect(mIdentity,TQT_SIGNAL(identityChanged(uint)),
  385. TQT_SLOT(slotIdentityChanged(uint)));
  386. connect( kmkernel->identityManager(), TQT_SIGNAL(changed(uint)),
  387. TQT_SLOT(slotIdentityChanged(uint)));
  388. connect(mEdtFrom,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
  389. TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
  390. connect(kmkernel->folderMgr(),TQT_SIGNAL(folderRemoved(KMFolder*)),
  391. TQT_SLOT(slotFolderRemoved(KMFolder*)));
  392. connect(kmkernel->imapFolderMgr(),TQT_SIGNAL(folderRemoved(KMFolder*)),
  393. TQT_SLOT(slotFolderRemoved(KMFolder*)));
  394. connect(kmkernel->dimapFolderMgr(),TQT_SIGNAL(folderRemoved(KMFolder*)),
  395. TQT_SLOT(slotFolderRemoved(KMFolder*)));
  396. connect( kmkernel, TQT_SIGNAL( configChanged() ),
  397. TQT_TQOBJECT(this), TQT_SLOT( slotConfigChanged() ) );
  398. connect (mEditor, TQT_SIGNAL (spellcheck_done(int)),
  399. this, TQT_SLOT (slotSpellcheckDone (int)));
  400. connect (mEditor, TQT_SIGNAL( attachPNGImageData(const TQByteArray &) ),
  401. this, TQT_SLOT ( slotAttachPNGImageData(const TQByteArray &) ) );
  402. connect (mEditor, TQT_SIGNAL( focusChanged(bool) ),
  403. this, TQT_SLOT (editorFocusChanged(bool)) );
  404. mMainWidget->resize(480,510);
  405. setCentralWidget(mMainWidget);
  406. rethinkFields();
  407. if ( !mClassicalRecipients ) {
  408. // This is ugly, but if it isn't called the line edits in the recipients
  409. // editor aren't wide enough until the first resize event comes.
  410. rethinkFields();
  411. }
  412. if ( GlobalSettings::self()->useExternalEditor() ) {
  413. mEditor->setUseExternalEditor(true);
  414. mEditor->setExternalEditorPath( GlobalSettings::self()->externalEditor() );
  415. }
  416. initAutoSave();
  417. slotUpdateSignatureActions();
  418. mMsg = 0;
  419. if (aMsg)
  420. setMsg(aMsg);
  421. fontChanged( mEditor->currentFont() ); // set toolbar buttons to correct values
  422. mDone = true;
  423. }
  424. //-----------------------------------------------------------------------------
  425. KMComposeWin::~KMComposeWin()
  426. {
  427. writeConfig();
  428. if (mFolder && mMsg)
  429. {
  430. mAutoDeleteMsg = false;
  431. mFolder->addMsg(mMsg);
  432. // Ensure that the message is correctly and fully parsed
  433. mFolder->unGetMsg( mFolder->count() - 1 );
  434. }
  435. if (mAutoDeleteMsg) {
  436. delete mMsg;
  437. mMsg = 0;
  438. }
  439. TQMap<TDEIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.begin();
  440. while ( it != mMapAtmLoadData.end() )
  441. {
  442. TDEIO::Job *job = it.key();
  443. mMapAtmLoadData.remove( it );
  444. job->kill();
  445. it = mMapAtmLoadData.begin();
  446. }
  447. deleteAll( mComposedMessages );
  448. for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
  449. delete *it;
  450. }
  451. }
  452. void KMComposeWin::setAutoDeleteWindow( bool f )
  453. {
  454. if ( f )
  455. setWFlags( getWFlags() | WDestructiveClose );
  456. else
  457. setWFlags( getWFlags() & ~WDestructiveClose );
  458. }
  459. //-----------------------------------------------------------------------------
  460. void KMComposeWin::send(int how)
  461. {
  462. switch (how) {
  463. case 1:
  464. slotSendNow();
  465. break;
  466. default:
  467. case 0:
  468. // TODO: find out, what the default send method is and send it this way
  469. case 2:
  470. slotSendLater();
  471. break;
  472. }
  473. }
  474. //-----------------------------------------------------------------------------
  475. void KMComposeWin::addAttachmentsAndSend(const KURL::List &urls, const TQString &/*comment*/, int how)
  476. {
  477. if (urls.isEmpty())
  478. {
  479. send(how);
  480. return;
  481. }
  482. mAttachFilesSend = how;
  483. mAttachFilesPending = urls;
  484. connect(this, TQT_SIGNAL(attachmentAdded(const KURL&, bool)), TQT_SLOT(slotAttachedFile(const KURL&)));
  485. for( KURL::List::ConstIterator itr = urls.begin(); itr != urls.end(); ++itr ) {
  486. if (!addAttach( *itr ))
  487. mAttachFilesPending.remove(mAttachFilesPending.find(*itr)); // only remove one copy of the url
  488. }
  489. if (mAttachFilesPending.isEmpty() && mAttachFilesSend == how)
  490. {
  491. send(mAttachFilesSend);
  492. mAttachFilesSend = -1;
  493. }
  494. }
  495. void KMComposeWin::slotAttachedFile(const KURL &url)
  496. {
  497. if (mAttachFilesPending.isEmpty())
  498. return;
  499. mAttachFilesPending.remove(mAttachFilesPending.find(url)); // only remove one copy of url
  500. if (mAttachFilesPending.isEmpty())
  501. {
  502. send(mAttachFilesSend);
  503. mAttachFilesSend = -1;
  504. }
  505. }
  506. //-----------------------------------------------------------------------------
  507. void KMComposeWin::addAttachment(KURL url,TQString /*comment*/)
  508. {
  509. addAttach(url);
  510. }
  511. //-----------------------------------------------------------------------------
  512. void KMComposeWin::addAttachment(const TQString &name,
  513. const TQCString &/*cte*/,
  514. const TQByteArray &data,
  515. const TQCString &type,
  516. const TQCString &subType,
  517. const TQCString &paramAttr,
  518. const TQString &paramValue,
  519. const TQCString &contDisp)
  520. {
  521. if (!data.isEmpty()) {
  522. KMMessagePart *msgPart = new KMMessagePart;
  523. msgPart->setName(name);
  524. if( type == "message" && subType == "rfc822" ) {
  525. msgPart->setMessageBody( data );
  526. } else {
  527. TQValueList<int> dummy;
  528. msgPart->setBodyAndGuessCte(data, dummy,
  529. kmkernel->msgSender()->sendQuotedPrintable());
  530. }
  531. msgPart->setTypeStr(type);
  532. msgPart->setSubtypeStr(subType);
  533. msgPart->setParameter(paramAttr,paramValue);
  534. msgPart->setContentDisposition(contDisp);
  535. addAttach(msgPart);
  536. }
  537. }
  538. //-----------------------------------------------------------------------------
  539. void KMComposeWin::slotAttachPNGImageData(const TQByteArray &image)
  540. {
  541. bool ok;
  542. TQString attName = KInputDialog::getText( "KMail", i18n("Name of the attachment:"), TQString(), &ok, this );
  543. if ( !ok )
  544. return;
  545. if ( !attName.lower().endsWith(".png") ) attName += ".png";
  546. addAttachment( attName, "base64", image, "image", "png", TQCString(), TQString(), TQCString() );
  547. }
  548. //-----------------------------------------------------------------------------
  549. void KMComposeWin::setBody(TQString body)
  550. {
  551. mEditor->setText(body);
  552. }
  553. //-----------------------------------------------------------------------------
  554. bool KMComposeWin::event(TQEvent *e)
  555. {
  556. if (e->type() == TQEvent::ApplicationPaletteChange)
  557. {
  558. readColorConfig();
  559. }
  560. return KMail::Composer::event(e);
  561. }
  562. //-----------------------------------------------------------------------------
  563. void KMComposeWin::readColorConfig(void)
  564. {
  565. if ( GlobalSettings::self()->useDefaultColors() ) {
  566. mForeColor = TQColor(kapp->palette().active().text());
  567. mBackColor = TQColor(kapp->palette().active().base());
  568. } else {
  569. mForeColor = GlobalSettings::self()->foregroundColor();
  570. mBackColor = GlobalSettings::self()->backgroundColor();
  571. }
  572. // Color setup
  573. mPalette = kapp->palette();
  574. TQColorGroup cgrp = mPalette.active();
  575. cgrp.setColor( TQColorGroup::Base, mBackColor);
  576. cgrp.setColor( TQColorGroup::Text, mForeColor);
  577. mPalette.setDisabled(cgrp);
  578. mPalette.setActive(cgrp);
  579. mPalette.setInactive(cgrp);
  580. mEdtFrom->setPalette(mPalette);
  581. mEdtReplyTo->setPalette(mPalette);
  582. if ( mClassicalRecipients ) {
  583. mEdtTo->setPalette(mPalette);
  584. mEdtCc->setPalette(mPalette);
  585. mEdtBcc->setPalette(mPalette);
  586. }
  587. mEdtSubject->setPalette(mPalette);
  588. mTransport->setPalette(mPalette);
  589. mEditor->setPalette(mPalette);
  590. mFcc->setPalette(mPalette);
  591. }
  592. //-----------------------------------------------------------------------------
  593. void KMComposeWin::readConfig( bool reload /* = false */ )
  594. {
  595. mDefCharset = KMMessage::defaultCharset();
  596. mBtnIdentity->setChecked( GlobalSettings::self()->stickyIdentity() );
  597. if (mBtnIdentity->isChecked()) {
  598. mId = (GlobalSettings::self()->previousIdentity()!=0) ?
  599. GlobalSettings::self()->previousIdentity() : mId;
  600. }
  601. mBtnFcc->setChecked( GlobalSettings::self()->stickyFcc() );
  602. mBtnTransport->setChecked( GlobalSettings::self()->stickyTransport() );
  603. mBtnDictionary->setChecked( GlobalSettings::self()->stickyDictionary() );
  604. TQStringList transportHistory = GlobalSettings::self()->transportHistory();
  605. TQString currentTransport = GlobalSettings::self()->currentTransport();
  606. mEdtFrom->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  607. mEdtReplyTo->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  608. if ( mClassicalRecipients ) {
  609. mEdtTo->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  610. mEdtCc->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  611. mEdtBcc->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  612. }
  613. else
  614. mRecipientsEditor->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  615. readColorConfig();
  616. if ( GlobalSettings::self()->useDefaultFonts() ) {
  617. mBodyFont = TDEGlobalSettings::generalFont();
  618. mFixedFont = TDEGlobalSettings::fixedFont();
  619. } else {
  620. mBodyFont = GlobalSettings::self()->composerFont();
  621. mFixedFont = GlobalSettings::self()->fixedFont();
  622. }
  623. slotUpdateFont();
  624. mEdtFrom->setFont(mBodyFont);
  625. mEdtReplyTo->setFont(mBodyFont);
  626. if ( mClassicalRecipients ) {
  627. mEdtTo->setFont(mBodyFont);
  628. mEdtCc->setFont(mBodyFont);
  629. mEdtBcc->setFont(mBodyFont);
  630. }
  631. mEdtSubject->setFont(mBodyFont);
  632. if ( !reload ) {
  633. TQSize siz = GlobalSettings::self()->composerSize();
  634. if (siz.width() < 200) siz.setWidth(200);
  635. if (siz.height() < 200) siz.setHeight(200);
  636. resize(siz);
  637. if ( !GlobalSettings::self()->snippetSplitterPosition().isEmpty() ) {
  638. mSnippetSplitter->setSizes( GlobalSettings::self()->snippetSplitterPosition() );
  639. } else {
  640. TQValueList<int> defaults;
  641. defaults << (int)(width() * 0.8) << (int)(width() * 0.2);
  642. mSnippetSplitter->setSizes( defaults );
  643. }
  644. }
  645. mIdentity->setCurrentIdentity( mId );
  646. kdDebug(5006) << "KMComposeWin::readConfig. " << mIdentity->currentIdentityName() << endl;
  647. const KPIM::Identity & ident =
  648. kmkernel->identityManager()->identityForUoid( mIdentity->currentIdentity() );
  649. mTransport->clear();
  650. mTransport->insertStringList( KMTransportInfo::availableTransports() );
  651. while ( transportHistory.count() > (uint)GlobalSettings::self()->maxTransportEntries() )
  652. transportHistory.remove( transportHistory.last() );
  653. mTransport->insertStringList( transportHistory );
  654. mTransport->setCurrentText( GlobalSettings::self()->defaultTransport() );
  655. if ( mBtnTransport->isChecked() ) {
  656. setTransport( currentTransport );
  657. }
  658. if ( mBtnDictionary->isChecked() ) {
  659. mDictionaryCombo->setCurrentByDictionaryName( GlobalSettings::self()->previousDictionary() );
  660. } else {
  661. mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
  662. }
  663. TQString fccName = "";
  664. if ( mBtnFcc->isChecked() ) {
  665. fccName = GlobalSettings::self()->previousFcc();
  666. } else if ( !ident.fcc().isEmpty() ) {
  667. fccName = ident.fcc();
  668. }
  669. setFcc( fccName );
  670. }
  671. //-----------------------------------------------------------------------------
  672. void KMComposeWin::writeConfig(void)
  673. {
  674. GlobalSettings::self()->setHeaders( mShowHeaders );
  675. GlobalSettings::self()->setStickyFcc( mBtnFcc->isChecked() );
  676. if ( !mIgnoreStickyFields ) {
  677. GlobalSettings::self()->setCurrentTransport( mTransport->currentText() );
  678. GlobalSettings::self()->setStickyTransport( mBtnTransport->isChecked() );
  679. GlobalSettings::self()->setStickyDictionary( mBtnDictionary->isChecked() );
  680. GlobalSettings::self()->setStickyIdentity( mBtnIdentity->isChecked() );
  681. GlobalSettings::self()->setPreviousIdentity( mIdentity->currentIdentity() );
  682. }
  683. GlobalSettings::self()->setPreviousFcc( mFcc->getFolder()->idString() );
  684. GlobalSettings::self()->setPreviousDictionary( mDictionaryCombo->currentDictionaryName() );
  685. GlobalSettings::self()->setAutoSpellChecking(
  686. mAutoSpellCheckingAction->isChecked() );
  687. TQStringList transportHistory = GlobalSettings::self()->transportHistory();
  688. transportHistory.remove(mTransport->currentText());
  689. if (KMTransportInfo::availableTransports().findIndex(mTransport
  690. ->currentText()) == -1) {
  691. transportHistory.prepend(mTransport->currentText());
  692. }
  693. GlobalSettings::self()->setTransportHistory( transportHistory );
  694. GlobalSettings::self()->setUseFixedFont( mFixedFontAction->isChecked() );
  695. GlobalSettings::self()->setUseHtmlMarkup( mHtmlMarkup );
  696. GlobalSettings::self()->setComposerSize( size() );
  697. GlobalSettings::self()->setShowSnippetManager( mSnippetAction->isChecked() );
  698. TDEConfigGroupSaver saver( KMKernel::config(), "Geometry" );
  699. saveMainWindowSettings( KMKernel::config(), "Composer" );
  700. GlobalSettings::setSnippetSplitterPosition( mSnippetSplitter->sizes() );
  701. // make sure config changes are written to disk, cf. bug 127538
  702. GlobalSettings::self()->writeConfig();
  703. }
  704. //-----------------------------------------------------------------------------
  705. void KMComposeWin::autoSaveMessage()
  706. {
  707. kdDebug(5006) << k_funcinfo << endl;
  708. if ( !mMsg || mComposer || mAutoSaveFilename.isEmpty() )
  709. return;
  710. kdDebug(5006) << k_funcinfo << "autosaving message" << endl;
  711. if ( mAutoSaveTimer )
  712. mAutoSaveTimer->stop();
  713. connect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  714. TQT_TQOBJECT(this), TQT_SLOT( slotContinueAutoSave() ) );
  715. // This method is called when KMail crashed, so don't try signing/encryption
  716. // and don't disable controls because it is also called from a timer and
  717. // then the disabling is distracting.
  718. applyChanges( true, true );
  719. // Don't continue before the applyChanges is done!
  720. }
  721. void KMComposeWin::slotContinueAutoSave()
  722. {
  723. disconnect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  724. TQT_TQOBJECT(this), TQT_SLOT( slotContinueAutoSave() ) );
  725. // Ok, it's done now - continue dead letter saving
  726. if ( mComposedMessages.isEmpty() ) {
  727. kdDebug(5006) << "Composing the message failed." << endl;
  728. return;
  729. }
  730. KMMessage *msg = mComposedMessages.first();
  731. if ( !msg ) // a bit of extra defensiveness
  732. return;
  733. kdDebug(5006) << k_funcinfo << "opening autoSaveFile " << mAutoSaveFilename
  734. << endl;
  735. const TQString filename =
  736. KMKernel::localDataPath() + "autosave/cur/" + mAutoSaveFilename;
  737. KSaveFile autoSaveFile( filename, 0600 );
  738. int status = autoSaveFile.status();
  739. kdDebug(5006) << k_funcinfo << "autoSaveFile.status() = " << status << endl;
  740. if ( status == 0 ) { // no error
  741. kdDebug(5006) << "autosaving message in " << filename << endl;
  742. int fd = autoSaveFile.handle();
  743. const DwString& msgStr = msg->asDwString();
  744. if ( ::write( fd, msgStr.data(), msgStr.length() ) == -1 )
  745. status = errno;
  746. }
  747. if ( status == 0 ) {
  748. kdDebug(5006) << k_funcinfo << "closing autoSaveFile" << endl;
  749. autoSaveFile.close();
  750. mLastAutoSaveErrno = 0;
  751. }
  752. else {
  753. kdDebug(5006) << k_funcinfo << "autosaving failed" << endl;
  754. autoSaveFile.abort();
  755. if ( status != mLastAutoSaveErrno ) {
  756. // don't show the same error message twice
  757. KMessageBox::queuedMessageBox( 0, KMessageBox::Sorry,
  758. i18n("Autosaving the message as %1 "
  759. "failed.\n"
  760. "Reason: %2" )
  761. .arg( filename, strerror( status ) ),
  762. i18n("Autosaving Failed") );
  763. mLastAutoSaveErrno = status;
  764. }
  765. }
  766. if ( autoSaveInterval() > 0 )
  767. updateAutoSave();
  768. }
  769. //-----------------------------------------------------------------------------
  770. void KMComposeWin::slotView(void)
  771. {
  772. if (!mDone)
  773. return; // otherwise called from rethinkFields during the construction
  774. // which is not the intended behavior
  775. int id;
  776. //This sucks awfully, but no, I cannot get an activated(int id) from
  777. // actionContainer()
  778. if (!TQT_TQOBJECT_CONST(sender())->isA("TDEToggleAction"))
  779. return;
  780. TDEToggleAction *act = (TDEToggleAction *) sender();
  781. if (act == mAllFieldsAction)
  782. id = 0;
  783. else if (act == mIdentityAction)
  784. id = HDR_IDENTITY;
  785. else if (act == mTransportAction)
  786. id = HDR_TRANSPORT;
  787. else if (act == mFromAction)
  788. id = HDR_FROM;
  789. else if (act == mReplyToAction)
  790. id = HDR_REPLY_TO;
  791. else if (act == mToAction)
  792. id = HDR_TO;
  793. else if (act == mCcAction)
  794. id = HDR_CC;
  795. else if (act == mBccAction)
  796. id = HDR_BCC;
  797. else if (act == mSubjectAction)
  798. id = HDR_SUBJECT;
  799. else if (act == mFccAction)
  800. id = HDR_FCC;
  801. else if ( act == mDictionaryAction )
  802. id = HDR_DICTIONARY;
  803. else
  804. {
  805. id = 0;
  806. kdDebug(5006) << "Something is wrong (Oh, yeah?)" << endl;
  807. return;
  808. }
  809. // sanders There's a bug here this logic doesn't work if no
  810. // fields are shown and then show all fields is selected.
  811. // Instead of all fields being shown none are.
  812. if (!act->isChecked())
  813. {
  814. // hide header
  815. if (id > 0) mShowHeaders = mShowHeaders & ~id;
  816. else mShowHeaders = abs(mShowHeaders);
  817. }
  818. else
  819. {
  820. // show header
  821. if (id > 0) mShowHeaders |= id;
  822. else mShowHeaders = -abs(mShowHeaders);
  823. }
  824. rethinkFields(true);
  825. }
  826. int KMComposeWin::calcColumnWidth(int which, long allShowing, int width)
  827. {
  828. if ( (allShowing & which) == 0 )
  829. return width;
  830. TQLabel *w;
  831. if ( which == HDR_IDENTITY )
  832. w = mLblIdentity;
  833. else if ( which == HDR_DICTIONARY )
  834. w = mDictionaryLabel;
  835. else if ( which == HDR_FCC )
  836. w = mLblFcc;
  837. else if ( which == HDR_TRANSPORT )
  838. w = mLblTransport;
  839. else if ( which == HDR_FROM )
  840. w = mLblFrom;
  841. else if ( which == HDR_REPLY_TO )
  842. w = mLblReplyTo;
  843. else if ( which == HDR_SUBJECT )
  844. w = mLblSubject;
  845. else
  846. return width;
  847. w->setBuddy( mEditor ); // set dummy so we don't calculate width of '&' for this label.
  848. w->adjustSize();
  849. w->show();
  850. return TQMAX( width, w->sizeHint().width() );
  851. }
  852. void KMComposeWin::rethinkFields(bool fromSlot)
  853. {
  854. //This sucks even more but again no ids. sorry (sven)
  855. int mask, row, numRows;
  856. long showHeaders;
  857. if (mShowHeaders < 0)
  858. showHeaders = HDR_ALL;
  859. else
  860. showHeaders = mShowHeaders;
  861. for (mask=1,mNumHeaders=0; mask<=showHeaders; mask<<=1)
  862. if ((showHeaders&mask) != 0) mNumHeaders++;
  863. numRows = mNumHeaders + 1;
  864. delete mGrid;
  865. mGrid = new TQGridLayout( mHeadersArea, numRows, 3, KDialogBase::marginHint()/2, KDialogBase::spacingHint());
  866. mGrid->setColStretch(0, 1);
  867. mGrid->setColStretch(1, 100);
  868. mGrid->setColStretch(2, 1);
  869. mGrid->setRowStretch( mNumHeaders + 1, 100 );
  870. row = 0;
  871. kdDebug(5006) << "KMComposeWin::rethinkFields" << endl;
  872. if (mRecipientsEditor)
  873. mLabelWidth = mRecipientsEditor->setFirstColumnWidth( 0 );
  874. mLabelWidth = calcColumnWidth( HDR_IDENTITY, showHeaders, mLabelWidth );
  875. mLabelWidth = calcColumnWidth( HDR_DICTIONARY, showHeaders, mLabelWidth );
  876. mLabelWidth = calcColumnWidth( HDR_FCC, showHeaders, mLabelWidth );
  877. mLabelWidth = calcColumnWidth( HDR_TRANSPORT, showHeaders, mLabelWidth );
  878. mLabelWidth = calcColumnWidth( HDR_FROM, showHeaders, mLabelWidth );
  879. mLabelWidth = calcColumnWidth( HDR_REPLY_TO, showHeaders, mLabelWidth );
  880. mLabelWidth = calcColumnWidth( HDR_SUBJECT, showHeaders, mLabelWidth );
  881. if (!fromSlot) mAllFieldsAction->setChecked(showHeaders==HDR_ALL);
  882. if (!fromSlot) mIdentityAction->setChecked(abs(mShowHeaders)&HDR_IDENTITY);
  883. rethinkHeaderLine(showHeaders,HDR_IDENTITY, row,
  884. mLblIdentity, mIdentity, mBtnIdentity);
  885. if (!fromSlot) mDictionaryAction->setChecked(abs(mShowHeaders)&HDR_DICTIONARY);
  886. rethinkHeaderLine(showHeaders,HDR_DICTIONARY, row,
  887. mDictionaryLabel, mDictionaryCombo, mBtnDictionary );
  888. if (!fromSlot) mFccAction->setChecked(abs(mShowHeaders)&HDR_FCC);
  889. rethinkHeaderLine(showHeaders,HDR_FCC, row,
  890. mLblFcc, mFcc, mBtnFcc);
  891. if (!fromSlot) mTransportAction->setChecked(abs(mShowHeaders)&HDR_TRANSPORT);
  892. rethinkHeaderLine(showHeaders,HDR_TRANSPORT, row,
  893. mLblTransport, mTransport, mBtnTransport);
  894. if (!fromSlot) mFromAction->setChecked(abs(mShowHeaders)&HDR_FROM);
  895. rethinkHeaderLine(showHeaders,HDR_FROM, row,
  896. mLblFrom, mEdtFrom /*, mBtnFrom */ );
  897. TQWidget *prevFocus = mEdtFrom;
  898. if (!fromSlot) mReplyToAction->setChecked(abs(mShowHeaders)&HDR_REPLY_TO);
  899. rethinkHeaderLine(showHeaders,HDR_REPLY_TO,row,
  900. mLblReplyTo, mEdtReplyTo, 0);
  901. if ( showHeaders & HDR_REPLY_TO ) {
  902. prevFocus = connectFocusMoving( prevFocus, mEdtReplyTo );
  903. }
  904. if ( mClassicalRecipients ) {
  905. if (!fromSlot) mToAction->setChecked(abs(mShowHeaders)&HDR_TO);
  906. rethinkHeaderLine(showHeaders, HDR_TO, row,
  907. mLblTo, mEdtTo, mBtnTo,
  908. i18n("Primary Recipients"),
  909. i18n("<qt>The email addresses you put "
  910. "in this field receive a copy of the email.</qt>"));
  911. if ( showHeaders & HDR_TO ) {
  912. prevFocus = connectFocusMoving( prevFocus, mEdtTo );
  913. }
  914. if (!fromSlot) mCcAction->setChecked(abs(mShowHeaders)&HDR_CC);
  915. rethinkHeaderLine(showHeaders, HDR_CC, row,
  916. mLblCc, mEdtCc, mBtnCc,
  917. i18n("Additional Recipients"),
  918. i18n("<qt>The email addresses you put "
  919. "in this field receive a copy of the email. "
  920. "Technically it is the same thing as putting all the "
  921. "addresses in the <b>To:</b> field but differs in "
  922. "that it usually symbolises the receiver of the "
  923. "Carbon Copy (CC) is a listener, not the main "
  924. "recipient.</qt>"));
  925. if ( showHeaders & HDR_CC ) {
  926. prevFocus = connectFocusMoving( prevFocus, mEdtCc );
  927. }
  928. if (!fromSlot) mBccAction->setChecked(abs(mShowHeaders)&HDR_BCC);
  929. rethinkHeaderLine(showHeaders,HDR_BCC, row,
  930. mLblBcc, mEdtBcc, mBtnBcc,
  931. i18n("Hidden Recipients"),
  932. i18n("<qt>Essentially the same thing "
  933. "as the <b>Copy To:</b> field but differs in that "
  934. "all other recipients do not see who receives a "
  935. "blind copy.</qt>"));
  936. if ( showHeaders & HDR_BCC ) {
  937. prevFocus = connectFocusMoving( prevFocus, mEdtBcc );
  938. }
  939. } else {
  940. mGrid->addMultiCellWidget( mRecipientsEditor, row, row, 0, 2 );
  941. ++row;
  942. if ( showHeaders & HDR_REPLY_TO ) {
  943. connect( mEdtReplyTo, TQT_SIGNAL( focusDown() ), mRecipientsEditor,
  944. TQT_SLOT( setFocusTop() ) );
  945. } else {
  946. connect( mEdtFrom, TQT_SIGNAL( focusDown() ), mRecipientsEditor,
  947. TQT_SLOT( setFocusTop() ) );
  948. }
  949. if ( showHeaders & HDR_REPLY_TO ) {
  950. connect( mRecipientsEditor, TQT_SIGNAL( focusUp() ), mEdtReplyTo, TQT_SLOT( setFocus() ) );
  951. } else {
  952. connect( mRecipientsEditor, TQT_SIGNAL( focusUp() ), mEdtFrom, TQT_SLOT( setFocus() ) );
  953. }
  954. connect( mRecipientsEditor, TQT_SIGNAL( focusDown() ), mEdtSubject,
  955. TQT_SLOT( setFocus() ) );
  956. connect( mEdtSubject, TQT_SIGNAL( focusUp() ), mRecipientsEditor,
  957. TQT_SLOT( setFocusBottom() ) );
  958. prevFocus = mRecipientsEditor;
  959. }
  960. if (!fromSlot) mSubjectAction->setChecked(abs(mShowHeaders)&HDR_SUBJECT);
  961. rethinkHeaderLine(showHeaders,HDR_SUBJECT, row,
  962. mLblSubject, mEdtSubject);
  963. connectFocusMoving( mEdtSubject, mEditor );
  964. assert(row<=mNumHeaders);
  965. if( !mAtmList.isEmpty() )
  966. mAtmListView->show();
  967. else
  968. mAtmListView->hide();
  969. resize(this->size());
  970. repaint();
  971. mHeadersArea->setMaximumHeight( mHeadersArea->sizeHint().height() );
  972. mGrid->activate();
  973. mHeadersArea->show();
  974. slotUpdateAttachActions();
  975. mIdentityAction->setEnabled(!mAllFieldsAction->isChecked());
  976. mDictionaryAction->setEnabled( !mAllFieldsAction->isChecked() );
  977. mTransportAction->setEnabled(!mAllFieldsAction->isChecked());
  978. mFromAction->setEnabled(!mAllFieldsAction->isChecked());
  979. if ( mReplyToAction ) mReplyToAction->setEnabled(!mAllFieldsAction->isChecked());
  980. if ( mToAction ) mToAction->setEnabled(!mAllFieldsAction->isChecked());
  981. if ( mCcAction ) mCcAction->setEnabled(!mAllFieldsAction->isChecked());
  982. if ( mBccAction ) mBccAction->setEnabled(!mAllFieldsAction->isChecked());
  983. mFccAction->setEnabled(!mAllFieldsAction->isChecked());
  984. mSubjectAction->setEnabled(!mAllFieldsAction->isChecked());
  985. if (mRecipientsEditor)
  986. mRecipientsEditor->setFirstColumnWidth( mLabelWidth );
  987. }
  988. TQWidget *KMComposeWin::connectFocusMoving( TQWidget *prev, TQWidget *next )
  989. {
  990. connect( prev, TQT_SIGNAL( focusDown() ), next, TQT_SLOT( setFocus() ) );
  991. connect( next, TQT_SIGNAL( focusUp() ), prev, TQT_SLOT( setFocus() ) );
  992. return next;
  993. }
  994. //-----------------------------------------------------------------------------
  995. void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
  996. TQLabel* aLbl,
  997. TQLineEdit* aEdt, TQPushButton* aBtn,
  998. const TQString &toolTip, const TQString &whatsThis )
  999. {
  1000. if (aValue & aMask)
  1001. {
  1002. if ( !toolTip.isEmpty() )
  1003. TQToolTip::add( aLbl, toolTip );
  1004. if ( !whatsThis.isEmpty() )
  1005. TQWhatsThis::add( aLbl, whatsThis );
  1006. aLbl->setFixedWidth( mLabelWidth );
  1007. aLbl->setBuddy(aEdt);
  1008. mGrid->addWidget(aLbl, aRow, 0);
  1009. aEdt->setBackgroundColor( mBackColor );
  1010. aEdt->show();
  1011. if (aBtn) {
  1012. mGrid->addWidget(aEdt, aRow, 1);
  1013. mGrid->addWidget(aBtn, aRow, 2);
  1014. aBtn->show();
  1015. } else {
  1016. mGrid->addMultiCellWidget(aEdt, aRow, aRow, 1, 2 );
  1017. }
  1018. aRow++;
  1019. }
  1020. else
  1021. {
  1022. aLbl->hide();
  1023. aEdt->hide();
  1024. if (aBtn) aBtn->hide();
  1025. }
  1026. }
  1027. //-----------------------------------------------------------------------------
  1028. void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
  1029. TQLabel* aLbl,
  1030. TQComboBox* aCbx, TQCheckBox* aChk)
  1031. {
  1032. if (aValue & aMask)
  1033. {
  1034. aLbl->adjustSize();
  1035. aLbl->resize((int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
  1036. aLbl->setMinimumSize(aLbl->size());
  1037. aLbl->show();
  1038. aLbl->setBuddy(aCbx);
  1039. mGrid->addWidget(aLbl, aRow, 0);
  1040. aCbx->show();
  1041. aCbx->setMinimumSize(100, aLbl->height()+2);
  1042. mGrid->addWidget(aCbx, aRow, 1);
  1043. if ( aChk ) {
  1044. mGrid->addWidget(aChk, aRow, 2);
  1045. aChk->setFixedSize(aChk->sizeHint().width(), aLbl->height());
  1046. aChk->show();
  1047. }
  1048. aRow++;
  1049. }
  1050. else
  1051. {
  1052. aLbl->hide();
  1053. aCbx->hide();
  1054. if ( aChk )
  1055. aChk->hide();
  1056. }
  1057. }
  1058. //-----------------------------------------------------------------------------
  1059. void KMComposeWin::getTransportMenu()
  1060. {
  1061. TQStringList availTransports;
  1062. mActNowMenu->clear();
  1063. mActLaterMenu->clear();
  1064. availTransports = KMail::TransportManager::transportNames();
  1065. TQStringList::Iterator it;
  1066. int id = 0;
  1067. for(it = availTransports.begin(); it != availTransports.end() ; ++it, id++)
  1068. {
  1069. mActNowMenu->insertItem((*it).replace("&", "&&"), id);
  1070. mActLaterMenu->insertItem((*it).replace("&", "&&"), id);
  1071. }
  1072. }
  1073. //-----------------------------------------------------------------------------
  1074. void KMComposeWin::setupActions(void)
  1075. {
  1076. TDEActionMenu *actActionNowMenu, *actActionLaterMenu;
  1077. if (kmkernel->msgSender()->sendImmediate()) //default == send now?
  1078. {
  1079. //default = send now, alternative = queue
  1080. ( void ) new TDEAction( i18n("&Send Mail"), "mail_send", CTRL+Key_Return,
  1081. TQT_TQOBJECT(this), TQT_SLOT(slotSendNow()), actionCollection(),"send_default");
  1082. // FIXME: change to mail_send_via icon when this exits.
  1083. actActionNowMenu = new TDEActionMenu (i18n("&Send Mail Via"), "mail_send",
  1084. actionCollection(), "send_default_via" );
  1085. (void) new TDEAction (i18n("Send &Later"), "queue", 0, TQT_TQOBJECT(this),
  1086. TQT_SLOT(slotSendLater()), actionCollection(),"send_alternative");
  1087. actActionLaterMenu = new TDEActionMenu (i18n("Send &Later Via"), "queue",
  1088. actionCollection(), "send_alternative_via" );
  1089. }
  1090. else //no, default = send later
  1091. {
  1092. //default = queue, alternative = send now
  1093. (void) new TDEAction (i18n("Send &Later"), "queue",
  1094. CTRL+Key_Return,
  1095. TQT_TQOBJECT(this), TQT_SLOT(slotSendLater()), actionCollection(),"send_default");
  1096. actActionLaterMenu = new TDEActionMenu (i18n("Send &Later Via"), "queue",
  1097. actionCollection(), "send_default_via" );
  1098. ( void ) new TDEAction( i18n("&Send Mail"), "mail_send", 0,
  1099. TQT_TQOBJECT(this), TQT_SLOT(slotSendNow()), actionCollection(),"send_alternative");
  1100. // FIXME: change to mail_send_via icon when this exits.
  1101. actActionNowMenu = new TDEActionMenu (i18n("&Send Mail Via"), "mail_send",
  1102. actionCollection(), "send_alternative_via" );
  1103. }
  1104. // needed for sending "default transport"
  1105. actActionNowMenu->setDelayed(true);
  1106. actActionLaterMenu->setDelayed(true);
  1107. connect( actActionNowMenu, TQT_SIGNAL( activated() ), this,
  1108. TQT_SLOT( slotSendNow() ) );
  1109. connect( actActionLaterMenu, TQT_SIGNAL( activated() ), this,
  1110. TQT_SLOT( slotSendLater() ) );
  1111. mActNowMenu = actActionNowMenu->popupMenu();
  1112. mActLaterMenu = actActionLaterMenu->popupMenu();
  1113. connect( mActNowMenu, TQT_SIGNAL( activated( int ) ), this,
  1114. TQT_SLOT( slotSendNowVia( int ) ) );
  1115. connect( mActNowMenu, TQT_SIGNAL( aboutToShow() ), this,
  1116. TQT_SLOT( getTransportMenu() ) );
  1117. connect( mActLaterMenu, TQT_SIGNAL( activated( int ) ), this,
  1118. TQT_SLOT( slotSendLaterVia( int ) ) );
  1119. connect( mActLaterMenu, TQT_SIGNAL( aboutToShow() ), this,
  1120. TQT_SLOT( getTransportMenu() ) );
  1121. (void) new TDEAction (i18n("Save as &Draft"), "filesave", 0,
  1122. TQT_TQOBJECT(this), TQT_SLOT(slotSaveDraft()),
  1123. actionCollection(), "save_in_drafts");
  1124. (void) new TDEAction (i18n("Save as &Template"), "filesave", 0,
  1125. TQT_TQOBJECT(this), TQT_SLOT(slotSaveTemplate()),
  1126. actionCollection(), "save_in_templates");
  1127. (void) new TDEAction (i18n("&Insert File..."), "fileopen", 0,
  1128. TQT_TQOBJECT(this), TQT_SLOT(slotInsertFile()),
  1129. actionCollection(), "insert_file");
  1130. mRecentAction = new TDERecentFilesAction (i18n("&Insert File Recent"),
  1131. "fileopen", 0,
  1132. TQT_TQOBJECT(this), TQT_SLOT(slotInsertRecentFile(const KURL&)),
  1133. actionCollection(), "insert_file_recent");
  1134. mRecentAction->loadEntries( KMKernel::config() );
  1135. (void) new TDEAction (i18n("&Address Book"), "contents",0,
  1136. TQT_TQOBJECT(this), TQT_SLOT(slotAddrBook()),
  1137. actionCollection(), "addressbook");
  1138. (void) new TDEAction (i18n("&New Composer"), "mail_new",
  1139. TDEStdAccel::shortcut(TDEStdAccel::New),
  1140. TQT_TQOBJECT(this), TQT_SLOT(slotNewComposer()),
  1141. actionCollection(), "new_composer");
  1142. (void) new TDEAction (i18n("New Main &Window"), "window_new", 0,
  1143. TQT_TQOBJECT(this), TQT_SLOT(slotNewMailReader()),
  1144. actionCollection(), "open_mailreader");
  1145. if ( !mClassicalRecipients ) {
  1146. new TDEAction( i18n("Select &Recipients..."), CTRL + Key_L, TQT_TQOBJECT(mRecipientsEditor),
  1147. TQT_SLOT( selectRecipients() ), actionCollection(), "select_recipients" );
  1148. new TDEAction( i18n("Save &Distribution List..."), 0, TQT_TQOBJECT(mRecipientsEditor),
  1149. TQT_SLOT( saveDistributionList() ), actionCollection(),
  1150. "save_distribution_list" );
  1151. }
  1152. //KStdAction::save(TQT_TQOBJECT(this), TQT_SLOT(), actionCollection(), "save_message");
  1153. KStdAction::print (TQT_TQOBJECT(this), TQT_SLOT(slotPrint()), actionCollection());
  1154. KStdAction::close (TQT_TQOBJECT(this), TQT_SLOT(slotClose()), actionCollection());
  1155. KStdAction::undo (TQT_TQOBJECT(this), TQT_SLOT(slotUndo()), actionCollection());
  1156. KStdAction::redo (TQT_TQOBJECT(this), TQT_SLOT(slotRedo()), actionCollection());
  1157. KStdAction::cut (TQT_TQOBJECT(this), TQT_SLOT(slotCut()), actionCollection());
  1158. KStdAction::copy (TQT_TQOBJECT(this), TQT_SLOT(slotCopy()), actionCollection());
  1159. KStdAction::pasteText (TQT_TQOBJECT(this), TQT_SLOT(slotPasteClipboard()), actionCollection());
  1160. KStdAction::selectAll (TQT_TQOBJECT(this), TQT_SLOT(slotMarkAll()), actionCollection());
  1161. KStdAction::find (TQT_TQOBJECT(this), TQT_SLOT(slotFind()), actionCollection());
  1162. KStdAction::findNext(TQT_TQOBJECT(this), TQT_SLOT(slotSearchAgain()), actionCollection());
  1163. KStdAction::replace (TQT_TQOBJECT(this), TQT_SLOT(slotReplace()), actionCollection());
  1164. KStdAction::spelling (TQT_TQOBJECT(this), TQT_SLOT(slotSpellcheck()), actionCollection(), "spellcheck");
  1165. mPasteQuotation = new TDEAction (i18n("Pa&ste as Quotation"),0,TQT_TQOBJECT(this),TQT_SLOT( slotPasteClipboardAsQuotation()),
  1166. actionCollection(), "paste_quoted");
  1167. (void) new TDEAction (i18n("Paste as Attac&hment"),0,TQT_TQOBJECT(this),TQT_SLOT( slotPasteClipboardAsAttachment()),
  1168. actionCollection(), "paste_att");
  1169. TDEAction * addq = new TDEAction(i18n("Add &Quote Characters"), 0, TQT_TQOBJECT(this),
  1170. TQT_SLOT(slotAddQuotes()), actionCollection(), "tools_quote");
  1171. connect( mEditor, TQT_SIGNAL(selectionAvailable(bool)),
  1172. addq, TQT_SLOT(setEnabled(bool)) );
  1173. TDEAction * remq = new TDEAction(i18n("Re&move Quote Characters"), 0, TQT_TQOBJECT(this),
  1174. TQT_SLOT(slotRemoveQuotes()), actionCollection(), "tools_unquote");
  1175. connect( mEditor, TQT_SIGNAL(selectionAvailable(bool)),
  1176. remq, TQT_SLOT(setEnabled(bool)) );
  1177. (void) new TDEAction (i18n("Cl&ean Spaces"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotCleanSpace()),
  1178. actionCollection(), "clean_spaces");
  1179. mFixedFontAction = new TDEToggleAction( i18n("Use Fi&xed Font"), 0, TQT_TQOBJECT(this),
  1180. TQT_SLOT(slotUpdateFont()), actionCollection(), "toggle_fixedfont" );
  1181. mFixedFontAction->setChecked( GlobalSettings::self()->useFixedFont() );
  1182. //these are checkable!!!
  1183. mUrgentAction = new TDEToggleAction (i18n("&Urgent"), 0,
  1184. actionCollection(),
  1185. "urgent");
  1186. mRequestMDNAction = new TDEToggleAction ( i18n("&Request Disposition Notification"), 0,
  1187. actionCollection(),
  1188. "options_request_mdn");
  1189. mRequestMDNAction->setChecked(GlobalSettings::self()->requestMDN());
  1190. //----- Message-Encoding Submenu
  1191. mEncodingAction = new TDESelectAction( i18n( "Se&t Encoding" ), "charset",
  1192. 0, TQT_TQOBJECT(this), TQT_SLOT(slotSetCharset() ),
  1193. actionCollection(), "charsets" );
  1194. mWordWrapAction = new TDEToggleAction (i18n("&Wordwrap"), 0,
  1195. actionCollection(), "wordwrap");
  1196. mWordWrapAction->setChecked(GlobalSettings::self()->wordWrap());
  1197. connect(mWordWrapAction, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotWordWrapToggled(bool)));
  1198. mSnippetAction = new TDEToggleAction ( i18n("&Snippets"), 0,
  1199. actionCollection(), "snippets");
  1200. connect(mSnippetAction, TQT_SIGNAL(toggled(bool)), mSnippetWidget, TQT_SLOT(setShown(bool)) );
  1201. mSnippetAction->setChecked( GlobalSettings::self()->showSnippetManager() );
  1202. mAutoSpellCheckingAction =
  1203. new TDEToggleAction( i18n( "&Automatic Spellchecking" ), "spellcheck", 0,
  1204. actionCollection(), "options_auto_spellchecking" );
  1205. const bool spellChecking = GlobalSettings::self()->autoSpellChecking();
  1206. mAutoSpellCheckingAction->setEnabled( !GlobalSettings::self()->useExternalEditor() );
  1207. mAutoSpellCheckingAction->setChecked( !GlobalSettings::self()->useExternalEditor() && spellChecking );
  1208. slotAutoSpellCheckingToggled( !GlobalSettings::self()->useExternalEditor() && spellChecking );
  1209. connect( mAutoSpellCheckingAction, TQT_SIGNAL( toggled( bool ) ),
  1210. TQT_TQOBJECT(this), TQT_SLOT( slotAutoSpellCheckingToggled( bool ) ) );
  1211. TQStringList encodings = KMMsgBase::supportedEncodings(true);
  1212. encodings.prepend( i18n("Auto-Detect"));
  1213. mEncodingAction->setItems( encodings );
  1214. mEncodingAction->setCurrentItem( -1 );
  1215. //these are checkable!!!
  1216. markupAction = new TDEToggleAction (i18n("Formatting (HTML)"), 0, TQT_TQOBJECT(this),
  1217. TQT_SLOT(slotToggleMarkup()),
  1218. actionCollection(), "html");
  1219. mAllFieldsAction = new TDEToggleAction (i18n("&All Fields"), 0, TQT_TQOBJECT(this),
  1220. TQT_SLOT(slotView()),
  1221. actionCollection(), "show_all_fields");
  1222. mIdentityAction = new TDEToggleAction (i18n("&Identity"), 0, TQT_TQOBJECT(this),
  1223. TQT_SLOT(slotView()),
  1224. actionCollection(), "show_identity");
  1225. mDictionaryAction = new TDEToggleAction (i18n("&Dictionary"), 0, TQT_TQOBJECT(this),
  1226. TQT_SLOT(slotView()),
  1227. actionCollection(), "show_dictionary");
  1228. mFccAction = new TDEToggleAction (i18n("&Sent-Mail Folder"), 0, TQT_TQOBJECT(this),
  1229. TQT_SLOT(slotView()),
  1230. actionCollection(), "show_fcc");
  1231. mTransportAction = new TDEToggleAction (i18n("&Mail Transport"), 0, TQT_TQOBJECT(this),
  1232. TQT_SLOT(slotView()),
  1233. actionCollection(), "show_transport");
  1234. mFromAction = new TDEToggleAction (i18n("&From"), 0, TQT_TQOBJECT(this),
  1235. TQT_SLOT(slotView()),
  1236. actionCollection(), "show_from");
  1237. mReplyToAction = new TDEToggleAction (i18n("&Reply To"), 0, TQT_TQOBJECT(this),
  1238. TQT_SLOT(slotView()),
  1239. actionCollection(), "show_reply_to");
  1240. if ( mClassicalRecipients ) {
  1241. mToAction = new TDEToggleAction (i18n("&To"), 0, TQT_TQOBJECT(this),
  1242. TQT_SLOT(slotView()),
  1243. actionCollection(), "show_to");
  1244. mCcAction = new TDEToggleAction (i18n("&CC"), 0, TQT_TQOBJECT(this),
  1245. TQT_SLOT(slotView()),
  1246. actionCollection(), "show_cc");
  1247. mBccAction = new TDEToggleAction (i18n("&BCC"), 0, TQT_TQOBJECT(this),
  1248. TQT_SLOT(slotView()),
  1249. actionCollection(), "show_bcc");
  1250. }
  1251. mSubjectAction = new TDEToggleAction (i18n("S&ubject"), 0, TQT_TQOBJECT(this),
  1252. TQT_SLOT(slotView()),
  1253. actionCollection(), "show_subject");
  1254. //end of checkable
  1255. mAppendSignatureAction = new TDEAction (i18n("Append S&ignature"), 0, TQT_TQOBJECT(this),
  1256. TQT_SLOT(slotAppendSignature()),
  1257. actionCollection(), "append_signature");
  1258. mPrependSignatureAction = new TDEAction (i18n("Prepend S&ignature"), 0, TQT_TQOBJECT(this),
  1259. TQT_SLOT(slotPrependSignature()),
  1260. actionCollection(), "prepend_signature");
  1261. mInsertSignatureAction = new TDEAction (i18n("Insert Signature At C&ursor Position"), "edit", 0, TQT_TQOBJECT(this),
  1262. TQT_SLOT(slotInsertSignatureAtCursor()),
  1263. actionCollection(), "insert_signature_at_cursor_position");
  1264. mAttachPK = new TDEAction (i18n("Attach &Public Key..."), 0, TQT_TQOBJECT(this),
  1265. TQT_SLOT(slotInsertPublicKey()),
  1266. actionCollection(), "attach_public_key");
  1267. mAttachMPK = new TDEAction (i18n("Attach &My Public Key"), 0, TQT_TQOBJECT(this),
  1268. TQT_SLOT(slotInsertMyPublicKey()),
  1269. actionCollection(), "attach_my_public_key");
  1270. (void) new TDEAction (i18n("&Attach File..."), "attach",
  1271. 0, TQT_TQOBJECT(this), TQT_SLOT(slotAttachFile()),
  1272. actionCollection(), "attach");
  1273. mAttachRemoveAction = new TDEAction (i18n("&Remove Attachment"), 0, TQT_TQOBJECT(this),
  1274. TQT_SLOT(slotAttachRemove()),
  1275. actionCollection(), "remove");
  1276. mAttachSaveAction = new TDEAction (i18n("&Save Attachment As..."), "filesave",0,
  1277. TQT_TQOBJECT(this), TQT_SLOT(slotAttachSave()),
  1278. actionCollection(), "attach_save");
  1279. mAttachPropertiesAction = new TDEAction (i18n("Attachment Pr&operties"), 0, TQT_TQOBJECT(this),
  1280. TQT_SLOT(slotAttachProperties()),
  1281. actionCollection(), "attach_properties");
  1282. setStandardToolBarMenuEnabled(true);
  1283. KStdAction::keyBindings(TQT_TQOBJECT(this), TQT_SLOT(slotEditKeys()), actionCollection());
  1284. KStdAction::configureToolbars(TQT_TQOBJECT(this), TQT_SLOT(slotEditToolbars()), actionCollection());
  1285. KStdAction::preferences(kmkernel, TQT_SLOT(slotShowConfigurationDialog()), actionCollection());
  1286. (void) new TDEAction (i18n("&Spellchecker..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotSpellcheckConfig()),
  1287. actionCollection(), "setup_spellchecker");
  1288. if ( Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) ) {
  1289. TDEToggleAction * a = new TDEToggleAction( i18n( "Encrypt Message with Chiasmus..." ),
  1290. "chidecrypted", 0, actionCollection(),
  1291. "encrypt_message_chiasmus" );
  1292. a->setCheckedState( KGuiItem( i18n( "Encrypt Message with Chiasmus..." ), "chiencrypted" ) );
  1293. mEncryptChiasmusAction = a;
  1294. connect( mEncryptChiasmusAction, TQT_SIGNAL(toggled(bool)),
  1295. TQT_TQOBJECT(this), TQT_SLOT(slotEncryptChiasmusToggled(bool)) );
  1296. } else {
  1297. mEncryptChiasmusAction = 0;
  1298. }
  1299. mEncryptAction = new TDEToggleAction (i18n("&Encrypt Message"),
  1300. "decrypted", 0,
  1301. actionCollection(), "encrypt_message");
  1302. mSignAction = new TDEToggleAction (i18n("&Sign Message"),
  1303. "signature", 0,
  1304. actionCollection(), "sign_message");
  1305. // get PGP user id for the chosen identity
  1306. const KPIM::Identity & ident =
  1307. kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
  1308. // PENDING(marc): check the uses of this member and split it into
  1309. // smime/openpgp and or enc/sign, if necessary:
  1310. mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
  1311. mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
  1312. mLastEncryptActionState = false;
  1313. mLastSignActionState = GlobalSettings::self()->pgpAutoSign();
  1314. // "Attach public key" is only possible if OpenPGP support is available:
  1315. mAttachPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() );
  1316. // "Attach my public key" is only possible if OpenPGP support is
  1317. // available and the user specified his key for the current identity:
  1318. mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
  1319. !ident.pgpEncryptionKey().isEmpty() );
  1320. if ( !Kleo::CryptoBackendFactory::instance()->openpgp() && !Kleo::CryptoBackendFactory::instance()->smime() ) {
  1321. // no crypto whatsoever
  1322. mEncryptAction->setEnabled( false );
  1323. setEncryption( false );
  1324. mSignAction->setEnabled( false );
  1325. setSigning( false );
  1326. } else {
  1327. const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
  1328. && !ident.pgpSigningKey().isEmpty();
  1329. const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
  1330. && !ident.smimeSigningKey().isEmpty();
  1331. setEncryption( false );
  1332. setSigning( ( canOpenPGPSign || canSMIMESign ) && GlobalSettings::self()->pgpAutoSign() );
  1333. }
  1334. connect(mEncryptAction, TQT_SIGNAL(toggled(bool)),
  1335. TQT_SLOT(slotEncryptToggled( bool )));
  1336. connect(mSignAction, TQT_SIGNAL(toggled(bool)),
  1337. TQT_SLOT(slotSignToggled( bool )));
  1338. TQStringList l;
  1339. for ( int i = 0 ; i < numCryptoMessageFormats ; ++i )
  1340. l.push_back( Kleo::cryptoMessageFormatToLabel( cryptoMessageFormats[i] ) );
  1341. mCryptoModuleAction = new TDESelectAction( i18n( "&Cryptographic Message Format" ), 0,
  1342. TQT_TQOBJECT(this), TQT_SLOT(slotSelectCryptoModule()),
  1343. actionCollection(), "options_select_crypto" );
  1344. mCryptoModuleAction->setItems( l );
  1345. mCryptoModuleAction->setCurrentItem( format2cb( ident.preferredCryptoMessageFormat() ) );
  1346. mCryptoModuleAction->setToolTip( i18n( "Select a cryptographic format for this message" ) );
  1347. slotSelectCryptoModule( true /* initialize */ );
  1348. TQStringList styleItems;
  1349. styleItems << i18n( "Standard" );
  1350. styleItems << i18n( "Bulleted List (Disc)" );
  1351. styleItems << i18n( "Bulleted List (Circle)" );
  1352. styleItems << i18n( "Bulleted List (Square)" );
  1353. styleItems << i18n( "Ordered List (Decimal)" );
  1354. styleItems << i18n( "Ordered List (Alpha lower)" );
  1355. styleItems << i18n( "Ordered List (Alpha upper)" );
  1356. listAction = new TDESelectAction( i18n( "Select Style" ), 0, actionCollection(),
  1357. "text_list" );
  1358. listAction->setItems( styleItems );
  1359. listAction->setToolTip( i18n( "Select a list style" ) );
  1360. connect( listAction, TQT_SIGNAL( activated( const TQString& ) ),
  1361. TQT_SLOT( slotListAction( const TQString& ) ) );
  1362. fontAction = new TDEFontAction( "Select Font", 0, actionCollection(),
  1363. "text_font" );
  1364. fontAction->setToolTip( i18n( "Select a font" ) );
  1365. connect( fontAction, TQT_SIGNAL( activated( const TQString& ) ),
  1366. TQT_SLOT( slotFontAction( const TQString& ) ) );
  1367. fontSizeAction = new TDEFontSizeAction( "Select Size", 0, actionCollection(),
  1368. "text_size" );
  1369. fontSizeAction->setToolTip( i18n( "Select a font size" ) );
  1370. connect( fontSizeAction, TQT_SIGNAL( fontSizeChanged( int ) ),
  1371. TQT_SLOT( slotSizeAction( int ) ) );
  1372. alignLeftAction = new TDEToggleAction (i18n("Align Left"), "text_left", 0,
  1373. TQT_TQOBJECT(this), TQT_SLOT(slotAlignLeft()), actionCollection(),
  1374. "align_left");
  1375. alignLeftAction->setChecked( true );
  1376. alignRightAction = new TDEToggleAction (i18n("Align Right"), "text_right", 0,
  1377. TQT_TQOBJECT(this), TQT_SLOT(slotAlignRight()), actionCollection(),
  1378. "align_right");
  1379. alignCenterAction = new TDEToggleAction (i18n("Align Center"), "text_center", 0,
  1380. TQT_TQOBJECT(this), TQT_SLOT(slotAlignCenter()), actionCollection(),
  1381. "align_center");
  1382. textBoldAction = new TDEToggleAction( i18n("&Bold"), "text_bold", CTRL+Key_B,
  1383. TQT_TQOBJECT(this), TQT_SLOT(slotTextBold()),
  1384. actionCollection(), "text_bold");
  1385. textItalicAction = new TDEToggleAction( i18n("&Italic"), "text_italic", CTRL+Key_I,
  1386. TQT_TQOBJECT(this), TQT_SLOT(slotTextItalic()),
  1387. actionCollection(), "text_italic");
  1388. textUnderAction = new TDEToggleAction( i18n("&Underline"), "text_under", CTRL+Key_U,
  1389. TQT_TQOBJECT(this), TQT_SLOT(slotTextUnder()),
  1390. actionCollection(), "text_under");
  1391. actionFormatReset = new TDEAction( i18n( "Reset Font Settings" ), "eraser", 0,
  1392. TQT_TQOBJECT(this), TQT_SLOT( slotFormatReset() ),
  1393. actionCollection(), "format_reset");
  1394. actionFormatColor = new TDEAction( i18n( "Text Color..." ), "colorize", 0,
  1395. TQT_TQOBJECT(this), TQT_SLOT( slotTextColor() ),
  1396. actionCollection(), "format_color");
  1397. // editorFocusChanged(false);
  1398. createGUI("kmcomposerui.rc");
  1399. connect( toolBar("htmlToolBar"), TQT_SIGNAL( visibilityChanged(bool) ),
  1400. TQT_TQOBJECT(this), TQT_SLOT( htmlToolBarVisibilityChanged(bool) ) );
  1401. // In Kontact, this entry would read "Configure Kontact", but bring
  1402. // up KMail's config dialog. That's sensible, though, so fix the label.
  1403. TDEAction* configureAction = actionCollection()->action("options_configure" );
  1404. if ( configureAction )
  1405. configureAction->setText( i18n("Configure KMail..." ) );
  1406. }
  1407. //-----------------------------------------------------------------------------
  1408. void KMComposeWin::setupStatusBar(void)
  1409. {
  1410. statusBar()->insertItem("", 0, 1);
  1411. statusBar()->setItemAlignment(0, AlignLeft | AlignVCenter);
  1412. statusBar()->insertItem(i18n( " Spellcheck: %1 ").arg( " " ), 3, 0, true );
  1413. statusBar()->insertItem(i18n( " Column: %1 ").arg(" "), 2, 0, true);
  1414. statusBar()->insertItem(i18n( " Line: %1 ").arg(" "), 1, 0, true);
  1415. }
  1416. //-----------------------------------------------------------------------------
  1417. void KMComposeWin::updateCursorPosition()
  1418. {
  1419. int col,line;
  1420. TQString temp;
  1421. line = mEditor->currentLine();
  1422. col = mEditor->currentColumn();
  1423. temp = i18n(" Line: %1 ").arg(line+1);
  1424. statusBar()->changeItem(temp,1);
  1425. temp = i18n(" Column: %1 ").arg(col+1);
  1426. statusBar()->changeItem(temp,2);
  1427. }
  1428. //-----------------------------------------------------------------------------
  1429. void KMComposeWin::setupEditor(void)
  1430. {
  1431. //TQPopupMenu* menu;
  1432. mEditor->setModified(false);
  1433. TQFontMetrics fm(mBodyFont);
  1434. mEditor->setTabStopWidth(fm.width(TQChar(' ')) * 8);
  1435. //mEditor->setFocusPolicy(TQWidget::ClickFocus);
  1436. slotWordWrapToggled( GlobalSettings::self()->wordWrap() );
  1437. // Font setup
  1438. slotUpdateFont();
  1439. /* installRBPopup() is broken in tdelibs, we should wait for
  1440. the new klibtextedit (dnaber, 2002-01-01)
  1441. menu = new TQPopupMenu(this);
  1442. //#ifdef BROKEN
  1443. menu->insertItem(i18n("Undo"),mEditor,
  1444. TQT_SLOT(undo()), TDEStdAccel::shortcut(TDEStdAccel::Undo));
  1445. menu->insertItem(i18n("Redo"),mEditor,
  1446. TQT_SLOT(redo()), TDEStdAccel::shortcut(TDEStdAccel::Redo));
  1447. menu->insertSeparator();
  1448. //#endif //BROKEN
  1449. menu->insertItem(i18n("Cut"), this, TQT_SLOT(slotCut()));
  1450. menu->insertItem(i18n("Copy"), this, TQT_SLOT(slotCopy()));
  1451. menu->insertItem(i18n("Paste"), this, TQT_SLOT(slotPasteClipboard()));
  1452. menu->insertItem(i18n("Mark All"),this, TQT_SLOT(slotMarkAll()));
  1453. menu->insertSeparator();
  1454. menu->insertItem(i18n("Find..."), this, TQT_SLOT(slotFind()));
  1455. menu->insertItem(i18n("Replace..."), this, TQT_SLOT(slotReplace()));
  1456. menu->insertSeparator();
  1457. menu->insertItem(i18n("Fixed Font Widths"), this, TQT_SLOT(slotUpdateFont()));
  1458. mEditor->installRBPopup(menu);
  1459. */
  1460. updateCursorPosition();
  1461. connect(mEditor,TQT_SIGNAL(CursorPositionChanged()),TQT_SLOT(updateCursorPosition()));
  1462. connect( mEditor, TQT_SIGNAL( currentFontChanged( const TQFont & ) ),
  1463. TQT_TQOBJECT(this), TQT_SLOT( fontChanged( const TQFont & ) ) );
  1464. connect( mEditor, TQT_SIGNAL( currentAlignmentChanged( int ) ),
  1465. TQT_TQOBJECT(this), TQT_SLOT( alignmentChanged( int ) ) );
  1466. }
  1467. //-----------------------------------------------------------------------------
  1468. static TQString cleanedUpHeaderString( const TQString & s )
  1469. {
  1470. // remove invalid characters from the header strings
  1471. TQString res( s );
  1472. res.replace( '\r', "" );
  1473. res.replace( '\n', " " );
  1474. return res.stripWhiteSpace();
  1475. }
  1476. //-----------------------------------------------------------------------------
  1477. TQString KMComposeWin::subject() const
  1478. {
  1479. return cleanedUpHeaderString( mEdtSubject->text() );
  1480. }
  1481. //-----------------------------------------------------------------------------
  1482. TQString KMComposeWin::to() const
  1483. {
  1484. if ( mEdtTo ) {
  1485. return cleanedUpHeaderString( mEdtTo->text() );
  1486. } else if ( mRecipientsEditor ) {
  1487. return mRecipientsEditor->recipientString( Recipient::To );
  1488. } else {
  1489. return TQString();
  1490. }
  1491. }
  1492. //-----------------------------------------------------------------------------
  1493. TQString KMComposeWin::cc() const
  1494. {
  1495. if ( mEdtCc && !mEdtCc->isHidden() ) {
  1496. return cleanedUpHeaderString( mEdtCc->text() );
  1497. } else if ( mRecipientsEditor ) {
  1498. return mRecipientsEditor->recipientString( Recipient::Cc );
  1499. } else {
  1500. return TQString();
  1501. }
  1502. }
  1503. //-----------------------------------------------------------------------------
  1504. TQString KMComposeWin::bcc() const
  1505. {
  1506. if ( mEdtBcc && !mEdtBcc->isHidden() ) {
  1507. return cleanedUpHeaderString( mEdtBcc->text() );
  1508. } else if ( mRecipientsEditor ) {
  1509. return mRecipientsEditor->recipientString( Recipient::Bcc );
  1510. } else {
  1511. return TQString();
  1512. }
  1513. }
  1514. //-----------------------------------------------------------------------------
  1515. TQString KMComposeWin::from() const
  1516. {
  1517. return cleanedUpHeaderString( mEdtFrom->text() );
  1518. }
  1519. //-----------------------------------------------------------------------------
  1520. TQString KMComposeWin::replyTo() const
  1521. {
  1522. if ( mEdtReplyTo ) {
  1523. return cleanedUpHeaderString( mEdtReplyTo->text() );
  1524. } else {
  1525. return TQString();
  1526. }
  1527. }
  1528. //-----------------------------------------------------------------------------
  1529. void KMComposeWin::verifyWordWrapLengthIsAdequate(const TQString &body)
  1530. {
  1531. int maxLineLength = 0;
  1532. int curPos;
  1533. int oldPos = 0;
  1534. if (mEditor->TQTextEdit::wordWrap() == TQTextEdit::FixedColumnWidth) {
  1535. for (curPos = 0; curPos < (int)body.length(); ++curPos)
  1536. if (body[curPos] == '\n') {
  1537. if ((curPos - oldPos) > maxLineLength)
  1538. maxLineLength = curPos - oldPos;
  1539. oldPos = curPos;
  1540. }
  1541. if ((curPos - oldPos) > maxLineLength)
  1542. maxLineLength = curPos - oldPos;
  1543. if (mEditor->wrapColumnOrWidth() < maxLineLength) // column
  1544. mEditor->setWrapColumnOrWidth(maxLineLength);
  1545. }
  1546. }
  1547. //-----------------------------------------------------------------------------
  1548. void KMComposeWin::decryptOrStripOffCleartextSignature( TQCString& body )
  1549. {
  1550. TQPtrList<Kpgp::Block> pgpBlocks;
  1551. TQStrList nonPgpBlocks;
  1552. if( Kpgp::Module::prepareMessageForDecryption( body,
  1553. pgpBlocks, nonPgpBlocks ) )
  1554. {
  1555. // Only decrypt/strip off the signature if there is only one OpenPGP
  1556. // block in the message
  1557. if( pgpBlocks.count() == 1 )
  1558. {
  1559. Kpgp::Block* block = pgpBlocks.first();
  1560. if( ( block->type() == Kpgp::PgpMessageBlock ) ||
  1561. ( block->type() == Kpgp::ClearsignedBlock ) )
  1562. {
  1563. if( block->type() == Kpgp::PgpMessageBlock )
  1564. // try to decrypt this OpenPGP block
  1565. block->decrypt();
  1566. else
  1567. // strip off the signature
  1568. block->verify();
  1569. body = nonPgpBlocks.first()
  1570. + block->text()
  1571. + nonPgpBlocks.last();
  1572. }
  1573. }
  1574. }
  1575. }
  1576. //-----------------------------------------------------------------------------
  1577. void KMComposeWin::setTransport( const TQString & transport )
  1578. {
  1579. kdDebug(5006) << "KMComposeWin::setTransport( \"" << transport << "\" )" << endl;
  1580. // Don't change the transport combobox if transport is empty
  1581. if ( transport.isEmpty() )
  1582. return;
  1583. bool transportFound = false;
  1584. for ( int i = 0; i < mTransport->count(); ++i ) {
  1585. if ( mTransport->text(i) == transport ) {
  1586. transportFound = true;
  1587. mTransport->setCurrentItem(i);
  1588. kdDebug(5006) << "transport found, it's no. " << i << " in the list" << endl;
  1589. break;
  1590. }
  1591. }
  1592. if ( !transportFound ) { // unknown transport
  1593. kdDebug(5006) << "unknown transport \"" << transport << "\"" << endl;
  1594. if ( transport.startsWith("smtp://") || transport.startsWith("smtps://") ||
  1595. transport.startsWith("file://") ) {
  1596. // set custom transport
  1597. mTransport->setEditText( transport );
  1598. }
  1599. else {
  1600. // neither known nor custom transport -> use default transport
  1601. mTransport->setCurrentText( GlobalSettings::self()->defaultTransport() );
  1602. }
  1603. }
  1604. }
  1605. //-----------------------------------------------------------------------------
  1606. void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
  1607. bool allowDecryption, bool isModified)
  1608. {
  1609. //assert(newMsg!=0);
  1610. if(!newMsg)
  1611. {
  1612. kdDebug(5006) << "KMComposeWin::setMsg() : newMsg == 0!" << endl;
  1613. return;
  1614. }
  1615. mMsg = newMsg;
  1616. KPIM::IdentityManager * im = kmkernel->identityManager();
  1617. mEdtFrom->setText(mMsg->from());
  1618. mEdtReplyTo->setText(mMsg->replyTo());
  1619. if ( mClassicalRecipients ) {
  1620. mEdtTo->setText(mMsg->to());
  1621. mEdtCc->setText(mMsg->cc());
  1622. mEdtBcc->setText(mMsg->bcc());
  1623. } else {
  1624. mRecipientsEditor->setRecipientString( mMsg->to(), Recipient::To );
  1625. mRecipientsEditor->setRecipientString( mMsg->cc(), Recipient::Cc );
  1626. mRecipientsEditor->setRecipientString( mMsg->bcc(), Recipient::Bcc );
  1627. mRecipientsEditor->setFocusBottom();
  1628. }
  1629. mEdtSubject->setText(mMsg->subject());
  1630. const bool stickyIdentity = mBtnIdentity->isChecked() && !mIgnoreStickyFields;
  1631. const bool messageHasIdentity = !newMsg->headerField("X-KMail-Identity").isEmpty();
  1632. if (!stickyIdentity && messageHasIdentity)
  1633. mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
  1634. // don't overwrite the header values with identity specific values
  1635. // unless the identity is sticky
  1636. if ( !stickyIdentity ) {
  1637. disconnect(mIdentity,TQT_SIGNAL(identityChanged(uint)),
  1638. TQT_TQOBJECT(this), TQT_SLOT(slotIdentityChanged(uint)));
  1639. }
  1640. // load the mId into the gui, sticky or not, without emitting
  1641. mIdentity->setCurrentIdentity( mId );
  1642. const uint idToApply = mId;
  1643. if ( !stickyIdentity ) {
  1644. connect(mIdentity,TQT_SIGNAL(identityChanged(uint)),
  1645. TQT_TQOBJECT(this), TQT_SLOT(slotIdentityChanged(uint)));
  1646. } else {
  1647. // load the message's state into the mId, without applying it to the gui
  1648. // that's so we can detect that the id changed (because a sticky was set)
  1649. // on apply()
  1650. if ( messageHasIdentity )
  1651. mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
  1652. else
  1653. mId = im->defaultIdentity().uoid();
  1654. }
  1655. // manually load the identity's value into the fields; either the one from the
  1656. // messge, where appropriate, or the one from the sticky identity. What's in
  1657. // mId might have changed meanwhile, thus the save value
  1658. slotIdentityChanged( idToApply );
  1659. const KPIM::Identity & ident = im->identityForUoid( mIdentity->currentIdentity() );
  1660. // check for the presence of a DNT header, indicating that MDN's were
  1661. // requested
  1662. TQString mdnAddr = newMsg->headerField("Disposition-Notification-To");
  1663. mRequestMDNAction->setChecked( ( !mdnAddr.isEmpty() &&
  1664. im->thatIsMe( mdnAddr ) ) ||
  1665. GlobalSettings::self()->requestMDN() );
  1666. // check for presence of a priority header, indicating urgent mail:
  1667. mUrgentAction->setChecked( newMsg->isUrgent() );
  1668. if (!ident.isXFaceEnabled() || ident.xface().isEmpty())
  1669. mMsg->removeHeaderField("X-Face");
  1670. else
  1671. {
  1672. TQString xface = ident.xface();
  1673. if (!xface.isEmpty())
  1674. {
  1675. int numNL = ( xface.length() - 1 ) / 70;
  1676. for ( int i = numNL; i > 0; --i )
  1677. xface.insert( i*70, "\n\t" );
  1678. mMsg->setHeaderField("X-Face", xface);
  1679. }
  1680. }
  1681. // enable/disable encryption if the message was/wasn't encrypted
  1682. switch ( mMsg->encryptionState() ) {
  1683. case KMMsgFullyEncrypted: // fall through
  1684. case KMMsgPartiallyEncrypted:
  1685. mLastEncryptActionState = true;
  1686. break;
  1687. case KMMsgNotEncrypted:
  1688. mLastEncryptActionState = false;
  1689. break;
  1690. default: // nothing
  1691. break;
  1692. }
  1693. // enable/disable signing if the message was/wasn't signed
  1694. switch ( mMsg->signatureState() ) {
  1695. case KMMsgFullySigned: // fall through
  1696. case KMMsgPartiallySigned:
  1697. mLastSignActionState = true;
  1698. break;
  1699. case KMMsgNotSigned:
  1700. mLastSignActionState = false;
  1701. break;
  1702. default: // nothing
  1703. break;
  1704. }
  1705. // if these headers are present, the state of the message should be overruled
  1706. if ( mMsg->headers().FindField( "X-KMail-SignatureActionEnabled" ) )
  1707. mLastSignActionState = (mMsg->headerField( "X-KMail-SignatureActionEnabled" ) == "true");
  1708. if ( mMsg->headers().FindField( "X-KMail-EncryptActionEnabled" ) )
  1709. mLastEncryptActionState = (mMsg->headerField( "X-KMail-EncryptActionEnabled" ) == "true");
  1710. if ( mMsg->headers().FindField( "X-KMail-CryptoMessageFormat" ) )
  1711. mCryptoModuleAction->setCurrentItem( format2cb( static_cast<Kleo::CryptoMessageFormat>(
  1712. mMsg->headerField( "X-KMail-CryptoMessageFormat" ).toInt() ) ) );
  1713. mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
  1714. mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
  1715. if ( Kleo::CryptoBackendFactory::instance()->openpgp() || Kleo::CryptoBackendFactory::instance()->smime() ) {
  1716. const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
  1717. && !ident.pgpSigningKey().isEmpty();
  1718. const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
  1719. && !ident.smimeSigningKey().isEmpty();
  1720. setEncryption( mLastEncryptActionState );
  1721. setSigning( ( canOpenPGPSign || canSMIMESign ) && mLastSignActionState );
  1722. }
  1723. slotUpdateSignatureAndEncrypionStateIndicators();
  1724. // "Attach my public key" is only possible if the user uses OpenPGP
  1725. // support and he specified his key:
  1726. mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
  1727. !ident.pgpEncryptionKey().isEmpty() );
  1728. TQString transport = newMsg->headerField("X-KMail-Transport");
  1729. const bool stickyTransport = mBtnTransport->isChecked() && !mIgnoreStickyFields;
  1730. if (!stickyTransport && !transport.isEmpty()) {
  1731. setTransport( transport );
  1732. }
  1733. // If we are using the default transport, and the originating account name of the original message matches the name of a valid transport, use setTransport() to set it
  1734. // See Bug 1239
  1735. if (transport.isEmpty() && !mMsg->originatingAccountName().isEmpty()) {
  1736. TQString transportCandidate = mMsg->originatingAccountName();
  1737. bool transportFound = false;
  1738. for ( int i = 0; i < mTransport->count(); ++i ) {
  1739. if ( mTransport->text(i) == transportCandidate ) {
  1740. transportFound = true;
  1741. setTransport(transportCandidate);
  1742. break;
  1743. }
  1744. }
  1745. }
  1746. if (!mBtnFcc->isChecked())
  1747. {
  1748. if (!mMsg->fcc().isEmpty())
  1749. setFcc(mMsg->fcc());
  1750. else
  1751. setFcc(ident.fcc());
  1752. }
  1753. const bool stickyDictionary = mBtnDictionary->isChecked() && !mIgnoreStickyFields;
  1754. if ( !stickyDictionary ) {
  1755. mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
  1756. }
  1757. partNode * root = partNode::fromMessage( mMsg );
  1758. KMail::ObjectTreeParser otp; // all defaults are ok
  1759. otp.parseObjectTree( root );
  1760. KMail::AttachmentCollector ac;
  1761. ac.collectAttachmentsFrom( root );
  1762. for ( std::vector<partNode*>::const_iterator it = ac.attachments().begin() ; it != ac.attachments().end() ; ++it )
  1763. addAttach( new KMMessagePart( (*it)->msgPart() ) );
  1764. mEditor->setText( otp.textualContent() );
  1765. mCharset = otp.textualContentCharset();
  1766. if ( partNode * n = root->findType( DwMime::kTypeText, DwMime::kSubtypeHtml ) )
  1767. if ( partNode * p = n->parentNode() )
  1768. if ( p->hasType( DwMime::kTypeMultipart ) &&
  1769. p->hasSubType( DwMime::kSubtypeAlternative ) )
  1770. if ( mMsg->headerField( "X-KMail-Markup" ) == "true" ) {
  1771. toggleMarkup( true );
  1772. // get cte decoded body part
  1773. mCharset = n->msgPart().charset();
  1774. TQCString bodyDecoded = n->msgPart().bodyDecoded();
  1775. // respect html part charset
  1776. const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
  1777. if ( codec ) {
  1778. mEditor->setText( codec->toUnicode( bodyDecoded ) );
  1779. } else {
  1780. mEditor->setText( TQString::fromLocal8Bit( bodyDecoded ) );
  1781. }
  1782. }
  1783. if ( mCharset.isEmpty() )
  1784. mCharset = mMsg->charset();
  1785. if ( mCharset.isEmpty() )
  1786. mCharset = mDefCharset;
  1787. setCharset( mCharset );
  1788. /* Handle the special case of non-mime mails */
  1789. if ( mMsg->numBodyParts() == 0 && otp.textualContent().isEmpty() ) {
  1790. mCharset=mMsg->charset();
  1791. if ( mCharset.isEmpty() || mCharset == "default" )
  1792. mCharset = mDefCharset;
  1793. TQCString bodyDecoded = mMsg->bodyDecoded();
  1794. if( allowDecryption )
  1795. decryptOrStripOffCleartextSignature( bodyDecoded );
  1796. const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
  1797. if (codec) {
  1798. mEditor->setText(codec->toUnicode(bodyDecoded));
  1799. } else
  1800. mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
  1801. }
  1802. #ifdef BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
  1803. const int num = mMsg->numBodyParts();
  1804. kdDebug(5006) << "KMComposeWin::setMsg() mMsg->numBodyParts="
  1805. << mMsg->numBodyParts() << endl;
  1806. if ( num > 0 ) {
  1807. KMMessagePart bodyPart;
  1808. int firstAttachment = 0;
  1809. mMsg->bodyPart(1, &bodyPart);
  1810. if ( bodyPart.typeStr().lower() == "text" &&
  1811. bodyPart.subtypeStr().lower() == "html" ) {
  1812. // check whether we are inside a mp/al body part
  1813. partNode *root = partNode::fromMessage( mMsg );
  1814. partNode *node = root->findType( DwMime::kTypeText,
  1815. DwMime::kSubtypeHtml );
  1816. if ( node && node->parentNode() &&
  1817. node->parentNode()->hasType( DwMime::kTypeMultipart ) &&
  1818. node->parentNode()->hasSubType( DwMime::kSubtypeAlternative ) ) {
  1819. // we have a mp/al body part with a text and an html body
  1820. kdDebug(5006) << "KMComposeWin::setMsg() : text/html found" << endl;
  1821. firstAttachment = 2;
  1822. if ( mMsg->headerField( "X-KMail-Markup" ) == "true" )
  1823. toggleMarkup( true );
  1824. }
  1825. delete root; root = 0;
  1826. }
  1827. if ( firstAttachment == 0 ) {
  1828. mMsg->bodyPart(0, &bodyPart);
  1829. if ( bodyPart.typeStr().lower() == "text" ) {
  1830. // we have a mp/mx body with a text body
  1831. kdDebug(5006) << "KMComposeWin::setMsg() : text/* found" << endl;
  1832. firstAttachment = 1;
  1833. }
  1834. }
  1835. if ( firstAttachment != 0 ) // there's text to show
  1836. {
  1837. mCharset = bodyPart.charset();
  1838. if ( mCharset.isEmpty() || mCharset == "default" )
  1839. mCharset = mDefCharset;
  1840. TQCString bodyDecoded = bodyPart.bodyDecoded();
  1841. if( allowDecryption )
  1842. decryptOrStripOffCleartextSignature( bodyDecoded );
  1843. // As nobody seems to know the purpose of the following line and
  1844. // as it breaks word wrapping of long lines if drafts with attachments
  1845. // are opened for editting in the composer (cf. Bug#41102) I comment it
  1846. // out. Ingo, 2002-04-21
  1847. //verifyWordWrapLengthIsAdequate(bodyDecoded);
  1848. const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
  1849. if (codec)
  1850. mEditor->setText(codec->toUnicode(bodyDecoded));
  1851. else
  1852. mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
  1853. //mEditor->insertLine("\n", -1); <-- why ?
  1854. } else mEditor->setText("");
  1855. for( int i = firstAttachment; i < num; ++i )
  1856. {
  1857. KMMessagePart *msgPart = new KMMessagePart;
  1858. mMsg->bodyPart(i, msgPart);
  1859. TQCString mimeType = msgPart->typeStr().lower() + '/'
  1860. + msgPart->subtypeStr().lower();
  1861. // don't add the detached signature as attachment when editting a
  1862. // PGP/MIME signed message
  1863. if( mimeType != "application/pgp-signature" ) {
  1864. addAttach(msgPart);
  1865. }
  1866. }
  1867. } else{
  1868. mCharset=mMsg->charset();
  1869. if ( mCharset.isEmpty() || mCharset == "default" )
  1870. mCharset = mDefCharset;
  1871. TQCString bodyDecoded = mMsg->bodyDecoded();
  1872. if( allowDecryption )
  1873. decryptOrStripOffCleartextSignature( bodyDecoded );
  1874. const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
  1875. if (codec) {
  1876. mEditor->setText(codec->toUnicode(bodyDecoded));
  1877. } else
  1878. mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
  1879. }
  1880. setCharset(mCharset);
  1881. #endif // BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
  1882. if( (GlobalSettings::self()->autoTextSignature()=="auto") && mayAutoSign ) {
  1883. //
  1884. // Espen 2000-05-16
  1885. // Delay the signature appending. It may start a fileseletor.
  1886. // Not user friendy if this modal fileseletor opens before the
  1887. // composer.
  1888. //
  1889. //TQTimer::singleShot( 200, this, TQT_SLOT(slotAppendSignature()) );
  1890. if ( GlobalSettings::self()->prependSignature() ) {
  1891. TQTimer::singleShot( 0, this, TQT_SLOT(slotPrependSignature()) );
  1892. } else {
  1893. TQTimer::singleShot( 0, this, TQT_SLOT(slotAppendSignature()) );
  1894. }
  1895. }
  1896. if ( mMsg->getCursorPos() > 0 ) {
  1897. // The message has a cursor position explicitly set, so avoid
  1898. // changing it when appending the signature.
  1899. mPreserveUserCursorPosition = true;
  1900. }
  1901. setModified( isModified );
  1902. // do this even for new messages
  1903. mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
  1904. // honor "keep reply in this folder" setting even when the identity is changed later on
  1905. mPreventFccOverwrite = ( !newMsg->fcc().isEmpty() && ident.fcc() != newMsg->fcc() );
  1906. }
  1907. //-----------------------------------------------------------------------------
  1908. void KMComposeWin::setFcc( const TQString &idString )
  1909. {
  1910. // check if the sent-mail folder still exists
  1911. if ( ! idString.isEmpty() && kmkernel->findFolderById( idString ) ) {
  1912. mFcc->setFolder( idString );
  1913. } else {
  1914. mFcc->setFolder( kmkernel->sentFolder() );
  1915. }
  1916. }
  1917. //-----------------------------------------------------------------------------
  1918. bool KMComposeWin::isModified() const
  1919. {
  1920. return ( mEditor->isModified() ||
  1921. mEdtFrom->edited() ||
  1922. ( mEdtReplyTo && mEdtReplyTo->edited() ) ||
  1923. ( mEdtTo && mEdtTo->edited() ) ||
  1924. ( mEdtCc && mEdtCc->edited() ) ||
  1925. ( mEdtBcc && mEdtBcc->edited() ) ||
  1926. ( mRecipientsEditor && mRecipientsEditor->isModified() ) ||
  1927. mEdtSubject->edited() ||
  1928. mAtmModified ||
  1929. ( mTransport->lineEdit() && mTransport->lineEdit()->edited() ) );
  1930. }
  1931. //-----------------------------------------------------------------------------
  1932. void KMComposeWin::setModified( bool modified )
  1933. {
  1934. mEditor->setModified( modified );
  1935. if ( !modified ) {
  1936. mEdtFrom->setEdited( false );
  1937. if ( mEdtReplyTo ) mEdtReplyTo->setEdited( false );
  1938. if ( mEdtTo ) mEdtTo->setEdited( false );
  1939. if ( mEdtCc ) mEdtCc->setEdited( false );
  1940. if ( mEdtBcc ) mEdtBcc->setEdited( false );
  1941. if ( mRecipientsEditor ) mRecipientsEditor->clearModified();
  1942. mEdtSubject->setEdited( false );
  1943. mAtmModified = false ;
  1944. if ( mTransport->lineEdit() )
  1945. mTransport->lineEdit()->setEdited( false );
  1946. }
  1947. }
  1948. //-----------------------------------------------------------------------------
  1949. bool KMComposeWin::queryClose ()
  1950. {
  1951. if ( !mEditor->checkExternalEditorFinished() )
  1952. return false;
  1953. if ( kmkernel->shuttingDown() || kapp->sessionSaving() )
  1954. return true;
  1955. if ( mComposer && mComposer->isPerformingSignOperation() ) // since the non-gpg-agent gpg plugin gets a passphrase using TQDialog::exec()
  1956. return false; // the user can try to close the window, which destroys mComposer mid-call.
  1957. if ( isModified() ) {
  1958. bool istemplate = ( mFolder!=0 && mFolder->isTemplates() );
  1959. const TQString savebut = ( istemplate ?
  1960. i18n("Re&save as Template") :
  1961. i18n("&Save as Draft") );
  1962. const TQString savetext = ( istemplate ?
  1963. i18n("Resave this message in the Templates folder. "
  1964. "It can then be used at a later time.") :
  1965. i18n("Save this message in the Drafts folder. "
  1966. "It can then be edited and sent at a later time.") );
  1967. const int rc = KMessageBox::warningYesNoCancel( this,
  1968. i18n("Do you want to save the message for later or discard it?"),
  1969. i18n("Close Composer"),
  1970. KGuiItem(savebut, "filesave", TQString(), savetext),
  1971. KStdGuiItem::discard() );
  1972. if ( rc == KMessageBox::Cancel )
  1973. return false;
  1974. else if ( rc == KMessageBox::Yes ) {
  1975. // doSend will close the window. Just return false from this method
  1976. if ( istemplate ) {
  1977. slotSaveTemplate();
  1978. } else {
  1979. slotSaveDraft();
  1980. }
  1981. return false;
  1982. }
  1983. }
  1984. cleanupAutoSave();
  1985. return true;
  1986. }
  1987. //-----------------------------------------------------------------------------
  1988. bool KMComposeWin::userForgotAttachment()
  1989. {
  1990. bool checkForForgottenAttachments =
  1991. mCheckForForgottenAttachments && GlobalSettings::self()->showForgottenAttachmentWarning();
  1992. if ( !checkForForgottenAttachments || ( mAtmList.count() > 0 ) )
  1993. return false;
  1994. TQStringList attachWordsList = GlobalSettings::self()->attachmentKeywords();
  1995. if ( attachWordsList.isEmpty() ) {
  1996. // default value (FIXME: this is duplicated in configuredialog.cpp)
  1997. attachWordsList << TQString::fromLatin1("attachment")
  1998. << TQString::fromLatin1("attached");
  1999. if ( TQString::fromLatin1("attachment") != i18n("attachment") )
  2000. attachWordsList << i18n("attachment");
  2001. if ( TQString::fromLatin1("attached") != i18n("attached") )
  2002. attachWordsList << i18n("attached");
  2003. }
  2004. TQRegExp rx ( TQString::fromLatin1("\\b") +
  2005. attachWordsList.join("\\b|\\b") +
  2006. TQString::fromLatin1("\\b") );
  2007. rx.setCaseSensitive( false );
  2008. bool gotMatch = false;
  2009. // check whether the subject contains one of the attachment key words
  2010. // unless the message is a reply or a forwarded message
  2011. TQString subj = subject();
  2012. gotMatch = ( KMMessage::stripOffPrefixes( subj ) == subj )
  2013. && ( rx.search( subj ) >= 0 );
  2014. if ( !gotMatch ) {
  2015. // check whether the non-quoted text contains one of the attachment key
  2016. // words
  2017. TQRegExp quotationRx ("^([ \\t]*([|>:}#]|[A-Za-z]+>))+");
  2018. for ( int i = 0; i < mEditor->numLines(); ++i ) {
  2019. TQString line = mEditor->textLine( i );
  2020. gotMatch = ( quotationRx.search( line ) < 0 )
  2021. && ( rx.search( line ) >= 0 );
  2022. if ( gotMatch )
  2023. break;
  2024. }
  2025. }
  2026. if ( !gotMatch )
  2027. return false;
  2028. int rc = KMessageBox::warningYesNoCancel( this,
  2029. i18n("The message you have composed seems to refer to an "
  2030. "attached file but you have not attached anything.\n"
  2031. "Do you want to attach a file to your message?"),
  2032. i18n("File Attachment Reminder"),
  2033. i18n("&Attach File..."),
  2034. i18n("&Send as Is") );
  2035. if ( rc == KMessageBox::Cancel )
  2036. return true;
  2037. if ( rc == KMessageBox::Yes ) {
  2038. slotAttachFile();
  2039. //preceed with editing
  2040. return true;
  2041. }
  2042. return false;
  2043. }
  2044. //-----------------------------------------------------------------------------
  2045. void KMComposeWin::applyChanges( bool dontSignNorEncrypt, bool dontDisable )
  2046. {
  2047. kdDebug(5006) << "entering KMComposeWin::applyChanges" << endl;
  2048. if(!mMsg || mComposer) {
  2049. kdDebug(5006) << "KMComposeWin::applyChanges() : mMsg == 0!\n" << endl;
  2050. emit applyChangesDone( false );
  2051. return;
  2052. }
  2053. // Make new job and execute it
  2054. mComposer = new MessageComposer( this );
  2055. connect( mComposer, TQT_SIGNAL( done( bool ) ),
  2056. TQT_TQOBJECT(this), TQT_SLOT( slotComposerDone( bool ) ) );
  2057. // TODO: Add a cancel button for the following operations?
  2058. // Disable any input to the window, so that we have a snapshot of the
  2059. // composed stuff
  2060. if ( !dontDisable ) setEnabled( false );
  2061. // apply the current state to the composer and let it do it's thing
  2062. mComposer->setDisableBreaking( mDisableBreaking ); // FIXME
  2063. mComposer->applyChanges( dontSignNorEncrypt );
  2064. }
  2065. void KMComposeWin::slotComposerDone( bool rc )
  2066. {
  2067. deleteAll( mComposedMessages );
  2068. mComposedMessages = mComposer->composedMessageList();
  2069. emit applyChangesDone( rc );
  2070. delete mComposer;
  2071. mComposer = 0;
  2072. // re-enable the composewin, the messsage composition is now done
  2073. setEnabled( true );
  2074. }
  2075. const KPIM::Identity & KMComposeWin::identity() const {
  2076. return kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
  2077. }
  2078. uint KMComposeWin::identityUid() const {
  2079. return mIdentity->currentIdentity();
  2080. }
  2081. Kleo::CryptoMessageFormat KMComposeWin::cryptoMessageFormat() const {
  2082. if ( !mCryptoModuleAction )
  2083. return Kleo::AutoFormat;
  2084. return cb2format( mCryptoModuleAction->currentItem() );
  2085. }
  2086. bool KMComposeWin::encryptToSelf() const {
  2087. // return !Kpgp::Module::getKpgp() || Kpgp::Module::getKpgp()->encryptToSelf();
  2088. TDEConfigGroup group( KMKernel::config(), "Composer" );
  2089. return group.readBoolEntry( "crypto-encrypt-to-self", true );
  2090. }
  2091. bool KMComposeWin::queryExit ()
  2092. {
  2093. return true;
  2094. }
  2095. //-----------------------------------------------------------------------------
  2096. bool KMComposeWin::addAttach(const KURL aUrl)
  2097. {
  2098. if ( !aUrl.isValid() ) {
  2099. KMessageBox::sorry( this, i18n( "<qt><p>KMail could not recognize the location of the attachment (%1);</p>"
  2100. "<p>you have to specify the full path if you wish to attach a file.</p></qt>" )
  2101. .arg( aUrl.prettyURL() ) );
  2102. return false;
  2103. }
  2104. const int maxAttachmentSize = GlobalSettings::maximumAttachmentSize();
  2105. const uint maximumAttachmentSizeInByte = maxAttachmentSize*1024*1024;
  2106. if ( aUrl.isLocalFile() && TQFileInfo( aUrl.pathOrURL() ).size() > maximumAttachmentSizeInByte ) {
  2107. KMessageBox::sorry( this, i18n( "<qt><p>Your administrator has disallowed attaching files bigger than %1 MB.</p>" ).arg( maxAttachmentSize ) );
  2108. return false;
  2109. }
  2110. TDEIO::TransferJob *job = TDEIO::get(aUrl);
  2111. TDEIO::Scheduler::scheduleJob( job );
  2112. atmLoadData ld;
  2113. ld.url = aUrl;
  2114. ld.data = TQByteArray();
  2115. ld.insert = false;
  2116. if( !aUrl.fileEncoding().isEmpty() )
  2117. ld.encoding = aUrl.fileEncoding().latin1();
  2118. mMapAtmLoadData.insert(job, ld);
  2119. mAttachJobs[job] = aUrl;
  2120. connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
  2121. TQT_TQOBJECT(this), TQT_SLOT(slotAttachFileResult(TDEIO::Job *)));
  2122. connect(job, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
  2123. TQT_TQOBJECT(this), TQT_SLOT(slotAttachFileData(TDEIO::Job *, const TQByteArray &)));
  2124. return true;
  2125. }
  2126. //-----------------------------------------------------------------------------
  2127. void KMComposeWin::addAttach(const KMMessagePart* msgPart)
  2128. {
  2129. mAtmList.append(msgPart);
  2130. // show the attachment listbox if it does not up to now
  2131. if (mAtmList.count()==1)
  2132. {
  2133. mAtmListView->resize(mAtmListView->width(), 50);
  2134. mAtmListView->show();
  2135. resize(size());
  2136. }
  2137. // add a line in the attachment listbox
  2138. KMAtmListViewItem *lvi = new KMAtmListViewItem( mAtmListView );
  2139. msgPartToItem(msgPart, lvi);
  2140. mAtmItemList.append(lvi);
  2141. // the Attach file job has finished, so the possibly present tmp dir can be deleted now.
  2142. if ( mTempDir != 0 ) {
  2143. delete mTempDir;
  2144. mTempDir = 0;
  2145. }
  2146. connect( lvi, TQT_SIGNAL( compress( int ) ),
  2147. TQT_TQOBJECT(this), TQT_SLOT( compressAttach( int ) ) );
  2148. connect( lvi, TQT_SIGNAL( uncompress( int ) ),
  2149. TQT_TQOBJECT(this), TQT_SLOT( uncompressAttach( int ) ) );
  2150. slotUpdateAttachActions();
  2151. }
  2152. //-----------------------------------------------------------------------------
  2153. void KMComposeWin::slotUpdateAttachActions()
  2154. {
  2155. int selectedCount = 0;
  2156. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it ) {
  2157. if ( (*it)->isSelected() ) {
  2158. ++selectedCount;
  2159. }
  2160. }
  2161. mAttachRemoveAction->setEnabled( selectedCount >= 1 );
  2162. mAttachSaveAction->setEnabled( selectedCount == 1 );
  2163. mAttachPropertiesAction->setEnabled( selectedCount == 1 );
  2164. }
  2165. //-----------------------------------------------------------------------------
  2166. TQString KMComposeWin::prettyMimeType( const TQString& type )
  2167. {
  2168. TQString t = type.lower();
  2169. KServiceType::Ptr st = KServiceType::serviceType( t );
  2170. return st ? st->comment() : t;
  2171. }
  2172. void KMComposeWin::msgPartToItem(const KMMessagePart* msgPart,
  2173. KMAtmListViewItem *lvi, bool loadDefaults)
  2174. {
  2175. assert(msgPart != 0);
  2176. if (!msgPart->fileName().isEmpty())
  2177. lvi->setText(0, msgPart->fileName());
  2178. else
  2179. lvi->setText(0, msgPart->name());
  2180. lvi->setText(1, TDEIO::convertSize( msgPart->decodedSize()));
  2181. lvi->setText(2, msgPart->contentTransferEncodingStr());
  2182. lvi->setText(3, prettyMimeType(msgPart->typeStr() + "/" + msgPart->subtypeStr()));
  2183. lvi->setAttachmentSize(msgPart->decodedSize());
  2184. if ( loadDefaults ) {
  2185. if( canSignEncryptAttachments() ) {
  2186. lvi->enableCryptoCBs( true );
  2187. lvi->setEncrypt( mEncryptAction->isChecked() );
  2188. lvi->setSign( mSignAction->isChecked() );
  2189. } else {
  2190. lvi->enableCryptoCBs( false );
  2191. }
  2192. }
  2193. }
  2194. //-----------------------------------------------------------------------------
  2195. void KMComposeWin::removeAttach(const TQString &aUrl)
  2196. {
  2197. int idx;
  2198. KMMessagePart* msgPart;
  2199. for(idx=0,msgPart=mAtmList.first(); msgPart;
  2200. msgPart=mAtmList.next(),idx++) {
  2201. if (msgPart->name() == aUrl) {
  2202. removeAttach(idx);
  2203. return;
  2204. }
  2205. }
  2206. }
  2207. //-----------------------------------------------------------------------------
  2208. void KMComposeWin::removeAttach(int idx)
  2209. {
  2210. mAtmModified = true;
  2211. KMAtmListViewItem *item = static_cast<KMAtmListViewItem*>( mAtmItemList.at( idx ) );
  2212. if ( item->itemBelow() )
  2213. mAtmSelectNew = item->itemBelow();
  2214. else if ( item->itemAbove() )
  2215. mAtmSelectNew = item->itemAbove();
  2216. mAtmList.remove(idx);
  2217. delete mAtmItemList.take(idx);
  2218. if( mAtmList.isEmpty() )
  2219. {
  2220. mAtmListView->hide();
  2221. mAtmListView->setMinimumSize(0, 0);
  2222. resize(size());
  2223. }
  2224. }
  2225. //-----------------------------------------------------------------------------
  2226. bool KMComposeWin::encryptFlagOfAttachment(int idx)
  2227. {
  2228. return (int)(mAtmItemList.count()) > idx
  2229. ? static_cast<KMAtmListViewItem*>( mAtmItemList.at( idx ) )->isEncrypt()
  2230. : false;
  2231. }
  2232. //-----------------------------------------------------------------------------
  2233. bool KMComposeWin::signFlagOfAttachment(int idx)
  2234. {
  2235. return (int)(mAtmItemList.count()) > idx
  2236. ? ((KMAtmListViewItem*)(mAtmItemList.at( idx )))->isSign()
  2237. : false;
  2238. }
  2239. //-----------------------------------------------------------------------------
  2240. void KMComposeWin::addrBookSelInto()
  2241. {
  2242. if ( mClassicalRecipients ) {
  2243. if ( GlobalSettings::self()->addresseeSelectorType() ==
  2244. GlobalSettings::EnumAddresseeSelectorType::New ) {
  2245. addrBookSelIntoNew();
  2246. } else {
  2247. addrBookSelIntoOld();
  2248. }
  2249. } else {
  2250. kdWarning() << "To be implemented: call recipients picker." << endl;
  2251. }
  2252. }
  2253. void KMComposeWin::addrBookSelIntoOld()
  2254. {
  2255. AddressesDialog dlg( this );
  2256. TQString txt;
  2257. TQStringList lst;
  2258. txt = to();
  2259. if ( !txt.isEmpty() ) {
  2260. lst = KPIM::splitEmailAddrList( txt );
  2261. dlg.setSelectedTo( lst );
  2262. }
  2263. txt = mEdtCc->text();
  2264. if ( !txt.isEmpty() ) {
  2265. lst = KPIM::splitEmailAddrList( txt );
  2266. dlg.setSelectedCC( lst );
  2267. }
  2268. txt = mEdtBcc->text();
  2269. if ( !txt.isEmpty() ) {
  2270. lst = KPIM::splitEmailAddrList( txt );
  2271. dlg.setSelectedBCC( lst );
  2272. }
  2273. dlg.setRecentAddresses( RecentAddresses::self( KMKernel::config() )->tdeabcAddresses() );
  2274. if (dlg.exec()==TQDialog::Rejected) return;
  2275. mEdtTo->setText( dlg.to().join(", ") );
  2276. mEdtTo->setEdited( true );
  2277. mEdtCc->setText( dlg.cc().join(", ") );
  2278. mEdtCc->setEdited( true );
  2279. mEdtBcc->setText( dlg.bcc().join(", ") );
  2280. mEdtBcc->setEdited( true );
  2281. //Make sure BCC field is shown if needed
  2282. if ( !mEdtBcc->text().isEmpty() ) {
  2283. mShowHeaders |= HDR_BCC;
  2284. rethinkFields( false );
  2285. }
  2286. }
  2287. void KMComposeWin::addrBookSelIntoNew()
  2288. {
  2289. AddresseeEmailSelection selection;
  2290. AddresseeSelectorDialog dlg( &selection );
  2291. TQString txt;
  2292. TQStringList lst;
  2293. txt = to();
  2294. if ( !txt.isEmpty() ) {
  2295. lst = KPIM::splitEmailAddrList( txt );
  2296. selection.setSelectedTo( lst );
  2297. }
  2298. txt = mEdtCc->text();
  2299. if ( !txt.isEmpty() ) {
  2300. lst = KPIM::splitEmailAddrList( txt );
  2301. selection.setSelectedCC( lst );
  2302. }
  2303. txt = mEdtBcc->text();
  2304. if ( !txt.isEmpty() ) {
  2305. lst = KPIM::splitEmailAddrList( txt );
  2306. selection.setSelectedBCC( lst );
  2307. }
  2308. if (dlg.exec()==TQDialog::Rejected) return;
  2309. TQStringList list = selection.to() + selection.toDistributionLists();
  2310. mEdtTo->setText( list.join(", ") );
  2311. mEdtTo->setEdited( true );
  2312. list = selection.cc() + selection.ccDistributionLists();
  2313. mEdtCc->setText( list.join(", ") );
  2314. mEdtCc->setEdited( true );
  2315. list = selection.bcc() + selection.bccDistributionLists();
  2316. mEdtBcc->setText( list.join(", ") );
  2317. mEdtBcc->setEdited( true );
  2318. //Make sure BCC field is shown if needed
  2319. if ( !mEdtBcc->text().isEmpty() ) {
  2320. mShowHeaders |= HDR_BCC;
  2321. rethinkFields( false );
  2322. }
  2323. }
  2324. //-----------------------------------------------------------------------------
  2325. void KMComposeWin::setCharset(const TQCString& aCharset, bool forceDefault)
  2326. {
  2327. if ((forceDefault && GlobalSettings::self()->forceReplyCharset()) || aCharset.isEmpty())
  2328. mCharset = mDefCharset;
  2329. else
  2330. mCharset = aCharset.lower();
  2331. if ( mCharset.isEmpty() || mCharset == "default" )
  2332. mCharset = mDefCharset;
  2333. if (mAutoCharset)
  2334. {
  2335. mEncodingAction->setCurrentItem( 0 );
  2336. return;
  2337. }
  2338. TQStringList encodings = mEncodingAction->items();
  2339. int i = 0;
  2340. bool charsetFound = false;
  2341. for ( TQStringList::Iterator it = encodings.begin(); it != encodings.end();
  2342. ++it, i++ )
  2343. {
  2344. if (i > 0 && ((mCharset == "us-ascii" && i == 1) ||
  2345. (i != 1 && TDEGlobal::charsets()->codecForName(
  2346. TDEGlobal::charsets()->encodingForName(*it))
  2347. == TDEGlobal::charsets()->codecForName(mCharset))))
  2348. {
  2349. mEncodingAction->setCurrentItem( i );
  2350. slotSetCharset();
  2351. charsetFound = true;
  2352. break;
  2353. }
  2354. }
  2355. if (!aCharset.isEmpty() && !charsetFound) setCharset("", true);
  2356. }
  2357. //-----------------------------------------------------------------------------
  2358. void KMComposeWin::slotAddrBook()
  2359. {
  2360. KAddrBookExternal::openAddressBook(this);
  2361. }
  2362. //-----------------------------------------------------------------------------
  2363. void KMComposeWin::slotAddrBookFrom()
  2364. {
  2365. addrBookSelInto();
  2366. }
  2367. //-----------------------------------------------------------------------------
  2368. void KMComposeWin::slotAddrBookReplyTo()
  2369. {
  2370. addrBookSelInto();
  2371. }
  2372. //-----------------------------------------------------------------------------
  2373. void KMComposeWin::slotAddrBookTo()
  2374. {
  2375. addrBookSelInto();
  2376. }
  2377. //-----------------------------------------------------------------------------
  2378. void KMComposeWin::slotAttachFile()
  2379. {
  2380. // Create File Dialog and return selected file(s)
  2381. // We will not care about any permissions, existence or whatsoever in
  2382. // this function.
  2383. // Handle the case where the last savedir is gone. kolab/issue4057
  2384. TQString recent;
  2385. KURL recentURL = KFileDialog::getStartURL( TQString(), recent );
  2386. if ( !recentURL.url().isEmpty() &&
  2387. !TDEIO::NetAccess::exists( recentURL, true, this ) ) {
  2388. recentURL = KURL( TQDir::homeDirPath() );
  2389. }
  2390. KFileDialog fdlg( recentURL.url(), TQString(), this, 0, true );
  2391. fdlg.setOperationMode( KFileDialog::Other );
  2392. fdlg.setCaption( i18n( "Attach File" ) );
  2393. fdlg.okButton()->setGuiItem( KGuiItem( i18n( "&Attach" ),"fileopen" ) );
  2394. fdlg.setMode( KFile::Files );
  2395. fdlg.exec();
  2396. KURL::List files = fdlg.selectedURLs();
  2397. for (KURL::List::Iterator it = files.begin(); it != files.end(); ++it)
  2398. addAttach(*it);
  2399. }
  2400. //-----------------------------------------------------------------------------
  2401. void KMComposeWin::slotAttachFileData(TDEIO::Job *job, const TQByteArray &data)
  2402. {
  2403. TQMap<TDEIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
  2404. assert(it != mMapAtmLoadData.end());
  2405. TQBuffer buff((*it).data);
  2406. buff.open(IO_WriteOnly | IO_Append);
  2407. buff.writeBlock(data.data(), data.size());
  2408. buff.close();
  2409. }
  2410. //-----------------------------------------------------------------------------
  2411. void KMComposeWin::slotAttachFileResult(TDEIO::Job *job)
  2412. {
  2413. TQMap<TDEIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
  2414. assert(it != mMapAtmLoadData.end());
  2415. KURL attachURL;
  2416. TQMap<TDEIO::Job*, KURL>::iterator jit = mAttachJobs.find(job);
  2417. bool attachURLfound = (jit != mAttachJobs.end());
  2418. if (attachURLfound)
  2419. {
  2420. attachURL = jit.data();
  2421. mAttachJobs.remove(jit);
  2422. }
  2423. if (job->error())
  2424. {
  2425. mMapAtmLoadData.remove(it);
  2426. job->showErrorDialog();
  2427. if (attachURLfound)
  2428. emit attachmentAdded(attachURL, false);
  2429. return;
  2430. }
  2431. if ((*it).insert)
  2432. {
  2433. (*it).data.resize((*it).data.size() + 1);
  2434. (*it).data[(*it).data.size() - 1] = '\0';
  2435. if ( const TQTextCodec * codec = TDEGlobal::charsets()->codecForName((*it).encoding) )
  2436. mEditor->insert( codec->toUnicode( (*it).data ) );
  2437. else
  2438. mEditor->insert( TQString::fromLocal8Bit( (*it).data ) );
  2439. mMapAtmLoadData.remove(it);
  2440. if (attachURLfound)
  2441. emit attachmentAdded(attachURL, true);
  2442. return;
  2443. }
  2444. TQCString partCharset;
  2445. if ( !( *it ).url.fileEncoding().isEmpty() ) {
  2446. partCharset = TQCString( ( *it ).url.fileEncoding().latin1() );
  2447. } else {
  2448. EncodingDetector ed;
  2449. TDELocale *loc = TDEGlobal::locale();
  2450. ed.setAutoDetectLanguage( EncodingDetector::scriptForLanguageCode ( loc->language() ) );
  2451. ed.analyze( (*it).data );
  2452. partCharset = ed.encoding();
  2453. if ( partCharset.isEmpty() ) //shouldn't happen
  2454. partCharset = mCharset;
  2455. }
  2456. KMMessagePart* msgPart;
  2457. KCursorSaver busy(KBusyPtr::busy());
  2458. TQString name( (*it).url.fileName() );
  2459. // ask the job for the mime type of the file
  2460. TQString mimeType = static_cast<TDEIO::MimetypeJob*>(job)->mimetype();
  2461. if ( name.isEmpty() ) {
  2462. // URL ends with '/' (e.g. http://www.kde.org/)
  2463. // guess a reasonable filename
  2464. if( mimeType == "text/html" )
  2465. name = "index.html";
  2466. else {
  2467. // try to determine a reasonable extension
  2468. TQStringList patterns( KMimeType::mimeType( mimeType )->patterns() );
  2469. TQString ext;
  2470. if( !patterns.isEmpty() ) {
  2471. ext = patterns[0];
  2472. int i = ext.findRev( '.' );
  2473. if( i == -1 )
  2474. ext.prepend( '.' );
  2475. else if( i > 0 )
  2476. ext = ext.mid( i );
  2477. }
  2478. name = TQString("unknown") += ext;
  2479. }
  2480. }
  2481. name.truncate( 256 ); // is this needed?
  2482. TQCString encoding = KMMsgBase::autoDetectCharset(partCharset,
  2483. KMMessage::preferredCharsets(), name);
  2484. if ( encoding.isEmpty() )
  2485. encoding = "utf-8";
  2486. TQCString encName;
  2487. if ( GlobalSettings::self()->outlookCompatibleAttachments() )
  2488. encName = KMMsgBase::encodeRFC2047String( name, encoding );
  2489. else
  2490. encName = KMMsgBase::encodeRFC2231String( name, encoding );
  2491. bool RFC2231encoded = false;
  2492. if ( !GlobalSettings::self()->outlookCompatibleAttachments() )
  2493. RFC2231encoded = name != TQString( encName );
  2494. // create message part
  2495. msgPart = new KMMessagePart;
  2496. msgPart->setName(name);
  2497. TQValueList<int> allowedCTEs;
  2498. if ( mimeType == "message/rfc822" ) {
  2499. msgPart->setMessageBody( (*it).data );
  2500. allowedCTEs << DwMime::kCte7bit;
  2501. allowedCTEs << DwMime::kCte8bit;
  2502. } else {
  2503. msgPart->setBodyAndGuessCte((*it).data, allowedCTEs,
  2504. !kmkernel->msgSender()->sendQuotedPrintable());
  2505. kdDebug(5006) << "autodetected cte: " << msgPart->cteStr() << endl;
  2506. }
  2507. int slash = mimeType.find( '/' );
  2508. if( slash == -1 )
  2509. slash = mimeType.length();
  2510. msgPart->setTypeStr( mimeType.left( slash ).latin1() );
  2511. msgPart->setSubtypeStr( mimeType.mid( slash + 1 ).latin1() );
  2512. msgPart->setContentDisposition(TQCString("attachment;\n\tfilename")
  2513. + ( RFC2231encoded ? "*=" + encName : "=\"" + encName + '"' ) );
  2514. mMapAtmLoadData.remove(it);
  2515. if ( msgPart->typeStr().lower() == "text" ) {
  2516. msgPart->setCharset(partCharset);
  2517. }
  2518. // show message part dialog, if not configured away (default):
  2519. TDEConfigGroup composer(KMKernel::config(), "Composer");
  2520. if ( GlobalSettings::self()->showMessagePartDialogOnAttach() ) {
  2521. const KCursorSaver saver( TQCursor::ArrowCursor );
  2522. KMMsgPartDialogCompat dlg(mMainWidget);
  2523. int encodings = 0;
  2524. for ( TQValueListConstIterator<int> it = allowedCTEs.begin() ;
  2525. it != allowedCTEs.end() ; ++it )
  2526. switch ( *it ) {
  2527. case DwMime::kCteBase64: encodings |= KMMsgPartDialog::Base64; break;
  2528. case DwMime::kCteQp: encodings |= KMMsgPartDialog::QuotedPrintable; break;
  2529. case DwMime::kCte7bit: encodings |= KMMsgPartDialog::SevenBit; break;
  2530. case DwMime::kCte8bit: encodings |= KMMsgPartDialog::EightBit; break;
  2531. default: ;
  2532. }
  2533. dlg.setShownEncodings( encodings );
  2534. dlg.setMsgPart(msgPart);
  2535. if (!dlg.exec()) {
  2536. delete msgPart;
  2537. msgPart = 0;
  2538. if (attachURLfound)
  2539. emit attachmentAdded(attachURL, false);
  2540. return;
  2541. }
  2542. }
  2543. mAtmModified = true;
  2544. // add the new attachment to the list
  2545. addAttach(msgPart);
  2546. if (attachURLfound)
  2547. emit attachmentAdded(attachURL, true);
  2548. }
  2549. //-----------------------------------------------------------------------------
  2550. void KMComposeWin::slotInsertFile()
  2551. {
  2552. KFileDialog fdlg(TQString(), TQString(), this, 0, true);
  2553. fdlg.setOperationMode( KFileDialog::Opening );
  2554. fdlg.okButton()->setText(i18n("&Insert"));
  2555. fdlg.setCaption(i18n("Insert File"));
  2556. fdlg.toolBar()->insertCombo(KMMsgBase::supportedEncodings(false), 4711,
  2557. false, 0, 0, 0);
  2558. KComboBox *combo = fdlg.toolBar()->getCombo(4711);
  2559. for (int i = 0; i < combo->count(); i++)
  2560. if (TDEGlobal::charsets()->codecForName(TDEGlobal::charsets()->
  2561. encodingForName(combo->text(i)))
  2562. == TQTextCodec::codecForLocale()) combo->setCurrentItem(i);
  2563. if (!fdlg.exec()) return;
  2564. KURL u = fdlg.selectedURL();
  2565. mRecentAction->addURL(u);
  2566. // Prevent race condition updating list when multiple composers are open
  2567. {
  2568. TDEConfig *config = KMKernel::config();
  2569. TDEConfigGroupSaver saver( config, "Composer" );
  2570. TQString encoding = TDEGlobal::charsets()->encodingForName(combo->currentText()).latin1();
  2571. TQStringList urls = config->readListEntry( "recent-urls" );
  2572. TQStringList encodings = config->readListEntry( "recent-encodings" );
  2573. // Prevent config file from growing without bound
  2574. // Would be nicer to get this constant from TDERecentFilesAction
  2575. uint mMaxRecentFiles = 30;
  2576. while (urls.count() > mMaxRecentFiles)
  2577. urls.erase( urls.fromLast() );
  2578. while (encodings.count() > mMaxRecentFiles)
  2579. encodings.erase( encodings.fromLast() );
  2580. // sanity check
  2581. if (urls.count() != encodings.count()) {
  2582. urls.clear();
  2583. encodings.clear();
  2584. }
  2585. urls.prepend( u.prettyURL() );
  2586. encodings.prepend( encoding );
  2587. config->writeEntry( "recent-urls", urls );
  2588. config->writeEntry( "recent-encodings", encodings );
  2589. mRecentAction->saveEntries( config );
  2590. }
  2591. slotInsertRecentFile(u);
  2592. }
  2593. //-----------------------------------------------------------------------------
  2594. void KMComposeWin::slotInsertRecentFile(const KURL& u)
  2595. {
  2596. if (u.fileName().isEmpty()) return;
  2597. TDEIO::Job *job = TDEIO::get(u);
  2598. atmLoadData ld;
  2599. ld.url = u;
  2600. ld.data = TQByteArray();
  2601. ld.insert = true;
  2602. // Get the encoding previously used when inserting this file
  2603. {
  2604. TDEConfig *config = KMKernel::config();
  2605. TDEConfigGroupSaver saver( config, "Composer" );
  2606. TQStringList urls = config->readListEntry( "recent-urls" );
  2607. TQStringList encodings = config->readListEntry( "recent-encodings" );
  2608. int index = urls.findIndex( u.prettyURL() );
  2609. if (index != -1) {
  2610. TQString encoding = encodings[ index ];
  2611. ld.encoding = encoding.latin1();
  2612. }
  2613. }
  2614. mMapAtmLoadData.insert(job, ld);
  2615. connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
  2616. TQT_TQOBJECT(this), TQT_SLOT(slotAttachFileResult(TDEIO::Job *)));
  2617. connect(job, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
  2618. TQT_TQOBJECT(this), TQT_SLOT(slotAttachFileData(TDEIO::Job *, const TQByteArray &)));
  2619. }
  2620. //-----------------------------------------------------------------------------
  2621. void KMComposeWin::slotSetCharset()
  2622. {
  2623. if (mEncodingAction->currentItem() == 0)
  2624. {
  2625. mAutoCharset = true;
  2626. return;
  2627. }
  2628. mAutoCharset = false;
  2629. mCharset = TDEGlobal::charsets()->encodingForName( mEncodingAction->
  2630. currentText() ).latin1();
  2631. }
  2632. //-----------------------------------------------------------------------------
  2633. void KMComposeWin::slotSelectCryptoModule( bool init )
  2634. {
  2635. if ( !init ) {
  2636. setModified( true );
  2637. }
  2638. if( canSignEncryptAttachments() ) {
  2639. // if the encrypt/sign columns are hidden then show them
  2640. if( 0 == mAtmListView->columnWidth( mAtmColEncrypt ) ) {
  2641. // set/unset signing/encryption for all attachments according to the
  2642. // state of the global sign/encrypt action
  2643. if( !mAtmList.isEmpty() ) {
  2644. for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
  2645. lvi;
  2646. lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
  2647. lvi->setSign( mSignAction->isChecked() );
  2648. lvi->setEncrypt( mEncryptAction->isChecked() );
  2649. }
  2650. }
  2651. int totalWidth = 0;
  2652. // determine the total width of the columns
  2653. for( int col=0; col < mAtmColEncrypt; col++ )
  2654. totalWidth += mAtmListView->columnWidth( col );
  2655. int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
  2656. - mAtmSignColWidth;
  2657. // reduce the width of all columns so that the encrypt and sign column
  2658. // fit
  2659. int usedWidth = 0;
  2660. for( int col=0; col < mAtmColEncrypt-1; col++ ) {
  2661. int newWidth = mAtmListView->columnWidth( col ) * reducedTotalWidth
  2662. / totalWidth;
  2663. mAtmListView->setColumnWidth( col, newWidth );
  2664. usedWidth += newWidth;
  2665. }
  2666. // the last column before the encrypt column gets the remaining space
  2667. // (because of rounding errors the width of this column isn't calculated
  2668. // the same way as the width of the other columns)
  2669. mAtmListView->setColumnWidth( mAtmColEncrypt-1,
  2670. reducedTotalWidth - usedWidth );
  2671. mAtmListView->setColumnWidth( mAtmColEncrypt, mAtmEncryptColWidth );
  2672. mAtmListView->setColumnWidth( mAtmColSign, mAtmSignColWidth );
  2673. for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
  2674. lvi;
  2675. lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
  2676. lvi->enableCryptoCBs( true );
  2677. }
  2678. }
  2679. } else {
  2680. // if the encrypt/sign columns are visible then hide them
  2681. if( 0 != mAtmListView->columnWidth( mAtmColEncrypt ) ) {
  2682. mAtmEncryptColWidth = mAtmListView->columnWidth( mAtmColEncrypt );
  2683. mAtmSignColWidth = mAtmListView->columnWidth( mAtmColSign );
  2684. int totalWidth = 0;
  2685. // determine the total width of the columns
  2686. for( int col=0; col < mAtmListView->columns(); col++ )
  2687. totalWidth += mAtmListView->columnWidth( col );
  2688. int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
  2689. - mAtmSignColWidth;
  2690. // increase the width of all columns so that the visible columns take
  2691. // up the whole space
  2692. int usedWidth = 0;
  2693. for( int col=0; col < mAtmColEncrypt-1; col++ ) {
  2694. int newWidth = mAtmListView->columnWidth( col ) * totalWidth
  2695. / reducedTotalWidth;
  2696. mAtmListView->setColumnWidth( col, newWidth );
  2697. usedWidth += newWidth;
  2698. }
  2699. // the last column before the encrypt column gets the remaining space
  2700. // (because of rounding errors the width of this column isn't calculated
  2701. // the same way as the width of the other columns)
  2702. mAtmListView->setColumnWidth( mAtmColEncrypt-1, totalWidth - usedWidth );
  2703. mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
  2704. mAtmListView->setColumnWidth( mAtmColSign, 0 );
  2705. for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
  2706. lvi;
  2707. lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
  2708. lvi->enableCryptoCBs( false );
  2709. }
  2710. }
  2711. }
  2712. }
  2713. static void showExportError( TQWidget * w, const GpgME::Error & err ) {
  2714. assert( err );
  2715. const TQString msg = i18n("<qt><p>An error occurred while trying to export "
  2716. "the key from the backend:</p>"
  2717. "<p><b>%1</b></p></qt>")
  2718. .arg( TQString::fromLocal8Bit( err.asString() ) );
  2719. KMessageBox::error( w, msg, i18n("Key Export Failed") );
  2720. }
  2721. //-----------------------------------------------------------------------------
  2722. void KMComposeWin::slotInsertMyPublicKey()
  2723. {
  2724. // get PGP user id for the chosen identity
  2725. mFingerprint =
  2726. kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() ).pgpEncryptionKey();
  2727. if ( !mFingerprint.isEmpty() )
  2728. startPublicKeyExport();
  2729. }
  2730. void KMComposeWin::startPublicKeyExport() {
  2731. if ( mFingerprint.isEmpty() || !Kleo::CryptoBackendFactory::instance()->openpgp() )
  2732. return;
  2733. Kleo::ExportJob * job = Kleo::CryptoBackendFactory::instance()->openpgp()->publicKeyExportJob( true );
  2734. assert( job );
  2735. connect( job, TQT_SIGNAL(result(const GpgME::Error&,const TQByteArray&)),
  2736. this, TQT_SLOT(slotPublicKeyExportResult(const GpgME::Error&,const TQByteArray&)) );
  2737. const GpgME::Error err = job->start( mFingerprint );
  2738. if ( err )
  2739. showExportError( this, err );
  2740. else
  2741. (void)new Kleo::ProgressDialog( job, i18n("Exporting key..."), this );
  2742. }
  2743. void KMComposeWin::slotPublicKeyExportResult( const GpgME::Error & err, const TQByteArray & keydata ) {
  2744. if ( err ) {
  2745. showExportError( this, err );
  2746. return;
  2747. }
  2748. // create message part
  2749. KMMessagePart * msgPart = new KMMessagePart();
  2750. msgPart->setName( i18n("OpenPGP key 0x%1").arg( mFingerprint ) );
  2751. msgPart->setTypeStr("application");
  2752. msgPart->setSubtypeStr("pgp-keys");
  2753. TQValueList<int> dummy;
  2754. msgPart->setBodyAndGuessCte(keydata, dummy, false);
  2755. msgPart->setContentDisposition( "attachment;\n\tfilename=0x" + TQCString( mFingerprint.latin1() ) + ".asc" );
  2756. // add the new attachment to the list
  2757. addAttach(msgPart);
  2758. rethinkFields(); //work around initial-size bug in TQt-1.32
  2759. }
  2760. //-----------------------------------------------------------------------------
  2761. void KMComposeWin::slotInsertPublicKey()
  2762. {
  2763. Kleo::KeySelectionDialog dlg( i18n("Attach Public OpenPGP Key"),
  2764. i18n("Select the public key which should "
  2765. "be attached."),
  2766. std::vector<GpgME::Key>(),
  2767. Kleo::KeySelectionDialog::PublicKeys|Kleo::KeySelectionDialog::OpenPGPKeys,
  2768. false /* no multi selection */,
  2769. false /* no remember choice box */,
  2770. this, "attach public key selection dialog" );
  2771. if ( dlg.exec() != TQDialog::Accepted )
  2772. return;
  2773. mFingerprint = dlg.fingerprint();
  2774. startPublicKeyExport();
  2775. }
  2776. //-----------------------------------------------------------------------------
  2777. void KMComposeWin::slotAttachPopupMenu(TQListViewItem *, const TQPoint &, int)
  2778. {
  2779. if (!mAttachMenu)
  2780. {
  2781. mAttachMenu = new TQPopupMenu(this);
  2782. mOpenId = mAttachMenu->insertItem(i18n("to open", "Open"), this,
  2783. TQT_SLOT(slotAttachOpen()));
  2784. mOpenWithId = mAttachMenu->insertItem(i18n("Open With..."), this,
  2785. TQT_SLOT(slotAttachOpenWith()));
  2786. mViewId = mAttachMenu->insertItem(i18n("to view", "View"), this,
  2787. TQT_SLOT(slotAttachView()));
  2788. mEditId = mAttachMenu->insertItem( i18n("Edit"), this, TQT_SLOT(slotAttachEdit()) );
  2789. mEditWithId = mAttachMenu->insertItem( i18n("Edit With..."), this,
  2790. TQT_SLOT(slotAttachEditWith()) );
  2791. mRemoveId = mAttachMenu->insertItem(i18n("Remove"), this, TQT_SLOT(slotAttachRemove()));
  2792. mSaveAsId = mAttachMenu->insertItem( SmallIconSet("filesaveas"), i18n("Save As..."), this,
  2793. TQT_SLOT( slotAttachSave() ) );
  2794. mPropertiesId = mAttachMenu->insertItem( i18n("Properties"), this,
  2795. TQT_SLOT( slotAttachProperties() ) );
  2796. mAttachMenu->insertSeparator();
  2797. mAttachMenu->insertItem(i18n("Add Attachment..."), this, TQT_SLOT(slotAttachFile()));
  2798. }
  2799. int selectedCount = 0;
  2800. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it ) {
  2801. if ( (*it)->isSelected() ) {
  2802. ++selectedCount;
  2803. }
  2804. }
  2805. mAttachMenu->setItemEnabled( mOpenId, selectedCount > 0 );
  2806. mAttachMenu->setItemEnabled( mOpenWithId, selectedCount > 0 );
  2807. mAttachMenu->setItemEnabled( mViewId, selectedCount > 0 );
  2808. mAttachMenu->setItemEnabled( mEditId, selectedCount == 1 );
  2809. mAttachMenu->setItemEnabled( mEditWithId, selectedCount == 1 );
  2810. mAttachMenu->setItemEnabled( mRemoveId, selectedCount > 0 );
  2811. mAttachMenu->setItemEnabled( mSaveAsId, selectedCount == 1 );
  2812. mAttachMenu->setItemEnabled( mPropertiesId, selectedCount == 1 );
  2813. mAttachMenu->popup(TQCursor::pos());
  2814. }
  2815. //-----------------------------------------------------------------------------
  2816. int KMComposeWin::currentAttachmentNum()
  2817. {
  2818. int i = 0;
  2819. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i )
  2820. if ( *it == mAtmListView->currentItem() )
  2821. return i;
  2822. return -1;
  2823. }
  2824. //-----------------------------------------------------------------------------
  2825. void KMComposeWin::slotAttachProperties()
  2826. {
  2827. int idx = currentAttachmentNum();
  2828. if (idx < 0) return;
  2829. KMMessagePart* msgPart = mAtmList.at(idx);
  2830. KMMsgPartDialogCompat dlg(mMainWidget);
  2831. dlg.setMsgPart(msgPart);
  2832. KMAtmListViewItem* listItem = (KMAtmListViewItem*)(mAtmItemList.at(idx));
  2833. if( canSignEncryptAttachments() && listItem ) {
  2834. dlg.setCanSign( true );
  2835. dlg.setCanEncrypt( true );
  2836. dlg.setSigned( listItem->isSign() );
  2837. dlg.setEncrypted( listItem->isEncrypt() );
  2838. } else {
  2839. dlg.setCanSign( false );
  2840. dlg.setCanEncrypt( false );
  2841. }
  2842. if (dlg.exec())
  2843. {
  2844. mAtmModified = true;
  2845. // values may have changed, so recreate the listbox line
  2846. if( listItem ) {
  2847. msgPartToItem(msgPart, listItem);
  2848. if( canSignEncryptAttachments() ) {
  2849. listItem->setSign( dlg.isSigned() );
  2850. listItem->setEncrypt( dlg.isEncrypted() );
  2851. }
  2852. }
  2853. }
  2854. if (msgPart->typeStr().lower() != "text") msgPart->setCharset(TQCString());
  2855. }
  2856. //-----------------------------------------------------------------------------
  2857. void KMComposeWin::compressAttach( int idx )
  2858. {
  2859. if (idx < 0) return;
  2860. unsigned int i;
  2861. for ( i = 0; i < mAtmItemList.count(); ++i )
  2862. if ( mAtmItemList.at( i )->itemPos() == idx )
  2863. break;
  2864. if ( i > mAtmItemList.count() )
  2865. return;
  2866. KMMessagePart* msgPart;
  2867. msgPart = mAtmList.at( i );
  2868. TQByteArray array;
  2869. TQBuffer dev( array );
  2870. KZip zip( &TQT_TQIODEVICE_OBJECT(dev) );
  2871. TQByteArray decoded = msgPart->bodyDecodedBinary();
  2872. if ( ! zip.open( IO_WriteOnly ) ) {
  2873. KMessageBox::sorry(0, i18n("KMail could not compress the file.") );
  2874. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
  2875. return;
  2876. }
  2877. zip.setCompression( KZip::DeflateCompression );
  2878. if ( ! zip.writeFile( msgPart->name(), "", "", decoded.size(),
  2879. decoded.data() ) ) {
  2880. KMessageBox::sorry(0, i18n("KMail could not compress the file.") );
  2881. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
  2882. return;
  2883. }
  2884. zip.close();
  2885. if ( array.size() >= decoded.size() ) {
  2886. if ( KMessageBox::questionYesNo( this, i18n("The compressed file is larger "
  2887. "than the original. Do you want to keep the original one?" ), TQString(), i18n("Keep"), i18n("Compress") )
  2888. == KMessageBox::Yes ) {
  2889. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
  2890. return;
  2891. }
  2892. }
  2893. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setUncompressedCodec(
  2894. msgPart->cteStr() );
  2895. msgPart->setCteStr( "base64" );
  2896. msgPart->setBodyEncodedBinary( array );
  2897. TQString name = msgPart->name() + ".zip";
  2898. msgPart->setName( name );
  2899. TQCString cDisp = "attachment;";
  2900. TQCString encoding = KMMsgBase::autoDetectCharset( msgPart->charset(),
  2901. KMMessage::preferredCharsets(), name );
  2902. kdDebug(5006) << "encoding: " << encoding << endl;
  2903. if ( encoding.isEmpty() ) encoding = "utf-8";
  2904. kdDebug(5006) << "encoding after: " << encoding << endl;
  2905. TQCString encName;
  2906. if ( GlobalSettings::self()->outlookCompatibleAttachments() )
  2907. encName = KMMsgBase::encodeRFC2047String( name, encoding );
  2908. else
  2909. encName = KMMsgBase::encodeRFC2231String( name, encoding );
  2910. cDisp += "\n\tfilename";
  2911. if ( name != TQString( encName ) )
  2912. cDisp += "*=" + encName;
  2913. else
  2914. cDisp += "=\"" + encName + '"';
  2915. msgPart->setContentDisposition( cDisp );
  2916. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setUncompressedMimeType(
  2917. msgPart->typeStr(), msgPart->subtypeStr() );
  2918. msgPart->setTypeStr( "application" );
  2919. msgPart->setSubtypeStr( "x-zip" );
  2920. KMAtmListViewItem* listItem = static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) );
  2921. msgPartToItem( msgPart, listItem, false );
  2922. }
  2923. //-----------------------------------------------------------------------------
  2924. void KMComposeWin::uncompressAttach( int idx )
  2925. {
  2926. if (idx < 0) return;
  2927. unsigned int i;
  2928. for ( i = 0; i < mAtmItemList.count(); ++i )
  2929. if ( mAtmItemList.at( i )->itemPos() == idx )
  2930. break;
  2931. if ( i > mAtmItemList.count() )
  2932. return;
  2933. KMMessagePart* msgPart;
  2934. msgPart = mAtmList.at( i );
  2935. TQBuffer dev( msgPart->bodyDecodedBinary() );
  2936. KZip zip( &TQT_TQIODEVICE_OBJECT(dev) );
  2937. TQByteArray decoded;
  2938. decoded = msgPart->bodyDecodedBinary();
  2939. if ( ! zip.open( IO_ReadOnly ) ) {
  2940. KMessageBox::sorry(0, i18n("KMail could not uncompress the file.") );
  2941. static_cast<KMAtmListViewItem *>( mAtmItemList.at( i ) )->setCompress( true );
  2942. return;
  2943. }
  2944. const KArchiveDirectory *dir = zip.directory();
  2945. KZipFileEntry *entry;
  2946. if ( dir->entries().count() != 1 ) {
  2947. KMessageBox::sorry(0, i18n("KMail could not uncompress the file.") );
  2948. static_cast<KMAtmListViewItem *>( mAtmItemList.at( i ) )->setCompress( true );
  2949. return;
  2950. }
  2951. entry = (KZipFileEntry*)dir->entry( dir->entries()[0] );
  2952. msgPart->setCteStr(
  2953. static_cast<KMAtmListViewItem*>( mAtmItemList.at(i) )->uncompressedCodec() );
  2954. msgPart->setBodyEncodedBinary( entry->data() );
  2955. TQString name = entry->name();
  2956. msgPart->setName( name );
  2957. zip.close();
  2958. TQCString cDisp = "attachment;";
  2959. TQCString encoding = KMMsgBase::autoDetectCharset( msgPart->charset(),
  2960. KMMessage::preferredCharsets(), name );
  2961. if ( encoding.isEmpty() ) encoding = "utf-8";
  2962. TQCString encName;
  2963. if ( GlobalSettings::self()->outlookCompatibleAttachments() )
  2964. encName = KMMsgBase::encodeRFC2047String( name, encoding );
  2965. else
  2966. encName = KMMsgBase::encodeRFC2231String( name, encoding );
  2967. cDisp += "\n\tfilename";
  2968. if ( name != TQString( encName ) )
  2969. cDisp += "*=" + encName;
  2970. else
  2971. cDisp += "=\"" + encName + '"';
  2972. msgPart->setContentDisposition( cDisp );
  2973. TQCString type, subtype;
  2974. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->uncompressedMimeType( type,
  2975. subtype );
  2976. msgPart->setTypeStr( type );
  2977. msgPart->setSubtypeStr( subtype );
  2978. KMAtmListViewItem* listItem = static_cast<KMAtmListViewItem*>(mAtmItemList.at( i ));
  2979. msgPartToItem( msgPart, listItem, false );
  2980. }
  2981. //-----------------------------------------------------------------------------
  2982. void KMComposeWin::slotAttachView()
  2983. {
  2984. int i = 0;
  2985. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
  2986. if ( (*it)->isSelected() ) {
  2987. viewAttach( i );
  2988. }
  2989. }
  2990. }
  2991. //-----------------------------------------------------------------------------
  2992. void KMComposeWin::slotAttachOpen()
  2993. {
  2994. int i = 0;
  2995. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
  2996. if ( (*it)->isSelected() ) {
  2997. openAttach( i, false );
  2998. }
  2999. }
  3000. }
  3001. //-----------------------------------------------------------------------------
  3002. void KMComposeWin::slotAttachOpenWith()
  3003. {
  3004. int i = 0;
  3005. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
  3006. if ( (*it)->isSelected() ) {
  3007. openAttach( i, true );
  3008. }
  3009. }
  3010. }
  3011. void KMComposeWin::slotAttachEdit()
  3012. {
  3013. int i = 0;
  3014. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
  3015. if ( (*it)->isSelected() ) {
  3016. editAttach( i, false );
  3017. }
  3018. }
  3019. }
  3020. void KMComposeWin::slotAttachEditWith()
  3021. {
  3022. int i = 0;
  3023. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
  3024. if ( (*it)->isSelected() ) {
  3025. editAttach( i, true );
  3026. }
  3027. }
  3028. }
  3029. //-----------------------------------------------------------------------------
  3030. bool KMComposeWin::inlineSigningEncryptionSelected() {
  3031. if ( !mSignAction->isChecked() && !mEncryptAction->isChecked() )
  3032. return false;
  3033. return cryptoMessageFormat() == Kleo::InlineOpenPGPFormat;
  3034. }
  3035. //-----------------------------------------------------------------------------
  3036. void KMComposeWin::viewAttach( int index )
  3037. {
  3038. TQString pname;
  3039. KMMessagePart* msgPart;
  3040. msgPart = mAtmList.at(index);
  3041. pname = msgPart->name().stripWhiteSpace();
  3042. if (pname.isEmpty()) pname=msgPart->contentDescription();
  3043. if (pname.isEmpty()) pname="unnamed";
  3044. KTempFile* atmTempFile = new KTempFile();
  3045. mAtmTempList.append( atmTempFile );
  3046. atmTempFile->setAutoDelete( true );
  3047. KPIM::kByteArrayToFile(msgPart->bodyDecodedBinary(), atmTempFile->name(), false, false,
  3048. false);
  3049. KMReaderMainWin *win = new KMReaderMainWin(msgPart, false,
  3050. atmTempFile->name(), pname, mCharset );
  3051. win->show();
  3052. }
  3053. //-----------------------------------------------------------------------------
  3054. void KMComposeWin::openAttach( int index, bool with )
  3055. {
  3056. KMMessagePart* msgPart = mAtmList.at(index);
  3057. const TQString contentTypeStr =
  3058. ( msgPart->typeStr() + '/' + msgPart->subtypeStr() ).lower();
  3059. KMimeType::Ptr mimetype;
  3060. mimetype = KMimeType::mimeType( contentTypeStr );
  3061. KTempFile* atmTempFile = new KTempFile();
  3062. mAtmTempList.append( atmTempFile );
  3063. const bool autoDelete = true;
  3064. atmTempFile->setAutoDelete( autoDelete );
  3065. KURL url;
  3066. url.setPath( atmTempFile->name() );
  3067. KPIM::kByteArrayToFile( msgPart->bodyDecodedBinary(), atmTempFile->name(), false, false,
  3068. false );
  3069. if ( ::chmod( TQFile::encodeName( atmTempFile->name() ), S_IRUSR ) != 0) {
  3070. TQFile::remove(url.path());
  3071. return;
  3072. }
  3073. KService::Ptr offer =
  3074. KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
  3075. if ( with || !offer || mimetype->name() == "application/octet-stream" ) {
  3076. if ( ( !KRun::displayOpenWithDialog( url, autoDelete ) ) && autoDelete ) {
  3077. TQFile::remove(url.path());
  3078. }
  3079. }
  3080. else {
  3081. if ( ( !KRun::run( *offer, url, autoDelete ) ) && autoDelete ) {
  3082. TQFile::remove( url.path() );
  3083. }
  3084. }
  3085. }
  3086. void KMComposeWin::editAttach(int index, bool openWith)
  3087. {
  3088. KMMessagePart* msgPart = mAtmList.at(index);
  3089. const TQString contentTypeStr =
  3090. ( msgPart->typeStr() + '/' + msgPart->subtypeStr() ).lower();
  3091. KTempFile* atmTempFile = new KTempFile();
  3092. mAtmTempList.append( atmTempFile );
  3093. atmTempFile->setAutoDelete( true );
  3094. atmTempFile->file()->writeBlock( msgPart->bodyDecodedBinary() );
  3095. atmTempFile->file()->flush();
  3096. KMail::EditorWatcher *watcher =
  3097. new KMail::EditorWatcher( KURL( atmTempFile->name() ), contentTypeStr, openWith,
  3098. TQT_TQOBJECT(this), this );
  3099. connect( watcher, TQT_SIGNAL(editDone(KMail::EditorWatcher*)), TQT_SLOT(slotEditDone(KMail::EditorWatcher*)) );
  3100. if ( watcher->start() ) {
  3101. mEditorMap.insert( watcher, msgPart );
  3102. mEditorTempFiles.insert( watcher, atmTempFile );
  3103. }
  3104. }
  3105. //-----------------------------------------------------------------------------
  3106. void KMComposeWin::slotAttachSave()
  3107. {
  3108. KMMessagePart* msgPart;
  3109. TQString fileName, pname;
  3110. int idx = currentAttachmentNum();
  3111. if (idx < 0) return;
  3112. msgPart = mAtmList.at(idx);
  3113. pname = msgPart->name();
  3114. if (pname.isEmpty()) pname="unnamed";
  3115. KURL url = KFileDialog::getSaveURL(pname, TQString(), 0, i18n("Save Attachment As"));
  3116. if( url.isEmpty() )
  3117. return;
  3118. kmkernel->byteArrayToRemoteFile(msgPart->bodyDecodedBinary(), url);
  3119. }
  3120. //-----------------------------------------------------------------------------
  3121. void KMComposeWin::slotAttachRemove()
  3122. {
  3123. mAtmSelectNew = 0;
  3124. bool attachmentRemoved = false;
  3125. int i = 0;
  3126. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ) {
  3127. if ( (*it)->isSelected() ) {
  3128. removeAttach( i );
  3129. attachmentRemoved = true;
  3130. }
  3131. else {
  3132. ++it;
  3133. ++i;
  3134. }
  3135. }
  3136. if ( attachmentRemoved ) {
  3137. setModified( true );
  3138. slotUpdateAttachActions();
  3139. if ( mAtmSelectNew ) {
  3140. mAtmListView->setSelected( mAtmSelectNew, true );
  3141. mAtmListView->setCurrentItem( mAtmSelectNew );
  3142. }
  3143. }
  3144. }
  3145. //-----------------------------------------------------------------------------
  3146. void KMComposeWin::slotFind()
  3147. {
  3148. mEditor->search();
  3149. }
  3150. void KMComposeWin::slotSearchAgain()
  3151. {
  3152. mEditor->repeatSearch();
  3153. }
  3154. //-----------------------------------------------------------------------------
  3155. void KMComposeWin::slotReplace()
  3156. {
  3157. mEditor->replace();
  3158. }
  3159. //-----------------------------------------------------------------------------
  3160. void KMComposeWin::slotUpdateFont()
  3161. {
  3162. kdDebug() << "KMComposeWin::slotUpdateFont " << endl;
  3163. if ( ! mFixedFontAction ) {
  3164. return;
  3165. }
  3166. mEditor->setFont( mFixedFontAction->isChecked() ? mFixedFont : mBodyFont );
  3167. }
  3168. TQString KMComposeWin::quotePrefixName() const
  3169. {
  3170. if ( !msg() )
  3171. return TQString();
  3172. int languageNr = GlobalSettings::self()->replyCurrentLanguage();
  3173. ReplyPhrases replyPhrases( TQString::number(languageNr) );
  3174. replyPhrases.readConfig();
  3175. TQString quotePrefix = msg()->formatString(
  3176. replyPhrases.indentPrefix() );
  3177. quotePrefix = msg()->formatString(quotePrefix);
  3178. return quotePrefix;
  3179. }
  3180. void KMComposeWin::slotPasteClipboardAsQuotation()
  3181. {
  3182. if( mEditor->hasFocus() && msg() )
  3183. {
  3184. TQString s = TQApplication::clipboard()->text();
  3185. if (!s.isEmpty())
  3186. mEditor->insert(addQuotesToText(s));
  3187. }
  3188. }
  3189. void KMComposeWin::slotPasteClipboardAsAttachment()
  3190. {
  3191. KURL url( TQApplication::clipboard()->text( TQClipboard::Clipboard ) );
  3192. if ( url.isValid() ) {
  3193. addAttach(TQApplication::clipboard()->text( TQClipboard::Clipboard ) );
  3194. return;
  3195. }
  3196. TQMimeSource *mimeSource = TQApplication::clipboard()->data();
  3197. if ( TQImageDrag::canDecode(mimeSource) ) {
  3198. slotAttachPNGImageData(mimeSource->encodedData("image/png"));
  3199. }
  3200. else {
  3201. bool ok;
  3202. TQString attName = KInputDialog::getText( "KMail", i18n("Name of the attachment:"), TQString(), &ok, this );
  3203. if ( !ok )
  3204. return;
  3205. KMMessagePart *msgPart = new KMMessagePart;
  3206. msgPart->setName(attName);
  3207. TQValueList<int> dummy;
  3208. msgPart->setBodyAndGuessCte(TQCString(TQApplication::clipboard()->text().latin1()), dummy,
  3209. kmkernel->msgSender()->sendQuotedPrintable());
  3210. addAttach(msgPart);
  3211. }
  3212. }
  3213. void KMComposeWin::slotAddQuotes()
  3214. {
  3215. if( mEditor->hasFocus() && msg() )
  3216. {
  3217. // TODO: I think this is backwards.
  3218. // i.e, if no region is marked then add quotes to every line
  3219. // else add quotes only on the lines that are marked.
  3220. if ( mEditor->hasMarkedText() ) {
  3221. TQString s = mEditor->markedText();
  3222. if(!s.isEmpty())
  3223. mEditor->insert(addQuotesToText(s));
  3224. } else {
  3225. int l = mEditor->currentLine();
  3226. int c = mEditor->currentColumn();
  3227. TQString s = mEditor->textLine(l);
  3228. s.prepend(quotePrefixName());
  3229. mEditor->insertLine(s,l);
  3230. mEditor->removeLine(l+1);
  3231. mEditor->setCursorPosition(l,c+2);
  3232. }
  3233. }
  3234. }
  3235. TQString KMComposeWin::addQuotesToText(const TQString &inputText)
  3236. {
  3237. TQString answer = TQString( inputText );
  3238. TQString indentStr = quotePrefixName();
  3239. answer.replace( '\n', '\n' + indentStr);
  3240. answer.prepend( indentStr );
  3241. answer += '\n';
  3242. return KMMessage::smartQuote( answer, GlobalSettings::self()->lineWrapWidth() );
  3243. }
  3244. TQString KMComposeWin::removeQuotesFromText(const TQString &inputText)
  3245. {
  3246. TQString s = inputText;
  3247. // remove first leading quote
  3248. TQString quotePrefix = '^' + quotePrefixName();
  3249. TQRegExp rx(quotePrefix);
  3250. s.remove(rx);
  3251. // now remove all remaining leading quotes
  3252. quotePrefix = '\n' + quotePrefixName();
  3253. rx = quotePrefix;
  3254. s.replace(rx, "\n");
  3255. return s;
  3256. }
  3257. void KMComposeWin::slotRemoveQuotes()
  3258. {
  3259. if( mEditor->hasFocus() && msg() )
  3260. {
  3261. // TODO: I think this is backwards.
  3262. // i.e, if no region is marked then remove quotes from every line
  3263. // else remove quotes only on the lines that are marked.
  3264. if ( mEditor->hasMarkedText() ) {
  3265. TQString s = mEditor->markedText();
  3266. mEditor->insert(removeQuotesFromText(s));
  3267. } else {
  3268. int l = mEditor->currentLine();
  3269. int c = mEditor->currentColumn();
  3270. TQString s = mEditor->textLine(l);
  3271. mEditor->insertLine(removeQuotesFromText(s),l);
  3272. mEditor->removeLine(l+1);
  3273. mEditor->setCursorPosition(l,c-2);
  3274. }
  3275. }
  3276. }
  3277. //-----------------------------------------------------------------------------
  3278. void KMComposeWin::slotUndo()
  3279. {
  3280. TQWidget* fw = focusWidget();
  3281. if (!fw) return;
  3282. if ( ::tqqt_cast<KEdit*>(fw) )
  3283. static_cast<TQTextEdit*>(fw)->undo();
  3284. else if (::tqqt_cast<TQLineEdit*>(fw))
  3285. static_cast<TQLineEdit*>(fw)->undo();
  3286. }
  3287. void KMComposeWin::slotRedo()
  3288. {
  3289. TQWidget* fw = focusWidget();
  3290. if (!fw) return;
  3291. if (::tqqt_cast<KEdit*>(fw))
  3292. static_cast<KEdit*>(fw)->redo();
  3293. else if (::tqqt_cast<TQLineEdit*>(fw))
  3294. static_cast<TQLineEdit*>(fw)->redo();
  3295. }
  3296. //-----------------------------------------------------------------------------
  3297. void KMComposeWin::slotCut()
  3298. {
  3299. TQWidget* fw = focusWidget();
  3300. if (!fw) return;
  3301. if (::tqqt_cast<KEdit*>(fw))
  3302. static_cast<KEdit*>(fw)->cut();
  3303. else if (::tqqt_cast<TQLineEdit*>(fw))
  3304. static_cast<TQLineEdit*>(fw)->cut();
  3305. }
  3306. //-----------------------------------------------------------------------------
  3307. void KMComposeWin::slotCopy()
  3308. {
  3309. TQWidget* fw = focusWidget();
  3310. if (!fw) return;
  3311. #ifdef KeyPress
  3312. #undef KeyPress
  3313. #endif
  3314. TQKeyEvent k(TQEvent::KeyPress, Key_C, 0, ControlButton);
  3315. kapp->notify(TQT_TQOBJECT(fw), TQT_TQEVENT(&k));
  3316. }
  3317. //-----------------------------------------------------------------------------
  3318. void KMComposeWin::slotPasteClipboard()
  3319. {
  3320. paste( TQClipboard::Clipboard );
  3321. }
  3322. void KMComposeWin::paste( TQClipboard::Mode mode )
  3323. {
  3324. TQWidget* fw = focusWidget();
  3325. if (!fw) return;
  3326. TQMimeSource *mimeSource = TQApplication::clipboard()->data( mode );
  3327. if ( mimeSource->provides("image/png") ) {
  3328. slotAttachPNGImageData(mimeSource->encodedData("image/png"));
  3329. } else if ( KURLDrag::canDecode( mimeSource ) ) {
  3330. KURL::List urlList;
  3331. if( KURLDrag::decode( mimeSource, urlList ) ) {
  3332. const TQString asText = i18n("Add as Text");
  3333. const TQString asAttachment = i18n("Add as Attachment");
  3334. const TQString text = i18n("Please select whether you want to insert the content as text into the editor, "
  3335. "or append the referenced file as an attachment.");
  3336. const TQString caption = i18n("Paste as text or attachment?");
  3337. int id = KMessageBox::questionYesNoCancel( this, text, caption,
  3338. KGuiItem( asText ), KGuiItem( asAttachment) );
  3339. switch ( id) {
  3340. case KMessageBox::Yes:
  3341. for ( KURL::List::Iterator it = urlList.begin();
  3342. it != urlList.end(); ++it ) {
  3343. mEditor->insert( (*it).url() );
  3344. }
  3345. break;
  3346. case KMessageBox::No:
  3347. for ( KURL::List::Iterator it = urlList.begin();
  3348. it != urlList.end(); ++it ) {
  3349. addAttach( *it );
  3350. }
  3351. break;
  3352. }
  3353. }
  3354. } else if ( TQTextDrag::canDecode( mimeSource ) ) {
  3355. TQString s;
  3356. if ( TQTextDrag::decode( mimeSource, s ) )
  3357. mEditor->insert( s );
  3358. }
  3359. }
  3360. //-----------------------------------------------------------------------------
  3361. void KMComposeWin::slotMarkAll()
  3362. {
  3363. TQWidget* fw = focusWidget();
  3364. if (!fw) return;
  3365. if (::tqqt_cast<TQLineEdit*>(fw))
  3366. static_cast<TQLineEdit*>(fw)->selectAll();
  3367. else if (::tqqt_cast<KEdit*>(fw))
  3368. static_cast<KEdit*>(fw)->selectAll();
  3369. }
  3370. //-----------------------------------------------------------------------------
  3371. void KMComposeWin::slotClose()
  3372. {
  3373. close(false);
  3374. }
  3375. //-----------------------------------------------------------------------------
  3376. void KMComposeWin::slotNewComposer()
  3377. {
  3378. KMComposeWin* win;
  3379. KMMessage* msg = new KMMessage;
  3380. msg->initHeader();
  3381. win = new KMComposeWin(msg);
  3382. win->show();
  3383. }
  3384. //-----------------------------------------------------------------------------
  3385. void KMComposeWin::slotNewMailReader()
  3386. {
  3387. KMMainWin *kmmwin = new KMMainWin(0);
  3388. kmmwin->show();
  3389. //d->resize(d->size());
  3390. }
  3391. //-----------------------------------------------------------------------------
  3392. void KMComposeWin::slotUpdWinTitle(const TQString& text)
  3393. {
  3394. TQString s( text );
  3395. // Remove characters that show badly in most window decorations:
  3396. // newlines tend to become boxes.
  3397. if (text.isEmpty())
  3398. setCaption("("+i18n("unnamed")+")");
  3399. else setCaption( s.replace( TQChar('\n'), ' ' ) );
  3400. }
  3401. //-----------------------------------------------------------------------------
  3402. void KMComposeWin::slotEncryptToggled(bool on)
  3403. {
  3404. setEncryption( on, true /* set by the user */ );
  3405. slotUpdateSignatureAndEncrypionStateIndicators();
  3406. }
  3407. //-----------------------------------------------------------------------------
  3408. void KMComposeWin::setEncryption( bool encrypt, bool setByUser )
  3409. {
  3410. bool wasModified = isModified();
  3411. if ( setByUser )
  3412. setModified( true );
  3413. if ( !mEncryptAction->isEnabled() )
  3414. encrypt = false;
  3415. // check if the user wants to encrypt messages to himself and if he defined
  3416. // an encryption key for the current identity
  3417. else if ( encrypt && encryptToSelf() && !mLastIdentityHasEncryptionKey ) {
  3418. if ( setByUser ) {
  3419. KMessageBox::sorry( this,
  3420. i18n("<qt><p>You have requested that messages be "
  3421. "encrypted to yourself, but the currently selected "
  3422. "identity does not define an (OpenPGP or S/MIME) "
  3423. "encryption key to use for this.</p>"
  3424. "<p>Please select the key(s) to use "
  3425. "in the identity configuration.</p>"
  3426. "</qt>"),
  3427. i18n("Undefined Encryption Key") );
  3428. setModified( wasModified );
  3429. }
  3430. encrypt = false;
  3431. }
  3432. // make sure the mEncryptAction is in the right state
  3433. mEncryptAction->setChecked( encrypt );
  3434. // show the appropriate icon
  3435. if ( encrypt )
  3436. mEncryptAction->setIcon("encrypted");
  3437. else
  3438. mEncryptAction->setIcon("decrypted");
  3439. // mark the attachments for (no) encryption
  3440. if ( canSignEncryptAttachments() ) {
  3441. for ( KMAtmListViewItem* entry =
  3442. static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
  3443. entry;
  3444. entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
  3445. entry->setEncrypt( encrypt );
  3446. }
  3447. }
  3448. //-----------------------------------------------------------------------------
  3449. void KMComposeWin::slotSignToggled(bool on)
  3450. {
  3451. setSigning( on, true /* set by the user */ );
  3452. slotUpdateSignatureAndEncrypionStateIndicators();
  3453. }
  3454. //-----------------------------------------------------------------------------
  3455. void KMComposeWin::setSigning( bool sign, bool setByUser )
  3456. {
  3457. bool wasModified = isModified();
  3458. if ( setByUser )
  3459. setModified( true );
  3460. if ( !mSignAction->isEnabled() )
  3461. sign = false;
  3462. // check if the user defined a signing key for the current identity
  3463. if ( sign && !mLastIdentityHasSigningKey ) {
  3464. if ( setByUser ) {
  3465. KMessageBox::sorry( this,
  3466. i18n("<qt><p>In order to be able to sign "
  3467. "this message you first have to "
  3468. "define the (OpenPGP or S/MIME) signing key "
  3469. "to use.</p>"
  3470. "<p>Please select the key to use "
  3471. "in the identity configuration.</p>"
  3472. "</qt>"),
  3473. i18n("Undefined Signing Key") );
  3474. setModified( wasModified );
  3475. }
  3476. sign = false;
  3477. }
  3478. // make sure the mSignAction is in the right state
  3479. mSignAction->setChecked( sign );
  3480. // mark the attachments for (no) signing
  3481. if ( canSignEncryptAttachments() ) {
  3482. for ( KMAtmListViewItem* entry =
  3483. static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
  3484. entry;
  3485. entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
  3486. entry->setSign( sign );
  3487. }
  3488. }
  3489. //-----------------------------------------------------------------------------
  3490. void KMComposeWin::slotWordWrapToggled(bool on)
  3491. {
  3492. if (on)
  3493. {
  3494. mEditor->setWordWrap( TQTextEdit::FixedColumnWidth );
  3495. mEditor->setWrapColumnOrWidth( GlobalSettings::self()->lineWrapWidth() );
  3496. }
  3497. else
  3498. {
  3499. mEditor->setWordWrap( TQTextEdit::WidgetWidth );
  3500. }
  3501. }
  3502. void KMComposeWin::disableWordWrap()
  3503. {
  3504. mEditor->setWordWrap( TQTextEdit::NoWrap );
  3505. }
  3506. void KMComposeWin::disableRecipientNumberCheck()
  3507. {
  3508. mCheckForRecipients = false;
  3509. }
  3510. void KMComposeWin::disableForgottenAttachmentsCheck()
  3511. {
  3512. mCheckForForgottenAttachments = false;
  3513. }
  3514. void KMComposeWin::ignoreStickyFields()
  3515. {
  3516. mIgnoreStickyFields = true;
  3517. mBtnTransport->setChecked( false );
  3518. mBtnDictionary->setChecked( false );
  3519. mBtnIdentity->setChecked( false );
  3520. mBtnTransport->setEnabled( false );
  3521. mBtnDictionary->setEnabled( false );
  3522. mBtnIdentity->setEnabled( false );
  3523. }
  3524. //-----------------------------------------------------------------------------
  3525. void KMComposeWin::slotPrint()
  3526. {
  3527. mMessageWasModified = isModified();
  3528. connect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  3529. TQT_TQOBJECT(this), TQT_SLOT( slotContinuePrint( bool ) ) );
  3530. applyChanges( true );
  3531. }
  3532. void KMComposeWin::slotContinuePrint( bool rc )
  3533. {
  3534. disconnect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  3535. TQT_TQOBJECT(this), TQT_SLOT( slotContinuePrint( bool ) ) );
  3536. if( rc ) {
  3537. if ( mComposedMessages.isEmpty() ) {
  3538. kdDebug(5006) << "Composing the message failed." << endl;
  3539. return;
  3540. }
  3541. KMCommand *command = new KMPrintCommand( this, mComposedMessages.first() );
  3542. command->start();
  3543. setModified( mMessageWasModified );
  3544. }
  3545. }
  3546. //----------------------------------------------------------------------------
  3547. bool KMComposeWin::validateAddresses( TQWidget * parent, const TQString & addresses )
  3548. {
  3549. TQString brokenAddress;
  3550. KPIM::EmailParseResult errorCode = KMMessage::isValidEmailAddressList( KMMessage::expandAliases( addresses ), brokenAddress );
  3551. if ( !( errorCode == KPIM::AddressOk || errorCode == KPIM::AddressEmpty ) ) {
  3552. TQString errorMsg( "<qt><p><b>" + brokenAddress +
  3553. "</b></p><p>" + KPIM::emailParseResultToString( errorCode ) +
  3554. "</p></qt>" );
  3555. KMessageBox::sorry( parent, errorMsg, i18n("Invalid Email Address") );
  3556. return false;
  3557. }
  3558. return true;
  3559. }
  3560. //----------------------------------------------------------------------------
  3561. void KMComposeWin::doSend( KMail::MessageSender::SendMethod method,
  3562. KMComposeWin::SaveIn saveIn )
  3563. {
  3564. if ( method != KMail::MessageSender::SendLater && kmkernel->isOffline() ) {
  3565. KMessageBox::information( this,
  3566. i18n("KMail is currently in offline mode,"
  3567. "your messages will be kept in the outbox until you go online."),
  3568. i18n("Online/Offline"), "kmailIsOffline" );
  3569. mSendMethod = KMail::MessageSender::SendLater;
  3570. } else {
  3571. mSendMethod = method;
  3572. }
  3573. mSaveIn = saveIn;
  3574. if ( saveIn == KMComposeWin::None ) {
  3575. if ( KPIM::getFirstEmailAddress( from() ).isEmpty() ) {
  3576. if ( !( mShowHeaders & HDR_FROM ) ) {
  3577. mShowHeaders |= HDR_FROM;
  3578. rethinkFields( false );
  3579. }
  3580. mEdtFrom->setFocus();
  3581. KMessageBox::sorry( this,
  3582. i18n("You must enter your email address in the "
  3583. "From: field. You should also set your email "
  3584. "address for all identities, so that you do "
  3585. "not have to enter it for each message.") );
  3586. return;
  3587. }
  3588. if ( to().isEmpty() )
  3589. {
  3590. if ( cc().isEmpty() && bcc().isEmpty()) {
  3591. if ( mEdtTo ) mEdtTo->setFocus();
  3592. KMessageBox::information( this,
  3593. i18n("You must specify at least one receiver,"
  3594. "either in the To: field or as CC or as BCC.") );
  3595. return;
  3596. }
  3597. else {
  3598. if ( mEdtTo ) mEdtTo->setFocus();
  3599. int rc =
  3600. KMessageBox::questionYesNo( this,
  3601. i18n("To field is missing."
  3602. "Send message anyway?"),
  3603. i18n("No To: specified") );
  3604. if ( rc == KMessageBox::No ){
  3605. return;
  3606. }
  3607. }
  3608. }
  3609. // Validate the To:, CC: and BCC fields
  3610. if ( !validateAddresses( this, to().stripWhiteSpace() ) ) {
  3611. return;
  3612. }
  3613. if ( !validateAddresses( this, cc().stripWhiteSpace() ) ) {
  3614. return;
  3615. }
  3616. if ( !validateAddresses( this, bcc().stripWhiteSpace() ) ) {
  3617. return;
  3618. }
  3619. if (subject().isEmpty())
  3620. {
  3621. mEdtSubject->setFocus();
  3622. int rc =
  3623. KMessageBox::questionYesNo( this,
  3624. i18n("You did not specify a subject. "
  3625. "Send message anyway?"),
  3626. i18n("No Subject Specified"),
  3627. i18n("S&end as Is"),
  3628. i18n("&Specify the Subject"),
  3629. "no_subject_specified" );
  3630. if( rc == KMessageBox::No )
  3631. {
  3632. return;
  3633. }
  3634. }
  3635. if ( userForgotAttachment() )
  3636. return;
  3637. }
  3638. KCursorSaver busy(KBusyPtr::busy());
  3639. mMsg->setDateToday();
  3640. // If a user sets up their outgoing messages preferences wrong and then
  3641. // sends mail that gets 'stuck' in their outbox, they should be able to
  3642. // rectify the problem by editing their outgoing preferences and
  3643. // resending.
  3644. // Hence this following conditional
  3645. TQString hf = mMsg->headerField("X-KMail-Transport");
  3646. if ((mTransport->currentText() != mTransport->text(0)) ||
  3647. (!hf.isEmpty() && (hf != mTransport->text(0))))
  3648. mMsg->setHeaderField("X-KMail-Transport", mTransport->currentText());
  3649. mDisableBreaking = ( saveIn != KMComposeWin::None );
  3650. const bool neverEncrypt = ( mDisableBreaking && GlobalSettings::self()->neverEncryptDrafts() )
  3651. || mSigningAndEncryptionExplicitlyDisabled;
  3652. connect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  3653. TQT_SLOT( slotContinueDoSend( bool ) ) );
  3654. if ( mEditor->textFormat() == TQt::RichText )
  3655. mMsg->setHeaderField( "X-KMail-Markup", "true" );
  3656. else
  3657. mMsg->removeHeaderField( "X-KMail-Markup" );
  3658. if ( mEditor->textFormat() == TQt::RichText && inlineSigningEncryptionSelected() ) {
  3659. TQString keepBtnText = mEncryptAction->isChecked() ?
  3660. mSignAction->isChecked() ? i18n( "&Keep markup, do not sign/encrypt" )
  3661. : i18n( "&Keep markup, do not encrypt" )
  3662. : i18n( "&Keep markup, do not sign" );
  3663. TQString yesBtnText = mEncryptAction->isChecked() ?
  3664. mSignAction->isChecked() ? i18n("Sign/Encrypt (delete markup)")
  3665. : i18n( "Encrypt (delete markup)" )
  3666. : i18n( "Sign (delete markup)" );
  3667. int ret = KMessageBox::warningYesNoCancel(this,
  3668. i18n("<qt><p>Inline signing/encrypting of HTML messages is not possible;</p>"
  3669. "<p>do you want to delete your markup?</p></qt>"),
  3670. i18n("Sign/Encrypt Message?"),
  3671. KGuiItem( yesBtnText ),
  3672. KGuiItem( keepBtnText ) );
  3673. if ( KMessageBox::Cancel == ret )
  3674. return;
  3675. if ( KMessageBox::No == ret ) {
  3676. mEncryptAction->setChecked(false);
  3677. mSignAction->setChecked(false);
  3678. }
  3679. else {
  3680. toggleMarkup(false);
  3681. }
  3682. }
  3683. if (neverEncrypt && saveIn != KMComposeWin::None ) {
  3684. // we can't use the state of the mail itself, to remember the
  3685. // signing and encryption state, so let's add a header instead
  3686. mMsg->setHeaderField( "X-KMail-SignatureActionEnabled", mSignAction->isChecked()? "true":"false" );
  3687. mMsg->setHeaderField( "X-KMail-EncryptActionEnabled", mEncryptAction->isChecked()? "true":"false" );
  3688. mMsg->setHeaderField( "X-KMail-CryptoMessageFormat", TQString::number( cryptoMessageFormat() ) );
  3689. } else {
  3690. mMsg->removeHeaderField( "X-KMail-SignatureActionEnabled" );
  3691. mMsg->removeHeaderField( "X-KMail-EncryptActionEnabled" );
  3692. mMsg->removeHeaderField( "X-KMail-CryptoMessageFormat" );
  3693. }
  3694. kdDebug(5006) << "KMComposeWin::doSend() - calling applyChanges()"
  3695. << endl;
  3696. applyChanges( neverEncrypt );
  3697. }
  3698. bool KMComposeWin::saveDraftOrTemplate( const TQString &folderName,
  3699. KMMessage *msg )
  3700. {
  3701. KMFolder *theFolder = 0, *imapTheFolder = 0;
  3702. // get the draftsFolder
  3703. if ( !folderName.isEmpty() ) {
  3704. theFolder = kmkernel->folderMgr()->findIdString( folderName );
  3705. if ( theFolder == 0 )
  3706. // This is *NOT* supposed to be "imapDraftsFolder", because a
  3707. // dIMAP folder works like a normal folder
  3708. theFolder = kmkernel->dimapFolderMgr()->findIdString( folderName );
  3709. if ( theFolder == 0 )
  3710. imapTheFolder = kmkernel->imapFolderMgr()->findIdString( folderName );
  3711. if ( !theFolder && !imapTheFolder ) {
  3712. const KPIM::Identity & id = kmkernel->identityManager()
  3713. ->identityForUoidOrDefault( msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt() );
  3714. KMessageBox::information( 0,
  3715. i18n("The custom drafts or templates folder for "
  3716. "identify \"%1\" does not exist (anymore); "
  3717. "therefore, the default drafts or templates "
  3718. "folder will be used.")
  3719. .arg( id.identityName() ) );
  3720. }
  3721. }
  3722. if ( imapTheFolder && imapTheFolder->noContent() )
  3723. imapTheFolder = 0;
  3724. bool didOpen = false;
  3725. if ( theFolder == 0 ) {
  3726. theFolder = ( mSaveIn==KMComposeWin::Drafts ?
  3727. kmkernel->draftsFolder() : kmkernel->templatesFolder() );
  3728. } else {
  3729. //XXX this looks really, really fishy
  3730. theFolder->open( "composer" );
  3731. didOpen = true;
  3732. }
  3733. kdDebug(5006) << k_funcinfo << "theFolder=" << theFolder->name() << endl;
  3734. if ( imapTheFolder )
  3735. kdDebug(5006) << k_funcinfo << "imapTheFolder=" << imapTheFolder->name() << endl;
  3736. bool sentOk = !( theFolder->addMsg( msg ) );
  3737. // Ensure the message is correctly and fully parsed
  3738. theFolder->unGetMsg( theFolder->count() - 1 );
  3739. msg = theFolder->getMsg( theFolder->count() - 1 );
  3740. // Does that assignment needs to be propagated out to the caller?
  3741. // Assuming the send is OK, the iterator is set to 0 immediately afterwards.
  3742. if ( imapTheFolder ) {
  3743. // move the message to the imap-folder and highlight it
  3744. imapTheFolder->moveMsg( msg );
  3745. (static_cast<KMFolderImap*>( imapTheFolder->storage() ))->getFolder();
  3746. }
  3747. if ( didOpen )
  3748. theFolder->close( "composer" );
  3749. return sentOk;
  3750. }
  3751. void KMComposeWin::slotContinueDoSend( bool sentOk )
  3752. {
  3753. kdDebug(5006) << "KMComposeWin::slotContinueDoSend( " << sentOk << " )"
  3754. << endl;
  3755. disconnect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  3756. TQT_TQOBJECT(this), TQT_SLOT( slotContinueDoSend( bool ) ) );
  3757. if ( !sentOk ) {
  3758. mDisableBreaking = false;
  3759. return;
  3760. }
  3761. for ( TQValueVector<KMMessage*>::iterator it = mComposedMessages.begin() ; it != mComposedMessages.end() ; ++it ) {
  3762. // remove fields that contain no data (e.g. an empty Cc: or Bcc:)
  3763. (*it)->cleanupHeader();
  3764. // needed for imap
  3765. (*it)->setComplete( true );
  3766. if ( mSaveIn==KMComposeWin::Drafts ) {
  3767. sentOk = saveDraftOrTemplate( (*it)->drafts(), (*it) );
  3768. } else if ( mSaveIn==KMComposeWin::Templates ) {
  3769. sentOk = saveDraftOrTemplate( (*it)->templates(), (*it) );
  3770. } else {
  3771. (*it)->setTo( KMMessage::expandAliases( to() ));
  3772. (*it)->setCc( KMMessage::expandAliases( cc() ));
  3773. if( !mComposer->originalBCC().isEmpty() )
  3774. (*it)->setBcc( KMMessage::expandAliases( mComposer->originalBCC() ));
  3775. TQString recips = (*it)->headerField( "X-KMail-Recipients" );
  3776. if( !recips.isEmpty() ) {
  3777. (*it)->setHeaderField( "X-KMail-Recipients", KMMessage::expandAliases( recips ), KMMessage::Address );
  3778. }
  3779. (*it)->cleanupHeader();
  3780. sentOk = kmkernel->msgSender()->send((*it), mSendMethod);
  3781. }
  3782. if (!sentOk)
  3783. return;
  3784. *it = 0; // don't kill it later...
  3785. }
  3786. RecentAddresses::self( KMKernel::config() )->add( bcc() );
  3787. RecentAddresses::self( KMKernel::config() )->add( cc() );
  3788. RecentAddresses::self( KMKernel::config() )->add( to() );
  3789. setModified( false );
  3790. mAutoDeleteMsg = false;
  3791. mFolder = 0;
  3792. cleanupAutoSave();
  3793. close();
  3794. return;
  3795. }
  3796. bool KMComposeWin::checkTransport() const
  3797. {
  3798. if ( KMail::TransportManager::transportNames().isEmpty() ) {
  3799. KMessageBox::information( mMainWidget,
  3800. i18n("Please create an account for sending and try again.") );
  3801. return false;
  3802. }
  3803. return true;
  3804. }
  3805. //----------------------------------------------------------------------------
  3806. void KMComposeWin::slotSendLater()
  3807. {
  3808. if ( !checkTransport() )
  3809. return;
  3810. if ( !checkRecipientNumber() )
  3811. return;
  3812. if ( mEditor->checkExternalEditorFinished() )
  3813. doSend( KMail::MessageSender::SendLater );
  3814. }
  3815. //----------------------------------------------------------------------------
  3816. void KMComposeWin::slotSaveDraft() {
  3817. if ( mEditor->checkExternalEditorFinished() )
  3818. doSend( KMail::MessageSender::SendLater, KMComposeWin::Drafts );
  3819. }
  3820. //----------------------------------------------------------------------------
  3821. void KMComposeWin::slotSaveTemplate() {
  3822. if ( mEditor->checkExternalEditorFinished() )
  3823. doSend( KMail::MessageSender::SendLater, KMComposeWin::Templates );
  3824. }
  3825. //----------------------------------------------------------------------------
  3826. void KMComposeWin::slotSendNowVia( int item )
  3827. {
  3828. TQStringList availTransports= KMail::TransportManager::transportNames();
  3829. TQString customTransport = availTransports[ item ];
  3830. mTransport->setCurrentText( customTransport );
  3831. slotSendNow();
  3832. }
  3833. //----------------------------------------------------------------------------
  3834. void KMComposeWin::slotSendLaterVia( int item )
  3835. {
  3836. TQStringList availTransports= KMail::TransportManager::transportNames();
  3837. TQString customTransport = availTransports[ item ];
  3838. mTransport->setCurrentText( customTransport );
  3839. slotSendLater();
  3840. }
  3841. //----------------------------------------------------------------------------
  3842. void KMComposeWin::slotSendNow() {
  3843. if ( !mEditor->checkExternalEditorFinished() )
  3844. return;
  3845. if ( !checkTransport() )
  3846. return;
  3847. if ( !checkRecipientNumber() )
  3848. return;
  3849. if ( GlobalSettings::self()->confirmBeforeSend() )
  3850. {
  3851. int rc = KMessageBox::warningYesNoCancel( mMainWidget,
  3852. i18n("About to send email..."),
  3853. i18n("Send Confirmation"),
  3854. i18n("&Send Now"),
  3855. i18n("Send &Later") );
  3856. if ( rc == KMessageBox::Yes )
  3857. doSend( KMail::MessageSender::SendImmediate );
  3858. else if ( rc == KMessageBox::No )
  3859. doSend( KMail::MessageSender::SendLater );
  3860. }
  3861. else
  3862. doSend( KMail::MessageSender::SendImmediate );
  3863. }
  3864. //----------------------------------------------------------------------------
  3865. bool KMComposeWin::checkRecipientNumber() const
  3866. {
  3867. uint thresHold = GlobalSettings::self()->recipientThreshold();
  3868. if ( mCheckForRecipients &&
  3869. GlobalSettings::self()->tooManyRecipients() &&
  3870. mRecipientsEditor->recipients().count() > thresHold ) {
  3871. if ( KMessageBox::questionYesNo( mMainWidget,
  3872. i18n("You are trying to send the mail to more than %1 recipients. Send message anyway?").arg(thresHold),
  3873. i18n("Too many receipients"),
  3874. i18n("&Send as Is"),
  3875. i18n("&Edit Recipients")) == KMessageBox::No ) {
  3876. return false;
  3877. }
  3878. }
  3879. return true;
  3880. }
  3881. //----------------------------------------------------------------------------
  3882. void KMComposeWin::slotAppendSignature()
  3883. {
  3884. insertSignature();
  3885. }
  3886. //----------------------------------------------------------------------------
  3887. void KMComposeWin::slotPrependSignature()
  3888. {
  3889. insertSignature( Prepend );
  3890. }
  3891. //----------------------------------------------------------------------------
  3892. void KMComposeWin::slotInsertSignatureAtCursor()
  3893. {
  3894. insertSignature( AtCursor );
  3895. }
  3896. //----------------------------------------------------------------------------
  3897. void KMComposeWin::insertSignature( SignaturePlacement placement )
  3898. {
  3899. bool mod = mEditor->isModified();
  3900. const KPIM::Identity &ident =
  3901. kmkernel->identityManager()->
  3902. identityForUoidOrDefault( mIdentity->currentIdentity() );
  3903. mOldSigText = GlobalSettings::self()->prependSignature()? ident.signature().rawText() : ident.signatureText();
  3904. if( !mOldSigText.isEmpty() )
  3905. {
  3906. mEditor->sync();
  3907. int paragraph, index;
  3908. mEditor->getCursorPosition( &paragraph, &index );
  3909. index = mEditor->indexOfCurrentLineStart( paragraph, index );
  3910. switch( placement ) {
  3911. case Append:
  3912. mEditor->setText( mEditor->text() + mOldSigText );
  3913. break;
  3914. case Prepend:
  3915. mOldSigText = "\n\n" + mOldSigText + "\n";
  3916. mEditor->insertAt( mOldSigText, paragraph, index );
  3917. break;
  3918. case AtCursor:
  3919. // If there is text in the same line, add a newline so that the stuff in
  3920. // the current line moves after the signature. Also remove a leading newline, it is not
  3921. // needed here.
  3922. if ( mEditor->paragraphLength( paragraph ) > 0 )
  3923. mOldSigText = mOldSigText + "\n";
  3924. if ( mOldSigText.startsWith( "\n" ) )
  3925. mOldSigText = mOldSigText.remove( 0, 1 );
  3926. // If we are inserting into a wordwrapped line, add a newline at the start to make
  3927. // the text edit hard-wrap the line here
  3928. if ( index != 0 )
  3929. mOldSigText = "\n" + mOldSigText;
  3930. mEditor->insertAt( mOldSigText, paragraph, index );
  3931. break;
  3932. }
  3933. mEditor->update();
  3934. mEditor->setModified(mod);
  3935. if ( mPreserveUserCursorPosition ) {
  3936. mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
  3937. // Only keep the cursor from the mMsg *once* based on the
  3938. // preserve-cursor-position setting; this handles the case where
  3939. // the message comes from a template with a specific cursor
  3940. // position set and the signature is appended automatically.
  3941. mPreserveUserCursorPosition = false;
  3942. } else {
  3943. // for append and prepend, move the cursor to 0,0, for insertAt,
  3944. // keep it in the same row, but move to first column
  3945. if ( index == 0 ) {
  3946. mEditor->setCursorPosition( paragraph, 0 );
  3947. } else {
  3948. // For word-wrapped lines, we have created a new paragraph, so change to that one
  3949. mEditor->setCursorPosition( paragraph + 1, 0 );
  3950. }
  3951. if ( placement == Prepend || placement == Append )
  3952. mEditor->setContentsPos( 0, 0 );
  3953. }
  3954. mEditor->sync();
  3955. }
  3956. }
  3957. //-----------------------------------------------------------------------------
  3958. void KMComposeWin::slotHelp()
  3959. {
  3960. kapp->invokeHelp();
  3961. }
  3962. //-----------------------------------------------------------------------------
  3963. void KMComposeWin::slotCleanSpace()
  3964. {
  3965. // Originally we simply used the KEdit::cleanWhiteSpace() method,
  3966. // but that code doesn't handle quoted-lines or signatures, so instead
  3967. // we now simply use regexp's to squeeze sequences of tabs and spaces
  3968. // into a single space, and make sure all our lines are single-spaced.
  3969. //
  3970. // Yes, extra space in a quote string is squeezed.
  3971. // Signatures are respected (i.e. not cleaned).
  3972. TQString s;
  3973. if ( mEditor->hasMarkedText() ) {
  3974. s = mEditor->markedText();
  3975. if( s.isEmpty() )
  3976. return;
  3977. } else {
  3978. s = mEditor->text();
  3979. }
  3980. // Remove the signature for now.
  3981. TQString sig;
  3982. bool restore = false;
  3983. const KPIM::Identity & ident =
  3984. kmkernel->identityManager()->identityForUoid( mId );
  3985. if ( !ident.isNull() ) {
  3986. sig = ident.signatureText();
  3987. if( !sig.isEmpty() ) {
  3988. if( s.endsWith( sig ) ) {
  3989. s.truncate( s.length() - sig.length() );
  3990. restore = true;
  3991. }
  3992. }
  3993. }
  3994. // Squeeze tabs and spaces
  3995. TQRegExp squeeze( "[\t ]+" );
  3996. s.replace( squeeze, TQChar( ' ' ) );
  3997. // Remove trailing whitespace
  3998. TQRegExp trailing( "\\s+$" );
  3999. s.replace( trailing, TQChar( '\n' ) );
  4000. // Single space lines
  4001. TQRegExp singleSpace( "[\n]{2,}" );
  4002. s.replace( singleSpace, TQChar( '\n' ) );
  4003. // Restore the signature
  4004. if ( restore )
  4005. s.append( sig );
  4006. // Put the new text in place.
  4007. // The lines below do not clear the undo history, but unfortuately cause
  4008. // the side-effect that you need to press Ctrl-Z twice (first Ctrl-Z will
  4009. // show cleared text area) to get back the original, pre-cleaned text.
  4010. // If you use mEditor->setText( s ) then the undo history is cleared so
  4011. // that isn't a good solution either.
  4012. // TODO: is TQt4 better at handling the undo history??
  4013. if ( !mEditor->hasMarkedText() )
  4014. mEditor->clear();
  4015. mEditor->insert( s );
  4016. }
  4017. //-----------------------------------------------------------------------------
  4018. void KMComposeWin::slotToggleMarkup()
  4019. {
  4020. if ( markupAction->isChecked() ) {
  4021. mHtmlMarkup = true;
  4022. toolBar("htmlToolBar")->show();
  4023. // markup will be toggled as soon as markup is actually used
  4024. fontChanged( mEditor->currentFont() ); // set buttons in correct position
  4025. mSaveFont = mEditor->currentFont();
  4026. }
  4027. else
  4028. toggleMarkup(false);
  4029. }
  4030. //-----------------------------------------------------------------------------
  4031. void KMComposeWin::toggleMarkup(bool markup)
  4032. {
  4033. if ( markup ) {
  4034. if ( !mUseHTMLEditor ) {
  4035. kdDebug(5006) << "setting RichText editor" << endl;
  4036. mUseHTMLEditor = true; // set it directly to true. setColor hits another toggleMarkup
  4037. mHtmlMarkup = true;
  4038. // set all highlighted text caused by spelling back to black
  4039. int paraFrom, indexFrom, paraTo, indexTo;
  4040. mEditor->getSelection ( &paraFrom, &indexFrom, &paraTo, &indexTo);
  4041. mEditor->selectAll();
  4042. // save the buttonstates because setColor calls fontChanged
  4043. bool _bold = textBoldAction->isChecked();
  4044. bool _italic = textItalicAction->isChecked();
  4045. mEditor->setColor(TQColor(0,0,0));
  4046. textBoldAction->setChecked(_bold);
  4047. textItalicAction->setChecked(_italic);
  4048. mEditor->setSelection ( paraFrom, indexFrom, paraTo, indexTo);
  4049. mEditor->setTextFormat(TQt::RichText);
  4050. mEditor->setModified(true);
  4051. markupAction->setChecked(true);
  4052. toolBar( "htmlToolBar" )->show();
  4053. mEditor->deleteAutoSpellChecking();
  4054. mAutoSpellCheckingAction->setChecked(false);
  4055. slotAutoSpellCheckingToggled(false);
  4056. }
  4057. } else { // markup is to be turned off
  4058. kdDebug(5006) << "setting PlainText editor" << endl;
  4059. mHtmlMarkup = false;
  4060. toolBar("htmlToolBar")->hide();
  4061. if ( mUseHTMLEditor ) { // it was turned on
  4062. mUseHTMLEditor = false;
  4063. mEditor->setTextFormat(TQt::PlainText);
  4064. TQString text = mEditor->text();
  4065. mEditor->setText(text); // otherwise the text still looks formatted
  4066. mEditor->setModified(true);
  4067. slotAutoSpellCheckingToggled(true);
  4068. }
  4069. }
  4070. }
  4071. void KMComposeWin::htmlToolBarVisibilityChanged( bool visible )
  4072. {
  4073. // disable markup if the user hides the HTML toolbar
  4074. if ( !visible ) {
  4075. markupAction->setChecked( false );
  4076. toggleMarkup( false );
  4077. }
  4078. }
  4079. void KMComposeWin::slotSubjectTextSpellChecked()
  4080. {
  4081. mSubjectTextWasSpellChecked = true;
  4082. }
  4083. //-----------------------------------------------------------------------------
  4084. void KMComposeWin::slotAutoSpellCheckingToggled( bool on )
  4085. {
  4086. if ( mEditor->autoSpellChecking(on) == -1 ) {
  4087. mAutoSpellCheckingAction->setChecked(false); // set it to false again
  4088. }
  4089. TQString temp;
  4090. if ( on )
  4091. temp = i18n( "Spellcheck: on" );
  4092. else
  4093. temp = i18n( "Spellcheck: off" );
  4094. statusBar()->changeItem( temp, 3 );
  4095. }
  4096. //-----------------------------------------------------------------------------
  4097. void KMComposeWin::slotSpellcheck()
  4098. {
  4099. if (mSpellCheckInProgress) return;
  4100. mSubjectTextWasSpellChecked = false;
  4101. mSpellCheckInProgress=true;
  4102. /*
  4103. connect (mEditor, TQT_SIGNAL (spellcheck_progress (unsigned)),
  4104. this, TQT_SLOT (spell_progress (unsigned)));
  4105. */
  4106. mEditor->spellcheck();
  4107. }
  4108. //-----------------------------------------------------------------------------
  4109. void KMComposeWin::slotUpdateSignatureActions()
  4110. {
  4111. //Check if an identity has signature or not and turn on/off actions in the
  4112. //edit menu accordingly.
  4113. const KPIM::Identity & ident =
  4114. kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
  4115. TQString sig = ident.signatureText();
  4116. if ( sig.isEmpty() ) {
  4117. mAppendSignatureAction->setEnabled( false );
  4118. mPrependSignatureAction->setEnabled( false );
  4119. mInsertSignatureAction->setEnabled( false );
  4120. }
  4121. else {
  4122. mAppendSignatureAction->setEnabled( true );
  4123. mPrependSignatureAction->setEnabled( true );
  4124. mInsertSignatureAction->setEnabled( true );
  4125. }
  4126. }
  4127. void KMComposeWin::polish()
  4128. {
  4129. // Ensure the html toolbar is appropriately shown/hidden
  4130. markupAction->setChecked(mHtmlMarkup);
  4131. if (mHtmlMarkup)
  4132. toolBar("htmlToolBar")->show();
  4133. else
  4134. toolBar("htmlToolBar")->hide();
  4135. KMail::Composer::polish();
  4136. }
  4137. //-----------------------------------------------------------------------------
  4138. void KMComposeWin::slotSpellcheckDone(int result)
  4139. {
  4140. kdDebug(5006) << "spell check complete: result = " << result << endl;
  4141. mSpellCheckInProgress=false;
  4142. switch( result )
  4143. {
  4144. case KS_CANCEL:
  4145. statusBar()->changeItem(i18n(" Spell check canceled."),0);
  4146. break;
  4147. case KS_STOP:
  4148. statusBar()->changeItem(i18n(" Spell check stopped."),0);
  4149. break;
  4150. default:
  4151. statusBar()->changeItem(i18n(" Spell check complete."),0);
  4152. break;
  4153. }
  4154. TQTimer::singleShot( 2000, this, TQT_SLOT(slotSpellcheckDoneClearStatus()) );
  4155. }
  4156. void KMComposeWin::slotSpellcheckDoneClearStatus()
  4157. {
  4158. statusBar()->changeItem("", 0);
  4159. }
  4160. //-----------------------------------------------------------------------------
  4161. void KMComposeWin::slotIdentityChanged( uint uoid )
  4162. {
  4163. const KPIM::Identity & ident =
  4164. kmkernel->identityManager()->identityForUoid( uoid );
  4165. if( ident.isNull() ) return;
  4166. //Turn on/off signature actions if identity has no signature.
  4167. slotUpdateSignatureActions();
  4168. if( !ident.fullEmailAddr().isNull() )
  4169. mEdtFrom->setText(ident.fullEmailAddr());
  4170. // make sure the From field is shown if it does not contain a valid email address
  4171. if ( KPIM::getFirstEmailAddress( from() ).isEmpty() )
  4172. mShowHeaders |= HDR_FROM;
  4173. if ( mEdtReplyTo ) mEdtReplyTo->setText(ident.replyToAddr());
  4174. if ( mRecipientsEditor ) {
  4175. // remove BCC of old identity and add BCC of new identity (if they differ)
  4176. const KPIM::Identity & oldIdentity =
  4177. kmkernel->identityManager()->identityForUoidOrDefault( mId );
  4178. if ( oldIdentity.bcc() != ident.bcc() ) {
  4179. mRecipientsEditor->removeRecipient( oldIdentity.bcc(), Recipient::Bcc );
  4180. mRecipientsEditor->addRecipient( ident.bcc(), Recipient::Bcc );
  4181. mRecipientsEditor->setFocusBottom();
  4182. }
  4183. }
  4184. // don't overwrite the BCC field under certain circomstances
  4185. // NOT edited and preset BCC from the identity
  4186. if( mEdtBcc && !mEdtBcc->edited() && !ident.bcc().isEmpty() ) {
  4187. // BCC NOT empty AND contains a diff adress then the preset BCC
  4188. // of the new identity
  4189. if( !mEdtBcc->text().isEmpty() && mEdtBcc->text() != ident.bcc() && !mEdtBcc->edited() ) {
  4190. mEdtBcc->setText( ident.bcc() );
  4191. } else {
  4192. // user type into the editbox an address that != to the preset bcc
  4193. // of the identity, we assume that since the user typed it
  4194. // they want to keep it
  4195. if ( mEdtBcc->text() != ident.bcc() && !mEdtBcc->text().isEmpty() ) {
  4196. TQString temp_string( mEdtBcc->text() + TQString::fromLatin1(",") + ident.bcc() );
  4197. mEdtBcc->setText( temp_string );
  4198. } else {
  4199. // if the user typed the same address as the preset BCC
  4200. // from the identity we will overwrite it to avoid duplicates.
  4201. mEdtBcc->setText( ident.bcc() );
  4202. }
  4203. }
  4204. }
  4205. // user edited the bcc box and has a preset bcc in the identity
  4206. // we will append whatever the user typed to the preset address
  4207. // allowing the user to keep all addresses
  4208. if( mEdtBcc && mEdtBcc->edited() && !ident.bcc().isEmpty() ) {
  4209. if( !mEdtBcc->text().isEmpty() ) {
  4210. TQString temp_string ( mEdtBcc->text() + TQString::fromLatin1(",") + ident.bcc() );
  4211. mEdtBcc->setText( temp_string );
  4212. } else {
  4213. mEdtBcc->setText( ident.bcc() );
  4214. }
  4215. }
  4216. // user typed nothing and the identity does not have a preset bcc
  4217. // we then reset the value to get rid of any previous
  4218. // values if the user changed identity mid way through.
  4219. if( mEdtBcc && !mEdtBcc->edited() && ident.bcc().isEmpty() ) {
  4220. mEdtBcc->setText( ident.bcc() );
  4221. }
  4222. // make sure the BCC field is shown because else it's ignored
  4223. if ( !ident.bcc().isEmpty() ) {
  4224. mShowHeaders |= HDR_BCC;
  4225. }
  4226. if ( ident.organization().isEmpty() )
  4227. mMsg->removeHeaderField("Organization");
  4228. else
  4229. mMsg->setHeaderField("Organization", ident.organization());
  4230. if (!ident.isXFaceEnabled() || ident.xface().isEmpty())
  4231. mMsg->removeHeaderField("X-Face");
  4232. else
  4233. {
  4234. TQString xface = ident.xface();
  4235. if (!xface.isEmpty())
  4236. {
  4237. int numNL = ( xface.length() - 1 ) / 70;
  4238. for ( int i = numNL; i > 0; --i )
  4239. xface.insert( i*70, "\n\t" );
  4240. mMsg->setHeaderField("X-Face", xface);
  4241. }
  4242. }
  4243. if ( !mBtnTransport->isChecked() && !mIgnoreStickyFields ) {
  4244. TQString transp = ident.transport();
  4245. if ( transp.isEmpty() )
  4246. {
  4247. mMsg->removeHeaderField("X-KMail-Transport");
  4248. transp = GlobalSettings::self()->defaultTransport();
  4249. }
  4250. else
  4251. mMsg->setHeaderField("X-KMail-Transport", transp);
  4252. setTransport( transp );
  4253. }
  4254. if ( !mBtnDictionary->isChecked() && !mIgnoreStickyFields ) {
  4255. mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
  4256. }
  4257. if ( !mBtnFcc->isChecked() && !mPreventFccOverwrite ) {
  4258. setFcc( ident.fcc() );
  4259. }
  4260. TQString edtText = mEditor->text();
  4261. if ( mOldSigText.isEmpty() ) {
  4262. const KPIM::Identity &id =
  4263. kmkernel->
  4264. identityManager()->
  4265. identityForUoidOrDefault( mMsg->headerField( "X-KMail-Identity" ).
  4266. stripWhiteSpace().toUInt() );
  4267. mOldSigText = GlobalSettings::self()->prependSignature() ? id.signature().rawText() : id.signatureText();
  4268. }
  4269. if ( !GlobalSettings::prependSignature() ) {
  4270. // try to truncate the old sig
  4271. // First remove any trailing whitespace
  4272. while ( !edtText.isEmpty() && edtText[edtText.length()-1].isSpace() )
  4273. edtText.truncate( edtText.length() - 1 );
  4274. // From the sig too, just in case
  4275. while ( !mOldSigText.isEmpty() && mOldSigText[mOldSigText.length()-1].isSpace() )
  4276. mOldSigText.truncate( mOldSigText.length() - 1 );
  4277. if ( edtText.endsWith( mOldSigText ) )
  4278. edtText.truncate( edtText.length() - mOldSigText.length() );
  4279. // now append the new sig
  4280. mOldSigText = ident.signatureText();
  4281. if( ( !mOldSigText.isEmpty() ) &&
  4282. ( GlobalSettings::self()->autoTextSignature() == "auto" ) ) {
  4283. edtText.append( mOldSigText );
  4284. }
  4285. mEditor->setText( edtText );
  4286. } else {
  4287. const int pos = edtText.find( mOldSigText );
  4288. if ( pos >= 0 && !mOldSigText.isEmpty() ) {
  4289. const int oldLength = mOldSigText.length();
  4290. mOldSigText = "\n\n"+ ident.signature().rawText() + "\n"; // see insertSignature()
  4291. edtText = edtText.replace( pos, oldLength, mOldSigText );
  4292. mEditor->setText( edtText );
  4293. } else {
  4294. insertSignature( Append );
  4295. }
  4296. }
  4297. // disable certain actions if there is no PGP user identity set
  4298. // for this profile
  4299. bool bNewIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
  4300. bool bNewIdentityHasEncryptionKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
  4301. mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
  4302. !ident.pgpEncryptionKey().isEmpty() );
  4303. // save the state of the sign and encrypt button
  4304. if ( !bNewIdentityHasEncryptionKey && mLastIdentityHasEncryptionKey ) {
  4305. mLastEncryptActionState = mEncryptAction->isChecked();
  4306. setEncryption( false );
  4307. }
  4308. if ( !bNewIdentityHasSigningKey && mLastIdentityHasSigningKey ) {
  4309. mLastSignActionState = mSignAction->isChecked();
  4310. setSigning( false );
  4311. }
  4312. // restore the last state of the sign and encrypt button
  4313. if ( bNewIdentityHasEncryptionKey && !mLastIdentityHasEncryptionKey )
  4314. setEncryption( mLastEncryptActionState );
  4315. if ( bNewIdentityHasSigningKey && !mLastIdentityHasSigningKey )
  4316. setSigning( mLastSignActionState );
  4317. mLastIdentityHasSigningKey = bNewIdentityHasSigningKey;
  4318. mLastIdentityHasEncryptionKey = bNewIdentityHasEncryptionKey;
  4319. setModified( true );
  4320. mId = uoid;
  4321. // make sure the From and BCC fields are shown if necessary
  4322. rethinkFields( false );
  4323. }
  4324. //-----------------------------------------------------------------------------
  4325. void KMComposeWin::slotSpellcheckConfig()
  4326. {
  4327. KDialogBase dlg(KDialogBase::Plain, i18n("Spellchecker"),
  4328. KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok,
  4329. TQT_TQWIDGET(this), 0, true, true );
  4330. KWin twin;
  4331. TQTabDialog qtd (this, "tabdialog", true);
  4332. KSpellConfig mKSpellConfig (&qtd);
  4333. mKSpellConfig.layout()->setMargin( KDialog::marginHint() );
  4334. qtd.addTab (&mKSpellConfig, i18n("Spellchecker"));
  4335. qtd.setCancelButton ();
  4336. twin.setIcons (qtd.winId(), kapp->icon(), kapp->miniIcon());
  4337. qtd.setCancelButton(KStdGuiItem::cancel().text());
  4338. qtd.setOkButton(KStdGuiItem::ok().text());
  4339. if (qtd.exec())
  4340. mKSpellConfig.writeGlobalSettings();
  4341. }
  4342. //-----------------------------------------------------------------------------
  4343. void KMComposeWin::slotStatusMessage(const TQString &message)
  4344. {
  4345. statusBar()->changeItem( message, 0 );
  4346. }
  4347. void KMComposeWin::slotEditToolbars()
  4348. {
  4349. saveMainWindowSettings(KMKernel::config(), "Composer");
  4350. KEditToolbar dlg(guiFactory(), this);
  4351. connect( &dlg, TQT_SIGNAL(newToolbarConfig()),
  4352. TQT_SLOT(slotUpdateToolbars()) );
  4353. dlg.exec();
  4354. }
  4355. void KMComposeWin::slotUpdateToolbars()
  4356. {
  4357. createGUI("kmcomposerui.rc");
  4358. applyMainWindowSettings(KMKernel::config(), "Composer");
  4359. }
  4360. void KMComposeWin::slotEditKeys()
  4361. {
  4362. KKeyDialog::configure( actionCollection(),
  4363. false /*don't allow one-letter shortcuts*/
  4364. );
  4365. }
  4366. void KMComposeWin::setReplyFocus( bool hasMessage )
  4367. {
  4368. mEditor->setFocus();
  4369. if ( hasMessage ) {
  4370. if( mMsg->getCursorPos() ) {
  4371. mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
  4372. } else {
  4373. mEditor->setCursorPosition( 1, 0 );
  4374. }
  4375. }
  4376. }
  4377. void KMComposeWin::setFocusToSubject()
  4378. {
  4379. mEdtSubject->setFocus();
  4380. }
  4381. int KMComposeWin::autoSaveInterval() const
  4382. {
  4383. return GlobalSettings::self()->autosaveInterval() * 1000 * 60;
  4384. }
  4385. void KMComposeWin::initAutoSave()
  4386. {
  4387. kdDebug(5006) << k_funcinfo << endl;
  4388. // make sure the autosave folder exists
  4389. KMFolderMaildir::createMaildirFolders( KMKernel::localDataPath() + "autosave" );
  4390. if ( mAutoSaveFilename.isEmpty() ) {
  4391. mAutoSaveFilename = KMFolderMaildir::constructValidFileName();
  4392. }
  4393. updateAutoSave();
  4394. }
  4395. void KMComposeWin::updateAutoSave()
  4396. {
  4397. if ( autoSaveInterval() == 0 ) {
  4398. delete mAutoSaveTimer; mAutoSaveTimer = 0;
  4399. }
  4400. else {
  4401. if ( !mAutoSaveTimer ) {
  4402. mAutoSaveTimer = new TQTimer( this, "mAutoSaveTimer" );
  4403. connect( mAutoSaveTimer, TQT_SIGNAL( timeout() ),
  4404. TQT_TQOBJECT(this), TQT_SLOT( autoSaveMessage() ) );
  4405. }
  4406. mAutoSaveTimer->start( autoSaveInterval() );
  4407. }
  4408. }
  4409. void KMComposeWin::setAutoSaveFilename( const TQString & filename )
  4410. {
  4411. mAutoSaveFilename = filename;
  4412. }
  4413. void KMComposeWin::cleanupAutoSave()
  4414. {
  4415. delete mAutoSaveTimer; mAutoSaveTimer = 0;
  4416. if ( !mAutoSaveFilename.isEmpty() ) {
  4417. kdDebug(5006) << k_funcinfo << "deleting autosave file "
  4418. << mAutoSaveFilename << endl;
  4419. KMFolderMaildir::removeFile( KMKernel::localDataPath() + "autosave",
  4420. mAutoSaveFilename );
  4421. mAutoSaveFilename = TQString();
  4422. }
  4423. }
  4424. void KMComposeWin::slotCompletionModeChanged( TDEGlobalSettings::Completion mode)
  4425. {
  4426. GlobalSettings::self()->setCompletionMode( (int) mode );
  4427. // sync all the lineedits to the same completion mode
  4428. mEdtFrom->setCompletionMode( mode );
  4429. mEdtReplyTo->setCompletionMode( mode );
  4430. if ( mClassicalRecipients ) {
  4431. mEdtTo->setCompletionMode( mode );
  4432. mEdtCc->setCompletionMode( mode );
  4433. mEdtBcc->setCompletionMode( mode );
  4434. }else
  4435. mRecipientsEditor->setCompletionMode( mode );
  4436. }
  4437. void KMComposeWin::slotConfigChanged()
  4438. {
  4439. readConfig( true /*reload*/);
  4440. updateAutoSave();
  4441. rethinkFields();
  4442. slotWordWrapToggled( mWordWrapAction->isChecked() );
  4443. }
  4444. /*
  4445. * checks if the drafts-folder has been deleted
  4446. * that is not nice so we set the system-drafts-folder
  4447. */
  4448. void KMComposeWin::slotFolderRemoved(KMFolder* folder)
  4449. {
  4450. // TODO: need to handle templates here?
  4451. if ( (mFolder) && (folder->idString() == mFolder->idString()) )
  4452. {
  4453. mFolder = kmkernel->draftsFolder();
  4454. kdDebug(5006) << "restoring drafts to " << mFolder->idString() << endl;
  4455. }
  4456. if (mMsg) mMsg->setParent(0);
  4457. }
  4458. void KMComposeWin::editorFocusChanged(bool gained)
  4459. {
  4460. mPasteQuotation->setEnabled(gained);
  4461. }
  4462. void KMComposeWin::slotSetAlwaysSend( bool bAlways )
  4463. {
  4464. mAlwaysSend = bAlways;
  4465. }
  4466. void KMComposeWin::slotListAction( const TQString& style )
  4467. {
  4468. toggleMarkup(true);
  4469. if ( style == i18n( "Standard" ) )
  4470. mEditor->setParagType( TQStyleSheetItem::DisplayBlock, TQStyleSheetItem::ListDisc );
  4471. else if ( style == i18n( "Bulleted List (Disc)" ) )
  4472. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListDisc );
  4473. else if ( style == i18n( "Bulleted List (Circle)" ) )
  4474. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListCircle );
  4475. else if ( style == i18n( "Bulleted List (Square)" ) )
  4476. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListSquare );
  4477. else if ( style == i18n( "Ordered List (Decimal)" ))
  4478. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListDecimal );
  4479. else if ( style == i18n( "Ordered List (Alpha lower)" ) )
  4480. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListLowerAlpha );
  4481. else if ( style == i18n( "Ordered List (Alpha upper)" ) )
  4482. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListUpperAlpha );
  4483. mEditor->viewport()->setFocus();
  4484. }
  4485. void KMComposeWin::slotFontAction( const TQString& font)
  4486. {
  4487. toggleMarkup(true);
  4488. mEditor->TQTextEdit::setFamily( font );
  4489. mEditor->viewport()->setFocus();
  4490. }
  4491. void KMComposeWin::slotSizeAction( int size )
  4492. {
  4493. toggleMarkup(true);
  4494. mEditor->setPointSize( size );
  4495. mEditor->viewport()->setFocus();
  4496. }
  4497. void KMComposeWin::slotAlignLeft()
  4498. {
  4499. toggleMarkup(true);
  4500. mEditor->TQTextEdit::setAlignment( AlignLeft );
  4501. }
  4502. void KMComposeWin::slotAlignCenter()
  4503. {
  4504. toggleMarkup(true);
  4505. mEditor->TQTextEdit::setAlignment( AlignHCenter );
  4506. }
  4507. void KMComposeWin::slotAlignRight()
  4508. {
  4509. toggleMarkup(true);
  4510. mEditor->TQTextEdit::setAlignment( AlignRight );
  4511. }
  4512. void KMComposeWin::slotTextBold()
  4513. {
  4514. toggleMarkup(true);
  4515. mEditor->TQTextEdit::setBold( textBoldAction->isChecked() );
  4516. }
  4517. void KMComposeWin::slotTextItalic()
  4518. {
  4519. toggleMarkup(true);
  4520. mEditor->TQTextEdit::setItalic( textItalicAction->isChecked() );
  4521. }
  4522. void KMComposeWin::slotTextUnder()
  4523. {
  4524. toggleMarkup(true);
  4525. mEditor->TQTextEdit::setUnderline( textUnderAction->isChecked() );
  4526. }
  4527. void KMComposeWin::slotFormatReset()
  4528. {
  4529. mEditor->setColor(mForeColor);
  4530. mEditor->setCurrentFont( mSaveFont ); // fontChanged is called now
  4531. }
  4532. void KMComposeWin::slotTextColor()
  4533. {
  4534. TQColor color = mEditor->color();
  4535. if ( KColorDialog::getColor( color, this ) ) {
  4536. toggleMarkup(true);
  4537. mEditor->setColor( color );
  4538. }
  4539. }
  4540. void KMComposeWin::fontChanged( const TQFont &f )
  4541. {
  4542. TQFont fontTemp = f;
  4543. fontTemp.setBold( true );
  4544. fontTemp.setItalic( true );
  4545. TQFontInfo fontInfo( fontTemp );
  4546. if ( fontInfo.bold() ) {
  4547. textBoldAction->setChecked( f.bold() );
  4548. textBoldAction->setEnabled( true ) ;
  4549. } else {
  4550. textBoldAction->setEnabled( false );
  4551. }
  4552. if ( fontInfo.italic() ) {
  4553. textItalicAction->setChecked( f.italic() );
  4554. textItalicAction->setEnabled( true ) ;
  4555. } else {
  4556. textItalicAction->setEnabled( false );
  4557. }
  4558. textUnderAction->setChecked( f.underline() );
  4559. fontAction->setFont( f.family() );
  4560. fontSizeAction->setFontSize( f.pointSize() );
  4561. }
  4562. void KMComposeWin::alignmentChanged( int a )
  4563. {
  4564. //toggleMarkup();
  4565. alignLeftAction->setChecked( ( a == AlignAuto ) || ( a & AlignLeft ) );
  4566. alignCenterAction->setChecked( ( a & AlignHCenter ) );
  4567. alignRightAction->setChecked( ( a & AlignRight ) );
  4568. }
  4569. namespace {
  4570. class TDEToggleActionResetter {
  4571. TDEToggleAction * mAction;
  4572. bool mOn;
  4573. public:
  4574. TDEToggleActionResetter( TDEToggleAction * action, bool on )
  4575. : mAction( action ), mOn( on ) {}
  4576. ~TDEToggleActionResetter() {
  4577. if ( mAction )
  4578. mAction->setChecked( mOn );
  4579. }
  4580. void disable() { mAction = 0; }
  4581. };
  4582. }
  4583. void KMComposeWin::slotEncryptChiasmusToggled( bool on ) {
  4584. mEncryptWithChiasmus = false;
  4585. if ( !on )
  4586. return;
  4587. TDEToggleActionResetter resetter( mEncryptChiasmusAction, false );
  4588. const Kleo::CryptoBackend::Protocol * chiasmus =
  4589. Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
  4590. if ( !chiasmus ) {
  4591. const TQString msg = Kleo::CryptoBackendFactory::instance()->knowsAboutProtocol( "Chiasmus" )
  4592. ? i18n( "Please configure a Crypto Backend to use for "
  4593. "Chiasmus encryption first.\n"
  4594. "You can do this in the Crypto Backends tab of "
  4595. "the configure dialog's Security page." )
  4596. : i18n( "It looks as though libkleopatra was compiled without "
  4597. "Chiasmus support. You might want to recompile "
  4598. "libkleopatra with --enable-chiasmus.");
  4599. KMessageBox::information( this, msg, i18n("No Chiasmus Backend Configured" ) );
  4600. return;
  4601. }
  4602. STD_NAMESPACE_PREFIX auto_ptr<Kleo::SpecialJob> job( chiasmus->specialJob( "x-obtain-keys", TQMap<TQString,TQVariant>() ) );
  4603. if ( !job.get() ) {
  4604. const TQString msg = i18n( "Chiasmus backend does not offer the "
  4605. "\"x-obtain-keys\" function. Please report this bug." );
  4606. KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
  4607. return;
  4608. }
  4609. if ( job->exec() ) {
  4610. job->showErrorDialog( this, i18n( "Chiasmus Backend Error" ) );
  4611. return;
  4612. }
  4613. const TQVariant result = job->property( "result" );
  4614. if ( result.type() != TQVariant::StringList ) {
  4615. const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
  4616. "The \"x-obtain-keys\" function did not return a "
  4617. "string list. Please report this bug." );
  4618. KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
  4619. return;
  4620. }
  4621. const TQStringList keys = result.toStringList();
  4622. if ( keys.empty() ) {
  4623. const TQString msg = i18n( "No keys have been found. Please check that a "
  4624. "valid key path has been set in the Chiasmus "
  4625. "configuration." );
  4626. KMessageBox::information( this, msg, i18n( "No Chiasmus Keys Found" ) );
  4627. return;
  4628. }
  4629. ChiasmusKeySelector selectorDlg( this, i18n( "Chiasmus Encryption Key Selection" ),
  4630. keys, GlobalSettings::chiasmusKey(),
  4631. GlobalSettings::chiasmusOptions() );
  4632. if ( selectorDlg.exec() != TQDialog::Accepted )
  4633. return;
  4634. GlobalSettings::setChiasmusOptions( selectorDlg.options() );
  4635. GlobalSettings::setChiasmusKey( selectorDlg.key() );
  4636. assert( !GlobalSettings::chiasmusKey().isEmpty() );
  4637. mEncryptWithChiasmus = true;
  4638. resetter.disable();
  4639. }
  4640. void KMComposeWin::slotEditDone(KMail::EditorWatcher * watcher)
  4641. {
  4642. kdDebug(5006) << k_funcinfo << endl;
  4643. KMMessagePart *part = mEditorMap[ watcher ];
  4644. KTempFile *tf = mEditorTempFiles[ watcher ];
  4645. mEditorMap.remove( watcher );
  4646. mEditorTempFiles.remove( watcher );
  4647. if ( !watcher->fileChanged() )
  4648. return;
  4649. tf->file()->reset();
  4650. TQByteArray data = tf->file()->readAll();
  4651. part->setBodyEncodedBinary( data );
  4652. }
  4653. void KMComposeWin::slotUpdateSignatureAndEncrypionStateIndicators()
  4654. {
  4655. const bool showIndicatorsAlways = false; // FIXME config option?
  4656. mSignatureStateIndicator->setText( mSignAction->isChecked()? i18n("Message will be signed") : i18n("Message will not be signed") );
  4657. mEncryptionStateIndicator->setText( mEncryptAction->isChecked()? i18n("Message will be encrypted") : i18n("Message will not be encrypted") );
  4658. if ( !showIndicatorsAlways ) {
  4659. mSignatureStateIndicator->setShown( mSignAction->isChecked() );
  4660. mEncryptionStateIndicator->setShown( mEncryptAction->isChecked() );
  4661. }
  4662. }
  4663. void KMComposeWin::slotAttachmentDragStarted()
  4664. {
  4665. kdDebug(5006) << k_funcinfo << endl;
  4666. int idx = 0;
  4667. TQStringList filenames;
  4668. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++idx ) {
  4669. if ( (*it)->isSelected() ) {
  4670. KMMessagePart* msgPart = mAtmList.at(idx);
  4671. KTempDir * tempDir = new KTempDir(); // will be deleted on composer close
  4672. tempDir->setAutoDelete( true );
  4673. mTempDirs.insert( tempDir );
  4674. const TQString fileName = tempDir->name() + "/" + msgPart->name();
  4675. KPIM::kByteArrayToFile(msgPart->bodyDecodedBinary(),
  4676. fileName,
  4677. false, false, false);
  4678. KURL url;
  4679. url.setPath( fileName );
  4680. filenames << url.path();
  4681. }
  4682. }
  4683. if ( filenames.isEmpty() ) return;
  4684. TQUriDrag *drag = new TQUriDrag( mAtmListView );
  4685. drag->setFileNames( filenames );
  4686. drag->dragCopy();
  4687. }
  4688. void KMComposeWin::recipientEditorSizeHintChanged()
  4689. {
  4690. TQTimer::singleShot( 1, this, TQT_SLOT(setMaximumHeaderSize()) );
  4691. }
  4692. void KMComposeWin::setMaximumHeaderSize()
  4693. {
  4694. mHeadersArea->setMaximumHeight( mHeadersArea->sizeHint().height() );
  4695. }